转载来源http://blog.csdn.net/whurs/article/details/53453702
1. framework层rro资源覆盖方案
在\framework\base\core\jni\android_util_AssetManager.cpp中:
before:
static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
{
if (isSystem) {
if (Environment::isSupported()) {
Environment* environment = new Environment();
if (environment != NULL) {
const char* overlay_dir = environment->getOverlayDir();
if (overlay_dir != NULL && strcmp(overlay_dir, "") != 0) {
ALOGD("Regionalization - getOverlayDir:%s", overlay_dir);
verifySystemIdmaps(overlay_dir);
}
delete environment;
}
}
verifySystemIdmaps(AssetManager::OVERLAY_DIR);
}
AssetManager* am = new AssetManager();
if (am == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", "");
return;
}
am->addDefaultAssets();
ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
after:
static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem) {
if (isSystem) {
if (Environment::isSupported()) {
Environment* environment = new Environment();
if (environment != NULL) {
const char* overlay_dir = environment->getOverlayDir();
if (overlay_dir != NULL && strcmp(overlay_dir, "") != 0) {
ALOGD("Regionalization - getOverlayDir:%s", overlay_dir);
verifySystemIdmaps(overlay_dir);
}
delete environment;
}
}
if (customed) {
char customed_overlay_dir[FILENAME_MAX] = {0};
char rro_ui[PROPERTY_VALUE_MAX];
property_get("persist.customed.ui.rro.current", rro_ui, "");
if (strlen(rro_ui) > 0) {
memset(customed_overlay_dir, 0, FILENAME_MAX);
snprintf(customed_overlay_dir, FILENAME_MAX, "/vendor/Customedoverlay/%s", rro_ui);
customed_overlay_dir[FILENAME_MAX - 1] = '\0';
struct stat info;
if(stat(customed_overlay_dir, &info) == 0 && S_ISDIR(info.st_mode))
if(!strcmp("overlay", rro_ui))
verifySystemIdmaps(customed_overlay_dir);
else
verifySystemIdmaps(AssetManager::OVERLAY_DIR);
else
verifySystemIdmaps(AssetManager::OVERLAY_DIR);
}
} else {
verifySystemIdmaps(AssetManager::OVERLAY_DIR);
}
}
AssetManager* am = new AssetManager();
if (am == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", "");
return;
}
am->addDefaultAssets();
ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
由此可见,主要是在jni层的android_content_AssetManager_init函数这里来添加overlay apk的目录,Android默认的目录AssetManager::OVERLAY_DIR是/vendor/overlay,这里我们根据情况
if (customed) {
来确定是否需要修改。如果需要修改,这通过我自己定义的属性persist.customed.ui.rro.current来获取自定义目录。这个可以通过adb shell命令来进行set/get操作。
这样我的overlay目录就是/vendor/Customedoverlay/myUI.
2. App层rro资源覆盖方案
同理,对于自定义App层的RRO资源覆盖目录则是在\framework\base\services\core\Java\com\android\server\pm\PackageManagerService.java
before:
// Collect vendor overlay packages.
// (Do this before scanning any apps.)
// For security and version matching reason, only consider
// overlay packages if they reside in VENDOR_OVERLAY_DIR.
File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
scanDirTracedLI(vendorOverlayDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
after:
File vendorOverlayDir;
if(customed) {
String CUMTOMED_OVERLAY_DIR = VENDOR_OVERLAY_DIR;
String rroUi = SystemProperties.get("persist.customed.ui.rro.current");
Slog.d(TAG, "**rroUi**:" + rroUi);
if(rroUi != null && !rroUi.equals("")) {
try {
String tmpOverlay = "/vendor/Customedoverlay/" + rroUi;
File tmpFile = new File(tmpOverlay);
if(tmpFile.isDirectory() && !rroUi.equals("overlay")) {
CUMTOMED_OVERLAY_DIR = tmpOverlay;
}
} catch (Exception ex) {
Slog.e(TAG, "Failed to set CPoverlay dir: " + ex.getMessage());
}
}
vendorOverlayDir = new File(CUMTOMED_OVERLAY_DIR);
} else {
vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
}
scanDirTracedLI(vendorOverlayDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
在阅读代码寻找线索的过程中,通过查看网上的资料,最初确认的是/system/vendor/overlay这个目录,这里是原生系统中用来存放overlay apk的地方。通过在Linux中使用grep搜索命令来grep -nrs “/system/vendor/overlay”来查找线索。在Environment.cpp中有这个目录的使用,
static const char* OVERLAY_DIR = "/system/vendor/overlay";
const char* Environment::getOverlayDir(void)
{
if (mPackagesCount != 0 && mStoragePos != NULL && mPackages != NULL) {
for (int i = mPackagesCount-1; i >= 0; i--) {
memset(mMediaFile, 0, PATH_MAX);
strlcpy(mOverlayDir, mStoragePos, PATH_MAX);
strlcat(mOverlayDir, "/", PATH_MAX);
strlcat(mOverlayDir, mPackages[i], PATH_MAX);
strlcat(mOverlayDir, OVERLAY_DIR, PATH_MAX);
if (kIsDebug) {
ALOGD("Environment::getOverlayDir() = %s\n", mOverlayDir);
}
char overlayFile[PATH_MAX];
memset(overlayFile, 0, PATH_MAX);
strlcpy(overlayFile, mOverlayDir, PATH_MAX);
strlcat(overlayFile, "/", PATH_MAX);
strlcat(overlayFile, mPackages[i], PATH_MAX);
strlcat(overlayFile, "FrameworksRes", PATH_MAX);
if (access(overlayFile, R_OK) == 0) {
if (kIsDebug) {
ALOGD("Environment::getOverlayDir() - overlayFile exists!\n");
}
return mOverlayDir;
}
}
}
return NULL;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
一步一步阅读代码才发现,最终也定位到了\framework\base\core\jni\android_util_AssetManager.cpp中,但却是下面这段代码:
if (isSystem) {
if (Environment::isSupported()) {
Environment* environment = new Environment();
if (environment != NULL) {
const char* overlay_dir = environment->getOverlayDir();
if (overlay_dir != NULL && strcmp(overlay_dir, "") != 0) {
ALOGD("Regionalization - getOverlayDir:%s", overlay_dir);
verifySystemIdmaps(overlay_dir);
}
delete environment;
}
}
通过修改Environment.cpp中的
static const char* OVERLAY_DIR = "/system/vendor/Customedoverlay";
但经过验证并没有效果。因此否定之前的设想,在通过查找,得知Android系统在init.rc文件中将/vendor 链接到了system/vendor:
# Link /vendor to /system/vendor for devices without a vendor partition.
symlink /system/vendor /vendor
因此也把/vendor/overlay链接到了/system/vendor/overlay。所以后来换成搜索/vendor/overlay来寻找线索,并最终得出以上结论。