ART: Add host apex provider and move all testing
Add HostApexProvider to access zipapexes. Update some common
code.
Wire up host apex testing. Remove all testing from runtests.sh.
Test: art/build/apex/runtests.sh
Test: art/build/apex/runtests.sh -l -t
Change-Id: I6442fdf28d001e39e2ace2b9b6ce2e25ce98af78
diff --git a/build/apex/art_apex_test.py b/build/apex/art_apex_test.py
index e636a72..b686152 100755
--- a/build/apex/art_apex_test.py
+++ b/build/apex/art_apex_test.py
@@ -51,7 +51,7 @@
def get(self, path):
dir, name = os.path.split(path)
if len(dir) == 0:
- dir = '/'
+ dir = '.'
map = self.read_dir(dir)
return map[name] if name in map else None
@@ -104,6 +104,73 @@
self._folder_cache[dir] = map
return 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.
+ zip = zipfile.ZipFile(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):
+ dir, name = os.path.split(path)
+ if len(dir) == 0:
+ dir = ''
+ map = self.read_dir(dir)
+ return map[name] if name in map else None
+
+ def read_dir(self, dir):
+ if dir in self._folder_cache:
+ return self._folder_cache[dir]
+ if not self._folder_cache:
+ self.parse_zip()
+ if dir in self._folder_cache:
+ return self._folder_cache[dir]
+ return {}
+
+ def parse_zip(self):
+ zip = zipfile.ZipFile(self._payload)
+ infos = 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:
+ dir, base = os.path.split(path)
+ # TODO: If directories are stored, base will be empty.
+
+ if not dir in self._folder_cache:
+ self._folder_cache[dir] = {}
+ dir_map = self._folder_cache[dir]
+ if not base 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)
+ else:
+ is_exec = False # Seems we can't get this easily?
+ is_symlink = False
+ is_dir = True
+ dir_map[base] = FSObject(base, is_dir, is_exec, is_symlink)
+ is_zipinfo = False
+ path = dir
+
class Checker:
def __init__(self, provider):
self._provider = provider
@@ -177,6 +244,14 @@
return False
return True
+ def check_no_library(self, file):
+ res1 = self.is_file('lib/%s' % (file))
+ res2 = self.is_file('lib64/%s' % (file))
+ if res1[0] or res2[0]:
+ self.fail('Library exists: %s', file)
+ return False
+ return True
+
def check_java_library(self, file):
return self.check_file('javalib/%s' % (file))
@@ -205,15 +280,17 @@
self.check_library('libart-dexlayout.so')
self.check_library('libart.so')
self.check_library('libartbase.so')
+ self.check_library('libartpalette.so')
+ self.check_no_library('libartpalette-system.so')
self.check_library('libdexfile.so')
+ self.check_library('libdexfile_external.so')
self.check_library('libopenjdkjvm.so')
self.check_library('libopenjdkjvmti.so')
self.check_library('libprofile.so')
# Check that the mounted image contains Android Core libraries.
- self.check_library('libexpat.so')
+ # Note: host vs target libs are checked elsewhere.
self.check_library('libjavacore.so')
self.check_library('libopenjdk.so')
- self.check_library('libz.so')
self.check_library('libziparchive.so')
# Check that the mounted image contains additional required libraries.
self.check_library('libadbconnection.so')
@@ -238,6 +315,28 @@
self.check_java_library('bouncycastle.jar')
self.check_java_library('apache-xml.jar')
+class ReleaseTargetChecker(Checker):
+ def __init__(self, provider):
+ super().__init__(provider)
+ def __str__(self):
+ return 'Release (Target) Checker'
+
+ def run(self):
+ # Check that the mounted image contains Android Core libraries.
+ self.check_library('libexpat.so')
+ self.check_library('libz.so')
+
+class ReleaseHostChecker(Checker):
+ def __init__(self, provider):
+ super().__init__(provider)
+ def __str__(self):
+ return 'Release (Host) Checker'
+
+ def run(self):
+ # Check that the mounted image contains Android Core libraries.
+ self.check_library('libexpat-host.so')
+ self.check_library('libz-host.so')
+
class DebugChecker(Checker):
def __init__(self, provider):
super().__init__(provider)
@@ -296,7 +395,7 @@
print(new_path)
if val.is_dir:
print_list_impl(provider, new_path)
- print_list_impl(provider, '.')
+ print_list_impl(provider, '')
def print_tree(provider, title):
def get_vertical(has_next_list):
@@ -326,36 +425,31 @@
print_tree_impl(provider, os.path.join(path, val.name), has_next_list)
has_next_list.pop()
print('%s' % (title))
- print_tree_impl(provider, '.', [])
+ print_tree_impl(provider, '', [])
# Note: do not sys.exit early, for __del__ cleanup.
def artApexTestMain(args):
- if not args.host and not args.target and not args.debug and not args.tree and not args.list:
- logging.error("None of --host, --target, --debug, --tree nor --list set")
+ if args.tree and args.debug:
+ logging.error("Both of --tree and --debug set")
return 1
- if args.tree and (args.host or args.debug):
- logging.error("Both of --tree and --host|--debug set")
- return 1
- if args.list and (args.host or args.debug):
- logging.error("Both of --list and --host|--debug set")
+ if args.list and args.debug:
+ logging.error("Both of --list and --debug set")
return 1
if args.list and args.tree:
logging.error("Both of --list and --tree set")
return 1
- if args.host and (args.target or args.debug):
- logging.error("Both of --host and --target|--debug set")
- return 1
- if args.debug and not args.target:
- args.target = True
- if args.target and not args.tmpdir:
+ if not args.tmpdir:
logging.error("Need a tmpdir.")
return 1
- if args.target and not args.debugfs:
+ if not args.host and not args.debugfs:
logging.error("Need debugfs.")
return 1
try:
- apex_provider = TargetApexProvider(args.apex, args.tmpdir, args.debugfs)
+ if args.host:
+ apex_provider = HostApexProvider(args.apex, args.tmpdir)
+ else:
+ apex_provider = TargetApexProvider(args.apex, args.tmpdir, args.debugfs)
except Exception as e:
logging.error('Failed to create provider: %s', e)
return 1
@@ -368,14 +462,15 @@
return 0
checkers = []
- if args.host:
- logging.error('host checking not yet supported')
- return 1
checkers.append(ReleaseChecker(apex_provider))
+ if args.host:
+ checkers.append(ReleaseHostChecker(apex_provider))
+ else:
+ checkers.append(ReleaseTargetChecker(apex_provider))
if args.debug:
checkers.append(DebugChecker(apex_provider))
- if args.debug and args.target:
+ if args.debug and not args.host:
checkers.append(DebugTargetChecker(apex_provider))
failed = False
@@ -414,8 +509,8 @@
# TODO: Add host support
configs= [
- {'name': 'com.android.runtime.release', 'target': True, 'debug': False, 'host': False},
- {'name': 'com.android.runtime.debug', 'target': True, 'debug': True, 'host': False},
+ {'name': 'com.android.runtime.release', 'debug': False, 'host': False},
+ {'name': 'com.android.runtime.debug', 'debug': True, 'host': False},
]
for config in configs:
@@ -426,7 +521,6 @@
failed = True
logging.error("Cannot find APEX %s. Please build it first.", args.apex)
continue
- args.target = config['target']
args.debug = config['debug']
args.host = config['host']
exit_code = artApexTestMain(args)
@@ -442,7 +536,7 @@
parser.add_argument('apex', help='apex file input')
parser.add_argument('--host', help='Check as host apex', action='store_true')
- parser.add_argument('--target', help='Check as target apex', action='store_true')
+
parser.add_argument('--debug', help='Check as debug apex', action='store_true')
parser.add_argument('--list', help='List all files', action='store_true')