Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6c0ddf24 authored by Tao Bao's avatar Tao Bao Committed by Gerrit Code Review
Browse files

Merge "releasetools: Allow skipping postinstall hooks when generating A/B OTAs."

parents 8bfde7c5 15a146a7
Loading
Loading
Loading
Loading
+50 −2
Original line number Diff line number Diff line
@@ -144,6 +144,13 @@ Usage: ota_from_target_files [flags] input_target_files output_ota_package

  --payload_signer_args <args>
      Specify the arguments needed for payload signer.

  --skip_postinstall
      Skip the postinstall hooks when generating an A/B OTA package (default:
      False). Note that this discards ALL the hooks, including non-optional
      ones. Should only be used if caller knows it's safe to do so (e.g. all the
      postinstall work is to dexopt apps and a data wipe will happen immediately
      after). Only meaningful when generating A/B OTAs.
"""

from __future__ import print_function
@@ -151,6 +158,7 @@ from __future__ import print_function
import multiprocessing
import os.path
import shlex
import shutil
import subprocess
import sys
import tempfile
@@ -193,8 +201,11 @@ OPTIONS.payload_signer = None
OPTIONS.payload_signer_args = []
OPTIONS.extracted_input = None
OPTIONS.key_passwords = []
OPTIONS.skip_postinstall = False


METADATA_NAME = 'META-INF/com/android/metadata'
POSTINSTALL_CONFIG = 'META/postinstall_config.txt'
UNZIP_PATTERN = ['IMAGES/*', 'META/*']


@@ -1215,7 +1226,7 @@ endif;
  WriteMetadata(metadata, output_zip)


def GetTargetFilesZipForSecondaryImages(input_file):
def GetTargetFilesZipForSecondaryImages(input_file, skip_postinstall=False):
  """Returns a target-files.zip file for generating secondary payload.

  Although the original target-files.zip already contains secondary slot
@@ -1229,6 +1240,7 @@ def GetTargetFilesZipForSecondaryImages(input_file):

  Args:
    input_file: The input target-files.zip file.
    skip_postinstall: Whether to skip copying the postinstall config file.

  Returns:
    The filename of the target-files.zip for generating secondary payload.
@@ -1247,6 +1259,10 @@ def GetTargetFilesZipForSecondaryImages(input_file):
                           'IMAGES/system.map'):
      pass

    # Skip copying the postinstall config if requested.
    elif skip_postinstall and info.filename == POSTINSTALL_CONFIG:
      pass

    elif info.filename.startswith(('META/', 'IMAGES/')):
      common.ZipWrite(target_zip, unzipped_file, arcname=info.filename)

@@ -1256,6 +1272,31 @@ def GetTargetFilesZipForSecondaryImages(input_file):
  return target_file


def GetTargetFilesZipWithoutPostinstallConfig(input_file):
  """Returns a target-files.zip that's not containing postinstall_config.txt.

  This allows brillo_update_payload script to skip writing all the postinstall
  hooks in the generated payload. The input target-files.zip file will be
  duplicated, with 'META/postinstall_config.txt' skipped. If input_file doesn't
  contain the postinstall_config.txt entry, the input file will be returned.

  Args:
    input_file: The input target-files.zip filename.

  Returns:
    The filename of target-files.zip that doesn't contain postinstall config.
  """
  # We should only make a copy if postinstall_config entry exists.
  with zipfile.ZipFile(input_file, 'r') as input_zip:
    if POSTINSTALL_CONFIG not in input_zip.namelist():
      return input_file

  target_file = common.MakeTempFile(prefix="targetfiles-", suffix=".zip")
  shutil.copyfile(input_file, target_file)
  common.ZipDelete(target_file, POSTINSTALL_CONFIG)
  return target_file


def WriteABOTAPackageWithBrilloScript(target_file, output_file,
                                      source_file=None):
  """Generate an Android OTA package that has A/B update payload."""
