diff options
| -rw-r--r-- | core/java/android/content/Context.java | 10 | ||||
| -rw-r--r-- | core/java/android/content/res/AssetManager.java | 18 | ||||
| -rw-r--r-- | core/jni/android_util_AssetManager.cpp | 87 | ||||
| -rw-r--r-- | core/jni/fd_utils.cpp | 4 | ||||
| -rw-r--r-- | libs/androidfw/AssetManager.cpp | 2 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/AssetManager.h | 6 | ||||
| -rw-r--r-- | services/core/Android.bp | 2 | ||||
| -rw-r--r-- | services/core/java/com/android/server/om/IdmapManager.java | 94 |
8 files changed, 191 insertions, 32 deletions
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 03eba7efea91..004417b80e26 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4335,6 +4335,16 @@ public abstract class Context { /** * 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. * * @see #getSystemService(String) 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> 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 <sys/system_properties.h> #include <sys/types.h> #include <sys/wait.h> +#include <unistd.h> #include <private/android_filesystem_config.h> // for AID_SYSTEM +#include <sstream> +#include <string> + #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/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR. + // use VENDOR_OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> 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<std::string> 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<std::string> 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<std::string> 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/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to - * OVERLAY_DIR. + * APKs in VENDOR_OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> 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); + } } } |