一直以来,与 iOS 相比,Android在性能、安全、功耗、碎片化(兼容性)问题上一直被诟病。知耻而后勇,知弱而图强。自 Android 4.0以来,Google一直致力于解决性能(Project Butter/OpenGLRenderer/RenderThread/ART)、安全(SELinux/FDE/FBE/VerifiedBoot)、功耗问题(Project Volta/Doze/App Standby/Background Execution Limits)。到了Android8.0,提出了Treble架构,致力于解决碎片化问题,在Android发展史上留下浓重的一笔。

到了P版本,Android似乎停止了演进,在架构上没有出现可圈可点的变化。然而并没有,Google正在酝酿下一个版本(Q)的大招——APEX。

APEX与Treble有着千丝万缕的关系,它们同为解决碎片化(兼容性)问题而生。Treble使得用户快速地更新系统版本。简单来说,Android系统由厂商代码(QCOM/MTK)以及AOSP代码两部分组成。厂商代码主要是硬件相关的,AOSP则代表Android系统版本。在没有Treble之前,这两部分代码是耦合在一起的,导致升级AOSP代码的同时,也需要同步升级厂商代码。

由于这两部分代码是不同的公司维护的,同时升级是一件不容易的事情,需要花费大量的精力,导致Android的最新版本迟迟不能推送到用户手上。

Treble通过HIDL和VNDK两个技术实现了厂商代码和AOSP代码的解耦。解耦后,就可以实现各自独立升级,极大地降低手机厂商升级Android版本的难度。对用户来说,甚至可以不用等待手机厂商最新的定制版Android系统,而直接刷入最新的原生Android系统。

Treble似乎很完美,但是仔细观察,升级流程还是太重了。上一个版本的某一个系统模块出现了问题(安全、兼容性等),需要等到下一个OTA版本才能解决。通过OTA升级版本是一个很重的流程,而且它是以整个Android系统为目标进行升级的。因此,如果只是针对特定的模块,通过OTA的方式来解决显然是不合适的,杀鸡焉用牛刀!

APEX呼之欲出,它的目标比Treble更进一步,要能够独立升级特定的系统模块,就像独立升级APK一样。事实上,APEX文件与APK文件的结构基本上是一样的,而且都是zip压缩格式。

APEX包内部包含两个配置文件AndroidManifest.xml和manifest.json,两者的内容是一样的。

AndroidManifest.xml

manifest.json

从配置文件的内容可以看到,APEX模块具有包名和版本号。目前从公开的Android Q代码可以看到,系统中存在以下这些APEX模块:

  • com.android.runtime: ART and bionic runtime (binaries and libraries)
  • com.android.tzdata: TimeZone and ICU data (libraries and configuration data)
  • com.android.resolv: Library used by Android to resolve network related requests (libraries)
  • com.android.conscrypt: A Java Security Provider (Java framework)

这些APEX文件保存在/system/apex或者/data/apex目录中。其中,保存在/data/apex目录中的APEX文件就是动态更新下载的,用来更新原来的APEX模块。

APEX包的主角是image.img文件,这是一个EXT2格式的Image文件:

它的内容由content和vbmeta两部分组成:

vbmeta包含content的签名信息。APEX模块激活后,content的内容受到dm-verity完整性保护,防止持久化攻击。dm-verity就是通过vbmeta的信息对content的内容进行完整性保护的。这与system分区受到的完整性保护机制是一致的。

下面我们主要介绍content中的内容。其中,manifest.json是配置文件,和APEX包根目录下的manifest.json内容是一样的。file1和file2是要更新的系统文件。

file_contexts文件用来指定file1和file2文件的SELinux上下文:

fs_config文件用来指定file1和file2文件的UID/GID:

如果APEX模块包含bin文件,那么可以在Image文件中指定ld.config.txt文件,用来描述该bin文件的LinkerNamespace。LinkerNamespace也是Treble引进的技术,用来隔离VNDK中不同Linker Namespace中的共享库,以确保具有相同库名称和不同符号的库不会发生冲突。

ld.config.txt的部分内容如下所示:

其中,第1行和第6行表示,当执行/apex/com.android.apex.text/bin目录下的bin文件时,将/apex/com.android.apex.test/${LIB}增加到它的动态库搜索路径中去。这样更新后的bin可以使用自带的so库代替原系统中的so库。

APEX模块是由系统服务ApexService管理的,它主要提供的功能有:

  • stagePackage:将APEX文件拷贝到/data/apex目录,并且命名为@.apex的形式
  • activatePackage:将APEX文件中的image.img挂载到/apex/@    
  • deactivatePackage:取消/apex/@的挂载,并删除文件夹

