Merge "Add new internal resolve method"
diff --git a/Android.mk b/Android.mk
index b204da7..109f610 100644
--- a/Android.mk
+++ b/Android.mk
@@ -931,6 +931,7 @@
     -since $(SRC_API_DIR)/23.txt 23 \
     -since $(SRC_API_DIR)/24.txt 24 \
     -since $(SRC_API_DIR)/25.txt 25 \
+    -since ./frameworks/base/api/current.txt O \
 		-werror -hide 111 -hide 113 \
 		-overview $(LOCAL_PATH)/core/java/overview.html
 
diff --git a/cmds/idmap/Android.mk b/cmds/idmap/Android.mk
index 50ccb07..eb6da18e 100644
--- a/cmds/idmap/Android.mk
+++ b/cmds/idmap/Android.mk
@@ -15,7 +15,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := idmap.cpp create.cpp scan.cpp inspect.cpp
+LOCAL_SRC_FILES := idmap.cpp create.cpp inspect.cpp
 
 LOCAL_SHARED_LIBRARIES := liblog libutils libandroidfw
 
diff --git a/cmds/idmap/idmap.cpp b/cmds/idmap/idmap.cpp
index 3ab1915..d388977 100644
--- a/cmds/idmap/idmap.cpp
+++ b/cmds/idmap/idmap.cpp
@@ -13,8 +13,6 @@
       idmap --help \n\
       idmap --fd target overlay fd \n\
       idmap --path target overlay idmap \n\
-      idmap --scan target-package-name-to-look-for path-to-target-apk dir-to-hold-idmaps \\\
-                   dir-to-scan [additional-dir-to-scan [additional-dir-to-scan [...]]]\n\
       idmap --inspect idmap \n\
 \n\
 DESCRIPTION \n\
@@ -49,11 +47,6 @@
       --path: create idmap for target package 'target' (path to apk) and overlay package \n\
               'overlay' (path to apk); write results to 'idmap' (path). \n\
 \n\
-      --scan: non-recursively search directory 'dir-to-scan' (path) for overlay packages with \n\
-              target package 'target-package-name-to-look-for' (package name) present at\n\
-              'path-to-target-apk' (path to apk). For each overlay package found, create an\n\
-              idmap file in 'dir-to-hold-idmaps' (path). \n\
-\n\
       --inspect: decode the binary format of 'idmap' (path) and display the contents in a \n\
                  debug-friendly format. \n\
 \n\
@@ -97,16 +90,6 @@
 NOTES \n\
       This tool and its expected invocation from installd is modelled on dexopt.";
 
-    bool verify_directory_readable(const char *path)
-    {
-        return access(path, R_OK | X_OK) == 0;
-    }
-
-    bool verify_directory_writable(const char *path)
-    {
-        return access(path, W_OK) == 0;
-    }
-
     bool verify_file_readable(const char *path)
     {
         return access(path, R_OK) == 0;
@@ -167,36 +150,6 @@
         return idmap_create_path(target_apk_path, overlay_apk_path, idmap_path);
     }
 
-    int maybe_scan(const char *target_package_name, const char *target_apk_path,
-            const char *idmap_dir, const android::Vector<const char *> *overlay_dirs)
-    {
-        if (!verify_root_or_system()) {
-            fprintf(stderr, "error: permission denied: not user root or user system\n");
-            return -1;
-        }
-
-        if (!verify_file_readable(target_apk_path)) {
-            ALOGD("error: failed to read apk %s: %s\n", target_apk_path, strerror(errno));
-            return -1;
-        }
-
-        if (!verify_directory_writable(idmap_dir)) {
-            ALOGD("error: no write access to %s: %s\n", idmap_dir, strerror(errno));
-            return -1;
-        }
-
-        const size_t N = overlay_dirs->size();
-        for (size_t i = 0; i < N; i++) {
-            const char *dir = overlay_dirs->itemAt(i);
-            if (!verify_directory_readable(dir)) {
-                ALOGD("error: no read access to %s: %s\n", dir, strerror(errno));
-                return -1;
-            }
-        }
-
-        return idmap_scan(target_package_name, target_apk_path, idmap_dir, overlay_dirs);
-    }
-
     int maybe_inspect(const char *idmap_path)
     {
         // anyone (not just root or system) may do --inspect
@@ -235,14 +188,6 @@
         return maybe_create_path(argv[2], argv[3], argv[4]);
     }
 
-    if (argc >= 6 && !strcmp(argv[1], "--scan")) {
-        android::Vector<const char *> v;
-        for (int i = 5; i < argc; i++) {
-            v.push(argv[i]);
-        }
-        return maybe_scan(argv[2], argv[3], argv[4], &v);
-    }
-
     if (argc == 3 && !strcmp(argv[1], "--inspect")) {
         return maybe_inspect(argv[2]);
     }
diff --git a/cmds/idmap/idmap.h b/cmds/idmap/idmap.h
index 8d4210b..5914de9 100644
--- a/cmds/idmap/idmap.h
+++ b/cmds/idmap/idmap.h
@@ -25,12 +25,6 @@
 
 int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, int fd);
 
-// Regarding target_package_name: the idmap_scan implementation should
-// be able to extract this from the manifest in target_apk_path,
-// simplifying the external API.
-int idmap_scan(const char *target_package_name, const char *target_apk_path,
-        const char *idmap_dir, const android::Vector<const char *> *overlay_dirs);
-
 int idmap_inspect(const char *idmap_path);
 
 #endif // _IDMAP_H_
diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
deleted file mode 100644
index ab6adfb..0000000
--- a/cmds/idmap/scan.cpp
+++ /dev/null
@@ -1,239 +0,0 @@
-#include <dirent.h>
-#include <inttypes.h>
-#include <sys/file.h>
-#include <sys/stat.h>
-
-#include "idmap.h"
-
-#include <memory>
-#include <androidfw/ResourceTypes.h>
-#include <androidfw/StreamingZipInflater.h>
-#include <androidfw/ZipFileRO.h>
-#include <private/android_filesystem_config.h> // for AID_SYSTEM
-#include <utils/SortedVector.h>
-#include <utils/String16.h>
-#include <utils/String8.h>
-
-#define NO_OVERLAY_TAG (-1000)
-
-using namespace android;
-
-namespace {
-    struct Overlay {
-        Overlay() {}
-        Overlay(const String8& a, const String8& i, int p) :
-            apk_path(a), idmap_path(i), priority(p) {}
-
-        bool operator<(Overlay const& rhs) const
-        {
-            return rhs.priority > priority;
-        }
-
-        String8 apk_path;
-        String8 idmap_path;
-        int priority;
-    };
-
-    bool writePackagesList(const char *filename, const SortedVector<Overlay>& overlayVector)
-    {
-        // the file is opened for appending so that it doesn't get truncated
-        // before we can guarantee mutual exclusion via the flock
-        FILE* fout = fopen(filename, "a");
-        if (fout == NULL) {
-            return false;
-        }
-
-        if (TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_EX)) != 0) {
-            fclose(fout);
-            return false;
-        }
-
-        if (TEMP_FAILURE_RETRY(ftruncate(fileno(fout), 0)) != 0) {
-            TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_UN));
-            fclose(fout);
-            return false;
-        }
-
-        for (size_t i = 0; i < overlayVector.size(); ++i) {
-            const Overlay& overlay = overlayVector[i];
-            fprintf(fout, "%s %s\n", overlay.apk_path.string(), overlay.idmap_path.string());
-        }
-
-        TEMP_FAILURE_RETRY(fflush(fout));
-        TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_UN));
-        fclose(fout);
-
-        // Make file world readable since Zygote (running as root) will read
-        // it when creating the initial AssetManger object
-        const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // 0644
-        if (chmod(filename, mode) == -1) {
-            unlink(filename);
-            return false;
-        }
-
-        return true;
-    }
-
-    String8 flatten_path(const char *path)
-    {
-        String16 tmp(path);
-        tmp.replaceAll('/', '@');
-        return String8(tmp);
-    }
-
-    int parse_overlay_tag(const ResXMLTree& parser, const char *target_package_name)
-    {
-        const size_t N = parser.getAttributeCount();
-        String16 target;
-        int priority = -1;
-        for (size_t i = 0; i < N; ++i) {
-            size_t len;
-            String16 key(parser.getAttributeName(i, &len));
-            if (key == String16("targetPackage")) {
-                const char16_t *p = parser.getAttributeStringValue(i, &len);
-                if (p != NULL) {
-                    target = String16(p, len);
-                }
-            } else if (key == String16("priority")) {
-                Res_value v;
-                if (parser.getAttributeValue(i, &v) == sizeof(Res_value)) {
-                    priority = v.data;
-                    if (priority < 0 || priority > 9999) {
-                        return -1;
-                    }
-                }
-            }
-        }
-        if (target == String16(target_package_name)) {
-            return priority;
-        }
-        return NO_OVERLAY_TAG;
-    }
-
-    int parse_manifest(const void *data, size_t size, const char *target_package_name)
-    {
-        ResXMLTree parser;
-        parser.setTo(data, size);
-        if (parser.getError() != NO_ERROR) {
-            ALOGD("%s failed to init xml parser, error=0x%08x\n", __FUNCTION__, parser.getError());
-            return -1;
-        }
-
-        ResXMLParser::event_code_t type;
-        do {
-            type = parser.next();
-            if (type == ResXMLParser::START_TAG) {
-                size_t len;
-                String16 tag(parser.getElementName(&len));
-                if (tag == String16("overlay")) {
-                    return parse_overlay_tag(parser, target_package_name);
-                }
-            }
-        } while (type != ResXMLParser::BAD_DOCUMENT && type != ResXMLParser::END_DOCUMENT);
-
-        return NO_OVERLAY_TAG;
-    }
-
-    int parse_apk(const char *path, const char *target_package_name)
-    {
-        std::unique_ptr<ZipFileRO> zip(ZipFileRO::open(path));
-        if (zip.get() == NULL) {
-            ALOGW("%s: failed to open zip %s\n", __FUNCTION__, path);
-            return -1;
-        }
-        ZipEntryRO entry;
-        if ((entry = zip->findEntryByName("AndroidManifest.xml")) == NULL) {
-            ALOGW("%s: failed to find entry AndroidManifest.xml\n", __FUNCTION__);
-            return -1;
-        }
-        uint32_t uncompLen = 0;
-        uint16_t method;
-        if (!zip->getEntryInfo(entry, &method, &uncompLen, NULL, NULL, NULL, NULL)) {
-            ALOGW("%s: failed to read entry info\n", __FUNCTION__);
-            return -1;
-        }
-        if (method != ZipFileRO::kCompressDeflated) {
-            ALOGW("%s: cannot handle zip compression method %" PRIu16 "\n", __FUNCTION__, method);
-            return -1;
-        }
-        FileMap *dataMap = zip->createEntryFileMap(entry);
-        if (dataMap == NULL) {
-            ALOGW("%s: failed to create FileMap\n", __FUNCTION__);
-            return -1;
-        }
-        char *buf = new char[uncompLen];
-        if (NULL == buf) {
-            ALOGW("%s: failed to allocate %" PRIu32 " byte\n", __FUNCTION__, uncompLen);
-            delete dataMap;
-            return -1;
-        }
-        StreamingZipInflater inflater(dataMap, uncompLen);
-        if (inflater.read(buf, uncompLen) < 0) {
-            ALOGW("%s: failed to inflate %" PRIu32 " byte\n", __FUNCTION__, uncompLen);
-            delete[] buf;
-            delete dataMap;
-            return -1;
-        }
-
-        int priority = parse_manifest(buf, static_cast<size_t>(uncompLen), target_package_name);
-        delete[] buf;
-        delete dataMap;
-        return priority;
-    }
-}
-
-int idmap_scan(const char *target_package_name, const char *target_apk_path,
-        const char *idmap_dir, const android::Vector<const char *> *overlay_dirs)
-{
-    String8 filename = String8(idmap_dir);
-    filename.appendPath("overlays.list");
-
-    SortedVector<Overlay> overlayVector;
-    const size_t N = overlay_dirs->size();
-    for (size_t i = 0; i < N; ++i) {
-        const char *overlay_dir = overlay_dirs->itemAt(i);
-        DIR *dir = opendir(overlay_dir);
-        if (dir == NULL) {
-            return EXIT_FAILURE;
-        }
-
-        struct dirent *dirent;
-        while ((dirent = readdir(dir)) != NULL) {
-            struct stat st;
-            char overlay_apk_path[PATH_MAX + 1];
-            snprintf(overlay_apk_path, PATH_MAX, "%s/%s", overlay_dir, dirent->d_name);
-            if (stat(overlay_apk_path, &st) < 0) {
-                continue;
-            }
-            if (!S_ISREG(st.st_mode)) {
-                continue;
-            }
-
-            int priority = parse_apk(overlay_apk_path, target_package_name);
-            if (priority < 0) {
-                continue;
-            }
-
-            String8 idmap_path(idmap_dir);
-            idmap_path.appendPath(flatten_path(overlay_apk_path + 1));
-            idmap_path.append("@idmap");
-
-            if (idmap_create_path(target_apk_path, overlay_apk_path, idmap_path.string()) != 0) {
-                ALOGE("error: failed to create idmap for target=%s overlay=%s idmap=%s\n",
-                        target_apk_path, overlay_apk_path, idmap_path.string());
-                continue;
-            }
-
-            Overlay overlay(String8(overlay_apk_path), idmap_path, priority);
-            overlayVector.add(overlay);
-        }
-
-        closedir(dir);
-    }
-
-    if (!writePackagesList(filename.string(), overlayVector)) {
-        return EXIT_FAILURE;
-    }
-
-    return EXIT_SUCCESS;
-}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 56f1e0c..f801e45 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2065,9 +2065,6 @@
                         com.android.internal.R.styleable.AndroidManifestResourceOverlay);
                 pkg.mOverlayTarget = sa.getString(
                         com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage);
