コード例 #1
0
ファイル: test_common.py プロジェクト: BEAOSP/build
 def test_LoadInfoDict_missingMetaMiscInfoTxt(self):
     target_files = self._test_LoadInfoDict_createTargetFiles(
         self.INFO_DICT_DEFAULT, 'BOOT/RAMDISK/system/etc/recovery.fstab')
     common.ZipDelete(target_files, 'META/misc_info.txt')
     with zipfile.ZipFile(target_files, 'r') as target_files_zip:
         self.assertRaises(ValueError, common.LoadInfoDict,
                           target_files_zip)
コード例 #2
0
    def RepackApexPayload(self, payload_dir, payload_key, signing_args=None):
        """Rebuilds the apex file with the updated payload directory."""
        apex_dir = common.MakeTempDir()
        # Extract the apex file and reuse its meta files as repack parameters.
        common.UnzipToDir(self.apex_path, apex_dir)
        arguments_dict = {
            'manifest': os.path.join(apex_dir, 'apex_manifest.pb'),
            'build_info': os.path.join(apex_dir, 'apex_build_info.pb'),
            'key': payload_key,
        }
        for filename in arguments_dict.values():
            assert os.path.exists(filename), 'file {} not found'.format(
                filename)

        # The repack process will add back these files later in the payload image.
        for name in ['apex_manifest.pb', 'apex_manifest.json', 'lost+found']:
            path = os.path.join(payload_dir, name)
            if os.path.isfile(path):
                os.remove(path)
            elif os.path.isdir(path):
                shutil.rmtree(path)

        # TODO(xunchang) the signing process can be improved by using
        # '--unsigned_payload_only'. But we need to parse the vbmeta earlier for
        # the signing arguments, e.g. algorithm, salt, etc.
        payload_img = os.path.join(apex_dir, APEX_PAYLOAD_IMAGE)
        generate_image_cmd = [
            'apexer', '--force', '--payload_only', '--do_not_check_keyname',
            '--apexer_tool_path',
            os.getenv('PATH')
        ]
        for key, val in arguments_dict.items():
            generate_image_cmd.extend(['--' + key, val])

        # Add quote to the signing_args as we will pass
        # --signing_args "--signing_helper_with_files=%path" to apexer
        if signing_args:
            generate_image_cmd.extend(
                ['--signing_args', '"{}"'.format(signing_args)])

        # optional arguments for apex repacking
        manifest_json = os.path.join(apex_dir, 'apex_manifest.json')
        if os.path.exists(manifest_json):
            generate_image_cmd.extend(['--manifest_json', manifest_json])
        generate_image_cmd.extend([payload_dir, payload_img])
        if OPTIONS.verbose:
            generate_image_cmd.append('-v')
        common.RunAndCheckOutput(generate_image_cmd)

        # Add the payload image back to the apex file.
        common.ZipDelete(self.apex_path, APEX_PAYLOAD_IMAGE)
        with zipfile.ZipFile(self.apex_path, 'a',
                             allowZip64=True) as output_apex:
            common.ZipWrite(output_apex,
                            payload_img,
                            APEX_PAYLOAD_IMAGE,
                            compress_type=zipfile.ZIP_STORED)
        return self.apex_path
コード例 #3
0
def SignApex(apex_data,
             payload_key,
             container_key,
             container_pw,
             codename_to_api_level_map,
             signing_args=None):
    """Signs the current APEX with the given payload/container keys.

  Args:
    apex_data: Raw APEX data.
    payload_key: The path to payload signing key (w/o extension).
    container_key: The path to container signing key (w/o extension).
    container_pw: The matching password of the container_key, or None.
    codename_to_api_level_map: A dict that maps from codename to API level.
    signing_args: Additional args to be passed to the payload signer.

  Returns:
    (signed_apex, payload_key_name): signed_apex is the path to the signed APEX
        file; payload_key_name is a str of the payload signing key name (e.g.
        com.android.tzdata).
  """
    apex_file = common.MakeTempFile(prefix='apex-', suffix='.apex')
    with open(apex_file, 'wb') as apex_fp:
        apex_fp.write(apex_data)

    APEX_PAYLOAD_IMAGE = 'apex_payload.img'

    # Signing an APEX is a two step process.
    # 1. Extract and sign the APEX_PAYLOAD_IMAGE entry with the given payload_key.
    payload_dir = common.MakeTempDir(prefix='apex-payload-')
    with zipfile.ZipFile(apex_file) as apex_fd:
        payload_file = apex_fd.extract(APEX_PAYLOAD_IMAGE, payload_dir)

    payload_info = apex_utils.ParseApexPayloadInfo(payload_file)
    apex_utils.SignApexPayload(payload_file, payload_key,
                               payload_info['apex.key'],
                               payload_info['Algorithm'], payload_info['Salt'],
                               signing_args)

    common.ZipDelete(apex_file, APEX_PAYLOAD_IMAGE)
    apex_zip = zipfile.ZipFile(apex_file, 'a')
    common.ZipWrite(apex_zip, payload_file, arcname=APEX_PAYLOAD_IMAGE)
    common.ZipClose(apex_zip)

    # 2. Sign the overall APEX container with container_key.
    signed_apex = common.MakeTempFile(prefix='apex-container-', suffix='.apex')
    common.SignFile(apex_file,
                    signed_apex,
                    container_key,
                    container_pw,
                    codename_to_api_level_map=codename_to_api_level_map)

    signed_and_aligned_apex = common.MakeTempFile(prefix='apex-container-',
                                                  suffix='.apex')
    common.RunAndCheckOutput(
        ['zipalign', '-f', '4096', signed_apex, signed_and_aligned_apex])

    return (signed_and_aligned_apex, payload_info['apex.key'])
