8

了解一下,Android 10中镜像文件的制作

 3 years ago
source link: https://blog.csdn.net/innost/article/details/103519211
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中镜像文件的制作

阿拉神农 2019-12-12 20:50:14 8086

写《深入理解Android Java虚拟机ART》一书的时候,我自己做了基于模拟器使用的系统镜像,供我学习ART使用。编译系统镜像的步骤是这样的:

  • 先创建一个avd设备,取个名字,比如innost-10_64。请从心底深切注意并认识到:这个虚拟设备和你自己买的那些用来做测试的真实手机差不多。因为不论是虚拟设备还是真实设备,上面跑的都是其实都是无色无味无形的软件。所以,模拟器是研究Android系统中那些和硬件无关模块的最好的试验场

  • 接下来,你要为这个设备选择系统。这个就是模拟同一个手机可以刷不同的系统。

avd manager中有下载镜像的地方。比如,API 29/Android 10.0/x86_64 非谷歌版镜像

format,png

图中的Android 10.0(Goolge)是带GMS的镜像,不使用GMS那套东西的话我们是不需要的。

现在,avd manager中能看到innost-10_64这个设备,对应的系统信息。

format,png

这个时候启动(点击右上角的绿色三角形),就能启动一个模拟设备。

作为一个搞机人,肯定必须必然要知道如何通过命令行启动这个设备。答案如下:

  • Android-Sdk/emulator/emulator -avd innost-10_64 -verbose

其中,加上-verbose选项后,emulator运行过程中(尤其是最开始的时候)会输出非常多的信息。

我们看看emulator支持的命令行选项,如下所示:

format,png

上图中展示了emulator的很多选项。那我之前是如何用它的呢?

  • 在写Android ART一书的时候,我用Nougat源码,比如lunch选择innost_x86_64-userdebug

  • make systemimg后,在out/target/product/innost_x86_64下会生成一个system.img文件

  • emulator -avd innost-10-64       -system out/target/product/innost_x86_64/system.img 

通过这种方式,我让这个模拟器使用了自己搞出来的system.img文件。这样的话,我就可以魔改系统镜像,并随时用模拟设备来做测试了。

非常可惜且我奇怪了将近8个月的事情是,到了Android 10后,emulator -system选项貌似失效了。表现情况就是模拟器说无法加载system镜像。为这事,我还托人找谷歌AOSP开发者问了(对方给了一个搞法,但是和我的需求并不一致),我还一度怀疑是qemu或者kernel镜像哪里有问题.....

直到最近这两周,我偶然看了下init的代码,结合官方一些文档,才知道失败的原因。这里先说结论:

  • Android 10后,AOSP支持动态分区(dynamic partition)。即system分区大小不是固定的,而是可以动态调整。千万不要小看这个事情。在此之前,system分区大小是固定的,有些厂商把system分区搞得比较小,结果在从虚拟机从Dalvik切到ART的时候,发现system分区不够用。这个时候就得重新划分区,导致用户数据需要被清空,甚至有些设备根本就无法升级format,png,而实际上存储空间还有很多空余。所以动态分区是为了解决这个问题。BTW,现在也不要高兴太早,动态分区需要kernel的支持,所以,老版本的设备可能依然不能升级...BTW,感觉现在windows/linux上好像都不支持随意调整分区大小吧...

  • Android 10后,AOSP内置了android verified boot(代码中叫AVB,或小写的avb),即启动校验。这个应该是配合动态分区来做的。启动校验肯定一直就有,但之前都是设备厂商/芯片厂商自己实现的。现在AOSP提供了AVB框架,貌似还支持Android Things相关系统。

Android 10中,make systemimage会多生成好几个image文件,我们看一下

format,png

上图,多了什么super.img、vbmeta.img等一大堆东西,更奇怪的是,除了system.img之外,还有一个system-qemu.img...

事出反常必有妖。从这个角度看,Android 10的镜像文件的生成看来有重大变化。恩,是时候开始一次折腾之旅了,毕竟,人呐,不能闲死(此话的来历,见上篇公众号文章"了解一下,Android 10 Build系统")

Makefile,了解一下

