From e3c00c29c73665e5d8cda458869f09bfce38a7aa Mon Sep 17 00:00:00 2001 From: Patrick Baumann Date: Wed, 19 Feb 2020 17:04:06 -0800 Subject: [PATCH] Cache app enumeration per-package enabled state This change queries PlatformCompat for state on package add and when the state is changed (notified via listener) to avoid expensive transformation to ApplicationInfo and any performance impact PlatformCompat may itself have. Bug: 149768323 Test: atest PackageManagerPerfTests AppEnumerationTests Change-Id: I19d8d0918ca6d0563e86a0c84e07cb2c0202543f --- .../com/android/server/pm/AppsFilter.java | 66 ++++++++++++++++--- .../server/pm/PackageManagerService.java | 2 +- 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index a1250cb8849f9..8cedab174cb99 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -25,6 +25,7 @@ import android.annotation.Nullable; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser; import android.content.pm.parsing.AndroidPackage; import android.content.pm.parsing.ComponentParseUtils; @@ -49,6 +50,7 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.server.FgThread; +import com.android.server.compat.CompatChange; import com.android.server.om.OverlayReferenceMapper; import java.io.PrintWriter; @@ -129,15 +131,25 @@ public class AppsFilter { /** @return true if the feature is enabled for the given package. */ boolean packageIsEnabled(AndroidPackage pkg); + + /** + * Initializes the package enablement state for the given package. This gives opportunity + * to do any expensive operations ahead of the actual checks. + */ + void initializePackageState(String packageName); } - private static class FeatureConfigImpl implements FeatureConfig { + private static class FeatureConfigImpl implements FeatureConfig, CompatChange.ChangeListener { private static final String FILTERING_ENABLED_NAME = "package_query_filtering_enabled"; private final PackageManagerService.Injector mInjector; + private final PackageManagerInternal mPmInternal; private volatile boolean mFeatureEnabled = PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT; + private final ArraySet mDisabledPackages = new ArraySet<>(); - private FeatureConfigImpl(PackageManagerService.Injector injector) { + private FeatureConfigImpl( + PackageManagerInternal pmInternal, PackageManagerService.Injector injector) { + mPmInternal = pmInternal; mInjector = injector; } @@ -156,6 +168,8 @@ public class AppsFilter { } } }); + mInjector.getCompatibility().registerListener( + PackageManager.FILTER_APPLICATION_QUERY, this); } @Override @@ -171,23 +185,55 @@ public class AppsFilter { @Override public boolean packageIsEnabled(AndroidPackage pkg) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "packageIsEnabled"); - final long token = Binder.clearCallingIdentity(); try { - // TODO(b/135203078): Do not use toAppInfo - return mInjector.getCompatibility().isChangeEnabled( - PackageManager.FILTER_APPLICATION_QUERY, pkg.toAppInfoWithoutState()); + return !mDisabledPackages.contains(pkg.getPackageName()); } finally { - Binder.restoreCallingIdentity(token); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } + + private boolean fetchPackageIsEnabled(AndroidPackage pkg) { + final long token = Binder.clearCallingIdentity(); + try { + // TODO(b/135203078): Do not use toAppInfo + final boolean changeEnabled = + mInjector.getCompatibility().isChangeEnabled( + PackageManager.FILTER_APPLICATION_QUERY, + pkg.toAppInfoWithoutState()); + return changeEnabled; + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void onCompatChange(String packageName) { + final AndroidPackage pkg = mPmInternal.getPackage(packageName); + if (pkg == null) { + mDisabledPackages.remove(packageName); + return; + } + boolean enabled = fetchPackageIsEnabled(pkg); + if (enabled) { + mDisabledPackages.remove(packageName); + } else { + mDisabledPackages.add(packageName); + } + } + + @Override + public void initializePackageState(String packageName) { + onCompatChange(packageName); + } } - public static AppsFilter create(PackageManagerService.Injector injector) { + /** Builder method for an AppsFilter */ + public static AppsFilter create( + PackageManagerInternal pms, PackageManagerService.Injector injector) { final boolean forceSystemAppsQueryable = injector.getContext().getResources() .getBoolean(R.bool.config_forceSystemPackagesQueryable); - final FeatureConfig featureConfig = new FeatureConfigImpl(injector); + final FeatureConfig featureConfig = new FeatureConfigImpl(pms, injector); final String[] forcedQueryablePackageNames; if (forceSystemAppsQueryable) { // all system apps already queryable, no need to read and parse individual exceptions @@ -400,6 +446,7 @@ public class AppsFilter { } } mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs); + mFeatureConfig.initializePackageState(newPkgSetting.pkg.getPackageName()); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } @@ -451,6 +498,7 @@ public class AppsFilter { } mOverlayReferenceMapper.removePkg(setting.name); + mFeatureConfig.initializePackageState(setting.pkg.getPackageName()); } /** diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 2a3f7ed628458..dfa61e7da472a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2489,7 +2489,7 @@ public class PackageManagerService extends IPackageManager.Stub new Injector.SystemServiceProducer<>(DisplayManager.class), new Injector.SystemServiceProducer<>(StorageManager.class), new Injector.SystemServiceProducer<>(AppOpsManager.class), - (i, pm) -> AppsFilter.create(i), + (i, pm) -> AppsFilter.create(pm.mPmInternal, i), (i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat")); PackageManagerService m = new PackageManagerService(injector, factoryTest, onlyCore);