コード例 #4
0
  def test_GetTargetFilesZipForSecondaryImages_withoutRadioImages(self):
    input_file = construct_target_files(secondary=True)
    common.ZipDelete(input_file, 'RADIO/bootloader.img')
    common.ZipDelete(input_file, 'RADIO/modem.img')
    target_file = GetTargetFilesZipForSecondaryImages(input_file)

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

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

    self.assertNotIn('IMAGES/boot.img', namelist)
    self.assertNotIn('IMAGES/system_other.img', namelist)
    self.assertNotIn('IMAGES/system.map', namelist)
    self.assertNotIn('RADIO/bootloader.img', namelist)
    self.assertNotIn('RADIO/modem.img', namelist)
コード例 #5
0
    def test_ZipDelete(self):
        zip_file = tempfile.NamedTemporaryFile(delete=False, suffix='.zip')
        output_zip = zipfile.ZipFile(zip_file.name,
                                     'w',
                                     compression=zipfile.ZIP_DEFLATED)
        with tempfile.NamedTemporaryFile() as entry_file:
            entry_file.write(os.urandom(1024))
            common.ZipWrite(output_zip, entry_file.name, arcname='Test1')
            common.ZipWrite(output_zip, entry_file.name, arcname='Test2')
            common.ZipWrite(output_zip, entry_file.name, arcname='Test3')
            common.ZipClose(output_zip)
        zip_file.close()

        try:
            common.ZipDelete(zip_file.name, 'Test2')
            with zipfile.ZipFile(zip_file.name, 'r') as check_zip:
                entries = check_zip.namelist()
                self.assertTrue('Test1' in entries)
                self.assertFalse('Test2' in entries)
                self.assertTrue('Test3' in entries)

            self.assertRaises(AssertionError, common.ZipDelete, zip_file.name,
                              'Test2')
            with zipfile.ZipFile(zip_file.name, 'r') as check_zip:
                entries = check_zip.namelist()
                self.assertTrue('Test1' in entries)
                self.assertFalse('Test2' in entries)
                self.assertTrue('Test3' in entries)

            common.ZipDelete(zip_file.name, ['Test3'])
            with zipfile.ZipFile(zip_file.name, 'r') as check_zip:
                entries = check_zip.namelist()
                self.assertTrue('Test1' in entries)
                self.assertFalse('Test2' in entries)
                self.assertFalse('Test3' in entries)

            common.ZipDelete(zip_file.name, ['Test1', 'Test2'])
            with zipfile.ZipFile(zip_file.name, 'r') as check_zip:
                entries = check_zip.namelist()
                self.assertFalse('Test1' in entries)
                self.assertFalse('Test2' in entries)
                self.assertFalse('Test3' in entries)
        finally:
            os.remove(zip_file.name)
コード例 #6
0
def ReplaceUpdatedFiles(zip_filename, files_list):
  """Updates all the ZIP entries listed in files_list.

  For now the list includes META/care_map.pb, and the related files under
  SYSTEM/ after rebuilding recovery.
  """
  common.ZipDelete(zip_filename, files_list)
  output_zip = zipfile.ZipFile(zip_filename, "a",
                               compression=zipfile.ZIP_DEFLATED,
                               allowZip64=True)
  for item in files_list:
    file_path = os.path.join(OPTIONS.input_tmp, item)
    assert os.path.exists(file_path)
    common.ZipWrite(output_zip, file_path, arcname=item)
  common.ZipClose(output_zip)
