天天看點

recovery image的OTA更新過程

recovery image的OTA更新主要是如下幾步:

1. 做OTA更新包的時候,将recovery.img和boot.img進行比較,生成recovery.img相對于boot.img的更新檔,即system/recovery-from-boot.p;

2. 同時,生成一個生成recovery.img的shell腳本,即system/etc/install-recovery.sh;

3. 正常的OTA更新之後,手機重新開機到normal模式,在init的過程中,執行install-recovery.sh,生成目标recovery.img.

下面給出以上步驟涉及的檔案。

1. build/tools/releasetools/ota_from_target_files

def WriteFullOTAPackage(input_zip, output_zip):
  # .................

  script.UnpackPackageDir("recovery", "/system")
  # .................
  boot_img = common.GetBootableImage("boot.img", "boot.img",
                                     OPTIONS.input_tmp, "BOOT")
  recovery_img = common.GetBootableImage("recovery.img", "recovery.img",
                                         OPTIONS.input_tmp, "RECOVERY")
  MakeRecoveryPatch(OPTIONS.input_tmp, output_zip, recovery_img, boot_img)
           

其中更新包中的recovery内容,是由MakeRecoveryPatch()函數生成的;recovery-from-boot.p的計算過程,也是在這個函數中。

def MakeRecoveryPatch(input_tmp, output_zip, recovery_img, boot_img):
  """Generate a binary patch that creates the recovery image starting
  with the boot image.  (Most of the space in these images is just the
  kernel, which is identical for the two, so the resulting patch
  should be efficient.)  Add it to the output zip, along with a shell
  script that is run from init.rc on first boot to actually do the
  patching and install the new recovery image.

  recovery_img and boot_img should be File objects for the
  corresponding images.  info should be the dictionary returned by
  common.LoadInfoDict() on the input target_files.

  Returns an Item for the shell script, which must be made
  executable.
  """

  diff_program = ["imgdiff"]
  path = os.path.join(input_tmp, "SYSTEM", "etc", "recovery-resource.dat")
  if os.path.exists(path):
    diff_program.append("-b")
    diff_program.append(path)
    bonus_args = "-b /system/etc/recovery-resource.dat"
  else:
    bonus_args = ""

  d = common.Difference(recovery_img, boot_img, diff_program=diff_program)
  _, _, patch = d.ComputePatch()
  common.ZipWriteStr(output_zip, "recovery/recovery-from-boot.p", patch)
  Item.Get("system/recovery-from-boot.p", dir=False)

  boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict)
  recovery_type, recovery_device = common.GetTypeAndDevice("/recovery", OPTIONS.info_dict)

  sh = """#!/system/bin/sh
if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then
  log -t recovery "Installing new recovery image"
  applypatch %(bonus_args)s %(boot_type)s:%(boot_device)s:%(boot_size)d:%(boot_sha1)s %(recovery_type)s:%(recovery_device)s %(recovery_sha1)s %(recovery_size)d %(boot_sha1)s:/system/recovery-from-boot.p
else
  log -t recovery "Recovery image already installed"
fi
""" % { 'boot_size': boot_img.size,
        'boot_sha1': boot_img.sha1,
        'recovery_size': recovery_img.size,
        'recovery_sha1': recovery_img.sha1,
        'boot_type': boot_type,
        'boot_device': boot_device,
        'recovery_type': recovery_type,
        'recovery_device': recovery_device,
        'bonus_args': bonus_args,
        }
  common.ZipWriteStr(output_zip, "recovery/etc/install-recovery.sh", sh)
  return Item.Get("system/etc/install-recovery.sh", dir=False)
           

上面代碼中的recovery-resource.dat這個檔案,如果用二進制編輯器打開,發現其開頭二個位元組是PK,即是一個壓縮檔案。當重命名成zip之後,可以解壓縮,可以看到存放的是recovery image的圖檔資源和密鑰。

2. init.rc

system/core/init.rc最終會拷貝到生成的boot image中,Linux内涵會執行init.rc中的指令,其中就包括對recovery image的更新,如下:

service flash_recovery /system/etc/install-recovery.sh
    class main
    oneshot