Merge "Add <intent-filter> support to <provider>." into klp-dev
This commit is contained in:
@ -7255,6 +7255,7 @@ package android.content.pm {
|
||||
method public abstract java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(java.lang.String, int);
|
||||
method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivities(android.content.Intent, int);
|
||||
method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivityOptions(android.content.ComponentName, android.content.Intent[], android.content.Intent, int);
|
||||
method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(android.content.Intent, int);
|
||||
method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentServices(android.content.Intent, int);
|
||||
method public abstract java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
|
||||
method public abstract deprecated void removePackageFromPreferred(java.lang.String);
|
||||
@ -7420,6 +7421,7 @@ package android.content.pm {
|
||||
ctor public ProviderInfo();
|
||||
ctor public ProviderInfo(android.content.pm.ProviderInfo);
|
||||
method public int describeContents();
|
||||
method public void dump(android.util.Printer, java.lang.String);
|
||||
field public static final android.os.Parcelable.Creator CREATOR;
|
||||
field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
|
||||
field public java.lang.String authority;
|
||||
@ -7453,6 +7455,7 @@ package android.content.pm {
|
||||
field public java.lang.CharSequence nonLocalizedLabel;
|
||||
field public int preferredOrder;
|
||||
field public int priority;
|
||||
field public android.content.pm.ProviderInfo providerInfo;
|
||||
field public java.lang.String resolvePackageName;
|
||||
field public android.content.pm.ServiceInfo serviceInfo;
|
||||
field public int specificIndex;
|
||||
@ -20982,6 +20985,7 @@ package android.provider {
|
||||
field public static final java.lang.String EXTRA_ERROR = "error";
|
||||
field public static final java.lang.String EXTRA_INFO = "info";
|
||||
field public static final java.lang.String EXTRA_LOADING = "loading";
|
||||
field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
|
||||
}
|
||||
|
||||
public static final class DocumentsContract.Document {
|
||||
@ -24477,6 +24481,7 @@ package android.test.mock {
|
||||
method public java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(java.lang.String, int);
|
||||
method public java.util.List<android.content.pm.ResolveInfo> queryIntentActivities(android.content.Intent, int);
|
||||
method public java.util.List<android.content.pm.ResolveInfo> queryIntentActivityOptions(android.content.ComponentName, android.content.Intent[], android.content.Intent, int);
|
||||
method public java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(android.content.Intent, int);
|
||||
method public java.util.List<android.content.pm.ResolveInfo> queryIntentServices(android.content.Intent, int);
|
||||
method public java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
|
||||
method public void removePackageFromPreferred(java.lang.String);
|
||||
|
@ -584,6 +584,22 @@ final class ApplicationPackageManager extends PackageManager {
|
||||
return queryIntentServicesAsUser(intent, flags, mContext.getUserId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ResolveInfo> queryIntentContentProvidersAsUser(
|
||||
Intent intent, int flags, int userId) {
|
||||
try {
|
||||
return mPM.queryIntentContentProviders(intent,
|
||||
intent.resolveTypeIfNeeded(mContext.getContentResolver()), flags, userId);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException("Package manager has died", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ResolveInfo> queryIntentContentProviders(Intent intent, int flags) {
|
||||
return queryIntentContentProvidersAsUser(intent, flags, mContext.getUserId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderInfo resolveContentProvider(String name,
|
||||
int flags) {
|
||||
|
@ -123,6 +123,9 @@ interface IPackageManager {
|
||||
List<ResolveInfo> queryIntentServices(in Intent intent,
|
||||
String resolvedType, int flags, int userId);
|
||||
|
||||
List<ResolveInfo> queryIntentContentProviders(in Intent intent,
|
||||
String resolvedType, int flags, int userId);
|
||||
|
||||
/**
|
||||
* This implements getInstalledPackages via a "last returned row"
|
||||
* mechanism that is not exposed in the API. This is to get around the IPC
|
||||
|
@ -2210,6 +2210,24 @@ public abstract class PackageManager {
|
||||
public abstract List<ResolveInfo> queryIntentServicesAsUser(Intent intent,
|
||||
int flags, int userId);
|
||||
|
||||
/** {@hide} */
|
||||
public abstract List<ResolveInfo> queryIntentContentProvidersAsUser(
|
||||
Intent intent, int flags, int userId);
|
||||
|
||||
/**
|
||||
* Retrieve all providers that can match the given intent.
|
||||
*
|
||||
* @param intent An intent containing all of the desired specification
|
||||
* (action, data, type, category, and/or component).
|
||||
* @param flags Additional option flags.
|
||||
* @return A List<ResolveInfo> containing one entry for each matching
|
||||
* ProviderInfo. These are ordered from best to worst match. If
|
||||
* there are no matching providers, an empty list is returned.
|
||||
* @see #GET_INTENT_FILTERS
|
||||
* @see #GET_RESOLVED_FILTER
|
||||
*/
|
||||
public abstract List<ResolveInfo> queryIntentContentProviders(Intent intent, int flags);
|
||||
|
||||
/**
|
||||
* Find a single content provider by its base path name.
|
||||
*
|
||||
|
@ -2819,7 +2819,14 @@ public class PackageParser {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parser.getName().equals("meta-data")) {
|
||||
if (parser.getName().equals("intent-filter")) {
|
||||
ProviderIntentInfo intent = new ProviderIntentInfo(outInfo);
|
||||
if (!parseIntent(res, parser, attrs, true, intent, outError)) {
|
||||
return false;
|
||||
}
|
||||
outInfo.intents.add(intent);
|
||||
|
||||
} else if (parser.getName().equals("meta-data")) {
|
||||
if ((outInfo.metaData=parseMetaData(res, parser, attrs,
|
||||
outInfo.metaData, outError)) == null) {
|
||||
return false;
|
||||
@ -3982,7 +3989,7 @@ public class PackageParser {
|
||||
return si;
|
||||
}
|
||||
|
||||
public final static class Provider extends Component {
|
||||
public final static class Provider extends Component<ProviderIntentInfo> {
|
||||
public final ProviderInfo info;
|
||||
public boolean syncable;
|
||||
|
||||
@ -4116,6 +4123,24 @@ public class PackageParser {
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ProviderIntentInfo extends IntentInfo {
|
||||
public final Provider provider;
|
||||
|
||||
public ProviderIntentInfo(Provider provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
sb.append("ProviderIntentInfo{");
|
||||
sb.append(Integer.toHexString(System.identityHashCode(this)));
|
||||
sb.append(' ');
|
||||
provider.appendComponentShortName(sb);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
|
@ -19,6 +19,7 @@ package android.content.pm;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.PatternMatcher;
|
||||
import android.util.Printer;
|
||||
|
||||
/**
|
||||
* Holds information about a specific
|
||||
@ -112,7 +113,13 @@ public final class ProviderInfo extends ComponentInfo
|
||||
flags = orig.flags;
|
||||
isSyncable = orig.isSyncable;
|
||||
}
|
||||
|
||||
|
||||
public void dump(Printer pw, String prefix) {
|
||||
super.dumpFront(pw, prefix);
|
||||
pw.println(prefix + "authority=" + authority);
|
||||
pw.println(prefix + "flags=0x" + Integer.toHexString(flags));
|
||||
}
|
||||
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Printer;
|
||||
import android.util.Slog;
|
||||
|
||||
import java.text.Collator;
|
||||
import java.util.Comparator;
|
||||
@ -34,20 +35,30 @@ import java.util.Comparator;
|
||||
* <intent> tags.
|
||||
*/
|
||||
public class ResolveInfo implements Parcelable {
|
||||
private static final String TAG = "ResolveInfo";
|
||||
|
||||
/**
|
||||
* The activity or broadcast receiver that corresponds to this resolution match,
|
||||
* if this resolution is for an activity or broadcast receiver. One and only one of this and
|
||||
* serviceInfo must be non-null.
|
||||
* The activity or broadcast receiver that corresponds to this resolution
|
||||
* match, if this resolution is for an activity or broadcast receiver.
|
||||
* Exactly one of {@link #activityInfo}, {@link #serviceInfo}, or
|
||||
* {@link #providerInfo} will be non-null.
|
||||
*/
|
||||
public ActivityInfo activityInfo;
|
||||
|
||||
/**
|
||||
* The service that corresponds to this resolution match, if this
|
||||
* resolution is for a service. One and only one of this and
|
||||
* activityInfo must be non-null.
|
||||
* The service that corresponds to this resolution match, if this resolution
|
||||
* is for a service. Exactly one of {@link #activityInfo},
|
||||
* {@link #serviceInfo}, or {@link #providerInfo} will be non-null.
|
||||
*/
|
||||
public ServiceInfo serviceInfo;
|
||||
|
||||
|
||||
/**
|
||||
* The provider that corresponds to this resolution match, if this
|
||||
* resolution is for a provider. Exactly one of {@link #activityInfo},
|
||||
* {@link #serviceInfo}, or {@link #providerInfo} will be non-null.
|
||||
*/
|
||||
public ProviderInfo providerInfo;
|
||||
|
||||
/**
|
||||
* The IntentFilter that was matched for this ResolveInfo.
|
||||
*/
|
||||
@ -120,6 +131,13 @@ public class ResolveInfo implements Parcelable {
|
||||
*/
|
||||
public boolean system;
|
||||
|
||||
private ComponentInfo getComponentInfo() {
|
||||
if (activityInfo != null) return activityInfo;
|
||||
if (serviceInfo != null) return serviceInfo;
|
||||
if (providerInfo != null) return providerInfo;
|
||||
throw new IllegalStateException("Missing ComponentInfo!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current textual label associated with this resolution. This
|
||||
* will call back on the given PackageManager to load the label from
|
||||
@ -142,7 +160,7 @@ public class ResolveInfo implements Parcelable {
|
||||
return label.toString().trim();
|
||||
}
|
||||
}
|
||||
ComponentInfo ci = activityInfo != null ? activityInfo : serviceInfo;
|
||||
ComponentInfo ci = getComponentInfo();
|
||||
ApplicationInfo ai = ci.applicationInfo;
|
||||
if (labelRes != 0) {
|
||||
label = pm.getText(ci.packageName, labelRes, ai);
|
||||
@ -176,7 +194,7 @@ public class ResolveInfo implements Parcelable {
|
||||
return dr;
|
||||
}
|
||||
}
|
||||
ComponentInfo ci = activityInfo != null ? activityInfo : serviceInfo;
|
||||
ComponentInfo ci = getComponentInfo();
|
||||
ApplicationInfo ai = ci.applicationInfo;
|
||||
if (icon != 0) {
|
||||
dr = pm.getDrawable(ci.packageName, icon, ai);
|
||||
@ -196,8 +214,8 @@ public class ResolveInfo implements Parcelable {
|
||||
*/
|
||||
public final int getIconResource() {
|
||||
if (icon != 0) return icon;
|
||||
if (activityInfo != null) return activityInfo.getIconResource();
|
||||
if (serviceInfo != null) return serviceInfo.getIconResource();
|
||||
final ComponentInfo ci = getComponentInfo();
|
||||
if (ci != null) return ci.getIconResource();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -225,6 +243,9 @@ public class ResolveInfo implements Parcelable {
|
||||
} else if (serviceInfo != null) {
|
||||
pw.println(prefix + "ServiceInfo:");
|
||||
serviceInfo.dump(pw, prefix + " ");
|
||||
} else if (providerInfo != null) {
|
||||
pw.println(prefix + "ProviderInfo:");
|
||||
providerInfo.dump(pw, prefix + " ");
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,6 +255,7 @@ public class ResolveInfo implements Parcelable {
|
||||
public ResolveInfo(ResolveInfo orig) {
|
||||
activityInfo = orig.activityInfo;
|
||||
serviceInfo = orig.serviceInfo;
|
||||
providerInfo = orig.providerInfo;
|
||||
filter = orig.filter;
|
||||
priority = orig.priority;
|
||||
preferredOrder = orig.preferredOrder;
|
||||
@ -247,7 +269,7 @@ public class ResolveInfo implements Parcelable {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
ComponentInfo ci = activityInfo != null ? activityInfo : serviceInfo;
|
||||
final ComponentInfo ci = getComponentInfo();
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
sb.append("ResolveInfo{");
|
||||
sb.append(Integer.toHexString(System.identityHashCode(this)));
|
||||
@ -278,6 +300,9 @@ public class ResolveInfo implements Parcelable {
|
||||
} else if (serviceInfo != null) {
|
||||
dest.writeInt(2);
|
||||
serviceInfo.writeToParcel(dest, parcelableFlags);
|
||||
} else if (providerInfo != null) {
|
||||
dest.writeInt(3);
|
||||
providerInfo.writeToParcel(dest, parcelableFlags);
|
||||
} else {
|
||||
dest.writeInt(0);
|
||||
}
|
||||
@ -309,18 +334,21 @@ public class ResolveInfo implements Parcelable {
|
||||
};
|
||||
|
||||
private ResolveInfo(Parcel source) {
|
||||
activityInfo = null;
|
||||
serviceInfo = null;
|
||||
providerInfo = null;
|
||||
switch (source.readInt()) {
|
||||
case 1:
|
||||
activityInfo = ActivityInfo.CREATOR.createFromParcel(source);
|
||||
serviceInfo = null;
|
||||
break;
|
||||
case 2:
|
||||
serviceInfo = ServiceInfo.CREATOR.createFromParcel(source);
|
||||
activityInfo = null;
|
||||
break;
|
||||
case 3:
|
||||
providerInfo = ProviderInfo.CREATOR.createFromParcel(source);
|
||||
break;
|
||||
default:
|
||||
activityInfo = null;
|
||||
serviceInfo = null;
|
||||
Slog.w(TAG, "Missing ComponentInfo!");
|
||||
break;
|
||||
}
|
||||
if (source.readInt() != 0) {
|
||||
|
@ -70,8 +70,14 @@ public final class DocumentsContract {
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
@Deprecated
|
||||
public static final String META_DATA_DOCUMENT_PROVIDER = "android.content.DOCUMENT_PROVIDER";
|
||||
|
||||
/**
|
||||
* Intent action used to identify {@link DocumentsProvider} instances.
|
||||
*/
|
||||
public static final String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER";
|
||||
|
||||
/** {@hide} */
|
||||
public static final String ACTION_MANAGE_ROOT = "android.provider.action.MANAGE_ROOT";
|
||||
/** {@hide} */
|
||||
|
@ -21,9 +21,11 @@ import static com.android.documentsui.DocumentsActivity.TAG;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.database.ContentObserver;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
@ -158,6 +160,9 @@ public class RootsCache {
|
||||
private class UpdateTask extends AsyncTask<Void, Void, Void> {
|
||||
private final String mFilterPackage;
|
||||
|
||||
private final Multimap<String, RootInfo> mTaskRoots = ArrayListMultimap.create();
|
||||
private final HashSet<String> mTaskStoppedAuthorities = Sets.newHashSet();
|
||||
|
||||
/**
|
||||
* Update all roots.
|
||||
*/
|
||||
@ -177,54 +182,64 @@ public class RootsCache {
|
||||
protected Void doInBackground(Void... params) {
|
||||
final long start = SystemClock.elapsedRealtime();
|
||||
|
||||
final Multimap<String, RootInfo> roots = ArrayListMultimap.create();
|
||||
final HashSet<String> stoppedAuthorities = Sets.newHashSet();
|
||||
|
||||
roots.put(mRecentsRoot.authority, mRecentsRoot);
|
||||
mTaskRoots.put(mRecentsRoot.authority, mRecentsRoot);
|
||||
|
||||
final ContentResolver resolver = mContext.getContentResolver();
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
final List<ProviderInfo> providers = pm.queryContentProviders(
|
||||
|
||||
// Pick up provider with action string
|
||||
final Intent intent = new Intent(DocumentsContract.PROVIDER_INTERFACE);
|
||||
final List<ResolveInfo> providers = pm.queryIntentContentProviders(intent, 0);
|
||||
for (ResolveInfo info : providers) {
|
||||
handleDocumentsProvider(info.providerInfo);
|
||||
}
|
||||
|
||||
// Pick up legacy providers
|
||||
final List<ProviderInfo> legacyProviders = pm.queryContentProviders(
|
||||
null, -1, PackageManager.GET_META_DATA);
|
||||
for (ProviderInfo info : providers) {
|
||||
for (ProviderInfo info : legacyProviders) {
|
||||
if (info.metaData != null && info.metaData.containsKey(
|
||||
DocumentsContract.META_DATA_DOCUMENT_PROVIDER)) {
|
||||
// Ignore stopped packages for now; we might query them
|
||||
// later during UI interaction.
|
||||
if ((info.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) {
|
||||
if (LOGD) Log.d(TAG, "Ignoring stopped authority " + info.authority);
|
||||
stoppedAuthorities.add(info.authority);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try using cached roots if filtering
|
||||
boolean cacheHit = false;
|
||||
if (mFilterPackage != null && !mFilterPackage.equals(info.packageName)) {
|
||||
synchronized (mLock) {
|
||||
if (roots.putAll(info.authority, mRoots.get(info.authority))) {
|
||||
if (LOGD) Log.d(TAG, "Used cached roots for " + info.authority);
|
||||
cacheHit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cache miss, or loading everything
|
||||
if (!cacheHit) {
|
||||
roots.putAll(
|
||||
info.authority, loadRootsForAuthority(resolver, info.authority));
|
||||
}
|
||||
handleDocumentsProvider(info);
|
||||
}
|
||||
}
|
||||
|
||||
final long delta = SystemClock.elapsedRealtime() - start;
|
||||
Log.d(TAG, "Update found " + roots.size() + " roots in " + delta + "ms");
|
||||
Log.d(TAG, "Update found " + mTaskRoots.size() + " roots in " + delta + "ms");
|
||||
synchronized (mLock) {
|
||||
mStoppedAuthorities = stoppedAuthorities;
|
||||
mRoots = roots;
|
||||
mRoots = mTaskRoots;
|
||||
mStoppedAuthorities = mTaskStoppedAuthorities;
|
||||
}
|
||||
mFirstLoad.countDown();
|
||||
return null;
|
||||
}
|
||||
|
||||
private void handleDocumentsProvider(ProviderInfo info) {
|
||||
// Ignore stopped packages for now; we might query them
|
||||
// later during UI interaction.
|
||||
if ((info.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) {
|
||||
if (LOGD) Log.d(TAG, "Ignoring stopped authority " + info.authority);
|
||||
mTaskStoppedAuthorities.add(info.authority);
|
||||
return;
|
||||
}
|
||||
|
||||
// Try using cached roots if filtering
|
||||
boolean cacheHit = false;
|
||||
if (mFilterPackage != null && !mFilterPackage.equals(info.packageName)) {
|
||||
synchronized (mLock) {
|
||||
if (mTaskRoots.putAll(info.authority, mRoots.get(info.authority))) {
|
||||
if (LOGD) Log.d(TAG, "Used cached roots for " + info.authority);
|
||||
cacheHit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cache miss, or loading everything
|
||||
if (!cacheHit) {
|
||||
mTaskRoots.putAll(info.authority,
|
||||
loadRootsForAuthority(mContext.getContentResolver(), info.authority));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -11,9 +11,9 @@
|
||||
android:grantUriPermissions="true"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.MANAGE_DOCUMENTS">
|
||||
<meta-data
|
||||
android:name="android.content.DOCUMENT_PROVIDER"
|
||||
android:value="true" />
|
||||
<intent-filter>
|
||||
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
|
||||
</intent-filter>
|
||||
</provider>
|
||||
|
||||
<!-- TODO: find a better place for tests to live -->
|
||||
@ -24,9 +24,9 @@
|
||||
android:exported="true"
|
||||
android:permission="android.permission.MANAGE_DOCUMENTS"
|
||||
android:enabled="false">
|
||||
<meta-data
|
||||
android:name="android.content.DOCUMENT_PROVIDER"
|
||||
android:value="true" />
|
||||
<intent-filter>
|
||||
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
|
||||
</intent-filter>
|
||||
</provider>
|
||||
</application>
|
||||
</manifest>
|
||||
|
@ -383,13 +383,12 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
// All available services, for your resolving pleasure.
|
||||
final ServiceIntentResolver mServices = new ServiceIntentResolver();
|
||||
|
||||
// Keys are String (provider class name), values are Provider.
|
||||
final HashMap<ComponentName, PackageParser.Provider> mProvidersByComponent =
|
||||
new HashMap<ComponentName, PackageParser.Provider>();
|
||||
// All available providers, for your resolving pleasure.
|
||||
final ProviderIntentResolver mProviders = new ProviderIntentResolver();
|
||||
|
||||
// Mapping from provider base names (first directory in content URI codePath)
|
||||
// to the provider information.
|
||||
final HashMap<String, PackageParser.Provider> mProviders =
|
||||
final HashMap<String, PackageParser.Provider> mProvidersByAuthority =
|
||||
new HashMap<String, PackageParser.Provider>();
|
||||
|
||||
// Mapping from instrumentation class names to info about them.
|
||||
@ -2095,7 +2094,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
if (!sUserManager.exists(userId)) return null;
|
||||
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get provider info");
|
||||
synchronized (mPackages) {
|
||||
PackageParser.Provider p = mProvidersByComponent.get(component);
|
||||
PackageParser.Provider p = mProviders.mProviders.get(component);
|
||||
if (DEBUG_PACKAGE_INFO) Log.v(
|
||||
TAG, "getProviderInfo " + component + ": " + p);
|
||||
if (p != null && mSettings.isEnabledLPr(p.info, flags, userId)) {
|
||||
@ -3120,6 +3119,43 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ResolveInfo> queryIntentContentProviders(
|
||||
Intent intent, String resolvedType, int flags, int userId) {
|
||||
if (!sUserManager.exists(userId)) return Collections.emptyList();
|
||||
ComponentName comp = intent.getComponent();
|
||||
if (comp == null) {
|
||||
if (intent.getSelector() != null) {
|
||||
intent = intent.getSelector();
|
||||
comp = intent.getComponent();
|
||||
}
|
||||
}
|
||||
if (comp != null) {
|
||||
final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
|
||||
final ProviderInfo pi = getProviderInfo(comp, flags, userId);
|
||||
if (pi != null) {
|
||||
final ResolveInfo ri = new ResolveInfo();
|
||||
ri.providerInfo = pi;
|
||||
list.add(ri);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
// reader
|
||||
synchronized (mPackages) {
|
||||
String pkgName = intent.getPackage();
|
||||
if (pkgName == null) {
|
||||
return mProviders.queryIntent(intent, resolvedType, flags, userId);
|
||||
}
|
||||
final PackageParser.Package pkg = mPackages.get(pkgName);
|
||||
if (pkg != null) {
|
||||
return mProviders.queryIntentForPackage(
|
||||
intent, resolvedType, flags, pkg.providers, userId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
|
||||
final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
|
||||
@ -3293,7 +3329,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
if (!sUserManager.exists(userId)) return null;
|
||||
// reader
|
||||
synchronized (mPackages) {
|
||||
final PackageParser.Provider provider = mProviders.get(name);
|
||||
final PackageParser.Provider provider = mProvidersByAuthority.get(name);
|
||||
PackageSetting ps = provider != null
|
||||
? mSettings.mPackages.get(provider.owner.packageName)
|
||||
: null;
|
||||
@ -3314,8 +3350,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
public void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo) {
|
||||
// reader
|
||||
synchronized (mPackages) {
|
||||
final Iterator<Map.Entry<String, PackageParser.Provider>> i = mProviders.entrySet()
|
||||
.iterator();
|
||||
final Iterator<Map.Entry<String, PackageParser.Provider>> i = mProvidersByAuthority
|
||||
.entrySet().iterator();
|
||||
final int userId = UserHandle.getCallingUserId();
|
||||
while (i.hasNext()) {
|
||||
Map.Entry<String, PackageParser.Provider> entry = i.next();
|
||||
@ -3341,7 +3377,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
ArrayList<ProviderInfo> finalList = null;
|
||||
// reader
|
||||
synchronized (mPackages) {
|
||||
final Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator();
|
||||
final Iterator<PackageParser.Provider> i = mProviders.mProviders.values().iterator();
|
||||
final int userId = processName != null ?
|
||||
UserHandle.getUserId(uid) : UserHandle.getCallingUserId();
|
||||
while (i.hasNext()) {
|
||||
@ -4313,8 +4349,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
if (p.info.authority != null) {
|
||||
String names[] = p.info.authority.split(";");
|
||||
for (int j = 0; j < names.length; j++) {
|
||||
if (mProviders.containsKey(names[j])) {
|
||||
PackageParser.Provider other = mProviders.get(names[j]);
|
||||
if (mProvidersByAuthority.containsKey(names[j])) {
|
||||
PackageParser.Provider other = mProvidersByAuthority.get(names[j]);
|
||||
Slog.w(TAG, "Can't install because provider name " + names[j] +
|
||||
" (in package " + pkg.applicationInfo.packageName +
|
||||
") is already used by "
|
||||
@ -4745,8 +4781,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
PackageParser.Provider p = pkg.providers.get(i);
|
||||
p.info.processName = fixProcessName(pkg.applicationInfo.processName,
|
||||
p.info.processName, pkg.applicationInfo.uid);
|
||||
mProvidersByComponent.put(new ComponentName(p.info.packageName,
|
||||
p.info.name), p);
|
||||
mProviders.addProvider(p);
|
||||
p.syncable = p.info.isSyncable;
|
||||
if (p.info.authority != null) {
|
||||
String names[] = p.info.authority.split(";");
|
||||
@ -4763,8 +4798,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
p = new PackageParser.Provider(p);
|
||||
p.syncable = false;
|
||||
}
|
||||
if (!mProviders.containsKey(names[j])) {
|
||||
mProviders.put(names[j], p);
|
||||
if (!mProvidersByAuthority.containsKey(names[j])) {
|
||||
mProvidersByAuthority.put(names[j], p);
|
||||
if (p.info.authority == null) {
|
||||
p.info.authority = names[j];
|
||||
} else {
|
||||
@ -4777,7 +4812,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
+ p.info.isSyncable);
|
||||
}
|
||||
} else {
|
||||
PackageParser.Provider other = mProviders.get(names[j]);
|
||||
PackageParser.Provider other = mProvidersByAuthority.get(names[j]);
|
||||
Slog.w(TAG, "Skipping provider name " + names[j] +
|
||||
" (in package " + pkg.applicationInfo.packageName +
|
||||
"): name already used by "
|
||||
@ -5108,8 +5143,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
int i;
|
||||
for (i=0; i<N; i++) {
|
||||
PackageParser.Provider p = pkg.providers.get(i);
|
||||
mProvidersByComponent.remove(new ComponentName(p.info.packageName,
|
||||
p.info.name));
|
||||
mProviders.removeProvider(p);
|
||||
if (p.info.authority == null) {
|
||||
|
||||
/* There was another ContentProvider with this authority when
|
||||
@ -5120,8 +5154,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
String names[] = p.info.authority.split(";");
|
||||
for (int j = 0; j < names.length; j++) {
|
||||
if (mProviders.get(names[j]) == p) {
|
||||
mProviders.remove(names[j]);
|
||||
if (mProvidersByAuthority.get(names[j]) == p) {
|
||||
mProvidersByAuthority.remove(names[j]);
|
||||
if (DEBUG_REMOVE) {
|
||||
if (chatty)
|
||||
Log.d(TAG, "Unregistered content provider: " + names[j]
|
||||
@ -5962,6 +5996,195 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
private int mFlags;
|
||||
};
|
||||
|
||||
private final class ProviderIntentResolver
|
||||
extends IntentResolver<PackageParser.ProviderIntentInfo, ResolveInfo> {
|
||||
public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
|
||||
boolean defaultOnly, int userId) {
|
||||
mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
|
||||
return super.queryIntent(intent, resolvedType, defaultOnly, userId);
|
||||
}
|
||||
|
||||
public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
|
||||
int userId) {
|
||||
if (!sUserManager.exists(userId))
|
||||
return null;
|
||||
mFlags = flags;
|
||||
return super.queryIntent(intent, resolvedType,
|
||||
(flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId);
|
||||
}
|
||||
|
||||
public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType,
|
||||
int flags, ArrayList<PackageParser.Provider> packageProviders, int userId) {
|
||||
if (!sUserManager.exists(userId))
|
||||
return null;
|
||||
if (packageProviders == null) {
|
||||
return null;
|
||||
}
|
||||
mFlags = flags;
|
||||
final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
|
||||
final int N = packageProviders.size();
|
||||
ArrayList<PackageParser.ProviderIntentInfo[]> listCut =
|
||||
new ArrayList<PackageParser.ProviderIntentInfo[]>(N);
|
||||
|
||||
ArrayList<PackageParser.ProviderIntentInfo> intentFilters;
|
||||
for (int i = 0; i < N; ++i) {
|
||||
intentFilters = packageProviders.get(i).intents;
|
||||
if (intentFilters != null && intentFilters.size() > 0) {
|
||||
PackageParser.ProviderIntentInfo[] array =
|
||||
new PackageParser.ProviderIntentInfo[intentFilters.size()];
|
||||
intentFilters.toArray(array);
|
||||
listCut.add(array);
|
||||
}
|
||||
}
|
||||
return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId);
|
||||
}
|
||||
|
||||
public final void addProvider(PackageParser.Provider p) {
|
||||
mProviders.put(p.getComponentName(), p);
|
||||
if (DEBUG_SHOW_INFO) {
|
||||
Log.v(TAG, " "
|
||||
+ (p.info.nonLocalizedLabel != null
|
||||
? p.info.nonLocalizedLabel : p.info.name) + ":");
|
||||
Log.v(TAG, " Class=" + p.info.name);
|
||||
}
|
||||
final int NI = p.intents.size();
|
||||
int j;
|
||||
for (j = 0; j < NI; j++) {
|
||||
PackageParser.ProviderIntentInfo intent = p.intents.get(j);
|
||||
if (DEBUG_SHOW_INFO) {
|
||||
Log.v(TAG, " IntentFilter:");
|
||||
intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
|
||||
}
|
||||
if (!intent.debugCheck()) {
|
||||
Log.w(TAG, "==> For Provider " + p.info.name);
|
||||
}
|
||||
addFilter(intent);
|
||||
}
|
||||
}
|
||||
|
||||
public final void removeProvider(PackageParser.Provider p) {
|
||||
mProviders.remove(p.getComponentName());
|
||||
if (DEBUG_SHOW_INFO) {
|
||||
Log.v(TAG, " " + (p.info.nonLocalizedLabel != null
|
||||
? p.info.nonLocalizedLabel : p.info.name) + ":");
|
||||
Log.v(TAG, " Class=" + p.info.name);
|
||||
}
|
||||
final int NI = p.intents.size();
|
||||
int j;
|
||||
for (j = 0; j < NI; j++) {
|
||||
PackageParser.ProviderIntentInfo intent = p.intents.get(j);
|
||||
if (DEBUG_SHOW_INFO) {
|
||||
Log.v(TAG, " IntentFilter:");
|
||||
intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
|
||||
}
|
||||
removeFilter(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean allowFilterResult(
|
||||
PackageParser.ProviderIntentInfo filter, List<ResolveInfo> dest) {
|
||||
ProviderInfo filterPi = filter.provider.info;
|
||||
for (int i = dest.size() - 1; i >= 0; i--) {
|
||||
ProviderInfo destPi = dest.get(i).providerInfo;
|
||||
if (destPi.name == filterPi.name
|
||||
&& destPi.packageName == filterPi.packageName) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PackageParser.ProviderIntentInfo[] newArray(int size) {
|
||||
return new PackageParser.ProviderIntentInfo[size];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isFilterStopped(PackageParser.ProviderIntentInfo filter, int userId) {
|
||||
if (!sUserManager.exists(userId))
|
||||
return true;
|
||||
PackageParser.Package p = filter.provider.owner;
|
||||
if (p != null) {
|
||||
PackageSetting ps = (PackageSetting) p.mExtras;
|
||||
if (ps != null) {
|
||||
// System apps are never considered stopped for purposes of
|
||||
// filtering, because there may be no way for the user to
|
||||
// actually re-launch them.
|
||||
return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0
|
||||
&& ps.getStopped(userId);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPackageForFilter(String packageName,
|
||||
PackageParser.ProviderIntentInfo info) {
|
||||
return packageName.equals(info.provider.owner.packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResolveInfo newResult(PackageParser.ProviderIntentInfo filter,
|
||||
int match, int userId) {
|
||||
if (!sUserManager.exists(userId))
|
||||
return null;
|
||||
final PackageParser.ProviderIntentInfo info = filter;
|
||||
if (!mSettings.isEnabledLPr(info.provider.info, mFlags, userId)) {
|
||||
return null;
|
||||
}
|
||||
final PackageParser.Provider provider = info.provider;
|
||||
if (mSafeMode && (provider.info.applicationInfo.flags
|
||||
& ApplicationInfo.FLAG_SYSTEM) == 0) {
|
||||
return null;
|
||||
}
|
||||
PackageSetting ps = (PackageSetting) provider.owner.mExtras;
|
||||
if (ps == null) {
|
||||
return null;
|
||||
}
|
||||
ProviderInfo pi = PackageParser.generateProviderInfo(provider, mFlags,
|
||||
ps.readUserState(userId), userId);
|
||||
if (pi == null) {
|
||||
return null;
|
||||
}
|
||||
final ResolveInfo res = new ResolveInfo();
|
||||
res.providerInfo = pi;
|
||||
if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) {
|
||||
res.filter = filter;
|
||||
}
|
||||
res.priority = info.getPriority();
|
||||
res.preferredOrder = provider.owner.mPreferredOrder;
|
||||
res.match = match;
|
||||
res.isDefault = info.hasDefault;
|
||||
res.labelRes = info.labelRes;
|
||||
res.nonLocalizedLabel = info.nonLocalizedLabel;
|
||||
res.icon = info.icon;
|
||||
res.system = isSystemApp(res.providerInfo.applicationInfo);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sortResults(List<ResolveInfo> results) {
|
||||
Collections.sort(results, mResolvePrioritySorter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dumpFilter(PrintWriter out, String prefix,
|
||||
PackageParser.ProviderIntentInfo filter) {
|
||||
out.print(prefix);
|
||||
out.print(
|
||||
Integer.toHexString(System.identityHashCode(filter.provider)));
|
||||
out.print(' ');
|
||||
filter.provider.printComponentShortName(out);
|
||||
out.print(" filter ");
|
||||
out.println(Integer.toHexString(System.identityHashCode(filter)));
|
||||
}
|
||||
|
||||
private final HashMap<ComponentName, PackageParser.Provider> mProviders
|
||||
= new HashMap<ComponentName, PackageParser.Provider>();
|
||||
private int mFlags;
|
||||
};
|
||||
|
||||
private static final Comparator<ResolveInfo> mResolvePrioritySorter =
|
||||
new Comparator<ResolveInfo>() {
|
||||
public int compare(ResolveInfo r1, ResolveInfo r2) {
|
||||
@ -10454,6 +10677,11 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) {
|
||||
dumpState.setTitlePrinted(true);
|
||||
}
|
||||
if (mProviders.dump(pw, dumpState.getTitlePrinted() ? "\nProvider Resolver Table:"
|
||||
: "Provider Resolver Table:", " ", packageName,
|
||||
dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) {
|
||||
dumpState.setTitlePrinted(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
|
||||
@ -10498,7 +10726,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
if (dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
|
||||
boolean printedSomething = false;
|
||||
for (PackageParser.Provider p : mProvidersByComponent.values()) {
|
||||
for (PackageParser.Provider p : mProviders.mProviders.values()) {
|
||||
if (packageName != null && !packageName.equals(p.info.packageName)) {
|
||||
continue;
|
||||
}
|
||||
@ -10512,7 +10740,8 @@ public class PackageManagerService extends IPackageManager.Stub {
|
||||
pw.print(" "); pw.println(p.toString());
|
||||
}
|
||||
printedSomething = false;
|
||||
for (Map.Entry<String, PackageParser.Provider> entry : mProviders.entrySet()) {
|
||||
for (Map.Entry<String, PackageParser.Provider> entry :
|
||||
mProvidersByAuthority.entrySet()) {
|
||||
PackageParser.Provider p = entry.getValue();
|
||||
if (packageName != null && !packageName.equals(p.info.packageName)) {
|
||||
continue;
|
||||
|
@ -282,6 +282,18 @@ public class MockPackageManager extends PackageManager {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public List<ResolveInfo> queryIntentContentProvidersAsUser(
|
||||
Intent intent, int flags, int userId) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ResolveInfo> queryIntentContentProviders(Intent intent, int flags) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderInfo resolveContentProvider(String name, int flags) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
Reference in New Issue
Block a user