OMS: Introduce default overlays

Default overlays are applied at first boot. They are specified by
package name in system property ro.boot.vendor.overlay.theme as a
semicolon separated list.

Eg:

ro.boot.vendor.overlay=com.android.vendor.overlay;com.android.vendor.overlay_two

Test: manual (remove /data/system/overlays.xml and reboot)
Change-Id: I8a7443a9059ccabfe1a63b075b95f1b2b6db7dbd
(cherry picked from commit a5ca62408381058c12bd5a1fe3b30f2512a73e03)
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 1c33e38..7cdd45fe 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -286,7 +286,7 @@
                 final String apkName = path.substring(path.lastIndexOf(File.separator));
                 boolean match = false;
                 for (String oldPath : oldPaths) {
-                    final String oldApkName = oldPath.substring(path.lastIndexOf(File.separator));
+                    final String oldApkName = oldPath.substring(oldPath.lastIndexOf(File.separator));
                     if (apkName.equals(oldApkName)) {
                         match = true;
                         break;
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java b/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
index d4623d6..82da9a3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
@@ -31,7 +31,8 @@
 
     public InterestingConfigChanges(int extraFlags) {
         mFlags = extraFlags | ActivityInfo.CONFIG_LOCALE
-                | ActivityInfo.CONFIG_UI_MODE | ActivityInfo.CONFIG_SCREEN_LAYOUT;
+                | ActivityInfo.CONFIG_UI_MODE | ActivityInfo.CONFIG_SCREEN_LAYOUT
+                | ActivityInfo.CONFIG_ASSETS_PATHS;
     }
 
     public boolean applyNewConfig(Resources res) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index ba4d46a..a692559 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -44,8 +44,11 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
+import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -70,6 +73,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
@@ -193,6 +197,14 @@
 
     static final String PERMISSION_DENIED = "Operation not permitted for user shell";
 
+    /**
+     * The system property that specifies the default overlays to apply.
+     * This is a semicolon separated list of package names.
+     *
+     * Ex: com.android.vendor.overlay_one;com.android.vendor.overlay_two
+     */
+    private static final String DEFAULT_OVERLAYS_PROP = "ro.boot.vendor.overlay.theme";
+
     private final Object mLock = new Object();
 
     private final AtomicFile mSettingsFile;
@@ -216,7 +228,8 @@
         mUserManager = UserManagerService.getInstance();
         IdmapManager im = new IdmapManager(installer);
         mSettings = new OverlayManagerSettings();
-        mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings);
+        mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
+                getDefaultOverlayPackages());
 
         final IntentFilter packageFilter = new IntentFilter();
         packageFilter.addAction(ACTION_PACKAGE_ADDED);
@@ -257,6 +270,21 @@
         updateAssets(newUserId, targets);
     }
 
+    private static Set<String> getDefaultOverlayPackages() {
+        final String str = SystemProperties.get(DEFAULT_OVERLAYS_PROP);
+        if (TextUtils.isEmpty(str)) {
+            return Collections.emptySet();
+        }
+
+        final ArraySet<String> defaultPackages = new ArraySet<>();
+        for (String packageName : str.split(";")) {
+            if (!TextUtils.isEmpty(packageName)) {
+                defaultPackages.add(packageName);
+            }
+        }
+        return defaultPackages;
+    }
+
     private final class PackageReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 0e33409..ed49383 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -27,8 +27,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.om.OverlayInfo;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
@@ -53,13 +53,16 @@
     private final PackageManagerHelper mPackageManager;
     private final IdmapManager mIdmapManager;
     private final OverlayManagerSettings mSettings;
+    private final Set<String> mDefaultOverlays;
 
     OverlayManagerServiceImpl(@NonNull final PackageManagerHelper packageManager,
             @NonNull final IdmapManager idmapManager,
-            @NonNull final OverlayManagerSettings settings) {
+            @NonNull final OverlayManagerSettings settings,
+            @NonNull final Set<String> defaultOverlays) {
         mPackageManager = packageManager;
         mIdmapManager = idmapManager;
         mSettings = settings;
+        mDefaultOverlays = defaultOverlays;
     }
 
     /*
@@ -92,12 +95,22 @@
             final PackageInfo overlayPackage = overlayPackages.get(i);
             final OverlayInfo oi = storedOverlayInfos.get(overlayPackage.packageName);
             if (oi == null || !oi.targetPackageName.equals(overlayPackage.overlayTarget)) {
-                if (oi != null) {
-                    packagesToUpdateAssets.add(oi.targetPackageName);
-                }
+                // Update the overlay if it didn't exist or had the wrong target package.
                 mSettings.init(overlayPackage.packageName, newUserId,
                         overlayPackage.overlayTarget,
                         overlayPackage.applicationInfo.getBaseCodePath());
+
+                if (oi == null) {
+                    // This overlay does not exist in our settings.
+                    if (mDefaultOverlays.contains(overlayPackage.packageName)) {
+                        // Enable this overlay by default.
+                        mSettings.setEnabled(overlayPackage.packageName, newUserId, true);
+                    }
+                } else {
+                    // The targetPackageName we have stored doesn't match the overlay's target.
+                    // Queue the old target for an update as well.
+                    packagesToUpdateAssets.add(oi.targetPackageName);
+                }
             }
 
             try {
@@ -132,7 +145,7 @@
             }
         }
 
-        return new ArrayList<String>(packagesToUpdateAssets);
+        return new ArrayList<>(packagesToUpdateAssets);
     }
 
     void onUserRemoved(final int userId) {
@@ -303,6 +316,7 @@
 
     void onDump(@NonNull final PrintWriter pw) {
         mSettings.dump(pw);
+        pw.println("Default overlays: " + TextUtils.join(";", mDefaultOverlays));
     }
 
     List<String> getEnabledOverlayPackageNames(@NonNull final String targetPackageName,
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index 44908a7..ff5c594 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -45,7 +45,6 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
-import java.util.Map;
 
 /**
  * Data structure representing the current state of all overlay packages in the
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8380983..cbd3ebb 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -496,18 +496,6 @@
     private static final String PACKAGE_SCHEME = "package";
 
     private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
-    /**
-     * If VENDOR_OVERLAY_THEME_PROPERTY is set, search for runtime resource overlay APKs also in
-     * VENDOR_OVERLAY_DIR/<value of VENDOR_OVERLAY_THEME_PROPERTY> in addition to
-     * VENDOR_OVERLAY_DIR.
-     */
-    private static final String VENDOR_OVERLAY_THEME_PROPERTY = "ro.boot.vendor.overlay.theme";
-    /**
-     * Same as VENDOR_OVERLAY_THEME_PROPERTY, except persistent. If set will override whatever
-     * is in VENDOR_OVERLAY_THEME_PROPERTY.
-     */
-    private static final String VENDOR_OVERLAY_THEME_PERSIST_PROPERTY
-            = "persist.vendor.overlay.theme";
 
     /** Permission grant: not grant the permission. */
     private static final int GRANT_DENIED = 1;
