美文网首页Android开发经验谈
你真的懂Android的img镜像生成原理吗?

你真的懂Android的img镜像生成原理吗?

作者: Android进阶小麦 | 来源:发表于2020-05-25 15:02 被阅读0次

前面有很多起因与废话,想看研究直接点标题跳转哈

参考文章

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

前言&起因

  • 我也算入了官改的圈子,这个圈子几乎没有任何的技术共享,开源,因为很多都涉及到私人利益,但我始终将自己独有的技术与可以分享的技术分开来,我也会分享一些其他作者觉得时自己独有的技术的教程,也遭到了一系列的攻击,但向我要技术的只要不是绝对私人的技术我都都会告诉他
  • MIUI系统4.27发布MIUI12,官改圈的作者们都来适配上了这个最新系统的官改,几乎每个人都遇到了Mi10刷了自己官改后相机删退的问题,我所知的一些资深官改作者在5.1假期基本都修复了这一问题
  • 而这一问题的导致就是我所开发的工具箱生成的官改系统相机也会闪退,那么除非我能忍受我在测试系统的时候就不能使用任何的扫码功能,否则我之后的任何相关功能都无法继续开发

5.1一个人到成都租房,第一天住酒店,第二天坐公交到20公里外的表哥家住,第三天才把房租下来,之后两天也忙个不停,那几天一言难尽。。。🤬

异常表现🤔

  • 在最新小米10/10pro,k20,一加8等设备上都采用了动态分区机制,引用了super这一分区,刷机的时候动态设置了system/vender/odm/product等分区的大小,节省了空间
  • 写这个的起因就是在二次打包小米10/10pro这两款机型的时候,system/vendor分区的一些权限会不正常,表现在于相机闪退,抓log显示getCap()空指针异常,但是官方包刷入后是没有问题的,所以异常的导致肯定不是在相机app上,并且qq/微信等所有的app都无法正常打开摄像头。

这部分的资料真的实在太少了,除了参考文章有帮到我,其他的更多的人根本不愿意分享这部分的知识

  • 而我作为官改制作工具的开发者,我的工具箱存在的意义就是让喜欢刷机的人可以自己制作官改,这也涉及利益,所以,他们的任何人都不可能告诉我解决方向。

相机报错详情😑

io.reactivex.exceptions.OnErrorNotImplementedException: Attempt to invoke virtual method 'boolean com.android.camera2.CameraCapabilities.isSupportParallelCameraDevice()' on a null object reference

错误追踪😑

通过logcat可以看到在设备开机启动相机服务的时候就失败了,如下:

1636 W CameraService_proxy: Could not notify cameraserver, camera service not available.
05-11 19:56:54.547  1636  1636 I CameraService_proxy: Could not notify camera service of user switch, retrying...

由于任何地方对摄像头的使用都会用到这个服务,但是它启动失败了,所以它会一直尝试启动,手机会发烫,电量消耗加快

定位到这个服务的rc文件 /vendor/etc/init/android.hardware.camera.provider@2.4-service_64.rc

#! /bin/sh
#
#Copyright (c) 2019 Qualcomm Technologies, Inc.
#All Rights Reserved.
#Confidential and Proprietary - Qualcomm Technologies, Inc.
#

service vendor.camera-provider-2-4 /vendor/bin/hw/android.hardware.camera.provider@2.4-service_64
    override
    interface android.hardware.camera.provider@2.4::ICameraProvider legacy/0
    class hal
    user cameraserver
    group audio camera input drmrpc oem_2907
    ioprio rt 4
    capabilities SYS_NICE
    writepid /dev/cpuset/camera-daemon/tasks /dev/stune/foreground/tasks

找到它的服务可执行文件 /vendor/bin/hw/android.hardware.camera.provider@2.4-service_64 是一个二进制,我们直接执行一下,输出如下:

