def _BuildBootableImage(sourcedir, fs_config_file, info_dict=None,
- has_ramdisk=False):
+ has_ramdisk=False, two_step_image=False):
"""Build a bootable image from the specified sourcedir.
Take a kernel, cmdline, and optionally a ramdisk directory from the input (in
- 'sourcedir'), and turn them into a boot image. Return the image data, or
- None if sourcedir does not appear to contains files for building the
- requested image."""
+ 'sourcedir'), and turn them into a boot image. 'two_step_image' indicates if
+ we are building a two-step special image (i.e. building a recovery image to
+ be loaded into /boot in two-step OTAs).
+
+ Return the image data, or None if sourcedir does not appear to contains files
+ for building the requested image.
+ """
def make_ramdisk():
ramdisk_img = tempfile.NamedTemporaryFile()
if (info_dict.get("boot_signer", None) == "true" and
info_dict.get("verity_key", None)):
- path = "/" + os.path.basename(sourcedir).lower()
+ # Hard-code the path as "/boot" for two-step special recovery image (which
+ # will be loaded into /boot during the two-step OTA).
+ if two_step_image:
+ path = "/boot"
+ else:
+ path = "/" + os.path.basename(sourcedir).lower()
cmd = [OPTIONS.boot_signer_path]
cmd.extend(OPTIONS.boot_signer_args)
cmd.extend([path, img.name,
def GetBootableImage(name, prebuilt_name, unpack_dir, tree_subdir,
- info_dict=None):
+ info_dict=None, two_step_image=False):
"""Return a File object with the desired bootable image.
Look for it in 'unpack_dir'/BOOTABLE_IMAGES under the name 'prebuilt_name',
fs_config = "META/" + tree_subdir.lower() + "_filesystem_config.txt"
data = _BuildBootableImage(os.path.join(unpack_dir, tree_subdir),
os.path.join(unpack_dir, fs_config),
- info_dict, has_ramdisk)
+ info_dict, has_ramdisk, two_step_image)
if data:
return File(name, data)
return None
script.AssertOemProperty(prop, oem_dict.get(prop))
+def _WriteRecoveryImageToBoot(script, output_zip):
+ """Find and write recovery image to /boot in two-step OTA.
+
+ In two-step OTAs, we write recovery image to /boot as the first step so that
+ we can reboot to there and install a new recovery image to /recovery.
+ A special "recovery-two-step.img" will be preferred, which encodes the correct
+ path of "/boot". Otherwise the device may show "device is corrupt" message
+ when booting into /boot.
+
+ Fall back to using the regular recovery.img if the two-step recovery image
+ doesn't exist. Note that rebuilding the special image at this point may be
+ infeasible, because we don't have the desired boot signer and keys when
+ calling ota_from_target_files.py.
+ """
+
+ recovery_two_step_img_name = "recovery-two-step.img"
+ recovery_two_step_img_path = os.path.join(
+ OPTIONS.input_tmp, "IMAGES", recovery_two_step_img_name)
+ if os.path.exists(recovery_two_step_img_path):
+ recovery_two_step_img = common.GetBootableImage(
+ recovery_two_step_img_name, recovery_two_step_img_name,
+ OPTIONS.input_tmp, "RECOVERY")
+ common.ZipWriteStr(
+ output_zip, recovery_two_step_img_name, recovery_two_step_img.data)
+ print "two-step package: using %s in stage 1/3" % (
+ recovery_two_step_img_name,)
+ script.WriteRawImage("/boot", recovery_two_step_img_name)
+ else:
+ print "two-step package: using recovery.img in stage 1/3"
+ # The "recovery.img" entry has been written into package earlier.
+ script.WriteRawImage("/boot", "recovery.img")
+
+
def HasRecoveryPatch(target_files_zip):
namelist = [name for name in target_files_zip.namelist()]
return ("SYSTEM/recovery-from-boot.p" in namelist or
script.AppendExtra("""
if get_stage("%(bcb_dev)s") == "2/3" then
""" % bcb_dev)
+
+ # Stage 2/3: Write recovery image to /recovery (currently running /boot).
+ script.Comment("Stage 2/3")
script.WriteRawImage("/recovery", "recovery.img")
script.AppendExtra("""
set_stage("%(bcb_dev)s", "3/3");
else if get_stage("%(bcb_dev)s") == "3/3" then
""" % bcb_dev)
+ # Stage 3/3: Make changes.
+ script.Comment("Stage 3/3")
+
# Dump fingerprints
script.Print("Target: %s" % target_fp)
set_stage("%(bcb_dev)s", "");
""" % bcb_dev)
script.AppendExtra("else\n")
- script.WriteRawImage("/boot", "recovery.img")
+
+ # Stage 1/3: Nothing to verify for full OTA. Write recovery image to /boot.
+ script.Comment("Stage 1/3")
+ _WriteRecoveryImageToBoot(script, output_zip)
+
script.AppendExtra("""
set_stage("%(bcb_dev)s", "2/3");
reboot_now("%(bcb_dev)s", "");
script.AppendExtra("""
if get_stage("%(bcb_dev)s") == "2/3" then
""" % bcb_dev)
+
+ # Stage 2/3: Write recovery image to /recovery (currently running /boot).
+ script.Comment("Stage 2/3")
script.AppendExtra("sleep(20);\n")
script.WriteRawImage("/recovery", "recovery.img")
script.AppendExtra("""
else if get_stage("%(bcb_dev)s") != "3/3" then
""" % bcb_dev)
+ # Stage 1/3: (a) Verify the current system.
+ script.Comment("Stage 1/3")
+
# Dump fingerprints
script.Print(source_fp)
script.Print(target_fp)
device_specific.IncrementalOTA_VerifyEnd()
if OPTIONS.two_step:
- script.WriteRawImage("/boot", "recovery.img")
+ # Stage 1/3: (b) Write recovery image to /boot.
+ _WriteRecoveryImageToBoot(script, output_zip)
+
script.AppendExtra("""
set_stage("%(bcb_dev)s", "2/3");
reboot_now("%(bcb_dev)s", "");
else
""" % bcb_dev)
+ # Stage 3/3: Make changes.
+ script.Comment("Stage 3/3")
+
# Verify the existing partitions.
system_diff.WriteVerifyScript(script, touched_blocks_only=True)
if vendor_diff:
script.AppendExtra("""
if get_stage("%(bcb_dev)s") == "2/3" then
""" % bcb_dev)
+
+ # Stage 2/3: Write recovery image to /recovery (currently running /boot).
+ script.Comment("Stage 2/3")
script.AppendExtra("sleep(20);\n")
script.WriteRawImage("/recovery", "recovery.img")
script.AppendExtra("""
else if get_stage("%(bcb_dev)s") != "3/3" then
""" % bcb_dev)
+ # Stage 1/3: (a) Verify the current system.
+ script.Comment("Stage 1/3")
+
# Dump fingerprints
script.Print("Source: %s" % (source_fp,))
script.Print("Target: %s" % (target_fp,))
device_specific.IncrementalOTA_VerifyEnd()
if OPTIONS.two_step:
- script.WriteRawImage("/boot", "recovery.img")
+ # Stage 1/3: (b) Write recovery image to /boot.
+ _WriteRecoveryImageToBoot(script, output_zip)
+
script.AppendExtra("""
set_stage("%(bcb_dev)s", "2/3");
reboot_now("%(bcb_dev)s", "");
else
""" % bcb_dev)
+ # Stage 3/3: Make changes.
+ script.Comment("Stage 3/3")
+
script.Comment("---- start making changes here ----")
device_specific.IncrementalOTA_InstallBegin()