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')
diff --git a/build/apex/runtests.sh b/build/apex/runtests.sh
index da73857..95c1de9 100755
--- a/build/apex/runtests.sh
+++ b/build/apex/runtests.sh
@@ -77,15 +77,6 @@
shift
done
-if $print_image_tree_p; then
- which tree >/dev/null || die "This script requires the 'tree' tool.
-On Debian-based systems, this can be installed with:
-
- sudo apt-get install tree
-"
-fi
-
-
# build_apex APEX_MODULE
# ----------------------
# Build APEX package APEX_MODULE.
@@ -96,24 +87,6 @@
fi
}
-# maybe_list_apex_contents MOUNT_POINT
-# ------------------------------------
-# If any listing/printing option was used, honor them and display the contents
-# of the APEX payload at MOUNT_POINT.
-function maybe_list_apex_contents {
- local mount_point=$1
-
- # List the contents of the mounted image using `find` (optional).
- if $list_image_files_p; then
- say "Listing image files" && find "$mount_point"
- fi
-
- # List the contents of the mounted image using `tree` (optional).
- if $print_image_tree_p; then
- say "Printing image tree" && ls -ld "$mount_point" && tree -aph --du "$mount_point"
- fi
-}
-
# maybe_list_apex_contents_apex APEX TMPDIR [other]
function maybe_list_apex_contents_apex {
local apex=$1
@@ -139,134 +112,6 @@
exit_status=1
}
-function check_file {
- [[ -f "$mount_point/$1" ]] || fail_check "Cannot find file '$1' in mounted image"
-}
-
-function check_binary {
- [[ -x "$mount_point/bin/$1" ]] || fail_check "Cannot find binary '$1' in mounted image"
-}
-
-function check_multilib_binary {
- # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
- # the precision of this test?
- if ! [[ -L "$mount_point/bin/${1}" ]]; then
- fail_check "Cannot find symlink for multilib binary '$1' in mounted image"
- fi
- [[ -x "$mount_point/bin/${1}32" ]] || [[ -x "$mount_point/bin/${1}64" ]] \
- || fail_check "Cannot find binary '$1' in mounted image"
-}
-
-function check_binary_symlink {
- [[ -h "$mount_point/bin/$1" ]] || fail_check "Cannot find symbolic link '$1' in mounted image"
-}
-
-function check_library {
- # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
- # the precision of this test?
- [[ -f "$mount_point/lib/$1" ]] || [[ -f "$mount_point/lib64/$1" ]] \
- || fail_check "Cannot find library '$1' in mounted image"
-}
-
-function check_no_library {
- # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
- # the precision of this test?
- [[ ! -f "$mount_point/lib/$1" && ! -f "$mount_point/lib64/$1" ]] \
- || die "Found unwanted library '$1' in mounted image"
-}
-
-function check_java_library {
- [[ -f "$mount_point/javalib/$1" ]] || fail_check "Cannot find java library '$1' in mounted image"
-}
-
-# !!! NOTE: Please also update art_apex_test.py !!!
-
-# Check contents of APEX payload located in `$mount_point`.
-function check_release_contents {
- # Check that the mounted image contains an APEX manifest.
- check_file apex_manifest.json
-
- # Check that the mounted image contains ART base binaries.
- check_multilib_binary dalvikvm
- # TODO: Does not work yet (b/119942078).
- : check_binary_symlink dalvikvm
- check_binary dex2oat
- check_binary dexoptanalyzer
- check_binary profman
-
- # oatdump is only in device apex's due to build rules
- # TODO: Check for it when it is also built for host.
- : check_binary oatdump
-
- # Check that the mounted image contains Android Runtime libraries.
- check_library libart-compiler.so
- check_library libart-dexlayout.so
- check_library libart.so
- check_library libartbase.so
- check_library libartpalette.so
- check_no_library libartpalette-system.so
- check_library libdexfile.so
- check_library libdexfile_external.so
- check_library libopenjdkjvm.so
- check_library libopenjdkjvmti.so
- check_library libprofile.so
- # Check that the mounted image contains Android Core libraries.
- check_library "libexpat${host_suffix}.so"
- check_library libjavacore.so
- check_library libopenjdk.so
- check_library "libz${host_suffix}.so"
- check_library libziparchive.so
- # Check that the mounted image contains additional required libraries.
- check_library libadbconnection.so
-
- # TODO: Should we check for other libraries, such as:
- #
- # libbacktrace.so
- # libbase.so
- # liblog.so
- # libsigchain.so
- # libtombstoned_client.so
- # libunwindstack.so
- # libvixl.so
- # libvixld.so
- # ...
- #
- # ?
-
- check_java_library core-oj.jar
- check_java_library core-libart.jar
- check_java_library okhttp.jar
- check_java_library bouncycastle.jar
- check_java_library apache-xml.jar
-}
-
-# Check debug contents of APEX payload located in `$mount_point`.
-function check_debug_contents {
- # Check that the mounted image contains ART tools binaries.
- check_binary dexdiag
- check_binary dexdump
- check_binary dexlist
-
- # Check that the mounted image contains ART debug binaries.
- check_binary dex2oatd
- check_binary dexoptanalyzerd
- check_binary profmand
-
- # Check that the mounted image contains Android Runtime debug libraries.
- check_library libartbased.so
- check_library libartd-compiler.so
- check_library libartd-dexlayout.so
- check_library libartd.so
- check_library libdexfiled.so
- check_library libopenjdkjvmd.so
- check_library libopenjdkjvmtid.so
- check_library libprofiled.so
- # Check that the mounted image contains Android Core debug libraries.
- check_library libopenjdkd.so
- # Check that the mounted image contains additional required debug libraries.
- check_library libadbconnectiond.so
-}
-
# Testing target (device) APEX packages.
# ======================================
@@ -299,14 +144,13 @@
apex_path="$ANDROID_PRODUCT_OUT/system/apex/${apex_module}.apex"
# List the contents of the APEX image (optional).
-maybe_list_apex_contents_apex $apex_path $work_dir --target --debugfs $ANDROID_HOST_OUT/bin/debugfs
+maybe_list_apex_contents_apex $apex_path $work_dir --debugfs $ANDROID_HOST_OUT/bin/debugfs
# Run tests on APEX package.
say "Checking APEX package $apex_module"
$SCRIPT_DIR/art_apex_test.py \
--tmpdir $work_dir \
--debugfs $ANDROID_HOST_OUT/bin/debugfs \
- --target \
$apex_path \
|| fail_check "Release checks failed"
@@ -334,14 +178,13 @@
apex_path="$ANDROID_PRODUCT_OUT/system/apex/${apex_module}.apex"
# List the contents of the APEX image (optional).
-maybe_list_apex_contents_apex $apex_path $work_dir --target --debugfs $ANDROID_HOST_OUT/bin/debugfs
+maybe_list_apex_contents_apex $apex_path $work_dir --debugfs $ANDROID_HOST_OUT/bin/debugfs
# Run tests on APEX package.
say "Checking APEX package $apex_module"
$SCRIPT_DIR/art_apex_test.py \
--tmpdir $work_dir \
--debugfs $ANDROID_HOST_OUT/bin/debugfs \
- --target \
--debug \
$apex_path \
|| fail_check "Debug checks failed"
@@ -369,51 +212,30 @@
cleanup_host
}
-# setup_host_apex APEX_MODULE MOUNT_POINT
-# ---------------------------------------
-# Extract Zip file from host APEX_MODULE and extract it in MOUNT_POINT.
-function setup_host_apex {
- local apex_module=$1
- local mount_point=$2
- local system_apexdir="$ANDROID_HOST_OUT/apex"
- local apex_package="$system_apexdir/$apex_module.zipapex"
-
- say "Extracting payload"
-
- # Extract the payload from the Android Runtime APEX.
- local image_filename="apex_payload.zip"
- unzip -q "$apex_package" "$image_filename" -d "$work_dir"
- mkdir "$mount_point"
- local image_file="$work_dir/$image_filename"
-
- # Unzipping the payload
- unzip -q "$image_file" -d "$mount_point"
-}
-
apex_module="com.android.runtime.host"
test_status=0
say "Processing APEX package $apex_module"
work_dir=$(mktemp -d)
-mount_point="$work_dir/zip"
-host_suffix="-host"
trap finish_host EXIT
# Build the APEX package (optional).
build_apex "$apex_module"
-
-# Set up APEX package.
-setup_host_apex "$apex_module" "$mount_point"
+apex_path="$ANDROID_HOST_OUT/apex/${apex_module}.zipapex"
# List the contents of the APEX image (optional).
-maybe_list_apex_contents "$mount_point"
+maybe_list_apex_contents_apex $apex_path $work_dir --host
# Run tests on APEX package.
say "Checking APEX package $apex_module"
-check_release_contents "$apex_module"
-check_debug_contents
+$SCRIPT_DIR/art_apex_test.py \
+ --tmpdir $work_dir \
+ --host \
+ --debug \
+ $apex_path \
+ || fail_check "Debug checks failed"
# Clean up.
trap - EXIT