Android Overlay 机制解析

04-27 896阅读

Android Overlay机制

Android Overlay 是一种资源替换机制,它能在不修改原资源文件的情况下,覆盖替换 res/ 下的字符和图片等资源。

Android Overlay 机制解析
(图片来源网络,侵删)

主要分为 静态Overlay (Static Resource Overlay) 和 运行时 Overlay (Runtime Resource Overlay) 。

静态Overlay (SRO):发生在编译时,需要在 Aosp 源码中配置。

运行时Overlay (RRO):发生在运行时,可以直接覆盖替换其他 apk 的资源而不需要其源码。

静态Overlay (SRO)

可以替换 string.xml 、图片、layout、anim、xml目录中的 xml 文件 。

常用场景:覆盖替换 frameworks/ 、packages/ 目录下的资源文件。如改翻译词条、图片、改默认值等。

frameworks/base/core/res/res/drawable-xxxhdpi/
frameworks/base/core/res/res/layout-xxxhdpi/
frameworks/base/core/res/res/values/
frameworks/base/packages/SettingsProvider/res/values/defaults.xml
packages/apps/Bluetooth/res/values/

1.配置 overlay 目录

在 AOSP 源码下下找到 PRODUCT_PACKAGE_OVERLAYS 的宏定义,一般都配置在 device 目录下,如 device/xxx/yyy/device.mk

# overlay
PRODUCT_PACKAGE_OVERLAYS := \
    device/xxx/yyy/overlay

2.替换资源文件

在 device/xxx/yyy/overlay (其他目录也可以,主要对应上上面定义的PRODUCT_PACKAGE_OVERLAYS即可)下按照 frameworks 目录新建对应的文件夹,放入要替换的文件即可。

device/xxx/yyy/overlay/frameworks/
device/xxx/yyy/overlay/packages/

这种会在编译版本的时候根据设置的路径和配置的res文件直接将对应修改编译到目标apk中,相对于静态Overlay,运行时Overlay更灵活

运行时Overlay (RRO)

https://source.android.google.cn/docs/core/architecture/rros?hl=zh-cn

可以替换 string.xml 、图片,不能替换 layout、anim、xml 目录中的 xml 文件 。

举个栗子:

frameworks/base/packages/overlays/NavigationBarMode3ButtonOverlay/Android.bp

26 runtime_resource_overlay {
27     name: "NavigationBarMode3ButtonOverlay",
28     theme: "NavigationBarMode3Button",
29     product_specific: true,
30 }

frameworks/base/packages/overlays/NavigationBarMode3ButtonOverlay/AndroidManifest.xml

18 
22     
25 
26     
27 

frameworks/base/packages/overlays/NavigationBarMode3ButtonOverlay/res/values/config.xml

19 
20     
24     0
25 

我们先来解释一下:

1.NavigationBarMode2ButtonOverlay是编译出来的overlay APK的名字,product_specific表示这个应用会在product目录下

2.NavigationBarMode3ButtonOverlay是一个没有Java代码的APK,com.android.internal.systemui.navbar.threebutton表示这个overlay的包名,android:targetPackage="android"表示目标应用是framework-res.apk,会替换这个应用的res资源,android:priority="1"表示优先级,越大越高

3.需要留意,即使只是想替换 values-xx/strings.xml 里的字符串,values/strings.xml 里也要加上对应的字符串,要不然会替换不成功

4.因为NavigationBarMode3ButtonOverlay是一个应用,所以这个也是必须的

PRODUCT_PACKAGES +=

NavigationBarMode3ButtonOverlay \

AOSP源码中像这样overlay还有很多。一般都是为了方便不同机型机器配置不同属性的,我们照着这个写就行了

如何知道系统中有哪些Overlay呢?

我们可以通过命令adb shell dumpsys overlay或者adb shell cmd overlay命令

这里我们着重介绍下cmd overlay,这个命令允许我们动态的对系统中的overlay进行修改:

adb shell cmd overlay