-                pkg.mOverlayPriority = sa.getInt(
-                        com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority,
-                        -1);
                 sa.recycle();
 
                 if (pkg.mOverlayTarget == null) {
@@ -2075,12 +2072,6 @@
                     mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                     return null;
                 }
-                if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) {
-                    outError[0] = "<overlay> priority must be between 0 and 9999";
-                    mParseError =
-                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
-                    return null;
-                }
                 XmlUtils.skipCurrentTag(parser);
 
             } else if (tagName.equals(TAG_KEY_SETS)) {
@@ -5518,7 +5509,6 @@
         public String mRequiredAccountType;
 
         public String mOverlayTarget;
-        public int mOverlayPriority;
         public boolean mTrustedOverlay;
 
         /**
@@ -5995,7 +5985,6 @@
             mRestrictedAccountType = dest.readString();
             mRequiredAccountType = dest.readString();
             mOverlayTarget = dest.readString();
-            mOverlayPriority = dest.readInt();
             mTrustedOverlay = (dest.readInt() == 1);
             mSigningKeys = (ArraySet<PublicKey>) dest.readArraySet(boot);
             mUpgradeKeySets = (ArraySet<String>) dest.readArraySet(boot);
@@ -6111,7 +6100,6 @@
             dest.writeString(mRestrictedAccountType);
             dest.writeString(mRequiredAccountType);
             dest.writeString(mOverlayTarget);
-            dest.writeInt(mOverlayPriority);
             dest.writeInt(mTrustedOverlay ? 1 : 0);
             dest.writeArraySet(mSigningKeys);
             dest.writeArraySet(mUpgradeKeySets);
@@ -6560,6 +6548,7 @@
             ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
         }
         ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
+        ai.resourceDirs = state.resourceDirs;
     }
 
     public static ApplicationInfo generateApplicationInfo(Package p, int flags,
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 24f1164..ee56a18 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -31,6 +31,8 @@
 
 import com.android.internal.util.ArrayUtils;
 
+import java.util.Arrays;
+
 /**
  * Per-user state information about a package.
  * @hide
@@ -54,6 +56,8 @@
     public ArraySet<String> disabledComponents;
     public ArraySet<String> enabledComponents;
 
+    public String[] resourceDirs;
+
     public PackageUserState() {
         installed = true;
         hidden = false;
@@ -81,6 +85,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);
     }
 
     /**
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 37e32ff..4cf55ba 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -222,19 +222,21 @@
      */
     final boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue,
             boolean resolveRefs) {
-        final int block = loadResourceValue(resId, (short) densityDpi, outValue, resolveRefs);
-        if (block < 0) {
-            return false;
-        }
+        synchronized (this) {
+            final int block = loadResourceValue(resId, (short) densityDpi, outValue, resolveRefs);
+            if (block < 0) {
+                return false;
+            }
 
-        // Convert the changing configurations flags populated by native code.
-        outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
-                outValue.changingConfigurations);
+            // Convert the changing configurations flags populated by native code.
+            outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
+                    outValue.changingConfigurations);
 
-        if (outValue.type == TypedValue.TYPE_STRING) {
-            outValue.string = mStringBlocks[block].get(outValue.data);
+            if (outValue.type == TypedValue.TYPE_STRING) {
+                outValue.string = mStringBlocks[block].get(outValue.data);
+            }
+            return true;
         }
-        return true;
     }
 
     /**
@@ -244,18 +246,20 @@
      * @param resId the resource id of the string array
      */
     final CharSequence[] getResourceTextArray(@ArrayRes int resId) {
-        final int[] rawInfoArray = getArrayStringInfo(resId);
-        final int rawInfoArrayLen = rawInfoArray.length;
-        final int infoArrayLen = rawInfoArrayLen / 2;
-        int block;
-        int index;
-        final CharSequence[] retArray = new CharSequence[infoArrayLen];
-        for (int i = 0, j = 0; i < rawInfoArrayLen; i = i + 2, j++) {
-            block = rawInfoArray[i];
-            index = rawInfoArray[i + 1];
-            retArray[j] = index >= 0 ? mStringBlocks[block].get(index) : null;
+        synchronized (this) {
+            final int[] rawInfoArray = getArrayStringInfo(resId);
+            final int rawInfoArrayLen = rawInfoArray.length;
+            final int infoArrayLen = rawInfoArrayLen / 2;
+            int block;
+            int index;
+            final CharSequence[] retArray = new CharSequence[infoArrayLen];
+            for (int i = 0, j = 0; i < rawInfoArrayLen; i = i + 2, j++) {
+                block = rawInfoArray[i];
+                index = rawInfoArray[i + 1];
+                retArray[j] = index >= 0 ? mStringBlocks[block].get(index) : null;
+            }
+            return retArray;
         }
-        return retArray;
     }
 
     /**
@@ -320,8 +324,10 @@
     }
 
     /*package*/ final CharSequence getPooledStringForCookie(int cookie, int id) {
-        // Cookies map to string blocks starting at 1.
-        return mStringBlocks[cookie - 1].get(id);
+        synchronized (this) {
+            // Cookies map to string blocks starting at 1.
+            return mStringBlocks[cookie - 1].get(id);
+        }
     }
 
     /**
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index 356804e..80ec03e 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -189,7 +189,9 @@
         // TODO: replace this with a discovery-based method that looks into /system/usr/hyphen-data
         String[] availableLanguages = {
             "as",
+            "bg",
             "bn",
+            "cu",
             "cy",
             "da",
             "de-1901", "de-1996", "de-CH-1901",
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 3d012bf..67f9f8f 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -59,6 +59,7 @@
     private static final int ALLOW_LIBS = 0x02;
     private static final int ALLOW_PERMISSIONS = 0x04;
     private static final int ALLOW_APP_CONFIGS = 0x08;
+    private static final int ALLOW_PRIVAPP_PERMISSIONS = 0x10;
     private static final int ALLOW_ALL = ~0;
 
     // Group-ids that are given to all packages as read from etc/permissions/*.xml.
@@ -225,6 +226,13 @@
         // Read configuration from the old permissions dir
         readPermissions(Environment.buildPath(
                 Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
+        // Allow Vendor to customize system configs around libs, features, permissions and apps
+        int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
+                ALLOW_APP_CONFIGS;
+        readPermissions(Environment.buildPath(
+                Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
+        readPermissions(Environment.buildPath(
+                Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
         // Allow ODM to customize system configs around libs, features and apps
         int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS;
         readPermissions(Environment.buildPath(
@@ -313,6 +321,7 @@
             boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0;
             boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;
             boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0;
+            boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS) != 0;
             while (true) {
                 XmlUtils.nextElement(parser);
                 if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
@@ -553,7 +562,7 @@
                         associatedPkgs.add(pkgname);
                     }
                     XmlUtils.skipCurrentTag(parser);
-                } else if ("privapp-permissions".equals(name) && allowAppConfigs) {
+                } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) {
                     readPrivAppPermissions(parser);
                 } else {
                     XmlUtils.skipCurrentTag(parser);
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 723dce6..314595f 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -119,96 +119,6 @@
     return block;
 }
 
-// This is called by zygote (running as user root) as part of preloadResources.
-static void verifySystemIdmaps()
-{
-    pid_t pid;
-    char system_id[10];
-
-    snprintf(system_id, sizeof(system_id), "%d", AID_SYSTEM);
-
-    switch (pid = fork()) {
-        case -1:
-            ALOGE("failed to fork for idmap: %s", strerror(errno));
-            break;
-        case 0: // child
-            {
-                struct __user_cap_header_struct capheader;
-                struct __user_cap_data_struct capdata;
-
-                memset(&capheader, 0, sizeof(capheader));
-                memset(&capdata, 0, sizeof(capdata));
-
-                capheader.version = _LINUX_CAPABILITY_VERSION;
-                capheader.pid = 0;
-
-                if (capget(&capheader, &capdata) != 0) {
-                    ALOGE("capget: %s\n", strerror(errno));
-                    exit(1);
-                }
-
-                capdata.effective = capdata.permitted;
-                if (capset(&capheader, &capdata) != 0) {
-                    ALOGE("capset: %s\n", strerror(errno));
-                    exit(1);
-                }
-
-                if (setgid(AID_SYSTEM) != 0) {
-                    ALOGE("setgid: %s\n", strerror(errno));
-                    exit(1);
-                }
-
-                if (setuid(AID_SYSTEM) != 0) {
-                    ALOGE("setuid: %s\n", strerror(errno));
-                    exit(1);
-                }
-
-                // Generic idmap parameters
-                const char* argv[8];
-                int argc = 0;
-                struct stat st;
-
-                memset(argv, NULL, sizeof(argv));
-                argv[argc++] = AssetManager::IDMAP_BIN;
-                argv[argc++] = "--scan";
-                argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
-                argv[argc++] = AssetManager::TARGET_APK_PATH;
-                argv[argc++] = AssetManager::IDMAP_DIR;
-
-                // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
-                // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
-                char subdir[PROP_VALUE_MAX];
-                int len = __system_property_get(AssetManager::OVERLAY_THEME_DIR_PERSIST_PROPERTY,
-                        subdir);
-                if (len == 0) {
-                    len = __system_property_get(AssetManager::OVERLAY_THEME_DIR_PROPERTY, subdir);
-                }
-                if (len > 0) {
-                    String8 overlayPath = String8(AssetManager::OVERLAY_DIR) + "/" + subdir;
-                    if (stat(overlayPath.string(), &st) == 0) {
-                        argv[argc++] = overlayPath.string();
-                    }
-                }
-                if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
-                    argv[argc++] = AssetManager::OVERLAY_DIR;
-                }
-
-                // Finally, invoke idmap (if any overlay directory exists)
-                if (argc > 5) {
-                    execv(AssetManager::IDMAP_BIN, (char* const*)argv);
-                    ALOGE("failed to execv for idmap: %s", strerror(errno));
-                    exit(1); // should never get here
-                } else {
-                    exit(0);
-                }
-            }
-            break;
-        default: // parent
-            waitpid(pid, NULL, 0);
-            break;
-    }
-}
-
 // ----------------------------------------------------------------------------
 
 // this guy is exported to other jni routines
@@ -1597,9 +1507,6 @@
 
 static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
 {
-    if (isSystem) {
-        verifySystemIdmaps();
-    }
     AssetManager* am = new AssetManager();
     if (am == NULL) {
         jniThrowException(env, "java/lang/OutOfMemoryError", "");
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index acacd76..84111ae 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -202,15 +202,6 @@
         *cookie = static_cast<int32_t>(mAssetPaths.size());
     }
 
-#ifdef __ANDROID__
-    // Load overlays, if any
-    asset_path oap;
-    for (size_t idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) {
-        oap.isSystemAsset = isSystemAsset;
-        mAssetPaths.add(oap);
-    }
-#endif
-
     if (mResources != NULL) {
         appendPathToResTable(ap, appAsLib);
     }
@@ -493,11 +484,6 @@
 }
 
 bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) const {
-    // skip those ap's that correspond to system overlays
-    if (ap.isSystemOverlay) {
-        return true;
-    }
-
     Asset* ass = NULL;
     ResTable* sharedRes = NULL;
     bool shared = true;
@@ -539,14 +525,6 @@
                 ALOGV("Creating shared resources for %s", ap.path.string());
                 sharedRes = new ResTable();
                 sharedRes->add(ass, idmap, nextEntryIdx + 1, false);
-#ifdef __ANDROID__
-                const char* data = getenv("ANDROID_DATA");
-                LOG_ALWAYS_FATAL_IF(data == NULL, "ANDROID_DATA not set");
-                String8 overlaysListPath(data);
-                overlaysListPath.appendPath(kResourceCache);
-                overlaysListPath.appendPath("overlays.list");
-                addSystemOverlays(overlaysListPath.string(), ap.path, sharedRes, nextEntryIdx);
-#endif
                 sharedRes = const_cast<AssetManager*>(this)->
                     mZipSet.setZipResourceTable(ap.path, sharedRes);
             }
@@ -655,58 +633,6 @@
     return ass;
 }
 
-void AssetManager::addSystemOverlays(const char* pathOverlaysList,
-        const String8& targetPackagePath, ResTable* sharedRes, size_t offset) const
-{
-    FILE* fin = fopen(pathOverlaysList, "r");
-    if (fin == NULL) {
-        return;
-    }
-
-#ifndef _WIN32
-    if (TEMP_FAILURE_RETRY(flock(fileno(fin), LOCK_SH)) != 0) {
-        fclose(fin);
-        return;
-    }
-#endif
-    char buf[1024];
-    while (fgets(buf, sizeof(buf), fin)) {
-        // format of each line:
-        //   <path to apk><space><path to idmap><newline>
-        char* space = strchr(buf, ' ');
-        char* newline = strchr(buf, '\n');
-        asset_path oap;
-
-        if (space == NULL || newline == NULL || newline < space) {
-            continue;
-        }
-
-        oap.path = String8(buf, space - buf);
-        oap.type = kFileTypeRegular;
-        oap.idmap = String8(space + 1, newline - space - 1);
-        oap.isSystemOverlay = true;
-
-        Asset* oass = const_cast<AssetManager*>(this)->
-            openNonAssetInPathLocked("resources.arsc",
-                    Asset::ACCESS_BUFFER,
-                    oap);
-
-        if (oass != NULL) {
-            Asset* oidmap = openIdmapLocked(oap);
-            offset++;
-            sharedRes->add(oass, oidmap, offset + 1, false);
-            const_cast<AssetManager*>(this)->mAssetPaths.add(oap);
-            const_cast<AssetManager*>(this)->mZipSet.addOverlay(targetPackagePath, oap);
-            delete oidmap;
-        }
-    }
-
-#ifndef _WIN32
-    TEMP_FAILURE_RETRY(flock(fileno(fin), LOCK_UN));
-#endif
-    fclose(fin);
-}
-
 const ResTable& AssetManager::getResources(bool required) const
 {
     const ResTable* rt = getResTable(required);
@@ -1446,20 +1372,6 @@
     return mModWhen == modWhen;
 }
 
-void AssetManager::SharedZip::addOverlay(const asset_path& ap)
-{
-    mOverlays.add(ap);
-}
-
-bool AssetManager::SharedZip::getOverlay(size_t idx, asset_path* out) const
-{
-    if (idx >= mOverlays.size()) {
-        return false;
-    }
-    *out = mOverlays[idx];
-    return true;
-}
-
 AssetManager::SharedZip::~SharedZip()
 {
     if (kIsDebug) {
@@ -1578,22 +1490,6 @@
     return true;
 }
 
-void AssetManager::ZipSet::addOverlay(const String8& path, const asset_path& overlay)
-{
-    int idx = getIndex(path);
-    sp<SharedZip> zip = mZipFile[idx];
-    zip->addOverlay(overlay);
-}
-
-bool AssetManager::ZipSet::getOverlay(const String8& path, size_t idx, asset_path* out) const
-{
-    sp<SharedZip> zip = SharedZip::get(path, false);
-    if (zip == NULL) {
-        return false;
-    }
-    return zip->getOverlay(idx, out);
-}
-
 /*
  * Compute the zip file's index.
  *
diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h
index becd307..f1e8b93 100644
--- a/libs/androidfw/include/androidfw/AssetManager.h
+++ b/libs/androidfw/include/androidfw/AssetManager.h
@@ -202,12 +202,10 @@
 private:
     struct asset_path
     {
-        asset_path() : path(""), type(kFileTypeRegular), idmap(""),
-                       isSystemOverlay(false), isSystemAsset(false) {}
+        asset_path() : path(""), type(kFileTypeRegular), idmap(""), isSystemAsset(false) {}
         String8 path;
         FileType type;
         String8 idmap;
-        bool isSystemOverlay;
         bool isSystemAsset;
     };
 
@@ -237,9 +235,6 @@
 
     Asset* openIdmapLocked(const struct asset_path& ap) const;
 
-    void addSystemOverlays(const char* pathOverlaysList, const String8& targetPackagePath,
-            ResTable* sharedRes, size_t offset) const;
-
     class SharedZip : public RefBase {
     public:
         static sp<SharedZip> get(const String8& path, bool createIfNotPresent = true);
@@ -254,9 +249,6 @@
 
         bool isUpToDate();
 
-        void addOverlay(const asset_path& ap);
-        bool getOverlay(size_t idx, asset_path* out) const;
-
     protected:
         ~SharedZip();
 
@@ -271,8 +263,6 @@
         Asset* mResourceTableAsset;
         ResTable* mResourceTable;
 
-        Vector<asset_path> mOverlays;
-
         static Mutex gLock;
         static DefaultKeyedVector<String8, wp<SharedZip> > gOpen;
     };
@@ -306,9 +296,6 @@
 
         bool isUpToDate();
 
-        void addOverlay(const String8& path, const asset_path& overlay);
-        bool getOverlay(const String8& path, size_t idx, asset_path* out) const;
-
     private:
         void closeZip(int idx);
 
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 34164b16..5b4dd48 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -118,6 +118,8 @@
     <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
     <!-- Permission needed to hold a wakelock in dumpstate.cpp (drop_root_user()) -->
     <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <!-- Permission needed to enable/disable overlays -->
+    <uses-permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES" />
 
     <application android:label="@string/app_label"
                  android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/res/values/arrays_tv.xml b/packages/SystemUI/res/values/arrays_tv.xml
new file mode 100644
index 0000000..08b1ab1
--- /dev/null
+++ b/packages/SystemUI/res/values/arrays_tv.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2017, 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.
+ */
+-->
+<resources>
+    <!-- List of package name or class name which are considered as Settings,
+         so PIP location should be adjusted to the left of the side panel.
+         This can be overriden in an overlay -->
+    <string-array name="tv_pip_settings_class_name" translatable="false">
+        <item>com.android.tv.settings</item>
+        <item>com.google.android.leanbacklauncher/.settings.HomeScreenSettingsActivity</item>
+        <item>com.google.android.apps.mediashell/.settings.CastSettingsActivity</item>
+        <item>com.google.android.katniss.setting/.SpeechSettingsActivity</item>
+        <item>com.google.android.katniss.setting/.SearchSettingsActivity</item>
+        <item>com.google.android.gsf.notouch/.UsageDiagnosticsSettingActivity</item>
+    </string-array>
+</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 376a0b6..df01aab 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -68,34 +68,10 @@
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private static final boolean DEBUG_FORCE_ONBOARDING =
             SystemProperties.getBoolean("debug.tv.pip_force_onboarding", false);
+    private static final String SETTINGS_PACKAGE_AND_CLASS_DELIMITER = "/";
 
     private static PipManager sPipManager;
-
-    /**
-     * List of package and class name which are considered as Settings,
-     * so PIP location should be adjusted to the left of the side panel.
-     */
-    private static final List<Pair<String, String>> sSettingsPackageAndClassNamePairList;
-    static {
-        sSettingsPackageAndClassNamePairList = new ArrayList<>();
-        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
-                "com.android.tv.settings", null));
-        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
-                "com.google.android.leanbacklauncher",
-                "com.google.android.leanbacklauncher.settings.HomeScreenSettingsActivity"));
-        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
-                "com.google.android.apps.mediashell",
-                "com.google.android.apps.mediashell.settings.CastSettingsActivity"));
-        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
-                "com.google.android.katniss",
-                "com.google.android.katniss.setting.SpeechSettingsActivity"));
-        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
-                "com.google.android.katniss",
-                "com.google.android.katniss.setting.SearchSettingsActivity"));
-        sSettingsPackageAndClassNamePairList.add(new Pair<String, String>(
-                "com.google.android.gsf.notouch",
-                "com.google.android.gsf.notouch.UsageDiagnosticsSettingActivity"));
-    }
+    private static List<Pair<String, String>> sSettingsPackageAndClassNamePairList;
 
     /**
      * State when there's no PIP.
@@ -252,6 +228,31 @@
         mOnboardingShown = Prefs.getBoolean(
                 mContext, TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN, false);
 
+        if (sSettingsPackageAndClassNamePairList == null) {
+            String[] settings = mContext.getResources().getStringArray(
+                    R.array.tv_pip_settings_class_name);
+            sSettingsPackageAndClassNamePairList = new ArrayList<>();
+            if (settings != null) {
+                for (int i = 0; i < settings.length; i++) {
+                    Pair<String, String> entry = null;
+                    String[] packageAndClassName =
+                            settings[i].split(SETTINGS_PACKAGE_AND_CLASS_DELIMITER);
+                    switch (packageAndClassName.length) {
+                        case 1:
+                            entry = Pair.<String, String>create(packageAndClassName[0], null);
+                            break;
+                        case 2:
+                            entry = Pair.<String, String>create(
+                                    packageAndClassName[0],
+                                    packageAndClassName[0] + packageAndClassName[1]);
+                    }
+                    if (entry != null) {
+                        sSettingsPackageAndClassNamePairList.add(entry);
+                    }
+                }
+            }
+        }
+
         loadConfigurationsAndApply();
         mPipRecentsOverlayManager = new PipRecentsOverlayManager(context);
         mMediaSessionManager =
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index 3f97d4f..cb13a3d 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.os.Trace;
 import android.util.Slog;
@@ -105,22 +106,25 @@
                         + ": service constructor threw an exception", ex);
             }
 
-            // Register it.
-            mServices.add(service);
-
-            // Start it.
-            try {
-                service.onStart();
-            } catch (RuntimeException ex) {
-                throw new RuntimeException("Failed to start service " + name
-                        + ": onStart threw an exception", ex);
-            }
+            startService(service);
             return service;
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
         }
     }
 
+    public void startService(@NonNull final SystemService service) {
+        // Register it.
+        mServices.add(service);
+        // Start it.
+        try {
+            service.onStart();
+        } catch (RuntimeException ex) {
+            throw new RuntimeException("Failed to start service " + service.getClass().getName()
+                    + ": onStart threw an exception", ex);
+        }
+    }
+
     /**
      * Starts the specified boot phase for all system services that have been started up to
      * this point.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 30b267f..7524351 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -23165,10 +23165,11 @@
     }
 
     void updateApplicationInfoLocked(@NonNull List<String> packagesToUpdate, int userId) {
+        final PackageManagerInternal packageManager = getPackageManagerInternalLocked();
         final boolean updateFrameworkRes = packagesToUpdate.contains("android");
         for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
             final ProcessRecord app = mLruProcesses.get(i);
-            if (app.thread == null) {
+            if (app.thread == null || app.pid == Process.myPid()) {
                 continue;
             }
 
@@ -23181,7 +23182,7 @@
                 final String packageName = app.pkgList.keyAt(j);
                 if (updateFrameworkRes || packagesToUpdate.contains(packageName)) {
                     try {
-                        final ApplicationInfo ai = mPackageManagerInt.getApplicationInfo(
+                        final ApplicationInfo ai = packageManager.getApplicationInfo(
                                 packageName, app.userId);
                         if (ai != null) {
                             app.thread.scheduleApplicationInfoChanged(ai);
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index cc709ce..ba4d46a 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -26,7 +26,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -42,7 +41,6 @@
 import android.os.Binder;
 import android.os.Environment;
 import android.os.IBinder;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
@@ -646,7 +644,7 @@
                     Slog.d(TAG, String.format("send broadcast %s", intent));
                 }
                 try {
-                    ActivityManagerNative.getDefault().broadcastIntent(null, intent, null, null, 0,
+                    ActivityManager.getService().broadcastIntent(null, intent, null, null, 0,
                             null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false,
                             userId);
                 } catch (RemoteException e) {
@@ -664,7 +662,38 @@
     }
 
     private void updateAssets(final int userId, List<String> targetPackageNames) {
-        // TODO: implement when we integrate OMS properly
+        final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
+        final boolean updateFrameworkRes = targetPackageNames.contains("android");
+        if (updateFrameworkRes) {
+            targetPackageNames = pm.getTargetPackageNames(userId);
+        }
+
+        final Map<String, List<String>> pendingChanges = new ArrayMap<>(targetPackageNames.size());
+        synchronized (mLock) {
+            final int N = targetPackageNames.size();
+            for (int i = 0; i < N; i++) {
+                final String targetPackageName = targetPackageNames.get(i);
+                pendingChanges.put(targetPackageName,
+                        mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
+            }
+        }
+
+        final int N = targetPackageNames.size();
+        for (int i = 0; i < N; i++) {
+            final String targetPackageName = targetPackageNames.get(i);
+            if (!pm.setEnabledOverlayPackages(
+                        userId, targetPackageName, pendingChanges.get(targetPackageName))) {
+                Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
+                            targetPackageName, userId));
+            }
+        }
+
+        final IActivityManager am = ActivityManager.getService();
+        try {
+            am.scheduleApplicationInfoChanged(targetPackageNames, userId);
+        } catch (RemoteException e) {
+            // Intentionally left empty.
+        }
     }
 
     private void schedulePersistSettings() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 33bd350..fbf953f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -661,9 +661,12 @@
     final ArrayMap<String, Set<String>> mKnownCodebase =
             new ArrayMap<String, Set<String>>();
 
-    // Tracks available target package names -> overlay package paths.
-    final ArrayMap<String, ArrayMap<String, PackageParser.Package>> mOverlays =
-        new ArrayMap<String, ArrayMap<String, PackageParser.Package>>();
+    // 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
@@ -3734,6 +3737,7 @@
             ApplicationInfo ai = PackageParser.generateApplicationInfo(ps.pkg, flags,
                     ps.readUserState(userId), userId);
             if (ai != null) {
+                rebaseEnabledOverlays(ai, userId);
                 ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
             }
             return ai;
@@ -3768,6 +3772,7 @@
                 ApplicationInfo ai = PackageParser.generateApplicationInfo(
                         p, flags, ps.readUserState(userId), userId);
                 if (ai != null) {
+                    rebaseEnabledOverlays(ai, userId);
                     ai.packageName = resolveExternalPackageNameLPr(p);
                 }
                 return ai;
@@ -3784,6 +3789,26 @@
         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;
@@ -7214,6 +7239,7 @@
                         ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags,
                                 ps.readUserState(userId), userId);
                         if (ai != null) {
+                            rebaseEnabledOverlays(ai, userId);
                             ai.packageName = resolveExternalPackageNameLPr(ps.pkg);
                         }
                     } else {
@@ -7237,6 +7263,7 @@
                         ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
                                 ps.readUserState(userId), userId);
                         if (ai != null) {
+                            rebaseEnabledOverlays(ai, userId);
                             ai.packageName = resolveExternalPackageNameLPr(p);
                             list.add(ai);
                         }
@@ -7380,6 +7407,7 @@
                         ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
                                 ps.readUserState(userId), userId);
                         if (ai != null) {
+                            rebaseEnabledOverlays(ai, userId);
                             finalList.add(ai);
                         }
                     }
@@ -7515,60 +7543,6 @@
         return finalList;
     }
 
-    private void createIdmapsForPackageLI(PackageParser.Package pkg) {
-        ArrayMap<String, PackageParser.Package> overlays = mOverlays.get(pkg.packageName);
-        if (overlays == null) {
-            Slog.w(TAG, "Unable to create idmap for " + pkg.packageName + ": no overlay packages");
-            return;
-        }
-        for (PackageParser.Package opkg : overlays.values()) {
-            // Not much to do if idmap fails: we already logged the error
-            // and we certainly don't want to abort installation of pkg simply
-            // because an overlay didn't fit properly. For these reasons,
-            // ignore the return value of createIdmapForPackagePairLI.
-            createIdmapForPackagePairLI(pkg, opkg);
-        }
-    }
-
-    private boolean createIdmapForPackagePairLI(PackageParser.Package pkg,
-            PackageParser.Package opkg) {
-        if (!opkg.mTrustedOverlay) {
-            Slog.w(TAG, "Skipping target and overlay pair " + pkg.baseCodePath + " and " +
-                    opkg.baseCodePath + ": overlay not trusted");
-            return false;
-        }
-        ArrayMap<String, PackageParser.Package> overlaySet = mOverlays.get(pkg.packageName);
-        if (overlaySet == null) {
-            Slog.e(TAG, "was about to create idmap for " + pkg.baseCodePath + " and " +
-                    opkg.baseCodePath + " but target package has no known overlays");
-            return false;
-        }
-        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
-        // TODO: generate idmap for split APKs
-        try {
-            mInstaller.idmap(pkg.baseCodePath, opkg.baseCodePath, sharedGid);
-        } catch (InstallerException e) {
-            Slog.e(TAG, "Failed to generate idmap for " + pkg.baseCodePath + " and "
-                    + opkg.baseCodePath);
-            return false;
-        }
-        PackageParser.Package[] overlayArray =
-            overlaySet.values().toArray(new PackageParser.Package[0]);
-        Comparator<PackageParser.Package> cmp = new Comparator<PackageParser.Package>() {
-            public int compare(PackageParser.Package p1, PackageParser.Package p2) {
-                return p1.mOverlayPriority - p2.mOverlayPriority;
-            }
-        };
-        Arrays.sort(overlayArray, cmp);
-
-        pkg.applicationInfo.resourceDirs = new String[overlayArray.length];
-        int i = 0;
-        for (PackageParser.Package p : overlayArray) {
-            pkg.applicationInfo.resourceDirs[i++] = p.baseCodePath;
-        }
-        return true;
-    }
-
     private void scanDirTracedLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + dir.getAbsolutePath() + "]");
         try {
@@ -10057,7 +10031,6 @@
         // writer
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
 
-        boolean createIdmapFailed = false;
         synchronized (mPackages) {
             // We don't expect installation to fail beyond this point
 
@@ -10398,36 +10371,9 @@
                     mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i));
                 }
             }
-
-            // Create idmap files for pairs of (packages, overlay packages).
-            // Note: "android", ie framework-res.apk, is handled by native layers.
-            if (pkg.mOverlayTarget != null) {
-                // This is an overlay package.
-                if (pkg.mOverlayTarget != null && !pkg.mOverlayTarget.equals("android")) {
-                    if (!mOverlays.containsKey(pkg.mOverlayTarget)) {
-                        mOverlays.put(pkg.mOverlayTarget,
-                                new ArrayMap<String, PackageParser.Package>());
-                    }
-                    ArrayMap<String, PackageParser.Package> map = mOverlays.get(pkg.mOverlayTarget);
-                    map.put(pkg.packageName, pkg);
-                    PackageParser.Package orig = mPackages.get(pkg.mOverlayTarget);
-                    if (orig != null && !createIdmapForPackagePairLI(orig, pkg)) {
-                        createIdmapFailed = true;
-                    }
-                }
-            } else if (mOverlays.containsKey(pkg.packageName) &&
-                    !pkg.packageName.equals("android")) {
-                // This is a regular package, with one or more known overlay packages.
-                createIdmapsForPackageLI(pkg);
-            }
         }
 
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-
-        if (createIdmapFailed) {
-            throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
-                    "scanPackageLI failed to createIdmap");
-        }
     }
 
     private static void maybeRenameForeignDexMarkers(PackageParser.Package existing,
@@ -20226,6 +20172,7 @@
         public static final int DUMP_FROZEN = 1 << 19;
         public static final int DUMP_DEXOPT = 1 << 20;
         public static final int DUMP_COMPILER_STATS = 1 << 21;
+        public static final int DUMP_ENABLED_OVERLAYS = 1 << 22;
 
         public static final int OPTION_SHOW_FILTERS = 1 << 0;
 
@@ -20345,6 +20292,7 @@
                 pw.println("    check-permission <permission> <package> [<user>]: does pkg hold perm?");
                 pw.println("    dexopt: dump dexopt state");
                 pw.println("    compiler-stats: dump compiler statistics");
+                pw.println("    enabled-overlays: dump list of enabled overlay packages");
                 pw.println("    <package.name>: info about given package");
                 return;
             } else if ("--checkin".equals(opt)) {
@@ -20473,6 +20421,8 @@
                 dumpState.setDump(DumpState.DUMP_DEXOPT);
             } else if ("compiler-stats".equals(cmd)) {
                 dumpState.setDump(DumpState.DUMP_COMPILER_STATS);
+            } else if ("enabled-overlays".equals(cmd)) {
+                dumpState.setDump(DumpState.DUMP_ENABLED_OVERLAYS);
             } else if ("write".equals(cmd)) {
                 synchronized (mPackages) {
                     mSettings.writeLPr();
@@ -20843,6 +20793,11 @@
                 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);
@@ -20939,6 +20894,23 @@
         }
     }
 
+    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();
@@ -23040,10 +23012,43 @@
         }
 
         @Override
-        public boolean setEnabledOverlayPackages(int userId, String targetPackageName,
-                List<String> overlayPackageNames) {
-            // TODO: implement when we integrate OMS properly
-            return false;
+        public boolean setEnabledOverlayPackages(int userId, @NonNull String targetPackageName,
+                @Nullable List<String> overlayPackageNames) {
+            synchronized (mPackages) {
+                if (targetPackageName == null || mPackages.get(targetPackageName) == null) {
+                    Slog.e(TAG, "failed to find package " + targetPackageName);
+                    return false;
+                }
+
+                ArrayList<String> paths = null;
+                if (overlayPackageNames != null) {
+                    final int N = overlayPackageNames.size();
+                    paths = new ArrayList<String>(N);
+                    for (int i = 0; i < N; i++) {
+                        final String packageName = overlayPackageNames.get(i);
+                        final PackageParser.Package pkg = mPackages.get(packageName);
+                        if (pkg == null) {
+                            Slog.e(TAG, "failed to find package " + packageName);
+                            return false;
+                        }
+                        paths.add(pkg.baseCodePath);
+                    }
+                }
+
+                ArrayMap<String, ArrayList<String>> userSpecificOverlays =
+                    mEnabledOverlayPaths.get(userId);
+                if (userSpecificOverlays == null) {
+                    userSpecificOverlays = new ArrayMap<String, ArrayList<String>>();
+                    mEnabledOverlayPaths.put(userId, userSpecificOverlays);
+                }
+
+                if (paths != null && paths.size() > 0) {
+                    userSpecificOverlays.put(targetPackageName, paths);
+                } else {
+                    userSpecificOverlays.remove(targetPackageName);
+                }
+                return true;
+            }
         }
 
         public ResolveInfo resolveIntent(Intent intent, String resolvedType,
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a5f1945..e586482 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -82,6 +82,7 @@
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
 import com.android.server.notification.NotificationManagerService;
+import com.android.server.om.OverlayManagerService;
 import com.android.server.os.DeviceIdentifiersPolicyService;
 import com.android.server.os.SchedulingPolicyService;
 import com.android.server.pm.Installer;
@@ -592,6 +593,11 @@
         mActivityManagerService.setSystemProcess();
         traceEnd();
 
+        // Manages Overlay packages
+        traceBeginAndSlog("StartOverlayManagerService");
+        mSystemServiceManager.startService(new OverlayManagerService(mSystemContext, installer));
+        traceEnd();
+
         // The sensor service needs access to package manager service, app ops
         // service, and permissions service, therefore we start it after them.
         // Start sensor service in a separate thread. Completion should be checked
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 384f49f..28596f7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -197,7 +197,6 @@
         assertEquals(a.installLocation, b.installLocation);
         assertEquals(a.coreApp, b.coreApp);
         assertEquals(a.mRequiredForAllUsers, b.mRequiredForAllUsers);
-        assertEquals(a.mOverlayPriority, b.mOverlayPriority);
         assertEquals(a.mTrustedOverlay, b.mTrustedOverlay);
         assertEquals(a.use32bitAbi, b.use32bitAbi);
         assertEquals(a.packageName, b.packageName);
@@ -433,7 +432,6 @@
         pkg.installLocation = 100;
         pkg.coreApp = true;
         pkg.mRequiredForAllUsers = true;
-        pkg.mOverlayPriority = 100;
         pkg.mTrustedOverlay = true;
         pkg.use32bitAbi = true;
         pkg.packageName = "foo";
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index f193ea4..eb8a1cc 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -14,7 +14,9 @@
 
 LANG_TO_SCRIPT = {
     'as': 'Beng',
+    'bg': 'Cyrl',
     'bn': 'Beng',
+    'cu': 'Cyrl',
     'cy': 'Latn',
     'da': 'Latn',
     'de': 'Latn',