首先,我们从m systemimage开始。但需要先学习下Makefile。依然是根据"了解一下,Android 10 Build系统"一文的知识,现在,我们必须将Makefile或其它.mk等文件看做是源码了(对,它属于Domain Specific Lanaguage。非常复杂)。

要真正看懂Makefile的话,需要了解Makefile的语法规则。它其实非常复杂,完整的语言详情可阅读官网https://www.gnu.org/software/make/manual/make.html

大体上说,Make是以rule为“单位”来驱动干活的。下面是一个rule的表示:

format,png

  • target:prerequistes一行是一个rule的目标以及依赖

  • recipe等行以tab开头。表示为了要达到一个target所需要的动作。动作可以是shell命令,也可以是调用Makefile里定义的函数。

所以,要分析Makfile,标准步骤如下:

  1. 先找到对应的rule以及它的依赖

  2. 然后确定其该rule的recipes,

这样我们就能知道为了达到某个target,我们需要准备哪些东西,做哪些事情。

现在看我写的一个Makefile,其中涉及到看懂AOSP中makefile文件的一些关键知识。

format,png
  • 我们通过define定义了一个functest函数(Makefile中,它其实叫cannied recipe,译为"罐装配方"),但其实我感觉和一个函数没什么区别。

  • @echo:echo是shell命令。前面加上@号之后,make将不会打印recipe的内容——意思是,如果没有@符号的话,make将打印每个recipe的内容,然后再执行这recipe。

cannied recipe可以被调用,调用方式有两种:

  • $(functest):直接调用这个罐装配方,貌似不能传参数

  • $(call functest, param1, param2):通过内置的call函数调用。可以传参数

在functest内部,$@代表调用它的target名,$^代表该target对应的依赖条件,而具体传过来的参数则是$1,$2表示。

做一个小测试,创建1.o,2.o,3.o,4.o文件后,执行make clean。clean将打印下面的内容:

format,png

另外,Makfile内置了很多命令,有操作文件的,操作字符串的,有支持for-each循环的,等等等等,在上面的官方文档中都可以找到说明

到此,Makfile相关基础知识就有了(很奇怪为何没有什么工具能解析Makefile,android build系统里定义了超多的变量、rule,target,现在要了解AOSP build系统,还只能靠最暴力的搜索...)

追踪systemimage目标

systemimage是一个编译目标。build目录下是整个AOSP编译系统的源码。mgrep syystemimage,提取相关的内容如下:

format,png

上面列了七个步骤。就是按前面提到的Makefile解析两步骤来找的(彻头彻尾的暴力搜索,毫无技术含量..)。

多说一下:Android中$(hide)的取值为

build/make/core/config.mk:180:hide := @

这样,make就不会打印recipe的内容了。

上面图片中,systemimage的制作是由python脚本build_image.py来实现的,并且依赖一个叫system_image_info.txt的文件。

我们马上来运行下这个脚本。不得不说,AOSP build工作真的不是写写配置就完事。上篇文章(了解一下,Android 10 Build系统)说了要懂go,这次大家也看到了,python也要懂...

format,png

上图展示了system_image_info.txt,原来它包含了生成镜像文件的配置。我们这里就不讨论怎么生成这个txt文件了。按上面的makefile查找方法,很容易找到生成这个文件的Rule。

在build_img.py中,我们发现真正的镜像制作工具是mkuserimg_mke2fs

这个工具由AOSP提供,源码为system/extras/ext4_utils/。

注意,lunch后,mkuserimg_mke2fs已经在PATH变量中了,大家可以执行下玩玩。

追踪system-qemu.img目标

上面介绍了system.img生成方法,现在看看system-qemu.img的规则,通过mgrep system-qemu.img,得到下图:

format,png

上图中有几个变量需要特别注意:

  • SGDISK => out/soong/host/linux-x86/bin/sgdisk  源码:external/gptfdisk。它是一个第三方开源库,其说明是“Command-line GUID partition table (GPT) manipulator for Linux and Unix”,也就是专用于Linux的硬盘分区工具

  • SIMG2IMG => out/soong/host/linux-x86/bin/simg2img 源码:system/core/libsparse。这个是将sparse镜像文件转换为非sparse镜像文件的工具,由AOSP提供。

  • MK_COMBINE_QEMU_IMAGE_SH => device/generic/goldfish/tools/mk_combined_img.py,一个工具

  • INSTALLED_SYSTEM_QEMU_CONFIG => out/target/product/generic_x86_64/system-qemu-config.txt。生成system-qemu.image的配置文件

