Add overlayPaths to ApplicationInfo

RROs have historically been APK packages. We now have the ability to
generate RROs on-the-fly. These "fabricated" RROs are not APKs.
ApplicationInfo#resourceDirs documentation states that it only contains
paths to packages. To prevent changing the behavior of resourceDirs
until we can deprecate and remove it, a new overlayPaths field has been
added to ApplicationInfo. This new field contains APK overlay paths as
well as non-APK overlay paths.

Bug: 172471315
Test: boot enable/disable overlays and examine overlays working as well
      as package manager dumpsys
Change-Id: I78c5eeef73b7d8bada61edc0f64a12a3cdc1ce16
diff --git a/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java b/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java
index d3938f4..afd8e29 100644
--- a/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java
+++ b/apct-tests/perftests/core/src/android/app/ResourcesManagerPerfTest.java
@@ -77,7 +77,7 @@
     }
 
     private void getResourcesForPath(String path) {
-        ResourcesManager.getInstance().getResources(null, path, null, null, null,
+        ResourcesManager.getInstance().getResources(null, path, null, null, null, null,
                 Display.DEFAULT_DISPLAY, null, sContext.getResources().getCompatibilityInfo(),
                 null, null);
     }
diff --git a/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java b/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java
index f4c0a17..45c723b 100644
--- a/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java
+++ b/apct-tests/perftests/core/src/android/app/ResourcesThemePerfTest.java
@@ -95,8 +95,9 @@
                 ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
 
         Resources destResources = resourcesManager.getResources(null, ai.sourceDir,
-                ai.splitSourceDirs, ai.resourceDirs, ai.sharedLibraryFiles, Display.DEFAULT_DISPLAY,
-                c, mContext.getResources().getCompatibilityInfo(), null, null);
+                ai.splitSourceDirs, ai.resourceDirs, ai.overlayPaths, ai.sharedLibraryFiles,
+                Display.DEFAULT_DISPLAY, c, mContext.getResources().getCompatibilityInfo(),
+                null, null);
         Assert.assertNotEquals(destResources.getAssets(), mContext.getAssets());
 
         Resources.Theme destTheme = destResources.newTheme();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e5a04c98..0cccbf4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2289,11 +2289,12 @@
      * Creates the top level resources for the given package. Will return an existing
      * Resources if one has already been created.
      */
-    Resources getTopLevelResources(String resDir, String[] splitResDirs, String[] overlayDirs,
-            String[] libDirs, LoadedApk pkgInfo, Configuration overrideConfig) {
-        return mResourcesManager.getResources(null, resDir, splitResDirs, overlayDirs, libDirs,
-                null, overrideConfig, pkgInfo.getCompatibilityInfo(), pkgInfo.getClassLoader(),
-                null);
+    Resources getTopLevelResources(String resDir, String[] splitResDirs, String[] legacyOverlayDirs,
+                    String[] overlayPaths, String[] libDirs, LoadedApk pkgInfo,
+                    Configuration overrideConfig) {
+        return mResourcesManager.getResources(null, resDir, splitResDirs, legacyOverlayDirs,
+                overlayPaths, libDirs, null, overrideConfig, pkgInfo.getCompatibilityInfo(),
+                pkgInfo.getClassLoader(), null);
     }
 
     @UnsupportedAppUsage
@@ -2462,12 +2463,15 @@
     private static boolean isLoadedApkResourceDirsUpToDate(LoadedApk loadedApk,
             ApplicationInfo appInfo) {
         Resources packageResources = loadedApk.mResources;
-        String[] overlayDirs = ArrayUtils.defeatNullable(loadedApk.getOverlayDirs());
-        String[] resourceDirs = ArrayUtils.defeatNullable(appInfo.resourceDirs);
+        boolean resourceDirsUpToDate = Arrays.equals(
+                ArrayUtils.defeatNullable(appInfo.resourceDirs),
+                ArrayUtils.defeatNullable(loadedApk.getOverlayDirs()));
+        boolean overlayPathsUpToDate = Arrays.equals(
+                ArrayUtils.defeatNullable(appInfo.overlayPaths),
+                ArrayUtils.defeatNullable(loadedApk.getOverlayPaths()));
 
         return (packageResources == null || packageResources.getAssets().isUpToDate())
-                && overlayDirs.length == resourceDirs.length
-                && ArrayUtils.containsAll(overlayDirs, resourceDirs);
+                && resourceDirsUpToDate && overlayPathsUpToDate;
     }
 
     @UnsupportedAppUsage
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 8ac9139..062cab4 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1728,7 +1728,7 @@
         final Resources r = mContext.mMainThread.getTopLevelResources(
                 sameUid ? app.sourceDir : app.publicSourceDir,
                 sameUid ? app.splitSourceDirs : app.splitPublicSourceDirs,
-                app.resourceDirs, app.sharedLibraryFiles,
+                app.resourceDirs, app.overlayPaths, app.sharedLibraryFiles,
                 mContext.mPackageInfo, configuration);
         if (r != null) {
             return r;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 4ddeb8f..9a20e0f 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2345,6 +2345,7 @@
                 pi.getResDir(),
                 splitResDirs,
                 pi.getOverlayDirs(),
+                pi.getOverlayPaths(),
                 pi.getApplicationInfo().sharedLibraryFiles,
                 overrideDisplayId,
                 overrideConfig,
@@ -2442,6 +2443,7 @@
                 mPackageInfo.getResDir(),
                 paths,
                 mPackageInfo.getOverlayDirs(),
+                mPackageInfo.getOverlayPaths(),
                 mPackageInfo.getApplicationInfo().sharedLibraryFiles,
                 mForceDisplayOverrideInResources ? getDisplayId() : null,
                 null,
@@ -2558,7 +2560,8 @@
     Resources createWindowContextResources() {
         final String resDir = mPackageInfo.getResDir();
         final String[] splitResDirs = mPackageInfo.getSplitResDirs();
-        final String[] overlayDirs = mPackageInfo.getOverlayDirs();
+        final String[] legacyOverlayDirs = mPackageInfo.getOverlayDirs();
+        final String[] overlayPaths = mPackageInfo.getOverlayPaths();
         final String[] libDirs = mPackageInfo.getApplicationInfo().sharedLibraryFiles;
         final int displayId = getDisplayId();
         final CompatibilityInfo compatInfo = (displayId == Display.DEFAULT_DISPLAY)
@@ -2567,7 +2570,7 @@
         final List<ResourcesLoader> loaders = mResources.getLoaders();
 
         return mResourcesManager.createBaseTokenResources(mToken, resDir, splitResDirs,
-                overlayDirs, libDirs, displayId, null /* overrideConfig */,
+                legacyOverlayDirs, overlayPaths, libDirs, displayId, null /* overrideConfig */,
                 compatInfo, mClassLoader, loaders);
     }
 
@@ -2855,6 +2858,7 @@
                 packageInfo.getResDir(),
                 splitDirs,
                 packageInfo.getOverlayDirs(),
+                packageInfo.getOverlayPaths(),
                 packageInfo.getApplicationInfo().sharedLibraryFiles,
                 displayId,
                 overrideConfiguration,
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index c01b5a3..be426aa 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -113,7 +113,8 @@
     private String mAppDir;
     @UnsupportedAppUsage
     private String mResDir;
-    private String[] mOverlayDirs;
+    private String[] mLegacyOverlayDirs;
+    private String[] mOverlayPaths;
     @UnsupportedAppUsage
     private String mDataDir;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -222,7 +223,8 @@
         mSplitAppDirs = null;
         mSplitResDirs = null;
         mSplitClassLoaderNames = null;
-        mOverlayDirs = null;
+        mLegacyOverlayDirs = null;
+        mOverlayPaths = null;
         mDataDir = null;
         mDataDirFile = null;
         mDeviceProtectedDataDirFile = null;
@@ -364,8 +366,8 @@
                 }
 
                 mResources = ResourcesManager.getInstance().getResources(null, mResDir,
-                        splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles,
-                        null, null, getCompatibilityInfo(),
+                        splitPaths, mLegacyOverlayDirs, mOverlayPaths,
+                        mApplicationInfo.sharedLibraryFiles, null, null, getCompatibilityInfo(),
                         getClassLoader(), mApplication == null ? null
                                 : mApplication.getResources().getLoaders());
             }
