summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt5
-rw-r--r--core/java/android/app/ApplicationPackageManager.java16
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl3
-rw-r--r--core/java/android/content/pm/PackageManager.java18
-rw-r--r--core/java/android/content/pm/PackageParser.java29
-rw-r--r--core/java/android/content/pm/ProviderInfo.java9
-rw-r--r--core/java/android/content/pm/ResolveInfo.java60
-rw-r--r--core/java/android/provider/DocumentsContract.java6
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsCache.java81
-rw-r--r--packages/ExternalStorageProvider/AndroidManifest.xml12
-rwxr-xr-xservices/java/com/android/server/pm/PackageManagerService.java273
-rw-r--r--test-runner/src/android/test/mock/MockPackageManager.java12
12 files changed, 444 insertions, 80 deletions
diff --git a/api/current.txt b/api/current.txt
index 548433e..9251d39 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -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);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 55c6672..b505d4f 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -585,6 +585,22 @@ final class ApplicationPackageManager extends PackageManager {
}
@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) {
try {
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index acd4ffa..267fb2a 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -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
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index b63db8a..8b8c58b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -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&lt;ResolveInfo&gt; 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.
*
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b489ee9..17d13e5 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -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
*/
diff --git a/core/java/android/content/pm/ProviderInfo.java b/core/java/android/content/pm/ProviderInfo.java
index a534176..f6ea058 100644
--- a/core/java/android/content/pm/ProviderInfo.java
+++ b/core/java/android/content/pm/ProviderInfo.java
@@ -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;
}
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index e360e40..1ff41c0 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -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;
* &lt;intent&gt; 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) {
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 631a8d4..1c14c38 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -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} */
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index bad0a96..eb56765 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -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));
+ }
+ }
}
/**
diff --git a/packages/ExternalStorageProvider/AndroidManifest.xml b/packages/ExternalStorageProvider/AndroidManifest.xml
index 7094efc..99a4260 100644
--- a/packages/ExternalStorageProvider/AndroidManifest.xml
+++ b/packages/ExternalStorageProvider/AndroidManifest.xml
@@ -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>
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 4710f17..2a93dfc 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -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)) {
@@ -3121,6 +3120,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;
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 5f944f6..661bd41 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -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();