OTA完整包生成方法

OTA完整包可用于T卡本地升级和OTA在线升级。OTA完整包包含完整的system、recovery.和boot.img。
发布一个版本固件正确顺序:

1
2
3
make -j4
make otapackage
./mkimage.sh ota

即可获得:out/target/product/{product_name}/ {product_name}-ota-eng.{uid}.zip

注意:发布固件必须使用./mkimage.sh ota,将boot与kernel打包,不需要单独烧kernel,如果量产固件是分开的,将会影响后面差异包升级,除非你不需要用差异升级!

在out/target/product/rk3288/目录下会生成ota完整包rk3288-ota-eng.root.zip,改名成
update.zip即可拷贝到T卡或内置flash中进行固件升级。

OTA差异包生成方法

OTA差异包只有差异内容,包大小比较小,主要用于OTA在线升级,也可T卡本地升级。OTA差异包制作需要特殊的编译进行手动制作。

  1. 首先发布v1版本的固件,生成v1版本的完整包
  2. 保存out/target/product/rk3288/obj/PACKAGING/target_files_intermediates/rk3288-target_files-eng.root.zip 为rk3288-target_files-v1.zip,作为v1版本的基础素材包。
  3. 修改kernel代码或者android代码,发布v2版本固件,生成v2版本完整包
  4. 保存out/target/product/rk3288/obj/PACKAGING/target_files_intermediates/rk3288-target_files-eng.root.zip 为rk3288-target_files-v2.zip,作为v2版本的基础素材包。
  5. 生成v1-v2的差异升级包:./build/tools/releasetools/ota_from_target_files -v -i rk3288-target_files-v1.zip -p out/host/linux-x86 -k build/target/product/security/testkey rk3288-target_files-v2.zip out/target/product/rk3288/rk3288-v1-v2.zip
  6. 最后生成的ota差异包

编译过程

编译主要分两步,

  1. 会准备一个包,其中包含升级需要的内容(原材料),比如,system 目录。
  2. 运行python 脚本 ./build/tools/releasetools/ota_from_target_files,以步骤一准备的ZIP包作为输入,最终生成需要的升级包。

第一步:填充所需要的材料

Makefile 依赖
otapackage 是一个伪目标

1
2
.PHONY: otapackage
otapackage: $(INTERNAL_OTA_PACKAGE_TARGET)

RECOVERY目录下的组件

填充 RECOVERY 子目录的内容。用于生成recovery.img。包括:kernel 的image, recovery 根文件系统的 image, recovery 根文件系统的内容

1
2
3
4
5
6
7
8
9
10
11
12
@# Components of the recovery image
$(hide) mkdir -p $(zip_root)/RECOVERY //创建中间包中的RECOVERY目录
$(hide) $(call package_files-copy-root, \
$(TARGET_RECOVERY_ROOT_OUT),$(zip_root)/RECOVERY/RAMDISK)
//拷贝相关分区文件到 RECOVERY 目录
1. $(ACP) $(INSTALLED_KERNEL_TARGET) $(zip_root)/RECOVERY/kernel
2. $(ACP) $(INSTALLED_2NDBOOTLOADER_TARGET) $(zip_root)/RECOVERY/second
3. echo "$(BOARD_KERNEL_CMDLINE)" > $(zip_root)/RECOVERY/cmdline
4. echo "$(BOARD_KERNEL_BASE)" > $(zip_root)/RECOVERY/base
5. echo "$(BOARD_KERNEL_PAGESIZE)" > $(zip_root)/RECOVERY/pagesize

BOOT 目录下的组件

填充 BOOT子目录的内容,用于生成boot.img。和 RECOVERY目录类似,包括:kernel 的image,根文件系统的 image,根文件系统的内容:

1
2
3
4
5
6
7
8
9
10
11
@# Components of the boot image
$(hide) mkdir -p $(zip_root)/BOOT
$(hide) $(call package_files-copy-root, \
$(TARGET_ROOT_OUT),$(zip_root)/BOOT/RAMDISK)
1. $(ACP) $(INSTALLED_KERNEL_TARGET) $(zip_root)/BOOT/kernel
2. $(ACP) $(INSTALLED_2NDBOOTLOADER_TARGET) $(zip_root)/BOOT/second
3. echo "$(BOARD_KERNEL_CMDLINE)" > $(zip_root)/BOOT/cmdline
4. echo "$(BOARD_KERNEL_BASE)" > $(zip_root)/BOOT/base
5. echo "$(BOARD_KERNEL_PAGESIZE)" > $(zip_root)/BOOT/pagesize
6.

RADIO 目录下的组件

1
2
3
$(hide) $(foreach t,$(INSTALLED_RADIOIMAGE_TARGET),\
mkdir -p $(zip_root)/RADIO; \
$(ACP) $(t) $(zip_root)/RADIO/$(notdir $(t));)

BOOTLOADER 组件内容

