Android OTA升级,顾名思义是指over-the-air升级方式。通过在线下载安装包的形式,对整个系统进行升级。
在说FOTA之前,先看看Android的系统分区。具体参考官方网页
Android分区
- boot 包括Linux系统内核和最小的系统文件。它负责安装系统和其他分区。
- recovery 用于系统升级的分区,里面有一个单独的Linux系统。它通过读取一个新的软件包,来逐步更新其他分区,最终达到系统更新的目的。
- system 包含在Android开源项目(AOSP)上提供源代码的系统应用程序和库。 在正常操作中,此分区挂载为只读; 其内容仅在OTA更新期间更改。
- userdata 存储由用户安装的应用程序保存的数据等。OTA更新过程通常不会触及该分区
- cache 应用使用的临时储存区域,访问该区域需要特殊权限。同时要用于储存下载的FOTA包。其他程序使用这个空间,期望文件可以随时消失。某些OTA软件包安装可能会导致此分区被完全擦除。
FOTA升级流程
- 手机会定期检测是否有更新(也可手动检测),并通知用户有新版本可用。
- 将安装包下载到cache分区,若cache分区不够,下载到data分区(这时候要注意是否有写入和删除权限),并根据
system/etc/security/otacerts.zip
的证书验证其加密签名。系统提示用户安装更新。 - 系统重启到recovery模式,运行的是recovery分区中的系统内核。而不是boot中的系统。
- init进程通过执行init.rc 脚本:service recovery /sbin/recovery 启动recovery程序
- recovery首先校验下载的安装包是否与res/keys(ramdisk)中的公匙相匹配。
- recovery根据脚本解析安装包,然后将修改分别更新到对应的分区中,在system 分区中包含了用于更新recovery分区的内容。
- 系统正常启动:启动更新后的boot,system分区。启动时检测是否对recovery分区有更新,若有差异,则更新到recovery分区(这里也是为什么修改了recovery的代码后,需要更新完,且在下个更新中才能得到验证)
- 设备通知服务器更新完成。
OTA包制作
在 build/tools/releasetools
中,ota_from_target_files
脚本制作OTA安装包。它既可以制作全包,也可制作差分包。所谓完整版安装包,就是包中已经包含了当前要更新到的系统所有文件,只要设备下载了安装包,并启动recovery模式,该包就可以完成更新,而不管系统当前的状态是什么样的。
要制作OTA包,需要先编译target包。编译target包的指令如下:
. build/envsetup.sh && lunch full_E266L-user //编译E266L
make -j4 otapackage //编译target包,并将包放入新建的dist_output中
这其中,make otapackage 分为两个部分,一个是编译target包,一部分是编译FULL_OTA包。编译target包,是在build/core/Makefile中执行的。具体代码如下:
# -----------------------------------------------------------------
# A zip of the directories that map to the target filesystem.
# This zip can be used to create an OTA package or filesystem image
# as a post-build step.
#
name := $(TARGET_PRODUCT)
ifeq ($(TARGET_BUILD_TYPE),debug)
name := $(name)_debug
endif
name := $(name)-target_files-$(FILE_NAME_TAG)
intermediates := $(call intermediates-dir-for,PACKAGING,target_files)
BUILT_TARGET_FILES_PACKAGE := $(intermediates)/$(name).zip
$(BUILT_TARGET_FILES_PACKAGE): intermediates := $(intermediates)
$(BUILT_TARGET_FILES_PACKAGE): \
zip_root := $(intermediates)/$(name)
# $(1): Directory to copy
# $(2): Location to copy it to
# The "ls -A" is to prevent "acp s/* d" from failing if s is empty.
define package_files-copy-root
if [ -d "$(strip $(1))" -a "$$(ls -A $(1))" ]; then \
mkdir -p $(2) && \
$(ACP) -rd $(strip $(1))/* $(2); \
fi
endef
built_ota_tools :=
# We can't build static executables when SANITIZE_TARGET=address
ifeq ($(strip $(SANITIZE_TARGET)),)
built_ota_tools += \
$(call intermediates-dir-for,EXECUTABLES,updater,,,$(TARGET_PREFER_32_BIT))/updater
endif
$(BUILT_TARGET_FILES_PACKAGE): PRIVATE_OTA_TOOLS := $(built_ota_tools)
$(BUILT_TARGET_FILES_PACKAGE): PRIVATE_RECOVERY_API_VERSION := $(RECOVERY_API_VERSION)
$(BUILT_TARGET_FILES_PACKAGE): PRIVATE_RECOVERY_FSTAB_VERSION := $(RECOVERY_FSTAB_VERSION)
ifeq ($(TARGET_RELEASETOOLS_EXTENSIONS),)
# default to common dir for device vendor
$(BUILT_TARGET_FILES_PACKAGE): tool_extensions := $(TARGET_DEVICE_DIR)/../common
else
$(BUILT_TARGET_FILES_PACKAGE): tool_extensions := $(TARGET_RELEASETOOLS_EXTENSIONS)
endif
# Build OTA tools if not using the AB Updater.
ifneq ($(AB_OTA_UPDATER),true)
$(BUILT_TARGET_FILES_PACKAGE): $(built_ota_tools)
endif
# If we are using recovery as boot, output recovery files to BOOT/.
ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
$(BUILT_TARGET_FILES_PACKAGE): PRIVATE_RECOVERY_OUT := BOOT
else
$(BUILT_TARGET_FILES_PACKAGE): PRIVATE_RECOVERY_OUT := RECOVERY
endif
# Depending on the various images guarantees that the underlying
# directories are up-to-date.
$(BUILT_TARGET_FILES_PACKAGE): \
$(INSTALLED_BOOTIMAGE_TARGET) \
$(INSTALLED_RADIOIMAGE_TARGET) \
$(INSTALLED_RECOVERYIMAGE_TARGET) \
$(INSTALLED_SYSTEMIMAGE) \
$(INSTALLED_USERDATAIMAGE_TARGET) \
$(INSTALLED_CACHEIMAGE_TARGET) \
$(INSTALLED_VENDORIMAGE_TARGET) \
$(INSTALLED_ANDROID_INFO_TXT_TARGET) \
$(SELINUX_FC) \
$(APKCERTS_FILE) \
$(HOST_OUT_EXECUTABLES)/fs_config \
| $(ACP)
ifeq ($(TARGET_USERIMAGES_USE_EXT4),true)
$(BUILT_TARGET_FILES_PACKAGE): $(INSTALLED_CACHEIMAGE_TARGET)
endif
@echo "Package target files: $@"
$(hide) rm -rf $@ $(zip_root)
$(hide) mkdir -p $(dir $@) $(zip_root)
ifneq (,$(INSTALLED_RECOVERYIMAGE_TARGET)$(filter true,$(BOARD_USES_RECOVERY_AS_BOOT)))
@# Components of the recovery image
$(hide) mkdir -p $(zip_root)/$(PRIVATE_RECOVERY_OUT)
$(hide) $(call package_files-copy-root, \
$(TARGET_RECOVERY_ROOT_OUT),$(zip_root)/$(PRIVATE_RECOVERY_OUT)/RAMDISK)
ifdef INSTALLED_KERNEL_TARGET
$(hide) $(ACP) $(INSTALLED_KERNEL_TARGET) $(zip_root)/$(PRIVATE_RECOVERY_OUT)/kernel
$(hide) $(ACP) $(recovery_ramdisk) $(zip_root)/RECOVERY/ramdisk
ifeq ($(MTK_HEADER_SUPPORT),yes)
$(hide) $(ACP) $(recovery_ramdisk_bthdr) $(zip_root)/RECOVERY/ramdisk-bthdr
endif
endif
ifdef INSTALLED_2NDBOOTLOADER_TARGET
$(hide) $(ACP) \
$(INSTALLED_2NDBOOTLOADER_TARGET) $(zip_root)/$(PRIVATE_RECOVERY_OUT)/second
endif
ifdef BOARD_KERNEL_CMDLINE
$(hide) echo "$(BOARD_KERNEL_CMDLINE)" > $(zip_root)/$(PRIVATE_RECOVERY_OUT)/cmdline
endif
ifdef BOARD_KERNEL_BASE
$(hide) echo "$(BOARD_KERNEL_BASE)" > $(zip_root)/$(PRIVATE_RECOVERY_OUT)/base
endif
ifdef BOARD_KERNEL_PAGESIZE
$(hide) echo "$(BOARD_KERNEL_PAGESIZE)" > $(zip_root)/$(PRIVATE_RECOVERY_OUT)/pagesize
endif
endif # INSTALLED_RECOVERYIMAGE_TARGET defined or BOARD_USES_RECOVERY_AS_BOOT is true
ifdef BOARD_RAMDISK_OFFSET
$(hide) echo "$(BOARD_RAMDISK_OFFSET)" > $(zip_root)/RECOVERY/ramdisk_offset
endif
ifdef BOARD_KERNEL_OFFSET
$(hide) echo "$(BOARD_KERNEL_OFFSET)" > $(zip_root)/RECOVERY/kernel_offset
endif
ifdef BOARD_TAGS_OFFSET
$(hide) echo "$(BOARD_TAGS_OFFSET)" > $(zip_root)/RECOVERY/tags_offset
endif
ifdef CUSTOM_BUILD_VERNO
$(hide) echo -n $(CUSTOM_BUILD_VERNO_HDR) > $(zip_root)/RECOVERY/board
endif
@# Components of the boot image
$(hide) mkdir -p $(zip_root)/BOOT
ifeq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
$(hide) mkdir -p $(zip_root)/ROOT
$(hide) $(call package_files-copy-root, \
$(TARGET_ROOT_OUT),$(zip_root)/ROOT)
else
$(hide) $(call package_files-copy-root, \
$(TARGET_ROOT_OUT),$(zip_root)/BOOT/RAMDISK)
endif
@# If we are using recovery as boot, this is already done when processing recovery.
ifneq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
ifdef INSTALLED_KERNEL_TARGET
$(hide) $(ACP) $(INSTALLED_KERNEL_TARGET) $(zip_root)/BOOT/kernel
$(hide) $(ACP) $(INSTALLED_RAMDISK_TARGET) $(zip_root)/BOOT/ramdisk
endif
ifdef INSTALLED_2NDBOOTLOADER_TARGET
$(hide) $(ACP) \
$(INSTALLED_2NDBOOTLOADER_TARGET) $(zip_root)/BOOT/second
endif
ifdef BOARD_KERNEL_CMDLINE
$(hide) echo "$(BOARD_KERNEL_CMDLINE)" > $(zip_root)/BOOT/cmdline
endif
ifdef BOARD_KERNEL_BASE
$(hide) echo "$(BOARD_KERNEL_BASE)" > $(zip_root)/BOOT/base
endif
ifdef BOARD_RAMDISK_OFFSET
$(hide) echo "$(BOARD_RAMDISK_OFFSET)" > $(zip_root)/BOOT/ramdisk_offset
endif
ifdef BOARD_KERNEL_OFFSET
$(hide) echo "$(BOARD_KERNEL_OFFSET)" > $(zip_root)/BOOT/kernel_offset
endif
ifdef BOARD_TAGS_OFFSET
$(hide) echo "$(BOARD_TAGS_OFFSET)" > $(zip_root)/BOOT/tags_offset
endif
ifdef BOARD_KERNEL_PAGESIZE
$(hide) echo "$(BOARD_KERNEL_PAGESIZE)" > $(zip_root)/BOOT/pagesize
endif
ifdef CUSTOM_BUILD_VERNO
$(hide) echo -n $(CUSTOM_BUILD_VERNO_HDR) > $(zip_root)/BOOT/board
endif
endif # BOARD_USES_RECOVERY_AS_BOOT
$(hide) $(foreach t,$(INSTALLED_RADIOIMAGE_TARGET),\
mkdir -p $(zip_root)/RADIO; \
$(ACP) $(t) $(zip_root)/RADIO/$(notdir $(t));)
@# Contents of the system image
$(hide) $(call package_files-copy-root, \
$(SYSTEMIMAGE_SOURCE_DIR),$(zip_root)/SYSTEM)
@# Contents of the data image
$(hide) $(call package_files-copy-root, \
$(TARGET_OUT_DATA),$(zip_root)/DATA)
ifdef BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE
@# Contents of the vendor image
$(hide) $(call package_files-copy-root, \
$(TARGET_OUT_VENDOR),$(zip_root)/VENDOR)
endif
#wschen 2012-11-07
$(if $(BOARD_CUSTOMIMAGE_PARTITION_SIZE), \
$(hide) $(call package_files-copy-root, \
$(TARGET_CUSTOM_OUT),$(zip_root)/CUSTOM))
@# Extra contents of the OTA package
$(hide) mkdir -p $(zip_root)/OTA
$(hide) $(ACP) $(INSTALLED_ANDROID_INFO_TXT_TARGET) $(zip_root)/OTA/
ifneq ($(AB_OTA_UPDATER),true)
ifneq ($(built_ota_tools),)
$(hide) mkdir -p $(zip_root)/OTA/bin
$(hide) $(ACP) $(PRIVATE_OTA_TOOLS) $(zip_root)/OTA/bin/
endif
endif
@# Files that do not end up in any images, but are necessary to
@# build them.
$(hide) mkdir -p $(zip_root)/META
$(hide) $(ACP) $(APKCERTS_FILE) $(zip_root)/META/apkcerts.txt
$(hide) if test -e $(tool_extensions)/releasetools.py; then $(ACP) $(tool_extensions)/releasetools.py $(zip_root)/META/; fi
$(hide) echo "$(PRODUCT_OTA_PUBLIC_KEYS)" > $(zip_root)/META/otakeys.txt
$(hide) $(ACP) $(SELINUX_FC) $(zip_root)/META/file_contexts.bin
$(hide) echo "recovery_api_version=$(PRIVATE_RECOVERY_API_VERSION)" > $(zip_root)/META/misc_info.txt
$(hide) echo "fstab_version=$(PRIVATE_RECOVERY_FSTAB_VERSION)" >> $(zip_root)/META/misc_info.txt
ifdef BOARD_FLASH_BLOCK_SIZE
$(hide) echo "blocksize=$(BOARD_FLASH_BLOCK_SIZE)" >> $(zip_root)/META/misc_info.txt
endif
ifdef BOARD_BOOTIMAGE_PARTITION_SIZE
$(hide) echo "boot_size=$(BOARD_BOOTIMAGE_PARTITION_SIZE)" >> $(zip_root)/META/misc_info.txt
endif
ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),)
$(hide) echo "recovery_as_boot=$(BOARD_USES_RECOVERY_AS_BOOT)" >> $(zip_root)/META/misc_info.txt
endif
ifeq ($(INSTALLED_RECOVERYIMAGE_TARGET),)
$(hide) echo "no_recovery=true" >> $(zip_root)/META/misc_info.txt
endif
ifdef BOARD_RECOVERYIMAGE_PARTITION_SIZE
$(hide) echo "recovery_size=$(BOARD_RECOVERYIMAGE_PARTITION_SIZE)" >> $(zip_root)/META/misc_info.txt
endif
ifdef BOARD_HAS_EXT4_RESERVED_BLOCKS
$(hide) echo "has_ext4_reserved_blocks=$(BOARD_HAS_EXT4_RESERVED_BLOCKS)" >> $(zip_root)/META/misc_info.txt
endif
ifdef TARGET_RECOVERY_FSTYPE_MOUNT_OPTIONS
@# TARGET_RECOVERY_FSTYPE_MOUNT_OPTIONS can be empty to indicate that nothing but defaults should be used.
$(hide) echo "recovery_mount_options=$(TARGET_RECOVERY_FSTYPE_MOUNT_OPTIONS)" >> $(zip_root)/META/misc_info.txt
else
$(hide) echo "recovery_mount_options=$(DEFAULT_TARGET_RECOVERY_FSTYPE_MOUNT_OPTIONS)" >> $(zip_root)/META/misc_info.txt
endif
$(hide) echo "tool_extensions=$(tool_extensions)" >> $(zip_root)/META/misc_info.txt
$(hide) echo "default_system_dev_certificate=$(DEFAULT_SYSTEM_DEV_CERTIFICATE)" >> $(zip_root)/META/misc_info.txt
ifdef PRODUCT_EXTRA_RECOVERY_KEYS
$(hide) echo "extra_recovery_keys=$(PRODUCT_EXTRA_RECOVERY_KEYS)" >> $(zip_root)/META/misc_info.txt
endif
$(hide) echo 'mkbootimg_args=$(BOARD_MKBOOTIMG_ARGS)' >> $(zip_root)/META/misc_info.txt
$(hide) echo 'mkbootimg_version_args=$(INTERNAL_MKBOOTIMG_VERSION_ARGS)' >> $(zip_root)/META/misc_info.txt
$(hide) echo "use_set_metadata=1" >> $(zip_root)/META/misc_info.txt
$(hide) echo "multistage_support=1" >> $(zip_root)/META/misc_info.txt
$(hide) echo "update_rename_support=1" >> $(zip_root)/META/misc_info.txt
$(hide) echo "blockimgdiff_versions=1,2,3,4" >> $(zip_root)/META/misc_info.txt
ifeq ($(MTK_HEADER_SUPPORT),yes)
$(hide) echo "mtk_header_support=1" >> $(zip_root)/META/misc_info.txt
endif
ifneq ($(OEM_THUMBPRINT_PROPERTIES),)
# OTA scripts are only interested in fingerprint related properties
$(hide) echo "oem_fingerprint_properties=$(OEM_THUMBPRINT_PROPERTIES)" >> $(zip_root)/META/misc_info.txt
endif
ifneq ($(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_BASE_FS_PATH),)
$(hide) $(ACP) $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_BASE_FS_PATH) \
$(zip_root)/META/$(notdir $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SYSTEM_BASE_FS_PATH))
endif
ifneq ($(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VENDOR_BASE_FS_PATH),)
$(hide) $(ACP) $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VENDOR_BASE_FS_PATH) \
$(zip_root)/META/$(notdir $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_VENDOR_BASE_FS_PATH))
endif
ifneq ($(strip $(SANITIZE_TARGET)),)
# We need to create userdata.img with real data because the instrumented libraries are in userdata.img.
$(hide) echo "userdata_img_with_data=true" >> $(zip_root)/META/misc_info.txt
endif
ifeq ($(BOARD_USES_FULL_RECOVERY_IMAGE),true)
$(hide) echo "full_recovery_image=true" >> $(zip_root)/META/misc_info.txt
endif
ifeq ($(TARGET_USERIMAGES_USE_UBIFS),true)
$(call generate-ubifs-prop-dictionary, $(zip_root)/META/misc_info.txt)
endif
$(call generate-userimage-prop-dictionary, $(zip_root)/META/misc_info.txt)
@# sign image used to get boot and recovery sig files
$(hide) $(SHELL) vendor/mediatek/proprietary/scripts/sign-image/sign_image.sh
@#prepare image and update list for OTA upgrade used
#[email protected] 20170411 add for preloader upgrade start
#$(hide) ./device/mediatek/build/releasetools/mt_ota_preprocess.py $(zip_root) $(PRODUCT_OUT) $(PRODUCT_OUT)/ota_update_list.txt
$(hide) MTK_LOADER_UPDATE=yes MTK_PRELOADER_OTA_BACKUP=no ./device/mediatek/build/releasetools/mt_ota_preprocess.py $(zip_root) $(PRODUCT_OUT) $(PRODUCT_OUT)/ota_update_list.txt
#[email protected] 20170411 add for preloader upgrade end
ifneq ($(INSTALLED_RECOVERYIMAGE_TARGET),)
$(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH MKBOOTIMG=$(MKBOOTIMG) \
./build/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.
$(hide) $(ACP) $(TOPDIR)system/update_engine/update_engine.conf $(zip_root)/META/update_engine_config.txt
$(hide) for part in $(AB_OTA_PARTITIONS); do \
echo "$${part}" >> $(zip_root)/META/ab_partitions.txt; \
done
$(hide) for conf in $(AB_OTA_POSTINSTALL_CONFIG); do \
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.
$(hide) echo "build_type=$(TARGET_BUILD_VARIANT)" >> $(zip_root)/META/misc_info.txt
$(hide) echo "ab_update=true" >> $(zip_root)/META/misc_info.txt
ifdef OSRELEASED_DIRECTORY
$(hide) $(ACP) $(TARGET_OUT_ETC)/$(OSRELEASED_DIRECTORY)/product_id $(zip_root)/META/product_id.txt
$(hide) $(ACP) $(TARGET_OUT_ETC)/$(OSRELEASED_DIRECTORY)/product_version $(zip_root)/META/product_version.txt
endif
endif
ifeq ($(BREAKPAD_GENERATE_SYMBOLS),true)
@# If breakpad symbols have been generated, add them to the zip.
$(hide) $(ACP) -r $(TARGET_OUT_BREAKPAD) $(zip_root)/BREAKPAD
endif
@# Zip everything up, preserving symlinks and placing META/ files first to
@# help early validation of the .zip file while uploading it.
$(hide) (cd $(zip_root) && \
zip -qryX ../$(notdir $@) ./META && \
zip -qryXu ../$(notdir $@) .)
@# Run fs_config on all the system, vendor, boot ramdisk,
@# and recovery ramdisk files in the zip, and save the output
$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="SYSTEM/" } /^SYSTEM\// {print "system/" $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -D $(TARGET_OUT) -S $(SELINUX_FC) > $(zip_root)/META/filesystem_config.txt
$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="VENDOR/" } /^VENDOR\// {print "vendor/" $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -D $(TARGET_OUT) -S $(SELINUX_FC) > $(zip_root)/META/vendor_filesystem_config.txt
ifeq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="ROOT/" } /^ROOT\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -D $(TARGET_OUT) -S $(SELINUX_FC) > $(zip_root)/META/root_filesystem_config.txt
endif
$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="BOOT/RAMDISK/" } /^BOOT\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -D $(TARGET_OUT) -S $(SELINUX_FC) > $(zip_root)/META/boot_filesystem_config.txt
ifneq ($(INSTALLED_RECOVERYIMAGE_TARGET),)
$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="RECOVERY/RAMDISK/" } /^RECOVERY\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -D $(TARGET_OUT) -S $(SELINUX_FC) > $(zip_root)/META/recovery_filesystem_config.txt
endif
# 2012-11-07
$(if $(BOARD_CUSTOMIMAGE_PARTITION_SIZE), \
$(hide) zipinfo -1 $@ | awk 'BEGIN { FS="CUSTOM/" } /^CUSTOM\// {print "custom/" $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -D $(TARGET_OUT) -S $(SELINUX_FC) > $(zip_root)/META/custom_filesystem_config.txt)
$(hide) (cd $(zip_root) && zip -qX ../$(notdir $@) META/*filesystem_config.txt)
$(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH MKBOOTIMG=$(MKBOOTIMG) \
./build/tools/releasetools/add_img_to_target_files -a -v -p $(HOST_OUT) $@
$(hide) ./build/tools/releasetools/replace_img_from_target_files.py $@ $(PRODUCT_OUT)
.PHONY: target-files-package
target-files-package: $(BUILT_TARGET_FILES_PACKAGE)
ifneq ($(filter $(MAKECMDGOALS),target-files-package),)
$(call dist-for-goals, target-files-package, $(BUILT_TARGET_FILES_PACKAGE))
endif
上面编译target包的过程,可以分为几个步骤:
- 创建RECOVERY目录,并填充该目录的内容,包括kernel的镜像和recovery根文件系统的镜像。此目录最终用于生成recovery.img。
- 创建并填充BOOT目录。包含kernel和cmdline以及pagesize大小等,该目录最终用来生成boot.img。
- 向SYSTEM目录填充system image。
- 向DATA填充data image。
- 用于生成OTA package包所需要的额外的内容。主要包括一些bin命令。
- 创建META目录并向该目录下添加一些文本文件,如
apkcerts.txt
(描述apk文件用到的认证证书),misc_info.txt
(描述Flash内存的块大小以及boot、recovery、system、userdata
等分区的大小信息)。 - 使用保留连接选项压缩我们在上面获得的root_zip目录。
- 使用
fs_config(build/tools/fs_config)
配置上面的zip包内所有的系统文件(system/下各目录、文件)的权限属主等信息。fs_config
包含了一个头文件#include“private/android_filesystem_config.h”
。在这个头文件中以硬编码的方式设定了system目录下各文件的权限、属主。执行完配置后会将配置后的信息以文本方式输出 到META/filesystem_config.txt
中。并再一次zip压缩成我们最终需要的原始包。
编译OTA包,则需要用到ota_from_target_files
脚本。其中编译完整OTA包(SD卡包),最终是用到WriteFullOTAPackage(input_zip, output_zip)
方法。编译增量包,需要用到WriteIncrementalOTAPackage
方法。两个方法另起文档具体分析。
在制作OTA包时,需要注意是否支持基于block的系统。所谓基于block,是指Android 5.0及更高版本使用块OTA更新来确保每个设备使用完全相同的分区。代替比较单个文件和计算二进制补丁,块OTA将整个分区作为一个文件处理,并计算一个二进制补丁,以确保生成的分区完全包含预期的位。 这允许设备系统映像通过fastboot或OTA实现相同的状态。