前面介绍了OTA的一些基本概念和常用的两种OTA升级方式(recovery和update_engine),基于之上本篇继续介绍一下OTA包的编译生成机制。
一、编译OTA包
编译生成OTA包的方式非常多,并且不同平台还有不一样的命令,在加上android 8.0引入的Android Treble架构,导致OTA包的制作方式存在一些列变化。本章就依次把他们的脉络进行梳理。

1、传统方式
在Android Treble化之前,AOSP已经提供了默认的方式来生成OTA升级包,主要是使用了如下几个命令:
- source build/envsetup.sh
- lunch <target>
- make -jN ---> 形成完成全量编译
- make otapackage ---> 生成完整OTA包
- make partialotapackage ---->生成部分OTA包
- make otardppackage ----->生成动态分区OTA包/使用场景非常少
make otapackage命令实际上是执行的aosp/build/make/core/Makefile中如下代码:
1)build-ota-package-target的调用

如上执行make otaxxx命令最终都是调用call build-ota-package-target函数,此函数的解析如下:
bash
$(call build-ota-package-target,$@,-k $(KEY_CERT_PAIR) --output_metadata_path $(INTERNAL_OTA_METADATA))
# call 是makefile的函数调用语法,这里调用的是build-ota-package-target函数,
# 传递KEY_CERT_PAIR和INTERNAL_OTA_METADATA参数
# build-ota-package-target函数定义
# 此函数核心代码调用了OTA_FROM_TARGET_FILES指定的脚本文件
define build-ota-package-target
PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$(dir $(ZIP2ZIP)):$$PATH \
$(OTA_FROM_TARGET_FILES) \
--verbose \
--path $(HOST_OUT) \
$(if $(OEM_OTA_CONFIG), --oem_settings $(OEM_OTA_CONFIG)) \
$(if $(BOOT_VAR_OTA_CONFIG), --boot_variable_file $(BOOT_VAR_OTA_CONFIG)) \
$(2) \
$(patsubst %.zip,%,$(BUILT_TARGET_FILES_PACKAGE)) $(1)
endef
2)ota_from_target_files工具的指定
其中OTA_FROM_TARGET_FILES的定义如下,指定了out目录下的生成的ota_from_target_files可执行文件

那么真的是out目录吗? 我这里直接下个结论,是的,我们通常自己做ota包的步骤如下:
cd /out/host/linux-x86/bin/
ota_from_target_files -v -k 秘钥文件路径 target.zip文件路径 ota包输出路径
3)KEY_CERT_PAIR签名文件指定

如上执行make otaxxx命令的时候指定秘钥文件,即宏变量KEY_CERT_PATH指定的key文件路径,我们看看他的赋值链如下:


如上最后还是回到了应用签名key,针对这块机制可以参考https://blog.csdn.net/qq_27672101/article/details/156126737
4)out/dist输出路径
在最新高通平台Android 16上面,执行make会默认在out/dist目录生成target包:

然而我执行make otapackage命令却出现如下编译报错:

2、平台方式
原因为这条基线,高通构建系统已切换到 Soong + Ninja(AOSP 从 Android 7.0+ 逐步迁移,Android 10+ 完全默认)。otapackage 目标未被注册 → 通常是因为:
- 设备配置(device/qcom/... 或 vendor/qcom/...)没有启用 Recovery 或 OTA 支持
- 高通 BSP(Board Support Package)移除了传统 OTA 构建逻辑
- 使用了 user/userdebug 以外的编译变体(但可能性较低)
- Android 版本较新(如 Android 12+),默认使用 update_payload 而非 otapackage
make otapackage的操作方式只能针对Android Treble化之前。
在Treble化之后无论是高通平台还是MTK平台还是展锐平台,都对system和vendor进行了分离,即使用了两套aosp代码,整个编译流程从之前的单一源码编译转换成了:
- 编译system侧代码
- 编译vendor侧代码
- 再进行合并,MTK使用split_build.py/高通使用build_image_standalone.py
- 注意AOSP原生不支持分区合并,因此分区合并都是不同平台实现不一样
1)高通平台
那么target包的生成流程呢?这里列一下高通的解决方案,先看看高通的合并命令可以提供的参数:
python vendor/qcom/opensource/core-utils/build/build_image_standalone.py
--image super #表示进行分区合并
--qssi_build_path "{CODE_PATH}/{QSSI_PATH}" #指定system代码路径
--target_build_path . #指定target包输出路径
--merged_build_path . #指定合并后的分区输出路径
--target_lunch ${PRODUCT_NAME} #指定设备 lunch 名称
--output_ota #表示不仅要生成镜像,还要生成合并后的
target_files.zip
如上命令参数--output_ota会把system侧的target包与vendor侧的target包进行合并:

