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
         }