Overlay manager (overlay) commands:
  help
    Print this help text.
  dump [--verbose] [--user USER_ID] [[FIELD] PACKAGE[:NAME]]
    Print debugging information about the overlay manager.
    With optional parameters PACKAGE and NAME, limit output to the specified
    overlay or target. With optional parameter FIELD, limit output to
    the corresponding SettingsItem field. Field names are all lower case
    and omit the m prefix, i.e. 'userid' for SettingsItem.mUserId.
  list [--user USER_ID] [PACKAGE[:NAME]]
    Print information about target and overlay packages.
    Overlay packages are printed in priority order. With optional
    parameters PACKAGE and NAME, limit output to the specified overlay or
    target.
  enable [--user USER_ID] PACKAGE[:NAME]
    Enable overlay within or owned by PACKAGE with optional unique NAME.
  disable [--user USER_ID] PACKAGE[:NAME]
    Disable overlay within or owned by PACKAGE with optional unique NAME.
  enable-exclusive [--user USER_ID] [--category] PACKAGE
    Enable overlay within or owned by PACKAGE and disable all other overlays
    for its target package. If the --category option is given, only disables
    other overlays in the same category.
  set-priority [--user USER_ID] PACKAGE PARENT|lowest|highest
    Change the priority of the overlay to be just higher than
    the priority of PARENT If PARENT is the special keyword
    'lowest', change priority of PACKAGE to the lowest priority.
    If PARENT is the special keyword 'highest', change priority of
    PACKAGE to the highest priority.
  lookup [--user USER_ID] [--verbose] PACKAGE-TO-LOAD PACKAGE:TYPE/NAME
    Load a package and print the value of a given resource
    applying the current configuration and enabled overlays.
    For a more fine-grained alternative, use 'idmap2 lookup'.
  fabricate [--user USER_ID] [--target-name OVERLAYABLE] --target PACKAGE
            --name NAME [--file FILE]
            PACKAGE:TYPE/NAME ENCODED-TYPE-ID/TYPE-NAME ENCODED-VALUE
    Create an overlay from a single resource. Caller must be root. Example:
      fabricate --target android --name LighterGray \
                android:color/lighter_gray 0x1c 0xffeeeeee

我们挑几个常用的

1.dump出当前系统中所有target为android的overlay以及mapping信息:

adb shell cmd overlay dump android

...
IDMAP OF com.google.android.overlay.gmsconfig.personalsafety
Paths:
    target path  : /system/framework/framework-res.apk
    overlay path : /product/overlay/GmsConfigOverlayPersonalSafety.apk
Mapping:
    0x01040241 -> 0x7f010000 (string/config_emergency_dialer_package -> string/config_emergency_dialer_package)

2.list出当前系统中所有target为android的overlay,其中[x]表示已启用的Overlay

adb shell cmd overlay list android

android
[x] com.google.android.overlay.gmsconfig.common
[x] com.google.android.overlay.gmsconfig.gsa
[x] com.google.android.overlay.gmsconfig.geotz
[ ] com.android.internal.display.cutout.emulation.corner
[ ] com.android.internal.display.cutout.emulation.double
[ ] com.android.internal.systemui.navbar.gestural_wide_back
  1. enable/disable某个Overlay(配置了isStatic=true的是无法disable的)

    adb shell cmd overlay disable com.android.systemui:neutral

[x] com.android.systemui:accent
[x] com.android.systemui:dynamic
[ ] com.android.systemui:neutral

adb shell cmd overlay enable com.android.systemui:neutral

[x] com.android.systemui:accent
[x] com.android.systemui:dynamic
[x] com.android.systemui:neutral
  1. enable-exclusive disable除指定overlay之外其他的所有overlay

  2. lookup 查看某个overlay实际覆盖的属性,比如上文的三指导航就可以用这个命令查看

adb shell cmd overlay lookup

com.android.internal.systemui.navbar.threebutton

android:integer/config_navBarInteractionMode

6.添加一个overlay

adb shell cmd overlay fabricate --target android --name com.android.internal.systemui.navbar.twobutton android:integer/config_navBarInteractionMode 0x010 0x1

此时我们通过命令可以看到我们刚添加的twobutton

IDMAP OF com.android.shell:com.android.internal.systemui.navbar.twobutton
Paths:
    target path  : /system/framework/framework-res.apk
    overlay path : /data/resource-cache/com.android.shell-com.android.internal.systemui.navbar.twobutton-rfZe.frro
Overlay name: com.android.internal.systemui.navbar.twobutton
Mapping:
    0x010e00b5 -> integer 0x00000001 (integer/config_navBarInteractionMode)

用enable使这个生效:adb shell cmd overlay enable com.android.shell:com.android.internal.systemui.navbar.twobutton

此时你会发现导航栏变成了两个按钮模式了

idmap2

OverlayManagerService 使用 idmap2 将目标软件包中的资源 ID 映射到叠加层软件包中的资源 ID。生成的 ID 映射存储在 /data/resource-cache/ 中。如果叠加层无法正常运行,请在 /data/resource-cache/ 中查找叠加层的相应 idmap 文件,然后运行以下命令。

adb shell idmap2 dump --idmap-path [file]

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]