diff options
author | 2024-12-02 20:40:34 +0000 | |
---|---|---|
committer | 2024-12-04 12:10:41 +0000 | |
commit | a0bdc8d7d84a470aabdb6a3bc5a0fa06a7d9dc84 (patch) | |
tree | 3a94f93ef9e068bfddaeaf0b6a0188fedf8c38a2 | |
parent | efad3542a83f4ccf34e987f9d2ba192b40ebc390 (diff) |
Clean up host APEX support.
#codehealth
Test: art/build/apex/runtests.sh
Bug: 279835185
Change-Id: I512f162f0f5208774a48049489ce3f1f5dbc0e31
-rwxr-xr-x | build/apex/art_apex_test.py | 270 |
1 files changed, 56 insertions, 214 deletions
diff --git a/build/apex/art_apex_test.py b/build/apex/art_apex_test.py index 0220363200..3c39e43b9f 100755 --- a/build/apex/art_apex_test.py +++ b/build/apex/art_apex_test.py @@ -24,7 +24,6 @@ import os.path import shutil import subprocess import sys -import zipfile logging.basicConfig(format='%(message)s') @@ -131,78 +130,6 @@ class TargetApexProvider: return apex_map -class HostApexProvider: - def __init__(self, apex, tmpdir): - self._tmpdir = tmpdir - self._folder_cache = {} - self._payload = os.path.join(self._tmpdir, 'apex_payload.zip') - # Extract payload to tmpdir. - apex_zip = zipfile.ZipFile(apex) - apex_zip.extract('apex_payload.zip', tmpdir) - - def __del__(self): - # Delete temps. - if os.path.exists(self._payload): - os.remove(self._payload) - - def get(self, path): - apex_dir, name = os.path.split(path) - if not apex_dir: - apex_dir = '' - apex_map = self.read_dir(apex_dir) - return apex_map[name] if name in apex_map else None - - def read_dir(self, apex_dir): - if apex_dir in self._folder_cache: - return self._folder_cache[apex_dir] - if not self._folder_cache: - self.parse_zip() - if apex_dir in self._folder_cache: - return self._folder_cache[apex_dir] - return {} - - def parse_zip(self): - apex_zip = zipfile.ZipFile(self._payload) - infos = apex_zip.infolist() - for zipinfo in infos: - path = zipinfo.filename - - # Assume no empty file is stored. - assert path - - def get_octal(val, index): - return (val >> (index * 3)) & 0x7 - - def bits_is_exec(val): - # TODO: Enforce group/other, too? - return get_octal(val, 2) & 1 == 1 - - is_zipinfo = True - while path: - apex_dir, base = os.path.split(path) - # TODO: If directories are stored, base will be empty. - - if apex_dir not in self._folder_cache: - self._folder_cache[apex_dir] = {} - dir_map = self._folder_cache[apex_dir] - if base not in dir_map: - if is_zipinfo: - bits = (zipinfo.external_attr >> 16) & 0xFFFF - is_dir = get_octal(bits, 4) == 4 - is_symlink = get_octal(bits, 4) == 2 - is_exec = bits_is_exec(bits) - size = zipinfo.file_size - else: - is_exec = False # Seems we can't get this easily? - is_symlink = False - is_dir = True - # Use a negative value as an indicator of undefined/unknown size. - size = -1 - dir_map[base] = FSObject(base, is_dir, is_exec, is_symlink, size) - is_zipinfo = False - path = apex_dir - - # DO NOT USE DIRECTLY! This is an "abstract" base class. class Checker: def __init__(self, provider): @@ -509,11 +436,18 @@ class ReleaseChecker: self._checker.check_optional_file('etc/package.map') # Check binaries for ART. + self._checker.check_executable('art_boot') + self._checker.check_executable('art_exec') + self._checker.check_executable('artd') self._checker.check_executable('dexdump') self._checker.check_executable('dexlist') + self._checker.check_executable('dexopt_chroot_setup') self._checker.check_executable('dexoptanalyzer') + self._checker.check_executable('oatdump') + self._checker.check_executable('odrefresh') self._checker.check_executable('profman') self._checker.check_symlinked_multilib_executable('dalvikvm') + self._checker.check_symlinked_multilib_executable('dex2oat') # Check exported libraries for ART. self._checker.check_native_library('libdexfile') @@ -527,12 +461,21 @@ class ReleaseChecker: self._checker.check_native_library('libart-disassembler') self._checker.check_native_library('libartbase') self._checker.check_native_library('libartpalette') - self._checker.check_prefer64_library('libarttools') self._checker.check_native_library('libdt_fd_forward') self._checker.check_native_library('libopenjdkjvm') self._checker.check_native_library('libopenjdkjvmti') + self._checker.check_native_library('libperfetto_hprof') self._checker.check_native_library('libprofile') self._checker.check_native_library('libsigchain') + self._checker.check_prefer64_library('libartservice') + self._checker.check_prefer64_library('libarttools') + + # Check internal Java libraries for ART. + self._checker.check_java_library('service-art') + self._checker.check_file('javalib/service-art.jar.prof') + + # Check exported native libraries for Managed Core Library. + self._checker.check_native_library('libandroidio') # Check Java libraries for Managed Core Library. self._checker.check_java_library('apache-xml') @@ -562,6 +505,7 @@ class ReleaseChecker: self._checker.check_native_library('libbase') self._checker.check_native_library('libc++') self._checker.check_native_library('libdt_socket') + self._checker.check_native_library('libexpat') self._checker.check_native_library('libjdwp') self._checker.check_native_library('liblz4') self._checker.check_native_library('liblzma') @@ -574,65 +518,6 @@ class ReleaseChecker: self._checker.check_optional_native_library('libclang_rt.ubsan*') -class ReleaseTargetChecker: - def __init__(self, checker): - self._checker = checker - - def __str__(self): - return 'Release (Target) Checker' - - def run(self): - # We don't check for the presence of the JSON APEX manifest (file - # `apex_manifest.json`, only present in target APEXes), as it is only - # included for compatibility reasons with Android Q and will likely be - # removed in Android R. - - # Check binaries for ART. - self._checker.check_executable('art_boot') - self._checker.check_executable('art_exec') - self._checker.check_executable('artd') - self._checker.check_executable('dexopt_chroot_setup') - self._checker.check_executable('oatdump') - self._checker.check_executable('odrefresh') - self._checker.check_symlinked_multilib_executable('dex2oat') - - # Check internal libraries for ART. - self._checker.check_prefer64_library('libartservice') - self._checker.check_native_library('libperfetto_hprof') - - # Check internal Java libraries - self._checker.check_java_library('service-art') - self._checker.check_file('javalib/service-art.jar.prof') - - # Check exported native libraries for Managed Core Library. - self._checker.check_native_library('libandroidio') - - # Check internal native library dependencies. - self._checker.check_native_library('libexpat') - - -class ReleaseHostChecker: - def __init__(self, checker): - self._checker = checker - - def __str__(self): - return 'Release (Host) Checker' - - def run(self): - # Check binaries for ART. - self._checker.check_executable('hprof-conv') - self._checker.check_symlinked_first_executable('dex2oatd') - self._checker.check_symlinked_first_executable('dex2oat') - - # Check exported native libraries for Managed Core Library. - self._checker.check_native_library('libicu') - self._checker.check_native_library('libandroidio') - - # Check internal libraries for Managed Core Library. - self._checker.check_native_library('libexpat-host') - self._checker.check_native_library('libz-host') - - class DebugChecker: def __init__(self, checker): self._checker = checker @@ -647,8 +532,10 @@ class DebugChecker: # Check debug binaries for ART. self._checker.check_executable('dexoptanalyzerd') - self._checker.check_symlinked_multilib_executable('imgdiagd') + self._checker.check_executable('oatdumpd') self._checker.check_executable('profmand') + self._checker.check_symlinked_multilib_executable('dex2oatd') + self._checker.check_symlinked_multilib_executable('imgdiagd') # Check exported libraries for ART. self._checker.check_native_library('libdexfiled') @@ -660,28 +547,13 @@ class DebugChecker: self._checker.check_native_library('libartd-disassembler') self._checker.check_native_library('libopenjdkjvmd') self._checker.check_native_library('libopenjdkjvmtid') + self._checker.check_native_library('libperfetto_hprofd') self._checker.check_native_library('libprofiled') + self._checker.check_prefer64_library('libartserviced') # Check internal libraries for Managed Core Library. self._checker.check_native_library('libopenjdkd') - -class DebugTargetChecker: - def __init__(self, checker): - self._checker = checker - - def __str__(self): - return 'Debug (Target) Checker' - - def run(self): - # Check ART debug binaries. - self._checker.check_executable('oatdumpd') - self._checker.check_symlinked_multilib_executable('dex2oatd') - - # Check ART internal libraries. - self._checker.check_prefer64_library('libartserviced') - self._checker.check_native_library('libperfetto_hprofd') - # Check internal native library dependencies. # # Like in the release package, we check that we don't get other dependencies @@ -698,12 +570,12 @@ class DebugTargetChecker: # (There are currently no debug-only native libraries.) -class TestingTargetChecker: +class TestingChecker: def __init__(self, checker): self._checker = checker def __str__(self): - return 'Testing (Target) Checker' + return 'Testing Checker' def run(self): # Check test directories. @@ -889,9 +761,6 @@ class Tree: # Note: do not sys.exit early, for __del__ cleanup. def art_apex_test_main(test_args): - if test_args.host and test_args.flattened: - logging.error('Both of --host and --flattened set') - return 1 if test_args.list and test_args.tree: logging.error('Both of --list and --tree set') return 1 @@ -901,7 +770,7 @@ def art_apex_test_main(test_args): if not test_args.flattened and not test_args.tmpdir: logging.error('Need a tmpdir.') return 1 - if not test_args.flattened and not test_args.host: + if not test_args.flattened: if not test_args.deapexer: logging.error('Need deapexer.') return 1 @@ -912,49 +781,33 @@ def art_apex_test_main(test_args): logging.error('Need fsck.erofs.') return 1 - if test_args.host: - # Host APEX. - if test_args.flavor not in [FLAVOR_DEBUG, FLAVOR_AUTO]: - logging.error('Using option --host with non-Debug APEX') - return 1 - # Host APEX is always a debug flavor (for now). - test_args.flavor = FLAVOR_DEBUG - else: - # Device APEX. + if test_args.flavor == FLAVOR_AUTO: + logging.warning('--flavor=auto, trying to autodetect. This may be incorrect!') + # The order of flavors in the list below matters, as the release tag (empty string) will + # match any package name. + for flavor in [ FLAVOR_DEBUG, FLAVOR_TESTING, FLAVOR_RELEASE ]: + flavor_tag = flavor + # Special handling for the release flavor, whose name is no longer part of the Release ART + # APEX file name (`com.android.art.capex` / `com.android.art`). + if flavor == FLAVOR_RELEASE: + flavor_tag = '' + flavor_pattern = '*.%s*' % flavor_tag + if fnmatch.fnmatch(test_args.apex, flavor_pattern): + test_args.flavor = flavor + logging.warning(' Detected %s flavor', flavor) + break if test_args.flavor == FLAVOR_AUTO: - logging.warning('--flavor=auto, trying to autodetect. This may be incorrect!') - # The order of flavors in the list below matters, as the release tag (empty string) will - # match any package name. - for flavor in [ FLAVOR_DEBUG, FLAVOR_TESTING, FLAVOR_RELEASE ]: - flavor_tag = flavor - # Special handling for the release flavor, whose name is no longer part of the Release ART - # APEX file name (`com.android.art.capex` / `com.android.art`). - if flavor == FLAVOR_RELEASE: - flavor_tag = '' - flavor_pattern = '*.%s*' % flavor_tag - if fnmatch.fnmatch(test_args.apex, flavor_pattern): - test_args.flavor = flavor - logging.warning(' Detected %s flavor', flavor) - break - if test_args.flavor == FLAVOR_AUTO: - logging.error(' Could not detect APEX flavor, neither %s, %s nor %s for \'%s\'', - FLAVOR_RELEASE, FLAVOR_DEBUG, FLAVOR_TESTING, test_args.apex) - return 1 - - try: - if test_args.host: - apex_provider = HostApexProvider(test_args.apex, test_args.tmpdir) - else: - apex_dir = test_args.apex - if not test_args.flattened: - # Extract the apex. It would be nice to use the output from "deapexer list" - # to avoid this work, but it doesn't provide info about executable bits. - apex_dir = extract_apex(test_args.apex, test_args.deapexer, test_args.debugfs, - test_args.fsckerofs, test_args.tmpdir) - apex_provider = TargetApexProvider(apex_dir) - except (zipfile.BadZipFile, zipfile.LargeZipFile) as e: - logging.error('Failed to create provider: %s', e) - return 1 + logging.error(' Could not detect APEX flavor, neither %s, %s nor %s for \'%s\'', + FLAVOR_RELEASE, FLAVOR_DEBUG, FLAVOR_TESTING, test_args.apex) + return 1 + + apex_dir = test_args.apex + if not test_args.flattened: + # Extract the apex. It would be nice to use the output from "deapexer list" + # to avoid this work, but it doesn't provide info about executable bits. + apex_dir = extract_apex(test_args.apex, test_args.deapexer, test_args.debugfs, + test_args.fsckerofs, test_args.tmpdir) + apex_provider = TargetApexProvider(apex_dir) if test_args.tree: Tree(apex_provider, test_args.apex, test_args.size).print_tree() @@ -991,16 +844,10 @@ def art_apex_test_main(test_args): base_checker = MultilibChecker(apex_provider) checkers.append(ReleaseChecker(base_checker)) - if test_args.host: - checkers.append(ReleaseHostChecker(base_checker)) - else: - checkers.append(ReleaseTargetChecker(base_checker)) if test_args.flavor == FLAVOR_DEBUG or test_args.flavor == FLAVOR_TESTING: checkers.append(DebugChecker(base_checker)) - if not test_args.host: - checkers.append(DebugTargetChecker(base_checker)) if test_args.flavor == FLAVOR_TESTING: - checkers.append(TestingTargetChecker(base_checker)) + checkers.append(TestingChecker(base_checker)) # This checker must be last. checkers.append(NoSuperfluousFilesChecker(base_checker)) @@ -1043,25 +890,22 @@ def art_apex_test_default(test_parser): test_args.debugfs) sys.exit(1) - # TODO: Add host support. # TODO: Add support for flattened APEX packages. configs = [ - {'name': 'com.android.art.capex', 'flavor': FLAVOR_RELEASE, 'host': False}, - {'name': 'com.android.art.debug.capex', 'flavor': FLAVOR_DEBUG, 'host': False}, + {'name': 'com.android.art.capex', 'flavor': FLAVOR_RELEASE}, + {'name': 'com.android.art.debug.capex', 'flavor': FLAVOR_DEBUG}, # Note: The Testing ART APEX is not a Compressed APEX. - {'name': 'com.android.art.testing.apex', 'flavor': FLAVOR_TESTING, 'host': False}, + {'name': 'com.android.art.testing.apex', 'flavor': FLAVOR_TESTING}, ] for config in configs: logging.info(config['name']) - # TODO: Host will need different path. test_args.apex = '%s/system/apex/%s' % (product_out, config['name']) if not os.path.exists(test_args.apex): failed = True logging.error('Cannot find APEX %s. Please build it first.', test_args.apex) continue test_args.flavor = config['flavor'] - test_args.host = config['host'] failed = art_apex_test_main(test_args) != 0 if failed: @@ -1073,8 +917,6 @@ if __name__ == '__main__': parser.add_argument('apex', help='APEX file input') - parser.add_argument('--host', help='Check as host APEX', action='store_true') - parser.add_argument('--flattened', help='Check as flattened (target) APEX', action='store_true') parser.add_argument('--flavor', help='Check as FLAVOR APEX', choices=FLAVORS_ALL, |