9

了解一下,Android 10中的APEX

 3 years ago
source link: https://blog.csdn.net/innost/article/details/103776120
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

了解一下,Android 10中的APEX

阿拉神农 2019-12-30 15:23:26 9487

Android碎片化的问题除了好多厂商加了更符合国人土豪味的特性之外,其实还有一个更基础性的问题就是升级太慢。为啥子?

format,png

不记得之前讲过没有(好像讲过),现在再讲一遍:

  • 谷歌是AOSP代码的亲爹。但是有个问题,它老人家把代码搞出来后呢,还不能给厂商使用。因为谷老大没有硬件—给其他玩家用的硬件。

  • 在这个生态链里,谷老大之后是华为,高通,MTK这样的芯片厂商。这些芯片厂商有芯片(SOC啊,全套都有,就好像拎包入住的精装修的房子——为毛码农可以拿房产做比喻,潘石屹不能学Python?),再加上自己偏底层,偏硬件的代码,配合谷老大的上层,组合一下卖给下游厂商。

  • 接下来是华米OV魅,他们肯定是基于芯片厂商的代码来再做自己的工作。

虽然谷歌用了很多办法来提高新系统的适配速度(有技术上的,有厂商合作方面的),但这个长长的链条摆在这,新系统普及率比ios差得不是一星半点。痛定思痛,谷歌终于发现瓶颈在哪了,其实还是技术上的:

  • 刚开始以为是驱动更新不及时,所以谷歌搞了Treble。从Android O开始。通过Treble,OS升级中和硬件相关的地方就尽可能摘出来,老的驱动也能跑在新的OS上。不知道用Treble后,OS升级率提高到多少,但显然还没让人满意。

  • Android Q,谷老大搞了一个mainline计划,这个计划中文名可以称作霸王硬上弓——霸王是谷歌,硬上弓也指这活很需要技术含量,不是谁都能搞。支撑mainline计划的核心就是本篇要讲的APEX。这么霸王的名字居然是Android Pony EXpress的简称(Android小马快线?)。

APEX和APK类似,它把Framework层中那些关键的东西搞成一个个的模块,然后可以单独升级这些模块。这些模块和就和一个一个的APK类似,就是一个压缩包,后缀名叫.apex。来看官方文档中对.apex文件格式的描述:

format,png

apex和apk类似,实际上也是一个压缩文件。只不过apk和apex的目标不一样。请大家谨记

  • apk是应用程序的载体,对应用开发者而言,可以apk方式对应用功能进行升级。

  • apex是系统功能的载体,对系统开发者(目前看主要是谷歌)而言,可以apex方式对系统功能进行升级。这些apex包将来就发布在谷歌的playstore上供我们下载。简直不能太棒!

apex相当于对系统功能进行了更细粒度的划分,可以独立升级这些功能。而从另外某个意义上来说,这种做法也更加限制了设备厂商的魔改行为——这就是谷歌mainline计划的目的。

现在,我们可以把apex看成是一个一个的系统升级包,接下来我们看看系统中有哪些模块被划归到apex里了。

了解一下,有哪些apex包?

我们以模拟器+x86_64不带谷歌服务的镜像为例,启动模拟器看一下。

format,png

/system目录下多了一个apex目录。这里存的就是可以通过apex方式升级的系统功能。现在先不谈怎么个升级法。先看看哪些功能被封装到不同的apex里了。我们看几个主要的。

com.android.runtime.debug

其核心是com.android.runtime。什么是runtime呢?就是ART虚拟机相关的东西。下面是这个apex包的成员:

format,png

图中,每一个apex包(或者是目录)都包含:

  • apex_manifest.json:这个是apex包的清单文件,类似apk中的AndroidManifest.xml。apex_manifest.json功能比AndroidManifest.xml要复杂,里边还包含该apex安装前和安装后要执行的命令。

  • apex_pubkey:apex包的签名信息。和apk一样,我们对apex包也需要校验

  • 剩下的目录就是此apex包的实际内容。显然,什么so,可执行程序,系统级jar包都可以包含在apex包中

