Merge "Delaying populating APEX cache until boot is completed."
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index dc990af..d52e237 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -30,6 +30,7 @@
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.File;
@@ -48,7 +49,9 @@
 class ApexManager {
     static final String TAG = "ApexManager";
     private final IApexService mApexService;
-    private final Map<String, PackageInfo> mActivePackagesCache;
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private Map<String, PackageInfo> mActivePackagesCache;
 
     ApexManager() {
         try {
@@ -57,31 +60,35 @@
         } catch (ServiceNotFoundException e) {
             throw new IllegalStateException("Required service apexservice not available");
         }
-        mActivePackagesCache = populateActivePackagesCache();
     }
 
-    @NonNull
-    private Map<String, PackageInfo> populateActivePackagesCache() {
-        try {
-            List<PackageInfo> list = new ArrayList<>();
-            final ApexInfo[] activePkgs = mApexService.getActivePackages();
-            for (ApexInfo ai : activePkgs) {
-                // If the device is using flattened APEX, don't report any APEX
-                // packages since they won't be managed or updated by PackageManager.
-                if ((new File(ai.packagePath)).isDirectory()) {
-                    break;
-                }
-                try {
-                    list.add(PackageParser.generatePackageInfoFromApex(
-                            new File(ai.packagePath), true /* collect certs */));
-                } catch (PackageParserException pe) {
-                    throw new IllegalStateException("Unable to parse: " + ai, pe);
-                }
+    private void populateActivePackagesCacheIfNeeded() {
+        synchronized (mLock) {
+            if (mActivePackagesCache != null) {
+                return;
             }
-            return list.stream().collect(Collectors.toMap(p -> p.packageName, Function.identity()));
-        } catch (RemoteException re) {
-            Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
-            throw new RuntimeException(re);
+            try {
+                List<PackageInfo> list = new ArrayList<>();
+                final ApexInfo[] activePkgs = mApexService.getActivePackages();
+                for (ApexInfo ai : activePkgs) {
+                    // If the device is using flattened APEX, don't report any APEX
+                    // packages since they won't be managed or updated by PackageManager.
+                    if ((new File(ai.packagePath)).isDirectory()) {
+                        break;
+                    }
+                    try {
+                        list.add(PackageParser.generatePackageInfoFromApex(
+                                new File(ai.packagePath), true /* collect certs */));
+                    } catch (PackageParserException pe) {
+                        throw new IllegalStateException("Unable to parse: " + ai, pe);
+                    }
+                }
+                mActivePackagesCache = list.stream().collect(
+                        Collectors.toMap(p -> p.packageName, Function.identity()));
+            } catch (RemoteException re) {
+                Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
+                throw new RuntimeException(re);
+            }
         }
     }
 
@@ -96,6 +103,7 @@
      *         is not found.
      */
     @Nullable PackageInfo getActivePackage(String packageName) {
+        populateActivePackagesCacheIfNeeded();
         return mActivePackagesCache.get(packageName);
     }
 
@@ -106,6 +114,7 @@
      *         active package.
      */
     Collection<PackageInfo> getActivePackages() {
+        populateActivePackagesCacheIfNeeded();
         return mActivePackagesCache.values();
     }
 
@@ -217,7 +226,7 @@
         ipw.println("Active APEX packages:");
         ipw.increaseIndent();
         try {
-            populateActivePackagesCache();
+            populateActivePackagesCacheIfNeeded();
             for (PackageInfo pi : mActivePackagesCache.values()) {
                 if (packageName != null && !packageName.equals(pi.packageName)) {
                     continue;
@@ -254,4 +263,8 @@
             ipw.println("Couldn't communicate with apexd.");
         }
     }
+
+    public void onBootCompleted() {
+        populateActivePackagesCacheIfNeeded();
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index d501c4f..cced0f4 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -209,8 +209,10 @@
         mStagingManager = new StagingManager(pm, this, am);
     }
 
-    private void setBootCompleted()  {
+    private void onBootCompleted()  {
         mBootCompleted = true;
+        // Tell APEX manager about it as well
+        mApexManager.onBootCompleted();
     }
 
     boolean isBootCompleted()  {
@@ -223,7 +225,7 @@
         mContext.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                setBootCompleted();
+                onBootCompleted();
                 mContext.unregisterReceiver(this);
             }
         }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));