@@ -379,7 +381,8 @@
         mApplicationInfo = aInfo;
         mAppDir = aInfo.sourceDir;
         mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir;
-        mOverlayDirs = aInfo.resourceDirs;
+        mLegacyOverlayDirs = aInfo.resourceDirs;
+        mOverlayPaths = aInfo.overlayPaths;
         mDataDir = aInfo.dataDir;
         mLibDir = aInfo.nativeLibraryDir;
         mDataDirFile = FileUtils.newFileOrNull(aInfo.dataDir);
@@ -1213,9 +1216,19 @@
         return mSplitResDirs;
     }
 
+    /**
+     * Corresponds to {@link ApplicationInfo#resourceDirs}.
+     */
     @UnsupportedAppUsage
     public String[] getOverlayDirs() {
-        return mOverlayDirs;
+        return mLegacyOverlayDirs;
+    }
+
+    /**
+     * Corresponds to {@link ApplicationInfo#overlayPaths}.
+     */
+    public String[] getOverlayPaths() {
+        return mOverlayPaths;
     }
 
     public String getDataDir() {
@@ -1252,8 +1265,8 @@
             }
 
             mResources = ResourcesManager.getInstance().getResources(null, mResDir,
-                    splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles,
-                    null, null, getCompatibilityInfo(),
+                    splitPaths, mLegacyOverlayDirs, mOverlayPaths,
+                    mApplicationInfo.sharedLibraryFiles, null, null, getCompatibilityInfo(),
                     getClassLoader(), null);
         }
         return mResources;
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 772833cc..ac8d3a2 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -39,6 +39,7 @@
 import android.os.Process;
 import android.os.Trace;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Pair;
@@ -60,6 +61,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Objects;
 import java.util.WeakHashMap;
@@ -174,8 +176,8 @@
          * based on.
          *
          * @see #activityResources
-         * @see #getResources(IBinder, String, String[], String[], String[], Integer, Configuration,
-         * CompatibilityInfo, ClassLoader, List)
+         * @see #getResources(IBinder, String, String[], String[], String[], String[], Integer,
+         * Configuration, CompatibilityInfo, ClassLoader, List)
          */
         public final Configuration overrideConfig = new Configuration();
 
@@ -482,8 +484,8 @@
             }
         }
 