那么,com.android.runtime apex包都有哪些内容呢?

format,png

以上是runtime apex的主要内容。可看出,它包含的大部分是ART虚拟机相关的so和可执行程序。另外,bionic C库的libc.so,libdl.so,libm.so也在其中。

另外,位于/system/lib下的libc.so等也变成了链接,指向位于apex包中的这些so。来看图:

format,png

注意上图中的/apex/com.android.runtime目录,这个和apex包的处理逻辑有关,我们稍后介绍。

com.android.media

com.android.media是多媒体相关的apex包,直接看它的内容:

format,png

media apex包还包含了libbinder.so,libc++.so等非常关键的so。但要指出的是,/system/lib下的libc++.so却不是链接到media下的libc++.so。也就是说,系统里存在多份libc++.so。一个是/system/lib下的libc++.so,另外一个是media apex下的libc++.so(实际上,另外一个apex包,com.android.media.swcodec下还有一个libc++.so)。

除了libc++.so外,其他好几个so也存在同样的情况。对这件事,我第一感觉是有点奇怪。为了加载到正确的so,可能需要链接器linker程序做对应的修改。此问题我没有继续查下去了,欢迎有知道的童鞋指教。

了解一下,apex的安装

apex的安装(包括更新,回退)是一个比较复杂的过程。

为此,谷歌不惜对init做了重大改动。这里,我不打算对init做更详细的分析,先浮光掠影带大家看一下。有需要的话可自己看看。

总体来说,init大体上还是我八年前在《深入理解Android 卷1》里分析的那个init的样子。比如都是解析init.rc文件,然后执行对应的动作。但我感觉现在的init对初学者非常的不友好。因为代码逻辑比较复杂,而且用上了C++(应该在Android 10之前就用上C++了)。

对于Android这样的复杂系统,我感觉从老版本开始学习其实是一个合适的方法。因为老版本的思想,目的可能更单纯,更容易掌握。这有点像Linux Kernel方面的书籍,绝大部分都停留在2.x时代。这也是我为什么不愿意给深入理解系列书籍升级版本的原因。深入理解系列,宁愿开垦一个之前从未写过的方向,也不要做老版本升级。有些知识,还真不是越新越好。以我个人经验看,7.0的时候我为了做一个Framework培训,大概花了1个月左右的时间就对自己的知识进行了全面升级。现在10.0的话,我感觉在3个月内可以完成知识升级工作。

整体来说,10.0中的init将分为三个阶段执行。这三个阶段挺有意思,都是执行init,但传的参数不一样。

format,png

