diff options
author | 2016-06-02 09:35:31 +0200 | |
---|---|---|
committer | 2017-02-21 14:29:43 -0800 | |
commit | 21a3d1ad686dee97b9cf0ed80389ee2ab0d48013 (patch) | |
tree | 79a415bcc73f60cda6dbac4ca414b22741c47266 | |
parent | f9bd2944694539f1dce74d420156cc50bbb4af14 (diff) |
OMS: integrate OverlayManagerService into framework
Hand over ownership of overlays to OverlayManagerService.
Changes to a package's overlays are propagated using the activity life
cycle. Affected activities will be recreated as needed. This provides a
well-defined point to modify an application's assets while the
application is paused.
Consolidate how overlays targeting the system and overlays targeting
regular applications are handled. Previously, system overlays were
handled as a special case. Now, everything is handled identically. As a
side effect, the call to idmap --scan during Zygote boot has become
obsolete and is removed.
Information on what overlays to use is recorded in
ApplicationInfo.resourceDirs. The PackageManagerService is responsible
for the creation of ApplicationInfo objects. The OverlayManagerService
is responsible for informing the PackageManagerService in advance about
what resourceDirs to use.
When launching an application, the ApplicationInfo is already populated
with up-to-date information about overlays.
When enabling or disabling an overlay for a running application, the
OverlayManagerService first notifies the PackageManagerService about the
updated resourceDirs. It then tells the ActivityManagerService to push
the new ApplicationInfo object to the application's ActivityThread.
Finally the application requests its ResourcesManager to create new
ResourcesImpl objects based on the updated paths.
Co-authored-by: Martin Wallgren <martin.wallgren@sonymobile.com>
Signed-off-by: Zoran Jovanovic <zoran.jovanovic@sonymobile.com>
Bug: 31052947
Test: run tests from 'OMS: tests for OverlayManagerService'
Change-Id: Idc96dae6fc075d5373aa055bbf50e919136d7353
-rw-r--r-- | cmds/idmap/Android.mk | 2 | ||||
-rw-r--r-- | cmds/idmap/idmap.cpp | 55 | ||||
-rw-r--r-- | cmds/idmap/idmap.h | 6 | ||||
-rw-r--r-- | cmds/idmap/scan.cpp | 239 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageParser.java | 13 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageUserState.java | 6 | ||||
-rw-r--r-- | core/jni/android_util_AssetManager.cpp | 93 | ||||
-rw-r--r-- | libs/androidfw/AssetManager.cpp | 104 | ||||
-rw-r--r-- | libs/androidfw/include/androidfw/AssetManager.h | 15 | ||||
-rw-r--r-- | packages/Shell/AndroidManifest.xml | 2 | ||||
-rw-r--r-- | services/core/java/com/android/server/SystemServiceManager.java | 24 | ||||
-rw-r--r-- | services/core/java/com/android/server/om/OverlayManagerService.java | 33 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerService.java | 183 | ||||
-rw-r--r-- | services/java/com/android/server/SystemServer.java | 6 | ||||
-rw-r--r-- | services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java | 2 |
15 files changed, 157 insertions, 626 deletions
diff --git a/cmds/idmap/Android.mk b/cmds/idmap/Android.mk index 50ccb07a3826..eb6da18ea0ad 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 3ab191553625..d388977e8e2f 100644 --- a/cmds/idmap/idmap.cpp +++ b/cmds/idmap/idmap.cpp @@ -13,8 +13,6 @@ SYNOPSIS \n\ 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 @@ OPTIONS \n\ --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 @@ EXAMPLES \n\ 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 @@ NOTES \n\ 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 @@ int main(int argc, char **argv) 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 8d4210bcb443..5914de96a99d 100644 --- a/cmds/idmap/idmap.h +++ b/cmds/idmap/idmap.h @@ -25,12 +25,6 @@ int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path, 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 ab6adfb9475f..000000000000 --- 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 56f1e0c4cb7b..f801e4547658 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -2065,9 +2065,6 @@ public class PackageParser { 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 @@ public class PackageParser { 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 class PackageParser { public String mRequiredAccountType; public String mOverlayTarget; - public int mOverlayPriority; public boolean mTrustedOverlay; /** @@ -5995,7 +5985,6 @@ public class PackageParser { 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 @@ public class PackageParser { 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 @@ public class PackageParser { 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 24f116452f0b..ee56a18e71a5 100644 --- a/core/java/android/content/pm/PackageUserState.java +++ b/core/java/android/content/pm/PackageUserState.java @@ -31,6 +31,8 @@ import android.util.ArraySet; import com.android.internal.util.ArrayUtils; +import java.util.Arrays; + /** * Per-user state information about a package. * @hide @@ -54,6 +56,8 @@ public class PackageUserState { public ArraySet<String> disabledComponents; public ArraySet<String> enabledComponents; + public String[] resourceDirs; + public PackageUserState() { installed = true; hidden = false; @@ -81,6 +85,8 @@ public class PackageUserState { 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/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 723dce6fcf1e..314595f73091 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -119,96 +119,6 @@ jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table, 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 jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jo 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 acacd7654cf1..84111ae0d499 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -202,15 +202,6 @@ bool AssetManager::addAssetPath( *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 @@ FileType AssetManager::getFileType(const char* fileName) } 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 @@ bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) con 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 @@ Asset* AssetManager::openIdmapLocked(const struct asset_path& ap) const 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 @@ bool AssetManager::SharedZip::isUpToDate() 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 @@ bool AssetManager::ZipSet::isUpToDate() 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 becd307d114d..f1e8b9364915 100644 --- a/libs/androidfw/include/androidfw/AssetManager.h +++ b/libs/androidfw/include/androidfw/AssetManager.h @@ -202,12 +202,10 @@ public: 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 @@ private: 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 @@ private: bool isUpToDate(); - void addOverlay(const asset_path& ap); - bool getOverlay(size_t idx, asset_path* out) const; - protected: ~SharedZip(); @@ -271,8 +263,6 @@ private: Asset* mResourceTableAsset; ResTable* mResourceTable; - Vector<asset_path> mOverlays; - static Mutex gLock; static DefaultKeyedVector<String8, wp<SharedZip> > gOpen; }; @@ -306,9 +296,6 @@ private: 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 34164b16a557..5b4dd48354e6 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/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java index 3f97d4fe436e..cb13a3d1dda2 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 @@ public class SystemServiceManager { + ": 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/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index cc709ce6f176..88e8ce67adeb 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -664,7 +664,38 @@ public final class OverlayManagerService extends SystemService { } 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 = ActivityManagerNative.getDefault(); + 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 f95ee8f74ea6..8797ec43550a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -658,9 +658,12 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ -3705,6 +3708,7 @@ public class PackageManagerService extends IPackageManager.Stub { ApplicationInfo ai = PackageParser.generateApplicationInfo(ps.pkg, flags, ps.readUserState(userId), userId); if (ai != null) { + rebaseEnabledOverlays(ai, userId); ai.packageName = resolveExternalPackageNameLPr(ps.pkg); } return ai; @@ -3739,6 +3743,7 @@ public class PackageManagerService extends IPackageManager.Stub { ApplicationInfo ai = PackageParser.generateApplicationInfo( p, flags, ps.readUserState(userId), userId); if (ai != null) { + rebaseEnabledOverlays(ai, userId); ai.packageName = resolveExternalPackageNameLPr(p); } return ai; @@ -3755,6 +3760,26 @@ public class PackageManagerService extends IPackageManager.Stub { 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; @@ -7089,6 +7114,7 @@ public class PackageManagerService extends IPackageManager.Stub { ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags, ps.readUserState(userId), userId); if (ai != null) { + rebaseEnabledOverlays(ai, userId); ai.packageName = resolveExternalPackageNameLPr(ps.pkg); } } else { @@ -7112,6 +7138,7 @@ public class PackageManagerService extends IPackageManager.Stub { ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags, ps.readUserState(userId), userId); if (ai != null) { + rebaseEnabledOverlays(ai, userId); ai.packageName = resolveExternalPackageNameLPr(p); list.add(ai); } @@ -7255,6 +7282,7 @@ public class PackageManagerService extends IPackageManager.Stub { ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags, ps.readUserState(userId), userId); if (ai != null) { + rebaseEnabledOverlays(ai, userId); finalList.add(ai); } } @@ -7390,60 +7418,6 @@ public class PackageManagerService extends IPackageManager.Stub { 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 { @@ -9932,7 +9906,6 @@ public class PackageManagerService extends IPackageManager.Stub { // writer Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings"); - boolean createIdmapFailed = false; synchronized (mPackages) { // We don't expect installation to fail beyond this point @@ -10273,36 +10246,9 @@ public class PackageManagerService extends IPackageManager.Stub { 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, @@ -20185,6 +20131,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); 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; @@ -20304,6 +20251,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); 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)) { @@ -20432,6 +20380,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); 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(); @@ -20802,6 +20752,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); 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); @@ -20898,6 +20853,23 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } } + 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(); @@ -22984,10 +22956,43 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); @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; + } } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 79176444b77a..d49fcda0efd8 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.media.projection.MediaProjectionManagerService; 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; @@ -594,6 +595,11 @@ public final class SystemServer { 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 384f49f54f41..28596f7b0ac2 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 @@ public class PackageParserTest { 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 @@ public class PackageParserTest { pkg.installLocation = 100; pkg.coreApp = true; pkg.mRequiredForAllUsers = true; - pkg.mOverlayPriority = 100; pkg.mTrustedOverlay = true; pkg.use32bitAbi = true; pkg.packageName = "foo"; |