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

Commit 1c808009 authored by Tianjie Xu's avatar Tianjie Xu
Browse files

Remove vendor & product in secondary payload

We used to carry the full OTA for vendor and product partitions when
generating the secondary payload. Since they are not actually used, we
can remove them to reduce the size of factory OTA packages. For example,
the size for a sargo package reduces from 454M to 283M after the change.

Bug: 140771390
Test: generate and apply a second payload on Pixel
Change-Id: I091dc07db8c345b182d9f5dd8d48f5c209245641
parent d30a9495
Loading
Loading
Loading
Loading
+59 −1
Original line number Original line Diff line number Diff line
@@ -250,6 +250,7 @@ UNZIP_PATTERN = ['IMAGES/*', 'META/*', 'OTA/*', 'RADIO/*']
TARGET_DIFFING_UNZIP_PATTERN = ['BOOT', 'RECOVERY', 'SYSTEM/*', 'VENDOR/*',
TARGET_DIFFING_UNZIP_PATTERN = ['BOOT', 'RECOVERY', 'SYSTEM/*', 'VENDOR/*',
                                'PRODUCT/*', 'SYSTEM_EXT/*', 'ODM/*']
                                'PRODUCT/*', 'SYSTEM_EXT/*', 'ODM/*']
RETROFIT_DAP_UNZIP_PATTERN = ['OTA/super_*.img', AB_PARTITIONS]
RETROFIT_DAP_UNZIP_PATTERN = ['OTA/super_*.img', AB_PARTITIONS]
SECONDARY_IMAGES_SKIP_PARTITIONS = ['odm', 'product', 'system_ext', 'vendor']




class BuildInfo(object):
class BuildInfo(object):
@@ -1792,6 +1793,43 @@ def GetTargetFilesZipForSecondaryImages(input_file, skip_postinstall=False):
  Returns:
  Returns:
    The filename of the target-files.zip for generating secondary payload.
    The filename of the target-files.zip for generating secondary payload.
  """
  """

  def GetInfoForSecondaryImages(info_file):
    """Updates info file for secondary payload generation.

    Scan each line in the info file, and remove the unwanted partitions from
    the dynamic partition list in the related properties. e.g.
    "super_google_dynamic_partitions_partition_list=system vendor product"
    will become "super_google_dynamic_partitions_partition_list=system".

    Args:
      info_file: The input info file. e.g. misc_info.txt.

    Returns:
      A string of the updated info content.
    """

    output_list = []
    with open(info_file) as f:
      lines = f.read().splitlines()

    # The suffix in partition_list variables that follows the name of the
    # partition group.
    LIST_SUFFIX = 'partition_list'
    for line in lines:
      if line.startswith('#') or '=' not in line:
        output_list.append(line)
        continue
      key, value = line.strip().split('=', 1)
      if key == 'dynamic_partition_list' or key.endswith(LIST_SUFFIX):
        partitions = value.split()
        partitions = [partition for partition in partitions if partition
                      not in SECONDARY_IMAGES_SKIP_PARTITIONS]
        output_list.append('{}={}'.format(key, ' '.join(partitions)))
      else:
        output_list.append(line)
    return '\n'.join(output_list)

  target_file = common.MakeTempFile(prefix="targetfiles-", suffix=".zip")
  target_file = common.MakeTempFile(prefix="targetfiles-", suffix=".zip")
  target_zip = zipfile.ZipFile(target_file, 'w', allowZip64=True)
  target_zip = zipfile.ZipFile(target_file, 'w', allowZip64=True)


