def GenerateNonAbOtaPackage(target_file, output_file, source_file=None): """Generates a non-A/B OTA package.""" # Check the loaded info dicts first. if OPTIONS.info_dict.get("no_recovery") == "true": raise common.ExternalError( "--- target build has specified no recovery ---") # Non-A/B OTAs rely on /cache partition to store temporary files. cache_size = OPTIONS.info_dict.get("cache_size") if cache_size is None: logger.warning("--- can't determine the cache partition size ---") OPTIONS.cache_size = cache_size if OPTIONS.extra_script is not None: with open(OPTIONS.extra_script) as fp: OPTIONS.extra_script = fp.read() if OPTIONS.extracted_input is not None: OPTIONS.input_tmp = OPTIONS.extracted_input else: logger.info("unzipping target target-files...") OPTIONS.input_tmp = common.UnzipTemp(target_file, UNZIP_PATTERN) OPTIONS.target_tmp = OPTIONS.input_tmp # If the caller explicitly specified the device-specific extensions path via # -s / --device_specific, use that. Otherwise, use META/releasetools.py if it # is present in the target target_files. Otherwise, take the path of the file # from 'tool_extensions' in the info dict and look for that in the local # filesystem, relative to the current directory. if OPTIONS.device_specific is None: from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py") if os.path.exists(from_input): logger.info("(using device-specific extensions from target_files)") OPTIONS.device_specific = from_input else: OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions") if OPTIONS.device_specific is not None: OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific) # Generate a full OTA. if source_file is None: with zipfile.ZipFile(target_file) as input_zip: WriteFullOTAPackage( input_zip, output_file) # Generate an incremental OTA. else: logger.info("unzipping source target-files...") OPTIONS.source_tmp = common.UnzipTemp( OPTIONS.incremental_source, UNZIP_PATTERN) with zipfile.ZipFile(target_file) as input_zip, \ zipfile.ZipFile(source_file) as source_zip: WriteBlockIncrementalOTAPackage( input_zip, source_zip, output_file)
def GetBootloaderImagesfromFls(unpack_dir, variant=None): """ Non-EFI bootloaders (example Sofia and its variants), comprise of various partitions. The partitions are obtained from get_bootloader_list(). Extract and return the *LoadMap.bin files from the *.fls files. """ bootloader_list = get_bootloader_list(unpack_dir) if variant: provdata_name = os.path.join(unpack_dir, "RADIO", "provdata_" + variant + ".zip") else: provdata_name = os.path.join(unpack_dir, "RADIO", "provdata" + ".zip") provdata, provdata_zip = common.UnzipTemp(provdata_name) additional_data_hash = collections.OrderedDict() partition_to_target = get_partition_target_hash(unpack_dir) platform_efi, platform_sflte = CheckIfSocEFI(unpack_dir, variant) for loader_partition in bootloader_list: curr_loader = partition_to_target[loader_partition] loader_filepath = os.path.join(provdata, curr_loader) extract = tempfile.mkdtemp(prefix=curr_loader) common.OPTIONS.tempfiles.append(extract) flstool = os.path.join(provdata, "FlsTool") cmd = [flstool, "-x", loader_filepath, "-o", extract] try: p = common.Run(cmd) except Exception as exc: print "Error: Unable to execute command: {}".format(' '.join(cmd)) raise exc p.communicate() assert p.returncode == 0, "FlsTool failed to extract LoadMap.bin" if platform_sflte: #for psi: it is verfied by bootrom, #so no need add secpack header, need bypass; #for bootloader: the combinded images in this partition already has secpack #so no need add secpack header, need bypass if (loader_partition == 'psi') or (loader_partition == 'bootloader'): for current_file in os.listdir(extract): if fnmatch.fnmatch(current_file, '*LoadMap0.bin'): loader_datafile = current_file else: #generate Merged.secbin with tool binary_merge GenerateBootloaderSecbin(extract, variant) for current_file in os.listdir(extract): if fnmatch.fnmatch(current_file, 'Merged.secbin'): loader_datafile = current_file else: for current_file in os.listdir(extract): if fnmatch.fnmatch(current_file, '*LoadMap0.bin'): loader_datafile = current_file loader_abspath = os.path.join(extract, loader_datafile) assert loader_datafile is not None, "Error in extracting the LoadMap.bin" loader_file = open(loader_abspath) loader_data = loader_file.read() additional_data_hash[loader_partition] = loader_data loader_file.close() return additional_data_hash
def ImgFromTargetFiles(input_file, output_file): """Creates an image archive from the input target_files zip. Args: input_file: Path to the input target_files zip. output_file: Output filename. Raises: ValueError: On invalid input. """ if not zipfile.is_zipfile(input_file): raise ValueError("%s is not a valid zipfile" % input_file) logger.info("Building image zip from target files zip.") # We need files under IMAGES/, OTA/, META/ for img_from_target_files.py. # However, common.LoadInfoDict() may read additional files under BOOT/, # RECOVERY/ and ROOT/. So unzip everything from the target_files.zip. input_tmp = common.UnzipTemp(input_file) LoadOptions(input_tmp) output_zip = zipfile.ZipFile(output_file, "w", compression=zipfile.ZIP_DEFLATED, allowZip64=not OPTIONS.sparse_userimages) try: CopyInfo(input_tmp, output_zip) CopyUserImages(input_tmp, output_zip) WriteSuperImages(input_tmp, output_zip) finally: logger.info("cleaning up...") common.ZipClose(output_zip)
def main(argv): def option_handler(): return True args = common.ParseOptions(argv, __doc__, extra_opts="", extra_long_opts=[], extra_option_handler=option_handler) if len(args) != 1: common.Usage(__doc__) sys.exit(1) logging_format = '%(asctime)s - %(filename)s - %(levelname)-8s: %(message)s' date_format = '%Y/%m/%d %H:%M:%S' logging.basicConfig(level=logging.INFO, format=logging_format, datefmt=date_format) logging.info("Unzipping the input target_files.zip: %s", args[0]) input_tmp, input_zip = common.UnzipTemp(args[0]) ValidateFileConsistency(input_zip, input_tmp) info_dict = common.LoadInfoDict(input_tmp) ValidateInstallRecoveryScript(input_tmp, info_dict) # TODO: Check if the OTA keys have been properly updated (the ones on /system, # in recovery image). logging.info("Done.")
def test_GetSparseImage_systemRootImage_filenameWithExtraLeadingSlash(self): target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip') with zipfile.ZipFile(target_files, 'w') as target_files_zip: target_files_zip.write( test_utils.construct_sparse_image([(0xCAC2, 16)]), arcname='IMAGES/system.img') target_files_zip.writestr( 'IMAGES/system.map', '\n'.join([ '//system/file1 1-5 9-10', '//system/file2 11-12', '/system/app/file3 13-15'])) target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7)) # '/system/file2' has less blocks listed (2) than actual (3). target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3)) # '/system/app/file3' has less blocks listed (3) than actual (4). target_files_zip.writestr('SYSTEM/app/file3', os.urandom(4096 * 4)) tempdir = common.UnzipTemp(target_files) with zipfile.ZipFile(target_files, 'r') as input_zip: sparse_image = common.GetSparseImage('system', tempdir, input_zip, False) self.assertFalse(sparse_image.file_map['//system/file1'].extra) self.assertTrue(sparse_image.file_map['//system/file2'].extra['incomplete']) self.assertTrue( sparse_image.file_map['/system/app/file3'].extra['incomplete'])
def main(argv): def option_handler(o, a): if o in ("-I", "--ifwi-directory"): OPTIONS.ifwi_directory = a elif o in ("-A", "--avb-key"): OPTIONS.avb_key = a OPTIONS.all_keys.add(a) elif o in ("-K", "--oem-key"): OPTIONS.oem_key = a OPTIONS.all_keys.add(a) elif o in ("-V", "--variant"): OPTIONS.variant = a else: return False return True args = common.ParseOptions(argv, __doc__, extra_opts="I:A:K:V:", extra_long_opts=[ "ifwi-directory=", "avb-key=", "oem-key=", "variant=" ], extra_option_handler=option_handler) if len(args) != 2: common.Usage(__doc__) sys.exit(1) output_fastboot_fn = args[1] print("Extracting the provdata.zip") prov_file = "provdata_" + OPTIONS.variant + ".zip" unpack_dir = common.UnzipTemp(args[0]) input_zip = zipfile.ZipFile(args[0], "r") input_provzip = zipfile.ZipFile( os.path.join(unpack_dir, "RADIO", prov_file), "r") print("Parsing build.prop for target_product") d = {} try: with open(os.path.join(unpack_dir, "SYSTEM", "build.prop")) as f: d = common.LoadDictionaryFromLines(f.read().split("\n")) except IOError as e: if e.errno == errno.ENOENT: raise KeyError(f) OPTIONS.target_product = d["ro.product.system.name"] print("Processing private keys") OPTIONS.info_dict = common.LoadInfoDict(input_zip) passwords = common.GetKeyPasswords(OPTIONS.all_keys) #process the provdata.zip to generate resigned one process_provzip(input_provzip, output_fastboot_fn) common.ZipClose(input_zip) print("Extract done.")
def MakeVFATFilesystem(root_zip, filename, title="ANDROIDIA", size=0, block_size=None, extra_size=0, extra_files=[], zipped=True): """Create a VFAT filesystem image with all the files in the provided root zipfile. The size of the filesystem, if not provided by the caller, will be 101% the size of the containing files""" if zipped: root = common.UnzipTemp(root_zip) root_zip = zipfile.ZipFile(root_zip, "r") else: root = root_zip for fn_src, fn_dest in extra_files: fn_dest = os.path.join(root, fn_dest) if not os.path.exists(os.path.dirname(fn_dest)): os.makedirs(os.path.dirname(fn_dest)) shutil.copy(fn_src, fn_dest) if size == 0: for dpath, dnames, fnames in os.walk(root): for f in fnames: size += os.path.getsize(os.path.join(dpath, f)) # Add 1% extra space, minimum 32K extra = size / 100 if extra < (32 * 1024): extra = 32 * 1024 size += extra size += extra_size # Round the size of the disk up to 32K so that total sectors is # a multiple of sectors per track (mtools complains otherwise) mod = size % (32 * 1024) if mod != 0: size = size + (32 * 1024) - mod # mtools freaks out otherwise if os.path.exists(filename): os.unlink(filename) add_dir_to_path("/sbin") cmd = ["mkdosfs"] if block_size: cmd.extend(["-S", str(block_size)]) cmd.extend(["-n", title, "-C", filename, str(size / 1024)]) try: p = common.Run(cmd) except Exception as exc: print("Error: Unable to execute command: {}".format(' '.join(cmd))) raise exc p.wait() assert p.returncode == 0, "mkdosfs failed" for f in os.listdir(root): in_p = os.path.join(root, f) out_p = os.path.relpath(in_p, root) PutFatFile(filename, in_p, out_p)
def test_LoadInfoDict_dirInput_legacyRecoveryFstabPath(self): target_files = self._test_LoadInfoDict_createTargetFiles( self.INFO_DICT_DEFAULT, 'BOOT/RAMDISK/system/etc/recovery.fstab') unzipped = common.UnzipTemp(target_files) loaded_dict = common.LoadInfoDict(unzipped) self.assertEqual(3, loaded_dict['recovery_api_version']) self.assertEqual(2, loaded_dict['fstab_version']) self.assertIn('/', loaded_dict['fstab']) self.assertIn('/system', loaded_dict['fstab'])
def main(argv): # This allows modifying the value from inner function. bootable_only_array = [False] def option_handler(o, _): if o in ("-z", "--bootable_zip"): bootable_only_array[0] = True else: return False return True args = common.ParseOptions(argv, __doc__, extra_opts="z", extra_long_opts=["bootable_zip"], extra_option_handler=option_handler) bootable_only = bootable_only_array[0] if len(args) != 2: common.Usage(__doc__) sys.exit(1) common.InitLogging() target_files = args[0] if os.path.isdir(target_files): logger.info("Building image zip from extracted target files.") OPTIONS.input_tmp = target_files elif zipfile.is_zipfile(target_files): logger.info("Building image zip from target files zip.") OPTIONS.input_tmp = common.UnzipTemp(args[0], ["IMAGES/*", "OTA/*"]) else: raise ValueError("%s is not a valid path." % target_files) output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED) CopyInfo(output_zip) try: images_path = os.path.join(OPTIONS.input_tmp, "IMAGES") # A target-files zip must contain the images since Lollipop. assert os.path.exists(images_path) for image in sorted(os.listdir(images_path)): if bootable_only and image not in ("boot.img", "recovery.img"): continue if not image.endswith(".img"): continue if image == "recovery-two-step.img": continue common.ZipWrite(output_zip, os.path.join(images_path, image), image) finally: logger.info("cleaning up...") common.ZipClose(output_zip) logger.info("done.")
def AddImagesToTargetFiles(filename): OPTIONS.input_tmp, input_zip = common.UnzipTemp(filename) for n in input_zip.namelist(): if n.startswith("IMAGES/"): print "target_files appears to already contain images." sys.exit(1) try: input_zip.getinfo("VENDOR/") has_vendor = True except KeyError: has_vendor = False OPTIONS.info_dict = common.LoadInfoDict(input_zip) if "selinux_fc" in OPTIONS.info_dict: OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts") input_zip.close() output_zip = zipfile.ZipFile(filename, "a", compression=zipfile.ZIP_DEFLATED) def banner(s): print "\n\n++++ " + s + " ++++\n\n" banner("boot") boot_image = common.GetBootableImage("IMAGES/boot.img", "boot.img", OPTIONS.input_tmp, "BOOT") if boot_image: boot_image.AddToZip(output_zip) banner("recovery") recovery_image = common.GetBootableImage("IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY") if recovery_image: recovery_image.AddToZip(output_zip) banner("system") AddSystem(output_zip) if has_vendor: banner("vendor") AddVendor(output_zip) banner("userdata") AddUserdata(output_zip) banner("userdata_extra") AddUserdataExtra(output_zip) banner("cache") AddCache(output_zip) output_zip.close()
def main(argv): # This allows modifying the value from inner function. bootable_only_array = [False] def option_handler(o, _): if o in ("-z", "--bootable_zip"): bootable_only_array[0] = True else: return False return True args = common.ParseOptions(argv, __doc__, extra_opts="z", extra_long_opts=["bootable_zip"], extra_option_handler=option_handler) OPTIONS.bootable_only = bootable_only_array[0] if len(args) != 2: common.Usage(__doc__) sys.exit(1) common.InitLogging() target_files = args[0] if os.path.isdir(target_files): logger.info("Building image zip from extracted target files.") OPTIONS.input_tmp = target_files elif zipfile.is_zipfile(target_files): logger.info("Building image zip from target files zip.") # We need files under IMAGES/, OTA/, META/ for img_from_target_files.py. # However, common.LoadInfoDict() may read additional files under BOOT/, # RECOVERY/ and ROOT/. So unzip everything from the target_files.zip. OPTIONS.input_tmp = common.UnzipTemp(target_files) else: raise ValueError("%s is not a valid path." % target_files) LoadOptions(OPTIONS.input_tmp) output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED, allowZip64=not OPTIONS.sparse_userimages) try: CopyInfo(OPTIONS.input_tmp, output_zip) CopyUserImages(OPTIONS.input_tmp, output_zip) WriteSuperImages(OPTIONS.input_tmp, output_zip) finally: logger.info("cleaning up...") common.ZipClose(output_zip) logger.info("done.")
def main(argv): bootable_only = [False] compression = [zipfile.ZIP_DEFLATED] def option_handler(o, _): if o in ("-z", "--bootable_zip"): bootable_only[0] = True elif o in ("-n", "--no_compression"): compression[0] = zipfile.ZIP_STORED else: return False return True args = common.ParseOptions( argv, __doc__, extra_opts="zn", extra_long_opts=["bootable_zip", "no_compression"], extra_option_handler=option_handler) bootable_only = bootable_only[0] compression = compression[0] if len(args) != 2: common.Usage(__doc__) sys.exit(1) OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0], ["IMAGES/*", "OTA/*"]) output_zip = zipfile.ZipFile(args[1], "w", compression) CopyInfo(output_zip) try: images_path = os.path.join(OPTIONS.input_tmp, "IMAGES") # A target-files zip must contain the images since Lollipop. assert os.path.exists(images_path) for image in sorted(os.listdir(images_path)): if bootable_only and image not in ("boot.img", "recovery.img"): continue if not image.endswith(".img"): continue if image == "recovery-two-step.img": continue common.ZipWrite(output_zip, os.path.join(images_path, image), image) finally: print("cleaning up...") common.ZipClose(output_zip) shutil.rmtree(OPTIONS.input_tmp) print("done.")
def LoadZipFile(self, filename): # First read the APK certs file to figure out whether there are compressed # APKs in the archive. If we do have compressed APKs in the archive, then we # must decompress them individually before we perform any analysis. # This is the list of wildcards of files we extract from |filename|. apk_extensions = ['*.apk'] self.certmap, compressed_extension = common.ReadApkCerts( zipfile.ZipFile(filename, "r")) if compressed_extension: apk_extensions.append("*.apk" + compressed_extension) d, z = common.UnzipTemp(filename, apk_extensions) try: self.apks = {} self.apks_by_basename = {} for dirpath, _, filenames in os.walk(d): for fn in filenames: # Decompress compressed APKs before we begin processing them. if compressed_extension and fn.endswith( compressed_extension): # First strip the compressed extension from the file. uncompressed_fn = fn[:-len(compressed_extension)] # Decompress the compressed file to the output file. common.Gunzip(os.path.join(dirpath, fn), os.path.join(dirpath, uncompressed_fn)) # Finally, delete the compressed file and use the uncompressed file # for further processing. Note that the deletion is not strictly required, # but is done here to ensure that we're not using too much space in # the temporary directory. os.remove(os.path.join(dirpath, fn)) fn = uncompressed_fn if fn.endswith(".apk"): fullname = os.path.join(dirpath, fn) displayname = fullname[len(d) + 1:] apk = APK(fullname, displayname) self.apks[apk.filename] = apk self.apks_by_basename[os.path.basename( apk.filename)] = apk self.max_pkg_len = max(self.max_pkg_len, len(apk.package)) self.max_fn_len = max(self.max_fn_len, len(apk.filename)) finally: shutil.rmtree(d) z.close()
def test_LoadInfoDict_repacking(self): target_files = self._test_LoadInfoDict_createTargetFiles( self.INFO_DICT_DEFAULT, 'BOOT/RAMDISK/system/etc/recovery.fstab') unzipped = common.UnzipTemp(target_files) loaded_dict = common.LoadInfoDict(unzipped, True) self.assertEqual(3, loaded_dict['recovery_api_version']) self.assertEqual(2, loaded_dict['fstab_version']) self.assertIn('/', loaded_dict['fstab']) self.assertIn('/system', loaded_dict['fstab']) self.assertEqual(os.path.join(unzipped, 'ROOT'), loaded_dict['root_dir']) self.assertEqual( os.path.join(unzipped, 'META', 'root_filesystem_config.txt'), loaded_dict['root_fs_config'])
def CheckVintfFromTargetFiles(inp, info_dict=None): """ Checks VINTF metadata of a target files zip. Args: inp: path to the target files archive. info_dict: The build-time info dict. If None, it will be loaded from inp. Returns: True if VINTF check is skipped or compatible, False if incompatible. Raise a RuntimeError if any error occurs. """ input_tmp = common.UnzipTemp(inp, GetVintfFileList() + UNZIP_PATTERN) return CheckVintfFromExtractedTargetFiles(input_tmp, info_dict)
def test_GetSparseImage_missingBlockMapFile(self): target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip') with zipfile.ZipFile(target_files, 'w') as target_files_zip: target_files_zip.write(test_utils.construct_sparse_image([ (0xCAC1, 6), (0xCAC3, 3), (0xCAC1, 4) ]), arcname='IMAGES/system.img') target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 8)) target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3)) tempdir = common.UnzipTemp(target_files) with zipfile.ZipFile(target_files, 'r') as input_zip: self.assertRaises(AssertionError, common.GetSparseImage, 'system', tempdir, input_zip, False)
def main(): parser = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument('target_files', help='the input target_files.zip to be validated') parser.add_argument( '--verity_key', help='the verity public key to verify the bootable images (Verified ' 'Boot 1.0), or the vbmeta image (Verified Boot 2.0, aka AVB), where ' 'applicable') for partition in common.AVB_PARTITIONS + common.AVB_VBMETA_PARTITIONS: parser.add_argument( '--avb_' + partition + '_key_path', help='the public or private key in PEM format to verify AVB chained ' 'partition of {}'.format(partition)) parser.add_argument( '--verity_key_mincrypt', help='the verity public key in mincrypt format to verify the system ' 'images, if target using Verified Boot 1.0') args = parser.parse_args() # Unprovided args will have 'None' as the value. options = vars(args) logging_format = '%(asctime)s - %(filename)s - %(levelname)-8s: %(message)s' date_format = '%Y/%m/%d %H:%M:%S' logging.basicConfig(level=logging.INFO, format=logging_format, datefmt=date_format) logging.info("Unzipping the input target_files.zip: %s", args.target_files) input_tmp = common.UnzipTemp(args.target_files) info_dict = common.LoadInfoDict(input_tmp) with zipfile.ZipFile(args.target_files, 'r', allowZip64=True) as input_zip: ValidateFileConsistency(input_zip, input_tmp, info_dict) CheckBuildPropDuplicity(input_tmp) ValidateInstallRecoveryScript(input_tmp, info_dict) ValidateVerifiedBootImages(input_tmp, info_dict, options) # TODO: Check if the OTA keys have been properly updated (the ones on /system, # in recovery image). logging.info("Done.")
def test_GetSparseImage_fileNotFound(self): target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip') with zipfile.ZipFile(target_files, 'w') as target_files_zip: target_files_zip.write(test_utils.construct_sparse_image([(0xCAC2, 16)]), arcname='IMAGES/system.img') target_files_zip.writestr( 'IMAGES/system.map', '\n'.join(['//system/file1 1-5 9-10', '//system/file2 11-12'])) target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7)) tempdir = common.UnzipTemp(target_files) with zipfile.ZipFile(target_files, 'r') as input_zip: self.assertRaises(AssertionError, common.GetSparseImage, 'system', tempdir, input_zip, False)
def main(argv): def option_handler(o, a): if o in ("-I", "--ifwi-directory"): OPTIONS.ifwi_directory = a elif o in ("-A", "--avb-key"): OPTIONS.avb_key = a OPTIONS.all_keys.add(a) elif o in ("-K", "--oem-key"): OPTIONS.oem_key = a OPTIONS.all_keys.add(a) elif o in ("-V", "--variant"): OPTIONS.variant = a else: return False return True args = common.ParseOptions(argv, __doc__, extra_opts="I:A:K:V:", extra_long_opts=[ "ifwi-directory=", "avb-key=", "oem-key=", "variant=" ], extra_option_handler=option_handler) if len(args) != 2: common.Usage(__doc__) sys.exit(1) output_fastboot_fn = args[1] print "Extracting the provdata.zip" prov_file = "provdata_" + OPTIONS.variant + ".zip" unpack_dir = common.UnzipTemp(args[0]) input_zip = zipfile.ZipFile(args[0], "r") input_provzip = zipfile.ZipFile( os.path.join(unpack_dir, "RADIO", prov_file), "r") print "Parsing build.prop for target_product" d = {} try: with open(os.path.join(unpack_dir, "SYSTEM", "build.prop")) as f: d = common.LoadDictionaryFromLines(f.read().split("\n")) except IOError, e: if e.errno == errno.ENOENT: raise KeyError(f)
def RebuildAndWriteSuperImages(input_file, output_file): """Builds and writes super images to the output file.""" logger.info('Building super image...') # We need files under IMAGES/, OTA/, META/ for img_from_target_files.py. # However, common.LoadInfoDict() may read additional files under BOOT/, # RECOVERY/ and ROOT/. So unzip everything from the target_files.zip. input_tmp = common.UnzipTemp(input_file) super_file = common.MakeTempFile('super_', '.img') BuildSuperImage(input_tmp, super_file) logger.info('Writing super.img to archive...') with zipfile.ZipFile(output_file, 'a', compression=zipfile.ZIP_DEFLATED, allowZip64=True) as output_zip: common.ZipWrite(output_zip, super_file, 'super.img')
def test_GetSparseImage_sharedBlocks_notAllowed(self): """Tests the case of having overlapping blocks but disallowed.""" target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip') with zipfile.ZipFile(target_files, 'w') as target_files_zip: target_files_zip.write(test_utils.construct_sparse_image([(0xCAC2, 16)]), arcname='IMAGES/system.img') # Block 10 is shared between two files. target_files_zip.writestr( 'IMAGES/system.map', '\n'.join(['/system/file1 1-5 9-10', '/system/file2 10-12'])) target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7)) target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3)) tempdir = common.UnzipTemp(target_files) with zipfile.ZipFile(target_files, 'r') as input_zip: self.assertRaises(AssertionError, common.GetSparseImage, 'system', tempdir, input_zip, False)
def test_GetSparseImage_sharedBlocks_allowed(self): """Tests the case for target using BOARD_EXT4_SHARE_DUP_BLOCKS := true.""" target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip') with zipfile.ZipFile(target_files, 'w') as target_files_zip: # Construct an image with a care_map of "0-5 9-12". target_files_zip.write( test_utils.construct_sparse_image([(0xCAC2, 16)]), arcname='IMAGES/system.img') # Block 10 is shared between two files. target_files_zip.writestr( 'IMAGES/system.map', '\n'.join([ '/system/file1 1-5 9-10', '/system/file2 10-12'])) target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7)) target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3)) tempdir = common.UnzipTemp(target_files) with zipfile.ZipFile(target_files, 'r') as input_zip: sparse_image = common.GetSparseImage('system', tempdir, input_zip, True) self.assertDictEqual( { '__COPY': RangeSet("0"), '__NONZERO-0': RangeSet("6-8 13-15"), '/system/file1': RangeSet("1-5 9-10"), '/system/file2': RangeSet("11-12"), }, sparse_image.file_map) # '/system/file2' should be marked with 'uses_shared_blocks', but not with # 'incomplete'. self.assertTrue( sparse_image.file_map['/system/file2'].extra['uses_shared_blocks']) self.assertNotIn( 'incomplete', sparse_image.file_map['/system/file2'].extra) # All other entries should look normal without any tags. self.assertFalse(sparse_image.file_map['__COPY'].extra) self.assertFalse(sparse_image.file_map['__NONZERO-0'].extra) self.assertFalse(sparse_image.file_map['/system/file1'].extra)
def LoadZipFile(self, filename): d, z = common.UnzipTemp(filename, ['*.apk']) try: self.apks = {} self.apks_by_basename = {} for dirpath, _, filenames in os.walk(d): for fn in filenames: if fn.endswith(".apk"): fullname = os.path.join(dirpath, fn) displayname = fullname[len(d)+1:] apk = APK(fullname, displayname) self.apks[apk.filename] = apk self.apks_by_basename[os.path.basename(apk.filename)] = apk self.max_pkg_len = max(self.max_pkg_len, len(apk.package)) self.max_fn_len = max(self.max_fn_len, len(apk.filename)) finally: shutil.rmtree(d) self.certmap = common.ReadApkCerts(z) z.close()
def main(argv): bootable_only = [False] def option_handler(o, _): if o in ("-z", "--bootable_zip"): bootable_only[0] = True else: return False return True args = common.ParseOptions(argv, __doc__, extra_opts="z", extra_long_opts=["bootable_zip"], extra_option_handler=option_handler) bootable_only = bootable_only[0] if len(args) != 2: common.Usage(__doc__) sys.exit(1) OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0]) output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED) CopyInfo(output_zip) AddRadio(output_zip) try: done = False images_path = os.path.join(OPTIONS.input_tmp, "IMAGES") if os.path.exists(images_path): # If this is a new target-files, it already contains the images, # and all we have to do is copy them to the output zip. # Skip oem.img files since they are not needed in fastboot images. images = os.listdir(images_path) if images: for image in images: if bootable_only and image not in ("boot.img", "recovery.img"): continue if not image.endswith(".img"): continue
def test_GetSparseImage_incompleteRanges(self): """Tests the case of ext4 images with holes.""" target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip') with zipfile.ZipFile(target_files, 'w') as target_files_zip: target_files_zip.write( test_utils.construct_sparse_image([(0xCAC2, 16)]), arcname='IMAGES/system.img') target_files_zip.writestr( 'IMAGES/system.map', '\n'.join([ '/system/file1 1-5 9-10', '/system/file2 11-12'])) target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 7)) # '/system/file2' has less blocks listed (2) than actual (3). target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3)) tempdir = common.UnzipTemp(target_files) with zipfile.ZipFile(target_files, 'r') as input_zip: sparse_image = common.GetSparseImage('system', tempdir, input_zip, False) self.assertFalse(sparse_image.file_map['/system/file1'].extra) self.assertTrue(sparse_image.file_map['/system/file2'].extra['incomplete'])
def test_GetSparseImage_emptyBlockMapFile(self): target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip') with zipfile.ZipFile(target_files, 'w') as target_files_zip: target_files_zip.write(test_utils.construct_sparse_image([ (0xCAC1, 6), (0xCAC3, 3), (0xCAC1, 4) ]), arcname='IMAGES/system.img') target_files_zip.writestr('IMAGES/system.map', '') target_files_zip.writestr('SYSTEM/file1', os.urandom(4096 * 8)) target_files_zip.writestr('SYSTEM/file2', os.urandom(4096 * 3)) tempdir = common.UnzipTemp(target_files) with zipfile.ZipFile(target_files, 'r') as input_zip: sparse_image = common.GetSparseImage('system', tempdir, input_zip, False) self.assertDictEqual( { '__COPY': RangeSet("0"), '__NONZERO-0': RangeSet("1-5 9-12"), }, sparse_image.file_map)
def build_fls(unpack_dir, target, variant=None): """Build fls flash file out of tfp""" sign, target2tag = check_signed_fls(target) tag = get_tag(target2tag) provdata_zip = 'provdata_%s.zip' % variant if variant else 'provdata.zip' provdata_name = os.path.join(unpack_dir, "RADIO", provdata_zip) provdata, provdata_zip = common.UnzipTemp(provdata_name) target2file = open(os.path.join(provdata, "fftf_build.opt")).read().strip() t2f = init_t2f_dict(target2file) flstool = os.path.join(provdata, os.path.basename(t2f["FLSTOOL"])) prg = os.path.join(provdata, os.path.basename(t2f["INTEL_PRG_FILE"])) out = os.path.join(unpack_dir, "IMAGES", target2tag + '.fls') infile = os.path.join(unpack_dir, "IMAGES", target2tag + '.img') psi, eblsec = get_psi(provdata, t2f) run_fls(flstool, prg, out, tag, infile, psi, eblsec) if sign: script = os.path.join(provdata, os.path.basename(t2f["SYSTEM_FLS_SIGN_SCRIPT"])) out_signed = os.path.join(unpack_dir, "IMAGES", target) sign_fls(flstool, out, script, out_signed, psi, eblsec) try: os.makedirs(os.path.join(t2f["FASTBOOT_IMG_DIR"])) except OSError as exc: if exc.errno == errno.EEXIST and os.path.isdir( os.path.join(t2f["FASTBOOT_IMG_DIR"])): pass else: raise shutil.copyfile(os.path.join(unpack_dir, "IMAGES", target2tag + '.img'), os.path.join(t2f["FASTBOOT_IMG_DIR"], target2tag + '.bin'))
def GetBootloaderImageFromTFP(unpack_dir, autosize=False, extra_files=None, variant=None, base_variant=None): if extra_files == None: extra_files = [] if variant: provdata_name = os.path.join(unpack_dir, "RADIO", "provdata_" + variant +".zip") if base_variant and (os.path.isfile(provdata_name) == False): provdata_name = os.path.join(unpack_dir, "RADIO", "provdata_" + base_variant +".zip") provdata, provdata_zip = common.UnzipTemp(provdata_name) cap_path = os.path.join(provdata,"capsule.fv") if os.path.exists(cap_path): extra_files.append((cap_path, "capsules/current.fv")) extra_files.append((cap_path, "BIOSUPDATE.fv")) else: print "No capsule.fv found in provdata_" + variant + ".zip" bootloader = tempfile.NamedTemporaryFile(delete=False) filename = bootloader.name bootloader.close() fastboot = GetFastbootImage(unpack_dir) if fastboot: fastboot_file = fastboot.WriteToTemp() extra_files.append((fastboot_file.name,"fastboot.img")) if not autosize: size = int(open(os.path.join(unpack_dir, "RADIO", "bootloader-size.txt")).read().strip()) else: size = 0 MakeVFATFilesystem(os.path.join(unpack_dir, "RADIO", "bootloader.zip"), filename, size=size, extra_files=extra_files) bootloader = open(filename) data = bootloader.read() bootloader.close() os.unlink(filename) return data
def BuildSuperImageFromTargetFiles(inp, out): input_tmp = common.UnzipTemp(inp, UNZIP_PATTERN) return BuildSuperImageFromExtractedTargetFiles(input_tmp, out)
def AddImagesToTargetFiles(filename): """Creates and adds images (boot/recovery/system/...) to a target_files.zip. It works with either a zip file (zip mode), or a directory that contains the files to be packed into a target_files.zip (dir mode). The latter is used when being called from build/make/core/Makefile. The images will be created under IMAGES/ in the input target_files.zip. Args: filename: the target_files.zip, or the zip root directory. """ if os.path.isdir(filename): OPTIONS.input_tmp = os.path.abspath(filename) else: OPTIONS.input_tmp = common.UnzipTemp(filename) if not OPTIONS.add_missing: if os.path.isdir(os.path.join(OPTIONS.input_tmp, "IMAGES")): logger.warning("target_files appears to already contain images.") sys.exit(1) OPTIONS.info_dict = common.LoadInfoDict(OPTIONS.input_tmp, repacking=True) has_recovery = OPTIONS.info_dict.get("no_recovery") != "true" has_boot = OPTIONS.info_dict.get("no_boot") != "true" has_vendor_boot = OPTIONS.info_dict.get("vendor_boot") == "true" # {vendor,odm,product,system_ext,vendor_dlkm,odm_dlkm, system, system_other}.img # can be built from source, or dropped into target_files.zip as a prebuilt blob. has_vendor = HasPartition("vendor") has_odm = HasPartition("odm") has_vendor_dlkm = HasPartition("vendor_dlkm") has_odm_dlkm = HasPartition("odm_dlkm") has_product = HasPartition("product") has_system_ext = HasPartition("system_ext") has_system = HasPartition("system") has_system_other = HasPartition("system_other") has_userdata = OPTIONS.info_dict.get("building_userdata_image") == "true" has_cache = OPTIONS.info_dict.get("building_cache_image") == "true" # Set up the output destination. It writes to the given directory for dir # mode; otherwise appends to the given ZIP. if os.path.isdir(filename): output_zip = None else: output_zip = zipfile.ZipFile(filename, "a", compression=zipfile.ZIP_DEFLATED, allowZip64=True) # Always make input_tmp/IMAGES available, since we may stage boot / recovery # images there even under zip mode. The directory will be cleaned up as part # of OPTIONS.input_tmp. images_dir = os.path.join(OPTIONS.input_tmp, "IMAGES") if not os.path.isdir(images_dir): os.makedirs(images_dir) # A map between partition names and their paths, which could be used when # generating AVB vbmeta image. partitions = {} def banner(s): logger.info("\n\n++++ %s ++++\n\n", s) boot_image = None if has_boot: banner("boot") boot_images = OPTIONS.info_dict.get("boot_images") if boot_images is None: boot_images = "boot.img" for index, b in enumerate(boot_images.split()): # common.GetBootableImage() returns the image directly if present. boot_image = common.GetBootableImage("IMAGES/" + b, b, OPTIONS.input_tmp, "BOOT") # boot.img may be unavailable in some targets (e.g. aosp_arm64). if boot_image: boot_image_path = os.path.join(OPTIONS.input_tmp, "IMAGES", b) # Although multiple boot images can be generated, include the image # descriptor of only the first boot image in vbmeta if index == 0: partitions['boot'] = boot_image_path if not os.path.exists(boot_image_path): boot_image.WriteToDir(OPTIONS.input_tmp) if output_zip: boot_image.AddToZip(output_zip) if has_vendor_boot: banner("vendor_boot") vendor_boot_image = common.GetVendorBootImage("IMAGES/vendor_boot.img", "vendor_boot.img", OPTIONS.input_tmp, "VENDOR_BOOT") if vendor_boot_image: partitions['vendor_boot'] = os.path.join(OPTIONS.input_tmp, "IMAGES", "vendor_boot.img") if not os.path.exists(partitions['vendor_boot']): vendor_boot_image.WriteToDir(OPTIONS.input_tmp) if output_zip: vendor_boot_image.AddToZip(output_zip) recovery_image = None if has_recovery: banner("recovery") recovery_image = common.GetBootableImage("IMAGES/recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY") assert recovery_image, "Failed to create recovery.img." partitions['recovery'] = os.path.join(OPTIONS.input_tmp, "IMAGES", "recovery.img") if not os.path.exists(partitions['recovery']): recovery_image.WriteToDir(OPTIONS.input_tmp) if output_zip: recovery_image.AddToZip(output_zip) banner("recovery (two-step image)") # The special recovery.img for two-step package use. recovery_two_step_image = common.GetBootableImage( "OTA/recovery-two-step.img", "recovery-two-step.img", OPTIONS.input_tmp, "RECOVERY", two_step_image=True) assert recovery_two_step_image, "Failed to create recovery-two-step.img." recovery_two_step_image_path = os.path.join( OPTIONS.input_tmp, "OTA", "recovery-two-step.img") if not os.path.exists(recovery_two_step_image_path): recovery_two_step_image.WriteToDir(OPTIONS.input_tmp) if output_zip: recovery_two_step_image.AddToZip(output_zip) if has_system: banner("system") partitions['system'] = AddSystem(output_zip, recovery_img=recovery_image, boot_img=boot_image) if has_vendor: banner("vendor") partitions['vendor'] = AddVendor(output_zip, recovery_img=recovery_image, boot_img=boot_image) if has_product: banner("product") partitions['product'] = AddProduct(output_zip) if has_system_ext: banner("system_ext") partitions['system_ext'] = AddSystemExt(output_zip) if has_odm: banner("odm") partitions['odm'] = AddOdm(output_zip) if has_vendor_dlkm: banner("vendor_dlkm") partitions['vendor_dlkm'] = AddVendorDlkm(output_zip) if has_odm_dlkm: banner("odm_dlkm") partitions['odm_dlkm'] = AddOdmDlkm(output_zip) if has_system_other: banner("system_other") AddSystemOther(output_zip) AddApexInfo(output_zip) if not OPTIONS.is_signing: banner("userdata") AddUserdata(output_zip) banner("cache") AddCache(output_zip) if OPTIONS.info_dict.get("board_bpt_enable") == "true": banner("partition-table") AddPartitionTable(output_zip) if OPTIONS.info_dict.get("has_dtbo") == "true": banner("dtbo") partitions['dtbo'] = AddDtbo(output_zip) if OPTIONS.info_dict.get("has_pvmfw") == "true": banner("pvmfw") partitions['pvmfw'] = AddPvmfw(output_zip) # Custom images. custom_partitions = OPTIONS.info_dict.get( "avb_custom_images_partition_list", "").strip().split() for partition_name in custom_partitions: partition_name = partition_name.strip() banner("custom images for " + partition_name) partitions[partition_name] = AddCustomImages(output_zip, partition_name) if OPTIONS.info_dict.get("avb_enable") == "true": # vbmeta_partitions includes the partitions that should be included into # top-level vbmeta.img, which are the ones that are not included in any # chained VBMeta image plus the chained VBMeta images themselves. # Currently custom_partitions are all chained to VBMeta image. vbmeta_partitions = common.AVB_PARTITIONS[:] + tuple(custom_partitions) vbmeta_system = OPTIONS.info_dict.get("avb_vbmeta_system", "").strip() if vbmeta_system: banner("vbmeta_system") partitions["vbmeta_system"] = AddVBMeta(output_zip, partitions, "vbmeta_system", vbmeta_system.split()) vbmeta_partitions = [ item for item in vbmeta_partitions if item not in vbmeta_system.split() ] vbmeta_partitions.append("vbmeta_system") vbmeta_vendor = OPTIONS.info_dict.get("avb_vbmeta_vendor", "").strip() if vbmeta_vendor: banner("vbmeta_vendor") partitions["vbmeta_vendor"] = AddVBMeta(output_zip, partitions, "vbmeta_vendor", vbmeta_vendor.split()) vbmeta_partitions = [ item for item in vbmeta_partitions if item not in vbmeta_vendor.split() ] vbmeta_partitions.append("vbmeta_vendor") if OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true": banner("vbmeta") AddVBMeta(output_zip, partitions, "vbmeta", vbmeta_partitions) if OPTIONS.info_dict.get("use_dynamic_partitions") == "true": if OPTIONS.info_dict.get("build_super_empty_partition") == "true": banner("super_empty") AddSuperEmpty(output_zip) if OPTIONS.info_dict.get("build_super_partition") == "true": if OPTIONS.info_dict.get( "build_retrofit_dynamic_partitions_ota_package") == "true": banner("super split images") AddSuperSplit(output_zip) banner("radio") ab_partitions_txt = os.path.join(OPTIONS.input_tmp, "META", "ab_partitions.txt") if os.path.exists(ab_partitions_txt): with open(ab_partitions_txt) as f: ab_partitions = f.readlines() # For devices using A/B update, make sure we have all the needed images # ready under IMAGES/ or RADIO/. CheckAbOtaImages(output_zip, ab_partitions) # Generate care_map.pb for ab_partitions, then write this file to # target_files package. output_care_map = os.path.join(OPTIONS.input_tmp, "META", "care_map.pb") AddCareMapForAbOta(output_zip if output_zip else output_care_map, ab_partitions, partitions) # Radio images that need to be packed into IMAGES/, and product-img.zip. pack_radioimages_txt = os.path.join(OPTIONS.input_tmp, "META", "pack_radioimages.txt") if os.path.exists(pack_radioimages_txt): with open(pack_radioimages_txt) as f: AddPackRadioImages(output_zip, f.readlines()) # Calculate the vbmeta digest and put the result in to META/ boot_images = OPTIONS.info_dict.get("boot_images") # Disable the digest calculation if the target_file is used as a container # for boot images. boot_container = boot_images and len(boot_images.split()) >= 2 if (OPTIONS.info_dict.get("avb_enable") == "true" and not boot_container and OPTIONS.info_dict.get("avb_building_vbmeta_image") == "true"): avbtool = OPTIONS.info_dict["avb_avbtool"] digest = verity_utils.CalculateVbmetaDigest(OPTIONS.input_tmp, avbtool) vbmeta_digest_txt = os.path.join(OPTIONS.input_tmp, "META", "vbmeta_digest.txt") with open(vbmeta_digest_txt, 'w') as f: f.write(digest) if output_zip: common.ZipClose(output_zip) if OPTIONS.replace_updated_files_list: ReplaceUpdatedFiles(output_zip.filename, OPTIONS.replace_updated_files_list)