@@ -1325,6 +1366,9 @@ def WriteABOTAPackageWithBrilloScript(target_file, output_file,
  # Metadata to comply with Android OTA package format.
  metadata = GetPackageMetadata(target_info, source_info)

  if OPTIONS.skip_postinstall:
    target_file = GetTargetFilesZipWithoutPostinstallConfig(target_file)

  # Generate payload.
  payload = Payload()
  payload.Generate(target_file, source_file)
@@ -1341,7 +1385,8 @@ def WriteABOTAPackageWithBrilloScript(target_file, output_file,
  if OPTIONS.include_secondary:
    # We always include a full payload for the secondary slot, even when
    # building an incremental OTA. See the comments for "--include_secondary".
    secondary_target_file = GetTargetFilesZipForSecondaryImages(target_file)
    secondary_target_file = GetTargetFilesZipForSecondaryImages(
        target_file, OPTIONS.skip_postinstall)
    secondary_payload = Payload(secondary=True)
    secondary_payload.Generate(secondary_target_file)
    secondary_payload.Sign(payload_signer)
@@ -1469,6 +1514,8 @@ def main(argv):
      OPTIONS.payload_signer_args = shlex.split(a)
    elif o == "--extracted_input_target_files":
      OPTIONS.extracted_input = a
    elif o == "--skip_postinstall":
      OPTIONS.skip_postinstall = True
    else:
      return False
    return True
@@ -1498,6 +1545,7 @@ def main(argv):
                                 "payload_signer=",
                                 "payload_signer_args=",
                                 "extracted_input_target_files=",
                                 "skip_postinstall",
                             ], extra_option_handler=option_handler)

  if len(args) != 2:
+44 −1
Original line number Diff line number Diff line
@@ -24,7 +24,9 @@ import common
import test_utils
from ota_from_target_files import (
    _LoadOemDicts, BuildInfo, GetPackageMetadata,
    GetTargetFilesZipForSecondaryImages, Payload, PayloadSigner,
    GetTargetFilesZipForSecondaryImages,
    GetTargetFilesZipWithoutPostinstallConfig,
    Payload, PayloadSigner, POSTINSTALL_CONFIG,
    WriteFingerprintAssertion)


@@ -37,6 +39,16 @@ def construct_target_files(secondary=False):
        'META/update_engine_config.txt',
        "PAYLOAD_MAJOR_VERSION=2\nPAYLOAD_MINOR_VERSION=4\n")

    # META/postinstall_config.txt
    target_files_zip.writestr(
        POSTINSTALL_CONFIG,
        '\n'.join([
            "RUN_POSTINSTALL_system=true",
            "POSTINSTALL_PATH_system=system/bin/otapreopt_script",
            "FILESYSTEM_TYPE_system=ext4",
            "POSTINSTALL_OPTIONAL_system=true",
        ]))

    # META/ab_partitions.txt
    ab_partitions = ['boot', 'system', 'vendor']
    target_files_zip.writestr(
@@ -539,10 +551,41 @@ class OtaFromTargetFilesTest(unittest.TestCase):
    self.assertIn('IMAGES/boot.img', namelist)
    self.assertIn('IMAGES/system.img', namelist)
    self.assertIn('IMAGES/vendor.img', namelist)
    self.assertIn(POSTINSTALL_CONFIG, namelist)

    self.assertNotIn('IMAGES/system_other.img', namelist)
    self.assertNotIn('IMAGES/system.map', namelist)

  def test_GetTargetFilesZipForSecondaryImages_skipPostinstall(self):
    input_file = construct_target_files(secondary=True)
    target_file = GetTargetFilesZipForSecondaryImages(
        input_file, skip_postinstall=True)

    with zipfile.ZipFile(target_file) as verify_zip:
      namelist = verify_zip.namelist()

    self.assertIn('META/ab_partitions.txt', namelist)
    self.assertIn('IMAGES/boot.img', namelist)
    self.assertIn('IMAGES/system.img', namelist)
    self.assertIn('IMAGES/vendor.img', namelist)

    self.assertNotIn('IMAGES/system_other.img', namelist)
    self.assertNotIn('IMAGES/system.map', namelist)
    self.assertNotIn(POSTINSTALL_CONFIG, namelist)

  def test_GetTargetFilesZipWithoutPostinstallConfig(self):
    input_file = construct_target_files()
    target_file = GetTargetFilesZipWithoutPostinstallConfig(input_file)
    with zipfile.ZipFile(target_file) as verify_zip:
      self.assertNotIn(POSTINSTALL_CONFIG, verify_zip.namelist())

  def test_GetTargetFilesZipWithoutPostinstallConfig_missingEntry(self):
    input_file = construct_target_files()
    common.ZipDelete(input_file, POSTINSTALL_CONFIG)
    target_file = GetTargetFilesZipWithoutPostinstallConfig(input_file)
    with zipfile.ZipFile(target_file) as verify_zip:
      self.assertNotIn(POSTINSTALL_CONFIG, verify_zip.namelist())


class PayloadSignerTest(unittest.TestCase):