コード例 #7
0
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
コード例 #8
0
ファイル: apex_utils.py プロジェクト: Pie-onyx/build_make
def SignUncompressedApex(avbtool, apex_file, payload_key, container_key,
                         container_pw, apk_keys, codename_to_api_level_map,
                         no_hashtree, signing_args=None):
  """Signs the current uncompressed APEX with the given payload/container keys.

  Args:
    apex_file: Uncompressed APEX file.
    payload_key: The path to payload signing key (w/ extension).
    container_key: The path to container signing key (w/o extension).
    container_pw: The matching password of the container_key, or None.
    apk_keys: A dict that holds the signing keys for apk files.
    codename_to_api_level_map: A dict that maps from codename to API level.
    no_hashtree: Don't include hashtree in the signed APEX.
    signing_args: Additional args to be passed to the payload signer.

  Returns:
    The path to the signed APEX file.
  """
  # 1. Extract the apex payload image and sign the containing apk files. Repack
  # the apex file after signing.
  apk_signer = ApexApkSigner(apex_file, container_pw,
                             codename_to_api_level_map)
  apex_file = apk_signer.ProcessApexFile(apk_keys, payload_key, signing_args)

  # 2a. Extract and sign the APEX_PAYLOAD_IMAGE entry with the given
  # payload_key.
  payload_dir = common.MakeTempDir(prefix='apex-payload-')
  with zipfile.ZipFile(apex_file) as apex_fd:
    payload_file = apex_fd.extract(APEX_PAYLOAD_IMAGE, payload_dir)
    zip_items = apex_fd.namelist()

  payload_info = ParseApexPayloadInfo(avbtool, payload_file)
  if no_hashtree is None:
    no_hashtree = payload_info.get("Tree Size", 0) == 0
  SignApexPayload(
      avbtool,
      payload_file,
      payload_key,
      payload_info['apex.key'],
      payload_info['Algorithm'],
      payload_info['Salt'],
      payload_info['Hash Algorithm'],
      no_hashtree,
      signing_args)

  # 2b. Update the embedded payload public key.
  payload_public_key = common.ExtractAvbPublicKey(avbtool, payload_key)
  common.ZipDelete(apex_file, APEX_PAYLOAD_IMAGE)
  if APEX_PUBKEY in zip_items:
    common.ZipDelete(apex_file, APEX_PUBKEY)
  apex_zip = zipfile.ZipFile(apex_file, 'a', allowZip64=True)
  common.ZipWrite(apex_zip, payload_file, arcname=APEX_PAYLOAD_IMAGE)
  common.ZipWrite(apex_zip, payload_public_key, arcname=APEX_PUBKEY)
  common.ZipClose(apex_zip)

  # 3. Sign the APEX container with container_key.
  signed_apex = common.MakeTempFile(prefix='apex-container-', suffix='.apex')

  # Specify the 4K alignment when calling SignApk.
  extra_signapk_args = OPTIONS.extra_signapk_args[:]
  extra_signapk_args.extend(['-a', '4096', '--align-file-size'])

  password = container_pw.get(container_key) if container_pw else None
  common.SignFile(
      apex_file,
      signed_apex,
      container_key,
      password,
      codename_to_api_level_map=codename_to_api_level_map,
      extra_signapk_args=extra_signapk_args)

  return signed_apex
コード例 #9
0
 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())
コード例 #10
0
 def test_Generate_invalidInput(self):
   target_file = construct_target_files()
   common.ZipDelete(target_file, 'IMAGES/vendor.img')
   payload = Payload()
   self.assertRaises(common.ExternalError, payload.Generate, target_file)
