Android OTA 脚本流程

这篇博客主要探讨了Android OTA升级过程中高通mbn文件的更新流程,包括WriteBlockIncrementalOTAPackage函数的详细步骤:解析image、检查属性、校验RADIO目录文件、写入升级脚本等。同时,文中提到了IncrementalOTA_VerifyEnd函数的内部操作,如GetRadioFiles和SplitFwTypes等,以及如何处理差分和全分升级的共image需求。

杂乱记录一下,以后再做整理
这里主要跟踪升级高通mbn文件的流程
主要根据生成的script脚本来逆向分析

解释会比较繁琐,因为本身对Python也不是特别懂,这里就当自学了:)

下面是WriteBlockIncrementalOTAPackage函数的主要流程
1.解析基础包和目标包中的boot,recovery和system 这三个image
2.检查device属性值是否满足要求
3.检查fingerprint属性值是否满足要求
4.对比bootimage的差异,将差异部分写入boot.img.p并放入patch目录下,在script脚本中写入检测boot的命令
5.在脚本中加入检查空间是否足够的命令
6.校验RADIO目录下的文件
7.写入脚本校验systemimage和vendorimage
8.向脚本中写入升级systemimage vendorimage bootimage的命令
9.升级RADIO目录下的文件

1.1
上面的1~5点
def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip):

  #1.下面这部分比较重要,应该是解析image的信息,以后再看
  source_boot = common.GetBootableImage(
      "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT",
      OPTIONS.source_info_dict)
  target_boot = common.GetBootableImage(
      "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT")
  updating_boot = (not OPTIONS.two_step and
                   (source_boot.data != target_boot.data))

  target_recovery = common.GetBootableImage(
      "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY")

  system_src = GetImage("system", OPTIONS.source_tmp)
  system_tgt = GetImage("system", OPTIONS.target_tmp)


  #2.检查device属性值是否满足要求
  #方法中会调用script.AssertDevice来检查ro.product.device属性值是否满足要求
  AppendAssertions(script, OPTIONS.target_info_dict, oem_dicts)
  #这里啥也没做
  device_specific.IncrementalOTA_Assertions()

  #打印出fingerprint的值
  script.Print("Source: %s" % (source_fp,))
  script.Print("Target: %s" % (target_fp,))
  #不知道调用到哪里去了,releasetools.py中没有这个方法
  device_specific.IncrementalOTA_VerifyBegin()

     #3.检查fingerprint属性值是否满足要求,具体实现在edify_generator.py中
     script.AssertSomeFingerprint

  #如果要升级bootimage,这里是肯定的
  if updating_boot:
    boot_type, boot_device = common.GetTypeAndDevice(
        "/boot", OPTIONS.source_info_dict)
    d = common.Difference(target_boot, source_boot)
    _, _, d = d.ComputePatch()
    if d is None:
      #没有差异,为什么要全分升级??
      include_full_boot = True
      common.ZipWriteStr(output_zip, "boot.img", target_boot.data)
    else:
      include_full_boot = False

      print("boot      target: %d  source: %d  diff: %d" % (
          target_boot.size, source_boot.size, len(d)))

      #4.将差异部分写入boot.img.p并放入patch目录下
      common.ZipWriteStr(output_zip, "patch/boot.img.p", d)
      #在script脚本中写入检测boot的命令
      script.PatchCheck("%s:%s:%d:%s:%d:%s" %
                        (boot_type, boot_device,
                         source_boot.size, source_boot.sha1,
                         target_boot.size, target_boot.sha1))
      size.append(target_boot.size)

  #5.size肯定不为空,在脚本中加入检查空间是否足够的命令
  if size:
    script.CacheFreeSpaceCheck(max(size))

  #6.这里就是校验mbn文件的地方,非常重要,common.py中调用到device/qcom/common/releasetools.py中的方法
  device_specific.IncrementalOTA_VerifyEnd()
  ......
1.2 详细看一下IncrementalOTA_VerifyEnd函数,第6点
def IncrementalOTA_VerifyEnd(info):
 #调用了OTA_VerifyEnd方法
 OTA_VerifyEnd(info, info.target_version, info.target_zip, info.source_zip)
 return