在系统正常运行期间,系统将APEX文件拷贝到/data/apex目录下。等到下次开机时,ApexService就会自动通过activatePackage激活APEX模块,实现替换系统原有的APEX模块的功能。

以com.android.apex.test为例,APEX模块的激活过程如下所示:

Step 1:从/data/apex/com.android.apex.text@1.apex中提取image.img文件。

Step 2:为image.img文件创建一个Loop Device。

Step 3:使用预置在系统中的/system/etc/security/apex/apex.key检验image.img的vbmeata签名。

Step 4:为Step 2中的Loop Device创建Verity Deivce,以便可以通过dm-verity保护image.img内容的完整性,防止持久化攻击。

Step 5:将VerityDeivce挂载在/apex/com.android.apex.test@1中。

Step 6:为/apex/com.android.apex.test@1创建符号链接/apex/com.android.apex.test。

从这个APEX模块的激活流程可以看到,一方面APEX模块受到dm-verity完整性保护,另一方面APEX模块通过版本号管理。其中,/apex/总是链接到最新版本的APEX模块。

APEX模块激活之后,它是如何替换系统中原来的模块的呢?被替换的模块可能是:

  • 配置文件(com.android.tzdata)
  • ELF可执行文件(com.android.runtime)
  • SO库文件(com.android.runtime/com.android.resolv)
  • JAR库文件(com.android.conscrypt)

不同类型的文件使用的替换方式是不一样的,我们分别介绍。

首先是配置文件,以com.android.tzdata为例,TimeZone信息是由libc负责读取的,它在读取的过程中,会优先检查/apex/com.android.tzdata下是否存在tzdata。如果存在,就会优先使用它:

*https://android.googlesource.com/platform/bionic/+/master/libc/tzcode/bionic.cpp

其次是ELF可执行文件,它所在的目录会被添加PATH环境变量中,以com.android.runtime为例,/apex/com.android.runtime/bin目录将会添加到PATH环境变量中:

*https://android.googlesource.com/platform/bionic/+/master/libc/include/paths.h

SO库文件和JAR库文件与ELF可执行文件类型,分别会被添加到各自的搜索路径中。

其中,将APEX模块中的SO库文件添加到搜索路径是在system/etc/ld.config.txt中配置的,以com.android.runtime为例:

*https://android.googlesource.com/platform/system/core/+/master/rootdir/etc/ld.config.txt

JAR库文件会被添加到BOOTCLASSPATH环境变量中,以com.android.conscrypt为例:

*https://android.googlesource.com/platform/build/+/master/target/product/base_system.mk

以上就是Android Q系统组件更新机制APEX。通过APEX,可以像更新APK一样更新系统组件,以快速解决Android系统的碎片化(兼容性)问题。我们也可以将APEX看作是Android系统的热更新机制。不过,从目前的热更新方式来看,只有预先指定的模块才可以进行热更新,不可以进行任意文件的更新。这是一个比较大的限制,不知道Google是否会考虑更灵活的方式,做到任意文件都可以进行热更新(使用Magisk的Magic Mount技术,或者overlayfs技术)。

转载自微信公众号:OPPO新技术

原文链接:https://mp.weixin.qq.com/s/9crfHyAiNUoLa6di9aQA3g

更多相关文章

  1. Android(安卓)Studio的使用小贴士
  2. ndk初体验
  3. android JNI学习之一
  4. xml文件内引用资源
  5. Android(安卓)Studio打包时如何将版本号修改成apk名字
  6. Android(安卓)Studio 移动项目到新文件夹,Installation failed wi
  7. Android5.1 Framework分析----如何在SystemServer中添加系统服务
  8. Android中SimpleAdapter,ArrayAdapter和BaseAdapter详解
  9. 使用ActivityGroup来切换Activity和Layout

随机推荐

  1. HBase基础 | 图数据库HGraphDB介绍
  2. 真正的机器学习平台根本不存在?
  3. MySQL数据库测试数据导入脚本与基础查询
  4. Apache iceberg:Netflix 数据仓库的基石
  5. Pinterest是如何基于Flink做实时分析的?
  6. IDEA激活码2020 最新idea激活码2021.3 全
  7. HBase实战 | 排查HBase堆外内存溢出
  8. 60TB 数据量的作业从 Hive 迁移到 Spark
  9. 企业信用评级等级是如何划分的?
  10. 2019,英伟达的低谷与涅槃