ardware.camera.provider@2.4-service_64; exit       <
WARNING: linker: Warning: "/vendor/lib64/libmialgo_ie_preview.so" unused DT entry: DT_RPATH (type 0xf arg 0x22741) (ignoring)
WARNING: linker: Warning: "/vendor/lib64/libcamera_scene.so" unused DT entry: DT_RPATH (type 0xf arg 0xe1b) (ignoring)
WARNING: linker: Warning: "/vendor/lib64/libarcsoft_bodyslim.so" unused DT entry: DT_RPATH (type 0xf arg 0xb74) (ignoring)
WARNING: linker: Warning: unable to normalize "D" (ignoring)
WARNING: linker: Warning: unable to normalize "\tools\android-ndk-r18b\toolchains\llvm\prebuilt\windows-x86_64\lib64\clang\7.0.2\lib\linux\aarch64" (ignoring)
WARNING: linker: Warning: unable to normalize "E" (ignoring)
WARNING: linker: Warning: unable to normalize "\Working\Code\android-ndk-r18b\toolchains\llvm\prebuilt\windows-x86_64\lib64\clang\7.0.2\lib\linux\aarch64" (ignoring)
WARNING: linker: Warning: unable to normalize "E" (ignoring)
WARNING: linker: Warning: unable to normalize "\Working\Code\android-ndk-r18b\toolchains\llvm\prebuilt\windows-x86_64\lib64\clang\7.0.2\lib\linux\aarch64" (ignoring)
WARNING: linker: Warning: unable to normalize "D" (ignoring)
WARNING: linker: Warning: unable to normalize "\tools\android-ndk-r18b\toolchains\llvm\prebuilt\windows-x86_64\lib64\clang\7.0.2\lib\linux\aarch64" (ignoring)
WARNING: linker: Warning: unable to normalize "E" (ignoring)
WARNING: linker: Warning: unable to normalize "\Working\Code\android-ndk-r18b\toolchains\llvm\prebuilt\windows-x86_64\lib64\clang\7.0.2\lib\linux\aarch64" (ignoring)
WARNING: linker: Warning: unable to normalize "E" (ignoring)
WARNING: linker: Warning: unable to normalize "\Working\Code\android-ndk-r18b\toolchains\llvm\prebuilt\windows-x86_64\lib64\clang\7.0.2\lib\linux\aarch64" (ignoring)
WARNING: linker: Warning: "/vendor/lib64/libmibokeh_845_video.so" unused DT entry: DT_RPATH (type 0xf arg 0x1e80) (ignoring)
WARNING: linker: Warning: "/vendor/lib64/libmibokeh_855.so" unused DT entry: DT_RPATH (type 0xf arg 0x1954) (ignoring)
WARNING: linker: Warning: unable to normalize "D" (ignoring)
WARNING: linker: Warning: unable to normalize "\android_tools\android-ndk-r18b\toolchains\llvm\prebuilt\windows-x86_64\lib64\clang\7.0.2\lib\linux\aarch64" (ignoring)
WARNING: linker: Warning: unable to normalize "D" (ignoring)
WARNING: linker: Warning: unable to normalize "\User\user\AppData\Local\Android\Sdk\ndk-bundle-r18b\toolchains\llvm\prebuilt\windows-x86_64\lib64\clang\7.0.2\lib\linux\aarch64" (ignoring)
WARNING: linker: Warning: unable to normalize "D" (ignoring)
WARNING: linker: Warning: unable to normalize "\User\user\AppData\Local\Android\Sdk\ndk-bundle-r18b\toolchains\llvm\prebuilt\windows-x86_64\lib64\clang\7.0.2\lib\linux\aarch64" (ignoring)
WARNING: linker: Warning: unable to normalize "D" (ignoring)
WARNING: linker: Warning: unable to normalize "\android_tools\android-ndk-r18b\toolchains\llvm\prebuilt\windows-x86_64\lib64\clang\7.0.2\lib\linux\aarch64" (ignoring)
WARNING: linker: Warning: unable to normalize "D" (ignoring)
WARNING: linker: Warning: unable to normalize "\User\user\AppData\Local\Android\Sdk\ndk-bundle-r18b\toolchains\llvm\prebuilt\windows-x86_64\lib64\clang\7.0.2\lib\linux\aarch64" (ignoring)
WARNING: linker: Warning: unable to normalize "D" (ignoring)
WARNING: linker: Warning: unable to normalize "\User\user\AppData\Local\Android\Sdk\ndk-bundle-r18b\toolchains\llvm\prebuilt\windows-x86_64\lib64\clang\7.0.2\lib\linux\aarch64" (ignoring)
terminating with uncaught exception of type std::bad_cast: std::bad_cast
Aborted

全是错,官方的系统执行这个文件是没有这个错的,我也只能确定是二次打包后才导致的,无法再从程序层定位

尝试从而ext4 img信息定位🧐

fs_config是从ext分区解析出来的包含分区内每一节点的权限/uid/gid信息,在重新生成镜像时会用到,它的格式如下:

lost+found 0000 0000 00700
#代表uid=0(root) gid=0(root) 权限为rwx------

file_context是从ext4分区解析出来的包含分区内每一节点的Selinux信息,生成镜像时会用到,格式如下:

/lost\+found u:object_r:rootfs:s0
#\为转义

初步定位

  • 1.使用工具箱二次打包官方系统
  • 2.分析出工具箱二次处理后system/vendor镜像大的fs_config/file_context/capabilities
  • 3.对比官方镜像中的信息(未发现任何差异,这是最头疼的🤯)

以上的各种确定大致就花了我两天吧,一遍上课一边定位bug,后来想起问题的关键是在凌晨两三点躺在床上的时候,想起来在Android Pie(9)的时候有一个错误是file_context缺失根目录Selinux的问题,也就是它记录了分区下所有节点的信息,就是没有记录自己所挂载到的节点信息

二次定位

system.img是系统分区,里面有大量的系统软件/framework层,本文不做详细研究

vendor.img是底层分区,里面有设备底层驱动

google为解决系统升级,系统适配带来的大量数据替换,从最初的a only到现在的sar结构,将系统层与驱动层分离出来(早期是在一起的)

  • 查看system.img所挂载点的信息,在sar(system as root)分区结构的系统中,system.img的挂载点就是/ 确认信息与官方源信息无差异
  • 查看vendor.mg所在挂载点的信息,挂载点为/vendor,发现异常

vendor挂载点异常如下

官方系统挂载点信息

/vendor 0000 2000 00755

也就是uid=0(root)、gid=2000(shell) 二次打包后vendor挂载点信息

/vendor 0000 0000 00755

gid从2000到了0000,所以分区根目录的权限就变成了root,从而导致没有root权限的程序根本访问不到这个分区的根目录 例如相机服务的services的gid为2000,他就拿不到底层第驱动的权限

Android镜像文件的生成

要了解这部分无疑逃不开看大量的帖子和看安卓系统的编译源码

鄙人3年前开始自己实现镜像的二次生成,自己写了一套万能的生成方案,覆盖安卓5-10,最近MIUI12出来才gg

旧的生成方案

也是我一直在用的方案

使用make_ext4fs程序生成(不能使用Android SDK中platform-tools中的这个程序,不能兼容到安卓9及以后,需要自行编译github第三方开发者针对pie后的修复)

make_ext4fs的作用是将整合好的文件夹生成标准的ext4分区img

make_ext4fs生成镜像方法

make_ext4fs -L $point -T 1230739200 $simg -s -S file_contexts -C fs_config -l $filesize -a $point volume.img $flodername

参数解析

  • -L:lable,镜像的标签(这个好像具体不影响,我a/b分区用的是/,a only用的是system)
  • -T:分区内所有节点的时间戳,在MIUI的系统上一般为0或者1230739200,这两者等效,都是1970/01/01,这个不一致也会导致系统很多异常bug
  • -s:生成sparse img(这里不做simg与rimg的区别分析),取消该开关即生成rimg
  • -S:分区Selinux信息
  • -l:分区的大小
  • -a:分区的挂载点(a/b分区是/,a only是system)
  • volume.img:镜像的名字
  • $flodername:需要打包成镜像的文件夹

更多参数执行make_ext4fs -h查看

Android8.0后引入的生成方案

可以知道的是google在Android 9.0的时候便删除了platform-tools中的make_ext4fs这个文件

我在最初编译一套兼容的打包方案就考虑过使用这方式,当时由于自己能力有限便放弃了,如果你google make_ext4fs应该能直接搜到我在别人开源下的issue

  • 需要阅读大量的安卓编译源码(我个人是看了大量的第三方文献)
  • 阅读github中aosp-mirror的Android镜像编译代码

最后在aosp-mirror platform_build库中的tools/releasetools找到了这一相关方案

涉及关键文件

  • build_image.py:将整合好的文件夹打包成ext4,将接收到的参数解析,并调用mkuserimg_mke2fs生成img镜像,也就是使用新的方案打包,需要一个system_image_info.txt作为参数
  • mkuserimg_mke2fs.sh:负责根据参数调用mke2fs、e2fsdroid
  • mke2fs:用来生成空白分区
  • e2fsdroid:用来将文件夹拷贝到空白分区内,并恢复fs_config、file_conetxt

以下为动态分区相关,本篇不做研究(自己试过了没有问题)

  • build_super_image.py:将已有的system/vendor/product/odm镜像生成super.img镜像
  • lpmake:用来生成super.img,参数为已经生成好的各个分区
  • lpunpack:用来加压super.img

第一次尝试生成镜像(以生成system.img为例)

来源本文顶部的几个参考帖子

使用以下命令

build_image.py ./system ./system_image_info.txt system.img

system_image_info.txt

ext_mkusering=./mkusering_mke2fs
fs_type=ext4
system_size=3508158464
extfs_sparse_flag=-s
squashfs_sparse_flag=-s
skip_fsck=true
selinux_fc=file_context
fs_config=fs_config

结果就是,各种失败

脚本执行后Linux系统ram瞬间从1g多到7g多,偶尔直接满(满的情况电脑就死机了),最后提示什么内存超出,输出本人是完全定位不到问题所在,这部分没有注意记录输出

以上我在手机本地生成与在Linux上的结果都是一样,各部分第三方的配置方案我都试过了,都不行

第二次尝试生成镜像

读了build_image.py后,它会根据接收到的参数,将接收到的参数放到字典,去生成与计算新的参数给mkeusering_mke2fs.sh

所以我们直接使用mkeusering_mke2fs.sh脚本

先看help输出

mkuserimg.sh [-s] SRC_DIR OUTPUT_FILE EXT_VARIANT MOUNT_POINT SIZE [-j <journal_size>]
             [-T TIMESTAMP] [-C FS_CONFIG] [-D PRODUCT_OUT] [-B BLOCK_LIST_FILE]
             [-d BASE_ALLOC_FILE_IN ] [-A BASE_ALLOC_FILE_OUT ] [-L LABEL]
             [-i INODES ] [-M RSV_PCT] [-e ERASE_BLOCK_SIZE] [-o FLASH_BLOCK_SIZE]
             [-U MKE2FS_UUID] [-S MKE2FS_HASH_SEED] [-c] [FILE_CONTEXTS]

经过很多次的尝试,总结出命令

mkuserimg.sh -s "\$PATH" "\$OUTPUT" ext4 / \$SIZE -T 0 -L / \$FILE_CONTEXTS

fs_config改动

添加vendor根挂载点权限

/ 0000 2000 00755

生成刷机包,刷入小米10,相机修复,以上所有工具用到的fs_config在linux设备上如已经保留分区所有节点的权限(就是打包前的文件夹内的节点权限都是正确的),可以直接省略。

生成的坑

正是由于我看了比较多的相关博客,绝大部分的作者加上了-M 0 -j 0这两个参数,最后经过了我大量的测试,这两个参数有一个就不开机!!!🤪

快捷参考

在修复的后期发现,用于生成gsi的开源库ErfanGSIs中也有新的打包方案🤯

结语

也就是说,make_ext4fs这一工具是无法恢复分区的根权限的,只有新的方案

  • 文章有任何的错误感谢各位指出。
  • 我不在乎这些圈子对我的攻击,我只需要做好自己的事(曾在酷安被一群人怼,说我偷他们的技术,就因为我指出了它们不对的地方,加上我又会一点逆向apk,在酷安,粉丝多是惹不起的)
  • 工具箱两个月能带给我的收入连一个月生活都维持不了,相比最初,已经添加了大量的付费功能,价格也没做任何上调,而官改巨头们所获得的的收入我应该至少得花上几年吧
  • 世上多的是比你过的轻松与比你过得艰难的人,不用太抱怨当下的生活
  • 大三开始休学一年,我做不好一边拼命学其他的技术还能念好书,这最终导致的是我挂的科越来越多,我还有太多都没有开始做的事,我最喜欢的,从来都不是计算机,身体现在也有比较明显的...一言难尽😑

作者:Nightmare梦魇兽
链接:https://juejin.im/post/5eb939f4e51d454dd940710f

相关文章

网友评论

    本文标题:你真的懂Android的img镜像生成原理吗?

    本文链接:https://www.haomeiwen.com/subject/fieyahtx.html