@@ -1808,12 +1846,32 @@ def GetTargetFilesZipForSecondaryImages(input_file, skip_postinstall=False):
    elif info.filename in ('IMAGES/system.img',
    elif info.filename in ('IMAGES/system.img',
                           'IMAGES/system.map'):
                           'IMAGES/system.map'):
      pass
      pass
    # Images like vendor and product are not needed in the secondary payload.
    elif info.filename in ['IMAGES/{}.img'.format(partition) for partition in
                           SECONDARY_IMAGES_SKIP_PARTITIONS]:
      pass


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


    elif info.filename.startswith(('META/', 'IMAGES/', 'RADIO/')):
    elif info.filename.startswith('META/'):
      # Remove the unnecessary partitions for secondary images from the
      # ab_partitions file.
      if info.filename == AB_PARTITIONS:
        with open(unzipped_file) as f:
          partition_list = f.read().splitlines()
        partition_list = [partition for partition in partition_list if partition
                          and partition not in SECONDARY_IMAGES_SKIP_PARTITIONS]
        common.ZipWriteStr(target_zip, info.filename, '\n'.join(partition_list))
      # Remove the unnecessary partitions from the dynamic partitions list.
      elif (info.filename == 'META/misc_info.txt' or
            info.filename == DYNAMIC_PARTITION_INFO):
        modified_info = GetInfoForSecondaryImages(unzipped_file)
        common.ZipWriteStr(target_zip, info.filename, modified_info)
      else:
        common.ZipWrite(target_zip, unzipped_file, arcname=info.filename)
    elif info.filename.startswith(('IMAGES/', 'RADIO/')):
      common.ZipWrite(target_zip, unzipped_file, arcname=info.filename)
      common.ZipWrite(target_zip, unzipped_file, arcname=info.filename)


  common.ZipClose(target_zip)
  common.ZipClose(target_zip)
+53 −3
Original line number Original line Diff line number Diff line
@@ -588,11 +588,11 @@ class OtaFromTargetFilesTest(test_utils.ReleaseToolsTestCase):


    with zipfile.ZipFile(target_file) as verify_zip:
    with zipfile.ZipFile(target_file) as verify_zip:
      namelist = verify_zip.namelist()
      namelist = verify_zip.namelist()
      ab_partitions = verify_zip.read('META/ab_partitions.txt')


    self.assertIn('META/ab_partitions.txt', namelist)
    self.assertIn('META/ab_partitions.txt', namelist)
    self.assertIn('IMAGES/boot.img', namelist)
    self.assertIn('IMAGES/boot.img', namelist)
    self.assertIn('IMAGES/system.img', namelist)
    self.assertIn('IMAGES/system.img', namelist)
    self.assertIn('IMAGES/vendor.img', namelist)
    self.assertIn('RADIO/bootloader.img', namelist)
    self.assertIn('RADIO/bootloader.img', namelist)
    self.assertIn('RADIO/modem.img', namelist)
    self.assertIn('RADIO/modem.img', namelist)
    self.assertIn(POSTINSTALL_CONFIG, namelist)
    self.assertIn(POSTINSTALL_CONFIG, namelist)
@@ -600,6 +600,9 @@ class OtaFromTargetFilesTest(test_utils.ReleaseToolsTestCase):
    self.assertNotIn('IMAGES/system_other.img', namelist)
    self.assertNotIn('IMAGES/system_other.img', namelist)
    self.assertNotIn('IMAGES/system.map', namelist)
    self.assertNotIn('IMAGES/system.map', namelist)


    expected_ab_partitions = ['boot', 'system', 'bootloader', 'modem']
    self.assertEqual('\n'.join(expected_ab_partitions), ab_partitions)

  @test_utils.SkipIfExternalToolsUnavailable()
  @test_utils.SkipIfExternalToolsUnavailable()
  def test_GetTargetFilesZipForSecondaryImages_skipPostinstall(self):
  def test_GetTargetFilesZipForSecondaryImages_skipPostinstall(self):
    input_file = construct_target_files(secondary=True)
    input_file = construct_target_files(secondary=True)