上图是init的main函数,稍微介绍下:

  • 首先是kernel启动后执行不带参数的init进程,这就进到上图中的FirstStageMain。FirstStageMain里边将做android verified boot,也就是把上篇文章(了解一下,Android 10中镜像文件的制作)里的分区挂载上来。第一阶段的代码中有大量和分区,avb有关的内容。是一个比较好的了解相关知识的地方

  • FirstStageMain最后会

    execv("/system/bin/init","selinux_setup")再次执行init(参数为"selinux_setup")。这将进入图中的SetupSelinux阶段。这个阶段也就是selinux相关处理。selinux是一个完备的知识体系,感兴趣的童鞋可阅读我在2014年2月CSDN上发的三篇selinux系列文章

    (https://blog.csdn.net/Innost/article/details/19299937)。这几篇文章秉承我们深入理解抄底式的学习风格,当年我拿它在SONY移动做内部培训用。唯一的小遗憾是没太讲selinux的programming。因为我当初理解它selinux更多是配置的事情。现在看也不完全对。

  • SetupSelinux最后

    execv("/system/bin/init","second_stage"),此后将转入图中的SecondStageMain就是我们早期init功能的处理之处。这块功能基本上用C++语言全部重写了(对比我在深入理解Android 卷1里2.3版本的init)。我个人感觉是init不美了。以前基于C结构体的OOP我觉得看着挺舒服....

apex作为一个系统功能安装包,肯定有一个对应的服务进行管理。在Android 10中,这个服务就是apexd。代码位于/system/apex下。init通过apexd.rc启动apex相关服务。看一下这个apexd.rc文件

format,png

apexd.rc有两个服务,一个是apexd-boostrap,一个是apexd。其实对应执行的程序都是/system/bin/apexd,只不过bootstrap带了一个参数“--bootstrap”。上面两个服务中,先启动apexd-bootstrap,然后再启动apexd。下面是apexd的入口代码:

format,png

apexd-bootstrap是主要处理apex包的地方。包括校验签名,apex版本比较等。然后,它会将apex包(例如/system/apex/com.android.runtime.debug等)挂载到/apex目录下。使用的方法是mount的MS_BIND标志。

format,png

我们看下apexd-bootstrap执行后,apex包mount的情况,

format,png

以上两个图中,最上面的是mount命令的结果。注意,apex包的mount和kernel的dm设备有比较密切的关系。Android 10大量使用了这个dm,以后有机会我们了解下。

下面的图是/apex/目录的内容。注意,有些目录名后面带一个@数字,比如com.android.conscrypt@290000000。这个290000000是com.android.conscrypt apex包中apex_manifest.json里的version字段。比如:

format,png

/apex是系统内部其他模块引用apex包的地方,这样就不需要使用/system/apex了。比如,我们上面的com.android.runtime.debug实际bind mount到/apex后将通过com.android.runtime来引用。

bind mount其实就是可以把一个目录挂载到多个目录。看起来效果和link一样。大家可在ubunutu上mount --bind试一下。

了解一下,apex的preinstall/postinstall

如果仅仅是挂载apex包,那我们还是太小瞧apex了。com.android.runtime的apex_manifest.json是这样的:

format,png

apex_manifest.json里还有preIntallHook和postInstallHook两个小东西。这两个东西指向apex包中bin/目录下的两个shell脚本。我们看一下postInstallHook的脚本(bin/art_postinstall_hook)。

format,png

这个脚本干了什么具体的事情我们先不细说,但是一个apex包升级居然还要涉及到脚本来执行,这还是第一次在Android上看到。所以,这里的复杂度比较高,很容易出错。我个人猜测未来可能会优化。

了解一下,apexservice

apexd服务将注册一个名为“apexservice”的服务到系统服务里,dumpsys apexservice打印的结果如下:

format,png

apexservice还有一些服务,如下:

format,png

到此,我们对apex的了解就告一段落。对一般开发者而言,只要知道apex包是被谷老大用来更新系统级功能的就行。另外,代码中有一个GSI(Generic System Image),这个GSI镜像可能包含的就是这些谷歌希望由自己来控制更新的apex包。通过这种方式,厂商能改的地方将大大受限,而能访问谷歌playstore的人们也可以第一时间享受谷歌的系统更新(但是谷歌经常也挖坑,搞出好多系统bugformat,pngformat,pngformat,png

后续的安排

AOSP 10源码撸了大概五天,发现其中有一些需要了解的知识,比如APEX、ART等。接下来会对这些东西做一系列的“了解”。在此也欢迎大家提供一些目标,好让我们的"了解Android 10”系列飞得更远一点。

最后的最后

  • 我期望的结果不是朋友们从我的书、文章、博客后学会了什么知识,干成了什么,而应该是说,神农,我可是踩在你的肩膀上的喔。

  • 关于学习方面的问题,我已经讨论完了。后面这个公众号将对一些基础的技术,新技术做一些学习和分享。也欢迎你的投稿。不过,正如我在公众号“联系方式”里说的那样——郑渊洁在童话大王《智齿》里有一句话令我印象深刻,大意是“我有权保持沉默,但你说的每一句话都可能成为我灵感的源泉”。所以,影响不是单向的,很可能我从你那学到的东西更多。

format,png

神农和朋友们的杂文集

长按识别二维码关注我们


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK