一、A/B升级之系统image的生成

Android A/B System OTA分析(二)系统image的生成 Android从7.0开始引入新的OTA升级方式,A/B System Updates,这里将其叫做A/B系统,涉及的内容较多,分多篇对A/B系统的各个方面进行分析。本文为第二篇,系统image的生成。image这个词的含义很多,这里指编译后可以烧写到设备的文件,如boot.img,system.img等,统称为镜像文件吧。本文基于AOSP 7.1.1_r23 (NMF27D)代码进行分析。传统OTA方式下:1. boot.img内有一个boot ramdisk,用于系统启动时加载system.img; 2 阅读详情

一、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大致整理了这么多内容,因为我也是刚开始看,可能没有整理全,后面再继续填坑。

修改MTK平台Android P系统支持系统A/B分区升级 文章目录MTK平台Android_P系统A/B升级至生成系统image一、device目录下的修改二、kernel 目录下的修改三、lk目录下的修改四、preloader目录下的修改五、修改img分区大小六、Android A/B System OTA分析 MTK平台Android_P系统A/B升级至生成系统image Platform: MT6739 OS: Android 9.0 MTK 平台... 阅读详情

相关推荐

A/B system OTA

与传统OTA方式相比,A/B系统的变化主要有: 系统的分区设置 传统方式只有一套分区 A/B系统有两套分区,称为slot A和slot B 跟bootloader沟通的方式 传统方式bootloader通过读取misc分区信息来决定是进入Android主系统还是Recovery系统 A/B系统的bootloader通过特定的分区信息来决定从slot A还是slot B启动 系统的编译过程 传统方...

weixin_44991625的博客 972

Android 系统编译移除应用

Android 系统编译移除应用 在系统编译的时候会编译很多应用module,内置的带源码应用,apk应用,系统debug应用等 默认源码编译出来有很多并不需要的应用,这些应用绝大部分都是通过 PRODUCT_PACKAGES += xxx PRODUCT_PACKAGES_DEBUG += xxx PRODUCT_PACKAGES_TESTS += xxx 加入编译的,而且这些PRODUCT_PACKAGES 又分散到很多的mk文件里添加 比如某个系统应用(Testxx)的编译加载,一般在某个mk文件会有

yxdspirit的专栏 4082

Android A/B System OTA分析(四)系统的启动和升级

AB OTA

qq_42135379的博客 2157

Android A/B System OTA分析(一)概览

Android从7.0开始引入新的OTA升级方式,A/B System Updates,这里将其叫做A/B系统。`A/B`系统涉及的内容较多,分多篇对`A/B`系统的各个方面进行分析。本文为第一篇,概览。

洛奇看世界 6万+

Android 系统OTA升级

一、升级包制作 1.1、编译一个完整刷机包 1.2、制作OTA包 在android目录下执行 make otapackage –j8 编译OTA包。以450平台为例,编译后会在 out\target\product\ msm8953_64\ 目录下生成一个升级整包 msm8953_64-ota-*.zip out\target\product\msm8953_64\obj\PACKAGING\target_files_intermediates目录下生成一个基础包 整包,是可以直接用于OT.

tq501501的博客 1万+

AB 系统OTA升级

A/B System 概述 Android从7.0开始,引入了新的OTA升级方式 A/B System Updates A/B系统是指设备上有A和B两套可以工作的系统(用户数据只有一份,为两套系统共用),我们可以理解为一套系统分区,另外一套为备份分区.其系统版本可能一样,也可能不一样;通过升级,可以将旧版本也更新为新版本.当然,设备出厂时这两套系统肯定是一样的. Android 7.0上传统OTA方式和新的A/B系统方式都存在,编译时只能选择其中的一种OTA方式.由于A/B系统在分区上与传统OTA的

weixin_46610861的博客 1951

Android11.0 V-A/B无缝OTA升级update_engine

前言 V-AB 升级方案其实早在 7.0 就已经引入了,只是并未强制启用,依旧兼容了之前 /cache 分区升级的方式。 Android recovery更新简单流程及注意点 所以一开始按照老思路来,解决完各种权限后最终发现 log 提示找不到 /cache 分区。后来查阅资料发现, 相较于 Android 10.0,Android 11.0 的 Recovery 分区与 cache 分区已删除。 AB 方案介绍 AB 方案就是双分区双系统,每个镜像都是双份,分别对应两个分区。 V-AB 方案介绍 V-AB

cczhengv 1万+

Android A/B System OTA分析(三)主系统和bootloader的通信

