[转载]Android overlay机制简介

由 adtxl 发布

转载自Android overlay简单总结
版权声明:本文为CSDN博主「一只特立独行的Yang」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Dylan_Sen/article/details/78878641

文简单总结Android 的overlay机制, 分为下面两部分:

1. SRO–Static resource overly(静态替换)
2. RRO–Runtime resource overlay (运行时替换)

1.SRO–Static resource overlay(静态替换)

SRO是在编译时完成的,我们可以根据不同的产品,为app/framework加载不同的资源, 由于相对较简单,所以下面就直奔主题,说说如何完成这个工作。

1.1. 添加路径,配置资源

对于Android的resource文件类型,可以看官网的介绍:
https://developer.android.com/guide/topics/resources/available-resources.html

在配置overlay编写overlay文件时要注意下面两点:

  • 对于可以根据key区分的资源,我们的overlay文件名字可以不和源包里的文件名字一致;
    [例如]string, string, array, bool, style,dimen等。

  • 对于依靠文件名字区分的资源, 我们的overlay文件名字必须和源包里的文件名字一致;
    [例如]drawable,layout,menu,animation,raw等。

1.2. 编写make文件,将路径添加到PRODUCT_PACKAGE_OVERLAYS或DEVICE_PACKAGE_OVERLAYS变量中。

PRODUCT_PACKAGE_OVERLAYS:用于一个指定的产品,即某个品牌的某个型号。
DEVICE_PACKAGE_OVERLAYS: 用于某个品牌的所有产品。

一般device/ 路径下的overlay使用DEVICE_PACKAGE_OVERLAYS,而vendor/路径下的overlay使用PRODUCT_PACKAGE_OVERLAYS

如果我们在编译时PRODUCT_PACKAGE_OVERLAYSDEVICE_PACKAGE_OVERLAYS都被加载而且overlay了源包中的相同的资源,那么PRODUCT_PACKAGE_OVERLAYS中的overlay资源会被最终使用,android build system替我们解决了这个问题, 所以我们不用担心。

下面的举两个例子,内容上有些匮乏,但是可供实际开发时参考。
[例子1]
我们以Android O源码中"device/google/atv/"中的overlay为例。
相关资源配置在"device/google/atv/overlay"路径下; make文件是“google/atv/products/atv_base.mk”。
“google/atv/products/atv_base.mk” 内容比较多,我们只摘录overlay相关的一句:

    DEVICE_PACKAGE_OVERLAYS := \
    device/google/atv/overlay

这里只有一个overlay路径所以比较简单,如果有多个overlay可以继续追加,并用空格隔开。

"device/google/atv/overlay"下的overlay分为两部分,一部分是针对framework/base/core, 另外一部分针对framework/base/packages 下面的截图是对core/res/res下资源的overlay:
image.png
也可以在overlay中添加源包中没有定义的资源,例如xml/global_keys.xml中的做法。

[例子2]
下面这个例子是在"vendor/google"路径中实现了对Telecom.apk资源配置的overlay。这个overlay会影响到incall-ui以及拨号盘的使用。
具体路径:“vendor/google/apps/GoogleDialer/overlay/packages/services/Telecomm/res/values/config.xml”
config.xml的内容如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- Package name for the default in-call UI and dialer [DO NOT TRANSLATE] -->
    <string name="ui_default_package" translatable="false">com.google.android.dialer</string>

    <!-- Class name for the default main Dialer activity [DO NOT TRANSLATE] -->
    <string name="dialer_default_class" translatable="false">com.google.android.dialer.extensions.GoogleDialtactsActivity</string>

    <!-- Class name for the default incall activity [DO NOT TRANSLATE] -->
    <string name="incall_default_class" translatable="false">com.android.incallui.InCallServiceImpl</string>
</resources>

下面是make文件的内容:

# Overlay for GoogleDialer
PRODUCT_PACKAGE_OVERLAYS += $(ANDROID_PARTNER_GMS_HOME)/apps/GoogleDialer/overlay

2 RRO–Runtime resource overlay(运行时替换)

对于RRO,分三部分:

  1. 资源相关知识点
  2. RRO apk的编写
  3. RRO apk的安装

2.1 资源相关知识点

对于Android的资源系统,官方有不少介绍,可以仔细看看:
https://developer.android.com/guide/topics/resources/index.html

我们可以将Android资源类型分为三类:

  1. 列表类型的xml资源文件,该类型的文件内部包含了多个资源项,典型的就是strings.xml,很多项目会有config.xml也大都是这种类型的文件。
  2. 值类型的xml文件,该类型的一个文件对应了一个资源项,比如layout目录下的布局文件,以及某些项目menu目录下的xml文件也大都是这种类型。
  3. 数据型资源文件,比如图片,音频,视频以及其他数据类型的文件,该类型的一个文件对应一个资源项。

在最终的安装包中第三种数据类型的资源文件会原封不动的保留。第二种值类型的xml资源文件,也会按照原有的目录结构和文件名字放入安装包中, 只是原有的xml格式会被压缩成特定的二进制流。列表型xml资源文件的内容会被全部编译到resources.arsc中。我们解压缩apk文件,看到内容如下图所示:

image227614af53883b5c.png

assets不属于android资源框架,所以不支持资源适配。
在res目录中,我们可以看到anim, color, layout, menu, drawable, mipmap, xml; 但是vaulues目录已经看不到了。
另外,在编译时会生成R.java这个类,为每个资源都生成了一个int类型的值,便于运行时快速查找。
ID的值类似0xPPTTiiii,PP表示package类型(01表示系统资源,7f表示应用资源); TT表示类型; iiii就是自动增长的编号了。

一般应用中使用资源通过Resources.java的下面两类接口:

  1. getString, getBoolean,getDrawable等。
  2. openRawResource。

传入的参数都是资源ID, 即R.XX.XXXX。接口是固定的,应用只需要传入相应的ID,framework负责根据当前的配置以及ID来查找最优资源,然后返回给应用。

image083daeed9d3fff4a.png

所以替换掉资源池中的资源对应用是不可见的,更不需要重新编译应用。在系统查找资源时overlay apk会比target apk优先查找,只有系统找到了更好的资源时一个候选资源才会被丢弃, 所以overlay apk中的资源被会优先使用。

imagec71b2be5f9417e82.png

2.2 编写RRO apk

RRO apk中不包含code,只有资源配置。AndroidMenifest.xml文件是重点。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.rrooverlay">
    <overlay android:targetPackage="com.example.android.rrotarget" android:priority="1"/>
</manifest>

android:targetPackage是我们要替换资源的目标apk,写包名就好。如果要替换framework下的资源,可以将android:targetPackage写成android

2.3 RRO apk的安装

由于RRO 可以修改资源,所以出于安全方面的考虑,只有"vendor/overlay"和“product/overlay”目录下的overlay apk才被接收(system/vendor/overlay和vendor/overlay是相关联的; 基于Android P)。资源ID是在apk编译过程中生成的,而overlay apk的编译时不用目标apk, 所以overlay apk中的资源并不会和目标apk中的资源分配同样的ID。这样资源的匹配只能通过我们定义的字符名称来完成,而字符匹配比较慢。在apk安装的过程中,“idmap"工具会帮忙生成map, 用来帮助overlay apk和目标apk同步资源。这个map数据存储在手机的”/data/resource-cache"目录中。


暂无评论

发表评论