Merge "ART: Fix off-by-one error in BCE."
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index 9b5c638..a87e14c 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -195,6 +195,7 @@
host_supported: true,
device_supported: false,
manifest: "manifest.json",
+ java_libs: libcore_target_java_libs,
native_shared_libs: art_runtime_base_native_shared_libs
+ art_runtime_debug_native_shared_libs
+ libcore_native_shared_libs
diff --git a/build/apex/art_apex_test.py b/build/apex/art_apex_test.py
new file mode 100755
index 0000000..e636a72
--- /dev/null
+++ b/build/apex/art_apex_test.py
@@ -0,0 +1,463 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import argparse
+import logging
+import os
+import subprocess
+import sys
+import zipfile
+
+logging.basicConfig(format='%(message)s')
+
+class FSObject:
+ def __init__(self, name, is_dir, is_exec, is_symlink):
+ self.name = name
+ self.is_dir = is_dir
+ self.is_exec = is_exec
+ self.is_symlink = is_symlink
+ def __str__(self):
+ return '%s(dir=%r,exec=%r,symlink=%r)' % (self.name, self.is_dir, self.is_exec, self.is_symlink)
+
+class TargetApexProvider:
+ def __init__(self, apex, tmpdir, debugfs):
+ self._tmpdir = tmpdir
+ self._debugfs = debugfs
+ self._folder_cache = {}
+ self._payload = os.path.join(self._tmpdir, 'apex_payload.img')
+ # Extract payload to tmpdir.
+ zip = zipfile.ZipFile(apex)
+ zip.extract('apex_payload.img', 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]
+ # Cannot use check_output as it will annoy with stderr.
+ process = subprocess.Popen([self._debugfs, '-R', 'ls -l -p %s' % (dir), self._payload],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ universal_newlines=True)
+ stdout, stderr = process.communicate()
+ res = str(stdout)
+ map = {}
+ # Debugfs output looks like this:
+ # debugfs 1.44.4 (18-Aug-2018)
+ # /12/040755/0/2000/.//
+ # /2/040755/1000/1000/..//
+ # /13/100755/0/2000/dalvikvm32/28456/
+ # /14/100755/0/2000/dexoptanalyzer/20396/
+ # /15/100755/0/2000/linker/1152724/
+ # /16/100755/0/2000/dex2oat/563508/
+ # /17/100755/0/2000/linker64/1605424/
+ # /18/100755/0/2000/profman/85304/
+ # /19/100755/0/2000/dalvikvm64/28576/
+ # | | | | | |
+ # | | | #- gid #- name #- size
+ # | | #- uid
+ # | #- type and permission bits
+ # #- inode nr (?)
+ #
+ # Note: could break just on '/' to avoid names with newlines.
+ for line in res.split("\n"):
+ if not line:
+ continue
+ comps = line.split('/')
+ if len(comps) != 8:
+ logging.warn('Could not break and parse line \'%s\'', line)
+ continue
+ bits = comps[2]
+ name = comps[5]
+ if len(bits) != 6:
+ logging.warn('Dont understand bits \'%s\'', bits)
+ continue
+ is_dir = True if bits[1] == '4' else False
+ def is_exec_bit(ch):
+ return True if int(ch) & 1 == 1 else False
+ is_exec = is_exec_bit(bits[3]) and is_exec_bit(bits[4]) and is_exec_bit(bits[5])
+ is_symlink = True if bits[1] == '2' else False
+ map[name] = FSObject(name, is_dir, is_exec, is_symlink)
+ self._folder_cache[dir] = map
+ return map
+
+class Checker:
+ def __init__(self, provider):
+ self._provider = provider
+ self._errors = 0
+ self._is_multilib = provider.get('lib64') is not None;
+
+ def fail(self, msg, *args):
+ self._errors += 1
+ logging.error(msg, args)
+
+ def error_count(self):
+ return self._errors
+
+ def is_file(self, file):
+ fs_object = self._provider.get(file)
+ if fs_object is None:
+ return (False, 'Could not find %s')
+ if fs_object.is_dir:
+ return (False, '%s is a directory')
+ return (True, '')
+
+ def check_file(self, file):
+ chk = self.is_file(file)
+ if not chk[0]:
+ self.fail(chk[1], file)
+ return chk[0]
+
+ def check_binary(self, file):
+ path = 'bin/%s' % (file)
+ if not self.check_file(path):
+ return False
+ if not self._provider.get(path).is_exec:
+ self.fail('%s is not executable', path)
+ return False
+ return True
+
+ def check_multilib_binary(self, file):
+ res = self.check_binary('%s32' % (file))
+ if self._is_multilib:
+ res = self.check_binary('%s64' % (file)) and res
+ self.check_binary_symlink(file)
+ return res
+
+ def check_binary_symlink(self, file):
+ path = 'bin/%s' % (file)
+ fs_object = self._provider.get(path)
+ if fs_object is None:
+ self.fail('Could not find %s', path)
+ return False
+ if fs_object.is_dir:
+ self.fail('%s is a directory', path)
+ return False
+ if not fs_object.is_symlink:
+ self.fail('%s is not a symlink', path)
+ return False
+ return True
+
+ def check_library(self, file):
+ # TODO: Use $TARGET_ARCH (e.g. check whether it is "arm" or "arm64") to improve
+ # the precision of this test?
+ res = self.check_file('lib/%s' % (file))
+ if self._is_multilib:
+ res = self.check_file('lib64/%s' % (file)) and res
+ return res
+
+ def check_single_library(self, file):
+ res1 = self.is_file('lib/%s' % (file))
+ res2 = self.is_file('lib64/%s' % (file))
+ if not res1[0] and not res2[0]:
+ self.fail('Library missing: %s', file)
+ return False
+ return True
+
+ def check_java_library(self, file):
+ return self.check_file('javalib/%s' % (file))
+
+class ReleaseChecker(Checker):
+ def __init__(self, provider):
+ super().__init__(provider)
+ def __str__(self):
+ return 'Release Checker'
+
+ def run(self):
+ # Check that the mounted image contains an APEX manifest.
+ self.check_file('apex_manifest.json')
+
+ # Check that the mounted image contains ART base binaries.
+ self.check_multilib_binary('dalvikvm')
+ self.check_binary('dex2oat')
+ self.check_binary('dexoptanalyzer')
+ self.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.
+ # self.check_binary('oatdump')
+
+ # Check that the mounted image contains Android Runtime libraries.
+ self.check_library('libart-compiler.so')
+ self.check_library('libart-dexlayout.so')
+ self.check_library('libart.so')
+ self.check_library('libartbase.so')
+ self.check_library('libdexfile.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')
+ 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')
+
+ # 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
+ # ...
+ #
+ # ?
+
+ self.check_java_library('core-oj.jar')
+ self.check_java_library('core-libart.jar')
+ self.check_java_library('okhttp.jar')
+ self.check_java_library('bouncycastle.jar')
+ self.check_java_library('apache-xml.jar')
+
+class DebugChecker(Checker):
+ def __init__(self, provider):
+ super().__init__(provider)
+ def __str__(self):
+ return 'Debug Checker'
+
+ def run(self):
+ # Check that the mounted image contains ART tools binaries.
+ self.check_binary('dexdiag')
+ self.check_binary('dexdump')
+ self.check_binary('dexlist')
+
+ # Check that the mounted image contains ART debug binaries.
+ # TODO(b/123427238): This should probably be dex2oatd, fix!
+ self.check_binary('dex2oatd32')
+ self.check_binary('dexoptanalyzerd')
+ self.check_binary('profmand')
+
+ # Check that the mounted image contains Android Runtime debug libraries.
+ self.check_library('libartbased.so')
+ self.check_library('libartd-compiler.so')
+ self.check_library('libartd-dexlayout.so')
+ self.check_library('libartd.so')
+ self.check_library('libdexfiled.so')
+ self.check_library('libopenjdkjvmd.so')
+ self.check_library('libopenjdkjvmtid.so')
+ self.check_library('libprofiled.so')
+ # Check that the mounted image contains Android Core debug libraries.
+ self.check_library('libopenjdkd.so')
+ # Check that the mounted image contains additional required debug libraries.
+ self.check_library('libadbconnectiond.so')
+
+class DebugTargetChecker(Checker):
+ def __init__(self, provider):
+ super().__init__(provider)
+ def __str__(self):
+ return 'Debug (Target) Checker'
+
+ def run(self):
+ # Check for files pulled in from debug target-only oatdump.
+ self.check_binary('oatdump')
+ self.check_single_library('libart-disassembler.so')
+
+def print_list(provider):
+ def print_list_impl(provider, path):
+ map = provider.read_dir(path)
+ if map is None:
+ return
+ map = dict(map)
+ if '.' in map:
+ del map['.']
+ if '..' in map:
+ del map['..']
+ for (_, val) in sorted(map.items()):
+ new_path = os.path.join(path, val.name)
+ print(new_path)
+ if val.is_dir:
+ print_list_impl(provider, new_path)
+ print_list_impl(provider, '.')
+
+def print_tree(provider, title):
+ def get_vertical(has_next_list):
+ str = ''
+ for v in has_next_list:
+ str += '%s ' % ('│' if v else ' ')
+ return str
+ def get_last_vertical(last):
+ return '└── ' if last else '├── ';
+ def print_tree_impl(provider, path, has_next_list):
+ map = provider.read_dir(path)
+ if map is None:
+ return
+ map = dict(map)
+ if '.' in map:
+ del map['.']
+ if '..' in map:
+ del map['..']
+ key_list = list(sorted(map.keys()))
+ for i in range(0, len(key_list)):
+ val = map[key_list[i]]
+ prev = get_vertical(has_next_list)
+ last = get_last_vertical(i == len(key_list) - 1)
+ print('%s%s%s' % (prev, last, val.name))
+ if val.is_dir:
+ has_next_list.append(i < len(key_list) - 1)
+ print_tree_impl(provider, os.path.join(path, val.name), has_next_list)
+ has_next_list.pop()
+ print('%s' % (title))
+ 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")
+ 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")
+ 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:
+ logging.error("Need a tmpdir.")
+ return 1
+ if args.target and not args.debugfs:
+ logging.error("Need debugfs.")
+ return 1
+
+ try:
+ apex_provider = TargetApexProvider(args.apex, args.tmpdir, args.debugfs)
+ except Exception as e:
+ logging.error('Failed to create provider: %s', e)
+ return 1
+
+ if args.tree:
+ print_tree(apex_provider, args.apex)
+ return 0
+ if args.list:
+ print_list(apex_provider)
+ return 0
+
+ checkers = []
+ if args.host:
+ logging.error('host checking not yet supported')
+ return 1
+
+ checkers.append(ReleaseChecker(apex_provider))
+ if args.debug:
+ checkers.append(DebugChecker(apex_provider))
+ if args.debug and args.target:
+ checkers.append(DebugTargetChecker(apex_provider))
+
+ failed = False
+ for checker in checkers:
+ logging.info('%s...', checker)
+ checker.run()
+ if checker.error_count() > 0:
+ logging.error('%s FAILED', checker)
+ failed = True
+ else:
+ logging.info('%s SUCCEEDED', checker)
+
+ return 1 if failed else 0
+
+def artApexTestDefault(parser):
+ if not 'ANDROID_PRODUCT_OUT' in os.environ:
+ logging.error('No-argument use requires ANDROID_PRODUCT_OUT')
+ sys.exit(1)
+ product_out = os.environ['ANDROID_PRODUCT_OUT']
+ if not 'ANDROID_HOST_OUT' in os.environ:
+ logging.error('No-argument use requires ANDROID_HOST_OUT')
+ sys.exit(1)
+ host_out = os.environ['ANDROID_HOST_OUT']
+
+ args = parser.parse_args(['dummy']) # For consistency.
+ args.debugfs = '%s/bin/debugfs' % (host_out)
+ args.tmpdir = '.'
+ args.tree = False
+ args.list = False
+ failed = False
+
+ if not os.path.exists(args.debugfs):
+ logging.error("Cannot find debugfs (default path %s). Please build it, e.g., m debugfs",
+ args.debugfs)
+ sys.exit(1)
+
+ # 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},
+ ]
+
+ for config in configs:
+ logging.info(config['name'])
+ # TODO: Host will need different path.
+ args.apex = '%s/system/apex/%s.apex' % (product_out, config['name'])
+ if not os.path.exists(args.apex):
+ 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)
+ if exit_code != 0:
+ failed = True
+
+ if failed:
+ sys.exit(1)
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='Check integrity of a Runtime APEX.')
+
+ 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')
+ parser.add_argument('--tree', help='Print directory tree', action='store_true')
+
+ parser.add_argument('--tmpdir', help='Directory for temp files')
+ parser.add_argument('--debugfs', help='Path to debugfs')
+
+ if len(sys.argv) == 1:
+ artApexTestDefault(parser)
+ else:
+ args = parser.parse_args()
+
+ if args is None:
+ sys.exit(1)
+
+ exit_code = artApexTestMain(args)
+ sys.exit(exit_code)
diff --git a/build/apex/ld.config.txt b/build/apex/ld.config.txt
index d0145e4..1f0bf4d 100644
--- a/build/apex/ld.config.txt
+++ b/build/apex/ld.config.txt
@@ -33,6 +33,17 @@
namespace.platform.link.default.shared_libs += libnativebridge.so
namespace.platform.link.default.shared_libs += libnativehelper.so
namespace.platform.link.default.shared_libs += libnativeloader.so
+# /system/lib/libc.so, etc are symlinks to /bionic/lib/libc.so, etc.
+# Add /bionic/lib to the permitted paths because linker uses realpath(3)
+# to check the accessibility of the lib. We could add this to search.paths
+# instead but that makes the resolution of bionic libs be dependent on
+# the order of /system/lib and /bionic/lib in search.paths. If /bionic/lib
+# is after /system/lib, then /bionic/lib is never tried because libc.so
+# is always found in /system/lib but fails to pass the accessibility test
+# because of its realpath. It's better to not depend on the ordering if
+# possible.
+namespace.platform.permitted.paths = /bionic/${LIB}
+namespace.platform.asan.permitted.paths = /bionic/${LIB}
# Note that we don't need to link the default namespace with conscrypt:
# the runtime Java code and binaries do not explicitly load native libraries
diff --git a/build/apex/runtests.sh b/build/apex/runtests.sh
index 155709a..20da825 100755
--- a/build/apex/runtests.sh
+++ b/build/apex/runtests.sh
@@ -17,6 +17,8 @@
# Run Android Runtime APEX tests.
+SCRIPT_DIR=$(dirname $0)
+
# Status of whole test script.
exit_status=0
# Status of current test suite.
@@ -31,17 +33,17 @@
exit 1
}
-which guestmount >/dev/null && which guestunmount >/dev/null && which virt-filesystems >/dev/null \
- || die "This script requires 'guestmount', 'guestunmount',
-and 'virt-filesystems' from libguestfs. On Debian-based systems, these tools
-can be installed with:
-
- sudo apt-get install libguestfs-tools
-"
-
[[ -n "$ANDROID_PRODUCT_OUT" ]] \
|| die "You need to source and lunch before you can use this script."
+[[ -n "$ANDROID_HOST_OUT" ]] \
+ || die "You need to source and lunch before you can use this script."
+
+if [ ! -e "$ANDROID_HOST_OUT/bin/debugfs" ] ; then
+ say "Could not find debugfs, building now."
+ make debugfs-host || die "Cannot build debugfs"
+fi
+
# Fail early.
set -e
@@ -112,6 +114,25 @@
fi
}
+# maybe_list_apex_contents_apex APEX TMPDIR [other]
+function maybe_list_apex_contents_apex {
+ local apex=$1
+ local tmpdir=$2
+ shift 2
+
+ # List the contents of the apex in list form.
+ if $list_image_files_p; then
+ say "Listing image files"
+ $SCRIPT_DIR/art_apex_test.py --list --tmpdir "$tmpdir" $@ $apex
+ fi
+
+ # List the contents of the apex in tree form.
+ if $print_image_tree_p; then
+ say "Printing image tree"
+ $SCRIPT_DIR/art_apex_test.py --tree --tmpdir "$tmpdir" $@ $apex
+ fi
+}
+
function fail_check {
echo "$0: FAILED: $*"
test_status=1
@@ -148,9 +169,11 @@
}
function check_java_library {
- [[ -x "$mount_point/javalib/$1" ]] || fail_check "Cannot find java library '$1' in mounted image"
+ [[ -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.
@@ -180,7 +203,6 @@
# Check that the mounted image contains Android Core libraries.
check_library "libexpat${host_suffix}.so"
check_library libjavacore.so
- check_library libjavacrypto.so
check_library libopenjdk.so
check_library "libz${host_suffix}.so"
check_library libziparchive.so
@@ -201,14 +223,11 @@
#
# ?
- # TODO: Enable for host
- if [ $1 != "com.android.runtime.host" ]; then
- 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
- fi
+ 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`.
@@ -243,7 +262,6 @@
# Clean-up.
function cleanup_target {
- guestunmount "$mount_point"
rm -rf "$work_dir"
}
@@ -254,34 +272,6 @@
cleanup_target
}
-# setup_target_apex APEX_MODULE MOUNT_POINT
-# -----------------------------------------
-# Extract image from target APEX_MODULE and mount it in MOUNT_POINT.
-function setup_target_apex {
- local apex_module=$1
- local mount_point=$2
- local system_apexdir="$ANDROID_PRODUCT_OUT/system/apex"
- local apex_package="$system_apexdir/$apex_module.apex"
-
- say "Extracting and mounting image"
-
- # Extract the payload from the Android Runtime APEX.
- local image_filename="apex_payload.img"
- unzip -q "$apex_package" "$image_filename" -d "$work_dir"
- mkdir "$mount_point"
- local image_file="$work_dir/$image_filename"
-
- # Check filesystems in the image.
- local image_filesystems="$work_dir/image_filesystems"
- virt-filesystems -a "$image_file" >"$image_filesystems"
- # We expect a single partition (/dev/sda) in the image.
- local partition="/dev/sda"
- echo "$partition" | cmp "$image_filesystems" -
-
- # Mount the image from the Android Runtime APEX.
- guestmount -a "$image_file" -m "$partition" --ro "$mount_point"
-}
-
# Testing release APEX package (com.android.runtime.release).
# -----------------------------------------------------------
@@ -291,23 +281,24 @@
say "Processing APEX package $apex_module"
work_dir=$(mktemp -d)
-mount_point="$work_dir/image"
-host_suffix=""
trap finish_target EXIT
# Build the APEX package (optional).
build_apex "$apex_module"
-
-# Set up APEX package.
-setup_target_apex "$apex_module" "$mount_point"
+apex_path="$ANDROID_PRODUCT_OUT/system/apex/${apex_module}.apex"
# List the contents of the APEX image (optional).
-maybe_list_apex_contents "$mount_point"
+maybe_list_apex_contents_apex $apex_path $work_dir --target --debugfs $ANDROID_HOST_OUT/bin/debugfs
# Run tests on APEX package.
say "Checking APEX package $apex_module"
-check_release_contents "$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"
# Clean up.
trap - EXIT
@@ -325,27 +316,25 @@
say "Processing APEX package $apex_module"
work_dir=$(mktemp -d)
-mount_point="$work_dir/image"
-host_suffix=""
trap finish_target EXIT
# Build the APEX package (optional).
build_apex "$apex_module"
-
-# Set up APEX package.
-setup_target_apex "$apex_module" "$mount_point"
+apex_path="$ANDROID_PRODUCT_OUT/system/apex/${apex_module}.apex"
# List the contents of the APEX image (optional).
-maybe_list_apex_contents "$mount_point"
+maybe_list_apex_contents_apex $apex_path $work_dir --target --debugfs $ANDROID_HOST_OUT/bin/debugfs
# Run tests on APEX package.
say "Checking APEX package $apex_module"
-check_release_contents "$apex_module"
-check_debug_contents
-# Check for files pulled in from debug target-only oatdump.
-check_binary oatdump
-check_library libart-disassembler.so
+$SCRIPT_DIR/art_apex_test.py \
+ --tmpdir $work_dir \
+ --debugfs $ANDROID_HOST_OUT/bin/debugfs \
+ --target \
+ --debug \
+ $apex_path \
+ || fail_check "Debug checks failed"
# Clean up.
trap - EXIT
diff --git a/build/art.go b/build/art.go
index 22f6410..5236e31 100644
--- a/build/art.go
+++ b/build/art.go
@@ -348,26 +348,7 @@
func libartDefaultsFactory() android.Module {
c := &codegenProperties{}
module := cc.DefaultsFactory(c)
- android.AddLoadHook(module, func(ctx android.LoadHookContext) {
- codegen(ctx, c, true)
-
- type props struct {
- Target struct {
- Android struct {
- Shared_libs []string
- }
- }
- }
-
- p := &props{}
- // TODO: express this in .bp instead b/79671158
- if !envTrue(ctx, "ART_TARGET_LINUX") {
- p.Target.Android.Shared_libs = []string{
- "libmetricslogger",
- }
- }
- ctx.AppendProperties(p)
- })
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, true) })
return module
}
@@ -375,27 +356,7 @@
func libartStaticDefaultsFactory() android.Module {
c := &codegenProperties{}
module := cc.DefaultsFactory(c)
- android.AddLoadHook(module, func(ctx android.LoadHookContext) {
- codegen(ctx, c, true)
-
- type props struct {
- Target struct {
- Android struct {
- Static_libs []string
- }
- }
- }
-
- p := &props{}
- // TODO: express this in .bp instead b/79671158
- if !envTrue(ctx, "ART_TARGET_LINUX") {
- p.Target.Android.Static_libs = []string{
- "libmetricslogger",
- "libstatssocket",
- }
- }
- ctx.AppendProperties(p)
- })
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, true) })
return module
}
diff --git a/oatdump/oatdump_test.cc b/oatdump/oatdump_test.cc
index 7b1de01..8505b0c 100644
--- a/oatdump/oatdump_test.cc
+++ b/oatdump/oatdump_test.cc
@@ -92,7 +92,7 @@
// Test is failing on target, b/77469384.
TEST_DISABLED_FOR_TARGET();
std::string error_msg;
- ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {}));
+ ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {"--runtime-arg", "-Xmx64M"}));
ASSERT_TRUE(Exec(kDynamic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly));
const std::string dex_location =
tmp_dir_+ "/" + android::base::Basename(GetTestDexFileName(GetAppBaseName().c_str())) +
@@ -109,7 +109,7 @@
TEST_DISABLED_FOR_ARM_AND_MIPS();
TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
std::string error_msg;
- ASSERT_TRUE(GenerateAppOdexFile(kDynamic, {}));
+ ASSERT_TRUE(GenerateAppOdexFile(kStatic, {"--runtime-arg", "-Xmx64M"}));
ASSERT_TRUE(Exec(kStatic, kModeOat, {"--export-dex-to=" + tmp_dir_}, kListOnly));
}
diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc
index af5e67a..1279997 100644
--- a/runtime/hidden_api.cc
+++ b/runtime/hidden_api.cc
@@ -29,15 +29,6 @@
#include "thread-inl.h"
#include "well_known_classes.h"
-#ifdef ART_TARGET_ANDROID
-#include <metricslogger/metrics_logger.h>
-using android::metricslogger::ComplexEventLogger;
-using android::metricslogger::ACTION_HIDDEN_API_ACCESSED;
-using android::metricslogger::FIELD_HIDDEN_API_ACCESS_METHOD;
-using android::metricslogger::FIELD_HIDDEN_API_ACCESS_DENIED;
-using android::metricslogger::FIELD_HIDDEN_API_SIGNATURE;
-#endif
-
namespace art {
namespace hiddenapi {
@@ -182,28 +173,6 @@
return member_name_ == other.member_name_ && type_signature_ == other.type_signature_;
}
-#ifdef ART_TARGET_ANDROID
-// Convert an AccessMethod enum to a value for logging from the proto enum.
-// This method may look odd (the enum values are current the same), but it
-// prevents coupling the internal enum to the proto enum (which should never
-// be changed) so that we are free to change the internal one if necessary in
-// future.
-inline static int32_t GetEnumValueForLog(AccessMethod access_method) {
- switch (access_method) {
- case AccessMethod::kNone:
- return android::metricslogger::ACCESS_METHOD_NONE;
- case AccessMethod::kReflection:
- return android::metricslogger::ACCESS_METHOD_REFLECTION;
- case AccessMethod::kJNI:
- return android::metricslogger::ACCESS_METHOD_JNI;
- case AccessMethod::kLinking:
- return android::metricslogger::ACCESS_METHOD_LINKING;
- default:
- DCHECK(false);
- }
-}
-#endif
-
void MemberSignature::LogAccessToEventLog(AccessMethod access_method, bool access_denied) {
#ifdef ART_TARGET_ANDROID
if (access_method == AccessMethod::kLinking || access_method == AccessMethod::kNone) {
@@ -213,19 +182,32 @@
// None does not correspond to actual access, so should also be ignored.
return;
}
- ComplexEventLogger log_maker(ACTION_HIDDEN_API_ACCESSED);
- log_maker.AddTaggedData(FIELD_HIDDEN_API_ACCESS_METHOD, GetEnumValueForLog(access_method));
- if (access_denied) {
- log_maker.AddTaggedData(FIELD_HIDDEN_API_ACCESS_DENIED, 1);
+ Runtime* runtime = Runtime::Current();
+ if (runtime->IsAotCompiler()) {
+ return;
}
+ JNIEnvExt* env = Thread::Current()->GetJniEnv();
const std::string& package_name = Runtime::Current()->GetProcessPackageName();
- if (!package_name.empty()) {
- log_maker.SetPackageName(package_name);
+ ScopedLocalRef<jstring> package_str(env, env->NewStringUTF(package_name.c_str()));
+ if (env->ExceptionCheck()) {
+ env->ExceptionClear();
+ LOG(ERROR) << "Unable to allocate string for package name which called hidden api";
}
std::ostringstream signature_str;
Dump(signature_str);
- log_maker.AddTaggedData(FIELD_HIDDEN_API_SIGNATURE, signature_str.str());
- log_maker.Record();
+ ScopedLocalRef<jstring> signature_jstr(env,
+ env->NewStringUTF(signature_str.str().c_str()));
+ if (env->ExceptionCheck()) {
+ env->ExceptionClear();
+ LOG(ERROR) << "Unable to allocate string for hidden api method signature";
+ }
+ env->CallStaticVoidMethod(WellKnownClasses::dalvik_system_VMRuntime,
+ WellKnownClasses::dalvik_system_VMRuntime_hiddenApiUsed, package_str.get(),
+ signature_jstr.get(), static_cast<jint>(access_method), access_denied);
+ if (env->ExceptionCheck()) {
+ env->ExceptionClear();
+ LOG(ERROR) << "Unable to report hidden api usage";
+ }
#else
UNUSED(access_method);
UNUSED(access_denied);
diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h
index 8bd59ea..e15e9f3 100644
--- a/runtime/hidden_api.h
+++ b/runtime/hidden_api.h
@@ -45,11 +45,13 @@
return static_cast<EnforcementPolicy>(api_policy_int);
}
+// Hidden API access method
+// Thist must be kept in sync with VMRuntime.HiddenApiUsageLogger.ACCESS_METHOD_*
enum class AccessMethod {
- kNone, // internal test that does not correspond to an actual access by app
- kReflection,
- kJNI,
- kLinking,
+ kNone = 0, // internal test that does not correspond to an actual access by app
+ kReflection = 1,
+ kJNI = 2,
+ kLinking = 3,
};
// Represents the API domain of a caller/callee.
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index f61faa3..955a455 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -84,6 +84,7 @@
jmethodID WellKnownClasses::dalvik_system_BaseDexClassLoader_getLdLibraryPath;
jmethodID WellKnownClasses::dalvik_system_VMRuntime_runFinalization;
+jmethodID WellKnownClasses::dalvik_system_VMRuntime_hiddenApiUsed;
jmethodID WellKnownClasses::java_lang_Boolean_valueOf;
jmethodID WellKnownClasses::java_lang_Byte_valueOf;
jmethodID WellKnownClasses::java_lang_Character_valueOf;
@@ -344,6 +345,7 @@
dalvik_system_BaseDexClassLoader_getLdLibraryPath = CacheMethod(env, dalvik_system_BaseDexClassLoader, false, "getLdLibraryPath", "()Ljava/lang/String;");
dalvik_system_VMRuntime_runFinalization = CacheMethod(env, dalvik_system_VMRuntime, true, "runFinalization", "(J)V");
+ dalvik_system_VMRuntime_hiddenApiUsed = CacheMethod(env, dalvik_system_VMRuntime, true, "hiddenApiUsed", "(Ljava/lang/String;Ljava/lang/String;IZ)V");
java_lang_ClassNotFoundException_init = CacheMethod(env, java_lang_ClassNotFoundException, false, "<init>", "(Ljava/lang/String;Ljava/lang/Throwable;)V");
java_lang_ClassLoader_loadClass = CacheMethod(env, java_lang_ClassLoader, false, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
@@ -486,6 +488,7 @@
dalvik_system_BaseDexClassLoader_getLdLibraryPath = nullptr;
dalvik_system_VMRuntime_runFinalization = nullptr;
+ dalvik_system_VMRuntime_hiddenApiUsed = nullptr;
java_lang_Boolean_valueOf = nullptr;
java_lang_Byte_valueOf = nullptr;
java_lang_Character_valueOf = nullptr;
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index f0e98a8..872b562 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -93,6 +93,7 @@
static jmethodID dalvik_system_BaseDexClassLoader_getLdLibraryPath;
static jmethodID dalvik_system_VMRuntime_runFinalization;
+ static jmethodID dalvik_system_VMRuntime_hiddenApiUsed;
static jmethodID java_lang_Boolean_valueOf;
static jmethodID java_lang_Byte_valueOf;
static jmethodID java_lang_Character_valueOf;
diff --git a/test/testrunner/run_build_test_target.py b/test/testrunner/run_build_test_target.py
index 139d1af..19f03c3 100755
--- a/test/testrunner/run_build_test_target.py
+++ b/test/testrunner/run_build_test_target.py
@@ -28,6 +28,7 @@
import argparse
import os
+import pathlib
import subprocess
import sys
@@ -108,7 +109,10 @@
run_test_command = [os.path.join(env.ANDROID_BUILD_TOP,
'art/test/testrunner/testrunner.py')]
test_flags = target.get('run-test', [])
- run_test_command += list(map(lambda a: a.format(SOONG_OUT_DIR=env.SOONG_OUT_DIR), test_flags))
+ out_dir = pathlib.PurePath(env.SOONG_OUT_DIR)
+ if not out_dir.is_absolute():
+ out_dir = pathlib.PurePath(env.ANDROID_BUILD_TOP).joinpath(out_dir)
+ run_test_command += list(map(lambda a: a.format(SOONG_OUT_DIR=str(out_dir)), test_flags))
# Let testrunner compute concurrency based on #cpus.
# b/65822340
# run_test_command += ['-j', str(n_threads)]
diff --git a/tools/build_linux_bionic.sh b/tools/build_linux_bionic.sh
index d3c1912..b401071 100755
--- a/tools/build_linux_bionic.sh
+++ b/tools/build_linux_bionic.sh
@@ -35,14 +35,22 @@
# Soong needs a bunch of variables set and will not run if they are missing.
# The default values of these variables is only contained in make, so use
# nothing to create the variables then remove all the other artifacts.
-build/soong/soong_ui.bash --make-mode nothing
+
+# TODO(b/123645297) Move hiddenapi steps to soong.
+#
+# Currently hiddenapi relies on .mk to build some of it's configuration files.
+# This prevents us from just cleaning using soong and forces us to do this
+# hacky workaround where we build the targets without linux_bionic and delete
+# the build-config files before going around again. If we fix this issue we can
+# change to only building 'nothing' instead.
+build/soong/soong_ui.bash --make-mode "$@"
+
if [ $? != 0 ]; then
exit 1
fi
out_dir=$(get_build_var OUT_DIR)
host_out=$(get_build_var HOST_OUT)
-mk_product_out=$(get_build_var PRODUCT_OUT)
# TODO(b/31559095) Figure out a better way to do this.
#
@@ -51,14 +59,17 @@
tmp_soong_var=$(mktemp --tmpdir soong.variables.bak.XXXXXX)
cat $out_dir/soong/soong.variables > ${tmp_soong_var}
-build/soong/soong_ui.bash --make-mode clean
-mkdir -p $out_dir/soong
-mkdir -p $mk_product_out
-# TODO(b/31559095) Soong will panic if this file isn't present. It contains
-# information from MAKE needed to let soong handle the invocation of dex2oat.
-# This would be great to have but for now isn't needed.
-echo "{}" > $mk_product_out/dexpreopt.config
+# See comment above about b/123645297 for why we cannot just do m clean. Clear
+# out all files except for intermediates and installed files.
+find $out_dir/ -maxdepth 1 -mindepth 1 \
+ -not -name soong \
+ -not -name host \
+ -not -name target | xargs -I '{}' rm -rf '{}'
+find $out_dir/soong/ -maxdepth 1 -mindepth 1 \
+ -not -name .intermediates \
+ -not -name host \
+ -not -name target | xargs -I '{}' rm -rf '{}'
python3 <<END - ${tmp_soong_var} ${out_dir}/soong/soong.variables
import json
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index 398981e..5177919 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -236,9 +236,8 @@
]
},
{
- description: "Expected networking failure on host: we expect 97 (EAFNOSUPPORT), but we get 22 (EINVAL)",
+ description: "Expected networking failure on host / old systems: we expect 97 (EAFNOSUPPORT), but we get 22 (EINVAL)",
result: EXEC_FAILED,
- modes: [host],
names: [
"libcore.libcore.io.OsTest#testCrossFamilyBindConnectSendto"
]