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
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 1222d9a..2b4b409 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.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 @@
static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
static final int MATCH_FACTORY_PACKAGE = 1 << 1;
+ private static final Singleton<ApexManager> sApexManagerSingleton =
+ new Singleton<ApexManager>() {
+ @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 List<ActiveApexInfo> getActiveApexInfos();
- abstract void systemReady();
+ abstract void systemReady(Context context);
/**
* Retrieves information about an APEX package.
@@ -248,7 +258,6 @@
@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 @@
@GuardedBy("mLock")
private List<PackageInfo> mAllPackagesCache;
- ApexManagerImpl(Context context, IApexService apexService) {
- mContext = context;
+ ApexManagerImpl(IApexService apexService) {
mApexService = apexService;
}
@@ -302,14 +310,14 @@
}
@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 @@
}
@Override
- void systemReady() {
+ void systemReady(Context context) {
// No-op
}