コード例 #11
0
def GetTargetFilesZipForRetrofitDynamicPartitions(input_file,
                                                  super_block_devices,
                                                  dynamic_partition_list):
    """Returns a target-files.zip for retrofitting dynamic partitions.

  This allows brillo_update_payload to generate an OTA based on the exact
  bits on the block devices. Postinstall is disabled.

  Args:
    input_file: The input target-files.zip filename.
    super_block_devices: The list of super block devices
    dynamic_partition_list: The list of dynamic partitions

  Returns:
    The filename of target-files.zip with *.img replaced with super_*.img for
    each block device in super_block_devices.
  """
    assert super_block_devices, "No super_block_devices are specified."

    replace = {
        'OTA/super_{}.img'.format(dev): 'IMAGES/{}.img'.format(dev)
        for dev in super_block_devices
    }

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

    with zipfile.ZipFile(input_file) as input_zip:
        namelist = input_zip.namelist()

    input_tmp = common.UnzipTemp(input_file, RETROFIT_DAP_UNZIP_PATTERN)

    # Remove partitions from META/ab_partitions.txt that is in
    # dynamic_partition_list but not in super_block_devices so that
    # brillo_update_payload won't generate update for those logical partitions.
    ab_partitions_file = os.path.join(input_tmp, *AB_PARTITIONS.split('/'))
    with open(ab_partitions_file) as f:
        ab_partitions_lines = f.readlines()
        ab_partitions = [line.strip() for line in ab_partitions_lines]
    # Assert that all super_block_devices are in ab_partitions
    super_device_not_updated = [
        partition for partition in super_block_devices
        if partition not in ab_partitions
    ]
    assert not super_device_not_updated, \
        "{} is in super_block_devices but not in {}".format(
            super_device_not_updated, AB_PARTITIONS)
    # ab_partitions -= (dynamic_partition_list - super_block_devices)
    new_ab_partitions = common.MakeTempFile(prefix="ab_partitions",
                                            suffix=".txt")
    with open(new_ab_partitions, 'w') as f:
        for partition in ab_partitions:
            if (partition in dynamic_partition_list
                    and partition not in super_block_devices):
                logger.info("Dropping %s from ab_partitions.txt", partition)
                continue
            f.write(partition + "\n")
    to_delete = [AB_PARTITIONS]

    # Always skip postinstall for a retrofit update.
    to_delete += [POSTINSTALL_CONFIG]

    # Delete dynamic_partitions_info.txt so that brillo_update_payload thinks this
    # is a regular update on devices without dynamic partitions support.
    to_delete += [DYNAMIC_PARTITION_INFO]

    # Remove the existing partition images as well as the map files.
    to_delete += list(replace.values())
    to_delete += ['IMAGES/{}.map'.format(dev) for dev in super_block_devices]

    common.ZipDelete(target_file, to_delete)

    target_zip = zipfile.ZipFile(target_file, 'a', allowZip64=True)

    # Write super_{foo}.img as {foo}.img.
    for src, dst in replace.items():
        assert src in namelist, \
            'Missing {} in {}; {} cannot be written'.format(src, input_file, dst)
        unzipped_file = os.path.join(input_tmp, *src.split('/'))
        common.ZipWrite(target_zip, unzipped_file, arcname=dst)

    # Write new ab_partitions.txt file
    common.ZipWrite(target_zip, new_ab_partitions, arcname=AB_PARTITIONS)

    common.ZipClose(target_zip)

    return target_file
コード例 #12
0
def SignApex(apex_data,
             payload_key,
             container_key,
             container_pw,
             codename_to_api_level_map,
             signing_args=None):
    """Signs the current APEX with the given payload/container keys.

  Args:
    apex_data: Raw APEX data.
    payload_key: The path to payload signing key (w/ extension).
    container_key: The path to container signing key (w/o extension).
    container_pw: The matching password of the container_key, or None.
    codename_to_api_level_map: A dict that maps from codename to API level.
    signing_args: Additional args to be passed to the payload signer.

  Returns:
    The path to the signed APEX file.
  """
    apex_file = common.MakeTempFile(prefix='apex-', suffix='.apex')
    with open(apex_file, 'wb') as apex_fp:
        apex_fp.write(apex_data)

    APEX_PAYLOAD_IMAGE = 'apex_payload.img'
    APEX_PUBKEY = 'apex_pubkey'

    # 1a. Extract and sign the APEX_PAYLOAD_IMAGE entry with the given
    # payload_key.
    payload_dir = common.MakeTempDir(prefix='apex-payload-')
    with zipfile.ZipFile(apex_file) as apex_fd:
        payload_file = apex_fd.extract(APEX_PAYLOAD_IMAGE, payload_dir)
        zip_items = apex_fd.namelist()

    payload_info = ParseApexPayloadInfo(payload_file)
    SignApexPayload(payload_file, payload_key, payload_info['apex.key'],
                    payload_info['Algorithm'], payload_info['Salt'],
                    signing_args)

    # 1b. Update the embedded payload public key.
    payload_public_key = common.ExtractAvbPublicKey(payload_key)

    common.ZipDelete(apex_file, APEX_PAYLOAD_IMAGE)
    if APEX_PUBKEY in zip_items:
        common.ZipDelete(apex_file, APEX_PUBKEY)
    apex_zip = zipfile.ZipFile(apex_file, 'a')
    common.ZipWrite(apex_zip, payload_file, arcname=APEX_PAYLOAD_IMAGE)
    common.ZipWrite(apex_zip, payload_public_key, arcname=APEX_PUBKEY)
    common.ZipClose(apex_zip)

    # 2. Align the files at page boundary (same as in apexer).
    aligned_apex = common.MakeTempFile(prefix='apex-container-',
                                       suffix='.apex')
    common.RunAndCheckOutput(
        ['zipalign', '-f', '4096', apex_file, aligned_apex])

    # 3. Sign the APEX container with container_key.
    signed_apex = common.MakeTempFile(prefix='apex-container-', suffix='.apex')

    # Specify the 4K alignment when calling SignApk.
    extra_signapk_args = OPTIONS.extra_signapk_args[:]
    extra_signapk_args.extend(['-a', '4096'])

    common.SignFile(aligned_apex,
                    signed_apex,
                    container_key,
                    container_pw,
                    codename_to_api_level_map=codename_to_api_level_map,
                    extra_signapk_args=extra_signapk_args)

    return signed_apex