Save overlay paths as user state

Instead of maintaining a separate structure just for overlay
paths, store them as user state in the package setting. Also
centralize updating the overlay paths to avoid issues with
inconsistent updates.

Fixes: 36561125
Test: Manual
Change-Id: Iac1c987e8650074dbc564e332d5da1950fad6ac5
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 9b0bab4..fdb0f2ba 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -6852,7 +6852,7 @@
             ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
         }
         ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
-        ai.resourceDirs = state.resourceDirs;
+        ai.resourceDirs = state.overlayPaths;
     }
 
     public static ApplicationInfo generateApplicationInfo(Package p, int flags,
@@ -7000,6 +7000,7 @@
             return null;
         }
         if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) {
+            updateApplicationInfo(a.info.applicationInfo, flags, state);
             return a.info;
         }
         // Make shallow copies so we can store the metadata safely
@@ -7088,6 +7089,7 @@
             return null;
         }
         if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) {
+            updateApplicationInfo(s.info.applicationInfo, flags, state);
             return s.info;
         }
         // Make shallow copies so we can store the metadata safely
@@ -7183,6 +7185,7 @@
         if (!copyNeeded(flags, p.owner, state, p.metaData, userId)
                 && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0
                         || p.info.uriPermissionPatterns == null)) {
+            updateApplicationInfo(p.info.applicationInfo, flags, state);
             return p.info;
         }
         // Make shallow copies so we can store the metadata safely
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 4e53914..470336c 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -55,7 +55,7 @@
     public ArraySet<String> disabledComponents;
     public ArraySet<String> enabledComponents;
 
-    public String[] resourceDirs;
+    public String[] overlayPaths;
 
     public PackageUserState() {
         installed = true;
@@ -83,8 +83,8 @@
         installReason = o.installReason;
         disabledComponents = ArrayUtils.cloneOrNull(o.disabledComponents);
         enabledComponents = ArrayUtils.cloneOrNull(o.enabledComponents);
-        resourceDirs =
-            o.resourceDirs == null ? null : Arrays.copyOf(o.resourceDirs, o.resourceDirs.length);
+        overlayPaths =
+            o.overlayPaths == null ? null : Arrays.copyOf(o.overlayPaths, o.overlayPaths.length);
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e62b107..3bbbde0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -675,13 +675,6 @@
     @GuardedBy("mPackages")
     final SparseIntArray mIsolatedOwners = new SparseIntArray();
 
-    // List of APK paths to load for each user and package. This data is never
-    // persisted by the package manager. Instead, the overlay manager will
-    // ensure the data is up-to-date in runtime.
-    @GuardedBy("mPackages")
-    final SparseArray<ArrayMap<String, ArrayList<String>>> mEnabledOverlayPaths =
-        new SparseArray<ArrayMap<String, ArrayList<String>>>();
-
     /**
      * Tracks new system packages [received in an OTA] that we expect to
      * find updated user-installed versions. Keys are package name, values
@@ -3583,8 +3576,6 @@
             return null;
         }
 
-        rebaseEnabledOverlays(packageInfo.applicationInfo, userId);
-
         packageInfo.packageName = packageInfo.applicationInfo.packageName =
                 resolveExternalPackageNameLPr(p);
 
@@ -4096,7 +4087,6 @@
             ApplicationInfo ai = PackageParser.generateApplicationInfo(ps.pkg, flags,
                     ps.readUserState(userId), userId);
             if (ai != null) {
-                rebaseEnabledOverlays(ai, userId);
                 ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
             }
             return ai;
@@ -4145,7 +4135,6 @@
                 ApplicationInfo ai = PackageParser.generateApplicationInfo(
                         p, flags, ps.readUserState(userId), userId);
                 if (ai != null) {
-                    rebaseEnabledOverlays(ai, userId);
                     ai.packageName = resolveExternalPackageNameLPr(p);
                 }
                 return ai;
@@ -4162,26 +4151,6 @@
         return null;
     }
 
-    private void rebaseEnabledOverlays(@NonNull ApplicationInfo ai, int userId) {
-        List<String> paths = new ArrayList<>();
-        ArrayMap<String, ArrayList<String>> userSpecificOverlays =
-            mEnabledOverlayPaths.get(userId);
-        if (userSpecificOverlays != null) {
-            if (!"android".equals(ai.packageName)) {
-                ArrayList<String> frameworkOverlays = userSpecificOverlays.get("android");
-                if (frameworkOverlays != null) {
-                    paths.addAll(frameworkOverlays);
-                }
-            }
-
-            ArrayList<String> appOverlays = userSpecificOverlays.get(ai.packageName);
-            if (appOverlays != null) {
-                paths.addAll(appOverlays);
-            }
-        }
-        ai.resourceDirs = paths.size() > 0 ? paths.toArray(new String[paths.size()]) : null;
-    }
-
     private String normalizePackageNameLPr(String packageName) {
         String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
         return normalizedPackageName != null ? normalizedPackageName : packageName;
@@ -4566,24 +4535,6 @@
         return updateFlagsForComponent(flags, userId, intent /*cookie*/);
     }
 
