一、A/B升级之系统image的生成
本篇将对AB升级打开宏开关后make 和 makeotapackage的流程做分析,下面这张图是之前文档中所提到的按照对应文件打开宏开关,即可开启AB升级,但是代码里面针对该宏控也有对应代码处理,本次先分析device 和 build下的修改

一、device主要修改
最初加入了MTK_AB_OTA_UPDATER = yes
去除cache分区编译的控制开关
ifneq ($(strip $(MTK_AB_OTA_UPDATER)), yes)
BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE := ext4
endif
diff --git a/mediateksample/k39tv1_64_bsp/BoardConfig.mk b/mediateksample/k39tv1_64_bsp/BoardConfig.mk index 13eb004..fd32381 100644 --- a/mediateksample/k39tv1_64_bsp/BoardConfig.mk +++ b/mediateksample/k39tv1_64_bsp/BoardConfig.mk @@ -6,10 +6,11 @@ include device/mediatek/mt6739/BoardConfig.mk #Config partition size -include $(MTK_PTGEN_OUT)/partition_size.mk +ifneq ($(strip $(MTK_AB_OTA_UPDATER)), yes) BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE := ext4 +endif BOARD_FLASH_BLOCK_SIZE := 4096 - MTK_INTERNAL_CDEFS := $(foreach t,$(AUTO_ADD_GLOBAL_DEFINE_BY_NAME),$(if $(filter-out no NO none NONE false FALSE,$($(t))),-D$(t))) MTK_INTERNAL_CDEFS += $(foreach t,$(AUTO_ADD_GLOBAL_DEFINE_BY_VALUE),$(if $(filter-out no NO none NONE false FALSE,$($(t))),$(foreach v,$(shell echo $($(t)) | tr '[a-z]' '[A-Z]'),-D$(v)))) MTK_INTERNAL_CDEFS += $(foreach t,$(AUTO_ADD_GLOBAL_DEFINE_BY_NAME_VALUE),$(if $(filter-out no NO none NONE false FALSE,$($(t))),-D$(t)=\"$(strip $($(t)))\")) diff --git a/mediateksample/k39tv1_64_bsp/ProjectConfig.mk b/mediateksample/k39tv1_64_bsp/ProjectConfig.mk index 99aebd3..3419c65 100755 --- a/mediateksample/k39tv1_64_bsp/ProjectConfig.mk +++ b/mediateksample/k39tv1_64_bsp/ProjectConfig.mk @@ -685,7 +685,8 @@ TRUSTONIC_TEE_SUPPORT = no USE_FRAUNHOFER_AAC = no USE_XML_AUDIO_POLICY_CONF = 1 WIFI_WEP_KEY_ID_SET = no -MTK_AB_OTA_UPDATER = no +CONFIG_MTK_AB_OTA_UPDATER = yes +MTK_AB_OTA_UPDATER = yes
搜索宏控相关文件如下
libiaobiao:~/code/s219_ab/device$ grep -rni "MTK_AB_OTA_UPDATER"
mediateksample/k39tv1_64_bsp/BoardConfig.mk:9:ifneq ($(strip $(MTK_AB_OTA_UPDATER)), yes)
mediateksample/k39tv1_64_bsp/ProjectConfig.mk:688:CONFIG_MTK_AB_OTA_UPDATER = yes
mediateksample/k39tv1_64_bsp/ProjectConfig.mk:689:MTK_AB_OTA_UPDATER = yes
mediatek/common/device.mk:3643:ifeq ($(strip $(MTK_AB_OTA_UPDATER)), yes)
mediatek/common/BoardConfig.mk:228: ifeq ($(strip $(MTK_AB_OTA_UPDATER)), yes)
mediatek/mt6739/BoardConfig.mk:132:ifneq ($(strip $(MTK_AB_OTA_UPDATER)),yes)
mediatek/build/build/tools/ptgen/MT6739/ptgen.mk:71: MTK_AB_OTA_UPDATER=${MTK_AB_OTA_UPDATER} \
mediatek/build/build/tools/ptgen/MT6739/ptgen.pl:195: $ArgList{MTK_AB_OTA_UPDATER} = $ENV{MTK_AB_OTA_UPDATER};
mediatek/build/build/tools/ptgen/MT6739/ptgen.pl:260: if ($ArgList{MTK_AB_OTA_UPDATER} eq "yes")
mediatek/build/build/tools/ptgen/MT6739/ptgen.pl:271: if ($ArgList{MTK_AB_OTA_UPDATER} eq "yes")
mediatek/build/build/tools/ptgen/MT6739/ptgen.pl:768: if ($ArgList{MTK_AB_OTA_UPDATER} eq "yes")
mediatek/build/build/tools/partition/gen-partition.py:123: if os.getenv("MTK_AB_OTA_UPDATER") == "yes":
1、mediatek/common/device.mk
# A/B System updates
ifeq ($(strip $(MTK_AB_OTA_UPDATER)), yes)
# Squashfs config system文件格式使用squashfs,这是与ext4不同的格式,目前没用到
#BOARD_SYSTEMIMAGE_FILE_SYSTEM_TYPE := squashfs
#PRODUCT_PACKAGES += mksquashfs
#PRODUCT_PACKAGES += mksquashfsimage.sh
#PRODUCT_PACKAGES += libsquashfs_utils
#将recovery ramdisk放到boot.img文件内
BOARD_USES_RECOVERY_AS_BOOT := true
#不再编译recovery.img
TARGET_NO_RECOVERY := true
#打开AB_OTA_UPDATER宏,这个本身是google原生的打开AB的主控开
AB_OTA_UPDATER := true
# A/B OTA partitions AB升级中可升级的分区
AB_OTA_PARTITIONS := \
boot \
system \
lk \
preloader
#编译update_engine update_verifier brillo_update_payload模块
PRODUCT_PACKAGES += \
update_engine \
shflags \
delta_generator \
bsdiff \
brillo_update_payload \
update_engine_sideload \
update_verifier \
#这两个时debug的调试工具update_engine_client 可以在adblog中输出升级流程
#bootctl是boot_control模块调用的工具,可以通过命令调用接口
PRODUCT_PACKAGES_DEBUG += \
update_engine_client \
bootctl
# bootctrl HAL and HIDL 编译启动相关的bootctrl hal层
PRODUCT_PACKAGES += \
bootctrl.$(MTK_PLATFORM_DIR) \
android.hardware.boot@1.0-impl \
android.hardware.boot@1.0-service
PRODUCT_STATIC_BOOT_CONTROL_HAL := bootctrl.$(MTK_PLATFORM_DIR)
# A/B OTA dexopt package
PRODUCT_PACKAGES += otapreopt_script
# Install odex files into the other system image
#编译了system_other 并将odex文件放入
BOARD_USES_SYSTEM_OTHER_ODEX := true
# A/B OTA dexopt update_engine hookup
AB_OTA_POSTINSTALL_CONFIG += \
RUN_POSTINSTALL_system=true \
POSTINSTALL_PATH_system=system/bin/otapreopt_script \
FILESYSTEM_TYPE_system=ext4 \
POSTINSTALL_OPTIONAL_system=true
# Tell the system to enable copying odexes from other partition.
PRODUCT_PACKAGES += \
cppreopts.sh
PRODUCT_PROPERTY_OVERRIDES += \
ro.cp_system_other_odex=1
DEVICE_MANIFEST_FILE += device/mediatek/common/project_manifest/manifest_boot.xml
endif
#下面一个单独的判断,定义是否将rootfs放入system,
ifneq ($(strip $(SYSTEM_AS_ROOT)), no)
BOARD_BUILD_SYSTEM_ROOT_IMAGE := true
endif
2、mediatek/common/BoardConfig.mk
这部分的修改与odex化的编译有关,以下时相关的资料
开odex优化首次开机速度,是牺牲空间换取时间的做法,仅限于空间足够的设备。开了odex之后,在编译的时候,整个system image就会被预先优化。由于在启动时不再需要进行app的dex文件进行优化(dex2oat操作)从而提升其启动速度。
关于odex,有几个下面几个宏开关:
1、WITH_DEXPREOPT
这个开关在6.0 USER版本上是默认开启的,意思就是USER版本要开odex预编译。会导致system image中的所有东西都被提前优化(pre-optimized)。这可能导致system image非常大。
那么问题就来了,既然 WITH_DEXPREOPT := true 默认开启,那么为什么首次启动依然耗时很长呢?这个就和第二个宏开关——DONT_DEXPREOPT_PREBUILTS有关了。
2、DONT_DEXPREOPT_PREBUILTS
如果我们不想把prebuilts目录中的第三方应用进行预先优化(这些应用在他们的Android.mk文件中有include$(BUILD_PREBUILT) ),而是希望这些app通过playstore 或者app提供商进行升级,那么我们可以打开这个宏开关。
事实上,6.0上面,这个宏开关也是默认开启的。我们全局搜索一下“(BUILD_PREBUILT) ”会发现很多结果,这也就是为什么默认odex都开了,为什么开机并没有觉得快的原因了。
因此我们在做odex优化的时候,都会关闭DONT_DEXPREOPT_PREBUILTS,然后重新给我们预置的App添加 LOCAL_DEX_PREOPT :=false 让它们不进行预编译,这样也就能节省一些不必要的空间消耗。同时因为关闭了DONT_DEXPREOPT_PREBUILTS,很多可以随ROM升级的系统App也就进行了预编译,因此开机速度就有了明显的提高。
开AB后DONT_DEXPREOPT_PREBUILTS :=false 看到这里其实看不出什么,后面分析Makefile可以看出具体生成,不过暂时根据out下生成的system 和 system_other system下面是单独的APK 而system_other是单独的odex和vdex,
ifeq ($(BUILD_GMS),yes)
ifeq ($(strip $(MTK_AB_OTA_UPDATER)), yes)
DONT_DEXPREOPT_PREBUILTS := false
else
DONT_DEXPREOPT_PREBUILTS := true
endif
else
ifeq ($(TARGET_BUILD_VARIANT),userdebug)
DEX_PREOPT_DEFAULT := nostripping
endif
endif
3、mediatek/mt6739/BoardConfig.mk
以下是谷歌原生文档关于该宏的介绍,如果打开AB升级,将会关闭该宏
在非 A/B 设备的恢复映像中添加 DTBO
为防止非 A/B 设备上出现 OTA 失败的情况,恢复分区必须“自给自足”,不得依赖于其他分区。
启动到恢复模式时,引导加载程序必须加载与恢复映像兼容的 DTBO 映像。在执行 OTA 期间,如果在 DTBO 映像更新后(但在完成全部更新之前)出现问题,设备将尝试启动到恢复模式,以完成 OTA。不过,由于 DTBO 分区已更新,恢复映像(尚未更新)可能会出现不匹配的情况。
为防止出现这种情况,在 Android 9 中,恢复映像也必须包含来自 DTBO 映像的信息。非 A/B 设备的恢复映像还必须包含附加到内核的设备 DTB,以便在更新期间不依赖于 DTB 分区。
实现
虽然搭载 Android 9 的所有设备都必须使用新的启动映像标头(版本 1),但只有非 A/B 设备才必须填充恢复映像的 recovery_dtbo 部分。要在 BoardConfig.mk 设备的 recovery.img 中添加 recovery_dtbo,请执行以下操作:
- 将
BOARD_INCLUDE_RECOVERY_DTBO配置设置为true:
BOARD_INCLUDE_RECOVERY_DTBO := true
- 扩展
BOARD_MKBOOTIMG_ARGS变量以指定启动映像标头版本:
BOARD_MKBOOTIMG_ARGS := --ramdisk_offset $(BOARD_RAMDISK_OFFSET) --tags_offset $(BOARD_KERNEL_TAGS_OFFSET) --header_version $(BOARD_BOOTIMG_HEADER_VERSION)
- 确保将
BOARD_PREBUILT_DTBOIMAGE变量设置为 DTBO 映像的路径。Android 编译系统会使用该变量在创建恢复映像时设置 mkbootimg 工具的recovery_dtbo参数。 - 如果变量
BOARD_INCLUDE_RECOVERY_DTBO、BOARD_MKBOOTIMG_ARGS和BOARD_PREBUILT_DTBOIMAGE均正确设置,Android 编译系统会将变量BOARD_PREBUILT_DTBOIMAGE指定的 DTBO 添加到recovery.img中。
ifeq ($(strip $(MTK_DTBO_FEATURE)),yes) ifeq ($(strip $(MTK_DTBO_UPGRADE_FROM_ANDROID_O)), yes) BOARD_PREBUILT_DTBOIMAGE := $(MTK_PTGEN_PRODUCT_OUT)/obj/PACKAGING/dtboimage/odmdtbo.img else BOARD_PREBUILT_DTBOIMAGE := $(MTK_PTGEN_PRODUCT_OUT)/obj/PACKAGING/dtboimage/dtbo.img endif ifneq ($(strip $(MTK_AB_OTA_UPDATER)),yes) BOARD_INCLUDE_RECOVERY_DTBO := true endif endif
mediatek/build/build/tools/ptgen/MT6739/ptgen.mk
4、mediatek/build/build/tools/ptgen/MT6739/ptgen.pl
MTK分区表存放位置:device/mediatek/build/build/tools/ptgen/xxx/xxx.xls
ptgen.pl文件会把xls文件解析成xxxAndroid_scatter.txt放在out/target/product/xxx/中
mtk的flashtool工具会读取这个文件把相关的镜像烧写到rom中
这里是根据判断选择对应分区文件,如果开了MTK_AB_OTA_UPDATER,选择我们emmc_ab的分区表,否则选择emmc的
$Partition_layout_xls = "$ptgen_location/partition_table_$ArgList{PLATFORM}";
if ($ArgList{EMMC_SUPPORT} eq "yes")
{
if ($ArgList{MTK_AB_OTA_UPDATER} eq "yes")
{
$ArgList{SHEET_NAME} = "emmc_ab";
}
else
{
$ArgList{SHEET_NAME} = "emmc";
}
}
elsif ($ArgList{UFS_BOOTING} eq "yes")
{
if ($ArgList{MTK_AB_OTA_UPDATER} eq "yes")
{
$ArgList{SHEET_NAME} = "ufs_ab";
}
else
{
$ArgList{SHEET_NAME} = "ufs";
}
}
else
{
$ArgList{SHEET_NAME} = "nand";
}
}
二、images生成流程
device修改很多开关主要作用时更改image的生成,而这部分全部是在makefile中,这是我们主要分析的文件,继续开车
1、recovery.img
ifeq (,$(filter true, $(TARGET_NO_KERNEL) $(TARGET_NO_RECOVERY))) INSTALLED_RECOVERYIMAGE_TARGET := $(PRODUCT_OUT)/recovery.img else INSTALLED_RECOVERYIMAGE_TARGET := endif
device.mk中定义了TARGET_NO_RECOVERY := true 由于TARGET_NO_KERNEL :=false ,所以条件不成立,
INSTALLED_RECOVERYIMAGE_TARGET :=,也就是不再生成recovery.img
2、boot.img
INSTALLED_BOOTIMAGE_TARGET := $(PRODUCT_OUT)/boot.img
MTK_BOOTIMAGE_TARGET := $(PRODUCT_OUT)/boot.img
INSTALLED_BOOTIMAGE_TARGET := $(call intermediates-dir-for,PACKAGING,boot)/boot.img
#这里判断条件较多,不过android对那个if 对应那个endif 还进行了标注,方便我们查看代码
#TARGET_NO_KERNEL 如果是true 条件不成立,这里我加了打印,其实它的值是
fasle,进入if条件
ifneq ($(strip $(TARGET_NO_KERNEL)),true)
$(warning "TARGET_NO_KERNEL is not supported anymore")
# -----------------------------------------------------------------
# the boot image, which is a collection of other images.
INTERNAL_BOOTIMAGE_ARGS := \
$(addprefix --second ,$(INSTALLED_2NDBOOTLOADER_TARGET)) \
--kernel $(INSTALLED_KERNEL_TARGET)
ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
INTERNAL_BOOTIMAGE_ARGS += --ramdisk $(INSTALLED_RAMDISK_TARGET)
endif
INTERNAL_BOOTIMAGE_FILES := $(filter-out --%,$(INTERNAL_BOOTIMAGE_ARGS))
ifdef BOARD_KERNEL_BASE
INTERNAL_BOOTIMAGE_ARGS += --base $(BOARD_KERNEL_BASE)
endif
ifdef BOARD_KERNEL_PAGESIZE
INTERNAL_BOOTIMAGE_ARGS += --pagesize $(BOARD_KERNEL_PAGESIZE)
endif
ifeq ($(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),true)
ifeq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
VERITY_KEYID := veritykeyid=id:`openssl x509 -in $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VERITY_SIGNING_KEY).x509.pem -text \
| grep keyid | sed 's/://g' | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]' | sed 's/keyid//g'`
endif
endif
INTERNAL_KERNEL_CMDLINE := $(strip $(BOARD_KERNEL_CMDLINE) buildvariant=$(TARGET_BUILD_VARIANT) $(VERITY_KEYID))
ifdef INTERNAL_KERNEL_CMDLINE
INTERNAL_BOOTIMAGE_ARGS += --cmdline "$(INTERNAL_KERNEL_CMDLINE)"
endif
INTERNAL_MKBOOTIMG_VERSION_ARGS := \
--os_version $(PLATFORM_VERSION) \
--os_patch_level $(PLATFORM_SECURITY_PATCH)
# BOARD_USES_RECOVERY_AS_BOOT = true must have BOARD_BUILD_SYSTEM_ROOT_IMAGE = true.
#这里的意思是说BOARD_USES_RECOVERY_AS_BOOT和BOARD_BUILD_SYSTEM_ROOT_IMAGE必须同时定义
ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
$(error BOARD_BUILD_SYSTEM_ROOT_IMAGE must be enabled for BOARD_USES_RECOVERY_AS_BOOT.)
endif
endif
# We build recovery as boot image if BOARD_USES_RECOVERY_AS_BOOT is true.
#如果BOARD_USES_RECOVERY_AS_BOOT为true,不走下面所有的代码,所以开启这个宏后,普通生成boot.img
#的代码将全部失效
ifneq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
ifeq ($(TARGET_BOOTIMAGE_USE_EXT2),true)
$(error TARGET_BOOTIMAGE_USE_EXT2 is not supported anymore)
else ifeq (true,$(BOARD_AVB_ENABLE)) # TARGET_BOOTIMAGE_USE_EXT2 != true
$(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(AVBTOOL) $(INTERNAL_BOOTIMAGE_FILES) $(BOARD_AVB_BOOT_KEY_PATH)
$(call pretty,"Target boot image: $@")
$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@
$(hide) $(call assert-max-image-size,$@,$(call get-hash-image-max-size,$(BOARD_BOOTIMAGE_PARTITION_SIZE)))
$(hide) $(AVBTOOL) add_hash_footer \
--image $@ \
--partition_size $(BOARD_BOOTIMAGE_PARTITION_SIZE) \
--partition_name boot $(INTERNAL_AVB_BOOT_SIGNING_ARGS) \
$(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS)
.PHONY: bootimage-nodeps
bootimage-nodeps: $(MKBOOTIMG) $(AVBTOOL) $(BOARD_AVB_BOOT_KEY_PATH)
@echo "make $@: ignoring dependencies"
$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(INSTALLED_BOOTIMAGE_TARGET)
$(hide) $(call assert-max-image-size,$(INSTALLED_BOOTIMAGE_TARGET),$(call get-hash-image-max-size,$(BOARD_BOOTIMAGE_PARTITION_SIZE)))
$(hide) $(AVBTOOL) add_hash_footer \
--image $(INSTALLED_BOOTIMAGE_TARGET) \
--partition_size $(BOARD_BOOTIMAGE_PARTITION_SIZE) \
--partition_name boot $(INTERNAL_AVB_BOOT_SIGNING_ARGS) \
$(BOARD_AVB_BOOT_ADD_HASH_FOOTER_ARGS)
else ifeq (true,$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_BOOT_SIGNER)) # BOARD_AVB_ENABLE != true
$(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_FILES) $(BOOT_SIGNER)
$(call pretty,"Target boot image: $@")
$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@
$(BOOT_SIGNER) /boot $@ $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VERITY_SIGNING_KEY).pk8 $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VERITY_SIGNING_KEY).x509.pem $@
$(hide) $(call assert-max-image-size,$@,$(BOARD_BOOTIMAGE_PARTITION_SIZE))
.PHONY: bootimage-nodeps
bootimage-nodeps: $(MKBOOTIMG) $(BOOT_SIGNER)
@echo "make $@: ignoring dependencies"
$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(INSTALLED_BOOTIMAGE_TARGET)
$(BOOT_SIGNER) /boot $(INSTALLED_BOOTIMAGE_TARGET) $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VERITY_SIGNING_KEY).pk8 $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VERITY_SIGNING_KEY).x509.pem $(INSTALLED_BOOTIMAGE_TARGET)
$(hide) $(call assert-max-image-size,$(INSTALLED_BOOTIMAGE_TARGET),$(BOARD_BOOTIMAGE_PARTITION_SIZE))
else ifeq (true,$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VBOOT)) # PRODUCT_SUPPORTS_BOOT_SIGNER != true
$(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_FILES) $(VBOOT_SIGNER) $(FUTILITY)
$(call pretty,"Target boot image: $@")
$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@.unsigned
$(VBOOT_SIGNER) $(FUTILITY) $@.unsigned $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VBOOT_SIGNING_KEY).vbpubk $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VBOOT_SIGNING_KEY).vbprivk $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VBOOT_SIGNING_SUBKEY).vbprivk $@.keyblock $@
$(hide) $(call assert-max-image-size,$@,$(BOARD_BOOTIMAGE_PARTITION_SIZE))
.PHONY: bootimage-nodeps
bootimage-nodeps: $(MKBOOTIMG) $(VBOOT_SIGNER) $(FUTILITY)
@echo "make $@: ignoring dependencies"
$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(INSTALLED_BOOTIMAGE_TARGET).unsigned
$(VBOOT_SIGNER) $(FUTILITY) $(INSTALLED_BOOTIMAGE_TARGET).unsigned $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VBOOT_SIGNING_KEY).vbpubk $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VBOOT_SIGNING_KEY).vbprivk $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VBOOT_SIGNING_SUBKEY).vbprivk $(INSTALLED_BOOTIMAGE_TARGET).keyblock $(INSTALLED_BOOTIMAGE_TARGET)
$(hide) $(call assert-max-image-size,$(INSTALLED_BOOTIMAGE_TARGET),$(BOARD_BOOTIMAGE_PARTITION_SIZE))
else # PRODUCT_SUPPORTS_VBOOT != true
$(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_FILES)
$(call pretty,"Target boot image: $@")
$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $@
$(hide) $(call assert-max-image-size,$@,$(BOARD_BOOTIMAGE_PARTITION_SIZE))
.PHONY: bootimage-nodeps
bootimage-nodeps: $(MKBOOTIMG)
@echo "make $@: ignoring dependencies"
$(hide) $(MKBOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) $(INTERNAL_MKBOOTIMG_VERSION_ARGS) $(BOARD_MKBOOTIMG_ARGS) --output $(INSTALLED_BOOTIMAGE_TARGET)
$(hide) $(call assert-max-image-size,$(INSTALLED_BOOTIMAGE_TARGET),$(BOARD_BOOTIMAGE_PARTITION_SIZE))
#这里是对每个判断条件的结尾进行了注释
endif # TARGET_BOOTIMAGE_USE_EXT2
endif # BOARD_USES_RECOVERY_AS_BOOT
else # TARGET_NO_KERNEL
根据代码的判断,因为BOARD_USES_RECOVERY_AS_BOOT 为true 所以不走普通的生成方式,那么真正生成boot.img是在哪里呢,字面翻译这个宏的意思时说我们要用recovery作为现在的boot,代码如下
#条件成立,进入ifeq
ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
#添加依赖BOOT_SIGNER
ifeq (true,$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_BOOT_SIGNER))
$(INSTALLED_BOOTIMAGE_TARGET) : $(BOOT_SIGNER)
endif
#添加依赖VBOOT_SIGNER
ifeq (true,$(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VBOOT))
$(INSTALLED_BOOTIMAGE_TARGET) : $(VBOOT_SIGNER)
endif
#添加依赖AVBTOOL BOARD_AVB_BOOT_KEY_PATH
ifeq (true,$(BOARD_AVB_ENABLE))
$(INSTALLED_BOOTIMAGE_TARGET) : $(AVBTOOL) $(BOARD_AVB_BOOT_KEY_PATH)
endif
#具体生成boot的部分,添加依赖,并调用build-recoveryimage-target 生成boot.img
$(INSTALLED_BOOTIMAGE_TARGET): $(MKBOOTFS) $(MKBOOTIMG) $(MINIGZIP) $(ADBD) \
$(INSTALLED_RAMDISK_TARGET) \
$(INTERNAL_RECOVERYIMAGE_FILES) \
$(recovery_initrc) $(recovery_sepolicy) $(recovery_kernel) \
$(INSTALLED_2NDBOOTLOADER_TARGET) \
$(recovery_build_props) $(recovery_resource_deps) \
$(recovery_fstab) \
$(RECOVERY_INSTALL_OTA_KEYS) \
$(INSTALLED_VENDOR_DEFAULT_PROP_TARGET) \
$(BOARD_RECOVERY_KERNEL_MODULES) \
$(DEPMOD)
$(call pretty,"Target boot image from recovery: $@")
$(call build-recoveryimage-target, $@)
endif
#以下是生成recovery.img的代码,其实跟上面是一模一样的
$(INSTALLED_RECOVERYIMAGE_TARGET): $(MKBOOTFS) $(MKBOOTIMG) $(MINIGZIP) $(ADBD) \
$(INSTALLED_RAMDISK_TARGET) \
$(INSTALLED_BOOTIMAGE_TARGET) \
$(INTERNAL_RECOVERYIMAGE_FILES) \
$(recovery_initrc) $(recovery_sepolicy) $(recovery_kernel) \
$(INSTALLED_2NDBOOTLOADER_TARGET) \
$(recovery_build_props) $(recovery_resource_deps) \
$(recovery_fstab) \
$(RECOVERY_INSTALL_OTA_KEYS) \
$(INSTALLED_VENDOR_DEFAULT_PROP_TARGET) \
$(BOARD_RECOVERY_KERNEL_MODULES) \
$(DEPMOD)
$(call build-recoveryimage-target, $@)
device.mk中定义了BOARD_USES_RECOVERY_AS_BOOT :=true,所以不再走原来生成boot.img的流程,使用生成recovery.img的方法打包成boot.img
3、cache.img
# -----------------------------------------------------------------
# cache partition image
#因为我们更改了BoardConfig.mk,所以BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE没有定义,不再生成cache.img
ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
INTERNAL_CACHEIMAGE_FILES := \
$(filter $(TARGET_OUT_CACHE)/%,$(ALL_DEFAULT_INSTALLED_MODULES))
cacheimage_intermediates := \
$(call intermediates-dir-for,PACKAGING,cache)
BUILT_CACHEIMAGE_TARGET := $(PRODUCT_OUT)/cache.img
define build-cacheimage-target
$(call pretty,"Target cache fs image: $(INSTALLED_CACHEIMAGE_TARGET)")
@mkdir -p $(TARGET_OUT_CACHE)
@mkdir -p $(cacheimage_intermediates) && rm -rf $(cacheimage_intermediates)/cache_image_info.txt
$(call generate-userimage-prop-dictionary, $(cacheimage_intermediates)/cache_image_info.txt, skip_fsck=true)
$(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH \
build/make/tools/releasetools/build_image.py \
$(TARGET_OUT_CACHE) $(cacheimage_intermediates)/cache_image_info.txt $(INSTALLED_CACHEIMAGE_TARGET) $(TARGET_OUT)
$(hide) $(call assert-max-image-size,$(INSTALLED_CACHEIMAGE_TARGET),$(BOARD_CACHEIMAGE_PARTITION_SIZE))
endef
# We just build this directly to the install location.
INSTALLED_CACHEIMAGE_TARGET := $(BUILT_CACHEIMAGE_TARGET)
$(INSTALLED_CACHEIMAGE_TARGET): $(INTERNAL_USERIMAGES_DEPS) $(INTERNAL_CACHEIMAGE_FILES) $(BUILD_IMAGE_SRCS)
$(build-cacheimage-target)
.PHONY: cacheimage-nodeps
cacheimage-nodeps: | $(INTERNAL_USERIMAGES_DEPS)
$(build-cacheimage-target)
else # BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
# we need to ignore the broken cache link when doing the rsync
#我们需要在执行rsync时忽略已损坏的缓存链接
IGNORE_CACHE_LINK := --exclude=cache
endif # BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
BoardConfig.mk中更改了代码
ifneq ($(strip $(MTK_AB_OTA_UPDATER)), yes)
BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE := ext4
endif
BOARD_FLASH_BLOCK_SIZE := 4096
所以生成cache.img的方法将不再执行,并忽略与cache相关的损坏的链接
4、system.img
# $(1): output file
define build-systemimage-target
@echo "Target system fs image: $(1)"
#调用$(call create-system-vendor-symlink)创建符号链接
$(call create-system-vendor-symlink)
#调用$(call create-system-product-symlink)创建符号链接
$(call create-system-product-symlink)
#删除之前的system_image_info.txt
@mkdir -p $(dir $(1)) $(systemimage_intermediates) && rm -rf $(systemimage_intermediates)/system_image_info.txt
#调用call generate-userimage-prop-dictionary,重新生成system_image_info.txt
$(call generate-userimage-prop-dictionary, $(systemimage_intermediates)/system_image_info.txt, \
skip_fsck=true)
#调用build_image.py 传入system_image_info.txt和$(PRODUCT_OUT)/system创建system.img文件
$(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH \
build/make/tools/releasetools/build_image.py \
$(TARGET_OUT) $(systemimage_intermediates)/system_image_info.txt $(1) $(TARGET_OUT) \
|| ( echo "Out of space? the tree size of $(TARGET_OUT) is (MB): " 1>&2 ;\
du -sm $(TARGET_OUT) 1>&2;\
if [ "$(INTERNAL_USERIMAGES_EXT_VARIANT)" == "ext4" ]; then \
maxsize=$(BOARD_SYSTEMIMAGE_PARTITION_SIZE); \
echo "The max is $$(( maxsize / 1048576 )) MB." 1>&2 ;\
else \
echo "The max is $$(( $(BOARD_SYSTEMIMAGE_PARTITION_SIZE) / 1048576 )) MB." 1>&2 ;\
fi; \
mkdir -p $(DIST_DIR); cp $(INSTALLED_FILES_FILE) $(DIST_DIR)/installed-files-rescued.txt; \
exit 1 )
endef
$(BUILT_SYSTEMIMAGE): $(FULL_SYSTEMIMAGE_DEPS) $(INSTALLED_FILES_FILE) $(BUILD_IMAGE_SRCS)
$(call build-systemimage-target,$@)
INSTALLED_SYSTEMIMAGE := $(PRODUCT_OUT)/system.img
SYSTEMIMAGE_SOURCE_DIR := $(TARGET_OUT)
这部分在之前分析make 生成 system.img时候提到过,传入的info文件将决定system.img中打包的内容
# $(1): the path of the output dictionary file
# $(2): additional "key=value" pairs to append to the dictionary file.
#调用该方法生成system_image_info.txt,其中BOARD_BUILD_SYSTEM_ROOT_IMAGE 宏是打开的会将如下两个值
#写入到info文件中
define generate-userimage-prop-dictionary
$(if $(filter true,$(BOARD_BUILD_SYSTEM_ROOT_IMAGE)),\
$(hide) echo "system_root_image=true" >> $(1);\
echo "ramdisk_dir=$(TARGET_ROOT_OUT)" >> $(1))
$(if $(2),$(hide) $(foreach kv,$(2),echo "$(kv)" >> $(1);))
endef
ext_mkuserimg=mkuserimg_mke2fs.sh fs_type=ext4 system_size=2684354560 userdata_size=3221225472 vendor_fs_type=ext4 vendor_size=578813952 extfs_sparse_flag=-s squashfs_sparse_flag=-s selinux_fc=out/target/product/k39tv1_64_bsp/obj/ETC/file_contexts.bin_intermediates/file_contexts.bin boot_signer=true verity=true verity_key=build/target/product/security/verity verity_signer_cmd=verity_signer verity_fec=true system_verity_block_device=/dev/block/platform/bootdevice/by-name/system vendor_verity_block_device=/dev/block/platform/bootdevice/by-name/vendor recovery_as_boot=true system_root_image=true ramdisk_dir=out/target/product/k39tv1_64_bsp/root skip_fsck=true
这两个参数的加入
system_root_image=true
ramdisk_dir=out/target/product/k39tv1_64_bsp/root
决定了真正最后生成的system.img文件会将ramdisk和filesystem一并打包,也就是说目前的system.img包含了rootfs(查看9.0的代码可以发现,即使是非ab,也有这两个参数从存在了)
5、system_other.img
# -----------------------------------------------------------------
# system_other partition image
#该BOARD_USES_SYSTEM_OTHER_ODEX打开后 会设定BOARD_USES_SYSTEM_OTHER
ifeq ($(BOARD_USES_SYSTEM_OTHER_ODEX),true)
BOARD_USES_SYSTEM_OTHER := true
# Marker file to identify that odex files are installed
INSTALLED_SYSTEM_OTHER_ODEX_MARKER := $(TARGET_OUT_SYSTEM_OTHER)/system-other-odex-marker
ALL_DEFAULT_INSTALLED_MODULES += $(INSTALLED_SYSTEM_OTHER_ODEX_MARKER)
$(INSTALLED_SYSTEM_OTHER_ODEX_MARKER):
$(hide) touch $@
endif
#BOARD_USES_SYSTEM_OTHER该宏为true,进入if生成system_other.img
ifdef BOARD_USES_SYSTEM_OTHER
INTERNAL_SYSTEMOTHERIMAGE_FILES := \
$(filter $(TARGET_OUT_SYSTEM_OTHER)/%,\
$(ALL_DEFAULT_INSTALLED_MODULES)\
$(ALL_PDK_FUSION_FILES)) \
$(PDK_FUSION_SYMLINK_STAMP)
INSTALLED_FILES_FILE_SYSTEMOTHER := $(PRODUCT_OUT)/installed-files-system-other.txt
$(INSTALLED_FILES_FILE_SYSTEMOTHER) : $(INTERNAL_SYSTEMOTHERIMAGE_FILES) $(FILESLIST)
@echo Installed file list: $@
@mkdir -p $(dir $@)
@rm -f $@
$(hide) $(FILESLIST) $(TARGET_OUT_SYSTEM_OTHER) > $(@:.txt=.json)
$(hide) build/make/tools/fileslist_util.py -c $(@:.txt=.json) > $@
systemotherimage_intermediates := \
$(call intermediates-dir-for,PACKAGING,system_other)
BUILT_SYSTEMOTHERIMAGE_TARGET := $(PRODUCT_OUT)/system_other.img
# Note that we assert the size is SYSTEMIMAGE_PARTITION_SIZE since this is the 'b' system image.
define build-systemotherimage-target
$(call pretty,"Target system_other fs image: $(INSTALLED_SYSTEMOTHERIMAGE_TARGET)")
@mkdir -p $(TARGET_OUT_SYSTEM_OTHER)
@mkdir -p $(systemotherimage_intermediates) && rm -rf $(systemotherimage_intermediates)/system_other_image_info.txt
$(call generate-userimage-prop-dictionary, $(systemotherimage_intermediates)/system_other_image_info.txt, skip_fsck=true)
$(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH \
build/make/tools/releasetools/build_image.py \
$(TARGET_OUT_SYSTEM_OTHER) $(systemotherimage_intermediates)/system_other_image_info.txt $(INSTALLED_SYSTEMOTHERIMAGE_TARGET) $(TARGET_OUT)
$(hide) $(call assert-max-image-size,$(INSTALLED_SYSTEMOTHERIMAGE_TARGET),$(BOARD_SYSTEMIMAGE_PARTITION_SIZE))
endef
# We just build this directly to the install location.
INSTALLED_SYSTEMOTHERIMAGE_TARGET := $(BUILT_SYSTEMOTHERIMAGE_TARGET)
ifneq (true,$(SANITIZE_LITE))
# Only create system_other when not building the second stage of a SANITIZE_LITE build.
$(INSTALLED_SYSTEMOTHERIMAGE_TARGET): $(INTERNAL_USERIMAGES_DEPS) $(INTERNAL_SYSTEMOTHERIMAGE_FILES) $(INSTALLED_FILES_FILE_SYSTEMOTHER)
$(build-systemotherimage-target)
endif
.PHONY: systemotherimage-nodeps
systemotherimage-nodeps: | $(INTERNAL_USERIMAGES_DEPS)
$(build-systemotherimage-target)
endif # BOARD_USES_SYSTEM_OTHER
device.mk打开ab后定义了生成system_other相关的宏# A/B BOARD_USES_SYSTEM_OTHER_ODEX := true,将system/app 和 system/priv-app下的odex文件存储到system_other.img中
这个img的生成有什么作用呢,查到这样一个说明
50% of system image is precompiled odex files (-2048MiB)
- Moved them to B partition
- Copied to /data on first boot
- See BOARD_USES_SYSTEM_OTHER_ODEX BoardConfig option
- Now A/B /system takes same space as non-A/B /system
意思是说将原来system里面的odex文件放到system_other.img中,刷机的时候放入B分区,并在首次开机的时候拷贝到data区进行预加载,这样ab升级中的system分区与非ab的情况一样,目的是为了减小system分区的大小,不过百分之50有些夸张了,我们编译出来的实际只有100多M,
开启AB升级方案的项目,因为很多需要升级的镜像都有两份,所以存储空间将会增大。为缓解此问题,有个针对odex的优化方案。
编译版本会生成两个system镜像:system.img和system_other.img,其中,system_other.img中存储的就是odex文件,这样system.img就能小很多,意味着可以为system分区划分较小的空间。
在首次开机时,假设system.img镜像存储在A slot,那么此时的B slot是闲置的。所以可以把system.img刷入A slot的system分区,把system_other.img刷入B slot的system分区。在首次开机时,再把system_other.img中的odex文件拷贝到data分区。
6、vendor.img 和 userdata.img
这两个img的生成在打开ab后没有变化,生成流程于system.img相同,根据对应info,调用build_image.py生成对应的文件
三、make 和make otapackage过程中的变化
1、build.prop中加入字段体现
make/tools/buildinfo.sh加入
if [ -n "$AB_OTA_UPDATER" ] ; then
echo "ro.build.ab_update=$AB_OTA_UPDATER"
fi
Makefile中会执行buildinfo.sh文件
$(intermediate_system_build_prop): $(BUILDINFO_SH) $(INTERNAL_BUILD_ID_MAKEFILE) $(BUILD_SYSTEM)/version_defaults.mk $(system_prop_file) $(INSTALLED_ANDROID_INFO_TXT_TARGET)
......
......
bash $(BUILDINFO_SH) >> $@
system/build.prop中增加:ro.build.ab_update=true
2、签名相关 Makefile
# Carry the public key for update_engine if it's a non-IoT target that # uses the AB updater. We use the same key as otacerts but in RSA public key # format. #如果update_engine是非IoT目标,则携带公钥 #使用AB更新程序。 我们使用与otacerts相同的密钥但使用RSA公钥format。 ifeq ($(AB_OTA_UPDATER),true) ifneq ($(PRODUCT_IOT),true) ALL_DEFAULT_INSTALLED_MODULES += $(TARGET_OUT_ETC)/update_engine/update-payload-key.pub.pem $(TARGET_OUT_ETC)/update_engine/update-payload-key.pub.pem: $(addsuffix .x509.pem,$(DEFAULT_KEY_CERT_PAIR)) $(hide) rm -f $@ $(hide) mkdir -p $(dir $@) $(hide) openssl x509 -pubkey -noout -in $< > $@ ALL_DEFAULT_INSTALLED_MODULES += $(TARGET_RECOVERY_ROOT_OUT)/etc/update_engine/update-payload-key.pub.pem $(TARGET_RECOVERY_ROOT_OUT)/etc/update_engine/update-payload-key.pub.pem: $(TARGET_OUT_ETC)/update_engine/update-payload-key.pub.pem $(hide) cp -f $< $@ endif endif
3、obj包的生成相关
#指定对应依赖 这个built_ota_tools其实生成的就是updater,如果是ab升级,obj包里不需要打包这个文件 ifeq ($(AB_OTA_UPDATER),true) updater_dep := system/update_engine/update_engine.conf else # Build OTA tools if not using the AB Updater. updater_dep := $(built_ota_tools) endif $(BUILT_TARGET_FILES_PACKAGE): $(updater_dep)
$(BUILT_TARGET_FILES_PACKAGE):
......
......
#如果是非AB,拷贝对应image和生成ota_update_list.txt,如果是ab,生成ab_partitions.txt,拷贝对应image
@# Copy raw images which need OTA updates from out folder to zip_root/IMAGES folder
$(hide) BOARD_AVB_ENABLE="$(BOARD_AVB_ENABLE)" AB_OTA_UPDATER="$(AB_OTA_UPDATER)" AB_OTA_PARTITIONS="$(AB_OTA_PARTITIONS)" $(TARGET_RELEASETOOLS_EXTENSIONS)/mt_ota_preprocess.py $(zip_root) $(PRODUCT_OUT) $(PRODUCT_OUT)/ota_update_list.txt
ifneq ($(INSTALLED_RECOVERYIMAGE_TARGET),)
$(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH MKBOOTIMG=$(MKBOOTIMG) \
build/make/tools/releasetools/make_recovery_patch $(zip_root) $(zip_root)
endif
ifeq ($(AB_OTA_UPDATER),true)
@# When using the A/B updater, include the updater config files in the zip.
#拷贝update_engine.conf 到META/update_engine_config.txt
$(hide) cp $(TOPDIR)system/update_engine/update_engine.conf $(zip_root)/META/update_engine_config.txt
$(hide) for part in $(AB_OTA_PARTITIONS); do \
#把AB_OTA_PARTITIONS定义的分区拷贝到META/ab_partitions.txt
echo "$${part}" >> $(zip_root)/META/ab_partitions.txt; \
done
$(hide) for conf in $(AB_OTA_POSTINSTALL_CONFIG); do \
#把AB_OTA_POSTINSTALL_CONFIG定义的内容拷贝到META/postinstall_config.txt
echo "$${conf}" >> $(zip_root)/META/postinstall_config.txt; \
done
@# Include the build type in META/misc_info.txt so the server can easily differentiate production builds.
#build_type放入misc_info
$(hide) echo "build_type=$(TARGET_BUILD_VARIANT)" >> $(zip_root)/META/misc_info.txt
#ab_update放入misc_info
$(hide) echo "ab_update=true" >> $(zip_root)/META/misc_info.txt
ifdef BRILLO_VENDOR_PARTITIONS
$(hide) mkdir -p $(zip_root)/VENDOR_IMAGES
$(hide) for f in $(BRILLO_VENDOR_PARTITIONS); do \
pair1="$$(echo $$f | awk -F':' '{print $$1}')"; \
pair2="$$(echo $$f | awk -F':' '{print $$2}')"; \
src=$${pair1}/$${pair2}; \
dest=$(zip_root)/VENDOR_IMAGES/$${pair2}; \
mkdir -p $$(dirname "$${dest}"); \
cp $${src} $${dest}; \
done;
endif
......
......
4、整包生成相关
AB情况下添加依赖,可执行文件brillo_update_payload,非AB情况下添加依赖brotli
ifeq ($(AB_OTA_UPDATER),true) $(INTERNAL_OTA_PACKAGE_TARGET): $(BRILLO_UPDATE_PAYLOAD) else $(INTERNAL_OTA_PACKAGE_TARGET): $(BROTLI) endif
关于device和build大致整理了这么多内容,因为我也是刚开始看,可能没有整理全,后面再继续填坑。
本文详细解析了A/B升级方案中系统Image的生成流程,包括开启宏开关后的make和makeotapackage过程,重点介绍了device和build下的关键修改,如AB升级宏控、系统分区调整及odex优化策略。
4154

被折叠的 条评论
为什么被折叠?



