summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Martin Stjernholm <mast@google.com> 2024-12-02 20:40:34 +0000
committer Martin Stjernholm <mast@google.com> 2024-12-04 12:10:41 +0000
commita0bdc8d7d84a470aabdb6a3bc5a0fa06a7d9dc84 (patch)
tree3a94f93ef9e068bfddaeaf0b6a0188fedf8c38a2
parentefad3542a83f4ccf34e987f9d2ba192b40ebc390 (diff)
Clean up host APEX support.
#codehealth Test: art/build/apex/runtests.sh Bug: 279835185 Change-Id: I512f162f0f5208774a48049489ce3f1f5dbc0e31
-rwxr-xr-xbuild/apex/art_apex_test.py270
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,