老套路,python脚本加一个配置文件。所以,生成system-qemu.img的配置文件是system-qemu-config.txt,其内容如下,就两行文本

  • out/target/product/generic_x86_64/vbmeta.img vbmeta 1

  • out/target/product/generic_x86_64/super.img super 2

mk_combined_img.py其实内部调用的就是sgdisk。执行sgdisk --print system-qemu.img,可显示这个镜像文件的信息。其中有两个分区,分别叫vbmeta以及super。如下图所示:

format,png

mk_combined_img并不复杂,核心还是利用sgdisk命令对vbmeta和super两个镜像文件进行合并处理。具体怎么玩sgdisk,这里就不说了。看了下,并不是很复杂(提示:不要想着去看sgdisk的实现,关键是怎么用它)

那么,vbmeta和super分别是什么呢?分别了解一下。

vbmeta.img,了解一下

生成vbmeta.img的罐装配方如下:

format,png
  • INSTALLED_VBMETAIMG_TARGET => out/target/product/generic_x86_64/vbmeta.img

  • AVB_CHAIN_KEY_DIR => 一个存储key的文件夹,但是命令执行完后又删除了

  • AVBTOOL => out/host/linux-x86/bin/avbtool 。源码在external/avb下。avb就是谷歌android verified boot的全部代码。

  • 其他参数,不说了

avbtool这个工具是供host生成vbmeta镜像时用的。它会用到私钥进行数字签名和加密。如果没定义下面两个变量的话,默认

BOARD_AVB_ALGORITHM := SHA256_RSA4096

BOARD_AVB_KEY_PATH :=  external/avb/test/data/testkey_rsa4096.pem

使用上述指定的加密和签名方式。

testkey_rsa4096.pem是个私钥文件,内容如下:

format,png

avbtool是android启动校验安全的核心组成部分,详细代码在external/avbtool下:

  • 生成镜像时使用工具avbtool

  • 设备上的系统启动时,使用libavb(由init使用)进行校验

关于avb,external/avb/README.md是详细了解它的关键文档,下面截个图看看:

format,png

使用avbtool工具,看下我们vbmeta.img的内容

format,png

如前所述,verified boot设备/芯片厂商早就有了。所以,文档里说,android verified boot只是verified boot的一种实现。另外,avb支持回退,A/B系统等各种看起来比较高级的功能。感兴趣的可以深入学习一把。BTW,Android Things(IoT)方面也可以使用它。

super.img,了解一下

生成super.img的罐装配方如下:

format,png
  • lpmake:command-line tool for creating Android Logical Partition images 源码在system/extras/partition_tools。

  • build_super_image.py:内部就是调用lpmake生成最终的super.img文件

生成super.img用到了一个名为misc_info.txt的配置文件,其内容如下:

format,png

我用这个配置文件,手动调用build_super_image.py生成一个dfptest/dfptest.img,输出如下。这个文件的md5和build生成的super.image一样。

format,png

super.img到底干啥自用的呢?它是实现动态分区的关键。来看官网说明:

https://source.android.com/devices/tech/ota/dynamic_partitions/implement

format,png

说白了,就是通过super+动态分区,system可以调整大小了。也就是说,system分区并不是真实的物理分区,而是逻辑分区。super分区远比system分区大。这样,system分区才能动态调整。另外,要说明的是,只有read-only的分区才能这么搞。/data分区就不适合,因为谁知道用户会存储多少内容呢....

到此,我们对Android 10如何生成镜像文件做了一些了解。涉及到相关知识有:

  • Makefile的一些语法,尤其是罐装配方

  • system.img和生成它的工具以及依赖。核心工具是mkuserimg_mke2fs

  • system-qemu.img和生成它的工具以及步骤。核心工具是sgdisk

  • vbmeta.img和生成它的相关工具以及步骤。核心工具是avbtool

  •  super.img和生成它的相关工具以及步骤。核心工具是lpmake

  • avb的相关知识以及super(动态分区)相关知识   

后续的安排

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

最后的最后

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

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

format,png

神农和朋友们的杂文集

长按识别二维码关注我们


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK