diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2019-11-11 21:23:59 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2019-11-11 21:23:59 +0000 |
commit | ff30d9fd59b70a6dbf8590ebdc6ddbccd81b561e (patch) | |
tree | a26da1d669e88b34b10b0f6c76b06abd8b694473 | |
parent | ed8bdf09d25c898b0962eaa1a645186d7954e381 (diff) | |
parent | a19d32b0216a289c888612cdd078679b850d7218 (diff) | |
download | art-android10-mainline-networking-release.tar.gz |
Snap for 6001391 from a19d32b0216a289c888612cdd078679b850d7218 to qt-aml-networking-releaseandroid-mainline-10.0.0_r6android10-mainline-networking-release
Change-Id: If29bb1a399233e3fa24a33d3b79c0d48613148eb
74 files changed, 1213 insertions, 661 deletions
diff --git a/CleanSpec.mk b/CleanSpec.mk index a094a242de..5aff4cfbff 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -99,6 +99,8 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/symbols/apex) # Remove dex2oat artifacts for boot image extensions (workaround for broken dependencies). $(call add-clean-step, find $(OUT_DIR) -name "*.oat" -o -name "*.odex" -o -name "*.art" -o -name '*.vdex' | xargs rm -f) +$(call add-clean-step, find $(OUT_DIR) -name "*.oat" -o -name "*.odex" -o -name "*.art" -o -name '*.vdex' | xargs rm -f) +$(call add-clean-step, find $(OUT_DIR) -name "*.oat" -o -name "*.odex" -o -name "*.art" -o -name '*.vdex' | xargs rm -f) # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST diff --git a/adbconnection/Android.bp b/adbconnection/Android.bp index da73619f00..239cecb2b9 100644 --- a/adbconnection/Android.bp +++ b/adbconnection/Android.bp @@ -55,15 +55,28 @@ art_cc_library { ], } +// We export a library to do the server-side socket handling that gets loaded +// by adbd from the art apex, so that we can update the socket handling +// independently from the adbd apex. cc_library { name: "libadbconnection_server", + srcs: ["adbconnection_server.cc"], + + export_include_dirs: ["include"], + + stl: "libc++_static", + shared_libs: ["liblog"], + whole_static_libs: ["libbase"], + + defaults: ["art_defaults"], visibility: [ - // TODO(b/133140750): Clean this up. "//system/core/adb", ], - srcs: ["adbconnection_server.cc"], - export_include_dirs: ["include"], - shared_libs: ["libbase"], + stubs: { + symbol_file: "libadbconnection_server.map.txt", + versions: ["1"], + }, + host_supported: true, recovery_available: true, } diff --git a/adbconnection/adbconnection_server.cc b/adbconnection/adbconnection_server.cc index 9c1aff913c..f69f4a7196 100644 --- a/adbconnection/adbconnection_server.cc +++ b/adbconnection/adbconnection_server.cc @@ -72,12 +72,12 @@ void adbconnection_listen(void (*callback)(int fd, pid_t pid)) { } while (true) { - int rc = TEMP_FAILURE_RETRY(epoll_wait(epfd.get(), events.data(), events.size(), -1)); - if (rc == -1) { + int epoll_rc = TEMP_FAILURE_RETRY(epoll_wait(epfd.get(), events.data(), events.size(), -1)); + if (epoll_rc == -1) { PLOG(FATAL) << "epoll_wait failed"; } - for (int i = 0; i < rc; ++i) { + for (int i = 0; i < epoll_rc; ++i) { const epoll_event& event = events[i]; if (event.data.fd == -1) { unique_fd client(TEMP_FAILURE_RETRY( diff --git a/adbconnection/libadbconnection_server.map.txt b/adbconnection/libadbconnection_server.map.txt new file mode 100644 index 0000000000..b631581031 --- /dev/null +++ b/adbconnection/libadbconnection_server.map.txt @@ -0,0 +1,22 @@ +# +# 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. +# + +LIBADBCONNECTION_SERVER_1 { + global: + adbconnection_listen; + local: + *; +}; diff --git a/build/Android.bp b/build/Android.bp index e2767ffc24..d686f34668 100644 --- a/build/Android.bp +++ b/build/Android.bp @@ -81,7 +81,8 @@ art_global_defaults { // Warn about thread safety violations with clang. "-Wthread-safety", - "-Wthread-safety-negative", + // TODO(b/144045034): turn on -Wthread-safety-negative + //"-Wthread-safety-negative", // Warn if switch fallthroughs aren't annotated. "-Wimplicit-fallthrough", diff --git a/build/apex/Android.bp b/build/apex/Android.bp index ceb3093294..809b8fce40 100644 --- a/build/apex/Android.bp +++ b/build/apex/Android.bp @@ -27,6 +27,7 @@ art_runtime_base_binaries_prefer32 = [ // the ART APEX. art_runtime_base_native_shared_libs = [ // External API (having APEX stubs). + "libadbconnection_server", "libdexfile_external", "libnativebridge", "libnativehelper", @@ -228,13 +229,6 @@ apex_defaults { art_tools_device_only_binaries, }, }, - binaries: [ - "art_postinstall_hook", - "art_preinstall_hook", - "art_preinstall_hook_boot", - "art_preinstall_hook_system_server", - "art_prepostinstall_utils", - ], prebuilts: ["com.android.art.ld.config.txt"], key: "com.android.art.key", required: [ @@ -269,7 +263,7 @@ apex_defaults { // Release version of the ART APEX module (not containing debug // variants nor tools), included in user builds. Also used for // storage-constrained devices in userdebug and eng builds. -apex { +art_apex { name: "com.android.art.release", defaults: ["com.android.art-defaults"], certificate: ":com.android.art.certificate", @@ -278,7 +272,7 @@ apex { // "Debug" version of the ART APEX module (containing both release and // debug variants, as well as additional tools), included in userdebug and // eng build. -apex { +art_apex { name: "com.android.art.debug", defaults: ["com.android.art-dev-defaults"], certificate: ":com.android.art.certificate", @@ -311,7 +305,7 @@ art_gtests = [ // "Testing" version of the ART APEX module (containing both release // and debug variants, additional tools, and ART gtests), for testing // purposes only. -apex_test { +art_apex_test { name: "com.android.art.testing", defaults: ["com.android.art-dev-defaults"], file_contexts: "com.android.art.debug", @@ -462,36 +456,3 @@ cc_prebuilt_binary { defaults: ["art-check-apex-gen-fakebin-defaults"], srcs: [":art-check-testing-apex-gen"], } - -// Pre-install scripts. - -sh_binary { - name: "art_preinstall_hook", - src: "art_preinstall_hook.sh", -} - -sh_binary { - name: "art_preinstall_hook_boot", - src: "art_preinstall_hook_boot.sh", -} - -sh_binary { - name: "art_preinstall_hook_system_server", - src: "art_preinstall_hook_system_server.sh", -} - -sh_binary { - name: "art_prepostinstall_utils", - src: "art_prepostinstall_utils.sh", -} - -sh_binary { - name: "art_postinstall_hook", - src: "art_postinstall_hook.sh", -} - -sh_binary { - name: "art_apex_boot_integrity", - src: "art_apex_boot_integrity.sh", - init_rc: ["art_apex_boot_integrity.rc"], -} diff --git a/build/apex/art_apex_test.py b/build/apex/art_apex_test.py index d9e5c0879e..7d2c79af23 100755 --- a/build/apex/art_apex_test.py +++ b/build/apex/art_apex_test.py @@ -267,6 +267,14 @@ class Checker: return False, '%s is a directory' return True, '' + def is_dir(self, path): + fs_object = self._provider.get(path) + if fs_object is None: + return False, 'Could not find %s' + if not fs_object.is_dir: + return False, '%s is not a directory' + return True, '' + def check_file(self, path): ok, msg = self.is_file(path) if not ok: @@ -294,27 +302,30 @@ class Checker: self.fail('%s is not a symlink', path) self._expected_file_globs.add(path) - def check_art_test_executable(self, filename): - # This is a simplistic implementation, as we declare victory as soon as the - # test binary is found for one of the supported (not built) architectures. - # Ideally we would propagate the built architectures from the build system - # to this script and require test binaries for all of them to be present. - # Note that this behavior is not specific to this method: there are other - # places in this script where we rely on this simplified strategy. + def arch_dirs_for_path(self, path): + # Look for target-specific subdirectories for the given directory path. + # This is needed because the list of build targets is not propagated + # to this script. # - # TODO: Implement the suggestion above (here and in other places in this - # script). - test_found = False + # TODO: Pass build target information to this script and fix all places + # where this function in used (or similar workarounds). + dirs = [] for arch in ARCHS: - test_path = '%s/%s/%s' % (ART_TEST_DIR, arch, filename) - test_is_file, _ = self.is_file(test_path) - if test_is_file: - test_found = True - self._expected_file_globs.add(test_path) - if not self._provider.get(test_path).is_exec: - self.fail('%s is not executable', test_path) - if not test_found: + dir = '%s/%s' % (path, arch) + found, _ = self.is_dir(dir) + if found: + dirs.append(dir) + return dirs + + def check_art_test_executable(self, filename): + dirs = self.arch_dirs_for_path(ART_TEST_DIR) + if not dirs: self.fail('ART test binary missing: %s', filename) + for dir in dirs: + test_path = '%s/%s' % (dir, filename) + self._expected_file_globs.add(test_path) + if not self._provider.get(test_path).is_exec: + self.fail('%s is not executable', test_path) def check_single_library(self, filename): lib_path = 'lib/%s' % filename @@ -328,6 +339,14 @@ class Checker: if not lib_is_file and not lib64_is_file: self.fail('Library missing: %s', filename) + def check_dexpreopt(self, basename): + dirs = self.arch_dirs_for_path('javalib') + if not dirs: + self.fail('Could not find javalib directory for any arch.') + for dir in dirs: + for ext in ['art', 'oat', 'vdex']: + self.check_file('%s/%s.%s' % (dir, basename, ext)) + def check_java_library(self, basename): return self.check_file('javalib/%s.jar' % basename) @@ -467,6 +486,7 @@ class ReleaseChecker: self._checker.check_native_library('libnativebridge') self._checker.check_native_library('libnativehelper') self._checker.check_native_library('libnativeloader') + self._checker.check_native_library('libadbconnection_server') # Check internal libraries for ART. self._checker.check_native_library('libadbconnection') @@ -522,6 +542,17 @@ class ReleaseChecker: self._checker.check_optional_native_library('libclang_rt.hwasan*') self._checker.check_optional_native_library('libclang_rt.ubsan*') + # Check dexpreopt files for libcore bootclasspath jars, unless this is a + # coverage build with EMMA_INSTRUMENT_FRAMEWORK=true (in that case we do not + # generate dexpreopt files because ART boot jars depend on framework and + # cannot be dexpreopted in isolation). + if 'EMMA_INSTRUMENT_FRAMEWORK' not in os.environ or not os.environ['EMMA_INSTRUMENT_FRAMEWORK']: + self._checker.check_dexpreopt('boot') + self._checker.check_dexpreopt('boot-apache-xml') + self._checker.check_dexpreopt('boot-bouncycastle') + self._checker.check_dexpreopt('boot-core-icu4j') + self._checker.check_dexpreopt('boot-core-libart') + self._checker.check_dexpreopt('boot-okhttp') class ReleaseTargetChecker: def __init__(self, checker): @@ -531,13 +562,6 @@ class ReleaseTargetChecker: return 'Release (Target) Checker' def run(self): - # Check the APEX package scripts. - self._checker.check_executable('art_postinstall_hook') - self._checker.check_executable('art_preinstall_hook') - self._checker.check_executable('art_preinstall_hook_boot') - self._checker.check_executable('art_preinstall_hook_system_server') - self._checker.check_executable('art_prepostinstall_utils') - # Check binaries for ART. self._checker.check_executable('oatdump') diff --git a/build/apex/art_postinstall_hook.sh b/build/apex/art_postinstall_hook.sh deleted file mode 100644 index cb3b887b76..0000000000 --- a/build/apex/art_postinstall_hook.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/system/bin/sh - -# 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. -# - -. `dirname $0`/art_prepostinstall_utils || exit 100 - -log_info "=== ART runtime post-install ===" - -# Check for OTA base folder. -if [ ! -d /data/ota/dalvik-cache ] ; then - log_error "Postinstall dalvik-cache does not exist or is not a directory" - exit 101 -fi - -log_info "Checking fsverity" - -# Measure (and enable) fsverity to see if things are installed. Enable is not -# idempotent, and we'd need to parse the error string to see whether it says -# data was installed. Rather do a two-step. -FILES=`find /data/ota/dalvik-cache -type f` -for FILE in $FILES ; do - fsverity measure $FILE && continue - ENABLE_MSG=`fsverity enable $FILE 2>&1` && continue - - # No installed data, can't enable. Clean up and fail. - log_error "Enable failed: $ENABLE_MSG" - rm -rf /data/ota/dalvik-cache - exit 200 -done - -log_info "Moving dalvik-cache" - -rm -rf /data/dalvik-cache/* || exit 102 -mv /data/ota/dalvik-cache/* /data/dalvik-cache/ || exit 103 -restorecon -R -F /data/dalvik-cache/* || exit 104 diff --git a/build/apex/art_preinstall_hook.sh b/build/apex/art_preinstall_hook.sh deleted file mode 100644 index 94a1b210ec..0000000000 --- a/build/apex/art_preinstall_hook.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/system/bin/sh - -# 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. -# - -. `dirname $0`/art_prepostinstall_utils || exit 100 - -log_info "=== ART runtime pre-install ===" - -set_arches || exit 101 -log_info "Arches = `echo $ARCHES`" - -# The runtime update uses /data/ota as a staging directory, similar to -# A/B OTA. (There is no overlap, as A/B uses slot prefixes.) - -# Create OTA base folder. -mkdir -p /data/ota/dalvik-cache || exit 102 -# Bind-mount to perceive as normal structure. -mount -o bind /data/ota/dalvik-cache /data/dalvik-cache || exit 103 - -for ARCH in $ARCHES ; do - log_info "Preparing compilation output directories for $ARCH" - - # Create OTA folders. - mkdir -p /data/ota/dalvik-cache/$ARCH || exit 104 - rm -rf /data/ota/dalvik-cache/$ARCH/* || exit 105 - - `dirname $0`/art_preinstall_hook_boot $ARCH || exit 200 -done - -PRIMARY_ARCH=`echo $ARCHES | sed -e 's/ .*//'` -`dirname $0`/art_preinstall_hook_system_server $PRIMARY_ARCH || exit 300 - -FILES=`find /data/dalvik-cache -type f` -for FILE in $FILES ; do - setup_fsverity $FILE || exit 400 -done diff --git a/build/apex/art_preinstall_hook_boot.sh b/build/apex/art_preinstall_hook_boot.sh deleted file mode 100644 index 0985befb9d..0000000000 --- a/build/apex/art_preinstall_hook_boot.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/system/bin/sh - -# 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. -# - -. `dirname $0`/art_prepostinstall_utils || exit 100 - -log_info "Preparing boot image compilation parameters" - -# Prefer DEX2OATBOOTCLASSPATH, then BOOTCLASSPATH. -USED_CLASSPATH=$DEX2OATBOOTCLASSPATH -if [ -z "$USED_CLASSPATH" ] ; then - USED_CLASSPATH=$BOOTCLASSPATH - if [ -z "$USED_CLASSPATH" ] ; then - log_error "Could not find boot class-path to compile" - exit 101 - fi -fi -BOOTCP=`echo $USED_CLASSPATH | tr ":" "\n"` - -DEX_FILES= -DEX_LOCATIONS= -for component in $BOOTCP ; do - DEX_FILES="$DEX_FILES --dex-file=$component" - DEX_LOCATIONS="$DEX_LOCATIONS --dex-location=$component" -done - -PROFILING= -if [ -f "/system/etc/boot-image.prof" ] ; then - PROFILING="--compiler-filter=speed-profile --profile-file=/system/etc/boot-image.prof" -fi -if [ -f "/system/etc/dirty-image-objects" ] ; then - PROFILING="$PROFILING --dirty-image-objects=/system/etc/dirty-image-objects" -fi - -DEX2OAT_IMAGE_XMX=`getprop dalvik.vm.image-dex2oat-Xmx` - -DEX2OAT_TARGET_ARCH=$1 -DEX2OAT_TARGET_CPU_VARIANT=`getprop dalvik.vm.isa.${DEX2OAT_TARGET_ARCH}.variant` -DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES=`getprop dalvik.vm.isa.${DEX2OAT_TARGET_ARCH}.features` - -log_info "Compiling boot image for $DEX2OAT_TARGET_ARCH" - -dex2oat \ - --avoid-storing-invocation \ - --runtime-arg -Xmx$DEX2OAT_IMAGE_XMX \ - $PROFILING \ - $DEX_FILES \ - $DEX_LOCATIONS \ - --generate-mini-debug-info \ - --strip \ - --oat-file=/data/dalvik-cache/$DEX2OAT_TARGET_ARCH/system@framework@boot.oat \ - --oat-location=/data/dalvik-cache/$DEX2OAT_TARGET_ARCH/system@framework@boot.oat \ - --image=/data/dalvik-cache/$DEX2OAT_TARGET_ARCH/system@framework@boot.art --base=0x70000000 \ - --instruction-set=$DEX2OAT_TARGET_ARCH \ - --instruction-set-variant=$DEX2OAT_TARGET_CPU_VARIANT \ - --instruction-set-features=$DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES \ - --android-root=/system \ - --no-inline-from=core-oj.jar \ - --abort-on-hard-verifier-error \ - --force-determinism || { log_error "Dex2oat failed" ; exit 102 ; } diff --git a/build/apex/art_preinstall_hook_system_server.sh b/build/apex/art_preinstall_hook_system_server.sh deleted file mode 100644 index 9462c3b885..0000000000 --- a/build/apex/art_preinstall_hook_system_server.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/system/bin/sh - -# 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. -# - -. `dirname $0`/art_prepostinstall_utils || exit 100 - -function dalvik_cache_name { - local input=$1 - # Strip first /, replace rest with @. - DALVIK_CACHE_NAME=`echo $input | sed -e 's,^/,,' -e 's,/,@,g'` - # Append @classes.dex. - DALVIK_CACHE_NAME="${DALVIK_CACHE_NAME}@classes.dex" -} - -log_info "Preparing system server compilation parameters" - -if [ "x$SYSTEMSERVERCLASSPATH" = "x" ] ; then - log_info "SYSTEMSERVERCLASSPATH is not set! Trying to retrieve from init.environ.rc." - SYSTEMSERVERCLASSPATH=`grep "export SYSTEMSERVERCLASSPATH" init.environ.rc | sed -e "s/.* //"` - if [ "x$SYSTEMSERVERCLASSPATH" = "x" ] ; then - log_error "Could not find SYSTEMSERVERCLASSPATH" - exit 101 - fi -fi -SYSCP=`echo $SYSTEMSERVERCLASSPATH | tr ":" "\n"` - -BOOTCPPARAM= -if [ ! -z "$DEX2OATBOOTCLASSPATH" ] ; then - BOOTCPPARAM="--runtime-arg -Xbootclasspath:$DEX2OATBOOTCLASSPATH" -fi - -DEX2OAT_IMAGE_XMX=`getprop dalvik.vm.dex2oat-Xmx` - -DEX2OAT_TARGET_ARCH=$1 -DEX2OAT_TARGET_CPU_VARIANT=`getprop dalvik.vm.isa.${DEX2OAT_TARGET_ARCH}.variant` -DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES=`getprop dalvik.vm.isa.${DEX2OAT_TARGET_ARCH}.features` - -# Do this like preopt: speed compile, no classpath, possibly pick up profiles. - -# TODO: App image? Would have to scan /system for an existing image. - -for COMPONENT in $SYSCP ; do - log_info "Compiling $COMPONENT" - dalvik_cache_name $COMPONENT - PROFILING= - if [ -f "${COMPONENT}.prof" ] ; then - PROFILING="--profile-file=${COMPONENT}.prof" - fi - dex2oat \ - --avoid-storing-invocation \ - --runtime-arg -Xmx$DEX2OAT_IMAGE_XMX \ - $BOOTCPPARAM \ - --class-loader-context=\& \ - --boot-image=/data/dalvik-cache/system@framework@boot.art \ - --dex-file=$COMPONENT \ - --dex-location=$COMPONENT \ - --oat-file=/data/dalvik-cache/$DEX2OAT_TARGET_ARCH/$DALVIK_CACHE_NAME \ - --android-root=/system \ - --instruction-set=$DEX2OAT_TARGET_ARCH \ - --instruction-set-variant=$DEX2OAT_TARGET_CPU_VARIANT \ - --instruction-set-features=$DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES \ - --no-generate-debug-info \ - --abort-on-hard-verifier-error \ - --force-determinism \ - --no-inline-from=core-oj.jar \ - --copy-dex-files=false \ - --compiler-filter=speed \ - --generate-mini-debug-info \ - $PROFILING \ - || { log_error "Dex2oat failed" ; exit 102 ; } -done diff --git a/build/apex/art_prepostinstall_utils.sh b/build/apex/art_prepostinstall_utils.sh deleted file mode 100644 index f5a94d12e3..0000000000 --- a/build/apex/art_prepostinstall_utils.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/system/bin/sh - -# 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. -# - -alias log_info="log -t art_apex -p i" -alias log_error="log -t art_apex -p f" - -# Set |ARCHES| to a string containing the architectures of the device. -function set_arches { - # Derive architectures. For now, stop at two. - local abilist_prop=`getprop ro.product.cpu.abilist` - local abilist=`echo $abilist_prop | tr "," "\n"` - ARCHES="" - for abi in $abilist ; do - case "$abi" in - arm64-v8a) - ARCHES="$ARCHES\narm64" - ;; - armeabi-v7a|armeabi) - ARCHES="$ARCHES\narm" - ;; - x86) - ARCHES="$ARCHES\nx86" - ;; - x86_64) - ARCHES="$ARCHES\nx86_64" - ;; - *) - log_error "Unsupported ABI $abi" - return 1 - ;; - esac - done - ARCHES=`echo $ARCHES | uniq` - return 0 -} - -function setup_fsverity { - local full_shell_path=`readlink -f $0` - local bin_dir=`dirname $full_shell_path` - local apex_dir=`dirname $bin_dir` - local sig_dir="${apex_dir}.signatures" - local file=$1 - local signature_file="$sig_dir/$file.sig" - # Setup. - log_info "fsverity setup for $file" - SETUP_MSG=`fsverity setup $file --signature=$signature_file --hash=sha256 2>&1` || \ - { log_error "Setup failed: $SETUP_MSG" ; return 300 ; } - # Enable. - log_info "fsverity enable for $file" - ENABLE_MSG=`fsverity enable $file 2>&1` || \ - { log_error "Enable failed: $ENABLE_MSG" ; return 301 ; } - # Test integrity. - INTEGRITY_MSG=`dd if=$file of=/dev/null bs=4k 2>&1` || \ - { log_error "Integrity failed: $INTEGRITY_MSG" ; return 302 ; } - return 0 -} diff --git a/build/apex/manifest-art.json b/build/apex/manifest-art.json index ebba1b27ef..59cbfac435 100644 --- a/build/apex/manifest-art.json +++ b/build/apex/manifest-art.json @@ -1,6 +1,4 @@ { "name": "com.android.art", - "version": 1, - "preInstallHook": "bin/art_preinstall_hook", - "postInstallHook": "bin/art_postinstall_hook" + "version": 1 } diff --git a/build/art.go b/build/art.go index 56eec54138..4c1099bc98 100644 --- a/build/art.go +++ b/build/art.go @@ -312,6 +312,10 @@ func init() { android.RegisterModuleType("art_global_defaults", artGlobalDefaultsFactory) android.RegisterModuleType("art_debug_defaults", artDebugDefaultsFactory) + // ART apex is special because it must include dexpreopt files for bootclasspath jars. + android.RegisterModuleType("art_apex", artApexBundleFactory) + android.RegisterModuleType("art_apex_test", artTestApexBundleFactory) + // TODO: This makes the module disable itself for host if HOST_PREFER_32_BIT is // set. We need this because the multilib types of binaries listed in the apex // rule must match the declared type. This is normally not difficult but HOST_PREFER_32_BIT @@ -321,8 +325,16 @@ func init() { android.RegisterModuleType("art_apex_test_host", artHostTestApexBundleFactory) } +func artApexBundleFactory() android.Module { + return apex.ApexBundleFactory(false /*testApex*/, true /*artApex*/) +} + +func artTestApexBundleFactory() android.Module { + return apex.ApexBundleFactory(true /*testApex*/, true /*artApex*/) +} + func artHostTestApexBundleFactory() android.Module { - module := apex.ApexBundleFactory( /*testApex*/ true) + module := apex.ApexBundleFactory(true /*testApex*/, true /*artApex*/) android.AddLoadHook(module, func(ctx android.LoadHookContext) { if envTrue(ctx, "HOST_PREFER_32_BIT") { type props struct { diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index feda8ba49e..095f027ca3 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -87,6 +87,7 @@ #include "mirror/class_loader.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" +#include "oat.h" #include "oat_file.h" #include "oat_file_assistant.h" #include "profile/profile_compilation_info.h" @@ -1221,10 +1222,6 @@ class Dex2Oat final { bool OpenFile() { // Prune non-existent dex files now so that we don't create empty oat files for multi-image. PruneNonExistentDexFiles(); - if (dex_locations_.empty()) { - LOG(ERROR) << "Nothing to compile after pruning non-existent dex files."; - return false; - } // Expand oat and image filenames for multi image. if ((IsBootImage() || IsBootImageExtension()) && image_filenames_.size() == 1) { diff --git a/dex2oat/dex2oat_image_test.cc b/dex2oat/dex2oat_image_test.cc index fc824c1a19..1a0a9c8892 100644 --- a/dex2oat/dex2oat_image_test.cc +++ b/dex2oat/dex2oat_image_test.cc @@ -50,7 +50,7 @@ namespace art { // A suitable address for loading the core images. -constexpr uint32_t kBaseAddress = 0x60000000; +constexpr uint32_t kBaseAddress = ART_BASE_ADDRESS; struct ImageSizes { size_t art_size = 0; diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc index 81366e4590..bd439b72b3 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -32,6 +32,7 @@ #include "arch/instruction_set_features.h" #include "base/macros.h" #include "base/mutex-inl.h" +#include "base/string_view_cpp20.h" #include "base/utils.h" #include "dex/art_dex_file_loader.h" #include "dex/base64_test_util.h" @@ -111,13 +112,15 @@ class Dex2oatTest : public Dex2oatEnvironmentTest { CompilerFilter::Filter filter, const std::vector<std::string>& extra_args = {}, bool expect_success = true, - bool use_fd = false) WARN_UNUSED { + bool use_fd = false, + bool use_zip_fd = false) WARN_UNUSED { return GenerateOdexForTest(dex_location, odex_location, filter, extra_args, expect_success, use_fd, + use_zip_fd, [](const OatFile&) {}); } @@ -131,9 +134,22 @@ class Dex2oatTest : public Dex2oatEnvironmentTest { const std::vector<std::string>& extra_args, bool expect_success, bool use_fd, + bool use_zip_fd, T check_oat) WARN_UNUSED { + std::vector<std::string> dex_locations; + if (use_zip_fd) { + std::string loc_arg = "--zip-location=" + dex_location; + CHECK(std::any_of(extra_args.begin(), + extra_args.end(), + [&](const std::string& s) { return s == loc_arg; })); + CHECK(std::any_of(extra_args.begin(), + extra_args.end(), + [](const std::string& s) { return StartsWith(s, "--zip-fd="); })); + } else { + dex_locations.push_back(dex_location); + } std::string error_msg; - int status = GenerateOdexForTestWithStatus({dex_location}, + int status = GenerateOdexForTestWithStatus(dex_locations, odex_location, filter, &error_msg, @@ -1082,7 +1098,8 @@ class Dex2oatClassLoaderContextTest : public Dex2oatTest { CompilerFilter::kQuicken, extra_args, expected_success, - /*use_fd*/ false, + /*use_fd=*/ false, + /*use_zip_fd=*/ false, check_oat)); } @@ -1602,8 +1619,9 @@ TEST_F(Dex2oatDedupeCode, DedupeTest) { base_oat_name, CompilerFilter::Filter::kSpeed, { "--deduplicate-code=false" }, - true, // expect_success - false, // use_fd + /*expect_success=*/ true, + /*use_fd=*/ false, + /*use_zip_fd=*/ false, [&no_dedupe_size](const OatFile& o) { no_dedupe_size = o.Size(); })); @@ -1613,8 +1631,9 @@ TEST_F(Dex2oatDedupeCode, DedupeTest) { base_oat_name, CompilerFilter::Filter::kSpeed, { "--deduplicate-code=true" }, - true, // expect_success - false, // use_fd + /*expect_success=*/ true, + /*use_fd=*/ false, + /*use_zip_fd=*/ false, [&dedupe_size](const OatFile& o) { dedupe_size = o.Size(); })); @@ -1630,8 +1649,9 @@ TEST_F(Dex2oatTest, UncompressedTest) { base_oat_name, CompilerFilter::Filter::kQuicken, { }, - true, // expect_success - false, // use_fd + /*expect_success=*/ true, + /*use_fd=*/ false, + /*use_zip_fd=*/ false, [](const OatFile& o) { CHECK(!o.ContainsDexCode()); })); @@ -1750,8 +1770,9 @@ TEST_F(Dex2oatTest, CompactDexGenerationFailure) { oat_filename, CompilerFilter::Filter::kVerify, { }, - true, // expect_success - false, // use_fd + /*expect_success=*/ true, + /*use_fd=*/ false, + /*use_zip_fd=*/ false, [](const OatFile& o) { CHECK(o.ContainsDexCode()); })); @@ -1882,8 +1903,9 @@ TEST_F(Dex2oatTest, DontExtract) { odex_location, CompilerFilter::Filter::kVerify, { "--copy-dex-files=false" }, - true, // expect_success - false, // use_fd + /*expect_success=*/ true, + /*use_fd=*/ false, + /*use_zip_fd=*/ false, [](const OatFile&) {})); { // Check the vdex doesn't have dex. @@ -1944,8 +1966,9 @@ TEST_F(Dex2oatTest, DontExtract) { // target. "--runtime-arg", "-Xuse-stderr-logger" }, - true, // expect_success - false, // use_fd + /*expect_success=*/ true, + /*use_fd=*/ false, + /*use_zip_fd=*/ false, [](const OatFile& o) { CHECK(o.ContainsDexCode()); })); @@ -2131,8 +2154,9 @@ TEST_F(Dex2oatTest, AppImageNoProfile) { odex_location, CompilerFilter::Filter::kSpeedProfile, { "--app-image-fd=" + std::to_string(app_image_file.GetFd()) }, - true, // expect_success - false, // use_fd + /*expect_success=*/ true, + /*use_fd=*/ false, + /*use_zip_fd=*/ false, [](const OatFile&) {})); // Open our generated oat file. std::string error_msg; @@ -2155,6 +2179,24 @@ TEST_F(Dex2oatTest, AppImageNoProfile) { EXPECT_EQ(header.GetImageSection(ImageHeader::kSectionArtFields).Size(), 0u); } +TEST_F(Dex2oatTest, ZipFd) { + std::string zip_location = GetTestDexFileName("MainUncompressed"); + std::unique_ptr<File> dex_file(OS::OpenFileForReading(zip_location.c_str())); + std::vector<std::string> extra_args{ + StringPrintf("--zip-fd=%d", dex_file->Fd()), + "--zip-location=" + zip_location, + }; + std::string out_dir = GetScratchDir(); + const std::string base_oat_name = out_dir + "/base.oat"; + ASSERT_TRUE(GenerateOdexForTest(zip_location, + base_oat_name, + CompilerFilter::Filter::kQuicken, + extra_args, + /*expect_success=*/ true, + /*use_fd=*/ false, + /*use_zip_fd=*/ true)); +} + TEST_F(Dex2oatTest, AppImageResolveStrings) { using Hotness = ProfileCompilationInfo::MethodHotness; // Create a profile with the startup method marked. @@ -2225,8 +2267,9 @@ TEST_F(Dex2oatTest, AppImageResolveStrings) { { "--app-image-file=" + app_image_location, "--resolve-startup-const-strings=true", "--profile-file=" + profile_file.GetFilename()}, - /* expect_success= */ true, - /* use_fd= */ false, + /*expect_success=*/ true, + /*use_fd=*/ false, + /*use_zip_fd=*/ false, [](const OatFile&) {})); // Open our generated oat file. std::string error_msg; @@ -2338,8 +2381,9 @@ TEST_F(Dex2oatClassLoaderContextTest, StoredClassLoaderContext) { odex_location, CompilerFilter::Filter::kQuicken, { "--class-loader-context=" + stored_context }, - true, // expect_success - false, // use_fd + /*expect_success=*/ true, + /*use_fd=*/ false, + /*use_zip_fd=*/ false, [&](const OatFile& oat_file) { EXPECT_NE(oat_file.GetClassLoaderContext(), stored_context) << output_; EXPECT_NE(oat_file.GetClassLoaderContext(), valid_context) << output_; @@ -2350,8 +2394,9 @@ TEST_F(Dex2oatClassLoaderContextTest, StoredClassLoaderContext) { CompilerFilter::Filter::kQuicken, { "--class-loader-context=" + valid_context, "--stored-class-loader-context=" + stored_context }, - true, // expect_success - false, // use_fd + /*expect_success=*/ true, + /*use_fd=*/ false, + /*use_zip_fd=*/ false, [&](const OatFile& oat_file) { EXPECT_EQ(oat_file.GetClassLoaderContext(), expected_stored_context) << output_; })); diff --git a/dex2oat/linker/image_test.cc b/dex2oat/linker/image_test.cc index 1a5701dd38..33d122bdbe 100644 --- a/dex2oat/linker/image_test.cc +++ b/dex2oat/linker/image_test.cc @@ -87,6 +87,8 @@ TEST_F(ImageTest, ImageHeaderIsValid) { oat_file_end, /*boot_image_begin=*/ 0u, /*boot_image_size=*/ 0u, + /*boot_image_component_count=*/ 0u, + /*boot_image_checksum=*/ 0u, sizeof(void*)); ASSERT_TRUE(image_header.IsValid()); diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h index fa08627168..9ec6e56922 100644 --- a/dex2oat/linker/image_test.h +++ b/dex2oat/linker/image_test.h @@ -48,6 +48,7 @@ #include "linker/multi_oat_relative_patcher.h" #include "lock_word.h" #include "mirror/object-inl.h" +#include "oat.h" #include "oat_writer.h" #include "scoped_thread_state_change-inl.h" #include "signal_catcher.h" diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc index ede5ef7704..eb87b82565 100644 --- a/dex2oat/linker/image_writer.cc +++ b/dex2oat/linker/image_writer.cc @@ -2653,6 +2653,22 @@ void ImageWriter::CreateHeader(size_t oat_index) { } } + // Compute boot image checksums for the primary component, leave as 0 otherwise. + uint32_t boot_image_components = 0u; + uint32_t boot_image_checksums = 0u; + if (oat_index == 0u) { + const std::vector<gc::space::ImageSpace*>& image_spaces = + Runtime::Current()->GetHeap()->GetBootImageSpaces(); + boot_image_components = dchecked_integral_cast<uint32_t>(image_spaces.size()); + DCHECK_EQ(boot_image_components == 0u, compiler_options_.IsBootImage()); + for (uint32_t i = 0; i != boot_image_components; ) { + const ImageHeader& header = image_spaces[i]->GetImageHeader(); + boot_image_checksums ^= header.GetImageChecksum(); + DCHECK_LE(header.GetComponentCount(), boot_image_components - i); + i += header.GetComponentCount(); + } + } + // Create the image sections. auto section_info_pair = image_info.CreateImageSections(); const size_t image_end = section_info_pair.first; @@ -2695,6 +2711,8 @@ void ImageWriter::CreateHeader(size_t oat_index) { PointerToLowMemUInt32(oat_file_end), boot_image_begin_, boot_image_size_, + boot_image_components, + boot_image_checksums, static_cast<uint32_t>(target_ptr_size_)); } diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index b3c8999e30..92de151416 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -61,6 +61,7 @@ #include "mirror/class_loader.h" #include "mirror/dex_cache-inl.h" #include "mirror/object-inl.h" +#include "oat.h" #include "oat_quick_method_header.h" #include "profile/profile_compilation_info.h" #include "quicken_info.h" diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h index fb263d9cd9..19c0cfefa2 100644 --- a/dex2oat/linker/oat_writer.h +++ b/dex2oat/linker/oat_writer.h @@ -35,7 +35,6 @@ #include "dex/type_reference.h" #include "linker/relative_patcher.h" // For RelativePatcherTargetProvider. #include "mirror/class.h" -#include "oat.h" namespace art { @@ -44,6 +43,7 @@ class CompiledMethod; class CompilerDriver; class CompilerOptions; class DexContainer; +class OatHeader; class OutputStream; class ProfileCompilationInfo; class TimingLogger; diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc index 2eb4476667..11600a8e01 100644 --- a/dex2oat/linker/oat_writer_test.cc +++ b/dex2oat/linker/oat_writer_test.cc @@ -41,6 +41,7 @@ #include "mirror/class-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" +#include "oat.h" #include "oat_file-inl.h" #include "oat_writer.h" #include "profile/profile_compilation_info.h" diff --git a/dex2oat/linker/relative_patcher_test.h b/dex2oat/linker/relative_patcher_test.h index dc53ac4321..f34e6eb059 100644 --- a/dex2oat/linker/relative_patcher_test.h +++ b/dex2oat/linker/relative_patcher_test.h @@ -29,7 +29,6 @@ #include "dex/string_reference.h" #include "driver/compiled_method_storage.h" #include "linker/relative_patcher.h" -#include "oat.h" #include "oat_quick_method_header.h" #include "stream/vector_output_stream.h" diff --git a/libartbase/Android.bp b/libartbase/Android.bp index e9b114319b..d8cf12366b 100644 --- a/libartbase/Android.bp +++ b/libartbase/Android.bp @@ -168,7 +168,6 @@ art_cc_library { defaults: ["libartbase_defaults"], visibility: [ // TODO(b/133140750): Clean this up. - "//frameworks/base/startop/view_compiler", "//packages/modules/NetworkStack/tests:__subpackages__", ], diff --git a/libartbase/base/hiddenapi_flags.h b/libartbase/base/hiddenapi_flags.h index cd0bc7578c..a9a903b71f 100644 --- a/libartbase/base/hiddenapi_flags.h +++ b/libartbase/base/hiddenapi_flags.h @@ -290,6 +290,16 @@ class ApiList { // Returns true when no ApiList is specified and no domain_api flags either. bool IsEmpty() const { return (GetValue() == Value::kInvalid) && (GetDomainApis() == 0); } + // Returns true if the ApiList is on blacklist. + bool IsBlacklisted() const { + return GetValue() == Value::kBlacklist; + } + + // Returns true if the ApiList is a test API. + bool IsTestApi() const { + return helper::MatchesBitMask(helper::ToBit(DomainApi::kTestApi), dex_flags_); + } + // Returns the maximum target SDK version allowed to access this ApiList. SdkVersion GetMaxAllowedSdkVersion() const { return kMaxSdkVersions[GetIntValue()]; } diff --git a/libartpalette/Android.bp b/libartpalette/Android.bp index ef140168db..0a45b8880b 100644 --- a/libartpalette/Android.bp +++ b/libartpalette/Android.bp @@ -63,10 +63,6 @@ art_cc_library { art_cc_library { name: "libartpalette", defaults: ["libartpalette_defaults"], - visibility: [ - // TODO(b/133140750): Clean this up. - "//frameworks/base/startop/view_compiler", - ], required: ["libartpalette-system"], // libartpalette.so dlopen()'s libartpalette-system. header_libs: ["libbase_headers"], target: { diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp index 554e17b18f..a08f89faa6 100644 --- a/libdexfile/Android.bp +++ b/libdexfile/Android.bp @@ -110,8 +110,6 @@ cc_defaults { ], defaults_visibility: [ "//art:__subpackages__", - // TODO(b/133140750): Clean this up. - "//frameworks/base/startop/view_compiler", ], static_libs: ["libdexfile"], } @@ -143,10 +141,6 @@ gensrcs { art_cc_library { name: "libdexfile", defaults: ["libdexfile_defaults"], - visibility: [ - // TODO(b/133140750): Clean this up. - "//frameworks/base/startop/view_compiler", - ], // Leave the symbols in the shared library so that stack unwinders can // produce meaningful name resolution. strip: { diff --git a/libelffile/elf/elf_builder.h b/libelffile/elf/elf_builder.h index b528f6a221..07f0d00b23 100644 --- a/libelffile/elf/elf_builder.h +++ b/libelffile/elf/elf_builder.h @@ -746,13 +746,13 @@ class ElfBuilder final { hash_.AllocateVirtualMemory(hash_.GetCacheSize()); Elf_Dyn dyns[] = { - { .d_tag = DT_HASH, .d_un.d_ptr = hash_.GetAddress() }, - { .d_tag = DT_STRTAB, .d_un.d_ptr = dynstr_.GetAddress() }, - { .d_tag = DT_SYMTAB, .d_un.d_ptr = dynsym_.GetAddress() }, - { .d_tag = DT_SYMENT, .d_un.d_ptr = sizeof(Elf_Sym) }, - { .d_tag = DT_STRSZ, .d_un.d_ptr = dynstr_.GetCacheSize() }, - { .d_tag = DT_SONAME, .d_un.d_ptr = soname_offset }, - { .d_tag = DT_NULL, .d_un.d_ptr = 0 }, + { .d_tag = DT_HASH, .d_un = { .d_ptr = hash_.GetAddress() }, }, + { .d_tag = DT_STRTAB, .d_un = { .d_ptr = dynstr_.GetAddress() }, }, + { .d_tag = DT_SYMTAB, .d_un = { .d_ptr = dynsym_.GetAddress() }, }, + { .d_tag = DT_SYMENT, .d_un = { .d_ptr = sizeof(Elf_Sym) }, }, + { .d_tag = DT_STRSZ, .d_un = { .d_ptr = dynstr_.GetCacheSize() }, }, + { .d_tag = DT_SONAME, .d_un = { .d_ptr = soname_offset }, }, + { .d_tag = DT_NULL, .d_un = { .d_ptr = 0 }, }, }; dynamic_.Add(&dyns, sizeof(dyns)); dynamic_.AllocateVirtualMemory(dynamic_.GetCacheSize()); diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc index 22a3bc5f06..50dc09c3c2 100644 --- a/openjdkjvmti/ti_redefine.cc +++ b/openjdkjvmti/ti_redefine.cc @@ -112,6 +112,7 @@ #include "non_debuggable_classes.h" #include "obj_ptr.h" #include "object_lock.h" +#include "reflective_value_visitor.h" #include "runtime.h" #include "runtime_globals.h" #include "stack.h" @@ -1640,6 +1641,11 @@ bool Redefiner::ClassRedefinition::FinishRemainingAllocations( } cur_data->SetNewClassObject(nc.Get()); + // We really want to be able to resolve to the new class-object using this dex-cache for + // verification work. Since we haven't put it in the class-table yet we wll just manually add it + // to the dex-cache. + // TODO: We should maybe do this in a better spot. + cur_data->GetNewDexCache()->SetResolvedType(nc->GetDexTypeIndex(), nc.Get()); } return true; } @@ -2087,25 +2093,84 @@ void Redefiner::ClassRedefinition::UpdateClassStructurally(const RedefinitionDat replacement->SetLockWord(orig->GetLockWord(false), false); orig->SetLockWord(art::LockWord::Default(), false); // Update live pointers in ART code. + auto could_change_resolution_of = [&](auto* field_or_method, + const auto& info) REQUIRES(art::Locks::mutator_lock_) { + constexpr bool is_method = std::is_same_v<art::ArtMethod*, decltype(field_or_method)>; + static_assert(is_method || std::is_same_v<art::ArtField*, decltype(field_or_method)>, + "Input is not field or method!"); + // Only dex-cache is used for resolution + if (LIKELY(info.GetType() != art::ReflectionSourceType::kSourceDexCacheResolvedField && + info.GetType() != art::ReflectionSourceType::kSourceDexCacheResolvedMethod)) { + return false; + } + if constexpr (is_method) { + // Only direct methods are used without further indirection through a vtable/IFTable. + // Constructors cannot be shadowed. + if (LIKELY(!field_or_method->IsDirect() || field_or_method->IsConstructor())) { + return false; + } + } else { + // Only non-private fields can be shadowed in a manner that's visible. + if (LIKELY(field_or_method->IsPrivate())) { + return false; + } + } + // We can only shadow things from our superclasses + if (LIKELY(!field_or_method->GetDeclaringClass()->IsAssignableFrom(orig))) { + return false; + } + if constexpr (is_method) { + auto direct_methods = replacement->GetDirectMethods(art::kRuntimePointerSize); + return std::find_if(direct_methods.begin(), + direct_methods.end(), + [&](art::ArtMethod& m) REQUIRES(art::Locks::mutator_lock_) { + return UNLIKELY(m.HasSameNameAndSignature(field_or_method)); + }) != direct_methods.end(); + } else { + auto pred = [&](art::ArtField& f) REQUIRES(art::Locks::mutator_lock_) { + return std::string_view(f.GetName()) == std::string_view(field_or_method->GetName()) && + std::string_view(f.GetTypeDescriptor()) == + std::string_view(field_or_method->GetTypeDescriptor()); + }; + if (field_or_method->IsStatic()) { + auto sfields = replacement->GetSFields(); + return std::find_if(sfields.begin(), sfields.end(), pred) != sfields.end(); + } else { + auto ifields = replacement->GetIFields(); + return std::find_if(ifields.begin(), ifields.end(), pred) != ifields.end(); + } + } + }; // TODO Performing 2 stack-walks back to back isn't the greatest. We might want to try to combine // it with the one ReplaceReferences does. Doing so would be rather complicated though. driver_->runtime_->VisitReflectiveTargets( [&](art::ArtField* f, const auto& info) REQUIRES(art::Locks::mutator_lock_) { + DCHECK(f != nullptr) << info; auto it = field_map.find(f); - if (it == field_map.end()) { - return f; + if (it != field_map.end()) { + VLOG(plugin) << "Updating " << info << " object for (field) " + << it->second->PrettyField(); + return it->second; + } else if (UNLIKELY(could_change_resolution_of(f, info))) { + // Resolution might change. Just clear the resolved value. + VLOG(plugin) << "Clearing resolution " << info << " for (field) " << f->PrettyField(); + return static_cast<art::ArtField*>(nullptr); } - VLOG(plugin) << "Updating " << info << " object for (field) " << it->second->PrettyField(); - return it->second; + return f; }, [&](art::ArtMethod* m, const auto& info) REQUIRES(art::Locks::mutator_lock_) { + DCHECK(m != nullptr) << info; auto it = method_map.find(m); - if (it == method_map.end()) { - return m; + if (it != method_map.end()) { + VLOG(plugin) << "Updating " << info << " object for (method) " + << it->second->PrettyMethod(); + return it->second; + } else if (UNLIKELY(could_change_resolution_of(m, info))) { + // Resolution might change. Just clear the resolved value. + VLOG(plugin) << "Clearing resolution " << info << " for (method) " << m->PrettyMethod(); + return static_cast<art::ArtMethod*>(nullptr); } - VLOG(plugin) << "Updating " << info << " object for (method) " - << it->second->PrettyMethod(); - return it->second; + return m; }); // Force every frame of every thread to deoptimize (any frame might have eg offsets compiled in). diff --git a/runtime/Android.bp b/runtime/Android.bp index cfa16f87dc..0546c69b41 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -497,7 +497,7 @@ gensrcs { "jdwp/jdwp_constants.h", "jni_id_type.h", "lock_word.h", - "oat.h", + "oat_file.h", "object_callbacks.h", "process_state.h", "reflective_value_visitor.h", diff --git a/runtime/art_field.h b/runtime/art_field.h index e44517e10b..bc2c399b74 100644 --- a/runtime/art_field.h +++ b/runtime/art_field.h @@ -75,6 +75,10 @@ class ArtField final { return (GetAccessFlags() & kAccFinal) != 0; } + bool IsPrivate() REQUIRES_SHARED(Locks::mutator_lock_) { + return (GetAccessFlags() & kAccPrivate) != 0; + } + uint32_t GetDexFieldIndex() { return field_dex_idx_; } diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index 3aec1c3211..dfadc622d1 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -39,7 +39,6 @@ #include "mirror/object-inl.h" #include "mirror/object_array.h" #include "mirror/string.h" -#include "oat.h" #include "obj_ptr-inl.h" #include "quick/quick_method_frame_info.h" #include "read_barrier-inl.h" diff --git a/runtime/dexopt_test.cc b/runtime/dexopt_test.cc index fd3d20d662..4f438e7aec 100644 --- a/runtime/dexopt_test.cc +++ b/runtime/dexopt_test.cc @@ -30,6 +30,7 @@ #include "dexopt_test.h" #include "gc/space/image_space.h" #include "hidden_api.h" +#include "oat.h" namespace art { void DexoptTest::SetUp() { diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 87ce674644..6a52d24f38 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -48,6 +48,7 @@ #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "mirror/var_handle.h" +#include "oat.h" #include "oat_file.h" #include "oat_quick_method_header.h" #include "quick_exception_handler.h" diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc index a1663c8503..53a03fd007 100644 --- a/runtime/gc/collector/concurrent_copying.cc +++ b/runtime/gc/collector/concurrent_copying.cc @@ -2023,12 +2023,12 @@ void ConcurrentCopying::RevokeThreadLocalMarkStacks(bool disable_weak_ref_access } void ConcurrentCopying::RevokeThreadLocalMarkStack(Thread* thread) { - Thread* self = Thread::Current(); - CHECK_EQ(self, thread); accounting::AtomicStack<mirror::Object>* tl_mark_stack = thread->GetThreadLocalMarkStack(); if (tl_mark_stack != nullptr) { - CHECK(is_marking_); - MutexLock mu(self, mark_stack_lock_); + // With 2-phase CC change, we cannot assert that is_marking_ will always be true + // as we perform thread stack scan even before enabling the read-barrier. + CHECK(is_marking_ || (use_generational_cc_ && !young_gen_)); + MutexLock mu(Thread::Current(), mark_stack_lock_); revoked_mark_stacks_.push_back(tl_mark_stack); RemoveThreadMarkStackMapping(thread, tl_mark_stack); thread->SetThreadLocalMarkStack(nullptr); diff --git a/runtime/gc/collector/immune_spaces_test.cc b/runtime/gc/collector/immune_spaces_test.cc index 88f5d4e0d0..b3a14e26d5 100644 --- a/runtime/gc/collector/immune_spaces_test.cc +++ b/runtime/gc/collector/immune_spaces_test.cc @@ -126,6 +126,8 @@ class ImmuneSpacesTest : public CommonRuntimeTest { /*oat_file_end=*/ PointerToLowMemUInt32(oat_map.Begin() + oat_size), /*boot_image_begin=*/ 0u, /*boot_image_size=*/ 0u, + /*boot_image_component_count=*/ 0u, + /*boot_image_checksum=*/ 0u, /*pointer_size=*/ sizeof(void*)); return new DummyImageSpace(std::move(image_map), std::move(live_bitmap), diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 4b63138dd6..85b79da329 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -1205,8 +1205,8 @@ void Heap::ResetGcPerformanceInfo() { post_gc_last_process_cpu_time_ns_ = process_cpu_start_time_ns_; post_gc_weighted_allocated_bytes_ = 0u; - total_bytes_freed_ever_ = 0; - total_objects_freed_ever_ = 0; + total_bytes_freed_ever_.store(0); + total_objects_freed_ever_.store(0); total_wait_time_ = 0; blocking_gc_count_ = 0; blocking_gc_time_ = 0; @@ -1903,7 +1903,21 @@ uint64_t Heap::GetObjectsAllocatedEver() const { } uint64_t Heap::GetBytesAllocatedEver() const { - return GetBytesFreedEver() + GetBytesAllocated(); + // Force the returned value to be monotonically increasing, in the sense that if this is called + // at A and B, such that A happens-before B, then the call at B returns a value no smaller than + // that at A. This is not otherwise guaranteed, since num_bytes_allocated_ is decremented first, + // and total_bytes_freed_ever_ is incremented later. + static std::atomic<uint64_t> max_bytes_so_far(0); + uint64_t so_far = max_bytes_so_far.load(std::memory_order_relaxed); + uint64_t current_bytes = GetBytesFreedEver(std::memory_order_acquire); + current_bytes += GetBytesAllocated(); + do { + if (current_bytes <= so_far) { + return so_far; + } + } while (!max_bytes_so_far.compare_exchange_weak(so_far /* updated */, + current_bytes, std::memory_order_relaxed)); + return current_bytes; } // Check whether the given object is an instance of the given class. @@ -2239,6 +2253,19 @@ void Heap::UnBindBitmaps() { } } +void Heap::IncrementFreedEver() { + // Counters are updated only by us, but may be read concurrently. + // The updates should become visible after the corresponding live object info. + total_objects_freed_ever_.store(total_objects_freed_ever_.load(std::memory_order_relaxed) + + GetCurrentGcIteration()->GetFreedObjects() + + GetCurrentGcIteration()->GetFreedLargeObjects(), + std::memory_order_release); + total_bytes_freed_ever_.store(total_bytes_freed_ever_.load(std::memory_order_relaxed) + + GetCurrentGcIteration()->GetFreedBytes() + + GetCurrentGcIteration()->GetFreedLargeObjectBytes(), + std::memory_order_release); +} + void Heap::PreZygoteFork() { if (!HasZygoteSpace()) { // We still want to GC in case there is some unreachable non moving objects that could cause a @@ -2313,10 +2340,7 @@ void Heap::PreZygoteFork() { if (temp_space_ != nullptr) { CHECK(temp_space_->IsEmpty()); } - total_objects_freed_ever_ += GetCurrentGcIteration()->GetFreedObjects() + - GetCurrentGcIteration()->GetFreedLargeObjects(); - total_bytes_freed_ever_ += GetCurrentGcIteration()->GetFreedBytes() + - GetCurrentGcIteration()->GetFreedLargeObjectBytes(); + IncrementFreedEver(); // Update the end and write out image. non_moving_space_->SetEnd(target_space.End()); non_moving_space_->SetLimit(target_space.Limit()); @@ -2588,10 +2612,7 @@ collector::GcType Heap::CollectGarbageInternal(collector::GcType gc_type, << "Could not find garbage collector with collector_type=" << static_cast<size_t>(collector_type_) << " and gc_type=" << gc_type; collector->Run(gc_cause, clear_soft_references || runtime->IsZygote()); - total_objects_freed_ever_ += GetCurrentGcIteration()->GetFreedObjects() + - GetCurrentGcIteration()->GetFreedLargeObjects(); - total_bytes_freed_ever_ += GetCurrentGcIteration()->GetFreedBytes() + - GetCurrentGcIteration()->GetFreedLargeObjectBytes(); + IncrementFreedEver(); RequestTrim(self); // Collect cleared references. SelfDeletingTask* clear = reference_processor_->CollectClearedReferences(self); diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index 6c3290f8ee..9ef6af5c97 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -553,13 +553,15 @@ class Heap { uint64_t GetBytesAllocatedEver() const; // Returns the total number of objects freed since the heap was created. - uint64_t GetObjectsFreedEver() const { - return total_objects_freed_ever_; + // With default memory order, this should be viewed only as a hint. + uint64_t GetObjectsFreedEver(std::memory_order mo = std::memory_order_relaxed) const { + return total_objects_freed_ever_.load(mo); } // Returns the total number of bytes freed since the heap was created. - uint64_t GetBytesFreedEver() const { - return total_bytes_freed_ever_; + // With default memory order, this should be viewed only as a hint. + uint64_t GetBytesFreedEver(std::memory_order mo = std::memory_order_relaxed) const { + return total_bytes_freed_ever_.load(mo); } space::RegionSpace* GetRegionSpace() const { @@ -1189,6 +1191,9 @@ class Heap { ALWAYS_INLINE void IncrementNumberOfBytesFreedRevoke(size_t freed_bytes_revoke); + // Update *_freed_ever_ counters to reflect current GC values. + void IncrementFreedEver(); + // Remove a vlog code from heap-inl.h which is transitively included in half the world. static void VlogHeapGrowth(size_t max_allowed_footprint, size_t new_footprint, size_t alloc_size); @@ -1342,10 +1347,10 @@ class Heap { size_t concurrent_start_bytes_; // Since the heap was created, how many bytes have been freed. - uint64_t total_bytes_freed_ever_; + std::atomic<uint64_t> total_bytes_freed_ever_; // Since the heap was created, how many objects have been freed. - uint64_t total_objects_freed_ever_; + std::atomic<uint64_t> total_objects_freed_ever_; // Number of bytes currently allocated and not yet reclaimed. Includes active // TLABS in their entirety, even if they have not yet been parceled out. diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 51bc6a85fa..9ff799c650 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -54,6 +54,7 @@ #include "mirror/executable-inl.h" #include "mirror/object-inl.h" #include "mirror/object-refvisitor-inl.h" +#include "oat.h" #include "oat_file.h" #include "runtime.h" #include "space-inl.h" @@ -818,6 +819,10 @@ class ImageSpace::Loader { image_filename); return nullptr; } + if (!ValidateBootImageChecksum(image_filename, *image_header, oat_file, error_msg)) { + DCHECK(!error_msg->empty()); + return nullptr; + } } if (VLOG_IS_ON(startup)) { @@ -941,6 +946,72 @@ class ImageSpace::Loader { } private: + static bool ValidateBootImageChecksum(const char* image_filename, + const ImageHeader& image_header, + const OatFile* oat_file, + /*out*/std::string* error_msg) { + // Use the boot image component count to calculate the checksum from + // the appropriate number of boot image chunks. + const std::vector<ImageSpace*>& image_spaces = + Runtime::Current()->GetHeap()->GetBootImageSpaces(); + uint32_t boot_image_component_count = image_header.GetBootImageComponentCount(); + size_t image_spaces_size = image_spaces.size(); + if (boot_image_component_count > image_spaces_size) { + *error_msg = StringPrintf("Too many boot image dependencies (%u > %zu) in image %s", + boot_image_component_count, + image_spaces_size, + image_filename); + return false; + } + uint32_t checksum = 0u; + size_t chunk_count = 0u; + for (size_t component_count = 0u; component_count != boot_image_component_count; ) { + const ImageHeader& current_header = image_spaces[component_count]->GetImageHeader(); + if (current_header.GetComponentCount() > boot_image_component_count - component_count) { + *error_msg = StringPrintf("Boot image component count in %s ends in the middle of a chunk, " + "%u is between %zu and %zu", + image_filename, + boot_image_component_count, + component_count, + component_count + current_header.GetComponentCount()); + return false; + } + component_count += current_header.GetComponentCount(); + checksum ^= current_header.GetImageChecksum(); + chunk_count += 1u; + } + if (image_header.GetBootImageChecksum() != checksum) { + *error_msg = StringPrintf("Boot image checksum mismatch (0x%x != 0x%x) in image %s", + image_header.GetBootImageChecksum(), + checksum, + image_filename); + return false; + } + // Oat checksums, if present, have already been validated, so we know that + // they match the loaded image spaces. Therefore, we just verify that they + // are consistent in the number of boot image chunks they list by looking + // for the kImageChecksumPrefix at the start of each component. + const char* oat_boot_class_path_checksums = + oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathChecksumsKey); + if (oat_boot_class_path_checksums != nullptr) { + size_t oat_bcp_chunk_count = 0u; + while (*oat_boot_class_path_checksums == kImageChecksumPrefix) { + oat_bcp_chunk_count += 1u; + // Find the start of the next component if any. + const char* separator = strchr(oat_boot_class_path_checksums, ':'); + oat_boot_class_path_checksums = (separator != nullptr) ? separator + 1u : ""; + } + if (oat_bcp_chunk_count != chunk_count) { + *error_msg = StringPrintf("Boot image chunk count mismatch (%zu != %zu) in image %s", + oat_bcp_chunk_count, + chunk_count, + image_filename); + return false; + } + } + return true; + } + static MemMap LoadImageFile(const char* image_filename, const char* image_location, const ImageHeader& image_header, @@ -1412,6 +1483,8 @@ class ImageSpace::BootImageLayout { size_t component_count; size_t reservation_size; uint32_t checksum; + uint32_t boot_image_component_count; + uint32_t boot_image_checksum; }; BootImageLayout(const std::string& image_location, ArrayRef<const std::string> boot_class_path) @@ -1492,6 +1565,10 @@ class ImageSpace::BootImageLayout { /*out*/std::vector<std::pair<std::string, size_t>>* base_locations_and_bcp_indexes, /*out*/std::string* error_msg); + bool ValidateBootImageChecksum(const std::string& actual_filename, + const ImageHeader& header, + /*out*/std::string* error_msg); + bool ReadHeader(const std::string& base_location, const std::string& base_filename, size_t bcp_index, @@ -1670,6 +1747,56 @@ bool ImageSpace::BootImageLayout::MatchNamedComponents( return true; } +bool ImageSpace::BootImageLayout::ValidateBootImageChecksum(const std::string& actual_filename, + const ImageHeader& header, + /*out*/std::string* error_msg) { + uint32_t boot_image_component_count = header.GetBootImageComponentCount(); + if (chunks_.empty() != (boot_image_component_count == 0u)) { + *error_msg = StringPrintf("Unexpected boot image component count in %s: %u, %s", + actual_filename.c_str(), + header.GetImageReservationSize(), + chunks_.empty() ? "should be 0" : "should not be 0"); + return false; + } + uint32_t component_count = 0u; + uint32_t composite_checksum = 0u; + for (const ImageChunk& chunk : chunks_) { + if (component_count == boot_image_component_count) { + break; // Hit the component count. + } + if (chunk.start_index != component_count) { + break; // End of contiguous chunks, fail below; same as reaching end of `chunks_`. + } + if (chunk.component_count > boot_image_component_count - component_count) { + *error_msg = StringPrintf("Boot image component count in %s ends in the middle of a chunk, " + "%u is between %u and %zu", + actual_filename.c_str(), + boot_image_component_count, + component_count, + component_count + chunk.component_count); + return false; + } + component_count += chunk.component_count; + composite_checksum ^= chunk.checksum; + } + DCHECK_LE(component_count, boot_image_component_count); + if (component_count != boot_image_component_count) { + *error_msg = StringPrintf("Missing boot image components for checksum in %s: %u > %u", + actual_filename.c_str(), + boot_image_component_count, + component_count); + return false; + } + if (composite_checksum != header.GetBootImageChecksum()) { + *error_msg = StringPrintf("Boot image checksum mismatch in %s: 0x%08x != 0x%08x", + actual_filename.c_str(), + header.GetBootImageChecksum(), + composite_checksum); + return false; + } + return true; +} + bool ImageSpace::BootImageLayout::ReadHeader(const std::string& base_location, const std::string& base_filename, size_t bcp_index, @@ -1702,6 +1829,9 @@ bool ImageSpace::BootImageLayout::ReadHeader(const std::string& base_location, allowed_reservation_size); return false; } + if (!ValidateBootImageChecksum(actual_filename, header, error_msg)) { + return false; + } if (chunks_.empty()) { base_address_ = reinterpret_cast32<uint32_t>(header.GetImageBegin()); @@ -1713,6 +1843,8 @@ bool ImageSpace::BootImageLayout::ReadHeader(const std::string& base_location, chunk.component_count = header.GetComponentCount(); chunk.reservation_size = header.GetImageReservationSize(); chunk.checksum = header.GetImageChecksum(); + chunk.boot_image_component_count = header.GetBootImageComponentCount(); + chunk.boot_image_checksum = header.GetBootImageChecksum(); chunks_.push_back(std::move(chunk)); next_bcp_index_ = bcp_index + header.GetComponentCount(); total_component_count_ += header.GetComponentCount(); @@ -2447,7 +2579,7 @@ class ImageSpace::BootImageLoader { bool OpenOatFile(ImageSpace* space, const std::string& dex_filename, bool validate_oat_file, - ArrayRef<const std::unique_ptr<ImageSpace>> available_dependencies, + ArrayRef<const std::unique_ptr<ImageSpace>> dependencies, TimingLogger* logger, /*inout*/MemMap* image_reservation, /*out*/std::string* error_msg) { @@ -2508,7 +2640,7 @@ class ImageSpace::BootImageLoader { space->GetName()); return false; } - } else if (available_dependencies.empty()) { + } else if (dependencies.empty()) { std::string expected_boot_class_path = android::base::Join(ArrayRef<const std::string>( boot_class_path_locations_).SubArray(0u, component_count), ':'); if (expected_boot_class_path != oat_boot_class_path) { @@ -2524,7 +2656,7 @@ class ImageSpace::BootImageLoader { if (!VerifyBootClassPathChecksums( oat_boot_class_path_checksums, oat_boot_class_path, - available_dependencies, + dependencies, ArrayRef<const std::string>(boot_class_path_locations_), ArrayRef<const std::string>(boot_class_path_), &local_error_msg)) { @@ -2591,6 +2723,14 @@ class ImageSpace::BootImageLoader { bool is_extension = (chunk.start_index != 0u); DCHECK_NE(spaces->empty(), is_extension); + if (max_image_space_dependencies < chunk.boot_image_component_count) { + DCHECK(is_extension); + *error_msg = StringPrintf("Missing dependencies for extension component %s, %zu < %u", + boot_class_path_locations_[chunk.start_index].c_str(), + max_image_space_dependencies, + chunk.boot_image_component_count); + return false; + } ArrayRef<const std::string> requested_bcp_locations = ArrayRef<const std::string>(boot_class_path_locations_).SubArray( chunk.start_index, chunk.component_count); @@ -2611,24 +2751,34 @@ class ImageSpace::BootImageLoader { !Loader::CheckImageComponentCount(*space, expected_component_count, error_msg)) { return false; } - if (i == 0 && chunk.checksum != space->GetImageHeader().GetImageChecksum()) { - *error_msg = StringPrintf("Image checksum modified since previously read from %s, " - "received %u, expected %u", + const ImageHeader& header = space->GetImageHeader(); + if (i == 0 && (chunk.checksum != header.GetImageChecksum() || + chunk.boot_image_component_count != header.GetBootImageComponentCount() || + chunk.boot_image_checksum != header.GetBootImageChecksum())) { + *error_msg = StringPrintf("Image header modified since previously read from %s; " + "checksum: 0x%08x -> 0x%08x," + "boot_image_component_count: %u -> %u, " + "boot_image_checksum: 0x%08x -> 0x%08x", space->GetImageFilename().c_str(), - space->GetImageHeader().GetImageChecksum(), - chunk.checksum); + chunk.checksum, + header.GetImageChecksum(), + chunk.boot_image_component_count, + header.GetBootImageComponentCount(), + chunk.boot_image_checksum, + header.GetBootImageChecksum()); return false; } } - ArrayRef<const std::unique_ptr<ImageSpace>> available_dependencies = - ArrayRef<const std::unique_ptr<ImageSpace>>(*spaces).SubArray(/*pos=*/ 0u, - max_image_space_dependencies); + DCHECK_GE(max_image_space_dependencies, chunk.boot_image_component_count); + ArrayRef<const std::unique_ptr<ImageSpace>> dependencies = + ArrayRef<const std::unique_ptr<ImageSpace>>(*spaces).SubArray( + /*pos=*/ 0u, chunk.boot_image_component_count); for (std::size_t i = 0u, size = locations.size(); i != size; ++i) { ImageSpace* space = (*spaces)[spaces->size() - chunk.component_count + i].get(); if (!OpenOatFile(space, boot_class_path_[chunk.start_index + i], validate_oat_file, - available_dependencies, + dependencies, logger, image_reservation, error_msg)) { @@ -3157,7 +3307,8 @@ bool ImageSpace::VerifyBootClassPathChecksums(std::string_view oat_checksums, size_t bcp_pos = 0u; if (StartsWith(oat_checksums, "i")) { - BootImageLayout layout(image_location, boot_class_path); + // Use only the matching part of the BCP for validation. + BootImageLayout layout(image_location, boot_class_path.SubArray(/*pos=*/ 0u, bcp_size)); std::string primary_image_location = layout.GetPrimaryImageLocation(); std::string system_filename; bool has_system = false; @@ -3257,10 +3408,17 @@ bool ImageSpace::VerifyBootClassPathChecksums( DCHECK(!error_msg->empty()); return false; } + const size_t num_image_spaces = image_spaces.size(); + if (num_image_spaces != oat_bcp_size) { + *error_msg = StringPrintf("Image header records more dependencies (%zu) than BCP (%zu)", + num_image_spaces, + oat_bcp_size); + return false; + } // Verify image checksums. size_t image_pos = 0u; - while (image_pos != image_spaces.size() && StartsWith(oat_checksums, "i")) { + while (image_pos != num_image_spaces && StartsWith(oat_checksums, "i")) { // Verify the current image checksum. const ImageHeader& current_header = image_spaces[image_pos]->GetImageHeader(); uint32_t component_count = current_header.GetComponentCount(); diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc index 98774bdf2d..6a9bdf6c79 100644 --- a/runtime/hidden_api.cc +++ b/runtime/hidden_api.cc @@ -435,15 +435,10 @@ bool ShouldDenyAccessToMemberImpl(T* member, ApiList api_list, AccessMethod acce DCHECK(member != nullptr); Runtime* runtime = Runtime::Current(); - EnforcementPolicy policy = runtime->GetHiddenApiEnforcementPolicy(); - DCHECK(policy != EnforcementPolicy::kDisabled) + EnforcementPolicy hiddenApiPolicy = runtime->GetHiddenApiEnforcementPolicy(); + DCHECK(hiddenApiPolicy != EnforcementPolicy::kDisabled) << "Should never enter this function when access checks are completely disabled"; - const bool deny_access = - (policy == EnforcementPolicy::kEnabled) && - IsSdkVersionSetAndMoreThan(runtime->GetTargetSdkVersion(), - api_list.GetMaxAllowedSdkVersion()); - MemberSignature member_signature(member); // Check for an exemption first. Exempted APIs are treated as white list. @@ -455,6 +450,18 @@ bool ShouldDenyAccessToMemberImpl(T* member, ApiList api_list, AccessMethod acce return false; } + EnforcementPolicy testApiPolicy = runtime->GetTestApiEnforcementPolicy(); + + bool deny_access = false; + if (hiddenApiPolicy == EnforcementPolicy::kEnabled) { + if (testApiPolicy == EnforcementPolicy::kDisabled && api_list.IsTestApi()) { + deny_access = false; + } else { + deny_access = IsSdkVersionSetAndMoreThan(runtime->GetTargetSdkVersion(), + api_list.GetMaxAllowedSdkVersion()); + } + } + if (access_method != AccessMethod::kNone) { // Print a log message with information about this class member access. // We do this if we're about to deny access, or the app is debuggable. diff --git a/runtime/hidden_api_test.cc b/runtime/hidden_api_test.cc index d5c03c3850..145bb07676 100644 --- a/runtime/hidden_api_test.cc +++ b/runtime/hidden_api_test.cc @@ -155,6 +155,44 @@ TEST_F(HiddenApiTest, CheckGetActionFromRuntimeFlags) { ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::Blacklist()), true); } +TEST_F(HiddenApiTest, CheckTestApiEnforcement) { + ScopedObjectAccess soa(self_); + + runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled); + runtime_->SetTargetSdkVersion( + static_cast<uint32_t>(hiddenapi::ApiList::GreylistMaxQ().GetMaxAllowedSdkVersion()) + 1); + + // Default case where all TestApis are treated like non-TestApi. + runtime_->SetTestApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Whitelist()), false); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Greylist()), false); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::GreylistMaxQ()), true); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::GreylistMaxP()), true); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::GreylistMaxO()), true); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Blacklist()), true); + + // A case where we want to allow access to TestApis. + runtime_->SetTestApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kDisabled); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Whitelist()), false); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Greylist()), false); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::GreylistMaxQ()), false); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::GreylistMaxP()), false); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::GreylistMaxO()), false); + ASSERT_EQ( + ShouldDenyAccess(hiddenapi::ApiList::TestApi() | hiddenapi::ApiList::Blacklist()), false); +} + TEST_F(HiddenApiTest, CheckMembersRead) { ASSERT_NE(nullptr, class1_field1_); ASSERT_NE(nullptr, class1_field12_); diff --git a/runtime/image.cc b/runtime/image.cc index 08b81c11c9..06ba946549 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -29,7 +29,7 @@ namespace art { const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' }; -const uint8_t ImageHeader::kImageVersion[] = { '0', '7', '9', '\0' }; // FP16ToHalf intrinsic +const uint8_t ImageHeader::kImageVersion[] = { '0', '8', '0', '\0' }; // Chained checksums. ImageHeader::ImageHeader(uint32_t image_reservation_size, uint32_t component_count, @@ -44,6 +44,8 @@ ImageHeader::ImageHeader(uint32_t image_reservation_size, uint32_t oat_file_end, uint32_t boot_image_begin, uint32_t boot_image_size, + uint32_t boot_image_component_count, + uint32_t boot_image_checksum, uint32_t pointer_size) : image_reservation_size_(image_reservation_size), component_count_(component_count), @@ -57,6 +59,8 @@ ImageHeader::ImageHeader(uint32_t image_reservation_size, oat_file_end_(oat_file_end), boot_image_begin_(boot_image_begin), boot_image_size_(boot_image_size), + boot_image_component_count_(boot_image_component_count), + boot_image_checksum_(boot_image_checksum), image_roots_(image_roots), pointer_size_(pointer_size) { CHECK_EQ(image_begin, RoundUp(image_begin, kPageSize)); diff --git a/runtime/image.h b/runtime/image.h index a2d163a47f..12950a3591 100644 --- a/runtime/image.h +++ b/runtime/image.h @@ -137,6 +137,8 @@ class PACKED(8) ImageHeader { uint32_t oat_file_end, uint32_t boot_image_begin, uint32_t boot_image_size, + uint32_t boot_image_component_count, + uint32_t boot_image_checksum, uint32_t pointer_size); bool IsValid() const; @@ -350,6 +352,14 @@ class PACKED(8) ImageHeader { return boot_image_size_; } + uint32_t GetBootImageComponentCount() const { + return boot_image_component_count_; + } + + uint32_t GetBootImageChecksum() const { + return boot_image_checksum_; + } + uint64_t GetDataSize() const { return data_size_; } @@ -461,10 +471,15 @@ class PACKED(8) ImageHeader { // .so files. Used for positioning a following alloc spaces. uint32_t oat_file_end_ = 0u; - // Boot image begin and end (app image headers only). + // Boot image begin and end (only applies to boot image extension and app image headers). uint32_t boot_image_begin_ = 0u; uint32_t boot_image_size_ = 0u; // Includes heap (*.art) and code (.oat). + // Number of boot image components that this image depends on and their composite checksum + // (only applies to boot image extension and app image headers). + uint32_t boot_image_component_count_ = 0u; + uint32_t boot_image_checksum_ = 0u; + // Absolute address of an Object[] of objects needed to reinitialize from an image. uint32_t image_roots_ = 0u; diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc index 38bd611c38..2dc9f672dd 100644 --- a/runtime/method_handles.cc +++ b/runtime/method_handles.cc @@ -419,6 +419,7 @@ static inline bool IsCallerTransformer(Handle<mirror::MethodType> callsite_type) static inline bool MethodHandleInvokeMethod(ArtMethod* called_method, Handle<mirror::MethodType> callsite_type, Handle<mirror::MethodType> target_type, + Handle<mirror::MethodType> nominal_type, Thread* self, ShadowFrame& shadow_frame, const InstructionOperands* const operands, @@ -543,6 +544,11 @@ static inline bool MethodHandleInvokeMethod(ArtMethod* called_method, return false; } + if (nominal_type != nullptr) { + return ConvertReturnValue(nominal_type, target_type, result) && + ConvertReturnValue(callsite_type, nominal_type, result); + } + return ConvertReturnValue(callsite_type, target_type, result); } @@ -714,8 +720,9 @@ bool DoInvokePolymorphicMethod(Thread* self, const InstructionOperands* const operands, JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { - StackHandleScope<1> hs(self); + StackHandleScope<2> hs(self); Handle<mirror::MethodType> handle_type(hs.NewHandle(method_handle->GetMethodType())); + Handle<mirror::MethodType> nominal_handle_type(hs.NewHandle(method_handle->GetNominalType())); const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind(); DCHECK(IsInvoke(handle_kind)); @@ -761,6 +768,7 @@ bool DoInvokePolymorphicMethod(Thread* self, return MethodHandleInvokeMethod(called_method, callsite_type, handle_type, + nominal_handle_type, self, shadow_frame, operands, diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc index c2c47a5187..96fc403690 100644 --- a/runtime/mirror/dex_cache.cc +++ b/runtime/mirror/dex_cache.cc @@ -176,19 +176,33 @@ void DexCache::InitializeDexCache(Thread* self, void DexCache::VisitReflectiveTargets(ReflectiveValueVisitor* visitor) { for (size_t i = 0; i < NumResolvedFields(); i++) { auto pair(GetNativePairPtrSize(GetResolvedFields(), i, kRuntimePointerSize)); + if (pair.index == FieldDexCachePair::InvalidIndexForSlot(i)) { + continue; + } ArtField* new_val = visitor->VisitField( pair.object, DexCacheSourceInfo(kSourceDexCacheResolvedField, pair.index, this)); if (UNLIKELY(new_val != pair.object)) { - pair.object = new_val; + if (new_val == nullptr) { + pair = FieldDexCachePair(nullptr, FieldDexCachePair::InvalidIndexForSlot(i)); + } else { + pair.object = new_val; + } SetNativePairPtrSize(GetResolvedFields(), i, pair, kRuntimePointerSize); } } for (size_t i = 0; i < NumResolvedMethods(); i++) { auto pair(GetNativePairPtrSize(GetResolvedMethods(), i, kRuntimePointerSize)); + if (pair.index == MethodDexCachePair::InvalidIndexForSlot(i)) { + continue; + } ArtMethod* new_val = visitor->VisitMethod( pair.object, DexCacheSourceInfo(kSourceDexCacheResolvedMethod, pair.index, this)); if (UNLIKELY(new_val != pair.object)) { - pair.object = new_val; + if (new_val == nullptr) { + pair = MethodDexCachePair(nullptr, MethodDexCachePair::InvalidIndexForSlot(i)); + } else { + pair.object = new_val; + } SetNativePairPtrSize(GetResolvedMethods(), i, pair, kRuntimePointerSize); } } diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc index 156895d03b..ce942c846d 100644 --- a/runtime/native/dalvik_system_ZygoteHooks.cc +++ b/runtime/native/dalvik_system_ZygoteHooks.cc @@ -134,24 +134,25 @@ static void CollectNonDebuggableClasses() REQUIRES(!Locks::mutator_lock_) { // Must match values in com.android.internal.os.Zygote. enum { - DEBUG_ENABLE_JDWP = 1, - DEBUG_ENABLE_CHECKJNI = 1 << 1, - DEBUG_ENABLE_ASSERT = 1 << 2, - DEBUG_ENABLE_SAFEMODE = 1 << 3, - DEBUG_ENABLE_JNI_LOGGING = 1 << 4, - DEBUG_GENERATE_DEBUG_INFO = 1 << 5, - DEBUG_ALWAYS_JIT = 1 << 6, - DEBUG_NATIVE_DEBUGGABLE = 1 << 7, - DEBUG_JAVA_DEBUGGABLE = 1 << 8, - DISABLE_VERIFIER = 1 << 9, - ONLY_USE_SYSTEM_OAT_FILES = 1 << 10, - DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 11, - HIDDEN_API_ENFORCEMENT_POLICY_MASK = (1 << 12) - | (1 << 13), - PROFILE_SYSTEM_SERVER = 1 << 14, - PROFILE_FROM_SHELL = 1 << 15, - USE_APP_IMAGE_STARTUP_CACHE = 1 << 16, - DEBUG_IGNORE_APP_SIGNAL_HANDLER = 1 << 17, + DEBUG_ENABLE_JDWP = 1, + DEBUG_ENABLE_CHECKJNI = 1 << 1, + DEBUG_ENABLE_ASSERT = 1 << 2, + DEBUG_ENABLE_SAFEMODE = 1 << 3, + DEBUG_ENABLE_JNI_LOGGING = 1 << 4, + DEBUG_GENERATE_DEBUG_INFO = 1 << 5, + DEBUG_ALWAYS_JIT = 1 << 6, + DEBUG_NATIVE_DEBUGGABLE = 1 << 7, + DEBUG_JAVA_DEBUGGABLE = 1 << 8, + DISABLE_VERIFIER = 1 << 9, + ONLY_USE_SYSTEM_OAT_FILES = 1 << 10, + DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 11, + HIDDEN_API_ENFORCEMENT_POLICY_MASK = (1 << 12) + | (1 << 13), + PROFILE_SYSTEM_SERVER = 1 << 14, + PROFILE_FROM_SHELL = 1 << 15, + USE_APP_IMAGE_STARTUP_CACHE = 1 << 16, + DEBUG_IGNORE_APP_SIGNAL_HANDLER = 1 << 17, + DISABLE_TEST_API_ENFORCEMENT_POLICY = 1 << 18, // bits to shift (flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) by to get a value // corresponding to hiddenapi::EnforcementPolicy @@ -319,6 +320,13 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env, (runtime_flags & HIDDEN_API_ENFORCEMENT_POLICY_MASK) >> API_ENFORCEMENT_POLICY_SHIFT); runtime_flags &= ~HIDDEN_API_ENFORCEMENT_POLICY_MASK; + if ((runtime_flags & DISABLE_TEST_API_ENFORCEMENT_POLICY) != 0u) { + runtime->SetTestApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kDisabled); + } else { + runtime->SetTestApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled); + } + runtime_flags &= ~DISABLE_TEST_API_ENFORCEMENT_POLICY; + bool profile_system_server = (runtime_flags & PROFILE_SYSTEM_SERVER) == PROFILE_SYSTEM_SERVER; runtime_flags &= ~PROFILE_SYSTEM_SERVER; diff --git a/runtime/oat.cc b/runtime/oat.cc index db6cda5027..3fceec9364 100644 --- a/runtime/oat.cc +++ b/runtime/oat.cc @@ -411,9 +411,4 @@ void OatHeader::Flatten(const SafeMap<std::string, std::string>* key_value_store key_value_store_size_ = data_ptr - reinterpret_cast<char*>(&key_value_store_); } -OatMethodOffsets::OatMethodOffsets(uint32_t code_offset) : code_offset_(code_offset) { -} - -OatMethodOffsets::~OatMethodOffsets() {} - } // namespace art diff --git a/runtime/oat.h b/runtime/oat.h index 7817bd3910..352b9e892e 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -32,8 +32,8 @@ class InstructionSetFeatures; class PACKED(4) OatHeader { public: static constexpr std::array<uint8_t, 4> kOatMagic { { 'o', 'a', 't', '\n' } }; - // Last oat version changed reason: Boot image extension. - static constexpr std::array<uint8_t, 4> kOatVersion { { '1', '7', '4', '\0' } }; + // Last oat version changed reason: Revert^4 Boot image extension. + static constexpr std::array<uint8_t, 4> kOatVersion { { '1', '7', '6', '\0' } }; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; static constexpr const char* kDebuggableKey = "debuggable"; @@ -134,31 +134,6 @@ class PACKED(4) OatHeader { DISALLOW_COPY_AND_ASSIGN(OatHeader); }; -// OatMethodOffsets are currently 5x32-bits=160-bits long, so if we can -// save even one OatMethodOffsets struct, the more complicated encoding -// using a bitmap pays for itself since few classes will have 160 -// methods. -enum OatClassType { - kOatClassAllCompiled = 0, // OatClass is followed by an OatMethodOffsets for each method. - kOatClassSomeCompiled = 1, // A bitmap of which OatMethodOffsets are present follows the OatClass. - kOatClassNoneCompiled = 2, // All methods are interpreted so no OatMethodOffsets are necessary. - kOatClassMax = 3, -}; - -std::ostream& operator<<(std::ostream& os, const OatClassType& rhs); - -class PACKED(4) OatMethodOffsets { - public: - explicit OatMethodOffsets(uint32_t code_offset = 0); - - ~OatMethodOffsets(); - - OatMethodOffsets(const OatMethodOffsets&) = default; - OatMethodOffsets& operator=(const OatMethodOffsets&) = default; - - uint32_t code_offset_; -}; - } // namespace art #endif // ART_RUNTIME_OAT_H_ diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 69d5efd4f4..70a9534824 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -34,7 +34,6 @@ #include "dex/utf.h" #include "index_bss_mapping.h" #include "mirror/object.h" -#include "oat.h" #include "runtime.h" namespace art { @@ -61,6 +60,31 @@ class DummyOatFile; } // namespace collector } // namespace gc +// OatMethodOffsets are currently 5x32-bits=160-bits long, so if we can +// save even one OatMethodOffsets struct, the more complicated encoding +// using a bitmap pays for itself since few classes will have 160 +// methods. +enum OatClassType { + kOatClassAllCompiled = 0, // OatClass is followed by an OatMethodOffsets for each method. + kOatClassSomeCompiled = 1, // A bitmap of OatMethodOffsets that are present follows the OatClass. + kOatClassNoneCompiled = 2, // All methods are interpreted so no OatMethodOffsets are necessary. + kOatClassMax = 3, +}; + +std::ostream& operator<<(std::ostream& os, const OatClassType& rhs); + +class PACKED(4) OatMethodOffsets { + public: + explicit OatMethodOffsets(uint32_t code_offset = 0) : code_offset_(code_offset) {} + + ~OatMethodOffsets() {} + + OatMethodOffsets(const OatMethodOffsets&) = default; + OatMethodOffsets& operator=(const OatMethodOffsets&) = default; + + uint32_t code_offset_; +}; + // Runtime representation of the OAT file format which holds compiler output. // The class opens an OAT file from storage and maps it to memory, typically with // dlopen and provides access to its internal data structures (see OatWriter for diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index 9a5409f46d..0412ab5909 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -34,6 +34,7 @@ #include "common_runtime_test.h" #include "dexopt_test.h" #include "hidden_api.h" +#include "oat.h" #include "oat_file.h" #include "oat_file_manager.h" #include "scoped_thread_state_change-inl.h" diff --git a/runtime/reflective_value_visitor.h b/runtime/reflective_value_visitor.h index 0b09a0bf8a..3a72760345 100644 --- a/runtime/reflective_value_visitor.h +++ b/runtime/reflective_value_visitor.h @@ -109,6 +109,10 @@ class ReflectionSourceInfo : public ValueObject { os << "Type=" << type_; } + ReflectionSourceType GetType() const { + return type_; + } + private: const ReflectionSourceType type_; diff --git a/runtime/runtime.cc b/runtime/runtime.cc index c6d9bfdf25..6d17204ef5 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -146,6 +146,7 @@ #include "native_bridge_art_interface.h" #include "native_stack_dump.h" #include "nativehelper/scoped_local_ref.h" +#include "oat.h" #include "oat_file.h" #include "oat_file_manager.h" #include "object_callbacks.h" @@ -288,6 +289,7 @@ Runtime::Runtime() safe_mode_(false), hidden_api_policy_(hiddenapi::EnforcementPolicy::kDisabled), core_platform_api_policy_(hiddenapi::EnforcementPolicy::kDisabled), + test_api_policy_(hiddenapi::EnforcementPolicy::kDisabled), dedupe_hidden_api_warnings_(true), hidden_api_access_event_log_rate_(0), dump_native_stack_on_sig_quit_(true), @@ -1860,6 +1862,16 @@ void Runtime::InitNativeMethods() { // a regular JNI libraries with a regular JNI_OnLoad. Most JNI libraries can // just use System.loadLibrary, but libcore can't because it's the library // that implements System.loadLibrary! + + // libicu_jni has to be initialized before libopenjdk{d} due to runtime dependency from + // libopenjdk{d} to Icu4cMetadata native methods in libicu_jni. See http://b/143888405 + { + std::string error_msg; + if (!java_vm_->LoadNativeLibrary( + env, "libicu_jni.so", nullptr, WellKnownClasses::java_lang_Object, &error_msg)) { + LOG(FATAL) << "LoadNativeLibrary failed for \"libicu_jni.so\": " << error_msg; + } + } { std::string error_msg; if (!java_vm_->LoadNativeLibrary( @@ -1877,13 +1889,6 @@ void Runtime::InitNativeMethods() { LOG(FATAL) << "LoadNativeLibrary failed for \"" << kOpenJdkLibrary << "\": " << error_msg; } } - { - std::string error_msg; - if (!java_vm_->LoadNativeLibrary( - env, "libicu_jni.so", nullptr, WellKnownClasses::java_lang_Object, &error_msg)) { - LOG(FATAL) << "LoadNativeLibrary failed for \"libicu_jni.so\": " << error_msg; - } - } // Initialize well known classes that may invoke runtime native methods. WellKnownClasses::LateInit(env); diff --git a/runtime/runtime.h b/runtime/runtime.h index ac84d32b82..cfa67a81de 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -92,7 +92,6 @@ class InternTable; class IsMarkedVisitor; class JavaVMExt; class LinearAlloc; -class MethodInspectionCallback; class MonitorList; class MonitorPool; class NullPointerHandler; @@ -602,6 +601,14 @@ class Runtime { return core_platform_api_policy_; } + void SetTestApiEnforcementPolicy(hiddenapi::EnforcementPolicy policy) { + test_api_policy_ = policy; + } + + hiddenapi::EnforcementPolicy GetTestApiEnforcementPolicy() const { + return test_api_policy_; + } + void SetHiddenApiExemptions(const std::vector<std::string>& exemptions) { hidden_api_exemptions_ = exemptions; } @@ -1219,6 +1226,9 @@ class Runtime { // Whether access checks on core platform API should be performed. hiddenapi::EnforcementPolicy core_platform_api_policy_; + // Whether access checks on test API should be performed. + hiddenapi::EnforcementPolicy test_api_policy_; + // List of signature prefixes of methods that have been removed from the blacklist, and treated // as if whitelisted. std::vector<std::string> hidden_api_exemptions_; diff --git a/runtime/thread.cc b/runtime/thread.cc index 59a38e161d..36c35f85ba 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -2439,13 +2439,19 @@ void Thread::Destroy() { { ScopedObjectAccess soa(self); Runtime::Current()->GetHeap()->RevokeThreadLocalBuffers(this); - if (kUseReadBarrier) { - Runtime::Current()->GetHeap()->ConcurrentCopyingCollector()->RevokeThreadLocalMarkStack(this); - } } } Thread::~Thread() { + if (kUseReadBarrier) { + // It's a cheap operation so can be done in the destructor (instead of + // Destroy()). + // Doing it without mutator_lock mutual exclusion is also necessary as there + // is a checkpoint in ConcurrentCopying which scans the threads' stacks, + // thereby assigning a thread-local mark-stack to self, breaking some + // assumptions about how the GC works (see b/140119552). + Runtime::Current()->GetHeap()->ConcurrentCopyingCollector()->RevokeThreadLocalMarkStack(this); + } CHECK(tlsPtr_.class_loader_override == nullptr); CHECK(tlsPtr_.jpeer == nullptr); CHECK(tlsPtr_.opeer == nullptr); diff --git a/test/1997-structural-shadow-method/expected.txt b/test/1997-structural-shadow-method/expected.txt new file mode 100644 index 0000000000..3a8b8de39b --- /dev/null +++ b/test/1997-structural-shadow-method/expected.txt @@ -0,0 +1,6 @@ +Hello! +Hello! +Hello! +Hello World! +Hello World! +Hello World! diff --git a/test/1997-structural-shadow-method/info.txt b/test/1997-structural-shadow-method/info.txt new file mode 100644 index 0000000000..71e3bfcd2e --- /dev/null +++ b/test/1997-structural-shadow-method/info.txt @@ -0,0 +1 @@ +Test structural redefinition when the method being added was resolvable previously. diff --git a/test/1997-structural-shadow-method/run b/test/1997-structural-shadow-method/run new file mode 100755 index 0000000000..03e41a58e7 --- /dev/null +++ b/test/1997-structural-shadow-method/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 2016 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. + +./default-run "$@" --jvmti --runtime-option -Xopaque-jni-ids:true diff --git a/test/1997-structural-shadow-method/src/Main.java b/test/1997-structural-shadow-method/src/Main.java new file mode 100644 index 0000000000..3c9bc85fb3 --- /dev/null +++ b/test/1997-structural-shadow-method/src/Main.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2017 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. + */ + +public class Main { + public static void main(String[] args) throws Exception { + art.Test1997.run(); + } +} diff --git a/test/1997-structural-shadow-method/src/art/Redefinition.java b/test/1997-structural-shadow-method/src/art/Redefinition.java new file mode 120000 index 0000000000..81eaf31bbb --- /dev/null +++ b/test/1997-structural-shadow-method/src/art/Redefinition.java @@ -0,0 +1 @@ +../../../jvmti-common/Redefinition.java
\ No newline at end of file diff --git a/test/1997-structural-shadow-method/src/art/Test1997.java b/test/1997-structural-shadow-method/src/art/Test1997.java new file mode 100644 index 0000000000..7309a31bd3 --- /dev/null +++ b/test/1997-structural-shadow-method/src/art/Test1997.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2016 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. + */ + +package art; + +import java.util.Base64; + +public class Test1997 { + + public static class SuperTransform { + // We will be shadowing this function. + public static void sayHi() { + System.out.println("Hello!"); + } + } + + // The class we will be transforming. + public static class Transform extends SuperTransform { + public static void sayHiTwice() { + Transform.sayHi(); + Transform.sayHi(); + } + } + + // public static class Transform extends SuperTransform { + // public static void sayHiTwice() { + // Transform.sayHi(); + // Transform.sayHi(); + // } + // public static void sayHi() { + // System.out.println("Hello World!"); + // } + // } + private static final byte[] DEX_BYTES = + Base64.getDecoder() + .decode( + "ZGV4CjAzNQA9wdy7Lgbrv+sD+wixborREr0maZCK5yqABAAAcAAAAHhWNBIAAAAAAAAAALwDAAAW" + + "AAAAcAAAAAkAAADIAAAAAgAAAOwAAAABAAAABAEAAAUAAAAMAQAAAQAAADQBAAAsAwAAVAEAAMIB" + + "AADKAQAA2AEAAPcBAAARAgAAIQIAAEUCAABlAgAAfAIAAJACAACkAgAAswIAAL4CAADBAgAAxQIA" + + "ANICAADYAgAA3QIAAOYCAADtAgAA+QIAAAADAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" + + "CQAAAAwAAAAMAAAACAAAAAAAAAANAAAACAAAALwBAAAHAAUAEAAAAAAAAAAAAAAAAQAAAAAAAAAB" + + "AAAAEgAAAAEAAAATAAAABQABABEAAAABAAAAAQAAAAAAAAAAAAAACgAAAKwDAACHAwAAAAAAAAEA" + + "AQABAAAAqgEAAAQAAABwEAAAAAAOAAIAAAACAAAArgEAAAgAAABiAAAAGgEBAG4gBAAQAA4AAAAA" + + "AAAAAACzAQAABwAAAHEAAgAAAHEAAgAAAA4ADwAOABUADngAEQAOPDwAAAAAAQAAAAYABjxpbml0" + + "PgAMSGVsbG8gV29ybGQhAB1MYXJ0L1Rlc3QxOTk3JFN1cGVyVHJhbnNmb3JtOwAYTGFydC9UZXN0" + + "MTk5NyRUcmFuc2Zvcm07AA5MYXJ0L1Rlc3QxOTk3OwAiTGRhbHZpay9hbm5vdGF0aW9uL0VuY2xv" + + "c2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVyQ2xhc3M7ABVMamF2YS9pby9Qcmlu" + + "dFN0cmVhbTsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AA1UZXN0MTk5" + + "Ny5qYXZhAAlUcmFuc2Zvcm0AAVYAAlZMAAthY2Nlc3NGbGFncwAEbmFtZQADb3V0AAdwcmludGxu" + + "AAVzYXlIaQAKc2F5SGlUd2ljZQAFdmFsdWUAdn5+RDh7ImNvbXBpbGF0aW9uLW1vZGUiOiJkZWJ1" + + "ZyIsIm1pbi1hcGkiOjEsInNoYS0xIjoiNjBkYTRkNjdiMzgxYzQyNDY3NzU3YzQ5ZmI2ZTU1NzU2" + + "ZDg4YTJmMyIsInZlcnNpb24iOiIxLjcuMTItZGV2In0AAgMBFBgCAgQCDgQJDxcLAAADAAGBgATU" + + "AgEJ7AIBCYwDAAAAAAAAAAIAAAB4AwAAfgMAAKADAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAEAAAAA" + + "AAAAAQAAABYAAABwAAAAAgAAAAkAAADIAAAAAwAAAAIAAADsAAAABAAAAAEAAAAEAQAABQAAAAUA" + + "AAAMAQAABgAAAAEAAAA0AQAAASAAAAMAAABUAQAAAyAAAAMAAACqAQAAARAAAAEAAAC8AQAAAiAA" + + "ABYAAADCAQAABCAAAAIAAAB4AwAAACAAAAEAAACHAwAAAxAAAAIAAACcAwAABiAAAAEAAACsAwAA" + + "ABAAAAEAAAC8AwAA"); + + public static void run() throws Exception { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(); + } + + public static void doTest() throws Exception { + Transform.sayHiTwice(); + Transform.sayHi(); + Redefinition.doCommonStructuralClassRedefinition(Transform.class, DEX_BYTES); + Transform.sayHiTwice(); + Transform.sayHi(); + } +} diff --git a/test/1998-structural-shadow-field/expected.txt b/test/1998-structural-shadow-field/expected.txt new file mode 100644 index 0000000000..9ae530e728 --- /dev/null +++ b/test/1998-structural-shadow-field/expected.txt @@ -0,0 +1,4 @@ +Hello +Hello +null +Hello diff --git a/test/1998-structural-shadow-field/info.txt b/test/1998-structural-shadow-field/info.txt new file mode 100644 index 0000000000..71e3bfcd2e --- /dev/null +++ b/test/1998-structural-shadow-field/info.txt @@ -0,0 +1 @@ +Test structural redefinition when the method being added was resolvable previously. diff --git a/test/1998-structural-shadow-field/run b/test/1998-structural-shadow-field/run new file mode 100755 index 0000000000..03e41a58e7 --- /dev/null +++ b/test/1998-structural-shadow-field/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 2016 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. + +./default-run "$@" --jvmti --runtime-option -Xopaque-jni-ids:true diff --git a/test/1998-structural-shadow-field/src/Main.java b/test/1998-structural-shadow-field/src/Main.java new file mode 100644 index 0000000000..f6aeca5b85 --- /dev/null +++ b/test/1998-structural-shadow-field/src/Main.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2017 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. + */ + +public class Main { + public static void main(String[] args) throws Exception { + art.Test1998.run(); + } +} diff --git a/test/1998-structural-shadow-field/src/art/Redefinition.java b/test/1998-structural-shadow-field/src/art/Redefinition.java new file mode 120000 index 0000000000..81eaf31bbb --- /dev/null +++ b/test/1998-structural-shadow-field/src/art/Redefinition.java @@ -0,0 +1 @@ +../../../jvmti-common/Redefinition.java
\ No newline at end of file diff --git a/test/1998-structural-shadow-field/src/art/Test1998.java b/test/1998-structural-shadow-field/src/art/Test1998.java new file mode 100644 index 0000000000..3fda936f84 --- /dev/null +++ b/test/1998-structural-shadow-field/src/art/Test1998.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2016 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. + */ + +package art; + +import java.util.Base64; + +public class Test1998 { + + public static class SuperTransform { + public static String greeting = "Hello"; + } + + // The class we will be transforming. + public static class Transform extends SuperTransform { } + + // public static class Transform extends SuperTransform { + // public static String greeting; + // } + private static final byte[] DEX_BYTES = + Base64.getDecoder() + .decode( +"ZGV4CjAzNQCYmnoWz4BqygrZQM4zf/mJ/25+dM86MHKAAwAAcAAAAHhWNBIAAAAAAAAAAMgCAAAP" + +"AAAAcAAAAAcAAACsAAAAAQAAAMgAAAABAAAA1AAAAAIAAADcAAAAAQAAAOwAAAB0AgAADAEAACgB" + +"AAAwAQAATwEAAGkBAAB5AQAAnQEAAL0BAADRAQAA4AEAAOsBAADuAQAA+wEAAAUCAAALAgAAEgIA" + +"AAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAkAAAAJAAAABgAAAAAAAAABAAUACwAAAAAAAAAAAAAA" + +"AQAAAAAAAAABAAAAAQAAAAAAAAAAAAAABwAAALgCAACZAgAAAAAAAAEAAQABAAAAJAEAAAQAAABw" + +"EAAAAAAOAAUADgAGPGluaXQ+AB1MYXJ0L1Rlc3QxOTk4JFN1cGVyVHJhbnNmb3JtOwAYTGFydC9U" + +"ZXN0MTk5OCRUcmFuc2Zvcm07AA5MYXJ0L1Rlc3QxOTk4OwAiTGRhbHZpay9hbm5vdGF0aW9uL0Vu" + +"Y2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVyQ2xhc3M7ABJMamF2YS9sYW5n" + +"L1N0cmluZzsADVRlc3QxOTk4LmphdmEACVRyYW5zZm9ybQABVgALYWNjZXNzRmxhZ3MACGdyZWV0" + +"aW5nAARuYW1lAAV2YWx1ZQB2fn5EOHsiY29tcGlsYXRpb24tbW9kZSI6ImRlYnVnIiwibWluLWFw" + +"aSI6MSwic2hhLTEiOiI2MGRhNGQ2N2IzODFjNDI0Njc3NTdjNDlmYjZlNTU3NTZkODhhMmYzIiwi" + +"dmVyc2lvbiI6IjEuNy4xMi1kZXYifQACAwENGAICBAIKBAkMFwgBAAEAAAkBgYAEjAIAAAAAAAAA" + +"AgAAAIoCAACQAgAArAIAAAAAAAAAAAAAAAAAAA8AAAAAAAAAAQAAAAAAAAABAAAADwAAAHAAAAAC" + +"AAAABwAAAKwAAAADAAAAAQAAAMgAAAAEAAAAAQAAANQAAAAFAAAAAgAAANwAAAAGAAAAAQAAAOwA" + +"AAABIAAAAQAAAAwBAAADIAAAAQAAACQBAAACIAAADwAAACgBAAAEIAAAAgAAAIoCAAAAIAAAAQAA" + +"AJkCAAADEAAAAgAAAKgCAAAGIAAAAQAAALgCAAAAEAAAAQAAAMgCAAA="); + + public static void run() throws Exception { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(); + } + + public static void doTest() throws Exception { + System.out.println(Transform.greeting); + System.out.println(SuperTransform.greeting); + Redefinition.doCommonStructuralClassRedefinition(Transform.class, DEX_BYTES); + System.out.println(Transform.greeting); + System.out.println(SuperTransform.greeting); + } +} diff --git a/test/580-fp16/src-art/Main.java b/test/580-fp16/src-art/Main.java index a89e1000d0..4aa8d55faa 100644 --- a/test/580-fp16/src-art/Main.java +++ b/test/580-fp16/src-art/Main.java @@ -39,8 +39,8 @@ public class Main { } } - public static void main(String args[]) { - // Test FP16 to float + public static void testHalfToFloatToHalfConversions(){ + // Test FP16 to float and back to Half for all possible Short values for (short h = Short.MIN_VALUE; h < Short.MAX_VALUE; h++) { if (FP16.isNaN(h)) { // NaN inputs are tested below. @@ -48,7 +48,9 @@ public class Main { } assertEquals(h, FP16.toHalf(FP16.toFloat(h))); } + } + public static void testToHalf(){ // These asserts check some known values and edge cases for FP16.toHalf // and have been inspired by the cts HalfTest. // Zeroes, NaN and infinities @@ -88,6 +90,9 @@ public class Main { assertEquals(0x7400, FP16.toHalf(16392.0f)); assertEquals(0x7800, FP16.toHalf(32784.0f)); + } + + public static void testToFloat(){ // FP16 SNaN/QNaN inputs to float // The most significant bit of mantissa: // V @@ -106,4 +111,10 @@ public class Main { assertEquals(0xffc00000, TestFP16ToFloatRawIntBits((short)(0xfe00))); // QNaN->QNaN assertEquals(0xffffe000, TestFP16ToFloatRawIntBits((short)(0xffff))); // QNaN->QNaN } + + public static void main(String args[]) { + testHalfToFloatToHalfConversions(); + testToHalf(); + testToFloat(); + } } diff --git a/test/956-methodhandles/src/Main.java b/test/956-methodhandles/src/Main.java index a54b481907..e70c83b060 100644 --- a/test/956-methodhandles/src/Main.java +++ b/test/956-methodhandles/src/Main.java @@ -95,6 +95,11 @@ public class Main { } } + public static class I { + public static void someVoidMethod() { + } + } + public static void main(String[] args) throws Throwable { testfindSpecial_invokeSuperBehaviour(); testfindSpecial_invokeDirectBehaviour(); @@ -635,6 +640,30 @@ public class Main { fail(); } catch (WrongMethodTypeException expected) { } + + // Zero / null introduction + MethodHandle voidMH = MethodHandles.lookup().findStatic(I.class, "someVoidMethod", + MethodType.methodType(void.class)); + { + MethodHandle booleanMH = voidMH.asType(MethodType.methodType(boolean.class)); + assertEquals(boolean.class, booleanMH.type().returnType()); + assertEquals(false, booleanMH.invoke()); + } + { + MethodHandle intMH = voidMH.asType(MethodType.methodType(int.class)); + assertEquals(int.class, intMH.type().returnType()); + assertEquals(0, intMH.invoke()); + } + { + MethodHandle longMH = voidMH.asType(MethodType.methodType(long.class)); + assertEquals(long.class, longMH.type().returnType()); + assertEquals(0L, longMH.invoke()); + } + { + MethodHandle objMH = voidMH.asType(MethodType.methodType(Object.class)); + assertEquals(Object.class, objMH.type().returnType()); + assertEquals(null, objMH.invoke()); + } } public static void assertTrue(boolean value) { diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc index 5fa7e19eda..4ca5fe8333 100644 --- a/test/common/runtime_state.cc +++ b/test/common/runtime_state.cc @@ -32,6 +32,7 @@ #include "mirror/class-inl.h" #include "mirror/class.h" #include "nativehelper/ScopedUtfChars.h" +#include "oat.h" #include "oat_file.h" #include "oat_quick_method_header.h" #include "profile/profile_compilation_info.h" diff --git a/test/knownfailures.json b/test/knownfailures.json index 049ff0dcbb..cd66472aa8 100644 --- a/test/knownfailures.json +++ b/test/knownfailures.json @@ -1145,7 +1145,9 @@ "1990-structural-bad-verify", "1991-hello-structural-retransform", "1992-retransform-no-such-field", - "1993-fallback-non-structural" + "1993-fallback-non-structural", + "1997-structural-shadow-method", + "1998-structural-shadow-field" ], "variant": "jvm", "description": ["Doesn't run on RI."] @@ -1267,5 +1269,11 @@ "env_vars": {"ART_READ_BARRIER_TYPE": "TABLELOOKUP"}, "bug": "b/140507091", "description": ["Test containing Checker assertions expecting Baker read barriers."] + }, + { + "tests": ["689-zygote-jit-deopt"], + "variant": "gcstress", + "bug": "b/137887811", + "description": ["Occasional timeouts."] } ] diff --git a/tools/jvmti-agents/ti-alloc-sample/mkflame.py b/tools/jvmti-agents/ti-alloc-sample/mkflame.py index 8f1dccfd99..f37aa4aafb 100755 --- a/tools/jvmti-agents/ti-alloc-sample/mkflame.py +++ b/tools/jvmti-agents/ti-alloc-sample/mkflame.py @@ -18,73 +18,196 @@ Usage: mkflame.py <jvmti_trace_file> """ +import argparse import sys -table = {} - -def add_definition_to_table(line): - """ - Adds line to the list of definitions in table. - """ - comma_pos = line.find(",") - index = int(line[1:comma_pos]) - definition = line[comma_pos+1:] - if line[0:1] == "=": - # Skip the type/size prefix for flame graphs. - semi_pos = definition.find(";") - definition = definition[semi_pos + 1:] - # Expand stack frame definitions to be a semicolon-separated list of stack - # frame methods. - expanded_definition = "" - while definition != "": - semi_pos = definition.find(";") - if semi_pos == -1: - method_index = int(definition) - definition = "" +class TraceCollection: + def __init__(self, args): + self.args = args + # A table indexed by number and containing the definition for that number. + self.definitions = {} + # The "weight" of a stack trace, either 1 for counting or the size of the allocation. + self.weights = {} + # The count for each individual allocation. + self.allocation_count = {} + + def definition(self, index): + """ + Returns the definition for "index". + """ + return self.definitions[index] + + def set_definition(self, index, definition): + """ + Sets the definition for "index". + """ + self.definitions[index] = definition + + def weight(self, index): + """ + Returns the weight for "index". + """ + return self.weights[index] + + def set_weight(self, index, weight): + """ + Sets the weight for "index". + """ + self.weights[index] = weight + + def read_file(self, filename): + """ + Reads a file into a DefinitionTable. + """ + def process_definition(line): + """ + Adds line to the list of definitions in table. + """ + def expand_stack_trace(definition): + """ + Converts a semicolon-separated list of numbers into the text stack trace. + """ + def get_allocation_thread(thread_type_size): + """ + Returns the thread of an allocation from the thread/type/size record. + """ + THREAD_STRING = "thread[" + THREAD_STRING_LEN = len(THREAD_STRING) + thread_string = thread_type_size[thread_type_size.find(THREAD_STRING) + + THREAD_STRING_LEN:] + return thread_string[:thread_string.find("]")] + + def get_allocation_type(thread_type_size): + """ + Returns the type of an allocation from the thread/type/size record. + """ + TYPE_STRING = "jclass[" + TYPE_STRING_LEN = len(TYPE_STRING) + type_string = thread_type_size[thread_type_size.find(TYPE_STRING) + TYPE_STRING_LEN:] + return type_string[:type_string.find(" ")] + + def get_allocation_size(thread_type_size): + """ + Returns the size of an allocation from the thread/type/size record. + """ + SIZE_STRING = "size[" + SIZE_STRING_LEN = len(SIZE_STRING) + size_string = thread_type_size[thread_type_size.find(SIZE_STRING) + SIZE_STRING_LEN:] + size_string = size_string[:size_string.find(",")] + return int(size_string) + + def get_top_and_weight(index): + thread_type_size = self.definition(int(tokens[0])) + size = get_allocation_size(thread_type_size) + if self.args.type_only: + thread_type_size = get_allocation_type(thread_type_size) + elif self.args.thread_only: + thread_type_size = get_allocation_thread(thread_type_size) + return (thread_type_size, size) + + tokens = definition.split(";") + # The first element (base) of the stack trace is the thread/type/size. + # Get the weight (either 1 or the number of bytes allocated). + (thread_type_size, weight) = get_top_and_weight(int(tokens[0])) + self.set_weight(index, weight) + # Remove the thread/type/size from the base of the stack trace. + del tokens[0] + # Build the stack trace list. + expanded_definition = "" + for i in range(len(tokens)): + if self.args.depth_limit > 0 and i >= self.args.depth_limit: + break + token = tokens[i] + # Replace semicolons by colons in the method entry signatures. + method = self.definition(int(token)).replace(";", ":") + if len(expanded_definition) > 0: + expanded_definition += ";" + expanded_definition += method + if not self.args.ignore_type: + # Add the thread/type/size as the top-most stack frame. + if len(expanded_definition) > 0: + expanded_definition += ";" + expanded_definition += thread_type_size.replace(";", ":") + if self.args.reverse_stack: + def_list = expanded_definition.split(";") + expanded_definition = ";".join(def_list[::-1]) + return expanded_definition + + # If the line contains a comma, it is of the form [+=]index,definition, + # where index is a string containing an integer, and definition is the + # value represented by the integer whenever it is used later. + # * Lines starting with + are either a thread/type/size record or a single + # stack frame. These are simply interned in the table. + # * Those starting with = are stack traces, and contain a sequence of + # numbers separated by semicolon. These are "expanded" and then interned. + comma_pos = line.find(",") + index = int(line[1:comma_pos]) + definition = line[comma_pos+1:] + if line[0:1] == "=": + definition = expand_stack_trace(definition) + # Intern the definition in the table. + #if len(definition) == 0: + # Zero length samples are errors and are discarded. + #print("ERROR: definition for " + str(index) + " is empty") + #return + self.set_definition(index, definition) + + def process_trace(index): + """ + Remembers one stack trace in the list of stack traces we have seen. + Remembering a stack trace increments a count associated with the trace. + """ + trace = self.definition(index) + if self.args.use_size: + weight = self.weight(index) + else: + weight = 1 + if trace in self.allocation_count: + self.allocation_count[trace] = self.allocation_count[trace] + weight else: - method_index = int(definition[:semi_pos]) - definition = definition[semi_pos + 1:] - # Replace semicolons by colons in the method entry signatures. - method = lookup_definition(method_index).replace(";", ":") - expanded_definition += ";" + method - definition = expanded_definition - table[index] = definition - -def lookup_definition(index): - """ - Returns the definition for "index" from table. - """ - return table[index] - -traces = {} -def record_stack_trace(string): - """ - Remembers one stack trace index in the list of stack traces we have seen. - Remembering a stack trace increments a count associated with the trace. - """ - index = int(string) - if index in traces: - count = traces[index] - traces[index] = count + 1 - else: - traces[index] = 1 + self.allocation_count[trace] = weight + + # Read the file, processing each line as a definition or stack trace. + tracefile = open(filename, "r") + current_allocation_trace = "" + for line in tracefile: + line = line.rstrip("\n") + if line[0:1] == "=" or line[0:1] == "+": + # definition. + process_definition(line) + else: + # stack trace. + process_trace(int(line)) + + def dump_flame_graph(self): + """ + Prints out a stack trace format compatible with flame graph creation utilities. + """ + for definition, weight in self.allocation_count.items(): + print(definition + " " + str(weight)) + +def parse_options(): + parser = argparse.ArgumentParser(description="Convert a trace to a form usable for flame graphs.") + parser.add_argument("filename", help="The trace file as input", type=str) + parser.add_argument("--use_size", help="Count by allocation size", action="store_true", + default=False) + parser.add_argument("--ignore_type", help="Ignore type of allocation", action="store_true", + default=False) + parser.add_argument("--reverse_stack", help="Reverse root and top of stacks", action="store_true", + default=False) + parser.add_argument("--type_only", help="Only consider allocation type", action="store_true", + default=False) + parser.add_argument("--thread_only", help="Only consider allocation thread", action="store_true", + default=False) + parser.add_argument("--depth_limit", help="Limit the length of a trace", type=int, default=0) + args = parser.parse_args() + return args def main(argv): - filename = argv[1] - pagefile = open(filename, "r") - current_allocation_trace = "" - for line in pagefile: - args = line.split() - line = line.rstrip("\n") - if line[0:1] == "=" or line[0:1] == "+": - # definition. - add_definition_to_table(line) - else: - # stack trace. - record_stack_trace(line) - # Dump all the traces, with count. - for k, v in traces.items(): - print(lookup_definition(k) + " " + str(v)) + args = parse_options() + trace_collection = TraceCollection(args) + trace_collection.read_file(args.filename) + trace_collection.dump_flame_graph() if __name__ == '__main__': sys.exit(main(sys.argv)) diff --git a/tools/jvmti-agents/ti-alloc-sample/ti_alloc_sample.cc b/tools/jvmti-agents/ti-alloc-sample/ti_alloc_sample.cc index 862aa51b86..d719db5af8 100644 --- a/tools/jvmti-agents/ti-alloc-sample/ti_alloc_sample.cc +++ b/tools/jvmti-agents/ti-alloc-sample/ti_alloc_sample.cc @@ -293,31 +293,15 @@ static std::string formatAllocation(jvmtiEnv* jvmti, // Formatter for a method entry on a call stack. static std::string formatMethod(jvmtiEnv* jvmti, JNIEnv* jni, jmethodID method_id) { - jclass declaring_class; - jvmtiError err = jvmti->GetMethodDeclaringClass(method_id, &declaring_class); - std::string class_name = ""; - if (err == JVMTI_ERROR_NONE) { - char* class_signature; - err = jvmti->GetClassSignature(declaring_class, - &class_signature, - /*generic_ptr*/ nullptr); - class_name = std::string(class_signature); - jvmti->Deallocate(reinterpret_cast<unsigned char*>(class_signature)); - jni->DeleteLocalRef(declaring_class); - } - char *method_name; - char *method_signature; - char *generic_pointer; - err = jvmti->GetMethodName(method_id, - &method_name, - &method_signature, - &generic_pointer); - std::string method = "METHODERROR"; - if (err == JVMTI_ERROR_NONE) { - method = ((method_name == nullptr) ? "UNKNOWN" : method_name); - method += ((method_signature == nullptr) ? "(UNKNOWN)" : method_signature); + ScopedMethodInfo smi(jvmti, jni, method_id); + std::string method; + if (smi.Init(/*get_generic=*/false)) { + method = std::string(smi.GetDeclaringClassInfo().GetName()) + + "::" + smi.GetName() + smi.GetSignature(); + } else { + method = "ERROR"; } - return string_table->Intern("+", class_name + "::" + method); + return string_table->Intern("+", method); } static int sampling_rate; diff --git a/tools/libcore_no_getrandom_failures.txt b/tools/libcore_no_getrandom_failures.txt index f2926e452c..05af9d7e19 100644 --- a/tools/libcore_no_getrandom_failures.txt +++ b/tools/libcore_no_getrandom_failures.txt @@ -15,6 +15,21 @@ "libcore.java.math.BigIntegerTest#test_probablePrime", "libcore.javax.crypto.CipherInputStreamTest#testDecryptCorruptGCM", "libcore.javax.crypto.CipherOutputStreamTest#testDecryptCorruptGCM", + "libcore.libcore.timezone.TelephonyLookupTest#createInstanceWithFallback", + "libcore.libcore.timezone.TelephonyLookupTest#getTelephonyNetworkFinder", + "libcore.libcore.timezone.TelephonyLookupTest#validateCountryCodeLowerCase", + "libcore.libcore.timezone.TelephonyLookupTest#validateDuplicateMccMnc", + "libcore.libcore.timezone.TelephonyLookupTest#xmlParsing_emptyFile", + "libcore.libcore.timezone.TelephonyLookupTest#xmlParsing_emptyNetworksOk", + "libcore.libcore.timezone.TelephonyLookupTest#xmlParsing_missingCountryCodeAttribute", + "libcore.libcore.timezone.TelephonyLookupTest#xmlParsing_missingMccAttribute", + "libcore.libcore.timezone.TelephonyLookupTest#xmlParsing_missingMncAttribute", + "libcore.libcore.timezone.TelephonyLookupTest#xmlParsing_missingNetworks", + "libcore.libcore.timezone.TelephonyLookupTest#xmlParsing_truncatedInput", + "libcore.libcore.timezone.TelephonyLookupTest#xmlParsing_unexpectedComments", + "libcore.libcore.timezone.TelephonyLookupTest#xmlParsing_unexpectedElementsIgnored", + "libcore.libcore.timezone.TelephonyLookupTest#xmlParsing_unexpectedRootElement", + "libcore.libcore.timezone.TelephonyLookupTest#xmlParsing_unexpectedTextIgnored", "libcore.libcore.timezone.TimeZoneFinderTest#createInstanceWithFallback", "libcore.libcore.timezone.TimeZoneFinderTest#getCountryZonesFinder", "libcore.libcore.timezone.TimeZoneFinderTest#getCountryZonesFinder_empty", |