@@ -612,7 +615,6 @@ class OtaFromTargetFilesTest(test_utils.ReleaseToolsTestCase):
    self.assertIn('META/ab_partitions.txt', namelist)
    self.assertIn('META/ab_partitions.txt', namelist)
    self.assertIn('IMAGES/boot.img', namelist)
    self.assertIn('IMAGES/boot.img', namelist)
    self.assertIn('IMAGES/system.img', namelist)
    self.assertIn('IMAGES/system.img', namelist)
    self.assertIn('IMAGES/vendor.img', namelist)
    self.assertIn('RADIO/bootloader.img', namelist)
    self.assertIn('RADIO/bootloader.img', namelist)
    self.assertIn('RADIO/modem.img', namelist)
    self.assertIn('RADIO/modem.img', namelist)


@@ -633,7 +635,6 @@ class OtaFromTargetFilesTest(test_utils.ReleaseToolsTestCase):
    self.assertIn('META/ab_partitions.txt', namelist)
    self.assertIn('META/ab_partitions.txt', namelist)
    self.assertIn('IMAGES/boot.img', namelist)
    self.assertIn('IMAGES/boot.img', namelist)
    self.assertIn('IMAGES/system.img', namelist)
    self.assertIn('IMAGES/system.img', namelist)
    self.assertIn('IMAGES/vendor.img', namelist)
    self.assertIn(POSTINSTALL_CONFIG, namelist)
    self.assertIn(POSTINSTALL_CONFIG, namelist)


    self.assertNotIn('IMAGES/system_other.img', namelist)
    self.assertNotIn('IMAGES/system_other.img', namelist)
@@ -641,6 +642,55 @@ class OtaFromTargetFilesTest(test_utils.ReleaseToolsTestCase):
    self.assertNotIn('RADIO/bootloader.img', namelist)
    self.assertNotIn('RADIO/bootloader.img', namelist)
    self.assertNotIn('RADIO/modem.img', namelist)
    self.assertNotIn('RADIO/modem.img', namelist)


  @test_utils.SkipIfExternalToolsUnavailable()
  def test_GetTargetFilesZipForSecondaryImages_dynamicPartitions(self):
    input_file = construct_target_files(secondary=True)
    misc_info = '\n'.join([
        'use_dynamic_partition_size=true',
        'use_dynamic_partitions=true',
        'dynamic_partition_list=system vendor product',
        'super_partition_groups=google_dynamic_partitions',
        'super_google_dynamic_partitions_group_size=4873781248',
        'super_google_dynamic_partitions_partition_list=system vendor product',
    ])
    dynamic_partitions_info = '\n'.join([
        'super_partition_groups=google_dynamic_partitions',
        'super_google_dynamic_partitions_group_size=4873781248',
        'super_google_dynamic_partitions_partition_list=system vendor product',
    ])

    with zipfile.ZipFile(input_file, 'a') as append_zip:
      common.ZipWriteStr(append_zip, 'META/misc_info.txt', misc_info)
      common.ZipWriteStr(append_zip, 'META/dynamic_partitions_info.txt',
                         dynamic_partitions_info)

    target_file = GetTargetFilesZipForSecondaryImages(input_file)

    with zipfile.ZipFile(target_file) as verify_zip:
      namelist = verify_zip.namelist()
      updated_misc_info = verify_zip.read('META/misc_info.txt')
      updated_dynamic_partitions_info = verify_zip.read(
          'META/dynamic_partitions_info.txt')

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

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

    # Check the vendor & product are removed from the partitions list.
    expected_misc_info = misc_info.replace('system vendor product',
                                           'system')
    expected_dynamic_partitions_info = dynamic_partitions_info.replace(
        'system vendor product', 'system')
    self.assertEqual(expected_misc_info, updated_misc_info)
    self.assertEqual(expected_dynamic_partitions_info,
                     updated_dynamic_partitions_info)

  @test_utils.SkipIfExternalToolsUnavailable()
  @test_utils.SkipIfExternalToolsUnavailable()
  def test_GetTargetFilesZipWithoutPostinstallConfig(self):
  def test_GetTargetFilesZipWithoutPostinstallConfig(self):
    input_file = construct_target_files()
    input_file = construct_target_files()