-    private ActivityInfo generateActivityInfo(ActivityInfo ai, int flags, PackageUserState state,
-            int userId) {
-        ActivityInfo ret = PackageParser.generateActivityInfo(ai, flags, state, userId);
-        if (ret != null) {
-            rebaseEnabledOverlays(ret.applicationInfo, userId);
-        }
-        return ret;
-    }
-
-    private ActivityInfo generateActivityInfo(PackageParser.Activity a, int flags,
-            PackageUserState state, int userId) {
-        ActivityInfo ai = PackageParser.generateActivityInfo(a, flags, state, userId);
-        if (ai != null) {
-            rebaseEnabledOverlays(ai.applicationInfo, userId);
-        }
-        return ai;
-    }
-
     @Override
     public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
         return getActivityInfoInternal(component, flags, Binder.getCallingUid(), userId);
@@ -4611,11 +4562,12 @@
                 if (filterAppAccessLPr(ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {
                     return null;
                 }
-                return generateActivityInfo(a, flags, ps.readUserState(userId), userId);
+                return PackageParser.generateActivityInfo(
+                        a, flags, ps.readUserState(userId), userId);
             }
             if (mResolveComponentName.equals(component)) {
-                return generateActivityInfo(mResolveActivity, flags, new PackageUserState(),
-                        userId);
+                return PackageParser.generateActivityInfo(
+                        mResolveActivity, flags, new PackageUserState(), userId);
             }
         }
         return null;
@@ -4669,7 +4621,8 @@
                 if (filterAppAccessLPr(ps, callingUid, component, TYPE_RECEIVER, userId)) {
                     return null;
                 }
-                return generateActivityInfo(a, flags, ps.readUserState(userId), userId);
+                return PackageParser.generateActivityInfo(
+                        a, flags, ps.readUserState(userId), userId);
             }
         }
         return null;
@@ -4805,12 +4758,8 @@
                 if (filterAppAccessLPr(ps, callingUid, component, TYPE_SERVICE, userId)) {
                     return null;
                 }
-                ServiceInfo si = PackageParser.generateServiceInfo(s, flags,
-                        ps.readUserState(userId), userId);
-                if (si != null) {
-                    rebaseEnabledOverlays(si.applicationInfo, userId);
-                }
-                return si;
+                return PackageParser.generateServiceInfo(
+                        s, flags, ps.readUserState(userId), userId);
             }
         }
         return null;
@@ -4833,12 +4782,8 @@
                 if (filterAppAccessLPr(ps, callingUid, component, TYPE_PROVIDER, userId)) {
                     return null;
                 }
-                ProviderInfo pi = PackageParser.generateProviderInfo(p, flags,
-                        ps.readUserState(userId), userId);
-                if (pi != null) {
-                    rebaseEnabledOverlays(pi.applicationInfo, userId);
-                }
-                return pi;
+                return PackageParser.generateProviderInfo(
+                        p, flags, ps.readUserState(userId), userId);
             }
         }
         return null;
@@ -8264,7 +8209,6 @@
                         ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags,
                                 ps.readUserState(userId), userId);
                         if (ai != null) {
-                            rebaseEnabledOverlays(ai, userId);
                             ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
                         }
                     } else {
@@ -8291,7 +8235,6 @@
                         ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
                                 ps.readUserState(userId), userId);
                         if (ai != null) {
-                            rebaseEnabledOverlays(ai, userId);
                             ai.packageName = resolveExternalPackageNameLPr(p);
                             list.add(ai);
                         }
@@ -8445,7 +8388,6 @@
                         ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
                                 ps.readUserState(userId), userId);
                         if (ai != null) {
-                            rebaseEnabledOverlays(ai, userId);
                             finalList.add(ai);
                         }
                     }
@@ -13308,7 +13250,8 @@
                 return null;
             }
             final PackageUserState userState = ps.readUserState(userId);
-            ActivityInfo ai = generateActivityInfo(activity, mFlags, userState, userId);
+            ActivityInfo ai =
+                    PackageParser.generateActivityInfo(activity, mFlags, userState, userId);
             if (ai == null) {
                 return null;
             }
@@ -22277,11 +22220,6 @@
                 dumpCompilerStatsLPr(pw, packageName);
             }
 
-            if (!checkin && dumpState.isDumping(DumpState.DUMP_ENABLED_OVERLAYS)) {
-                if (dumpState.onTitlePrinted()) pw.println();
-                dumpEnabledOverlaysLPr(pw);
-            }
-
             if (!checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) {
                 if (dumpState.onTitlePrinted()) pw.println();
                 mSettings.dumpReadMessagesLPr(pw, dumpState);
@@ -22478,23 +22416,6 @@
         }
     }
 
