Android实战进阶篇--QCM6490 OTA升级全流程解析

张开发
2026/4/14 14:29:21 15 分钟阅读

分享文章

Android实战进阶篇--QCM6490 OTA升级全流程解析
1. QCM6490平台OTA升级基础认知第一次接触QCM6490的OTA升级时我被各种专业术语搞得晕头转向。后来在实际项目中踩过几次坑才明白这个高通的物联网平台确实有些特殊之处。简单来说OTAOver-The-Air升级就像给手机远程安装系统补丁但工业场景下的要求更严苛——不能影响设备正常运行升级失败要能回滚还得考虑网络环境不稳定等各种现实问题。QCM6490作为高通面向物联网和边缘计算的主力芯片其OTA机制与普通Android手机最大的区别在于双系统分区设计。我经手的一个智能摄像头项目就吃过亏开发阶段直接照搬手机OTA方案结果设备升级后频繁死机。后来发现是没处理好AB分区的切换逻辑导致新老系统互相干扰。这里特别提醒在QCM6490上做OTA必须搞清楚三个核心概念整包升级完整的新系统镜像通常几百MB大小适合大版本更新差分升级仅包含变更部分的补丁包可能只有几十MB适合小版本迭代回滚机制当升级失败时能自动恢复到旧版本这对工业设备至关重要去年给某物流公司做车载终端升级系统时我们就因为没处理好差分升级的版本校验导致一批设备变砖。后来用update_engine_client --check_for_update命令预检才解决问题。所以建议大家在开发初期就要建立完整的版本号管理规则避免出现v1.0.1直接升v1.1.0这种跨度太大的情况。2. 整包升级实战全流程2.1 镜像资源包生成技巧整包升级的第一步是生成系统镜像资源包这里最容易踩的坑是分区大小设置。我遇到过好几次因为vendor分区预留空间不足导致打包失败的情况。具体操作时建议先用这个命令检查当前系统分区布局adb shell ls -al /dev/block/bootdevice/by-name/在编译镜像时务必在device/qcom/qcm6490/目录下的BoardConfig.mk中确认这些参数BOARD_SYSTEMIMAGE_PARTITION_SIZEBOARD_VENDORIMAGE_PARTITION_SIZEBOARD_USERDATAIMAGE_PARTITION_SIZE最近帮客户调试时发现个隐藏问题某些QCM6490开发板的emmc实际容量比标称值小5%直接导致大版本升级失败。后来我们在生成镜像时专门加了5%的余量BOARD_SYSTEMIMAGE_PARTITION_SIZE : $(shell echo $$(($(原来的值)*105/100)))2.2 升级包制作详解制作升级包最关键的步骤是生成OTA工具链。我习惯用这个命令初始化编译环境source build/envsetup.sh lunch qcm6490-userdebug然后执行打包命令时建议加上--retrofit_dynamic_partitions参数以适应不同硬件配置make otatools dist -j$(nproc) \ TARGET_RELEASETOOLS_EXTENSIONSvendor/qcom/proprietary/ota_extensions生成的zip包需要特别注意签名问题。有次客户反映升级包校验失败排查发现是测试环境和产线用的签名证书不同。现在我们都统一用这套命令签名java -jar out/host/linux-x86/framework/signapk.jar \ vendor/qcom/proprietary/ota_extensions/testkey.x509.pem \ vendor/qcom/proprietary/ota_extensions/testkey.pk8 \ input.zip output-signed.zip2.3 整包升级执行策略实际部署时推荐先用模拟环境测试。我常用的方法是adb push output-signed.zip /data/ota_package/ adb shell update_engine_client --update --follow \ --payloadfile:///data/ota_package/output-signed.zip在工业现场遇到过4G网络不稳定的情况后来我们改进了断点续传机制。关键是在payload_properties.txt中加入这两个参数FILE_HASHxxx FILE_SIZExxx还有个血泪教训某次升级后设备WiFi模块失效原因是忘了包含firmware更新。现在我们的检查清单必含基带固件WiFi固件传感器校准数据3. 差分升级进阶技巧3.1 双版本镜像处理做差分升级时最容易出错的就是版本匹配问题。我们团队现在严格执行这套流程为旧版本打标签git tag -a v1.0.0 -m Base version编译旧版本镜像make -j$(nproc)切换到新版本分支git checkout v1.0.1编译新版本镜像make -j$(nproc)生成差分包的黄金命令是./build/tools/releasetools/ota_from_target_files \ -i v1.0.0.zip v1.0.1.zip incremental_update.zip特别注意要检查META/目录下的inf文件确保pre-device字段与设备匹配。有次因为粗心写错型号前缀导致200台设备升级失败。3.2 可选分区优化QCM6490支持动态分区后处理system_ext和product分区变得很棘手。我们的经验是小更新尽量排除vendor分区--exclude_vendor修改boot.img时必须包含vbmeta--include_vbmeta使用这个命令查看分区变更./build/tools/releasetools/ota_from_target_files \ --verbose \ --diff_input_filev1.0.0.zip \ v1.0.1.zip incremental_update.zip最近发现个性能优化技巧在生成差分包时添加--block参数可以显著减少升级时间--block --worker_threads$(nproc)3.3 差分包生成陷阱生成差分包最怕遇到伪变更——文件内容没变但时间戳变化导致被误识别为修改。我们现在先用这个脚本预处理#!/bin/bash find out/target/product/qcm6490/ -type f -exec touch -d 2023-01-01 00:00:00 {} \;另一个常见问题是dex文件优化导致的差异。解决方案是在BoardConfig.mk中设置WITH_DEXPREOPT : false3.4 差分升级实战现场升级时我们开发了这个状态监控脚本adb shell while true; do logcat -d | grep update_engine; sleep 1; done关键状态码要牢记UPDATE_STATUS_IDLE0UPDATE_STATUS_CHECKING_FOR_UPDATE1UPDATE_STATUS_UPDATE_AVAILABLE2UPDATE_STATUS_FINALIZING6遇到卡在54%进度的问题时通常是文件系统权限问题。我们的应急方案是adb shell setenforce 0 adb shell restorecon -Rv /data/ota_package4. 两种升级方式深度解析4.1 update_engine_client全攻略这个工具的强大之处在于丰富的调试选项。我最常用的组合命令adb shell update_engine_client \ --update --follow \ --payloadhttp://192.168.1.100/update.zip \ --offset1024 \ --size524288 \ --headersAuthorization: Bearer xxxx调试网络问题时这几个参数特别有用--prewarm预热连接--max_retries5重试次数--timeout60超时设置最近发现个隐藏功能通过--apply_payload可以直接应用原始payload.binadb shell update_engine_client \ --apply_payloadfile:///data/payload.bin \ --payload_offset20484.2 API升级开发指南在开发自定义升级APP时这些API调用经验值得分享首先初始化连接IUpdateEngine engine IUpdateEngine.Stub.asInterface( ServiceManager.getService(android.os.UpdateEngineService));然后设置回调监听UpdateEngineCallback callback new UpdateEngineCallback() { Override public void onStatusUpdate(int status, float percent) { // 处理进度更新 } }; engine.bind(callback);开始升级时要注意权限问题uses-permission android:nameandroid.permission.OTA_UPDATE / uses-permission android:nameandroid.permission.DOWNLOAD_WITHOUT_NOTIFICATION /我们遇到过回调丢失的问题最后发现是Binder事务缓冲区溢出。现在的解决方案是Bundle params new Bundle(); params.putInt(priority, 1); engine.applyPayload(http://example.com/update.zip, 0, 0, params);5. 升级失败排查手册去年处理过最棘手的案例是设备升级后陷入bootloop。后来总结出这套排查流程首先获取last_logadb shell cat /proc/last_kmsg kmsg.log然后检查升级标记adb shell cat /misc/update_engine/prefs/last-update常见错误代码速查ErrorCode::kDownloadTransferError20网络问题ErrorCode::kNewRootfsVerificationError52签名校验失败ErrorCode::kFilesystemCopierError37空间不足我们的应急恢复方案是进入fastboot模式adb reboot bootloader刷入旧版本bootloaderfastboot flash boot_a old_boot.img触发回滚fastboot set_active other6. 性能优化实战在智能电表项目中发现升级速度直接影响设备可用性。经过测试总结出这些优化点压缩算法选择bsdiff适合小文件imgdiff适合大镜像zstd平衡压缩率和速度在BoardConfig.mk中添加BLOCK_BASED_OTA : true TARGET_USERIMAGES_SPARSE_EXT_DISABLED : true差分生成时使用--block --worker_threads8 --compress_threads4实测下来1.2GB系统镜像的升级时间从15分钟降到7分钟。最关键的是这个参数BOARD_EXT4_SHARE_DUP_BLOCKS : true7. 安全加固方案给银行客户做定制系统时他们对升级安全有严格要求。我们实现的方案包括双重签名验证def verify_signature(package): # 验证Google标准签名 verify_google_sig(package) # 验证厂商自定义签名 verify_vendor_sig(package)在updater-script中添加强制校验assert(verify_file(/system/build.prop, a1b2c3d4e5f6));网络传输加密UpdateEngineParams.Builder() .setHeader(X-Encrypted-Payload, true) .setPublicKey(publicKey) .build();最近还实现了防回滚机制# 在payload_properties.txt中添加 REQUIRED_MIN_VERSION202301018. 自动化测试框架我们团队开发的自动化测试流程包含环境准备脚本def setup_test_env(): flash_base_image(v1.0.0) configure_network(10.0.0.1) install_monitor_app()升级测试用例def test_incremental_update(): download_package(v1.0.1) trigger_update() assert wait_for_complete(300) verify_system_version(v1.0.1) run_post_update_checks()异常场景模拟def test_power_failure_during_update(): start_update() time.sleep(random.randint(30,120)) cut_power_supply() restore_power() verify_rollback_successful()这套框架已经发现过三个严重BUG包括一个会导致分区表损坏的致命错误。9. 生产环境部署建议在工厂批量升级时这些经验特别重要使用多线程推送工具#!/bin/bash for ip in $(seq 1 254); do scp update.zip 192.168.1.$ip:/data/ota_package/ if (( $ip % 10 0 )); then wait; fi done状态监控看板def monitor_cluster(): devices get_all_devices() with ThreadPoolExecutor(20) as executor: results executor.map(check_update_status, devices) update_dashboard(results)紧急停止开关adb shell update_engine_client --cancel最近项目中的最佳实践是先在5%的设备上灰度发布监控24小时无异常后再全量推送。

更多文章