Watch ComponentResolver
Bug: 181964615 Make ComponentResolver a watched object, where changes are notified to PackageManagerService. At the same time, make it snappable, since it has state that is changed by PMS. commit. Test: atest * FrameworksServicesTests:AppsFilterTest * FrameworksServicesTests:PackageInstallerSessionTest * FrameworksServicesTests:PackageManagerServiceTest * FrameworksServicesTests:PackageManagerSettingsTests * FrameworksServicesTests:ScanTests * FrameworksServicesTests:UserSystemPackageInstallerTest * PackageManagerServiceBootTest * UserLifecycleTests#startUser * UserLifecycleTests#stopUser * UserLifecycleTests#switchUser * android.appsecurity.cts.EphemeralTest * android.appsecurity.cts.InstantAppUserTest * FrameworksServicesTests:WatcherTest * CtsContentTestCases:IntentFilterTest * CtsDynamicMimeHostTestCases * CtsRoleTestCases Change-Id: Iccf02e4d32170ca91cf0976603a9bfc0b0627303
This commit is contained in:
@@ -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));
|
||||
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 && 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;
|
||||
filter.setPriority(0);
|
||||
}
|
||||
if (DEBUG_FILTERS) {
|
||||
Slog.i(TAG, "Protected action; cap priority to 0;"
|
||||
+ " package: " + packageName
|
||||
+ " activity: " + className
|
||||
+ " origPrio: " + filter.getPriority());
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user