Android开发经验谈

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

2020-05-25  本文已影响0人  Android进阶小麦

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

参考文章

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

前言&起因

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

异常表现🤔

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

相机报错详情😑

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
#\为转义

初步定位

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

二次定位

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

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

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

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

参数解析

更多参数执行make_ext4fs -h查看

Android8.0后引入的生成方案

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

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

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

涉及关键文件

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

第一次尝试生成镜像(以生成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这一工具是无法恢复分区的根权限的,只有新的方案

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

上一篇 下一篇

猜你喜欢

热点阅读