@@ -2470,16 +2458,6 @@
             // Collect vendor overlay packages. (Do this before scanning any apps.)
             // For security and version matching reason, only consider
             // overlay packages if they reside in the right directory.
-            String overlayThemeDir = SystemProperties.get(VENDOR_OVERLAY_THEME_PERSIST_PROPERTY);
-            if (overlayThemeDir.isEmpty()) {
-                overlayThemeDir = SystemProperties.get(VENDOR_OVERLAY_THEME_PROPERTY);
-            }
-            if (!overlayThemeDir.isEmpty()) {
-                scanDirTracedLI(new File(VENDOR_OVERLAY_DIR, overlayThemeDir), mDefParseFlags
-                        | PackageParser.PARSE_IS_SYSTEM
-                        | PackageParser.PARSE_IS_SYSTEM_DIR
-                        | PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
-            }
             scanDirTracedLI(new File(VENDOR_OVERLAY_DIR), mDefParseFlags
                     | PackageParser.PARSE_IS_SYSTEM
                     | PackageParser.PARSE_IS_SYSTEM_DIR
@@ -3409,6 +3387,8 @@
             return null;
         }
 
+        rebaseEnabledOverlays(packageInfo.applicationInfo, userId);
+
         packageInfo.packageName = packageInfo.applicationInfo.packageName =
                 resolveExternalPackageNameLPr(p);
 
@@ -4141,8 +4121,12 @@
             if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
-                return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId),
-                        userId);
+                ActivityInfo ri = PackageParser.generateActivityInfo(a, flags,
+                        ps.readUserState(userId), userId);
+                if (ri != null) {
+                    rebaseEnabledOverlays(ri.applicationInfo, userId);
+                }
+                return ri;
             }
         }
         return null;
@@ -4268,8 +4252,12 @@
             if (s != null && mSettings.isEnabledAndMatchLPr(s.info, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
-                return PackageParser.generateServiceInfo(s, flags, ps.readUserState(userId),
-                        userId);
+                ServiceInfo si = PackageParser.generateServiceInfo(s, flags,
+                        ps.readUserState(userId), userId);
+                if (si != null) {
+                    rebaseEnabledOverlays(si.applicationInfo, userId);
+                }
+                return si;
             }
         }
         return null;
@@ -4288,8 +4276,12 @@
             if (p != null && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {
                 PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                 if (ps == null) return null;
-                return PackageParser.generateProviderInfo(p, flags, ps.readUserState(userId),
-                        userId);
+                ProviderInfo pi = PackageParser.generateProviderInfo(p, flags,
+                        ps.readUserState(userId), userId);
+                if (pi != null) {
+                    rebaseEnabledOverlays(pi.applicationInfo, userId);
+                }
+                return pi;
             }
         }
         return null;
@@ -23184,7 +23176,7 @@
                 ArrayList<String> paths = null;
                 if (overlayPackageNames != null) {
                     final int N = overlayPackageNames.size();
-                    paths = new ArrayList<String>(N);
+                    paths = new ArrayList<>(N);
                     for (int i = 0; i < N; i++) {
                         final String packageName = overlayPackageNames.get(i);
                         final PackageParser.Package pkg = mPackages.get(packageName);
@@ -23199,7 +23191,7 @@
                 ArrayMap<String, ArrayList<String>> userSpecificOverlays =
                     mEnabledOverlayPaths.get(userId);
                 if (userSpecificOverlays == null) {
-                    userSpecificOverlays = new ArrayMap<String, ArrayList<String>>();
+                    userSpecificOverlays = new ArrayMap<>();
                     mEnabledOverlayPaths.put(userId, userSpecificOverlays);
                 }