From be7a42364904bdc145b75ba88a6822deaba9437c Mon Sep 17 00:00:00 2001 From: Oli Lan Date: Thu, 28 Nov 2019 11:34:21 +0000 Subject: [PATCH] Make ApexManager a singleton. Currently ApexManager is only accessed from PackageManager, but upcoming changes to allow rollback of apex data directories will require RollbackManager to access it as well. (See go/apex-data-directories) Multiple ApexManagers can already be created, but as the class maintains a cache of apex packages, it would be inefficient to have many of them. This change makes ApexManager into a singleton so that PackageManager and RollbackManager can use the same one. Bug: 141148175 Test: atest CtsStagedInstallHostTestCases Change-Id: Id43a20bf94f349c87d50de5dad7c90bee50f39f1 --- .../com/android/server/pm/ApexManager.java | 46 +++++++++++-------- .../server/pm/PackageManagerService.java | 4 +- .../android/server/pm/ApexManagerTest.java | 2 +- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index 1222d9a29baf0..2b4b409f329a2 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -36,6 +36,7 @@ import android.os.Environment; import android.os.RemoteException; import android.os.ServiceManager; import android.sysprop.ApexProperties; +import android.util.Singleton; import android.util.Slog; import com.android.internal.annotations.GuardedBy; @@ -65,22 +66,31 @@ abstract class ApexManager { static final int MATCH_ACTIVE_PACKAGE = 1 << 0; static final int MATCH_FACTORY_PACKAGE = 1 << 1; + private static final Singleton sApexManagerSingleton = + new Singleton() { + @Override + protected ApexManager create() { + if (ApexProperties.updatable().orElse(false)) { + try { + return new ApexManagerImpl(IApexService.Stub.asInterface( + ServiceManager.getServiceOrThrow("apexservice"))); + } catch (ServiceManager.ServiceNotFoundException e) { + throw new IllegalStateException( + "Required service apexservice not available"); + } + } else { + return new ApexManagerFlattenedApex(); + } + } + }; + /** * Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerFlattenedApex} * depending on whether this device supports APEX, i.e. {@link ApexProperties#updatable()} * evaluates to {@code true}. */ - static ApexManager create(Context systemContext) { - if (ApexProperties.updatable().orElse(false)) { - try { - return new ApexManagerImpl(systemContext, IApexService.Stub.asInterface( - ServiceManager.getServiceOrThrow("apexservice"))); - } catch (ServiceManager.ServiceNotFoundException e) { - throw new IllegalStateException("Required service apexservice not available"); - } - } else { - return new ApexManagerFlattenedApex(); - } + static ApexManager getInstance() { + return sApexManagerSingleton.get(); } /** @@ -101,7 +111,7 @@ abstract class ApexManager { */ abstract List getActiveApexInfos(); - abstract void systemReady(); + abstract void systemReady(Context context); /** * Retrieves information about an APEX package. @@ -248,7 +258,6 @@ abstract class ApexManager { @VisibleForTesting static class ApexManagerImpl extends ApexManager { private final IApexService mApexService; - private final Context mContext; private final Object mLock = new Object(); /** * A map from {@code APEX packageName} to the {@Link PackageInfo} generated from the {@code @@ -260,8 +269,7 @@ abstract class ApexManager { @GuardedBy("mLock") private List mAllPackagesCache; - ApexManagerImpl(Context context, IApexService apexService) { - mContext = context; + ApexManagerImpl(IApexService apexService) { mApexService = apexService; } @@ -302,14 +310,14 @@ abstract class ApexManager { } @Override - void systemReady() { - mContext.registerReceiver(new BroadcastReceiver() { + void systemReady(Context context) { + context.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // Post populateAllPackagesCacheIfNeeded to a background thread, since it's // expensive to run it in broadcast handler thread. BackgroundThread.getHandler().post(() -> populateAllPackagesCacheIfNeeded()); - mContext.unregisterReceiver(this); + context.unregisterReceiver(this); } }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); } @@ -643,7 +651,7 @@ abstract class ApexManager { } @Override - void systemReady() { + void systemReady(Context context) { // No-op } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 3d4247e761b5a..fcaf5e1d912a2 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2605,7 +2605,7 @@ public class PackageManagerService extends IPackageManager.Stub mProtectedPackages = new ProtectedPackages(mContext); - mApexManager = ApexManager.create(mContext); + mApexManager = ApexManager.getInstance(); mAppsFilter = mInjector.getAppsFilter(); mDirsToScanAsSystem = new ArrayList<>(); @@ -20371,7 +20371,7 @@ public class PackageManagerService extends IPackageManager.Stub storage.registerListener(mStorageListener); mInstallerService.systemReady(); - mApexManager.systemReady(); + mApexManager.systemReady(mContext); mPackageDexOptimizer.systemReady(); mInjector.getStorageManagerInternal().addExternalStoragePolicy( diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java index 178f38aac0b7f..fb9c68a5b70d2 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java @@ -68,7 +68,7 @@ public class ApexManagerTest { @Before public void setUp() throws RemoteException { mContext = InstrumentationRegistry.getInstrumentation().getContext(); - mApexManager = new ApexManager.ApexManagerImpl(mContext, mApexService); + mApexManager = new ApexManager.ApexManagerImpl(mApexService); } @Test