#来详细看看
def OTA_VerifyEnd(info, api_version, target_zip, source_zip=None):
  #明显,这里加载filesmap文件
  print "Loading radio filesmap..."
  #filesmap是字典格式,键值对中的键是唯一的,注意,这里读取的是目标版本中RADIO目录的文件
  filesmap = LoadFilesMap(target_zip)
  if filesmap == {}:
    print "warning radio-update: no or invalid filesmap file found"
    return False

  print "Loading radio target..."
  #加载目标包中RADIO
<think> 我们正在讨论的是Android R(即Android 11)系统的OTA升级流程。根据引用[3]中描述的标准OTA升级流程,并结合Android R的特性,我们可以将流程分为以下几个阶段: 1. **检查更新与下载阶段**: - 系统通过`SystemUpdateService`(通常由系统应用如Settings或系统更新应用触发)定期或手动检查OTA服务器。 - 服务器返回更新信息(包括版本号、下载地址等)[^3]。 - 下载更新包到设备的`/data`分区或`/cache`分区(具体位置可能因设备而异)[^3]。 2. **准备安装阶段**: - 下载完成后,系统会提示用户安装更新。用户可以选择立即安装或稍后安装。 - 当用户确认安装后,系统会调用`RecoverySystem`的API(如`installPackage()`)来触发重启进入recovery模式[^2][^3]。 3. **重启进入recovery模式**: - 设备重启后,引导加载程序(bootloader)会加载recovery分区(而不是正常启动的boot分区)[^3]。 - recovery环境初始化,并执行recovery二进制程序(如`/system/bin/recovery`)。 4. **更新包验证与安装**: - recovery程序读取`/cache/recovery/command`文件中的指令(该文件由`RecoverySystem`在重启前写入)[^3]。 - 验证更新包的签名(使用设备内置的公钥验证更新包中的签名,确保包未被篡改)[^3]。 - 如果验证通过,则开始解压更新包并应用更新。更新通常包括: - 更新`boot`分区(内核) - 更新`system`分区(系统文件) - 更新`vendor`分区(厂商相关文件) - 更新`recovery`分区(新的recovery)[^3]。 5. **处理AB分区(如果支持)**: - 对于支持A/B分区的设备(Android R默认支持),更新过程略有不同: - 设备有两个系统分区(A和B),当前运行在其中一个分区(例如A分区),更新会安装到另一个未使用的分区(B分区)[^2]。 - 这样可以在后台安装更新,用户无需长时间等待。安装完成后,在下次重启时切换分区即可[^2]。 6. **完成更新并重启**: - 更新完成后,设备会重启。 - 对于非A/B分区设备:重启后进入更新后的系统。 - 对于A/B分区设备:重启后切换到更新后的分区(例如从A切换到B)[^2]。 - 系统启动时会验证recovery分区的完整性,如果与系统不匹配,会更新recovery分区[^3]。 7. **清理**: - 更新成功后,系统会清理更新包和临时文件。 ### 关键代码与配置(引用[2]): - **Settings中的OTA入口**:在`my_device_info.xml`中添加一个`Preference`用于触发更新检查。 - **MyDeviceInfoFragment.java**:在该类中处理点击事件,调用系统更新服务。 ### 注意事项: - **签名验证**:确保更新包由设备信任的密钥签名,否则会中止安装[^3]。 - **A/B分区**:在Android R中,A/B分区是主流方案,它减少了更新失败导致设备无法启动的风险,并实现了无缝更新[^2]。 ### 流程图示例: ```mermaid graph TD A[用户手动检查更新/自动检查] --> B{服务器有更新?} B -- 有 --> C[下载更新包到/cache或/data分区] B -- 无 --> Z[结束] C --> D[提示用户安装] D --> E[用户确认安装] E --> F[调用RecoverySystem.installPackage] F --> G[写入/cache/recovery/command] G --> H[重启设备进入recovery] H --> I[recovery读取command文件] I --> J[验证签名] J -- 通过 --> K[解压更新包并更新分区] J -- 失败 --> M[进入错误界面] K --> L[重启设备] L --> N[启动新系统] N --> O[清理临时文件] ``` §§相关问题§§ 1. Android R中A/B分区升级的具体实现细节是什么? 2. 如何为自定义ROM实现OTA服务器? 3. OTA升级过程中如何保证数据安全? 4. 如何处理OTA升级失败的情况? </think>### Android R (Android 11) OTA升级详细流程 Android R系统的OTA升级流程主要分为五个阶段,支持A/B分区和无缝更新(Seamless Updates)技术[^2][^3]: #### 1. **更新检测与下载阶段** ```mermaid graph LR A[Settings/系统更新应用] --> B{检查服务器更新} B -->|有更新| C[下载更新包到/data/ota_package] B -->|无更新| D[结束] C --> E[验证更新包签名] ``` - 用户通过**系统设置 > 关于手机 > 系统更新**触发更新检查[^2] - 系统访问OTA服务器获取更新包信息(版本号、下载地址等)[^3] - 下载更新包到安全位置:`/data/ota_package/` - **签名验证**:使用设备端预置密钥验证更新包完整性(防止篡改)[^3] #### 2. **安装准备阶段 ```mermaid graph TB F[安装确认] --> G[创建更新指令] G --> H[/写入/cache/recovery/command/] H --> I[设置系统属性] I --> J[准备A/B分区切换] ``` - 用户确认安装后,系统生成更新指令文件: ```bash # /cache/recovery/command 内容示例 --update_package=/data/ota_package/update.zip --locale=zh_CN ``` - 对于**A/B分区设备**: - 更新后台写入非活动分区(如当前使用slot A,则更新slot B) - 保留原系统分区完整(确保更新失败可回退)[^2] #### 3. **Recovery模式执行阶段 设备重启后进入recovery环境: 1. 加载recovery分区内核 2. 执行`recovery`二进制程序 3. 解析`/cache/recovery/command`指令 4. 关键操作: ```bash apply_patch("/system", "/data/ota_package/system.patch") # 增量更新 flash_partition("boot", "/data/ota_package/boot.img") # 刷入内核 update_recovery() # 更新recovery自身 ``` #### 4. **A/B分区更新流程Android R核心特性) ```mermaid graph LR K[当前系统 Slot_A] --> L[下载更新到 Slot_B] L --> M[验证Slot_B完整性] M --> N[设置Slot_B为下次启动分区] N --> O[重启进入Slot_B] ``` - **双分区结构**: - `boot_a`/`boot_b` - `system_a`/`system_b` - `vendor_a`/`vendor_b` - 更新过程完全在后台进行,用户可正常使用设备[^2] - 重启时通过**bootloader控制**切换活动分区[^3] #### 5. **启动验证与清理阶段 1. 首次启动新分区时: - 触发**dm-verity**验证分区完整性 - 执行`postinstall`脚本(如更新firmware) 2. 更新成功后: - 删除临时文件:`/data/ota_package/` - 更新系统版本号(可通过`adb shell getprop ro.build.version`查看) 3. 若更新失败: - 自动回退至原分区启动 - 生成错误日志:`/cache/recovery/last_log` ### 关键代码实现(引用[2]) 1. **设置界面入口**: ```xml <!-- packages/apps/Settings/res/xml/my_device_info.xml --> <Preference android:key="system_update" android:title="@string/system_update_title" /> ``` 2. **更新触发逻辑**: ```java // packages/apps/Settings/src/.../MyDeviceInfoFragment.java public boolean onPreferenceClick(Preference preference) { if ("system_update".equals(preference.getKey())) { Intent intent = new Intent("android.settings.SYSTEM_UPDATE_SETTINGS"); startActivity(intent); return true; } return false; } ``` ### 安全机制 | 机制 | 作用 | 实现位置 | |---------------------|-------------------------------|----------------------| | VAB(Virtual A/B) | 支持无需recovery的更新 | Android R新增[^2] | | dm-verity | 分区完整性验证 | 内核层 | | AVB(Android Verified Boot) | 启动链验证 | Bootloader层 |
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值