Loading tools/releasetools/Android.bp +10 −1 Original line number Diff line number Diff line Loading @@ -122,13 +122,15 @@ python_defaults { "releasetools_check_target_files_vintf", "releasetools_common", "releasetools_verity_utils", "apex_manifest", ], required: [ "brillo_update_payload", "checkvintf", "lz4", "toybox", "unpack_bootimg" "unpack_bootimg", "deapexer", ], target: { darwin: { Loading Loading @@ -169,6 +171,8 @@ python_library_host { "apex_utils.py", ], libs: [ "apex_manifest", "ota_metadata_proto", "releasetools_common", ], } Loading Loading @@ -544,6 +548,8 @@ python_defaults { ], data: [ "testdata/**/*", ":com.android.apex.compressed.v1", ":com.android.apex.compressed.v1_original", ], target: { darwin: { Loading @@ -551,6 +557,9 @@ python_defaults { enabled: false, }, }, required: [ "deapexer", ], } python_test_host { Loading tools/releasetools/apex_utils.py +78 −5 Original line number Diff line number Diff line Loading @@ -21,7 +21,12 @@ import shlex import shutil import zipfile import apex_manifest import common from common import UnzipTemp, RunAndCheckOutput, MakeTempFile, OPTIONS import ota_metadata_pb2 logger = logging.getLogger(__name__) Loading Loading @@ -69,7 +74,7 @@ class ApexApkSigner(object): if not os.path.exists(self.debugfs_path): raise ApexSigningError( "Couldn't find location of debugfs_static: " + "Path {} does not exist. ".format(debugfs_path) + "Path {} does not exist. ".format(self.debugfs_path) + "Make sure bin/debugfs_static can be found in -p <path>") list_cmd = ['deapexer', '--debugfs_path', self.debugfs_path, 'list', self.apex_path] Loading Loading @@ -105,7 +110,7 @@ class ApexApkSigner(object): if not os.path.exists(self.debugfs_path): raise ApexSigningError( "Couldn't find location of debugfs_static: " + "Path {} does not exist. ".format(debugfs_path) + "Path {} does not exist. ".format(self.debugfs_path) + "Make sure bin/debugfs_static can be found in -p <path>") payload_dir = common.MakeTempDir() extract_cmd = ['deapexer', '--debugfs_path', Loading @@ -127,7 +132,8 @@ class ApexApkSigner(object): # signed apk file. unsigned_apk = common.MakeTempFile() os.rename(apk_path, unsigned_apk) common.SignFile(unsigned_apk, apk_path, key_name, self.key_passwords.get(key_name), common.SignFile( unsigned_apk, apk_path, key_name, self.key_passwords.get(key_name), codename_to_api_level_map=self.codename_to_api_level_map) has_signed_apk = True return payload_dir, has_signed_apk Loading Loading @@ -427,4 +433,71 @@ def SignApex(avbtool, apex_data, payload_key, container_key, container_pw, except common.ExternalError as e: raise ApexInfoError( 'Failed to get type for {}:\n{}'.format(apex_file)) 'Failed to get type for {}:\n{}'.format(apex_file, e)) def GetApexInfoFromTargetFiles(input_file): """ Get information about system APEX stored in the input_file zip Args: input_file: The filename of the target build target-files zip or directory. Return: A list of ota_metadata_pb2.ApexInfo() populated using the APEX stored in /system partition of the input_file """ # Extract the apex files so that we can run checks on them if not isinstance(input_file, str): raise RuntimeError("must pass filepath to target-files zip or directory") if os.path.isdir(input_file): tmp_dir = input_file else: tmp_dir = UnzipTemp(input_file, ["SYSTEM/apex/*"]) target_dir = os.path.join(tmp_dir, "SYSTEM/apex/") apex_infos = [] for apex_filename in os.listdir(target_dir): apex_filepath = os.path.join(target_dir, apex_filename) if not os.path.isfile(apex_filepath) or \ not zipfile.is_zipfile(apex_filepath): logger.info("Skipping %s because it's not a zipfile", apex_filepath) continue apex_info = ota_metadata_pb2.ApexInfo() # Open the apex file to retrieve information manifest = apex_manifest.fromApex(apex_filepath) apex_info.package_name = manifest.name apex_info.version = manifest.version # Check if the file is compressed or not debugfs_path = "debugfs" if OPTIONS.search_path: debugfs_path = os.path.join(OPTIONS.search_path, "bin", "debugfs_static") deapexer = 'deapexer' if OPTIONS.search_path: deapexer_path = os.path.join(OPTIONS.search_path, "deapexer") if os.path.isfile(deapexer_path): deapexer = deapexer_path apex_type = RunAndCheckOutput([ deapexer, "--debugfs_path", debugfs_path, 'info', '--print-type', apex_filepath]).rstrip() if apex_type == 'COMPRESSED': apex_info.is_compressed = True elif apex_type == 'UNCOMPRESSED': apex_info.is_compressed = False else: raise RuntimeError('Not an APEX file: ' + apex_type) # Decompress compressed APEX to determine its size if apex_info.is_compressed: decompressed_file_path = MakeTempFile(prefix="decompressed-", suffix=".apex") # Decompression target path should not exist os.remove(decompressed_file_path) RunAndCheckOutput([deapexer, 'decompress', '--input', apex_filepath, '--output', decompressed_file_path]) apex_info.decompressed_size = os.path.getsize(decompressed_file_path) apex_infos.append(apex_info) return apex_infos tools/releasetools/ota_metadata.proto +7 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,13 @@ message DeviceState { repeated PartitionState partition_state = 7; } message ApexInfo { string package_name = 1; int64 version = 2; bool is_compressed = 3; int64 decompressed_size = 4; } // The metadata of an OTA package. It contains the information of the package // and prerequisite to install the update correctly. message OtaMetadata { Loading tools/releasetools/test_ota_from_target_files.py +22 −1 Original line number Diff line number Diff line Loading @@ -33,10 +33,11 @@ from ota_from_target_files import ( GetTargetFilesZipWithoutPostinstallConfig, Payload, PayloadSigner, POSTINSTALL_CONFIG, StreamingPropertyFiles, AB_PARTITIONS) from apex_utils import GetApexInfoFromTargetFiles from test_utils import PropertyFilesTestCase def construct_target_files(secondary=False): def construct_target_files(secondary=False, compressedApex=False): """Returns a target-files.zip file for generating OTA packages.""" target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip') with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip: Loading Loading @@ -78,6 +79,11 @@ def construct_target_files(secondary=False): target_files_zip.writestr('IMAGES/system_other.img', os.urandom(len("system_other"))) if compressedApex: apex_file_name = 'com.android.apex.compressed.v1.capex' apex_file = os.path.join(test_utils.get_current_dir(), apex_file_name) target_files_zip.write(apex_file, 'SYSTEM/apex/' + apex_file_name) return target_files Loading Loading @@ -274,6 +280,21 @@ class OtaFromTargetFilesTest(test_utils.ReleaseToolsTestCase): }, metadata) @test_utils.SkipIfExternalToolsUnavailable() def test_GetApexInfoFromTargetFiles(self): target_files = construct_target_files(compressedApex=True) apex_infos = GetApexInfoFromTargetFiles(target_files) self.assertEqual(len(apex_infos), 1) self.assertEqual(apex_infos[0].package_name, "com.android.apex.compressed") self.assertEqual(apex_infos[0].version, 1) self.assertEqual(apex_infos[0].is_compressed, True) # Compare the decompressed APEX size with the original uncompressed APEX original_apex_name = 'com.android.apex.compressed.v1_original.apex' original_apex_filepath = os.path.join(test_utils.get_current_dir(), original_apex_name) uncompressed_apex_size = os.path.getsize(original_apex_filepath) self.assertEqual(apex_infos[0].decompressed_size, uncompressed_apex_size) def test_GetPackageMetadata_retrofitDynamicPartitions(self): target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None) common.OPTIONS.retrofit_dynamic_partitions = True Loading tools/releasetools/test_utils.py +5 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,11 @@ def get_testdata_dir(): current_dir = os.path.dirname(os.path.realpath(__file__)) return os.path.join(current_dir, 'testdata') def get_current_dir(): """Returns the current dir, relative to the script dir.""" # The script dir is the one we want, which could be different from pwd. current_dir = os.path.dirname(os.path.realpath(__file__)) return current_dir def get_search_path(): """Returns the search path that has 'framework/signapk.jar' under.""" Loading Loading
tools/releasetools/Android.bp +10 −1 Original line number Diff line number Diff line Loading @@ -122,13 +122,15 @@ python_defaults { "releasetools_check_target_files_vintf", "releasetools_common", "releasetools_verity_utils", "apex_manifest", ], required: [ "brillo_update_payload", "checkvintf", "lz4", "toybox", "unpack_bootimg" "unpack_bootimg", "deapexer", ], target: { darwin: { Loading Loading @@ -169,6 +171,8 @@ python_library_host { "apex_utils.py", ], libs: [ "apex_manifest", "ota_metadata_proto", "releasetools_common", ], } Loading Loading @@ -544,6 +548,8 @@ python_defaults { ], data: [ "testdata/**/*", ":com.android.apex.compressed.v1", ":com.android.apex.compressed.v1_original", ], target: { darwin: { Loading @@ -551,6 +557,9 @@ python_defaults { enabled: false, }, }, required: [ "deapexer", ], } python_test_host { Loading
tools/releasetools/apex_utils.py +78 −5 Original line number Diff line number Diff line Loading @@ -21,7 +21,12 @@ import shlex import shutil import zipfile import apex_manifest import common from common import UnzipTemp, RunAndCheckOutput, MakeTempFile, OPTIONS import ota_metadata_pb2 logger = logging.getLogger(__name__) Loading Loading @@ -69,7 +74,7 @@ class ApexApkSigner(object): if not os.path.exists(self.debugfs_path): raise ApexSigningError( "Couldn't find location of debugfs_static: " + "Path {} does not exist. ".format(debugfs_path) + "Path {} does not exist. ".format(self.debugfs_path) + "Make sure bin/debugfs_static can be found in -p <path>") list_cmd = ['deapexer', '--debugfs_path', self.debugfs_path, 'list', self.apex_path] Loading Loading @@ -105,7 +110,7 @@ class ApexApkSigner(object): if not os.path.exists(self.debugfs_path): raise ApexSigningError( "Couldn't find location of debugfs_static: " + "Path {} does not exist. ".format(debugfs_path) + "Path {} does not exist. ".format(self.debugfs_path) + "Make sure bin/debugfs_static can be found in -p <path>") payload_dir = common.MakeTempDir() extract_cmd = ['deapexer', '--debugfs_path', Loading @@ -127,7 +132,8 @@ class ApexApkSigner(object): # signed apk file. unsigned_apk = common.MakeTempFile() os.rename(apk_path, unsigned_apk) common.SignFile(unsigned_apk, apk_path, key_name, self.key_passwords.get(key_name), common.SignFile( unsigned_apk, apk_path, key_name, self.key_passwords.get(key_name), codename_to_api_level_map=self.codename_to_api_level_map) has_signed_apk = True return payload_dir, has_signed_apk Loading Loading @@ -427,4 +433,71 @@ def SignApex(avbtool, apex_data, payload_key, container_key, container_pw, except common.ExternalError as e: raise ApexInfoError( 'Failed to get type for {}:\n{}'.format(apex_file)) 'Failed to get type for {}:\n{}'.format(apex_file, e)) def GetApexInfoFromTargetFiles(input_file): """ Get information about system APEX stored in the input_file zip Args: input_file: The filename of the target build target-files zip or directory. Return: A list of ota_metadata_pb2.ApexInfo() populated using the APEX stored in /system partition of the input_file """ # Extract the apex files so that we can run checks on them if not isinstance(input_file, str): raise RuntimeError("must pass filepath to target-files zip or directory") if os.path.isdir(input_file): tmp_dir = input_file else: tmp_dir = UnzipTemp(input_file, ["SYSTEM/apex/*"]) target_dir = os.path.join(tmp_dir, "SYSTEM/apex/") apex_infos = [] for apex_filename in os.listdir(target_dir): apex_filepath = os.path.join(target_dir, apex_filename) if not os.path.isfile(apex_filepath) or \ not zipfile.is_zipfile(apex_filepath): logger.info("Skipping %s because it's not a zipfile", apex_filepath) continue apex_info = ota_metadata_pb2.ApexInfo() # Open the apex file to retrieve information manifest = apex_manifest.fromApex(apex_filepath) apex_info.package_name = manifest.name apex_info.version = manifest.version # Check if the file is compressed or not debugfs_path = "debugfs" if OPTIONS.search_path: debugfs_path = os.path.join(OPTIONS.search_path, "bin", "debugfs_static") deapexer = 'deapexer' if OPTIONS.search_path: deapexer_path = os.path.join(OPTIONS.search_path, "deapexer") if os.path.isfile(deapexer_path): deapexer = deapexer_path apex_type = RunAndCheckOutput([ deapexer, "--debugfs_path", debugfs_path, 'info', '--print-type', apex_filepath]).rstrip() if apex_type == 'COMPRESSED': apex_info.is_compressed = True elif apex_type == 'UNCOMPRESSED': apex_info.is_compressed = False else: raise RuntimeError('Not an APEX file: ' + apex_type) # Decompress compressed APEX to determine its size if apex_info.is_compressed: decompressed_file_path = MakeTempFile(prefix="decompressed-", suffix=".apex") # Decompression target path should not exist os.remove(decompressed_file_path) RunAndCheckOutput([deapexer, 'decompress', '--input', apex_filepath, '--output', decompressed_file_path]) apex_info.decompressed_size = os.path.getsize(decompressed_file_path) apex_infos.append(apex_info) return apex_infos
tools/releasetools/ota_metadata.proto +7 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,13 @@ message DeviceState { repeated PartitionState partition_state = 7; } message ApexInfo { string package_name = 1; int64 version = 2; bool is_compressed = 3; int64 decompressed_size = 4; } // The metadata of an OTA package. It contains the information of the package // and prerequisite to install the update correctly. message OtaMetadata { Loading
tools/releasetools/test_ota_from_target_files.py +22 −1 Original line number Diff line number Diff line Loading @@ -33,10 +33,11 @@ from ota_from_target_files import ( GetTargetFilesZipWithoutPostinstallConfig, Payload, PayloadSigner, POSTINSTALL_CONFIG, StreamingPropertyFiles, AB_PARTITIONS) from apex_utils import GetApexInfoFromTargetFiles from test_utils import PropertyFilesTestCase def construct_target_files(secondary=False): def construct_target_files(secondary=False, compressedApex=False): """Returns a target-files.zip file for generating OTA packages.""" target_files = common.MakeTempFile(prefix='target_files-', suffix='.zip') with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip: Loading Loading @@ -78,6 +79,11 @@ def construct_target_files(secondary=False): target_files_zip.writestr('IMAGES/system_other.img', os.urandom(len("system_other"))) if compressedApex: apex_file_name = 'com.android.apex.compressed.v1.capex' apex_file = os.path.join(test_utils.get_current_dir(), apex_file_name) target_files_zip.write(apex_file, 'SYSTEM/apex/' + apex_file_name) return target_files Loading Loading @@ -274,6 +280,21 @@ class OtaFromTargetFilesTest(test_utils.ReleaseToolsTestCase): }, metadata) @test_utils.SkipIfExternalToolsUnavailable() def test_GetApexInfoFromTargetFiles(self): target_files = construct_target_files(compressedApex=True) apex_infos = GetApexInfoFromTargetFiles(target_files) self.assertEqual(len(apex_infos), 1) self.assertEqual(apex_infos[0].package_name, "com.android.apex.compressed") self.assertEqual(apex_infos[0].version, 1) self.assertEqual(apex_infos[0].is_compressed, True) # Compare the decompressed APEX size with the original uncompressed APEX original_apex_name = 'com.android.apex.compressed.v1_original.apex' original_apex_filepath = os.path.join(test_utils.get_current_dir(), original_apex_name) uncompressed_apex_size = os.path.getsize(original_apex_filepath) self.assertEqual(apex_infos[0].decompressed_size, uncompressed_apex_size) def test_GetPackageMetadata_retrofitDynamicPartitions(self): target_info = common.BuildInfo(self.TEST_TARGET_INFO_DICT, None) common.OPTIONS.retrofit_dynamic_partitions = True Loading
tools/releasetools/test_utils.py +5 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,11 @@ def get_testdata_dir(): current_dir = os.path.dirname(os.path.realpath(__file__)) return os.path.join(current_dir, 'testdata') def get_current_dir(): """Returns the current dir, relative to the script dir.""" # The script dir is the one we want, which could be different from pwd. current_dir = os.path.dirname(os.path.realpath(__file__)) return current_dir def get_search_path(): """Returns the search path that has 'framework/signapk.jar' under.""" Loading