diff options
| -rw-r--r-- | services/core/java/com/android/server/pm/ComponentResolver.java | 232 | ||||
| -rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerService.java | 8 |
2 files changed, 184 insertions, 56 deletions
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java index 1d556fec31ea..dde9f822ac76 100644 --- a/services/core/java/com/android/server/pm/ComponentResolver.java +++ b/services/core/java/com/android/server/pm/ComponentResolver.java @@ -59,6 +59,9 @@ import com.android.server.IntentResolver; import com.android.server.pm.parsing.PackageInfoUtils; import com.android.server.pm.parsing.PackageInfoUtils.CachedApplicationInfoGenerator; import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.utils.Snappable; +import com.android.server.utils.SnapshotCache; +import com.android.server.utils.WatchableImpl; import java.io.PrintWriter; import java.util.ArrayList; @@ -72,12 +75,19 @@ import java.util.Set; import java.util.function.Function; /** Resolves all Android component types [activities, services, providers and receivers]. */ -public class ComponentResolver { +public class ComponentResolver + extends WatchableImpl + implements Snappable { private static final boolean DEBUG = false; private static final String TAG = "PackageManager"; private static final boolean DEBUG_FILTERS = false; private static final boolean DEBUG_SHOW_INFO = false; + // Convenience function to report that this object has changed. + private void onChanged() { + dispatchChange(this); + } + /** * The set of all protected actions [i.e. those actions for which a high priority * intent filter is disallowed]. @@ -158,27 +168,27 @@ public class ComponentResolver { * would be able to hold its lock while checking the package setting state.</li> * </ol> */ - private final Object mLock; + private final PackageManagerTracedLock mLock; /** All available activities, for your resolving pleasure. */ @GuardedBy("mLock") - private final ActivityIntentResolver mActivities = new ActivityIntentResolver(); + private final ActivityIntentResolver mActivities; /** All available providers, for your resolving pleasure. */ @GuardedBy("mLock") - private final ProviderIntentResolver mProviders = new ProviderIntentResolver(); + private final ProviderIntentResolver mProviders; /** All available receivers, for your resolving pleasure. */ @GuardedBy("mLock") - private final ActivityIntentResolver mReceivers = new ReceiverIntentResolver(); + private final ReceiverIntentResolver mReceivers; /** All available services, for your resolving pleasure. */ @GuardedBy("mLock") - private final ServiceIntentResolver mServices = new ServiceIntentResolver(); + private final ServiceIntentResolver mServices; /** Mapping from provider authority [first directory in content URI codePath) to provider. */ @GuardedBy("mLock") - private final ArrayMap<String, ParsedProvider> mProvidersByAuthority = new ArrayMap<>(); + private final ArrayMap<String, ParsedProvider> mProvidersByAuthority; /** Whether or not processing protected filters should be deferred. */ private boolean mDeferProtectedFilters = true; @@ -200,12 +210,57 @@ public class ComponentResolver { ComponentResolver(UserManagerService userManager, PackageManagerInternal packageManagerInternal, - Object lock) { + PackageManagerTracedLock lock) { sPackageManagerInternal = packageManagerInternal; sUserManager = userManager; mLock = lock; + + mActivities = new ActivityIntentResolver(); + mProviders = new ProviderIntentResolver(); + mReceivers = new ReceiverIntentResolver(); + mServices = new ServiceIntentResolver(); + mProvidersByAuthority = new ArrayMap<>(); + mDeferProtectedFilters = true; + + mSnapshot = new SnapshotCache<ComponentResolver>(this, this) { + @Override + public ComponentResolver createSnapshot() { + return new ComponentResolver(mSource); + }}; + } + + // Copy constructor used in creating snapshots. + private ComponentResolver(ComponentResolver orig) { + // Do not set the static variables that are set in the default constructor. Do + // create a new object for the lock. The snapshot is read-only, so a lock is not + // strictly required. However, the current code is simpler if the lock exists, + // but does not contend with any outside class. + // TODO: make the snapshot lock-free + mLock = new PackageManagerTracedLock(); + + mActivities = new ActivityIntentResolver(orig.mActivities); + mProviders = new ProviderIntentResolver(orig.mProviders); + mReceivers = new ReceiverIntentResolver(orig.mReceivers); + mServices = new ServiceIntentResolver(orig.mServices); + mProvidersByAuthority = new ArrayMap<>(orig.mProvidersByAuthority); + mDeferProtectedFilters = orig.mDeferProtectedFilters; + mProtectedFilters = (mProtectedFilters == null) + ? null + : new ArrayList<>(orig.mProtectedFilters); + + mSnapshot = null; } + final SnapshotCache<ComponentResolver> mSnapshot; + + /** + * Create a snapshot. + */ + public ComponentResolver snapshot() { + return mSnapshot.snapshot(); + } + + /** Returns the given activity */ @Nullable @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) @@ -474,6 +529,7 @@ public class ComponentResolver { addReceiversLocked(pkg, chatty); addProvidersLocked(pkg, chatty); addServicesLocked(pkg, chatty); + onChanged(); } // expect single setupwizard package final String setupWizardPackage = ArrayUtils.firstOrNull( @@ -489,6 +545,7 @@ public class ComponentResolver { final List<ParsedActivity> systemActivities = disabledPkg != null ? disabledPkg.getActivities() : null; adjustPriority(systemActivities, pair.first, pair.second, setupWizardPackage); + onChanged(); } } @@ -496,6 +553,7 @@ public class ComponentResolver { void removeAllComponents(AndroidPackage pkg, boolean chatty) { synchronized (mLock) { removeAllComponentsLocked(pkg, chatty); + onChanged(); } } @@ -504,51 +562,54 @@ public class ComponentResolver { * all of the filters defined on the /system partition and know the special components. */ void fixProtectedFilterPriorities() { - if (!mDeferProtectedFilters) { - return; - } - mDeferProtectedFilters = false; + synchronized (mLock) { + if (!mDeferProtectedFilters) { + return; + } + mDeferProtectedFilters = false; - if (mProtectedFilters == null || mProtectedFilters.size() == 0) { - return; - } - final List<Pair<ParsedMainComponent, ParsedIntentInfo>> protectedFilters = - mProtectedFilters; - mProtectedFilters = null; + if (mProtectedFilters == null || mProtectedFilters.size() == 0) { + return; + } + final List<Pair<ParsedMainComponent, ParsedIntentInfo>> protectedFilters = + mProtectedFilters; + mProtectedFilters = null; - // expect single setupwizard package - final String setupWizardPackage = ArrayUtils.firstOrNull( + // expect single setupwizard package + final String setupWizardPackage = ArrayUtils.firstOrNull( sPackageManagerInternal.getKnownPackageNames( - PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM)); - - if (DEBUG_FILTERS && setupWizardPackage == null) { - Slog.i(TAG, "No setup wizard;" - + " All protected intents capped to priority 0"); - } - for (int i = protectedFilters.size() - 1; i >= 0; --i) { - final Pair<ParsedMainComponent, ParsedIntentInfo> pair = protectedFilters.get(i); - ParsedMainComponent component = pair.first; - ParsedIntentInfo filter = pair.second; - String packageName = component.getPackageName(); - String className = component.getClassName(); - if (packageName.equals(setupWizardPackage)) { + PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM)); + + if (DEBUG_FILTERS && setupWizardPackage == null) { + Slog.i(TAG, "No setup wizard;" + + " All protected intents capped to priority 0"); + } + for (int i = protectedFilters.size() - 1; i >= 0; --i) { + final Pair<ParsedMainComponent, ParsedIntentInfo> pair = protectedFilters.get(i); + ParsedMainComponent component = pair.first; + ParsedIntentInfo filter = pair.second; + String packageName = component.getPackageName(); + String className = component.getClassName(); + if (packageName.equals(setupWizardPackage)) { + if (DEBUG_FILTERS) { + Slog.i(TAG, "Found setup wizard;" + + " allow priority " + filter.getPriority() + ";" + + " package: " + packageName + + " activity: " + className + + " priority: " + filter.getPriority()); + } + // skip setup wizard; allow it to keep the high priority filter + continue; + } if (DEBUG_FILTERS) { - Slog.i(TAG, "Found setup wizard;" - + " allow priority " + filter.getPriority() + ";" + Slog.i(TAG, "Protected action; cap priority to 0;" + " package: " + packageName + " activity: " + className - + " priority: " + filter.getPriority()); + + " origPrio: " + filter.getPriority()); } - // skip setup wizard; allow it to keep the high priority filter - continue; - } - if (DEBUG_FILTERS) { - Slog.i(TAG, "Protected action; cap priority to 0;" - + " package: " + packageName - + " activity: " + className - + " origPrio: " + filter.getPriority()); + filter.setPriority(0); } - filter.setPriority(0); + onChanged(); } } @@ -1181,9 +1242,20 @@ public class ComponentResolver { private abstract static class MimeGroupsAwareIntentResolver<F extends Pair<? extends ParsedComponent, ParsedIntentInfo>, R> extends IntentResolver<F, R> { - private ArrayMap<String, F[]> mMimeGroupToFilter = new ArrayMap<>(); + private final ArrayMap<String, F[]> mMimeGroupToFilter = new ArrayMap<>(); private boolean mIsUpdatingMimeGroup = false; + // Default constructor + MimeGroupsAwareIntentResolver() { + } + + // Copy constructor used in creating snapshots + MimeGroupsAwareIntentResolver(MimeGroupsAwareIntentResolver<F, R> orig) { + copyFrom(orig); + copyInto(mMimeGroupToFilter, orig.mMimeGroupToFilter); + mIsUpdatingMimeGroup = orig.mIsUpdatingMimeGroup; + } + @Override public void addFilter(F f) { IntentFilter intentFilter = getIntentFilter(f); @@ -1282,6 +1354,17 @@ public class ComponentResolver { private static class ActivityIntentResolver extends MimeGroupsAwareIntentResolver<Pair<ParsedActivity, ParsedIntentInfo>, ResolveInfo> { + // Default constructor + ActivityIntentResolver() { + } + + // Copy constructor used in creating snapshots + ActivityIntentResolver(ActivityIntentResolver orig) { + super(orig); + mActivities.putAll(orig.mActivities); + mFlags = orig.mFlags; + } + @Override public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) { @@ -1330,7 +1413,7 @@ public class ComponentResolver { return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId); } - private void addActivity(ParsedActivity a, String type, + protected void addActivity(ParsedActivity a, String type, List<Pair<ParsedActivity, ParsedIntentInfo>> newIntents) { mActivities.put(a.getComponentName(), a); if (DEBUG_SHOW_INFO) { @@ -1354,7 +1437,7 @@ public class ComponentResolver { } } - private void removeActivity(ParsedActivity a, String type) { + protected void removeActivity(ParsedActivity a, String type) { mActivities.remove(a.getComponentName()); if (DEBUG_SHOW_INFO) { Log.v(TAG, " " + type + ":"); @@ -1567,8 +1650,11 @@ public class ComponentResolver { return pkg.getActivities(); } - // Keys are String (activity class name), values are Activity. - private final ArrayMap<ComponentName, ParsedActivity> mActivities = + // Keys are String (activity class name), values are Activity. This attribute is + // protected because it is accessed directly from ComponentResolver. That works + // even if the attribute is private, but fails for subclasses of + // ActivityIntentResolver. + protected final ArrayMap<ComponentName, ParsedActivity> mActivities = new ArrayMap<>(); private int mFlags; } @@ -1576,6 +1662,15 @@ public class ComponentResolver { // Both receivers and activities share a class, but point to different get methods private static final class ReceiverIntentResolver extends ActivityIntentResolver { + // Default constructor + ReceiverIntentResolver() { + } + + // Copy constructor used in creating snapshots + ReceiverIntentResolver(ReceiverIntentResolver orig) { + super(orig); + } + @Override protected List<ParsedActivity> getResolveList(AndroidPackage pkg) { return pkg.getReceivers(); @@ -1584,6 +1679,17 @@ public class ComponentResolver { private static final class ProviderIntentResolver extends MimeGroupsAwareIntentResolver<Pair<ParsedProvider, ParsedIntentInfo>, ResolveInfo> { + // Default constructor + ProviderIntentResolver() { + } + + // Copy constructor used in creating snapshots + ProviderIntentResolver(ProviderIntentResolver orig) { + super(orig); + mProviders.putAll(orig.mProviders); + mFlags = orig.mFlags; + } + @Override public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) { @@ -1829,6 +1935,17 @@ public class ComponentResolver { private static final class ServiceIntentResolver extends MimeGroupsAwareIntentResolver<Pair<ParsedService, ParsedIntentInfo>, ResolveInfo> { + // Default constructor + ServiceIntentResolver() { + } + + // Copy constructor used in creating snapshots + ServiceIntentResolver(ServiceIntentResolver orig) { + copyFrom(orig); + mServices.putAll(orig.mServices); + mFlags = orig.mFlags; + } + @Override public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) { @@ -2213,11 +2330,16 @@ public class ComponentResolver { * @return true if any intent filters were changed due to this update */ boolean updateMimeGroup(String packageName, String group) { - boolean hasChanges = mActivities.updateMimeGroup(packageName, group); - hasChanges |= mProviders.updateMimeGroup(packageName, group); - hasChanges |= mReceivers.updateMimeGroup(packageName, group); - hasChanges |= mServices.updateMimeGroup(packageName, group); - + boolean hasChanges = false; + synchronized (mLock) { + hasChanges |= mActivities.updateMimeGroup(packageName, group); + hasChanges |= mProviders.updateMimeGroup(packageName, group); + hasChanges |= mReceivers.updateMimeGroup(packageName, group); + hasChanges |= mServices.updateMimeGroup(packageName, group); + if (hasChanges) { + onChanged(); + } + } return hasChanges; } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 95a2ae6c13f5..2b2205abbe74 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1481,7 +1481,9 @@ public class PackageManagerService extends IPackageManager.Stub // Internal interface for permission manager private final PermissionManagerServiceInternal mPermissionManager; + @Watched private final ComponentResolver mComponentResolver; + // List of packages names to keep cached, even if they are uninstalled for all users private List<String> mKeepUninstalledPackages; @@ -1854,6 +1856,7 @@ public class PackageManagerService extends IPackageManager.Stub public final ApplicationInfo androidApplication; public final String appPredictionServicePackage; public final AppsFilter appsFilter; + public final ComponentResolver componentResolver; public final PackageManagerService service; Snapshot(int type) { @@ -1879,6 +1882,7 @@ public class PackageManagerService extends IPackageManager.Stub : new ApplicationInfo(mAndroidApplication); appPredictionServicePackage = mAppPredictionServicePackage; appsFilter = mAppsFilter.snapshot(); + componentResolver = mComponentResolver.snapshot(); } else if (type == Snapshot.LIVE) { settings = mSettings; isolatedOwners = mIsolatedOwners; @@ -1895,6 +1899,7 @@ public class PackageManagerService extends IPackageManager.Stub androidApplication = mAndroidApplication; appPredictionServicePackage = mAppPredictionServicePackage; appsFilter = mAppsFilter; + componentResolver = mComponentResolver; } else { throw new IllegalArgumentException(); } @@ -2142,6 +2147,7 @@ public class PackageManagerService extends IPackageManager.Stub mInstantAppRegistry = args.instantAppRegistry; mLocalAndroidApplication = args.androidApplication; mAppsFilter = args.appsFilter; + mComponentResolver = args.componentResolver; mAppPredictionServicePackage = args.appPredictionServicePackage; @@ -2152,7 +2158,6 @@ public class PackageManagerService extends IPackageManager.Stub mContext = args.service.mContext; mInjector = args.service.mInjector; mApexManager = args.service.mApexManager; - mComponentResolver = args.service.mComponentResolver; mInstantAppResolverConnection = args.service.mInstantAppResolverConnection; mDefaultAppProvider = args.service.mDefaultAppProvider; mDomainVerificationManager = args.service.mDomainVerificationManager; @@ -6159,6 +6164,7 @@ public class PackageManagerService extends IPackageManager.Stub mInstantAppRegistry.registerObserver(mWatcher); mSettings.registerObserver(mWatcher); mIsolatedOwners.registerObserver(mWatcher); + mComponentResolver.registerObserver(mWatcher); // If neither "build" attribute is true then this may be a mockito test, and verification // can fail as a false positive. Watchable.verifyWatchedAttributes(this, mWatcher, !(mIsEngBuild || mIsUserDebugBuild)); |