summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/content/Context.java10
-rw-r--r--core/java/android/content/res/AssetManager.java18
-rw-r--r--core/jni/android_util_AssetManager.cpp87
-rw-r--r--core/jni/fd_utils.cpp4
-rw-r--r--libs/androidfw/AssetManager.cpp2
-rw-r--r--libs/androidfw/include/androidfw/AssetManager.h6
-rw-r--r--services/core/Android.bp2
-rw-r--r--services/core/java/com/android/server/om/IdmapManager.java94
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);
+ }
}
}