本章要介绍的运行时Overlay(RuntimeResourceOverlay)
Android Runtime Resource Overlay 简介】并不冲突,
只是在新的Android O版本,Google对于RR0机制的安全性进行了加强,后续有详细介绍。
首先系统编译过程中一般会将packages/apps目录下的源码项目通过AAPT打包成APK,存放至system/app或者system/priv-app目录下,最后连同其他资源打包得到系统镜像,当然也可以将APK直接打包到系统镜像。
静态Overlay
静态Overlay,简称为SRO,发生在编译时,需要在Android系统源码环境中进行配置。
配置步骤:
1.修改产品(高通msm8996对于framework层字串)的mk文件,添加如下代码:
t88909aa1/ap/android/device/qcom/
Name Date Size
common/ H 24-三月-2018 4 KiB
msm8909/ H 31-三月-2018 4 KiB
msm8909_512go/ H 10-三月-2018 4 KiB
msm8909go/ H 24-三月-2018 4 KiB
msm8996/ H 24-三月-2018 4 KiB
sepolicy/ H 06-一月-2018 4 KiB
t88909aa1/ap/android/device/qcom/msm8996/
H A D msm8996.mk 73 $(call inherit-product, device/qcom/common/common64.mk)
t88909aa1/ap/android/device/qcom/common/
H A D common.mk 5 # device-vendor.mk first to make sure QC specific files gets installed.
$(call inherit-product-if-exists, $(QCPATH)/common/config/device-vendor.mk)
H A D common64.mk 5 # device-vendor.mk first to make sure QC specific files gets installed.
$(call inherit-product-if-exists, $(QCPATH)/common/config/device-vendor.mk)
t88909aa1/ap/android/vendor/qcom/proprietary/common/config/device-vendor.mk
$(call inherit-product-if-exists, vendor/qcom/proprietary/qrdplus/Extension/products.mk)
$(call inherit-product-if-exists, vendor/qcom/proprietary/qrdplus/Extension/products.mk)
t88909aa1/ap/android/vendor/qcom/proprietary/qrdplus/Extension/
PRODUCT_PACKAGE_OVERLAYS += vendor/qcom/proprietary/qrdplus/Extension/apps/BatterySaver/overlay
实际修改的overlay文件:
t88909aa1/ap/android/vendor/qcom/proprietary/qrdplus/Extension/apps/BatterySaver/overlay/frameworks/base/core/res/res/values/
strings.xml
2.在overlays目录下添加对应产品的overlay项目,overlay项目实际上就是源项目剔除代码和替换资源后的项目,注意包名路径需要与源项目保持一致。
原理
实际上,SRO的实现很简单,只是在通过AAPT打包成APK时,通过-S命令多增加了一个资源目录(overlay目录)而已,我们平时打包APK只是通过AAPT -S指定了一个资源目录,而Overlay又额外增加了一个资源目录而已。
AAPT -S命令可以指定多个资源目录,overlay的资源将替换原res中的重名文件。可见SRO在编译成APK时已经完成。
运行时Overlay
运行时Overlay,简称RRO,顾名思义,该机制的资源替换发生在运行时。
与SRO的区别
RRO能直接定制替换第三方APK的资源,而不需要其源码。SRO如上节所述,则需要对应APK的源码才能完成,一般而言,第三方是不会提供项目源码的。
RRO的编译结果会得到一个xxx_overlay.apk,加上原项目的apk,总共会有2个apk,而SRO最终只会得到一个已经完成资源替换的apk。得到的overlay.apk可以视为一个正常的apk,因为它能被安装,含有自己的AndroidManifest.xml文件,当然正常下,overlay.apk是不含有执行代码的。
RRO不能替换AndroidManifest.xml文件及layout目录中的xml文件。虽然RRO具有自己的AndroidManifest.xml文件,但它却不能替换源项目中的AndroidManifest.xml文件。关于layout目录中的xml文件,SRO是可以替换的。
配置如下:
下面以创建WuiDemo的RRO为例进行说明:
创建一个新项目,包名命名为
com.overlay.wuidemo
,事实上包名可以随意命名,这样命名可读性高,一看包名就知道是哪个项目的overlay。
至此,我们需要额外关注就是Android O在RRO变化:
1.安全性提高,需要的不仅仅时OverLay同Target 两个Apk签名一致,还需要在Target Apk声明具有android.permission.CHANGE_OVERLAY_PACKAGES。
分析:
frameworks/base/services/core/java/com/android/server/om/OverlayManagerService.java
private void enforceChangeOverlayPackagesPermission(@NonNull final String message) {
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, message);
}
代码中检查权限的举动
2.配置规范行
Android O上面对于RRO,Google专门为其提供一个服务【OverlayManagerService】,如下:
t88909aa1/ap/android/frameworks/base/services/java/com/android/server/
H A D SystemServer.java 91 import com.android.server.om.OverlayManagerService;
649 mSystemServiceManager.startService(new OverlayManagerService(mSystemContext, installer));
t88909aa1/ap/android/frameworks/base/core/java/android/content/om/
OverlayInfo.java 33 * com.android.server.om.OverlayManagerService} should never have this
t88909aa1/ap/android/frameworks/base/services/core/java/com/android/server/om/
IdmapManager.java H A D 28-十二月-2017 4.4 KiB
OverlayManagerService.java H A D 28-十二月-2017 37.3 KiB
OverlayManagerServiceImpl.java H A D 28-十二月-2017 23.5 KiB
OverlayManagerSettings.java H A D 28-十二月-2017 19.6 KiB
OverlayManagerShellCommand.java H A D 28-十二月-2017 7.1 KiB
/t88909aa1/ap/android/frameworks/base/services/core/java/com/android/server/pm/
H A D PackageManagerService.java 846 // OverlayManagerService will update each of them with a correct gid from its
在【frameworks/base/services/core/java/com/android/server/om/OverlayManagerService.java】306行我们可以看到
frameworks/base/services/core/java/com/android/server/om/OverlayManagerService.java
private static final String DEFAULT_OVERLAYS_PROP = "ro.boot.vendor.overlay.theme";
private static Set getDefaultOverlayPackages() {
307 final String str = SystemProperties.get(DEFAULT_OVERLAYS_PROP);
308 if (TextUtils.isEmpty(str)) {
309 return Collections.emptySet();
310 }
311
312 final ArraySet defaultPackages = new ArraySet<>();
313 for (String packageName : str.split(";")) {
314 if (!TextUtils.isEmpty(packageName)) {
315 defaultPackages.add(packageName);
316 }
317 }
318 return defaultPackages;
319 }
此处还需要配置overlay包名,多个overlay应用需要以;分隔。
故我们时需要配置【ro.boot.vendor.overlay.theme】属性的。
原理
以我们常见的图片资源访问为例,当我们在应用层调用getDrawable方法的时候,会调用系统的getResource方法,该方法会根据资源id及设备配置信息(语言、像素密度等)来查找并返回合适的图片资源。此处,我们只关注根据id来选择资源。
如果id表明是系统资源,那么就会去framework-res.apk中查找并返回资源,一般位于/vendor/framework目录下,可root手机查看;如果是应用资源则在overlay和app中查找并返回。
个overlay包
当对应项目只有一个overlay包时,那么查找资源时,会先从overlay.apk中进行查找,查找成功直接返回,反之则从app中查找。
多个overlay包
当对应项目具有多个overlay包时,会按照overlay包的优先级从高到底依次进行查找,如果overlay包都查找失败,才会到app中进行查找。
以访问R.drawable.ic_01为例,会先从overlay1包先查找,因为其优先级最高,查找到则直接返回。
如果访问R.drawable.ic_02,先从overlay1查找,查找失败,接着从overlay2中查找,查找到直接返回。
如果访问R.drawable.ic_03,依次从overlay1,overlay2中查找,查找失败,最后会从app中查找到,并返回。
ps:
a.OverLay同Target Apk需要签名一致
b.Target Apk需要申请允许RRO overlay权限
c.OverLay同Target Apk必须保持统一的资源ID,系统或应用或其他自定义的资源ID
【资源ID】
我们知道资源文件在打包之后,会在R.java文件中生成一个对应的int类型资源id,这个id遵循以下的规则:
0xppttiiii
其中,
pp:01表示是系统资源,7f表示是应用资源
tt:用于表示资源类型,如string、array、图片资源等
iiii:用于表示相同类型的不同资源
总结
SRO实际上只是利用AAPT重新打包,发生在编译时;RRO,才是overlay机制的关键,其本质是Android系统的动态资源查找机制。
实际运用当中,Overlay机制一般用于手机厂商为不同运营商做客制化定制,或者做主题换肤;一般,第三方应用是无法享受该机制的,除非与手机厂商合作,不过应用层现在也有了换肤框架Android-Skin-Loader,其本质也是利用Android的资源查找机制。
其他补充 :https://blog.csdn.net/wh_19910525/article/details/39254815#comments
https://blog.csdn.net/Dylan_Sen/article/details/78878641 Android overlay简单总结
https://blog.csdn.net/wh_19910525/article/details/39254815 Android平台Overlay机制