自定义Android资源覆盖rro方案

转载来源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) {
        // Load frameworks-res.apk's overlay through regionalization environment
        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) {
        // Load frameworks-res.apk's overlay through regionalization environment
        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;
            }
        }
//在此处加入我们自己想要定制的overlay目录
        if (customed) {//判断是否自定义overlay目录
                char customed_overlay_dir[FILENAME_MAX] = {0};
                char rro_ui[PROPERTY_VALUE_MAX];
                //get ui schemes by property value
                property_get("persist.customed.ui.rro.current", rro_ui, "");
                //whether rro_ui value is null
                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;
                    //check whether customed_overlay_dir is a directory
                    if(stat(customed_overlay_dir, &info) == 0 && S_ISDIR(info.st_mode))
                        //if the property value equals "overlay", we will user the origin default directory.
                        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) {//判断是否自定义overlay目录
 
 
  • 1
  • 1

来确定是否需要修改。如果需要修改,这通过我自己定义的属性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);
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

after:

// 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;
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);
            }
            // Check if PackageFrameworksRes dir exists.
            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) {
        // Load frameworks-res.apk's overlay through regionalization environment
        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;
            }
        }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

通过修改Environment.cpp中的

static const char* OVERLAY_DIR = "/system/vendor/Customedoverlay";
 
 
  • 1
  • 1

但经过验证并没有效果。因此否定之前的设想,在通过查找,得知Android系统在init.rc文件中将/vendor 链接到了system/vendor:

# Link /vendor to /system/vendor for devices without a vendor partition.
symlink /system/vendor /vendor
 
 
  • 1
  • 2
  • 1
  • 2

因此也把/vendor/overlay链接到了/system/vendor/overlay。所以后来换成搜索/vendor/overlay来寻找线索,并最终得出以上结论。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值