summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2019-11-11 21:23:59 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2019-11-11 21:23:59 +0000
commitff30d9fd59b70a6dbf8590ebdc6ddbccd81b561e (patch)
treea26da1d669e88b34b10b0f6c76b06abd8b694473
parented8bdf09d25c898b0962eaa1a645186d7954e381 (diff)
parenta19d32b0216a289c888612cdd078679b850d7218 (diff)
downloadart-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
-rw-r--r--CleanSpec.mk2
-rw-r--r--adbconnection/Android.bp21
-rw-r--r--adbconnection/adbconnection_server.cc6
-rw-r--r--adbconnection/libadbconnection_server.map.txt22
-rw-r--r--build/Android.bp3
-rw-r--r--build/apex/Android.bp47
-rwxr-xr-xbuild/apex/art_apex_test.py74
-rw-r--r--build/apex/art_postinstall_hook.sh48
-rw-r--r--build/apex/art_preinstall_hook.sh49
-rw-r--r--build/apex/art_preinstall_hook_boot.sh73
-rw-r--r--build/apex/art_preinstall_hook_system_server.sh84
-rw-r--r--build/apex/art_prepostinstall_utils.sh70
-rw-r--r--build/apex/manifest-art.json4
-rw-r--r--build/art.go14
-rw-r--r--dex2oat/dex2oat.cc5
-rw-r--r--dex2oat/dex2oat_image_test.cc2
-rw-r--r--dex2oat/dex2oat_test.cc91
-rw-r--r--dex2oat/linker/image_test.cc2
-rw-r--r--dex2oat/linker/image_test.h1
-rw-r--r--dex2oat/linker/image_writer.cc18
-rw-r--r--dex2oat/linker/oat_writer.cc1
-rw-r--r--dex2oat/linker/oat_writer.h2
-rw-r--r--dex2oat/linker/oat_writer_test.cc1
-rw-r--r--dex2oat/linker/relative_patcher_test.h1
-rw-r--r--libartbase/Android.bp1
-rw-r--r--libartbase/base/hiddenapi_flags.h10
-rw-r--r--libartpalette/Android.bp4
-rw-r--r--libdexfile/Android.bp6
-rw-r--r--libelffile/elf/elf_builder.h14
-rw-r--r--openjdkjvmti/ti_redefine.cc83
-rw-r--r--runtime/Android.bp2
-rw-r--r--runtime/art_field.h4
-rw-r--r--runtime/art_method-inl.h1
-rw-r--r--runtime/dexopt_test.cc1
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc1
-rw-r--r--runtime/gc/collector/concurrent_copying.cc8
-rw-r--r--runtime/gc/collector/immune_spaces_test.cc2
-rw-r--r--runtime/gc/heap.cc43
-rw-r--r--runtime/gc/heap.h17
-rw-r--r--runtime/gc/space/image_space.cc186
-rw-r--r--runtime/hidden_api.cc21
-rw-r--r--runtime/hidden_api_test.cc38
-rw-r--r--runtime/image.cc6
-rw-r--r--runtime/image.h17
-rw-r--r--runtime/method_handles.cc10
-rw-r--r--runtime/mirror/dex_cache.cc18
-rw-r--r--runtime/native/dalvik_system_ZygoteHooks.cc44
-rw-r--r--runtime/oat.cc5
-rw-r--r--runtime/oat.h29
-rw-r--r--runtime/oat_file.h26
-rw-r--r--runtime/oat_file_assistant_test.cc1
-rw-r--r--runtime/reflective_value_visitor.h4
-rw-r--r--runtime/runtime.cc19
-rw-r--r--runtime/runtime.h12
-rw-r--r--runtime/thread.cc12
-rw-r--r--test/1997-structural-shadow-method/expected.txt6
-rw-r--r--test/1997-structural-shadow-method/info.txt1
-rwxr-xr-xtest/1997-structural-shadow-method/run17
-rw-r--r--test/1997-structural-shadow-method/src/Main.java21
l---------test/1997-structural-shadow-method/src/art/Redefinition.java1
-rw-r--r--test/1997-structural-shadow-method/src/art/Test1997.java84
-rw-r--r--test/1998-structural-shadow-field/expected.txt4
-rw-r--r--test/1998-structural-shadow-field/info.txt1
-rwxr-xr-xtest/1998-structural-shadow-field/run17
-rw-r--r--test/1998-structural-shadow-field/src/Main.java21
l---------test/1998-structural-shadow-field/src/art/Redefinition.java1
-rw-r--r--test/1998-structural-shadow-field/src/art/Test1998.java65
-rw-r--r--test/580-fp16/src-art/Main.java15
-rw-r--r--test/956-methodhandles/src/Main.java29
-rw-r--r--test/common/runtime_state.cc1
-rw-r--r--test/knownfailures.json10
-rwxr-xr-xtools/jvmti-agents/ti-alloc-sample/mkflame.py247
-rw-r--r--tools/jvmti-agents/ti-alloc-sample/ti_alloc_sample.cc32
-rw-r--r--tools/libcore_no_getrandom_failures.txt15
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",