-        if (key.mOverlayDirs != null) {
-            for (final String idmapPath : key.mOverlayDirs) {
+        if (key.mOverlayPaths != null) {
+            for (final String idmapPath : key.mOverlayPaths) {
                 apkKeys.add(new ApkKey(idmapPath, false /*sharedLib*/, true /*overlay*/));
             }
         }
@@ -783,14 +785,16 @@
 
     /**
      * Creates base resources for a binder token. Calls to
-     * {@link #getResources(IBinder, String, String[], String[], String[], Integer, Configuration,
-     * CompatibilityInfo, ClassLoader, List)} with the same binder token will have their override
-     * configurations merged with the one specified here.
+     *
+     * {@link #getResources(IBinder, String, String[], String[], String[], String[], Integer,
+     * Configuration, CompatibilityInfo, ClassLoader, List)} with the same binder token will have
+     * their override configurations merged with the one specified here.
      *
      * @param token Represents an {@link Activity} or {@link WindowContext}.
      * @param resDir The base resource path. Can be null (only framework resources will be loaded).
      * @param splitResDirs An array of split resource paths. Can be null.
-     * @param overlayDirs An array of overlay paths. Can be null.
+     * @param legacyOverlayDirs An array of overlay APK paths. Can be null.
+     * @param overlayPaths An array of overlay APK and non-APK paths. Can be null.
      * @param libDirs An array of resource library paths. Can be null.
      * @param displayId The ID of the display for which to create the resources.
      * @param overrideConfig The configuration to apply on top of the base configuration. Can be
@@ -804,7 +808,8 @@
     public @Nullable Resources createBaseTokenResources(@NonNull IBinder token,
             @Nullable String resDir,
             @Nullable String[] splitResDirs,
-            @Nullable String[] overlayDirs,
+            @Nullable String[] legacyOverlayDirs,
+            @Nullable String[] overlayPaths,
             @Nullable String[] libDirs,
             int displayId,
             @Nullable Configuration overrideConfig,
@@ -817,7 +822,7 @@
             final ResourcesKey key = new ResourcesKey(
                     resDir,
                     splitResDirs,
-                    overlayDirs,
+                    combinedOverlayPaths(legacyOverlayDirs, overlayPaths),
                     libDirs,
                     displayId,
                     overrideConfig,
@@ -1043,7 +1048,8 @@
      * @param activityToken Represents an Activity. If null, global resources are assumed.
      * @param resDir The base resource path. Can be null (only framework resources will be loaded).
      * @param splitResDirs An array of split resource paths. Can be null.
-     * @param overlayDirs An array of overlay paths. Can be null.
+     * @param legacyOverlayDirs An array of overlay APK paths. Can be null.
+     * @param overlayPaths An array of overlay APK and non-APK paths. Can be null.
      * @param libDirs An array of resource library paths. Can be null.
      * @param overrideDisplayId The ID of the display for which the returned Resources should be
      * based. This will cause display-based configuration properties to override those of the base
@@ -1063,7 +1069,8 @@
             @Nullable IBinder activityToken,
             @Nullable String resDir,
             @Nullable String[] splitResDirs,
-            @Nullable String[] overlayDirs,
+            @Nullable String[] legacyOverlayDirs,
+            @Nullable String[] overlayPaths,
             @Nullable String[] libDirs,
             @Nullable Integer overrideDisplayId,
             @Nullable Configuration overrideConfig,
@@ -1075,7 +1082,7 @@
             final ResourcesKey key = new ResourcesKey(
                     resDir,
                     splitResDirs,
-                    overlayDirs,
+                    combinedOverlayPaths(legacyOverlayDirs, overlayPaths),
                     libDirs,
                     overrideDisplayId != null ? overrideDisplayId : INVALID_DISPLAY,
                     overrideConfig,
@@ -1250,7 +1257,7 @@
 
         // Create the new ResourcesKey with the rebased override config.
         final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir,
-                oldKey.mSplitResDirs, oldKey.mOverlayDirs, oldKey.mLibDirs,
+                oldKey.mSplitResDirs, oldKey.mOverlayPaths, oldKey.mLibDirs,
                 displayId, rebasedOverrideConfig, oldKey.mCompatInfo, oldKey.mLoaders);
 
         if (DEBUG) {
@@ -1393,7 +1400,7 @@
                         updatedResourceKeys.put(impl, new ResourcesKey(
                                 key.mResDir,
                                 key.mSplitResDirs,
-                                key.mOverlayDirs,
+                                key.mOverlayPaths,
                                 newLibAssets,
                                 key.mDisplayId,
                                 key.mOverrideConfiguration,
@@ -1423,7 +1430,8 @@
 
             // ApplicationInfo is mutable, so clone the arrays to prevent outside modification
             String[] copiedSplitDirs = ArrayUtils.cloneOrNull(newSplitDirs);
-            String[] copiedResourceDirs = ArrayUtils.cloneOrNull(appInfo.resourceDirs);
+            String[] copiedResourceDirs = combinedOverlayPaths(appInfo.resourceDirs,
+                    appInfo.overlayPaths);
 
             final ArrayMap<ResourcesImpl, ResourcesKey> updatedResourceKeys = new ArrayMap<>();
             final int implCount = mResourceImpls.size();
@@ -1458,6 +1466,39 @@
         }
     }
 
+    /**
+     * Creates an array with the contents of {@param overlayPaths} and the unique elements of
+     * {@param resourceDirs}.
+     *
+     * {@link ApplicationInfo#resourceDirs} only contains paths of overlays APKs.
+     * {@link ApplicationInfo#overlayPaths} was created to contain paths of overlay of varying file
+     * formats. It also contains the contents of {@code resourceDirs} because the order of loaded
+     * overlays matter. In case {@code resourceDirs} contains overlay APK paths that are not present
+     * in overlayPaths (perhaps an app inserted an additional overlay path into a
+     * {@code resourceDirs}), this method is used to combine the contents of {@code resourceDirs}
+     * that do not exist in {@code overlayPaths}} and {@code overlayPaths}}.
+     */
+    @Nullable
+    private static String[] combinedOverlayPaths(@Nullable String[] resourceDirs,
+            @Nullable String[] overlayPaths) {
+        if (resourceDirs == null) {
+            return ArrayUtils.cloneOrNull(overlayPaths);
+        } else if(overlayPaths == null) {
+            return ArrayUtils.cloneOrNull(resourceDirs);
+        } else {
+            final ArrayList<String> paths = new ArrayList<>();
+            for (final String path : overlayPaths) {
+                paths.add(path);
+            }
+            for (final String path : resourceDirs) {
+                if (!paths.contains(path)) {
+                    paths.add(path);
+                }
+            }
+            return paths.toArray(new String[0]);
+        }
+    }
+
     private void redirectResourcesToNewImplLocked(
             @NonNull final ArrayMap<ResourcesImpl, ResourcesKey> updatedResourceKeys) {
         // Bail early if there is no work to do.
@@ -1559,7 +1600,7 @@
                 final ResourcesKey newKey = new ResourcesKey(
                         oldKey.mResDir,
                         oldKey.mSplitResDirs,
-                        oldKey.mOverlayDirs,
+                        oldKey.mOverlayPaths,
                         oldKey.mLibDirs,
                         oldKey.mDisplayId,
                         oldKey.mOverrideConfiguration,
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6ec1169..01ff432 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -923,6 +923,14 @@
     public String[] resourceDirs;
 
     /**
+     * Contains the contents of {@link #resourceDirs} and along with paths for overlays that may or
+     * may not be APK packages.
+     *
+     * {@hide}
+     */
+    public String[] overlayPaths;
+
+    /**
      * String retrieved from the seinfo tag found in selinux policy. This value can be set through
      * the mac_permissions.xml policy construct. This value is used for setting an SELinux security
      * context on the process as well as its data directory.
@@ -1472,6 +1480,9 @@
         if (resourceDirs != null) {
             pw.println(prefix + "resourceDirs=" + Arrays.toString(resourceDirs));
         }
+        if (overlayPaths != null) {
+            pw.println(prefix + "overlayPaths=" + Arrays.toString(overlayPaths));
+        }
         if ((dumpFlags & DUMP_FLAG_DETAILS) != 0 && seInfo != null) {
             pw.println(prefix + "seinfo=" + seInfo);
             pw.println(prefix + "seinfoUser=" + seInfoUser);
@@ -1568,6 +1579,11 @@
                 proto.write(ApplicationInfoProto.RESOURCE_DIRS, dir);
             }
         }
+        if (overlayPaths != null) {
+            for (String dir : overlayPaths) {
+                proto.write(ApplicationInfoProto.OVERLAY_PATHS, dir);
+            }
+        }
         proto.write(ApplicationInfoProto.DATA_DIR, dataDir);
         proto.write(ApplicationInfoProto.CLASS_LOADER_NAME, classLoaderName);
         if (!ArrayUtils.isEmpty(splitClassLoaderNames)) {
@@ -1717,6 +1733,7 @@
         primaryCpuAbi = orig.primaryCpuAbi;
         secondaryCpuAbi = orig.secondaryCpuAbi;
         resourceDirs = orig.resourceDirs;
+        overlayPaths = orig.overlayPaths;
         seInfo = orig.seInfo;
         seInfoUser = orig.seInfoUser;
         sharedLibraryFiles = orig.sharedLibraryFiles;
@@ -1803,6 +1820,7 @@
         dest.writeString8(primaryCpuAbi);
         dest.writeString8(secondaryCpuAbi);
         dest.writeString8Array(resourceDirs);
+        dest.writeString8Array(overlayPaths);
         dest.writeString8(seInfo);
         dest.writeString8(seInfoUser);
         dest.writeString8Array(sharedLibraryFiles);
@@ -1886,6 +1904,7 @@
         primaryCpuAbi = source.readString8();
         secondaryCpuAbi = source.readString8();
         resourceDirs = source.createString8Array();
+        overlayPaths = source.createString8Array();
         seInfo = source.readString8();
         seInfoUser = source.readString8();
         sharedLibraryFiles = source.createString8Array();
@@ -2282,7 +2301,9 @@
      * @hide
      */
     public String[] getAllApkPaths() {
-        final String[][] inputLists = { splitSourceDirs, sharedLibraryFiles, resourceDirs };
+        final String[][] inputLists = {
+                splitSourceDirs, sharedLibraryFiles, resourceDirs, overlayPaths
+        };
         final List<String> output = new ArrayList<>(10);
         if (sourceDir != null) {
             output.add(sourceDir);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e6c0f6a..0819d17 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -54,6 +54,7 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.overlay.OverlayPaths;
 import android.content.pm.split.SplitAssetLoader;
 import android.content.res.ApkAssets;
 import android.content.res.AssetManager;
@@ -7969,7 +7970,11 @@
             ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
         }
         ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
-        ai.resourceDirs = state.getAllOverlayPaths();
+        final OverlayPaths overlayPaths = state.getAllOverlayPaths();
+        if (overlayPaths != null) {
+            ai.resourceDirs = overlayPaths.getResourceDirs().toArray(new String[0]);
+            ai.overlayPaths = overlayPaths.getOverlayPaths().toArray(new String[0]);
+        }
         ai.icon = (sUseRoundIcon && ai.roundIconRes != 0) ? ai.roundIconRes : ai.iconRes;
     }
 
@@ -8600,6 +8605,7 @@
                 null,
                 null,
                 androidAppInfo.resourceDirs,
+                androidAppInfo.overlayPaths,
                 androidAppInfo.sharedLibraryFiles,
                 null,
                 null,
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 5cc74c0..e115597 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -31,6 +31,7 @@
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
+import android.content.pm.overlay.OverlayPaths;
 import android.content.pm.parsing.component.ParsedMainComponent;
 import android.os.BaseBundle;
 import android.os.Debug;
@@ -53,7 +54,6 @@
 
 import java.io.IOException;
 import java.util.Arrays;
-import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Objects;
 
@@ -85,9 +85,10 @@
     public ArraySet<String> disabledComponents;
     public ArraySet<String> enabledComponents;
 
-    private String[] overlayPaths;
-    private ArrayMap<String, String[]> sharedLibraryOverlayPaths; // Lib name to overlay paths
-    private String[] cachedOverlayPaths;
+    private OverlayPaths overlayPaths;
+    // Maps library name to overlay paths.
+    private ArrayMap<String, OverlayPaths> sharedLibraryOverlayPaths;
+    private OverlayPaths cachedOverlayPaths;
 
     @Nullable
     private ArrayMap<ComponentName, Pair<String, Integer>> componentLabelIconOverrideMap;
@@ -121,8 +122,7 @@
         uninstallReason = o.uninstallReason;
         disabledComponents = ArrayUtils.cloneOrNull(o.disabledComponents);
         enabledComponents = ArrayUtils.cloneOrNull(o.enabledComponents);
-        overlayPaths =
-            o.overlayPaths == null ? null : Arrays.copyOf(o.overlayPaths, o.overlayPaths.length);
+        overlayPaths = o.overlayPaths;
         if (o.sharedLibraryOverlayPaths != null) {
             sharedLibraryOverlayPaths = new ArrayMap<>(o.sharedLibraryOverlayPaths);
         }
@@ -132,25 +132,55 @@
         }
     }
 
-    public String[] getOverlayPaths() {
+    @Nullable
+    public OverlayPaths getOverlayPaths() {
         return overlayPaths;
     }
 
-    public void setOverlayPaths(String[] paths) {
-        overlayPaths = paths;
-        cachedOverlayPaths = null;
-    }
-
-    public Map<String, String[]> getSharedLibraryOverlayPaths() {
+    @Nullable
+    public Map<String, OverlayPaths> getSharedLibraryOverlayPaths() {
         return sharedLibraryOverlayPaths;
     }
 
-    public void setSharedLibraryOverlayPaths(String library, String[] paths) {
+    /**
+     * Sets the path of overlays currently enabled for this package and user combination.
+     * @return true if the path contents differ than what they were previously
+     */
+    @Nullable
+    public boolean setOverlayPaths(@Nullable OverlayPaths paths) {
+        if (Objects.equals(paths, overlayPaths)) {
+            return false;
+        }
+        if ((overlayPaths == null && paths.isEmpty())
+                || (paths == null && overlayPaths.isEmpty())) {
+            return false;
+        }
+        overlayPaths = paths;
+        cachedOverlayPaths = null;
+        return true;
+    }
+
+    /**
+     * Sets the path of overlays currently enabled for a library that this package uses.
+     *
+     * @return true if the path contents for the library differ than what they were previously
+     */
+    public boolean setSharedLibraryOverlayPaths(@NonNull String library,
+            @Nullable OverlayPaths paths) {
         if (sharedLibraryOverlayPaths == null) {
             sharedLibraryOverlayPaths = new ArrayMap<>();
         }
-        sharedLibraryOverlayPaths.put(library, paths);
+        final OverlayPaths currentPaths = sharedLibraryOverlayPaths.get(library);
+        if (Objects.equals(paths, currentPaths)) {
+            return false;
+        }
         cachedOverlayPaths = null;
+        if (paths == null || paths.isEmpty()) {
+            return sharedLibraryOverlayPaths.remove(library) != null;
+        } else {
+            sharedLibraryOverlayPaths.put(library, paths);
+            return true;
+        }
     }
 
     /**
@@ -332,35 +362,21 @@
         return isComponentEnabled;
     }
 
-    public String[] getAllOverlayPaths() {
+    public OverlayPaths getAllOverlayPaths() {
         if (overlayPaths == null && sharedLibraryOverlayPaths == null) {
             return null;
         }
-
         if (cachedOverlayPaths != null) {
             return cachedOverlayPaths;
         }
-
-        final LinkedHashSet<String> paths = new LinkedHashSet<>();
-        if (overlayPaths != null) {
-            final int N = overlayPaths.length;
-            for (int i = 0; i < N; i++) {
-                paths.add(overlayPaths[i]);
-            }
-        }
-
+        final OverlayPaths.Builder newPaths = new OverlayPaths.Builder();
+        newPaths.addAll(overlayPaths);
         if (sharedLibraryOverlayPaths != null) {
-            for (String[] libOverlayPaths : sharedLibraryOverlayPaths.values()) {
-                if (libOverlayPaths != null) {
-                    final int N = libOverlayPaths.length;
-                    for (int i = 0; i < N; i++) {
-                        paths.add(libOverlayPaths[i]);
-                    }
-                }
+            for (final OverlayPaths libOverlayPaths : sharedLibraryOverlayPaths.values()) {
+                newPaths.addAll(libOverlayPaths);
             }
         }
-
-        cachedOverlayPaths = paths.toArray(new String[0]);
+        cachedOverlayPaths = newPaths.build();
         return cachedOverlayPaths;
     }
 
diff --git a/core/java/android/content/pm/overlay/OverlayPaths.java b/core/java/android/content/pm/overlay/OverlayPaths.java
new file mode 100644
index 0000000..a4db733
--- /dev/null
+++ b/core/java/android/content/pm/overlay/OverlayPaths.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.overlay;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.util.DataClass;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/** @hide */
+@DataClass(genConstructor = false, genBuilder = false, genHiddenBuilder = false,
+        genEqualsHashCode = true, genToString = true)
+public class OverlayPaths {
+    /**
+     * Represents {@link android.content.pm.ApplicationInfo#resourceDirs}.
+     * Only contains paths to APKs of overlays that can have their idmap resolved from their base
+     * APK path. Currently all overlay APKs can have their idmap path resolved from their idmap
+     * path.
+     */
+    @NonNull
+    private final List<String> mResourceDirs = new ArrayList<>();
+
+    /**
+     * Represents {@link android.content.pm.ApplicationInfo#overlayPaths}.
+     * Contains the contents of {@link #getResourceDirs()} and along with paths for overlays
+     * that are not APKs.
+     */
+    @NonNull
+    private final List<String> mOverlayPaths = new ArrayList<>();
+
+    public static class Builder {
+        final OverlayPaths mPaths = new OverlayPaths();
+
+        /**
+         * Adds a non-APK path to the contents of {@link OverlayPaths#getOverlayPaths()}.
+         */
+        public Builder addNonApkPath(@NonNull String idmapPath) {
+            mPaths.mOverlayPaths.add(idmapPath);
+            return this;
+        }
+
+        /**
+         * Adds a overlay APK path to the contents of {@link OverlayPaths#getResourceDirs()} and
+         * {@link OverlayPaths#getOverlayPaths()}.
+         */
+        public Builder addApkPath(@NonNull String overlayPath) {
+            addUniquePath(mPaths.mResourceDirs, overlayPath);
+            addUniquePath(mPaths.mOverlayPaths, overlayPath);
+            return this;
+        }
+
+        public Builder addAll(@Nullable OverlayPaths other) {
+            if (other != null) {
+                for (final String path : other.getResourceDirs()) {
+                    addUniquePath(mPaths.mResourceDirs, path);
+                }
+                for (final String path : other.getOverlayPaths()) {
+                    addUniquePath(mPaths.mOverlayPaths, path);
+                }
+            }
+            return this;
+        }
+
+        public OverlayPaths build() {
+            return mPaths;
+        }
+
+        private static void addUniquePath(@NonNull List<String> paths, @NonNull String path) {
+            if (!paths.contains(path)) {
+                paths.add(path);
+            }
+        }
+    }
+
+    /**
+     * Returns whether {@link #getOverlayPaths()} and {@link #getOverlayPaths} are empty.
+     */
+    public boolean isEmpty() {
+        return mResourceDirs.isEmpty() && mOverlayPaths.isEmpty();
+    }
+
+    private OverlayPaths() {
+    }
+
+
+
+    // Code below generated by codegen v1.0.22.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/overlay/OverlayPaths.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Represents {@link android.content.pm.ApplicationInfo#resourceDirs}.
+     * Only contains paths to APKs of overlays that can have their idmap resolved from their base
+     * APK path. Currently all overlay APKs can have their idmap path resolved from their idmap
+     * path.
+     */
+    @DataClass.Generated.Member
+    public @NonNull List<String> getResourceDirs() {
+        return mResourceDirs;
+    }
+
+    /**
+     * Represents {@link android.content.pm.ApplicationInfo#overlayPaths}.
+     * Contains the contents of {@link #getResourceDirs()} and along with paths for overlays
+     * that are not APKs.
+     */
+    @DataClass.Generated.Member
+    public @NonNull List<String> getOverlayPaths() {
+        return mOverlayPaths;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "OverlayPaths { " +
+                "resourceDirs = " + mResourceDirs + ", " +
+                "overlayPaths = " + mOverlayPaths +
+                " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@android.annotation.Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(OverlayPaths other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        OverlayPaths that = (OverlayPaths) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && Objects.equals(mResourceDirs, that.mResourceDirs)
+                && Objects.equals(mOverlayPaths, that.mOverlayPaths);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + Objects.hashCode(mResourceDirs);
+        _hash = 31 * _hash + Objects.hashCode(mOverlayPaths);
+        return _hash;
+    }
+
+    @DataClass.Generated(
+            time = 1612307813586L,
+            codegenVersion = "1.0.22",
+            sourceFile = "frameworks/base/core/java/android/content/pm/overlay/OverlayPaths.java",
+            inputSignatures = "private final @android.annotation.NonNull java.util.List<java.lang.String> mResourceDirs\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mOverlayPaths\npublic  boolean isEmpty()\nclass OverlayPaths extends java.lang.Object implements []\nfinal  android.content.pm.overlay.OverlayPaths mPaths\npublic  android.content.pm.overlay.OverlayPaths.Builder addNonApkPath(java.lang.String)\npublic  android.content.pm.overlay.OverlayPaths.Builder addApkPath(java.lang.String)\npublic  android.content.pm.overlay.OverlayPaths.Builder addAll(android.content.pm.overlay.OverlayPaths)\npublic  android.content.pm.overlay.OverlayPaths build()\nprivate static  void addUniquePath(java.util.List<java.lang.String>,java.lang.String)\nclass Builder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genHiddenBuilder=false, genEqualsHashCode=true, genToString=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index b7365b3..fb0d904 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -41,6 +41,7 @@
 import android.content.pm.ServiceInfo;
 import android.content.pm.Signature;
 import android.content.pm.SigningInfo;
+import android.content.pm.overlay.OverlayPaths;
 import android.content.pm.parsing.component.ComponentParseUtils;
 import android.content.pm.parsing.component.ParsedActivity;
 import android.content.pm.parsing.component.ParsedAttribution;
@@ -412,7 +413,11 @@
             ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
         }
         ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
-        ai.resourceDirs = state.getAllOverlayPaths();
+        final OverlayPaths overlayPaths = state.getAllOverlayPaths();
+        if (overlayPaths != null) {
+            ai.resourceDirs = overlayPaths.getResourceDirs().toArray(new String[0]);
+            ai.overlayPaths = overlayPaths.getOverlayPaths().toArray(new String[0]);
+        }
 
         return ai;
     }
diff --git a/core/java/android/content/res/ResourcesKey.java b/core/java/android/content/res/ResourcesKey.java
index 05769dd..99b56a8 100644
--- a/core/java/android/content/res/ResourcesKey.java
+++ b/core/java/android/content/res/ResourcesKey.java
@@ -38,7 +38,7 @@
     public final String[] mSplitResDirs;
 
     @Nullable
-    public final String[] mOverlayDirs;
+    public final String[] mOverlayPaths;
 
     @Nullable
     public final String[] mLibDirs;
@@ -67,7 +67,7 @@
 
     public ResourcesKey(@Nullable String resDir,
                         @Nullable String[] splitResDirs,
-                        @Nullable String[] overlayDirs,
+                        @Nullable String[] overlayPaths,
                         @Nullable String[] libDirs,
                         int overrideDisplayId,
                         @Nullable Configuration overrideConfig,
@@ -75,7 +75,7 @@
                         @Nullable ResourcesLoader[] loader) {
         mResDir = resDir;
         mSplitResDirs = splitResDirs;
-        mOverlayDirs = overlayDirs;
+        mOverlayPaths = overlayPaths;
         mLibDirs = libDirs;
         mLoaders = (loader != null && loader.length == 0) ? null : loader;
         mDisplayId = overrideDisplayId;
@@ -86,7 +86,7 @@
         int hash = 17;
         hash = 31 * hash + Objects.hashCode(mResDir);
         hash = 31 * hash + Arrays.hashCode(mSplitResDirs);
-        hash = 31 * hash + Arrays.hashCode(mOverlayDirs);
+        hash = 31 * hash + Arrays.hashCode(mOverlayPaths);
         hash = 31 * hash + Arrays.hashCode(mLibDirs);
         hash = 31 * hash + Objects.hashCode(mDisplayId);
         hash = 31 * hash + Objects.hashCode(mOverrideConfiguration);
@@ -98,12 +98,12 @@
     @UnsupportedAppUsage
     public ResourcesKey(@Nullable String resDir,
             @Nullable String[] splitResDirs,
-            @Nullable String[] overlayDirs,
+            @Nullable String[] overlayPaths,
             @Nullable String[] libDirs,
             int displayId,
             @Nullable Configuration overrideConfig,
             @Nullable CompatibilityInfo compatInfo) {
-        this(resDir, splitResDirs, overlayDirs, libDirs, displayId, overrideConfig, compatInfo,
+        this(resDir, splitResDirs, overlayPaths, libDirs, displayId, overrideConfig, compatInfo,
                 null);
     }
 
@@ -115,7 +115,7 @@
         if (mResDir != null && mResDir.startsWith(path)) {
             return true;
         } else {
-            return anyStartsWith(mSplitResDirs, path) || anyStartsWith(mOverlayDirs, path)
+            return anyStartsWith(mSplitResDirs, path) || anyStartsWith(mOverlayPaths, path)
                     || anyStartsWith(mLibDirs, path);
         }
     }
@@ -154,7 +154,7 @@
         if (!Arrays.equals(mSplitResDirs, peer.mSplitResDirs)) {
             return false;
         }
-        if (!Arrays.equals(mOverlayDirs, peer.mOverlayDirs)) {
+        if (!Arrays.equals(mOverlayPaths, peer.mOverlayPaths)) {
             return false;
         }
         if (!Arrays.equals(mLibDirs, peer.mLibDirs)) {
@@ -186,8 +186,8 @@
         }
         builder.append("]");
         builder.append(" mOverlayDirs=[");
-        if (mOverlayDirs != null) {
-            builder.append(TextUtils.join(",", mOverlayDirs));
+        if (mOverlayPaths != null) {
+            builder.append(TextUtils.join(",", mOverlayPaths));
         }
         builder.append("]");
         builder.append(" mLibDirs=[");
diff --git a/core/proto/android/content/package_item_info.proto b/core/proto/android/content/package_item_info.proto
index bb39ea8..5c6116a 100644
--- a/core/proto/android/content/package_item_info.proto
+++ b/core/proto/android/content/package_item_info.proto
@@ -114,4 +114,5 @@
         optional bool native_heap_zero_init = 21;
     }
     optional Detail detail = 17;
+    repeated string overlay_paths = 18;
 }
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
index 45adf83..46dbe0f 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -90,12 +90,12 @@
     @SmallTest
     public void testMultipleCallsWithIdenticalParametersCacheReference() {
         Resources resources = mResourcesManager.getResources(
-                null, APP_ONE_RES_DIR, null, null, null, null, null,
+                null, APP_ONE_RES_DIR, null, null, null, null, null, null,
                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
         assertNotNull(resources);
 
         Resources newResources = mResourcesManager.getResources(
-                null, APP_ONE_RES_DIR, null, null, null, null, null,
+                null, APP_ONE_RES_DIR, null, null, null, null, null, null,
                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
         assertNotNull(newResources);
         assertSame(resources, newResources);
@@ -104,14 +104,14 @@
     @SmallTest
     public void testMultipleCallsWithDifferentParametersReturnDifferentReferences() {
         Resources resources = mResourcesManager.getResources(
-                null, APP_ONE_RES_DIR, null, null, null, null, null,
+                null, APP_ONE_RES_DIR, null, null, null, null, null, null,
                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
         assertNotNull(resources);
 
         Configuration overrideConfig = new Configuration();
         overrideConfig.smallestScreenWidthDp = 200;
         Resources newResources = mResourcesManager.getResources(
-                null, APP_ONE_RES_DIR, null, null, null, null, overrideConfig,
+                null, APP_ONE_RES_DIR, null, null, null, null, null, overrideConfig,
                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
         assertNotNull(newResources);
         assertNotSame(resources, newResources);
@@ -120,12 +120,12 @@
     @SmallTest
     public void testAddingASplitCreatesANewImpl() {
         Resources resources1 = mResourcesManager.getResources(
-                null, APP_ONE_RES_DIR, null, null, null, null, null,
+                null, APP_ONE_RES_DIR, null, null, null, null, null, null,
                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
         assertNotNull(resources1);
 
         Resources resources2 = mResourcesManager.getResources(
-                null, APP_ONE_RES_DIR, new String[] { APP_ONE_RES_SPLIT_DIR }, null, null,
+                null, APP_ONE_RES_DIR, new String[] { APP_ONE_RES_SPLIT_DIR }, null, null, null,
                 null, null, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null,
                 null);
         assertNotNull(resources2);
@@ -137,12 +137,12 @@
     @SmallTest
     public void testUpdateConfigurationUpdatesAllAssetManagers() {
         Resources resources1 = mResourcesManager.getResources(
-                null, APP_ONE_RES_DIR, null, null, null, null, null,
+                null, APP_ONE_RES_DIR, null, null, null, null, null, null,
                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
         assertNotNull(resources1);
 
         Resources resources2 = mResourcesManager.getResources(
-                null, APP_TWO_RES_DIR, null, null, null, null, null,
+                null, APP_TWO_RES_DIR, null, null, null, null, null, null,
                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
         assertNotNull(resources2);
 
@@ -150,7 +150,7 @@
         final Configuration overrideConfig = new Configuration();
         overrideConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
         Resources resources3 = mResourcesManager.getResources(
-                activity, APP_ONE_RES_DIR, null, null, null, null,
+                activity, APP_ONE_RES_DIR, null, null, null, null, null,
                 overrideConfig, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
         assertNotNull(resources3);
 
@@ -183,13 +183,13 @@
     public void testTwoActivitiesWithIdenticalParametersShareImpl() {
         Binder activity1 = new Binder();
         Resources resources1 = mResourcesManager.getResources(
-                activity1, APP_ONE_RES_DIR, null, null, null, null, null,
+                activity1, APP_ONE_RES_DIR, null, null, null, null, null, null,
                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
         assertNotNull(resources1);
 
         Binder activity2 = new Binder();
         Resources resources2 = mResourcesManager.getResources(
-                activity2, APP_ONE_RES_DIR, null, null, null, null, null,
+                activity2, APP_ONE_RES_DIR, null, null, null, null, null, null,
                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
         assertNotNull(resources1);
 
@@ -204,7 +204,7 @@
     public void testThemesGetUpdatedWithNewImpl() {
         Binder activity1 = new Binder();
         Resources resources1 = mResourcesManager.createBaseTokenResources(
-                activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+                activity1, APP_ONE_RES_DIR, null, null, null, null, Display.DEFAULT_DISPLAY, null,
                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
         assertNotNull(resources1);
 
@@ -237,15 +237,15 @@
         Configuration config1 = new Configuration();
         config1.densityDpi = 280;
         Resources resources1 = mResourcesManager.createBaseTokenResources(
-                activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, config1,
-                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
+                activity1, APP_ONE_RES_DIR, null, null, null, null, Display.DEFAULT_DISPLAY,
+                config1, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
         assertNotNull(resources1);
 
         // Create a Resources based on the Activity.
         Configuration config2 = new Configuration();
         config2.screenLayout |= Configuration.SCREENLAYOUT_ROUND_YES;
         Resources resources2 = mResourcesManager.getResources(
-                activity1, APP_ONE_RES_DIR, null, null, null, null, config2,
+                activity1, APP_ONE_RES_DIR, null, null, null, null, null, config2,
                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
         assertNotNull(resources2);
 
@@ -286,8 +286,8 @@
         final Configuration overrideConfig = new Configuration();
         overrideConfig.densityDpi = originalOverrideDensity;
         final Resources resources = mResourcesManager.createBaseTokenResources(
-                token, APP_ONE_RES_DIR, null /* splitResDirs */, null /* overlayDirs */,
-                null /* libDirs */, Display.DEFAULT_DISPLAY, overrideConfig,
+                token, APP_ONE_RES_DIR, null /* splitResDirs */, null /* legacyOverlayDirs */,
+                null /* overlayDirs */,null /* libDirs */, Display.DEFAULT_DISPLAY, overrideConfig,
                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null /* classLoader */,
                 null /* loaders */);
 
@@ -315,12 +315,12 @@
 
         // Create a base token resources that are based on the default display.
         Resources activityResources = mResourcesManager.createBaseTokenResources(
-                activity, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+                activity, APP_ONE_RES_DIR, null, null, null,null, Display.DEFAULT_DISPLAY, null,
                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
         // Create another resources that explicitly override the display of the base token above
         // and set it to DEFAULT_DISPLAY.
         Resources defaultDisplayResources = mResourcesManager.getResources(
-                activity, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
+                activity, APP_ONE_RES_DIR, null, null, null, null, Display.DEFAULT_DISPLAY, null,
                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
 
         assertEquals(mDisplayMetricsMap.get(Display.DEFAULT_DISPLAY).widthPixels,
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 6886cde..737a9e4 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -30,6 +30,7 @@
 import android.content.pm.PackageManager.ComponentInfoFlags;
 import android.content.pm.PackageManager.PackageInfoFlags;
 import android.content.pm.PackageManager.ResolveInfoFlags;
+import android.content.pm.overlay.OverlayPaths;
 import android.content.pm.parsing.component.ParsedMainComponent;
 import android.os.Bundle;
 import android.os.Handler;
@@ -49,8 +50,8 @@
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.Collection;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
@@ -535,17 +536,17 @@
      * Set which overlay to use for a package.
      * @param userId The user for which to update the overlays.
      * @param targetPackageName The package name of the package for which to update the overlays.
-     * @param overlayPackageNames The complete list of overlay packages that should be enabled for
-     *                            the target. Previously enabled overlays not specified in the list
-     *                            will be disabled. Pass in null or an empty list to disable
-     *                            all overlays. The order of the items is significant if several
-     *                            overlays modify the same resource.
+     * @param overlayPaths  The complete list of overlay paths that should be enabled for
+     *                      the target. Previously enabled overlays not specified in the list
+     *                      will be disabled. Pass in null or empty paths to disable all overlays.
+     *                      The order of the items is significant if several overlays modify the
+     *                      same resource.
      * @param outUpdatedPackageNames An output list that contains the package names of packages
      *                               affected by the update of enabled overlays.
      * @return true if all packages names were known by the package manager, false otherwise
      */
     public abstract boolean setEnabledOverlayPackages(int userId, String targetPackageName,
-            List<String> overlayPackageNames, Collection<String> outUpdatedPackageNames);
+            @Nullable OverlayPaths overlayPaths, Set<String> outUpdatedPackageNames);
 
     /**
      * Resolves an activity intent, allowing instant apps to be resolved.
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 50fb176..fd2fb1f 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -50,6 +50,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.UserInfo;
+import android.content.pm.overlay.OverlayPaths;
 import android.content.res.ApkAssets;
 import android.net.Uri;
 import android.os.Binder;
@@ -1376,18 +1377,18 @@
                 targetPackageNames = pm.getTargetPackageNames(userId);
             }
 
-            final Map<String, List<String>> pendingChanges =
+            final Map<String, OverlayPaths> pendingChanges =
                     new ArrayMap<>(targetPackageNames.size());
             synchronized (mLock) {
-                final List<String> frameworkOverlays =
-                        mImpl.getEnabledOverlayPackageNames("android", userId);
+                final OverlayPaths frameworkOverlays =
+                        mImpl.getEnabledOverlayPaths("android", userId);
                 for (final String targetPackageName : targetPackageNames) {
-                    List<String> list = new ArrayList<>();
+                    final OverlayPaths.Builder list = new OverlayPaths.Builder();
                     if (!"android".equals(targetPackageName)) {
                         list.addAll(frameworkOverlays);
                     }
-                    list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
-                    pendingChanges.put(targetPackageName, list);
+                    list.addAll(mImpl.getEnabledOverlayPaths(targetPackageName, userId));
+                    pendingChanges.put(targetPackageName, list.build());
                 }
             }
 
@@ -1395,7 +1396,7 @@
             for (final String targetPackageName : targetPackageNames) {
                 if (DEBUG) {
                     Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
-                            + TextUtils.join(",", pendingChanges.get(targetPackageName))
+                            + pendingChanges.get(targetPackageName)
                             + "] userId=" + userId);
                 }
 
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index e60411bb..c547c36 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -31,6 +31,7 @@
 import android.content.om.OverlayInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.content.pm.overlay.OverlayPaths;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -697,19 +698,20 @@
         removeIdmapIfPossible(oi);
     }
 
-    List<String> getEnabledOverlayPackageNames(@NonNull final String targetPackageName,
+    OverlayPaths getEnabledOverlayPaths(@NonNull final String targetPackageName,
             final int userId) {
         final List<OverlayInfo> overlays = mSettings.getOverlaysForTarget(targetPackageName,
                 userId);
-        final List<String> paths = new ArrayList<>(overlays.size());
+        final OverlayPaths.Builder paths = new OverlayPaths.Builder();
         final int n = overlays.size();
         for (int i = 0; i < n; i++) {
             final OverlayInfo oi = overlays.get(i);
-            if (oi.isEnabled()) {
-                paths.add(oi.packageName);
+            if (!oi.isEnabled()) {
+                continue;
             }
+            paths.addApkPath(oi.baseCodePath);
         }
-        return paths;
+        return paths.build();
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5d4fa1e..42723f4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -193,6 +193,7 @@
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
 import android.content.pm.ModuleInfo;
+import android.content.pm.overlay.OverlayPaths;
 import android.content.pm.PackageChangeEvent;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInfoLite;
@@ -234,6 +235,7 @@
 import android.content.pm.dex.ArtManager;
 import android.content.pm.dex.DexMetadataHelper;
 import android.content.pm.dex.IArtManager;
+import android.content.pm.overlay.OverlayPaths;
 import android.content.pm.parsing.ApkLiteParseUtils;
 import android.content.pm.parsing.PackageLite;
 import android.content.pm.parsing.ParsingPackageUtils;
@@ -18122,11 +18124,8 @@
                             if (libPs == null) {
                                 continue;
                             }
-                            final String[] overlayPaths = libPs.getOverlayPaths(currentUserId);
-                            if (overlayPaths != null) {
-                                ps.setOverlayPathsForLibrary(sharedLib.getName(),
-                                        Arrays.asList(overlayPaths), currentUserId);
-                            }
+                            ps.setOverlayPathsForLibrary(sharedLib.getName(),
+                                    libPs.getOverlayPaths(currentUserId), currentUserId);
                         }
                     }
                 }
@@ -26616,34 +26615,19 @@
 
         @Override
         public boolean setEnabledOverlayPackages(int userId, @NonNull String targetPackageName,
-                @Nullable List<String> overlayPackageNames,
-                @NonNull Collection<String> outUpdatedPackageNames) {
+                @Nullable OverlayPaths overlayPaths,
+                @NonNull Set<String> outUpdatedPackageNames) {
+            boolean modified = false;
             synchronized (mLock) {
                 final AndroidPackage targetPkg = mPackages.get(targetPackageName);
                 if (targetPackageName == null || targetPkg == null) {
                     Slog.e(TAG, "failed to find package " + targetPackageName);
                     return false;
                 }
-                ArrayList<String> overlayPaths = null;
-                if (overlayPackageNames != null && overlayPackageNames.size() > 0) {
-                    final int N = overlayPackageNames.size();
-                    overlayPaths = new ArrayList<>(N);
-                    for (int i = 0; i < N; i++) {
-                        final String packageName = overlayPackageNames.get(i);
-                        final AndroidPackage pkg = mPackages.get(packageName);
-                        if (pkg == null) {
-                            Slog.e(TAG, "failed to find package " + packageName);
-                            return false;
-                        }
-                        overlayPaths.add(pkg.getBaseApkPath());
-                    }
-                }
 
-                ArraySet<String> updatedPackageNames = null;
                 if (targetPkg.getLibraryNames() != null) {
                     // Set the overlay paths for dependencies of the shared library.
-                    updatedPackageNames = new ArraySet<>();
-                    for (String libName : targetPkg.getLibraryNames()) {
+                    for (final String libName : targetPkg.getLibraryNames()) {
                         final SharedLibraryInfo info = getSharedLibraryInfoLPr(libName,
                                 SharedLibraryInfo.VERSION_UNDEFINED);
                         if (info == null) {
@@ -26654,28 +26638,30 @@
                         if (dependents == null) {
                             continue;
                         }
-                        for (VersionedPackage dependent : dependents) {
+                        for (final VersionedPackage dependent : dependents) {
                             final PackageSetting ps = mSettings.getPackageLPr(
                                     dependent.getPackageName());
                             if (ps == null) {
                                 continue;
                             }
-                            ps.setOverlayPathsForLibrary(libName, overlayPaths, userId);
-                            updatedPackageNames.add(dependent.getPackageName());
+                            if (ps.setOverlayPathsForLibrary(libName, overlayPaths, userId)) {
+                                outUpdatedPackageNames.add(dependent.getPackageName());
+                                modified = true;
+                            }
                         }
                     }
                 }
 
                 final PackageSetting ps = mSettings.getPackageLPr(targetPackageName);
-                ps.setOverlayPaths(overlayPaths, userId);
-
-                outUpdatedPackageNames.add(targetPackageName);
-                if (updatedPackageNames != null) {
-                    outUpdatedPackageNames.addAll(updatedPackageNames);
+                if (ps.setOverlayPaths(overlayPaths, userId)) {
+                    outUpdatedPackageNames.add(targetPackageName);
+                    modified = true;
                 }
             }
 
-            invalidatePackageInfoCache();
+            if (modified) {
+                invalidatePackageInfoCache();
+            }
             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 3a14283..5364cbf 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.content.pm.PackageUserState;
 import android.content.pm.Signature;
 import android.content.pm.SuspendDialogInfo;
+import android.content.pm.overlay.OverlayPaths;
 import android.os.PersistableBundle;
 import android.os.incremental.IncrementalManager;
 import android.service.pm.PackageProto;
@@ -44,7 +45,6 @@
 
 import java.io.File;
 import java.util.Arrays;
-import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -327,21 +327,20 @@
         modifyUserState(userId).uninstallReason = uninstallReason;
     }
 
-    void setOverlayPaths(List<String> overlayPaths, int userId) {
-        modifyUserState(userId).setOverlayPaths(overlayPaths == null ? null :
-            overlayPaths.toArray(new String[overlayPaths.size()]));
+    boolean setOverlayPaths(OverlayPaths overlayPaths, int userId) {
+        return modifyUserState(userId).setOverlayPaths(overlayPaths);
     }
 
-    String[] getOverlayPaths(int userId) {
+    OverlayPaths getOverlayPaths(int userId) {
         return readUserState(userId).getOverlayPaths();
     }
 
-    void setOverlayPathsForLibrary(String libName, List<String> overlayPaths, int userId) {
-        modifyUserState(userId).setSharedLibraryOverlayPaths(libName,
-                overlayPaths == null ? null : overlayPaths.toArray(new String[0]));
+    boolean setOverlayPathsForLibrary(String libName, OverlayPaths overlayPaths,
+            int userId) {
+        return modifyUserState(userId).setSharedLibraryOverlayPaths(libName, overlayPaths);
     }
 
-    Map<String, String[]> getOverlayPathsForLibrary(int userId) {
+    Map<String, OverlayPaths> getOverlayPathsForLibrary(int userId) {
         return readUserState(userId).getSharedLibraryOverlayPaths();
     }
 
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index fb033e6..311d6622 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -40,6 +40,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ComponentInfo;
 import android.content.pm.IntentFilterVerificationInfo;
+import android.content.pm.overlay.OverlayPaths;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageUserState;
@@ -49,6 +50,7 @@
 import android.content.pm.SuspendDialogInfo;
 import android.content.pm.UserInfo;
 import android.content.pm.VerifierDeviceIdentity;
+import android.content.pm.overlay.OverlayPaths;
 import android.content.pm.parsing.PackageInfoWithoutStateUtils;
 import android.content.pm.parsing.component.ParsedComponent;
 import android.content.pm.parsing.component.ParsedIntentInfo;
@@ -4686,26 +4688,58 @@
                 }
             }
 
-            String[] overlayPaths = ps.getOverlayPaths(user.id);
-            if (overlayPaths != null && overlayPaths.length > 0) {
-                pw.print(prefix); pw.println("    overlay paths:");
-                for (String path : overlayPaths) {
-                    pw.print(prefix); pw.print("      "); pw.println(path);
+            final OverlayPaths overlayPaths = ps.getOverlayPaths(user.id);
+            if (overlayPaths != null) {
+                if (!overlayPaths.getOverlayPaths().isEmpty()) {
+                    pw.print(prefix);
+                    pw.println("    overlay paths:");
+                    for (String path : overlayPaths.getOverlayPaths()) {
+                        pw.print(prefix);
+                        pw.print("      ");
+                        pw.println(path);
+                    }
+                }
+                if (!overlayPaths.getResourceDirs().isEmpty()) {
+                    pw.print(prefix);
+                    pw.println("    legacy overlay paths:");
+                    for (String path : overlayPaths.getResourceDirs()) {
+                        pw.print(prefix);
+                        pw.print("      ");
+                        pw.println(path);
+                    }
                 }
             }
 
-            Map<String, String[]> sharedLibraryOverlayPaths =
+            final Map<String, OverlayPaths> sharedLibraryOverlayPaths =
                     ps.getOverlayPathsForLibrary(user.id);
             if (sharedLibraryOverlayPaths != null) {
-                for (Map.Entry<String, String[]> libOverlayPaths :
+                for (Map.Entry<String, OverlayPaths> libOverlayPaths :
                         sharedLibraryOverlayPaths.entrySet()) {
-                    if (libOverlayPaths.getValue() == null) {
+                    final OverlayPaths paths = libOverlayPaths.getValue();
+                    if (paths == null) {
                         continue;
                     }
-                    pw.print(prefix); pw.print("    ");
-                    pw.print(libOverlayPaths.getKey()); pw.println(" overlay paths:");
-                    for (String path : libOverlayPaths.getValue()) {
-                        pw.print(prefix); pw.print("      "); pw.println(path);
+                    if (!paths.getOverlayPaths().isEmpty()) {
+                        pw.print(prefix);
+                        pw.println("    ");
+                        pw.print(libOverlayPaths.getKey());
+                        pw.println(" overlay paths:");
+                        for (String path : paths.getOverlayPaths()) {
+                            pw.print(prefix);
+                            pw.print("        ");
+                            pw.println(path);
+                        }
+                    }
+                    if (!paths.getResourceDirs().isEmpty()) {
+                        pw.print(prefix);
+                        pw.println("      ");
+                        pw.print(libOverlayPaths.getKey());
+                        pw.println(" legacy overlay paths:");
+                        for (String path : paths.getResourceDirs()) {
+                            pw.print(prefix);
+                            pw.print("      ");
+                            pw.println(path);
+                        }
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 61fe023..5460e36 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2086,6 +2086,7 @@
                 pi.getResDir(),
                 null /* splitResDirs */,
                 pi.getOverlayDirs(),
+                pi.getOverlayPaths(),
                 pi.getApplicationInfo().sharedLibraryFiles,
                 mDisplayContent.getDisplayId(),
                 null /* overrideConfig */,
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index e6a238a..ba60111 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -814,6 +814,7 @@
         assertArrayEquals(a.splitSourceDirs, that.splitSourceDirs);
         assertArrayEquals(a.splitPublicSourceDirs, that.splitPublicSourceDirs);
         assertArrayEquals(a.resourceDirs, that.resourceDirs);
+        assertArrayEquals(a.overlayPaths, that.overlayPaths);
         assertEquals(a.seInfo, that.seInfo);
         assertArrayEquals(a.sharedLibraryFiles, that.sharedLibraryFiles);
         assertEquals(a.dataDir, that.dataDir);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
index 938e4cc..7297622 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
@@ -21,11 +21,14 @@
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
 
 import android.content.pm.PackageManager;
 import android.content.pm.PackageUserState;
 import android.content.pm.SuspendDialogInfo;
+import android.content.pm.overlay.OverlayPaths;
 import android.os.PersistableBundle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -346,4 +349,40 @@
         assertLastPackageUsageSet(
                 testState6, PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT - 1, 60L);
     }
+
+    @Test
+    public void testOverlayPaths() {
+        final PackageUserState testState = new PackageUserState();
+        assertFalse(testState.setOverlayPaths(null));
+        assertFalse(testState.setOverlayPaths(new OverlayPaths.Builder().build()));
+
+        assertTrue(testState.setOverlayPaths(new OverlayPaths.Builder()
+                .addApkPath("/path/to/some.apk").build()));
+        assertFalse(testState.setOverlayPaths(new OverlayPaths.Builder()
+                .addApkPath("/path/to/some.apk").build()));
+
+        assertTrue(testState.setOverlayPaths(new OverlayPaths.Builder().build()));
+        assertFalse(testState.setOverlayPaths(null));
+    }
+    @Test
+    public void testSharedLibOverlayPaths() {
+        final PackageUserState testState = new PackageUserState();
+        final String LIB_ONE = "lib1";
+        final String LIB_TW0 = "lib2";
+        assertFalse(testState.setSharedLibraryOverlayPaths(LIB_ONE, null));
+        assertFalse(testState.setSharedLibraryOverlayPaths(LIB_ONE,
+                new OverlayPaths.Builder().build()));
+
+        assertTrue(testState.setSharedLibraryOverlayPaths(LIB_ONE, new OverlayPaths.Builder()
+                .addApkPath("/path/to/some.apk").build()));
+        assertFalse(testState.setSharedLibraryOverlayPaths(LIB_ONE, new OverlayPaths.Builder()
+                .addApkPath("/path/to/some.apk").build()));
+        assertTrue(testState.setSharedLibraryOverlayPaths(LIB_TW0, new OverlayPaths.Builder()
+                .addApkPath("/path/to/some.apk").build()));
+
+        assertTrue(testState.setSharedLibraryOverlayPaths(LIB_ONE,
+                new OverlayPaths.Builder().build()));
+        assertFalse(testState.setSharedLibraryOverlayPaths(LIB_ONE, null));
+    }
+
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
index 61252c4..ff0aec7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
@@ -248,6 +248,7 @@
             .ignored("Deferred pre-R, but assigned immediately in R")}
             requiresSmallestWidthDp=${this.requiresSmallestWidthDp}
             resourceDirs=${this.resourceDirs?.contentToString()}
+            overlayPaths=${this.overlayPaths?.contentToString()}
             roundIconRes=${this.roundIconRes}
             scanPublicSourceDir=${this.scanPublicSourceDir
             .ignored("Deferred pre-R, but assigned immediately in R")}