2)MTK平台
MTK平台关于OTA升级我没有深入研究过,不过可以看到的它的原理实际上和上面的高通方式基本一致,如下在对system侧与vendor侧进行合并的时候,需要使用split_build.py工具,至于这个工具是原生的还是mtk的,这个暂时没有深究,个人理解应该是MTK的,因为原生aosp就不支持分区合并。
python out_sys/target/product/${CUSTOM_BUILD_SYSTEM_NAME}/images/split_build.py
--system-dir {ANDROID_SYSTEM_DIR}/out_sys/target/product/{CUSTOM_BUILD_SYSTEM_NAME}/images \
--vendor-dir {ANDROID_VENDOR_DIR}/out/target/product/{CUSTOM_PROJECT_NAME}/images \
--kernel-dir {ANDROID_VENDOR_DIR}/out/target/product/{CUSTOM_PROJECT_NAME}/images \
--output-dir ${ANDROID_MERGED_DIR} \
--otapackage
如上命令参数,同理--system-dir --vendor-dir kernel-dir指定编译出来的镜像,最后--output-dir目录指定输出路径,最关键的是--otapackage参数会做如下几步:
- 重建完整的
target_files目录结构:
- 从
--system-dir解包或复制SYSTEM/,PRODUCT/,SYSTEM_EXT/等目录- 从
--vendor-dir提取VENDOR/,ODM/- 从
--kernel-dir获取BOOT/,DTBO/,VBMETA/- 合并生成一个符合 AOSP 格式的
merged_target_files/目录- 生成**
target_files.zip**
- 调用 AOSP 工具生成 OTA 包:类似如下命令
build/tools/releasetools/ota_from_target_files.py \ --package_key ... \ --downgrade_allowed \ merged_target_files.zip \ $ {ANDROID_MERGED_DIR}/ota_update.zip
3、ota_from_target_files终极奥义
从如上可以对OTA包的编译生成进行如下总结:
- AOSP标准方式:make otapackage/partialotapackage/otardppackage
- 高通平台方式:build_image_standalone.py工具
- MTK平台方式:split_build.py工具
最后都不约而同的执行了aosp提供的ota_from_target_files工具。
那么我们自己手动去做OTA包或者差分包的时候,是如何做的呢?其实也是通过ota_from_target_files工具进行生成:
步骤一:环境变量配置
AndroidS已以上的项目,首先确认下本地的java环境是否是java11即以上版本
如果本地低于java11 版本,请找该项目代码,从代码中设置java11 的临时环境:
cd androidu
export JAVA_HOME=`pwd`/prebuilts/jdk/jdk11/linux-x86
export PATH={JAVA_HOME}/bin:PATH
设置完后可以使用 java --version 确认下是否设置成功
步骤二:ota_from_target_files命令
使用编译后out目录下的 ota_from_target_files 文件制作不同的OTA包。
注意:因当前很多项目 vendor 和 system image是通过不同的代码来编译的,需要使用system image 编译的ota_from_target_files 文件
- 编译差分包:
./androidu/out_sys/host/linux-x86/bin/ota_from_target_files -v
-k build/target/product/security//releasekey #指定应用签名key
-i merged_target_A.zip merged_target_B.zip #指定差分版本对应的target包
A_to_B_ota.zip #指定OTA输出文件名
- 编译全包:
./androidu/out_sys/host/linux-x86/bin/ota_from_target_files -v
-k build/target/product/security//releasekey #指定应用签名key
merged_target_B.zip #指定全包版本对应的target包
B_ota.zip #指定OTA输出文件名
案例一:高通项目全包命令封装
bash
CODE_PATH=${SCRIPT_PATH}
LA_UM_PATH=os/la.um
QSSI_PATH=os/la.qssi16
function build_full_ota()
{
local project_codepath="${CODE_PATH}/${LA_UM_PATH}"
local ota_toolpath="${project_codepath}/out/host/linux-x86/bin/"
local releasekey_filename="${project_codepath}/build/target/product/security/"
gotodir "${project_codepath}/out/dist/"
echo "---------------------------------------------build_full_ota---------------------------------------------"
${ota_toolpath}/ota_from_target_files -v -k ${releasekey_filename}/releasekey merged-qssi_64_lahaina612-target_files.zip merged-qssi_64_lahaina612-ota.zip
}