From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Thu, 30 Mar 2023 17:42:56 +0300 Subject: [PATCH] exec spawning: support runtime resource overlays --- core/java/android/app/IActivityManager.aidl | 2 ++ .../android/content/res/AssetManager.java | 33 +++++++++++++++++-- .../com/android/internal/os/ExecInit.java | 4 +++ .../server/am/ActivityManagerService.java | 6 ++++ 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 8367441b1b95..e582ea40ccf5 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -760,4 +760,6 @@ interface IActivityManager { *

*/ int getBackgroundRestrictionExemptionReason(int uid); + + String[] getSystemIdmapPaths(); } diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 4d9c3258f659..2e0ba40c6552 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -24,6 +24,7 @@ import android.annotation.Nullable; import android.annotation.StringRes; import android.annotation.StyleRes; import android.annotation.TestApi; +import android.app.ActivityManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo; import android.content.res.Configuration.NativeConfig; @@ -38,6 +39,7 @@ import android.util.TypedValue; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.om.OverlayConfig; +import com.android.internal.os.ExecInit; import java.io.FileDescriptor; import java.io.FileNotFoundException; @@ -233,6 +235,9 @@ public final class AssetManager implements AutoCloseable { } } + /** @hide */ + public static volatile String[] systemIdmapPaths_; + /** * This must be called from Zygote so that system assets are shared by all applications. * @hide @@ -249,8 +254,32 @@ public final class AssetManager implements AutoCloseable { final ArrayList apkAssets = new ArrayList<>(); apkAssets.add(ApkAssets.loadFromPath(frameworkPath, ApkAssets.PROPERTY_SYSTEM)); - final String[] systemIdmapPaths = - OverlayConfig.getZygoteInstance().createImmutableFrameworkIdmapsInZygote(); + // createImmutableFrameworkIdmapsInZygote() should be called only in zygote, it fails + // in regular processes and is unnecessary there. + // When it's called in zygote, overlay state is cached in /data/resource-cache/*@idmap + // files. These files are readable by regular app processes. + // + // When exec-based spawning in used, in-memory cache of assets is lost, and the spawned + // process is unable to recreate it, since it's not allowed to create idmaps. + // + // As a workaround, ask the ActivityManager to return paths of cached idmaps and use + // them directly. ActivityManager runs in system_server, which always uses zygote-based + // spawning. + + String[] systemIdmapPaths; + if (ExecInit.isExecSpawned) { + try { + systemIdmapPaths = ActivityManager.getService().getSystemIdmapPaths(); + Objects.requireNonNull(systemIdmapPaths); + } catch (Throwable t) { + Log.e(TAG, "unable to retrieve systemIdmapPaths", t); + systemIdmapPaths = new String[0]; + } + } else { + systemIdmapPaths = OverlayConfig.getZygoteInstance().createImmutableFrameworkIdmapsInZygote(); + systemIdmapPaths_ = systemIdmapPaths; + } + for (String idmapPath : systemIdmapPaths) { apkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, ApkAssets.PROPERTY_SYSTEM)); } diff --git a/core/java/com/android/internal/os/ExecInit.java b/core/java/com/android/internal/os/ExecInit.java index 749c67abf389..39f08b6a0f15 100644 --- a/core/java/com/android/internal/os/ExecInit.java +++ b/core/java/com/android/internal/os/ExecInit.java @@ -84,6 +84,8 @@ public class ExecInit { } } + public static boolean isExecSpawned; + /** * The main function called when an application is started with exec-based spawning. * @@ -99,6 +101,8 @@ public class ExecInit { Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from exec"); } + isExecSpawned = true; + // Check whether the first argument is a "-cp" in argv, and assume the next argument is the // classpath. If found, create a PathClassLoader and use it for applicationInit. ClassLoader classLoader = null; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 62b5df33df15..58f379421c3e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -18626,4 +18626,10 @@ public class ActivityManagerService extends IActivityManager.Stub Trace.traceBegin(traceTag, methodName + subInfo); } } + + @Override + public String[] getSystemIdmapPaths() { + // see comment in AssetManager#createSystemAssetsInZygoteLocked() + return android.content.res.AssetManager.systemIdmapPaths_; + } }