BOOTLOADER 需要提供之前使用的 BOOTLOADER 和 新的 BOOTLOADER 文件 以及 MISC 分区文件
之前使用的BOOTLOADER 放置在目录:$(TARGET_DEVICE_DIR)/ota/loader/RKLoader.bin)
新的 BOOTLOADER 文件 放置在目录:$(PRODUCT_OUT)/RKLoader_new.bin
MISC 分区文件 放置在目录:$(TARGET_DEVICE_DIR)/ota/loader/misc_loadercmd.img

1
2
3
4
5
6
7
8
ifeq ($(INSTALLED_LOADER_TARGET),)
$(info No RK Loader for TARGET_DEVICE $(TARGET_DEVICE) to otapackage) //不需要更新BOOTLOADER
else
@# Contents of the rk loader bin
$(hide) mkdir -p $(zip_root)/LOADER
$(hide) $(HOST_OUT_EXECUTABLES)/remkloader '$(INSTALLED_LOADER_TARGET)' $(INSTALLED_NEW_LOADER_TARGET)
$(hide) cat $(INSTALLED_LOADER_MISC_TARGET) $(INSTALLED_NEW_LOADER_TARGET) > $(zip_root)/LOADER/RKLoader.img
endif

Parameter 组件内容

parameter 需要放置在 $(TARGET_DEVICE_DIR)/ota/parameter/parameter*) 目录中

1
2
3
4
5
6
7
ifeq ($(INSTALLED_PARAMETER_TARGET),)
$(info No parameter for TARGET_DEVICE $(TARGET_DEVICE) to otapackage) //不需要更新Parameter
else
$(hide) rm -rf $(zip_root)/PARAMETER
$(hide) mkdir -p $(zip_root)/PARAMETER
$(hide) $(HOST_OUT_EXECUTABLES)/mkparameter '$(INSTALLED_PARAMETER_TARGET)' $(zip_root)/PARAMETER/parameter
endif

常规的system 以及 data 分区内容

填充 SYSTEM子目录的内容。 这是升级的主要内容。
生成 META/filesystem_config.txt 并将其加入到 zip 包中。该文件保存了 system 目录下各目录、文件的权限及 owner

1
2
3
4
5
6
@# 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)

供应商定制相关内容

1
2
3
4
5
ifdef BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE
@# Contents of the vendor image
$(hide) $(call package_files-copy-root, \
$(TARGET_OUT_VENDOR),$(zip_root)/VENDOR)
endif

第二步:ota_from_target_files 命令执行

核心是一个python脚本: ota_from_target_files, 它以前一步骤生成的ZIP包作为输入,生成可用于OTA升级的zip包。
生成的完整升级包会存放在out\target\product[project-name]\目录下

1
2
3
4
5
6
7
8
9
10
INTERNAL_OTA_PACKAGE_TARGET :# $(PRODUCT_OUT)/$(name).zip
$(INTERNAL_OTA_PACKAGE_TARGET): KEY_CERT_PAIR :# $(DEFAULT_KEY_CERT_PAIR) 签名
$(INTERNAL_OTA_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(DISTTOOLS)
@echo "Package OTA: $@"
$(hide) PATH#$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH MKBOOTIMG#$(MKBOOTIMG) \
./build/tools/releasetools/ota_from_target_files -v \
-p $(HOST_OUT) \
-k $(KEY_CERT_PAIR) \
$(if $(OEM_OTA_CONFIG), -o $(OEM_OTA_CONFIG)) \
$(BUILT_TARGET_FILES_PACKAGE) $@

生成中间包

生成的中间包存放在out/target/product/[project-name]/obj/PACKAGING/target_files_intermediates/目录下,该文件可用于创建差分升级包以及全量包
源码中的英文注释为:

1
2
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.

中间包宏变量为: BUILT_TARGET_FILES_PACKAGE
部分代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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) //定义依赖
... //省略一部分依赖说明
# 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_LOADER_TARGET) \
$(INSTALLED_PARAMETER_TARGET) \
$(INSTALLED_RECOVERYIMAGE_TARGET) \
$(INSTALLED_SYSTEMIMAGE) \
$(INSTALLED_USERDATAIMAGE_TARGET) \
$(INSTALLED_CACHEIMAGE_TARGET) \
$(INSTALLED_VENDORIMAGE_TARGET) \
$(INSTALLED_ANDROID_INFO_TXT_TARGET) \
$(SELINUX_FC) \
$(built_ota_tools) \
$(APKCERTS_FILE) \
$(HOST_OUT_EXECUTABLES)/fs_config \
| $(ACP)
上述依赖主要定义各个分区系统的文件
//之后执行命令
@echo "Package target files: $@" //打印日志
$(hide) rm -rf $@ $(zip_root) //删除原有文件目录
$(hide) mkdir -p $(dir $@) $(zip_root) //重新创建目录