Merge "Prepare for switch to idmap2"
This commit is contained in:
committed by
Android (Google) Code Review
commit
db54beb98c
@@ -4333,6 +4333,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.
|
||||
|
||||
@@ -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.
|
||||
/**
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user