1. framework层rro资源覆盖方案

在\framework\base\core\jni\android_util_AssetManager.cpp中:  before:

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

29static 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(am));

}

after:

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

51static 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(am));

}

由此可见,主要是在jni层的android_content_AssetManager_init函数这里来添加overlay apk的目录,Android默认的目录AssetManager::OVERLAY_DIR是/vendor/overlay,这里我们根据情况

1

1if (customed) {//判断是否自定义overlay目录

来确定是否需要修改。如果需要修改,这通过我自己定义的属性persist.customed.ui.rro.current来获取自定义目录。这个可以通过adb shell命令来进行set/get操作。

0818b9ca8b590ca3270a3433284dd417.png

这样我的overlay目录就是/vendor/Customedoverlay/myUI.

2. App层rro资源覆盖方案

同理,对于自定义App层的RRO资源覆盖目录则是在\framework\base\services\core\Java\com\android\server\pm\PackageManagerService.java  before:

1

2

3

4

5

6

7

8

9

1

2

3

4

5

6

7

8

9// 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:

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// 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);

在阅读代码寻找线索的过程中,通过查看网上的资料,最初确认的是/system/vendor/overlay这个目录,这里是原生系统中用来存放overlay apk的地方。通过在Linux中使用grep搜索命令来grep -nrs “/system/vendor/overlay”来查找线索。在Environment.cpp中有这个目录的使用,

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

33static 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;

}

一步一步阅读代码才发现,最终也定位到了\framework\base\core\jni\android_util_AssetManager.cpp中,但却是下面这段代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

0818b9ca8b590ca3270a3433284dd417.png

1

2

3

4

5

6

7

8

9

10

11

12

13if (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;

}

}

通过修改Environment.cpp中的

1

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

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

1

2

1

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

symlink /system/vendor /vendor

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

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