手动挂载apex镜像
1.loop设备
在类 UNIX 系统里,loop 设备是一种伪设备(pseudo-device),或者也可以说是仿真设备。它能使我们像块设备一样访问一个文件。
这要先从mount的流程来理解,挂载操作,实际上就是把设备上的文件系统/目录文件连接到指定的目录(directory)下,在操作系统层面就是把挂载设备和挂载目录的对应关系加到内核中的Vfsmount里的对应表单里(内核启动后会从硬盘上加载到内存里),这样我们就可以通过访问目录路径来访问设备上的数据了。
loop mount是另一种mount方式,如果说普通mount解决了实际硬件存储设备的挂载,bind mount解决了目录到目录的挂载,那么loop mount则解决了将档案文件到目录的挂载
档案,英文Archive,与文件(file)不同,是一个打包好的文件集,里面一般包含许多文件, 比如 tar,jar,iso ,img就是常见的档案格式
那又是怎么实现将档案文件挂载到目录下呢?
实际上,系统先把档案文件(比如某个.iso文件)映射到loop设备上
#losetup /dev/loop0 xxxx.iso 使系统误认为xxxx.iso为存储设备/dev/loop0
再欺骗mount命令,使他认为 /dev/loop0真的是个设备在运行,挂载到指定目录
#mount -t xxxx.iso /dev/loop0 /loop设备路径
但前提是,被访问的loop设备里的档案文件具有linux识别的文件系统,像tar, jar, zip 这样的档案,只是一种压缩格式,本身不是文件系统,即使通过loop mount挂载上去了,直接访问他也读不出什么数据,这很好理解,就像在windows下不装任何解压软件,就无法打开压缩文件一样。所有一般我们都是拿img、iso映射到loop设备。
2.apex包结构
APEX文件格式如下
从顶层看,APEX文件是一个Zip文件,其中的文件均是未压缩的。
其中的四个文件有apex_manifest.json
,AndroidManifest.xml
,apex_pubkey
,apex_payload.img
-
apex_manifest.json文件包括package name和版本,用来标识该APEX文件
-
AndroidManifest.xml可以允许APEX文件使用一些apk的工具,像adb、package manager、 app install app等。举个例子APEX文件可以使用aapt检查文件的metadata。该文件还包括packcage name和版本号,这些内容通常也会再apex_manifest.json文件中。
-
apex_payload.img是依赖dm-verity的EXT4文件系统镜像。该镜像在运行时通过一个回环设备加载。具体地说,metadata和hash tree是通过libavb创建的。apex_payload.img还没有被解析,因为要求该文件是可挂载的。一些常规文件包含在该镜像中。
-
apex_pubkey是用来给文件系统签名的公钥。该公钥确保下载的apex文件是以编译阶段相同的方式签名。
3.开始实验
-
将apex解压缩,上传到Linux中
其实apex包就是个压缩包,将后缀名改成.zip
,自行使用Windows解压工具进行解压
上传后我们可以看下它的文件结构和它的文件系统属性
amx@amxxxx:~/Android/system$ file apex_payload.img
apex_payload.img: Linux rev 1.0 ext2 filesystem data, UUID=7d1522e1-9dfa-5edb-a43e-98e3a4d20250 (extents) (large files) (huge files)
amx@amxxxx:~/Android/system$ tune2fs -l apex_payload.img
tune2fs 1.44.5 (15-Dec-2018)
Filesystem volume name: <none>
Last mounted on: <not available>
Filesystem UUID: 7d1522e1-9dfa-5edb-a43e-98e3a4d20250
Filesystem magic number: 0xEF53
Filesystem revision #: 1 (dynamic)
Filesystem features: ext_attr dir_index filetype extent sparse_super large_file huge_file uninit_bg dir_nlink extra_isize shared_blocks
Filesystem flags: signed_directory_hash
Default mount options: user_xattr acl
Filesystem state: clean
Errors behavior: Continue
Filesystem OS type: Linux
Inode count: 32
Block count: 8213
Reserved block count: 0
Free blocks: 8
Free inodes: 5
First block: 0
Block size: 4096
Fragment size: 4096
Blocks per group: 32768
Fragments per group: 32768
Inodes per group: 32
Inode blocks per group: 2
Filesystem created: Thu Jan 1 08:00:01 1970
Last mount time: n/a
Last write time: Thu Jan 1 08:00:01 1970
Mount count: 0
Maximum mount count: -1
Last checked: Thu Jan 1 08:00:01 1970
Check interval: 0 (<none>)
Lifetime writes: 32 MB
Reserved blocks uid: 0 (user root)
Reserved blocks gid: 0 (group root)
First inode: 11
Inode size: 256
Required extra isize: 32
Desired extra isize: 32
Default directory hash: half_md4
Directory Hash Seed: 7d1522e1-9dfa-5edb-a43e-98e3a4d20250
- 查看当前空闲的loop设备
amx@amxxxx:~/Android/system$ sudo losetup -f
/dev/loop0
可以看到当前空闲的loop设备为/dev/loop0
,所以我们打算将apex与/dev/loop0进行关联
- 将apex镜像与loop设备关联
amx@amxxxx:~/Android/system$ sudo losetup /dev/loop0 apex_payload.img
- 将loop设备挂载到目标节点上
amx@amxxxx:~/Android/system$ sudo mount -o ro /dev/loop0 /home/amx/Android/apex/com.android.i18n
这里我模仿了安卓将它挂载到了/home/amx/Android/apex/com.android.i18n
这里只能使用ro只读形式挂载,因为apex_playload.img采用了ext4文件系统,且在文件系统中添加了
shared_block
属性,该属性不允许随意修改镜像文件,也是为了将镜像文件尽量压缩到最小(从名字就可以看出来共享块)。这里可以通过改变inode结构改变这个属性,但是有点难度,需要了解ext文件系统才行。
- 查看是否挂载成功
可以看到我们可以像访问块设备一样访问apex包啦
4.参考
- https://blog.csdn.net/shengxia1999/article/details/52081286?spm=1001.2014.3001.5506
- https://blog.csdn.net/qq_28351465/article/details/106458089?spm=1001.2014.3001.5506