android 读取各分区大小,Android8 分区表变化和相关信息
8种机械键盘轴体对比
本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?
来源: https://pengzhangdev.github.io/android8-partiton-table/
差异简述¶
在Android8.0之后, 就存在两套分区表, 分别对应的是A/B系统和非A/B系统.非A/B系统的分区表与之前分区表一样, 没有变化.
A/B系统的分区表, 是本文的主要描述点.
所谓的A/B系统, 是指设备上存在两套系统, 其分区名也是存在_a 和 _b 的区别.两套系统中, 只有一套为active, 运行状态, 而升级则执行在另一套系统的分区中. 从而达到, 不管升级成功与否, 总有一套系统保证能使用.
而刷机, 包括挂时的分区表中, 都不会添加后缀(_a或_b). 只有在fastboot刷机时, 或者在init挂载时, 找到active的slot, 在指定分区名字后面添加后缀并挂载. 所以, 单纯从源码或者刷机包是无法指定哪些分区被指定为A/B了.
A/B系统带来的好处是:无缝升级, 不需要再进入recovery进行升级.
双系统备份, 不管是系统升级失败, 还是被破坏, 都可以切换到另一个系统, 确保用户设备的正常使用.
分区表与其内容¶
下面主要针对pixel设备进行分析, 也就是Android8的源码中marlin设备.
刷机文件和刷机方式¶
首先我们看下android官网提供的marlin设备刷机文件. 下面是基带和bootloader的刷机文件.
zip包中的文件如下.
如果单纯按照之前对该zip包文件的理解, 文件名字就是对应的分区名. 然而在A/B系统中, 却并不是如此. 而是按照一定的规则查找A/B分区.
首先, 最先注意到的是两个system大小不一致, 但是这个展开来讲有点多, 我们先把A/B系统刷机的第一个规则介绍以下, 代码在后文介绍第二个规则时可以同时看到.
A/B系统fastboot刷机时, 如果没有指定slot, 则默认刷入的是active的slot, 比如如果bootloader标记为slot A 为active, 则所有分区默认刷入slot A, 也就是说boot_a, system_a 等. 但是, 如果bootloader反馈某个分区没有区分A/B, 则默认直接刷入该分区. 比如 vendor 无区分A/B, 则直接刷入vendor.
然后, 我们关注下system.img和system_other.img, 如果单纯理解为这两个image分别刷入A/B分区, 则大小也完全对应不上. 大小问题, 我们稍后再看, 先研究下system_other.img刷入哪个分区.
static struct {
char img_name[17];
char sig_name[17];
char part_name[9];
bool is_optional;
bool is_secondary;
} images[] = {
{"boot.img", "boot.sig", "boot", false, false},
{"boot_other.img", "boot.sig", "boot", true, true},
{"recovery.img", "recovery.sig", "recovery", true, false},
{"system.img", "system.sig", "system", false, false},
{"system_other.img", "system.sig", "system", true, true},
{"vendor.img", "vendor.sig", "vendor", true, false},
{"vendor_other.img", "vendor.sig", "vendor", true, true},
};
其中 is_secondary 如果为true, 则意味着输入非active slot.
if (!skip_secondary) { // 默认 false
if (slot_override != "") { // 刷机时 为 ""
secondary = get_other_slot(transport, slot_override);
} else {
secondary = get_other_slot(transport); // 获取非active slot
}
if (secondary == "") {
if (supports_AB(transport)) {
fprintf(stderr, "Warning: Could not determine slot for secondary images. Ignoring.n");
}
skip_secondary = true;
}
}
for (size_t i = 0; i < arraysize(images); ++i) {
const char* slot = slot_override.c_str();
if (images[i].is_secondary) {
if (!skip_secondary) {
slot = secondary.c_str(); //指定为非active slot
} else {
continue;
}
}
int fd = unzip_to_file(zip, images[i].img_name);
if (fd == -1) {
if (images[i].is_optional) {
continue;
}
CloseArchive(zip);
exit(1); // unzip_to_file already explained why.
}
fastboot_buffer buf;
if (!load_buf_fd(transport, fd, &buf)) {
die("cannot load %s from flash: %s", images[i].img_name, strerror(errno));
}
auto update = [&](const std::string &partition) {
do_update_signature(zip, images[i].sig_name);
if (erase_first && needs_erase(transport, partition.c_str())) {
fb_queue_erase(partition.c_str());
}
flash_buf(partition.c_str(), &buf);
/* not closing the fd here since the sparse code keeps the fd around
* but hasn't mmaped data yet. The tmpfile will get cleaned up when the
* program exits.
*/
};
do_for_partitions(transport, images[i].part_name, slot, update, false);
}
所以, system_other.img 会刷入非active slot, 如果active为a. 则刷入system_b.
在确定system_other.img会刷入另一个slot后, 按照第一个规则(只刷active的slot), 则可以基本猜测, system_other.img中的内容不是用于启动系统的, 或者不是完整系统.
对比, 其内容差异, system_other.img 中, 只有 app 和 priv-app目录.system_other.img的目录中只存在odex和vdex文件, 也就是app优化过的文件, 并且额外多一个文件system-other-odex-marker. 这个文件是个线索, 所以, 初步可以判断, 系统启动后一定会从system_b将这些数据复制到/data/下.
下面我们看下这个文件的作用和如何copy.
on property:sys.cppreopt=requested && property:ro.boot.slot_suffix=_a
mount ext4 /dev/block/bootdevice/by-name/system_b /postinstall ro nosuid nodev noexec
exec - root -- /system/bin/cppreopts.sh /postinstall
# Optional script to copy additional preloaded content to data directory
exec - system system -- /system/bin/preloads_copy.sh /postinstall
umount /postinstall
setprop sys.cppreopt finished
on property:sys.cppreopt=requested && property:ro.boot.slot_suffix=_b
mount ext4 /dev/block/bootdevice/by-name/system_a /postinstall ro nosuid nodev noexec
exec - root -- /system/bin/cppreopts.sh /postinstall
# Optional script to copy additional preloaded content to data directory
exec - system system -- /system/bin/preloads_copy.sh /postinstall
umount /postinstall
setprop sys.cppreopt finished
在启动为任何之一时, 会从另一个slot挂载到/postinstall, 然后使用cppreopts.sh, 将odexvdex文件拷贝到/data/
dalvik-cache//xiam, isa是硬件架构(arm64/arm32).
而 preloads_copy.sh 会将system_other中的preloads文件拷贝到/data/preloads/ 目录下.
基于以上system的机制, 在刷机时, 实际只刷入一套系统到active slot中, 然后从另一套系统中的system分区将优化后的dex包拷贝到data分区下,. 与之前的差异是, 连应用的编译和优化都在host端完成, android8的启动速度将非常快.
源码和分区大小¶
从recovery的fstab中,我们可以看到的分区表如下:
/dev/block/platform/soc/624000.ufshc/by-name/system_a
/dev/block/platform/soc/624000.ufshc/by-name/system_b
/dev/block/platform/soc/624000.ufshc/by-name/vendor_a
/dev/block/platform/soc/624000.ufshc/by-name/vendor_b
/dev/block/platform/soc/624000.ufshc/by-name/userdata
/dev/block/platform/soc/624000.ufshc/by-name/boot_a
/dev/block/platform/soc/624000.ufshc/by-name/boot_b
但以上分区表在主系统中无法看到, 或者说主系统中只有在vendor下存在fstab, 其他地方并没有, 而vendor下的fstab内容如下, 是由vendor底下的init.{device}.rc 挂载.
/dev/block/platform/soc/624000.ufshc/by-name/system / ext4 ro,barrier=1 wait,slotselect,verify
/dev/block/platform/soc/624000.ufshc/by-name/modem /firmware/radio vfat ro,shortname=lower,uid=1000,gid=0,dmask=227,fmask=337,context=u:object_r:firmware_file:s0 wait,slotselect
/dev/block/platform/soc/624000.ufshc/by-name/userdata /data ext4 noatime,nosuid,nodev,barrier=1,noauto_da_alloc latemount,wait,check,formattable,fileencryption=ice,quota
/dev/block/zram0 none swap defaults zramsize=536870912,max_comp_streams=4
/dev/block/platform/soc/624000.ufshc/by-name/misc /misc emmc defaults defaults
/devices/*/xhci-hcd.0.auto/usb* auto vfat defaults voldmanaged=usb:auto
初步判断, 其有用的内容是给vold的挂载信息和基带分区. 但不管怎么看至少缺少了vendor挂载的信息. 而且fstab在vendor分区下, 则意味着vendor的挂载将提前到和boot同个级别. 没错, 新引入了一个early-mounted, 而分区表是在 device tree 中, 也就是启动后, 在 /proc/device-tree/firmware/android/fstab/vendor.
上文的fstab还给我们一个信息, 标志位slotselect, 意味这system分区是分A/B系统的并且由init根据active的slot选择对应的真实分区路径(后缀'_a'或'_b')进行挂载.
我们在看一眼system分区, 其挂载点是 / . 没错, 在Android8之后, system分区的确是被挂载到 /, 也就是说, system分区包含了rootfs, 其内容如下.
total 1724
drwxr-xr-x. 21 root root 4096 Sep 8 18:30 .
drwxrwxrwx 25 werther werther 32768 Sep 19 13:15 ..
drwxr-xr-x. 2 root root 4096 Sep 8 15:49 acct
drwxrwx--x. 2 werther werther 4096 Sep 8 15:49 bt_firmware
lrw-r--r--. 1 root root 50 Sep 8 18:30 bugreports -> /data/user_de/0/com.android.shell/files/bugreports
lrw-r--r--. 1 root root 11 Sep 8 18:30 cache -> /data/cache
lrw-r--r--. 1 root root 13 Sep 8 18:30 charger -> /sbin/charger
dr-x------. 2 root root 4096 Sep 8 15:49 config
lrw-r--r--. 1 root root 17 Sep 8 18:30 d -> /sys/kernel/debug
drwxrwx--x. 2 werther werther 4096 Sep 8 15:49 data
lrw-------. 1 root root 23 Sep 8 18:30 default.prop -> system/etc/prop.default
drwxr-xr-x. 2 root root 4096 Sep 8 15:49 dev
lrw-r--r--. 1 root root 15 Sep 8 18:30 dsp -> /vendor/lib/dsp
lrw-r--r--. 1 root root 11 Sep 8 18:30 etc -> /system/etc
drwxr-xr-x. 3 root root 4096 Sep 8 15:49 firmware
-rwxr-x---. 1 root 2000 1559136 Sep 8 18:11 init
-rwxr-x---. 1 root 2000 996 Sep 8 15:49 init.environ.rc
-rwxr-x---. 1 root 2000 26830 Sep 8 15:49 init.rc
-rwxr-x---. 1 root 2000 141 Sep 8 15:49 init.recovery.marlin.rc
-rwxr-x---. 1 root 2000 7623 Sep 8 15:49 init.usb.configfs.rc
-rwxr-x---. 1 root 2000 5715 Sep 8 15:49 init.usb.rc
-rwxr-x---. 1 root 2000 497 Sep 8 15:49 init.zygote32.rc
-rwxr-x---. 1 root 2000 847 Sep 8 15:49 init.zygote64_32.rc
drwx------. 2 root root 16384 Sep 8 18:30 lost+found
drwxr-xr-x. 2 root werther 4096 Sep 8 15:49 mnt
drwxr-xr-x. 2 root root 4096 Sep 8 15:49 oem
drwxr-xr-x. 2 root root 4096 Sep 8 15:49 persist
drwxr-xr-x. 2 root root 4096 Sep 8 15:49 postinstall
drwxr-xr-x. 2 root root 4096 Sep 8 15:49 proc
drwxr-xr-x. 3 root root 4096 Sep 8 15:48 res
drwxr-xr-x. 2 root root 4096 Sep 8 15:49 root
drwxr-x---. 2 root 2000 4096 Sep 8 18:11 sbin
lrw-r--r--. 1 root root 21 Sep 8 18:30 sdcard -> /storage/self/primary
drwxr-x--x. 2 root 1028 4096 Sep 8 15:49 storage
drwxr-xr-x. 2 root root 4096 Sep 8 15:49 sys
drwxr-xr-x. 16 root root 4096 Sep 8 18:30 system
-rw-r--r--. 1 root root 4849 Sep 8 15:49 ueventd.rc
drwxr-xr-x. 2 root 2000 4096 Sep 8 15:49 vendor
-rw-r--r--. 1 root root 524 Sep 8 15:50 verity_key
那么, 这些变化是如何做到的, 并且, 为什么system.img中要包含rootfs? 我们在后文会提到.
我们来看下Android官方网站给出的从普通分区切换到A/B分区, 对于分区大小的影响.Pixel Partitions SizeA/BNon-A/BBootloader50*250
Boot32*232
Recovery032
Cache0100
Radio70*270
Vendor300*2300
System2048*24096
Total50004680
从这张表上,我们看到pixel分区的A/B系统包括 bootloader, boot, radio, vendor, system.
分区表改变对系统逻辑的影响¶
这里总结下以上分区表的改变:没有recovery分区和cache分区.
vendor分区提前挂载(不是在fstab文件中中挂载, 在 device tree中指定)
真实分区名字存在_a和_b后缀.
挂载分区方式改变¶
early-mounted代码见 init_first_stage.cpp 在init第一次启动时, 会调用DoFirstStageMount, 和一些环境的配置. 完成后再次运行init, 进入第二阶段的执行. 而第二阶段实际上就是跟以前的Android处理方式一样.
挂载时选择slot的代码见init的DoFirstStageMount 刷机时选择slog的代码见fastboot, 也可见上面贴的代码.
boot包含recovery功能¶
首先, 升级切换成A/B无缝升级, 具体说明请参考recovery8的文档.
但是, recovery的功能并不止是升级, 还包括恢复, 如其名字.
为了支持恢复出厂设置的功能, recovery的功能被集成到了boot中, bootloader在进入recovery的时候, 进的是boot分区, 但是传的参数不包含skip_initramfs.
正常启动到android系统时的启动参数.
skip_initramfs rootwait ro init=/init root="/dev/dm-0 dm=system none ro,0 1 android-verity "
这里设置的skip_initramfs, 是通知内核, 跳过boot中的ramdisk. 这个参数是android添加的, 标准内核不支持.
然后我们解析下剩余参数, 主要是root参数. 这里可以看到, root指定的是system分区. 也就是说, 根分区就是以system分区.
然后我们看下启动recovery时的参数.
rootwait init=/init ro
这里因为没指定skip_initramfs, 所以, 会直接读取boot分区中的ramdisk.
进一步的理解就是, boot.img包含的是以前recovery的内容, 功能只有恢复出厂设置. 而原来的boot与system合并为system.img.
编译参数改变¶
https://source.android.com/devices/tech/ota/ab_implement
必须定义存档参数如下:
AB_OTA_UPDATER := true
AB_OTA_PARTITIONS :=
boot
system
vendor
*and other partitions updated through update_engine (radio, bootloader, etc.)*
BOARD_BUILD_SYSTEM_ROOT_IMAGE := true
TARGET_NO_RECOVERY := true
BOARD_USES_RECOVERY_AS_BOOT := true
PRODUCT_PACKAGES +=
update_engine
update_verifier
*For an example, refer to /device/google/marlin/+/android-7.1.0_r1/device-common.mk. You can optionally conduct the post-install (but pre-reboot) dex2oat step described in Compiling. *
必须不定义的参数如下:
BOARD_RECOVERYIMAGE_PARTITION_SIZE
BOARD_CACHEIMAGE_PARTITION_SIZE
BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
评论
android 读取各分区大小,Android8 分区表变化和相关信息相关推荐
- android 读取各分区大小,Android userData分区大小查看
首先,可以用个命令 cat /proc/partitions 查看分区大小如下所示:(单位KBytes) cat /proc/partitions major minor #blocks name ...
- android 读取各分区大小,Android查看各分区空间大小命令及相关操作
查看各个分区空间大小命令 SuperBox:/ $ df Filesystem 1K-blocks Used Available Use% Mounted on tmpfs 897520 496 89 ...
- Android之如何获取手机程序列表以及程序相关信息并启动指定程序
效果图: 程序列表: 启动程序,获取程序信息: 代码如下: 创建一个AppInfo类来表示应用程序 <pre name="code" class="java&quo ...
- android system 分区大小,Android System分区大小异常
平台:Freescale / Android 4.2.2 问题描述: 用 df 命令,看到/system分区大小275M. 用 busybox fdisk -l /dev/block/mmcblk0p ...
- 修改sh文件_修改Android分区大小
文档说明 本文档以SC826-CN-01(MSM8953平台)为例,描述如何修改Android系统的Cache分区大小. 默认代码Cache分区大小为256M,下面我们修改为512M. 相关文件路径 ...
- Android System分区大小异常
平台:Freescale / Android 4.2.2 问题描述: 用 df 命令,看到/system分区大小275M. 用 busybox fdisk -l /dev/block/mmcblk0p ...
- android外置sd大小,android 读取外置和内置存储卡路径和大小
[实例简介] android 读取外置和内置存储卡路径和大小,亲测好使,项目中以运用 [实例截图] [核心代码] a81fbea6-cb7a-4c96-be21-d52578f6de0a └── SD ...
- android gpt分区大小,[MTK] 如何确认各个分区起始偏移与大小
[MTK] 如何确认各个分区起始偏移与大小 无标签 2020-05-15 阅读:2972 分区表中(partition_table_MTXXXX_emmc.csv)中包含各分区预设大小信息,但是 (1 ...
- Android 修改分区大小
这里以android的cache分区为例. 查看当前使用cache大小: python device/rockchip/common/get_partition_size.py rockdev/Ima ...
最新文章
- Lambda表达式可以被转换为委托类型
- 科研文献|季节变化是流域尺度上土壤抗性变化的主要驱动因素
- 目标跟踪学习算法DSST
- ios学习——键盘的收起
- stm32 bootloader跳转
- 如何从我的eclipse项目中删除javascript验证?
- 如何安全的使用密码登录账号(在不知道密码的情况下)
- Java算法面试题(009) 毒酒问题
- 006 与PHP无关的EXCEL分割字符串
- 微博 用户画像_新浪微博数据采集方法以及数据分析(用户画像) - 八爪鱼采集器...
- 单片机通过串口与电脑通信
- 杨韬的Markdown自定义CSS样式
- c语言求两个字符串的交集,用c语言求两个集合的交集,并集,差集
- app端分页 简单的分页 java
- 前端模型--css动画(旋转八音盒)
- 高斯-赛德尔(Gauss-Seidel)解线性方程组的Matlab实现
- 通过uart串口和printf函数打印
- oracle常用创建模式,ORACLE 常用操作命令
- 《Unity游戏优化》笔记(4)[21/02/05_周五][P29_46]
- people who change the files in the active changelist also change