A/B系统中,指定了用于通信的HAL层boot_control功能的定义,但没有指定通信数据具体的存储实现,这点有别于传统方式下AOSP定义的存储于misc分区的bootloader_message结构。/***//**//* init 用于HAL初始化调用,仅启动时调用一次 *//**//* 返回系统slot分区套数,1套slot包含boot, system和vendor分区 *//**//* 返回系统当前所在的slot位置 *//**/

qq_42135379的博客 1741

Qwen-Image支持生成符合A/B测试需求的变体图

Qwen-Image基于MMDiT架构与200亿参数,支持精准图像生成与局部修改,大幅提升A/B测试素材生产效率。通过区域重绘、样式统一与自动化流水线集成,实现文案、配色等变量的秒级变体输出,确保实验一致性与投放质量。

weixin_36289742的博客 597

Android 系统升级:从Recovery到A/B,深入解析核心流程与演进

本文深入解析Android系统升级技术的演进历程,从传统的Recovery模式到现代的A/B分区方案,详细介绍了核心流程与技术突破。通过对比实验和实战指南,帮助开发者理解OTA升级机制,提升系统稳定性与用户体验。文章还探讨了未来Android系统升级的发展方向,包括流式更新和虚拟化技术。

weixin_33462167的博客 238

衡山派Luban-Lite系统A/B分区OTA升级机制深度解析与配置指南

本文深度解析了衡山派Luban-Lite系统A/B分区OTA升级机制,详细阐述了其双系统设计如何实现安全、可靠的远程固件升级,并有效规避设备变砖风险。文章提供了从分区表配置、环境变量设置到升级包制作与网络升级流程的完整配置指南,帮助开发者快速掌握这一嵌入式系统的核心升级技术。

weixin_35677363的博客 556

RK3588 AB镜像升级学习(一)

这里的步骤跟生成system.img基本一致,宏函数build-userdataimage-target内通过build_image.py来将$(PRODUCT_OUT)/data目录内容打包生成userdata.img,不同的是,这里不再需要放入ramdisk的内容。对比A/B系统下boot.img生成方式和非A/B系统下recovery.img的生成方式,基本上是一样的,所以A/B系统下的boot.img相当于非A/B系统下的recovery.img。

习惯就好zz的专栏 3636

自动换挡频率计的设计精髓:如何用数字电路优雅地解决量程切换难题

本文深入解析了自动换挡频率计的设计精髓,重点探讨如何利用数字电路优雅解决量程切换难题。通过74系列通用数字集成电路构建智能化的自动量程切换系统,详细介绍了状态检测、决策逻辑和档位执行等核心模块的设计方法,并对比了不同实现方案的优劣,为电子测量领域的工程师提供了实用的硬件设计参考。

weixin_27869497的博客 407

linux ab双分区升级,AB 系统OTA升级

A/B System 概述Android从7.0开始,引入了新的OTA升级方式 A/B System UpdatesA/B系统是指设备上有A和B两套可以工作的系统(用户数据只有一份,为两套系统共用),我们可以理解为一套系统分区,另外一套为备份分区.其系统版本可能一样,也可能不一样;通过升级,可以将旧版本也更新为新版本.当然,设备出厂时这两套系统肯定是一样的.Android 7.0上传统OTA方式和...

weixin_42131261的博客 8152

射频测试基础知识总结

表示可以辐射到空间的电磁频率,频率范围从300KHz~110GHz之间,射频简称RF,是高频交流变化电磁波的简称,其每秒变化小于1000次被称为低频电流,超过10000次的称为高频电流,而射频就是这种高频电流。为了确保天线接收的信号能够在接收机的最后一级被正确的恢复,一个好的低噪音放大器需要在放大信号的同时产生尽可能低的噪音以及失真。两种,带内试验的范围也有一定的差别,比如,带内试验主要是检测信号的质量,如功率、频谱宽度、调制质量,而带外测试的是信号的杂散、谐波,主要是看对频带之外的干扰有多大。

cny70的博客 9628

射频工程师笔记---射频通信基础

回顾一下移动通信技术的发展,其实是互联网和通信技术的融合过程。在这个过程中,很多应用都在不断加入其中。比如计算机跟通信的融合产生了互联网、互联网跟手机的融合带来了移动互联网。手机可以看杂志、看视频、听音乐,于是又出现了内容服务产业;再后来,电视音箱等设备也能联网,于是网络跟家电又产生了融合。所以应用的出现总是在融合其他产业。在1995年,比尔·盖茨在《未来之路》一书中首次提出:在未来...

多年硬件从业经历,热爱学习,记录生活! 2万+
上一篇: 二、A/B 升级update_engine分析-整体模块
下一篇: 三、A/B 升级update_engine分析-客户端
李标标
博客等级 码龄11年 124粉丝 43原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值