-    private void dumpEnabledOverlaysLPr(PrintWriter pw) {
-        pw.println("Enabled overlay paths:");
-        final int N = mEnabledOverlayPaths.size();
-        for (int i = 0; i < N; i++) {
-            final int userId = mEnabledOverlayPaths.keyAt(i);
-            pw.println(String.format("    User %d:", userId));
-            final ArrayMap<String, ArrayList<String>> userSpecificOverlays =
-                mEnabledOverlayPaths.valueAt(i);
-            final int M = userSpecificOverlays.size();
-            for (int j = 0; j < M; j++) {
-                final String targetPackageName = userSpecificOverlays.keyAt(j);
-                final ArrayList<String> overlayPackagePaths = userSpecificOverlays.valueAt(j);
-                pw.println(String.format("        %s: %s", targetPackageName, overlayPackagePaths));
-            }
-        }
-    }
-
     private String dumpDomainString(String packageName) {
         List<IntentFilterVerificationInfo> iviList = getIntentFilterVerifications(packageName)
                 .getList();
@@ -24669,11 +24590,10 @@
                     Slog.e(TAG, "failed to find package " + targetPackageName);
                     return false;
                 }
-
-                ArrayList<String> paths = null;
-                if (overlayPackageNames != null) {
+                ArrayList<String> overlayPaths = null;
+                if (overlayPackageNames != null && overlayPackageNames.size() > 0) {
                     final int N = overlayPackageNames.size();
-                    paths = new ArrayList<>(N);
+                    overlayPaths = new ArrayList<>(N);
                     for (int i = 0; i < N; i++) {
                         final String packageName = overlayPackageNames.get(i);
                         final PackageParser.Package pkg = mPackages.get(packageName);
@@ -24681,22 +24601,17 @@
                             Slog.e(TAG, "failed to find package " + packageName);
                             return false;
                         }
-                        paths.add(pkg.baseCodePath);
+                        overlayPaths.add(pkg.baseCodePath);
                     }
                 }
 
-                ArrayMap<String, ArrayList<String>> userSpecificOverlays =
-                    mEnabledOverlayPaths.get(userId);
-                if (userSpecificOverlays == null) {
-                    userSpecificOverlays = new ArrayMap<>();
-                    mEnabledOverlayPaths.put(userId, userSpecificOverlays);
+                final PackageSetting ps = mSettings.mPackages.get(targetPackageName);
+                String[] frameworkOverlayPaths = null;
+                if (!"android".equals(targetPackageName)) {
+                    frameworkOverlayPaths =
+                            mSettings.mPackages.get("android").getOverlayPaths(userId);
                 }
-
-                if (paths != null && paths.size() > 0) {
-                    userSpecificOverlays.put(targetPackageName, paths);
-                } else {
-                    userSpecificOverlays.remove(targetPackageName);
-                }
+                ps.setOverlayPaths(overlayPaths, frameworkOverlayPaths, userId);
                 return true;
             }
         }
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 14f65eb..d17267f 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -31,6 +31,7 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.google.android.collect.Lists;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -329,6 +330,27 @@
         modifyUserState(userId).installReason = installReason;
     }
 
+    void setOverlayPaths(List<String> overlayPaths, String[] frameworkOverlayPaths, int userId) {
+        if (overlayPaths == null && frameworkOverlayPaths == null) {
+            modifyUserState(userId).overlayPaths = null;
+            return;
+        }
+        final List<String> paths;
+        if (frameworkOverlayPaths == null) {
+            paths = overlayPaths;
+        } else {
+            paths = Lists.newArrayList(frameworkOverlayPaths);
+            if (overlayPaths != null) {
+                paths.addAll(overlayPaths);
+            }
+        }
+        modifyUserState(userId).overlayPaths = paths.toArray(new String[paths.size()]);
+    }
+
+    String[] getOverlayPaths(int userId) {
+        return readUserState(userId).overlayPaths;
+    }
+
     /** Only use for testing. Do NOT use in production code. */
     @VisibleForTesting
     SparseArray<PackageUserState> getUserState() {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 24cbdbf..b006c2d 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4858,6 +4858,15 @@
             pw.print(ps.getEnabled(user.id));
             pw.print(" instant=");
             pw.println(ps.getInstantApp(user.id));
+
+            String[] overlayPaths = ps.getOverlayPaths(user.id);
+            if (overlayPaths != null && overlayPaths.length > 0) {
+                pw.println("Overlay paths:");
+                for (String path : overlayPaths) {
+                    pw.println(path);
+                }
+            }
+
             String lastDisabledAppCaller = ps.getLastDisabledAppCaller(user.id);
             if (lastDisabledAppCaller != null) {
                 pw.print(prefix); pw.print("    lastDisabledCaller: ");