From 4ce46793091bf073e93fce72d4a9d3ed1d5201d1 Mon Sep 17 00:00:00 2001 From: Dario Freni Date: Fri, 1 Jun 2018 14:02:08 +0100 Subject: androidfw changes to support /product-services. See CL I7a6a30bf8e8db9f2738594d187bb9148f138b8da for a more detailed description of the change. Test: see CL I7a6a30bf8e8db9f2738594d187bb9148f138b8da description Bug: 80741439 Change-Id: I6cc9d713c07c319fc2ee1c531af41243bd1d4aee --- libs/androidfw/AssetManager.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'libs/androidfw/AssetManager.cpp') diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index fc625bbaf72d..843c1461e21b 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -74,6 +74,7 @@ const char* AssetManager::RESOURCES_FILENAME = "resources.arsc"; const char* AssetManager::IDMAP_BIN = "/system/bin/idmap"; const char* AssetManager::OVERLAY_DIR = "/vendor/overlay"; const char* AssetManager::PRODUCT_OVERLAY_DIR = "/product/overlay"; +const char* AssetManager::PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay"; const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme"; const char* AssetManager::TARGET_PACKAGE_NAME = "android"; const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk"; -- cgit v1.2.3-59-g8ed1b From 06a1ac82294c2f6b73af59936195546b5eb78ed6 Mon Sep 17 00:00:00 2001 From: Mårten Kongstad Date: Thu, 20 Sep 2018 13:09:47 +0200 Subject: Prepare for switch to idmap2 Prepare the idmap and asset managers for interfacing with idmap2 instead of today's installd + idmap pipeline, but don't make the switch just yet. Instead, idmap2 runs as its own native daemon with an AIDL interface. This removes the need for installd to fork and exec on each idmap call, saving about 50 ms per call. Bug: 78815803 Test: atest OverlayDeviceTests OverlayHostTests Change-Id: I60852e15d99329896ff9de6559d1e7cd1c67e33d --- core/java/android/content/Context.java | 10 +++ core/java/android/content/res/AssetManager.java | 18 ++++- core/jni/android_util_AssetManager.cpp | 87 +++++++++++++++++++- core/jni/fd_utils.cpp | 4 +- libs/androidfw/AssetManager.cpp | 2 +- libs/androidfw/include/androidfw/AssetManager.h | 6 +- services/core/Android.bp | 2 + .../java/com/android/server/om/IdmapManager.java | 94 +++++++++++++++++----- 8 files changed, 191 insertions(+), 32 deletions(-) (limited to 'libs/androidfw/AssetManager.cpp') diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 2aa32c4b9cff..61d004e00b4a 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4305,6 +4305,16 @@ public abstract class Context { */ public static final String OVERLAY_SERVICE = "overlay"; + /** + * Use with {@link #getSystemService(String)} to retrieve a + * {android.os.IIdmap2} for managing idmap files (used by overlay + * packages). + * + * @see #getSystemService(String) + * @hide + */ + public static final String IDMAP_SERVICE = "idmap"; + /** * Use with {@link #getSystemService(String)} to retrieve a * {@link VrManager} for accessing the VR service. diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 5f2374995775..4371c772c047 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -58,6 +58,7 @@ import java.util.HashMap; public final class AssetManager implements AutoCloseable { private static final String TAG = "AssetManager"; private static final boolean DEBUG_REFS = false; + private static final boolean FEATURE_FLAG_IDMAP2 = false; private static final String FRAMEWORK_APK_PATH = "/system/framework/framework-res.apk"; @@ -195,13 +196,23 @@ public final class AssetManager implements AutoCloseable { return; } - // Make sure that all IDMAPs are up to date. - nativeVerifySystemIdmaps(); try { final ArrayList apkAssets = new ArrayList<>(); apkAssets.add(ApkAssets.loadFromPath(FRAMEWORK_APK_PATH, true /*system*/)); - loadStaticRuntimeOverlays(apkAssets); + if (FEATURE_FLAG_IDMAP2) { + final String[] systemIdmapPaths = + nativeCreateIdmapsForStaticOverlaysTargetingAndroid(); + if (systemIdmapPaths == null) { + throw new IOException("idmap2 scan failed"); + } + for (String idmapPath : systemIdmapPaths) { + apkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, true /*system*/)); + } + } else { + nativeVerifySystemIdmaps(); + loadStaticRuntimeOverlays(apkAssets); + } sSystemApkAssetsSet = new ArraySet<>(apkAssets); sSystemApkAssets = apkAssets.toArray(new ApkAssets[apkAssets.size()]); @@ -1404,6 +1415,7 @@ public final class AssetManager implements AutoCloseable { private static native long nativeAssetGetRemainingLength(long assetPtr); private static native void nativeVerifySystemIdmaps(); + private static native String[] nativeCreateIdmapsForStaticOverlaysTargetingAndroid(); // Global debug native methods. /** diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index b2d44e73d861..7b564ae162ce 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -24,9 +24,13 @@ #include #include #include +#include #include // for AID_SYSTEM +#include +#include + #include "android-base/logging.h" #include "android-base/properties.h" #include "android-base/stringprintf.h" @@ -38,6 +42,7 @@ #include "androidfw/AssetManager2.h" #include "androidfw/AttributeResolution.h" #include "androidfw/MutexGuard.h" +#include "androidfw/PosixUtils.h" #include "androidfw/ResourceTypes.h" #include "core_jni_helpers.h" #include "jni.h" @@ -54,6 +59,7 @@ extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap); extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap); using ::android::base::StringPrintf; +using ::android::util::ExecuteBinary; namespace android { @@ -161,18 +167,20 @@ static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) { argv[argc++] = AssetManager::IDMAP_DIR; // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined, - // use OVERLAY_DIR/ in addition to OVERLAY_DIR. + // use VENDOR_OVERLAY_DIR/ in + // addition to VENDOR_OVERLAY_DIR. std::string overlay_theme_path = base::GetProperty(AssetManager::OVERLAY_THEME_DIR_PROPERTY, ""); if (!overlay_theme_path.empty()) { - overlay_theme_path = std::string(AssetManager::OVERLAY_DIR) + "/" + overlay_theme_path; + overlay_theme_path = + std::string(AssetManager::VENDOR_OVERLAY_DIR) + "/" + overlay_theme_path; if (stat(overlay_theme_path.c_str(), &st) == 0) { argv[argc++] = overlay_theme_path.c_str(); } } - if (stat(AssetManager::OVERLAY_DIR, &st) == 0) { - argv[argc++] = AssetManager::OVERLAY_DIR; + if (stat(AssetManager::VENDOR_OVERLAY_DIR, &st) == 0) { + argv[argc++] = AssetManager::VENDOR_OVERLAY_DIR; } if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) { @@ -200,6 +208,75 @@ static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) { } } +static jobjectArray NativeCreateIdmapsForStaticOverlaysTargetingAndroid(JNIEnv* env, + jclass /*clazz*/) { + // --input-directory can be given multiple times, but idmap2 expects the directory to exist + std::vector input_dirs; + struct stat st; + if (stat(AssetManager::VENDOR_OVERLAY_DIR, &st) == 0) { + input_dirs.push_back(AssetManager::VENDOR_OVERLAY_DIR); + } + + if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) { + input_dirs.push_back(AssetManager::PRODUCT_OVERLAY_DIR); + } + + if (stat(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR, &st) == 0) { + input_dirs.push_back(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR); + } + + if (input_dirs.empty()) { + LOG(WARNING) << "no directories for idmap2 to scan"; + return env->NewObjectArray(0, g_stringClass, nullptr); + } + + std::vector argv{"/system/bin/idmap2", + "scan", + "--recursive", + "--target-package-name", "android", + "--target-apk-path", "/system/framework/framework-res.apk", + "--output-directory", "/data/resource-cache"}; + + for (const auto& dir : input_dirs) { + argv.push_back("--input-directory"); + argv.push_back(dir); + } + + const auto result = ExecuteBinary(argv); + + if (!result) { + LOG(ERROR) << "failed to execute idmap2"; + return nullptr; + } + + if (result->status != 0) { + LOG(ERROR) << "idmap2: " << result->stderr; + return nullptr; + } + + std::vector idmap_paths; + std::istringstream input(result->stdout); + std::string path; + while (std::getline(input, path)) { + idmap_paths.push_back(path); + } + + jobjectArray array = env->NewObjectArray(idmap_paths.size(), g_stringClass, nullptr); + if (array == nullptr) { + return nullptr; + } + for (size_t i = 0; i < idmap_paths.size(); i++) { + const std::string path = idmap_paths[i]; + jstring java_string = env->NewStringUTF(path.c_str()); + if (env->ExceptionCheck()) { + return nullptr; + } + env->SetObjectArrayElement(array, i, java_string); + env->DeleteLocalRef(java_string); + } + return array; +} + static jint CopyValue(JNIEnv* env, ApkAssetsCookie cookie, const Res_value& value, uint32_t ref, uint32_t type_spec_flags, ResTable_config* config, jobject out_typed_value) { env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.dataType); @@ -1405,6 +1482,8 @@ static const JNINativeMethod gAssetManagerMethods[] = { // System/idmap related methods. {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps}, + {"nativeCreateIdmapsForStaticOverlaysTargetingAndroid", "()[Ljava/lang/String;", + (void*)NativeCreateIdmapsForStaticOverlaysTargetingAndroid}, // Global management/debug methods. {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount}, diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 2465759a9fa5..a398e498a301 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -85,7 +85,7 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { // See AssetManager.cpp for more details on overlay-subdir. static const char* kOverlayDir = "/system/vendor/overlay/"; static const char* kVendorOverlayDir = "/vendor/overlay"; - static const char* kOverlaySubdir = "/system/vendor/overlay-subdir/"; + static const char* kVendorOverlaySubdir = "/system/vendor/overlay-subdir/"; static const char* kSystemProductOverlayDir = "/system/product/overlay/"; static const char* kProductOverlayDir = "/product/overlay"; static const char* kSystemProductServicesOverlayDir = "/system/product_services/overlay/"; @@ -93,7 +93,7 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { static const char* kApkSuffix = ".apk"; if ((android::base::StartsWith(path, kOverlayDir) - || android::base::StartsWith(path, kOverlaySubdir) + || android::base::StartsWith(path, kVendorOverlaySubdir) || android::base::StartsWith(path, kVendorOverlayDir) || android::base::StartsWith(path, kSystemProductOverlayDir) || android::base::StartsWith(path, kProductOverlayDir) diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 843c1461e21b..1cb0d25d8c08 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -72,7 +72,7 @@ static volatile int32_t gCount = 0; const char* AssetManager::RESOURCES_FILENAME = "resources.arsc"; const char* AssetManager::IDMAP_BIN = "/system/bin/idmap"; -const char* AssetManager::OVERLAY_DIR = "/vendor/overlay"; +const char* AssetManager::VENDOR_OVERLAY_DIR = "/vendor/overlay"; const char* AssetManager::PRODUCT_OVERLAY_DIR = "/product/overlay"; const char* AssetManager::PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay"; const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme"; diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h index cdb87bcb8e11..e22e2d239a55 100644 --- a/libs/androidfw/include/androidfw/AssetManager.h +++ b/libs/androidfw/include/androidfw/AssetManager.h @@ -59,13 +59,13 @@ class AssetManager : public AAssetManager { public: static const char* RESOURCES_FILENAME; static const char* IDMAP_BIN; - static const char* OVERLAY_DIR; + static const char* VENDOR_OVERLAY_DIR; static const char* PRODUCT_OVERLAY_DIR; static const char* PRODUCT_SERVICES_OVERLAY_DIR; /* * If OVERLAY_THEME_DIR_PROPERTY is set, search for runtime resource overlay - * APKs in OVERLAY_DIR/ in addition to - * OVERLAY_DIR. + * APKs in VENDOR_OVERLAY_DIR/ in + * addition to VENDOR_OVERLAY_DIR. */ static const char* OVERLAY_THEME_DIR_PROPERTY; static const char* TARGET_PACKAGE_NAME; diff --git a/services/core/Android.bp b/services/core/Android.bp index 888ad1da3fcc..617430090998 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -3,6 +3,7 @@ java_library_static { aidl: { include_dirs: [ + "frameworks/base/cmds/idmap2/idmap2d/aidl", "frameworks/native/aidl/binder", "frameworks/native/cmds/dumpstate/binder", "system/core/storaged/binder", @@ -13,6 +14,7 @@ java_library_static { srcs: [ "java/**/*.java", ":dumpstate_aidl", + ":idmap2_aidl", ":netd_aidl", ":netd_metrics_aidl", ":installd_aidl", diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java index 807c343d0d10..731e6bcfb074 100644 --- a/services/core/java/com/android/server/om/IdmapManager.java +++ b/services/core/java/com/android/server/om/IdmapManager.java @@ -16,36 +16,46 @@ package com.android.server.om; +import static android.content.Context.IDMAP_SERVICE; +import static android.text.format.DateUtils.SECOND_IN_MILLIS; + import static com.android.server.om.OverlayManagerService.DEBUG; import static com.android.server.om.OverlayManagerService.TAG; import android.annotation.NonNull; import android.content.om.OverlayInfo; import android.content.pm.PackageInfo; +import android.os.IBinder; +import android.os.IIdmap2; +import android.os.RemoteException; +import android.os.ServiceManager; import android.os.UserHandle; import android.util.Slog; -import com.android.server.pm.Installer.InstallerException; +import com.android.internal.os.BackgroundThread; import com.android.server.pm.Installer; -import java.io.DataInputStream; import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; /** * Handle the creation and deletion of idmap files. * * The actual work is performed by the idmap binary, launched through Installer - * and installd. + * and installd (or idmap2). * * Note: this class is subclassed in the OMS unit tests, and hence not marked as final. */ class IdmapManager { + private static final boolean FEATURE_FLAG_IDMAP2 = false; + private final Installer mInstaller; + private IIdmap2 mIdmap2Service; IdmapManager(final Installer installer) { mInstaller = installer; + if (FEATURE_FLAG_IDMAP2) { + connectToIdmap2d(); + } } boolean createIdmap(@NonNull final PackageInfo targetPackage, @@ -59,8 +69,12 @@ class IdmapManager { final String targetPath = targetPackage.applicationInfo.getBaseCodePath(); final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath(); try { - mInstaller.idmap(targetPath, overlayPath, sharedGid); - } catch (InstallerException e) { + if (FEATURE_FLAG_IDMAP2) { + mIdmap2Service.createIdmap(targetPath, overlayPath, userId); + } else { + mInstaller.idmap(targetPath, overlayPath, sharedGid); + } + } catch (Exception e) { Slog.w(TAG, "failed to generate idmap for " + targetPath + " and " + overlayPath + ": " + e.getMessage()); return false; @@ -69,13 +83,16 @@ class IdmapManager { } boolean removeIdmap(@NonNull final OverlayInfo oi, final int userId) { - // unused userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible if (DEBUG) { Slog.d(TAG, "remove idmap for " + oi.baseCodePath); } try { - mInstaller.removeIdmap(oi.baseCodePath); - } catch (InstallerException e) { + if (FEATURE_FLAG_IDMAP2) { + mIdmap2Service.removeIdmap(oi.baseCodePath, userId); + } else { + mInstaller.removeIdmap(oi.baseCodePath); + } + } catch (Exception e) { Slog.w(TAG, "failed to remove idmap for " + oi.baseCodePath + ": " + e.getMessage()); return false; } @@ -83,19 +100,58 @@ class IdmapManager { } boolean idmapExists(@NonNull final OverlayInfo oi) { - // unused OverlayInfo.userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible - return new File(getIdmapPath(oi.baseCodePath)).isFile(); + return new File(getIdmapPath(oi.baseCodePath, oi.userId)).isFile(); } boolean idmapExists(@NonNull final PackageInfo overlayPackage, final int userId) { - // unused userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible - return new File(getIdmapPath(overlayPackage.applicationInfo.getBaseCodePath())).isFile(); + return new File(getIdmapPath(overlayPackage.applicationInfo.getBaseCodePath(), userId)) + .isFile(); } - private String getIdmapPath(@NonNull final String baseCodePath) { - final StringBuilder sb = new StringBuilder("/data/resource-cache/"); - sb.append(baseCodePath.substring(1).replace('/', '@')); - sb.append("@idmap"); - return sb.toString(); + private @NonNull String getIdmapPath(@NonNull final String overlayPackagePath, + final int userId) { + if (FEATURE_FLAG_IDMAP2) { + try { + return mIdmap2Service.getIdmapPath(overlayPackagePath, userId); + } catch (Exception e) { + Slog.w(TAG, "failed to get idmap path for " + overlayPackagePath + ": " + + e.getMessage()); + return ""; + } + } else { + final StringBuilder sb = new StringBuilder("/data/resource-cache/"); + sb.append(overlayPackagePath.substring(1).replace('/', '@')); + sb.append("@idmap"); + return sb.toString(); + } + } + + private void connectToIdmap2d() { + IBinder binder = ServiceManager.getService(IDMAP_SERVICE); + if (binder != null) { + try { + binder.linkToDeath(new IBinder.DeathRecipient() { + @Override + public void binderDied() { + Slog.w(TAG, "service '" + IDMAP_SERVICE + "' died; reconnecting..."); + connectToIdmap2d(); + } + + }, 0); + } catch (RemoteException e) { + binder = null; + } + } + if (binder != null) { + mIdmap2Service = IIdmap2.Stub.asInterface(binder); + if (DEBUG) { + Slog.d(TAG, "service '" + IDMAP_SERVICE + "' connected"); + } + } else { + Slog.w(TAG, "service '" + IDMAP_SERVICE + "' not found; trying again..."); + BackgroundThread.getHandler().postDelayed(() -> { + connectToIdmap2d(); + }, SECOND_IN_MILLIS); + } } } -- cgit v1.2.3-59-g8ed1b From 67d5c938e98681f20243345232ebd2c77b390419 Mon Sep 17 00:00:00 2001 From: Mårten Kongstad Date: Fri, 25 May 2018 15:58:17 +0200 Subject: idmap: optimize time to create idmap data Change idmap to iterate over the resources in the overlay package instead of the target package when scanning for resources defined in both packages. This cuts down the runtime cost of creating an idmap considerably since the algorithm now scales with the number of resources in the overlay package (a handful) and not the number of resources in the target package (android: 10k, SystemUI: 8k) at a minor cost to code complexity. Improvements on the runtime of ResTable::createIdmap (systrace on an emulator running aosp_x86_64-eng): - target=android: 12.5 ms -> 3.0 ms - target=SystemUI: 8.6 ms -> 1.0 ms The bulk of the cost of creating an idmap from installd is now the fork and execl to call "idmap --fd ..." which weigh in at 16 ms. Bug: 80150169 Test: make libandroidfw_tests Test: atest OverlayHostTests OverlayDeviceTests Change-Id: I98e18d5958c0cd835a73055b714f5bf0f4f95a09 --- libs/androidfw/AssetManager.cpp | 2 +- libs/androidfw/ResourceTypes.cpp | 252 ++++++++++++----------- libs/androidfw/include/androidfw/ResourceTypes.h | 2 +- libs/androidfw/tests/Idmap_test.cpp | 2 +- 4 files changed, 134 insertions(+), 124 deletions(-) (limited to 'libs/androidfw/AssetManager.cpp') diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 1cb0d25d8c08..365be10f597f 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -349,7 +349,7 @@ bool AssetManager::createIdmap(const char* targetApkPath, const char* overlayApk goto exit; } } - ret = tables[0].createIdmap(tables[1], targetCrc, overlayCrc, + ret = tables[1].createIdmap(tables[0], targetCrc, overlayCrc, targetApkPath, overlayApkPath, (void**)outData, outSize) == NO_ERROR; } diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 76db18de6122..f7fb89e54ef3 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -26,7 +26,9 @@ #include #include +#include #include +#include #include #include @@ -7033,170 +7035,178 @@ status_t DynamicRefTable::lookupResourceValue(Res_value* value) const { return NO_ERROR; } -struct IdmapTypeMap { - ssize_t overlayTypeId; - size_t entryOffset; - Vector entryMap; +struct IdmapMatchingResources { + void Add(uint32_t targetResId, uint32_t overlayResId) { + uint8_t targetTypeid = Res_GETTYPE(targetResId); + if (typeMappings.find(targetTypeid) == typeMappings.end()) { + typeMappings.emplace(targetTypeid, std::set>()); + } + auto& entries = typeMappings[targetTypeid]; + entries.insert(std::make_pair(targetResId, overlayResId)); + } + + void FixPadding() { + for (auto ti = typeMappings.cbegin(); ti != typeMappings.cend(); ++ti) { + uint32_t last_seen = 0xffffffff; + size_t total_entries = 0; + for (auto ei = ti->second.cbegin(); ei != ti->second.cend(); ++ei) { + assert(last_seen == 0xffffffff || last_seen < ei->first); + entryPadding[ei->first] = (last_seen == 0xffffffff) ? 0 : ei->first - last_seen - 1; + last_seen = ei->first; + total_entries += 1 + entryPadding[ei->first]; + } + numberOfEntriesIncludingPadding[ti->first] = total_entries; + } + } + + // resource type ID in context of target -> set of resource entries mapping target -> overlay + std::map>> typeMappings; + + // resource ID in context of target -> trailing padding for that resource (call FixPadding + // before use) + std::map entryPadding; + + // resource type ID in context of target -> total number of entries, including padding entries, + // for that type (call FixPadding before use) + std::map numberOfEntriesIncludingPadding; }; -status_t ResTable::createIdmap(const ResTable& overlay, +status_t ResTable::createIdmap(const ResTable& targetResTable, uint32_t targetCrc, uint32_t overlayCrc, const char* targetPath, const char* overlayPath, void** outData, size_t* outSize) const { - // see README for details on the format of map - if (mPackageGroups.size() == 0) { - ALOGW("idmap: target package has no package groups, cannot create idmap\n"); + if (targetPath == NULL || overlayPath == NULL || outData == NULL || outSize == NULL) { + ALOGE("idmap: unexpected NULL parameter"); return UNKNOWN_ERROR; } - - if (mPackageGroups[0]->packages.size() == 0) { - ALOGW("idmap: target package has no packages in its first package group, " - "cannot create idmap\n"); + if (strlen(targetPath) > 255) { + ALOGE("idmap: target path exceeds idmap file format limit of 255 chars"); + return UNKNOWN_ERROR; + } + if (strlen(overlayPath) > 255) { + ALOGE("idmap: overlay path exceeds idmap file format limit of 255 chars"); + return UNKNOWN_ERROR; + } + if (mPackageGroups.size() == 0 || mPackageGroups[0]->packages.size() == 0) { + ALOGE("idmap: invalid overlay package"); + return UNKNOWN_ERROR; + } + if (targetResTable.mPackageGroups.size() == 0 || + targetResTable.mPackageGroups[0]->packages.size() == 0) { + ALOGE("idmap: invalid target package"); return UNKNOWN_ERROR; } - // The number of resources overlaid that were not explicitly marked overlayable. - size_t forcedOverlayCount = 0u; - - KeyedVector map; - - // overlaid packages are assumed to contain only one package group - const PackageGroup* pg = mPackageGroups[0]; - - // starting size is header - *outSize = ResTable::IDMAP_HEADER_SIZE_BYTES; + const ResTable_package* targetPackageStruct = targetResTable.mPackageGroups[0]->packages[0]->package; + const size_t tmpNameSize = arraysize(targetPackageStruct->name); + char16_t tmpName[tmpNameSize]; + strcpy16_dtoh(tmpName, targetPackageStruct->name, tmpNameSize); + const String16 targetPackageName(tmpName); - // target package id and number of types in map - *outSize += 2 * sizeof(uint16_t); + const PackageGroup* packageGroup = mPackageGroups[0]; - // overlay packages are assumed to contain only one package group - const ResTable_package* overlayPackageStruct = overlay.mPackageGroups[0]->packages[0]->package; - char16_t tmpName[sizeof(overlayPackageStruct->name)/sizeof(overlayPackageStruct->name[0])]; - strcpy16_dtoh(tmpName, overlayPackageStruct->name, sizeof(overlayPackageStruct->name)/sizeof(overlayPackageStruct->name[0])); - const String16 overlayPackage(tmpName); + // the number of resources overlaid that were not explicitly marked overlayable + size_t forcedOverlayCount = 0u; - for (size_t typeIndex = 0; typeIndex < pg->types.size(); ++typeIndex) { - const TypeList& typeList = pg->types[typeIndex]; + // find the resources that exist in both packages + IdmapMatchingResources matchingResources; + for (size_t typeIndex = 0; typeIndex < packageGroup->types.size(); ++typeIndex) { + const TypeList& typeList = packageGroup->types[typeIndex]; if (typeList.isEmpty()) { continue; } - const Type* typeConfigs = typeList[0]; - IdmapTypeMap typeMap; - typeMap.overlayTypeId = -1; - typeMap.entryOffset = 0; - for (size_t entryIndex = 0; entryIndex < typeConfigs->entryCount; ++entryIndex) { - uint32_t resID = Res_MAKEID(pg->id - 1, typeIndex, entryIndex); - resource_name resName; - if (!this->getResourceName(resID, false, &resName)) { - if (typeMap.entryMap.isEmpty()) { - typeMap.entryOffset++; - } + uint32_t overlay_resid = Res_MAKEID(packageGroup->id - 1, typeIndex, entryIndex); + resource_name current_res; + if (!getResourceName(overlay_resid, false, ¤t_res)) { continue; } uint32_t typeSpecFlags = 0u; - const String16 overlayType(resName.type, resName.typeLen); - const String16 overlayName(resName.name, resName.nameLen); - uint32_t overlayResID = overlay.identifierForName(overlayName.string(), - overlayName.size(), - overlayType.string(), - overlayType.size(), - overlayPackage.string(), - overlayPackage.size(), - &typeSpecFlags); - if (overlayResID == 0) { - // No such target resource was found. - if (typeMap.entryMap.isEmpty()) { - typeMap.entryOffset++; - } + const uint32_t target_resid = targetResTable.identifierForName( + current_res.name, + current_res.nameLen, + current_res.type, + current_res.typeLen, + targetPackageName.string(), + targetPackageName.size(), + &typeSpecFlags); + + if (target_resid == 0) { continue; } - // Now that we know this is being overlaid, check if it can be, and emit a warning if - // it can't. if ((dtohl(typeConfigs->typeSpecFlags[entryIndex]) & ResTable_typeSpec::SPEC_OVERLAYABLE) == 0) { - forcedOverlayCount++; - } - - if (typeMap.overlayTypeId == -1) { - typeMap.overlayTypeId = Res_GETTYPE(overlayResID) + 1; - } - - if (Res_GETTYPE(overlayResID) + 1 != static_cast(typeMap.overlayTypeId)) { - ALOGE("idmap: can't mix type ids in entry map. Resource 0x%08x maps to 0x%08x" - " but entries should map to resources of type %02zx", - resID, overlayResID, typeMap.overlayTypeId); - return BAD_TYPE; - } - - if (typeMap.entryOffset + typeMap.entryMap.size() < entryIndex) { - // pad with 0xffffffff's (indicating non-existing entries) before adding this entry - size_t index = typeMap.entryMap.size(); - size_t numItems = entryIndex - (typeMap.entryOffset + index); - if (typeMap.entryMap.insertAt(0xffffffff, index, numItems) < 0) { - return NO_MEMORY; - } + ++forcedOverlayCount; } - typeMap.entryMap.add(Res_GETENTRY(overlayResID)); - } - if (!typeMap.entryMap.isEmpty()) { - if (map.add(static_cast(typeIndex), typeMap) < 0) { - return NO_MEMORY; - } - *outSize += (4 * sizeof(uint16_t)) + (typeMap.entryMap.size() * sizeof(uint32_t)); + matchingResources.Add(target_resid, overlay_resid); } } - if (map.isEmpty()) { - ALOGW("idmap: no resources in overlay package present in base package"); + if (matchingResources.typeMappings.empty()) { + ALOGE("idmap: no matching resources"); return UNKNOWN_ERROR; } + matchingResources.FixPadding(); + + // write idmap + *outSize = ResTable::IDMAP_HEADER_SIZE_BYTES; // magic, version, target and overlay crc + *outSize += 2 * sizeof(uint16_t); // target package id, type count + const auto typesEnd = matchingResources.typeMappings.cend(); + for (auto ti = matchingResources.typeMappings.cbegin(); ti != typesEnd; ++ti) { + *outSize += 4 * sizeof(uint16_t); // target type, overlay type, entry count, entry offset + *outSize += matchingResources.numberOfEntriesIncludingPadding[ti->first] * + sizeof(uint32_t); // entries + } if ((*outData = malloc(*outSize)) == NULL) { return NO_MEMORY; } - uint32_t* data = (uint32_t*)*outData; - *data++ = htodl(IDMAP_MAGIC); - *data++ = htodl(ResTable::IDMAP_CURRENT_VERSION); - *data++ = htodl(targetCrc); - *data++ = htodl(overlayCrc); - const char* paths[] = { targetPath, overlayPath }; - for (int j = 0; j < 2; ++j) { - char* p = (char*)data; - const char* path = paths[j]; - const size_t I = strlen(path); - if (I > 255) { - ALOGV("path exceeds expected 255 characters: %s\n", path); - return UNKNOWN_ERROR; - } - for (size_t i = 0; i < 256; ++i) { - *p++ = i < I ? path[i] : '\0'; - } - data += 256 / sizeof(uint32_t); + // write idmap header + uint32_t* data = reinterpret_cast(*outData); + *data++ = htodl(IDMAP_MAGIC); // write: magic + *data++ = htodl(ResTable::IDMAP_CURRENT_VERSION); // write: version + *data++ = htodl(targetCrc); // write: target crc + *data++ = htodl(overlayCrc); // write: overlay crc + + char* charData = reinterpret_cast(data); + size_t pathLen = strlen(targetPath); + for (size_t i = 0; i < 256; ++i) { + *charData++ = i < pathLen ? targetPath[i] : '\0'; // write: target path } - const size_t mapSize = map.size(); + pathLen = strlen(overlayPath); + for (size_t i = 0; i < 256; ++i) { + *charData++ = i < pathLen ? overlayPath[i] : '\0'; // write: overlay path + } + data += (2 * 256) / sizeof(uint32_t); + + // write idmap data header uint16_t* typeData = reinterpret_cast(data); - *typeData++ = htods(pg->id); - *typeData++ = htods(mapSize); - for (size_t i = 0; i < mapSize; ++i) { - uint8_t targetTypeId = map.keyAt(i); - const IdmapTypeMap& typeMap = map[i]; - *typeData++ = htods(targetTypeId + 1); - *typeData++ = htods(typeMap.overlayTypeId); - *typeData++ = htods(typeMap.entryMap.size()); - *typeData++ = htods(typeMap.entryOffset); - - const size_t entryCount = typeMap.entryMap.size(); - uint32_t* entries = reinterpret_cast(typeData); - for (size_t j = 0; j < entryCount; j++) { - entries[j] = htodl(typeMap.entryMap[j]); + *typeData++ = htods(targetPackageStruct->id); // write: target package id + *typeData++ = + htods(static_cast(matchingResources.typeMappings.size())); // write: type count + + // write idmap data + for (auto ti = matchingResources.typeMappings.cbegin(); ti != typesEnd; ++ti) { + const size_t entryCount = matchingResources.numberOfEntriesIncludingPadding[ti->first]; + auto ei = ti->second.cbegin(); + *typeData++ = htods(Res_GETTYPE(ei->first) + 1); // write: target type id + *typeData++ = htods(Res_GETTYPE(ei->second) + 1); // write: overlay type id + *typeData++ = htods(entryCount); // write: entry count + *typeData++ = htods(Res_GETENTRY(ei->first)); // write: (target) entry offset + uint32_t *entryData = reinterpret_cast(typeData); + for (; ei != ti->second.cend(); ++ei) { + const size_t padding = matchingResources.entryPadding[ei->first]; + for (size_t i = 0; i < padding; ++i) { + *entryData++ = htodl(0xffffffff); // write: padding + } + *entryData++ = htodl(Res_GETENTRY(ei->second)); // write: (overlay) entry } typeData += entryCount * 2; } diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index 59abad45edbb..ad33fcfa2429 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -1990,7 +1990,7 @@ public: // Return value: on success: NO_ERROR; caller is responsible for free-ing // outData (using free(3)). On failure, any status_t value other than // NO_ERROR; the caller should not free outData. - status_t createIdmap(const ResTable& overlay, + status_t createIdmap(const ResTable& targetResTable, uint32_t targetCrc, uint32_t overlayCrc, const char* targetPath, const char* overlayPath, void** outData, size_t* outSize) const; diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp index 26d28965d459..10b83a75304d 100644 --- a/libs/androidfw/tests/Idmap_test.cpp +++ b/libs/androidfw/tests/Idmap_test.cpp @@ -40,7 +40,7 @@ class IdmapTest : public ::testing::Test { ASSERT_EQ(NO_ERROR, overlay_table.add(overlay_data_.data(), overlay_data_.size())); char target_name[256] = "com.android.basic"; - ASSERT_EQ(NO_ERROR, target_table_.createIdmap(overlay_table, 0, 0, target_name, target_name, + ASSERT_EQ(NO_ERROR, overlay_table.createIdmap(target_table_, 0, 0, target_name, target_name, &data_, &data_size_)); } -- cgit v1.2.3-59-g8ed1b From 48c24cf1490be40c8b8ef44cfb6479a4895cdfe1 Mon Sep 17 00:00:00 2001 From: Mårten Kongstad Date: Mon, 25 Feb 2019 10:54:09 +0100 Subject: Add support for /odm/overlay Add support for runtime resource overlay (RRO) APKs in /odm/overlay. Bug: 121033532 Test: manual (adb push apk to /odm/overlay, reboot, cmd overlay list) Change-Id: I0918d276dfa6a43054068d3f84ecd0d1639f1d0b --- core/java/android/content/pm/ApplicationInfo.java | 13 +++++++ core/java/android/content/pm/PackageParser.java | 5 +++ core/jni/android_util_AssetManager.cpp | 10 +++++- core/jni/fd_utils.cpp | 6 +++- libs/androidfw/AssetManager.cpp | 1 + libs/androidfw/include/androidfw/AssetManager.h | 1 + .../android/server/pm/PackageManagerService.java | 41 +++++++++++++++++++++- .../java/com/android/server/pm/PackageSetting.java | 4 +++ .../java/com/android/server/pm/SettingBase.java | 3 +- .../core/java/com/android/server/pm/Settings.java | 6 +++- 10 files changed, 85 insertions(+), 5 deletions(-) (limited to 'libs/androidfw/AssetManager.cpp') diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 5328dda03893..1c2afd2e7fd6 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -687,6 +687,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public static final int PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX = 1 << 29; + /** + * Value for {@link #privateFlags}: whether this app is pre-installed on the + * ODM partition of the system image. + * @hide + */ + public static final int PRIVATE_FLAG_ODM = 1 << 30; + /** @hide */ @IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = { PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE, @@ -717,6 +724,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE, PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE, PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX, + PRIVATE_FLAG_ODM, }) @Retention(RetentionPolicy.SOURCE) public @interface ApplicationInfoPrivateFlags {} @@ -1969,6 +1977,11 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { return (privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0; } + /** @hide */ + public boolean isOdm() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0; + } + /** @hide */ public boolean isPartiallyDirectBootAware() { return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE) != 0; diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 93bc6d7eb583..81788b92a4b8 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -6919,6 +6919,11 @@ public class PackageParser { return applicationInfo.isProductServices(); } + /** @hide */ + public boolean isOdm() { + return applicationInfo.isOdm(); + } + /** @hide */ public boolean isPrivileged() { return applicationInfo.isPrivilegedApp(); diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index bf56ef438a1d..d3f9196ce763 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -163,7 +163,7 @@ static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) { } // Generic idmap parameters - const char* argv[8]; + const char* argv[9]; int argc = 0; struct stat st; @@ -199,6 +199,10 @@ static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) { argv[argc++] = AssetManager::PRODUCT_SERVICES_OVERLAY_DIR; } + if (stat(AssetManager::ODM_OVERLAY_DIR, &st) == 0) { + argv[argc++] = AssetManager::ODM_OVERLAY_DIR; + } + // Finally, invoke idmap (if any overlay directory exists) if (argc > 5) { execv(AssetManager::IDMAP_BIN, (char* const*)argv); @@ -233,6 +237,10 @@ static jobjectArray NativeCreateIdmapsForStaticOverlaysTargetingAndroid(JNIEnv* input_dirs.push_back(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR); } + if (stat(AssetManager::ODM_OVERLAY_DIR, &st) == 0) { + input_dirs.push_back(AssetManager::ODM_OVERLAY_DIR); + } + if (input_dirs.empty()) { LOG(WARNING) << "no directories for idmap2 to scan"; return env->NewObjectArray(0, g_stringClass, nullptr); diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index d8d46560876d..099635246f05 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -102,6 +102,8 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { static const char* kProductOverlayDir = "/product/overlay"; static const char* kSystemProductServicesOverlayDir = "/system/product_services/overlay/"; static const char* kProductServicesOverlayDir = "/product_services/overlay"; + static const char* kSystemOdmOverlayDir = "/system/odm/overlay"; + static const char* kOdmOverlayDir = "/odm/overlay"; static const char* kApkSuffix = ".apk"; if ((android::base::StartsWith(path, kOverlayDir) @@ -110,7 +112,9 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { || android::base::StartsWith(path, kSystemProductOverlayDir) || android::base::StartsWith(path, kProductOverlayDir) || android::base::StartsWith(path, kSystemProductServicesOverlayDir) - || android::base::StartsWith(path, kProductServicesOverlayDir)) + || android::base::StartsWith(path, kProductServicesOverlayDir) + || android::base::StartsWith(path, kSystemOdmOverlayDir) + || android::base::StartsWith(path, kOdmOverlayDir)) && android::base::EndsWith(path, kApkSuffix) && path.find("/../") == std::string::npos) { return true; diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 365be10f597f..21609d30e92c 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -75,6 +75,7 @@ const char* AssetManager::IDMAP_BIN = "/system/bin/idmap"; const char* AssetManager::VENDOR_OVERLAY_DIR = "/vendor/overlay"; const char* AssetManager::PRODUCT_OVERLAY_DIR = "/product/overlay"; const char* AssetManager::PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay"; +const char* AssetManager::ODM_OVERLAY_DIR = "/odm/overlay"; const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme"; const char* AssetManager::TARGET_PACKAGE_NAME = "android"; const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk"; diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h index e22e2d239a55..a015eabc200c 100644 --- a/libs/androidfw/include/androidfw/AssetManager.h +++ b/libs/androidfw/include/androidfw/AssetManager.h @@ -62,6 +62,7 @@ public: static const char* VENDOR_OVERLAY_DIR; static const char* PRODUCT_OVERLAY_DIR; static const char* PRODUCT_SERVICES_OVERLAY_DIR; + static const char* ODM_OVERLAY_DIR; /* * If OVERLAY_THEME_DIR_PROPERTY is set, search for runtime resource overlay * APKs in VENDOR_OVERLAY_DIR/ in diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 098225f9e820..92a3ac72a685 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -476,6 +476,7 @@ public class PackageManagerService extends IPackageManager.Stub static final int SCAN_AS_VENDOR = 1 << 20; static final int SCAN_AS_PRODUCT = 1 << 21; static final int SCAN_AS_PRODUCT_SERVICES = 1 << 22; + static final int SCAN_AS_ODM = 1 << 23; @IntDef(flag = true, prefix = { "SCAN_" }, value = { SCAN_NO_DEX, @@ -594,6 +595,8 @@ public class PackageManagerService extends IPackageManager.Stub private static final String PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay"; + private static final String ODM_OVERLAY_DIR = "/odm/overlay"; + /** Canonical intent used to identify what counts as a "web browser" app */ private static final Intent sBrowserIntent; static { @@ -2523,6 +2526,13 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_AS_SYSTEM | SCAN_AS_PRODUCT_SERVICES, 0); + scanDirTracedLI(new File(ODM_OVERLAY_DIR), + mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM_DIR, + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_ODM, + 0); mParallelPackageParserCallback.findStaticOverlayPackages(); @@ -10399,6 +10409,7 @@ public class PackageManagerService extends IPackageManager.Stub *
  • {@link #SCAN_AS_PRODUCT_SERVICES}
  • *
  • {@link #SCAN_AS_INSTANT_APP}
  • *
  • {@link #SCAN_AS_VIRTUAL_PRELOAD}
  • + *
  • {@link #SCAN_AS_ODM}
  • * */ private @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags, @@ -10435,6 +10446,10 @@ public class PackageManagerService extends IPackageManager.Stub & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0) { scanFlags |= SCAN_AS_PRODUCT_SERVICES; } + if ((systemPkgSetting.pkgPrivateFlags + & ApplicationInfo.PRIVATE_FLAG_ODM) != 0) { + scanFlags |= SCAN_AS_ODM; + } } if (pkgSetting != null) { final int userId = ((user == null) ? 0 : user.getIdentifier()); @@ -11206,6 +11221,10 @@ public class PackageManagerService extends IPackageManager.Stub pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES; } + if ((scanFlags & SCAN_AS_ODM) != 0) { + pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ODM; + } + // Check if the package is signed with the same key as the platform package. if (PLATFORM_PACKAGE_NAME.equals(pkg.packageName) || (platformPkg != null && compareSignatures( @@ -12128,6 +12147,8 @@ public class PackageManagerService extends IPackageManager.Stub codeRoot = Environment.getProductDirectory(); } else if (FileUtils.contains(Environment.getProductServicesDirectory(), codePath)) { codeRoot = Environment.getProductServicesDirectory(); + } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) { + codeRoot = Environment.getOdmDirectory(); } else { // Unrecognized code path; take its top real segment as the apk root: // e.g. /something/app/blah.apk => /something @@ -17217,13 +17238,15 @@ public class PackageManagerService extends IPackageManager.Stub final boolean oem = isOemApp(oldPackage); final boolean vendor = isVendorApp(oldPackage); final boolean product = isProductApp(oldPackage); + final boolean odm = isOdmApp(oldPackage); final @ParseFlags int systemParseFlags = parseFlags; final @ScanFlags int systemScanFlags = scanFlags | SCAN_AS_SYSTEM | (privileged ? SCAN_AS_PRIVILEGED : 0) | (oem ? SCAN_AS_OEM : 0) | (vendor ? SCAN_AS_VENDOR : 0) - | (product ? SCAN_AS_PRODUCT : 0); + | (product ? SCAN_AS_PRODUCT : 0) + | (odm ? SCAN_AS_ODM : 0); if (DEBUG_INSTALL) { Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg @@ -17554,6 +17577,10 @@ public class PackageManagerService extends IPackageManager.Stub & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0; } + private static boolean isOdmApp(PackageParser.Package pkg) { + return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0; + } + private static boolean hasDomainURLs(PackageParser.Package pkg) { return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0; } @@ -18328,6 +18355,15 @@ public class PackageManagerService extends IPackageManager.Stub return false; } + static boolean locationIsOdm(String path) { + try { + return path.startsWith(Environment.getOdmDirectory().getCanonicalPath() + "/"); + } catch (IOException e) { + Slog.e(TAG, "Unable to access code path " + path); + } + return false; + } + /* * Tries to delete system package. */ @@ -18441,6 +18477,9 @@ public class PackageManagerService extends IPackageManager.Stub if (locationIsProductServices(codePathString)) { scanFlags |= SCAN_AS_PRODUCT_SERVICES; } + if (locationIsOdm(codePathString)) { + scanFlags |= SCAN_AS_ODM; + } final File codePath = new File(codePathString); final PackageParser.Package pkg = diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 2c2cc7ea78f9..ead09b424d61 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -152,6 +152,10 @@ public final class PackageSetting extends PackageSettingBase { return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0; } + public boolean isOdm() { + return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0; + } + public boolean isSystem() { return (pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0; } diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java index fbf54391209c..a24818f04f52 100644 --- a/services/core/java/com/android/server/pm/SettingBase.java +++ b/services/core/java/com/android/server/pm/SettingBase.java @@ -64,6 +64,7 @@ abstract class SettingBase { | ApplicationInfo.PRIVATE_FLAG_VENDOR | ApplicationInfo.PRIVATE_FLAG_PRODUCT | ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES - | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER); + | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER + | ApplicationInfo.PRIVATE_FLAG_ODM); } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 6a1f223917b6..f1647d5b29ba 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -776,7 +776,8 @@ public final class Settings { | ApplicationInfo.PRIVATE_FLAG_OEM | ApplicationInfo.PRIVATE_FLAG_VENDOR | ApplicationInfo.PRIVATE_FLAG_PRODUCT - | ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES); + | ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES + | ApplicationInfo.PRIVATE_FLAG_ODM); pkgSetting.pkgFlags |= pkgFlags & ApplicationInfo.FLAG_SYSTEM; pkgSetting.pkgPrivateFlags |= pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; @@ -788,6 +789,8 @@ public final class Settings { pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT; pkgSetting.pkgPrivateFlags |= pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES; + pkgSetting.pkgPrivateFlags |= + pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_ODM; pkgSetting.primaryCpuAbiString = primaryCpuAbi; pkgSetting.secondaryCpuAbiString = secondaryCpuAbi; if (childPkgNames != null) { @@ -4401,6 +4404,7 @@ public final class Settings { ApplicationInfo.PRIVATE_FLAG_PRODUCT, "PRODUCT", ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES, "PRODUCT_SERVICES", ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD, "VIRTUAL_PRELOAD", + ApplicationInfo.PRIVATE_FLAG_ODM, "ODM", }; void dumpVersionLPr(IndentingPrintWriter pw) { -- cgit v1.2.3-59-g8ed1b From eb8a5c0b915683d9df54112a7345106b1eb762fe Mon Sep 17 00:00:00 2001 From: Mårten Kongstad Date: Mon, 25 Feb 2019 14:18:17 +0100 Subject: Add support for /oem/overlay Add support for runtime resource overlay (RRO) APKs in /oem/overlay. Bug: 121033532 Test: manual (adb push apk to /oem/overlay, reboot, cmd overlay list) Change-Id: I70b23b11831d57b3241e6057c745aa4ce9f795ef --- core/jni/android_util_AssetManager.cpp | 10 +++++++++- core/jni/fd_utils.cpp | 6 +++++- libs/androidfw/AssetManager.cpp | 1 + libs/androidfw/include/androidfw/AssetManager.h | 1 + .../core/java/com/android/server/pm/PackageManagerService.java | 9 +++++++++ 5 files changed, 25 insertions(+), 2 deletions(-) (limited to 'libs/androidfw/AssetManager.cpp') diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index d3f9196ce763..2b471fec9c8f 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -163,7 +163,7 @@ static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) { } // Generic idmap parameters - const char* argv[9]; + const char* argv[10]; int argc = 0; struct stat st; @@ -203,6 +203,10 @@ static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) { argv[argc++] = AssetManager::ODM_OVERLAY_DIR; } + if (stat(AssetManager::OEM_OVERLAY_DIR, &st) == 0) { + argv[argc++] = AssetManager::OEM_OVERLAY_DIR; + } + // Finally, invoke idmap (if any overlay directory exists) if (argc > 5) { execv(AssetManager::IDMAP_BIN, (char* const*)argv); @@ -241,6 +245,10 @@ static jobjectArray NativeCreateIdmapsForStaticOverlaysTargetingAndroid(JNIEnv* input_dirs.push_back(AssetManager::ODM_OVERLAY_DIR); } + if (stat(AssetManager::OEM_OVERLAY_DIR, &st) == 0) { + input_dirs.push_back(AssetManager::OEM_OVERLAY_DIR); + } + if (input_dirs.empty()) { LOG(WARNING) << "no directories for idmap2 to scan"; return env->NewObjectArray(0, g_stringClass, nullptr); diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 099635246f05..59732d71778c 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -104,6 +104,8 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { static const char* kProductServicesOverlayDir = "/product_services/overlay"; static const char* kSystemOdmOverlayDir = "/system/odm/overlay"; static const char* kOdmOverlayDir = "/odm/overlay"; + static const char* kSystemOemOverlayDir = "/system/oem/overlay"; + static const char* kOemOverlayDir = "/oem/overlay"; static const char* kApkSuffix = ".apk"; if ((android::base::StartsWith(path, kOverlayDir) @@ -114,7 +116,9 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { || android::base::StartsWith(path, kSystemProductServicesOverlayDir) || android::base::StartsWith(path, kProductServicesOverlayDir) || android::base::StartsWith(path, kSystemOdmOverlayDir) - || android::base::StartsWith(path, kOdmOverlayDir)) + || android::base::StartsWith(path, kOdmOverlayDir) + || android::base::StartsWith(path, kSystemOemOverlayDir) + || android::base::StartsWith(path, kOemOverlayDir)) && android::base::EndsWith(path, kApkSuffix) && path.find("/../") == std::string::npos) { return true; diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 21609d30e92c..4755cb866310 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -76,6 +76,7 @@ const char* AssetManager::VENDOR_OVERLAY_DIR = "/vendor/overlay"; const char* AssetManager::PRODUCT_OVERLAY_DIR = "/product/overlay"; const char* AssetManager::PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay"; const char* AssetManager::ODM_OVERLAY_DIR = "/odm/overlay"; +const char* AssetManager::OEM_OVERLAY_DIR = "/oem/overlay"; const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme"; const char* AssetManager::TARGET_PACKAGE_NAME = "android"; const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk"; diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h index a015eabc200c..66fba26b7289 100644 --- a/libs/androidfw/include/androidfw/AssetManager.h +++ b/libs/androidfw/include/androidfw/AssetManager.h @@ -63,6 +63,7 @@ public: static const char* PRODUCT_OVERLAY_DIR; static const char* PRODUCT_SERVICES_OVERLAY_DIR; static const char* ODM_OVERLAY_DIR; + static const char* OEM_OVERLAY_DIR; /* * If OVERLAY_THEME_DIR_PROPERTY is set, search for runtime resource overlay * APKs in VENDOR_OVERLAY_DIR/ in diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 78aa5a0b66d7..251a42879328 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -597,6 +597,8 @@ public class PackageManagerService extends IPackageManager.Stub private static final String ODM_OVERLAY_DIR = "/odm/overlay"; + private static final String OEM_OVERLAY_DIR = "/oem/overlay"; + /** Canonical intent used to identify what counts as a "web browser" app */ private static final Intent sBrowserIntent; static { @@ -2533,6 +2535,13 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_AS_SYSTEM | SCAN_AS_ODM, 0); + scanDirTracedLI(new File(OEM_OVERLAY_DIR), + mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM_DIR, + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_OEM, + 0); mParallelPackageParserCallback.findStaticOverlayPackages(); -- cgit v1.2.3-59-g8ed1b