diff options
-rw-r--r-- | Android.mk | 24 | ||||
-rw-r--r-- | build/Android.common_test.mk | 2 | ||||
-rw-r--r-- | build/art.go | 4 | ||||
-rw-r--r-- | openjdkjvmti/ti_thread.cc | 33 | ||||
-rw-r--r-- | runtime/runtime.cc | 15 | ||||
-rw-r--r-- | runtime/thread.cc | 8 | ||||
-rw-r--r-- | runtime/thread.h | 2 | ||||
-rw-r--r-- | runtime/well_known_classes.cc | 4 | ||||
-rw-r--r-- | runtime/well_known_classes.h | 2 | ||||
-rw-r--r-- | test/Android.bp | 2 | ||||
-rwxr-xr-x | test/etc/run-test-jar | 42 | ||||
-rwxr-xr-x | test/run-test | 19 | ||||
-rwxr-xr-x | tools/buildbot-build.sh | 2 |
13 files changed, 138 insertions, 21 deletions
diff --git a/Android.mk b/Android.mk index a98bedc245..e4cc5c04ff 100644 --- a/Android.mk +++ b/Android.mk @@ -487,14 +487,28 @@ PRIVATE_BIONIC_FILES := \ lib/bootstrap/libdl.so \ lib64/bootstrap/libc.so \ lib64/bootstrap/libm.so \ - lib64/bootstrap/libdl.so - -.PHONY: art-bionic-files -art-bionic-files: libc.bootstrap libdl.bootstrap libm.bootstrap linker + lib64/bootstrap/libdl.so \ + +PRIVATE_RUNTIME_DEPENDENCY_LIBS := \ + lib/libnativebridge.so \ + lib64/libnativebridge.so \ + lib/libnativehelper.so \ + lib64/libnativehelper.so \ + lib/libdexfile_external.so \ + lib64/libdexfile_external.so \ + lib/libnativeloader.so \ + lib64/libnativeloader.so \ + +.PHONY: standalone-apex-files +standalone-apex-files: libc.bootstrap libdl.bootstrap libm.bootstrap linker com.android.runtime.debug for f in $(PRIVATE_BIONIC_FILES); do \ tf=$(TARGET_OUT)/$$f; \ if [ -f $$tf ]; then cp -f $$tf $$(echo $$tf | sed 's,bootstrap/,,'); fi; \ done + for f in $(PRIVATE_RUNTIME_DEPENDENCY_LIBS); do \ + tf=$(TARGET_OUT)/../apex/com.android.runtime.debug/$$f; \ + if [ -f $$tf ]; then cp -f $$tf $(TARGET_OUT)/$$f; fi; \ + done ######################################################################## # Phony target for only building what go/lem requires for pushing ART on /data. @@ -529,7 +543,7 @@ build-art-target-golem: dex2oat dalvikvm linker libstdc++ \ $(TARGET_CORE_IMG_OUT_BASE)-interpreter.art \ libc.bootstrap libdl.bootstrap libm.bootstrap \ icu-data-art-test \ - art-bionic-files + standalone-apex-files # remove debug libraries from public.libraries.txt because golem builds # won't have it. sed -i '/libartd.so/d' $(TARGET_OUT)/etc/public.libraries.txt diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk index 12eae899c2..55b8ae237d 100644 --- a/build/Android.common_test.mk +++ b/build/Android.common_test.mk @@ -127,7 +127,6 @@ define build-art-test-dex LOCAL_MODULE_TAGS := tests LOCAL_JAVA_LIBRARIES := $(TARGET_TEST_CORE_JARS) LOCAL_MODULE_PATH := $(3) - LOCAL_DEX_PREOPT_IMAGE_LOCATION := $(TARGET_CORE_IMG_OUT) ifneq ($(wildcard $(LOCAL_PATH)/$(2)/main.list),) LOCAL_MIN_SDK_VERSION := 19 LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(LOCAL_PATH)/$(2)/main.list --minimal-main-dex @@ -143,7 +142,6 @@ define build-art-test-dex LOCAL_DEX_PREOPT := false LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_test.mk $(4) LOCAL_JAVA_LIBRARIES := $(HOST_TEST_CORE_JARS) - LOCAL_DEX_PREOPT_IMAGE := $(HOST_CORE_IMG_LOCATION) ifneq ($(wildcard $(LOCAL_PATH)/$(2)/main.list),) LOCAL_MIN_SDK_VERSION := 19 LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(LOCAL_PATH)/$(2)/main.list --minimal-main-dex diff --git a/build/art.go b/build/art.go index 4b638298c4..4db8da28e0 100644 --- a/build/art.go +++ b/build/art.go @@ -253,8 +253,10 @@ func prefer32Bit(ctx android.LoadHookContext) { ctx.AppendProperties(p) } +var testMapKey = android.NewOnceKey("artTests") + func testMap(config android.Config) map[string][]string { - return config.Once("artTests", func() interface{} { + return config.Once(testMapKey, func() interface{} { return make(map[string][]string) }).(map[string][]string) } diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc index 051db4c67e..1021648a2c 100644 --- a/openjdkjvmti/ti_thread.cc +++ b/openjdkjvmti/ti_thread.cc @@ -47,6 +47,7 @@ #include "mirror/class.h" #include "mirror/object-inl.h" #include "mirror/string.h" +#include "mirror/throwable.h" #include "nativehelper/scoped_local_ref.h" #include "nativehelper/scoped_utf_chars.h" #include "obj_ptr.h" @@ -83,6 +84,17 @@ struct ThreadCallback : public art::ThreadLifecycleCallback { } void ThreadStart(art::Thread* self) override REQUIRES_SHARED(art::Locks::mutator_lock_) { + // Needs to be checked first because we might start these threads before we actually send the + // VMInit event. + if (self->IsSystemDaemon()) { + // System daemon threads are things like the finalizer or gc thread. It would be dangerous to + // allow agents to get in the way of these threads starting up. These threads include things + // like the HeapTaskDaemon and the finalizer daemon. + // + // This event can happen during the time before VMInit or just after zygote fork. Since the + // second is hard to distinguish we unfortunately cannot really check the state here. + return; + } if (!started) { // Runtime isn't started. We only expect at most the signal handler or JIT threads to be // started here. @@ -132,16 +144,35 @@ void ThreadUtil::VMInitEventSent() { gThreadCallback.Post<ArtJvmtiEvent::kThreadStart>(art::Thread::Current()); } + +static void WaitForSystemDaemonStart(art::Thread* self) REQUIRES_SHARED(art::Locks::mutator_lock_) { + { + art::ScopedThreadStateChange strc(self, art::kNative); + JNIEnv* jni = self->GetJniEnv(); + jni->CallStaticVoidMethod(art::WellKnownClasses::java_lang_Daemons, + art::WellKnownClasses::java_lang_Daemons_waitForDaemonStart); + } + if (self->IsExceptionPending()) { + LOG(WARNING) << "Exception occured when waiting for system daemons to start: " + << self->GetException()->Dump(); + self->ClearException(); + } +} + void ThreadUtil::CacheData() { // We must have started since it is now safe to cache our data; gThreadCallback.started = true; - art::ScopedObjectAccess soa(art::Thread::Current()); + art::Thread* self = art::Thread::Current(); + art::ScopedObjectAccess soa(self); art::ObjPtr<art::mirror::Class> thread_class = soa.Decode<art::mirror::Class>(art::WellKnownClasses::java_lang_Thread); CHECK(thread_class != nullptr); context_class_loader_ = thread_class->FindDeclaredInstanceField("contextClassLoader", "Ljava/lang/ClassLoader;"); CHECK(context_class_loader_ != nullptr); + // Now wait for all required system threads to come up before allowing the rest of loading to + // continue. + WaitForSystemDaemonStart(self); } void ThreadUtil::Unregister() { diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 1465b14d44..7ecfdc70cd 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -869,14 +869,21 @@ bool Runtime::Start() { GetInstructionSetString(kRuntimeISA)); } - // Send the initialized phase event. Send it before starting daemons, as otherwise - // sending thread events becomes complicated. + StartDaemonThreads(); + + // Make sure the environment is still clean (no lingering local refs from starting daemon + // threads). { ScopedObjectAccess soa(self); - callbacks_->NextRuntimePhase(RuntimePhaseCallback::RuntimePhase::kInit); + self->GetJniEnv()->AssertLocalsEmpty(); } - StartDaemonThreads(); + // Send the initialized phase event. Send it after starting the Daemon threads so that agents + // cannot delay the daemon threads from starting forever. + { + ScopedObjectAccess soa(self); + callbacks_->NextRuntimePhase(RuntimePhaseCallback::RuntimePhase::kInit); + } { ScopedObjectAccess soa(self); diff --git a/runtime/thread.cc b/runtime/thread.cc index 4828aaef2c..44b45cfa75 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -4258,4 +4258,12 @@ int Thread::GetNativePriority() { return priority; } +bool Thread::IsSystemDaemon() const { + if (GetPeer() == nullptr) { + return false; + } + return jni::DecodeArtField( + WellKnownClasses::java_lang_Thread_systemDaemon)->GetBoolean(GetPeer()); +} + } // namespace art diff --git a/runtime/thread.h b/runtime/thread.h index 7a14fd7b48..ec276b59f5 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -1230,6 +1230,8 @@ class Thread { return this == jit_sensitive_thread_; } + bool IsSystemDaemon() const REQUIRES_SHARED(Locks::mutator_lock_); + // Returns true if StrictMode events are traced for the current thread. static bool IsSensitiveThread() { if (is_sensitive_thread_hook_ != nullptr) { diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index 955a455d36..19fbf63ff5 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -92,6 +92,7 @@ jmethodID WellKnownClasses::java_lang_ClassLoader_loadClass; jmethodID WellKnownClasses::java_lang_ClassNotFoundException_init; jmethodID WellKnownClasses::java_lang_Daemons_start; jmethodID WellKnownClasses::java_lang_Daemons_stop; +jmethodID WellKnownClasses::java_lang_Daemons_waitForDaemonStart; jmethodID WellKnownClasses::java_lang_Double_valueOf; jmethodID WellKnownClasses::java_lang_Float_valueOf; jmethodID WellKnownClasses::java_lang_Integer_valueOf; @@ -132,6 +133,7 @@ jfieldID WellKnownClasses::java_lang_Thread_lock; jfieldID WellKnownClasses::java_lang_Thread_name; jfieldID WellKnownClasses::java_lang_Thread_priority; jfieldID WellKnownClasses::java_lang_Thread_nativePeer; +jfieldID WellKnownClasses::java_lang_Thread_systemDaemon; jfieldID WellKnownClasses::java_lang_Thread_unparkedBeforeStart; jfieldID WellKnownClasses::java_lang_ThreadGroup_groups; jfieldID WellKnownClasses::java_lang_ThreadGroup_ngroups; @@ -351,6 +353,7 @@ void WellKnownClasses::Init(JNIEnv* env) { java_lang_Daemons_start = CacheMethod(env, java_lang_Daemons, true, "start", "()V"); java_lang_Daemons_stop = CacheMethod(env, java_lang_Daemons, true, "stop", "()V"); + java_lang_Daemons_waitForDaemonStart = CacheMethod(env, java_lang_Daemons, true, "waitForDaemonStart", "()V"); java_lang_invoke_MethodHandles_lookup = CacheMethod(env, "java/lang/invoke/MethodHandles", true, "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;"); java_lang_invoke_MethodHandles_Lookup_findConstructor = CacheMethod(env, "java/lang/invoke/MethodHandles$Lookup", false, "findConstructor", "(Ljava/lang/Class;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;"); @@ -385,6 +388,7 @@ void WellKnownClasses::Init(JNIEnv* env) { java_lang_Thread_name = CacheField(env, java_lang_Thread, false, "name", "Ljava/lang/String;"); java_lang_Thread_priority = CacheField(env, java_lang_Thread, false, "priority", "I"); java_lang_Thread_nativePeer = CacheField(env, java_lang_Thread, false, "nativePeer", "J"); + java_lang_Thread_systemDaemon = CacheField(env, java_lang_Thread, false, "systemDaemon", "Z"); java_lang_Thread_unparkedBeforeStart = CacheField(env, java_lang_Thread, false, "unparkedBeforeStart", "Z"); java_lang_ThreadGroup_groups = CacheField(env, java_lang_ThreadGroup, false, "groups", "[Ljava/lang/ThreadGroup;"); java_lang_ThreadGroup_ngroups = CacheField(env, java_lang_ThreadGroup, false, "ngroups", "I"); diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h index 872b562bd5..3c5144fbd5 100644 --- a/runtime/well_known_classes.h +++ b/runtime/well_known_classes.h @@ -101,6 +101,7 @@ struct WellKnownClasses { static jmethodID java_lang_ClassNotFoundException_init; static jmethodID java_lang_Daemons_start; static jmethodID java_lang_Daemons_stop; + static jmethodID java_lang_Daemons_waitForDaemonStart; static jmethodID java_lang_Double_valueOf; static jmethodID java_lang_Float_valueOf; static jmethodID java_lang_Integer_valueOf; @@ -141,6 +142,7 @@ struct WellKnownClasses { static jfieldID java_lang_Thread_name; static jfieldID java_lang_Thread_priority; static jfieldID java_lang_Thread_nativePeer; + static jfieldID java_lang_Thread_systemDaemon; static jfieldID java_lang_Thread_unparkedBeforeStart; static jfieldID java_lang_ThreadGroup_groups; static jfieldID java_lang_ThreadGroup_ngroups; diff --git a/test/Android.bp b/test/Android.bp index 467a7179a5..d070d76349 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -540,6 +540,6 @@ art_cc_test_library { "art_debug_defaults", "art_defaults", ], - header_libs: ["libnativebridge-dummy-headers"], + header_libs: ["libnativebridge-headers"], srcs: ["115-native-bridge/nativebridge.cc"], } diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar index 2910920b13..9d79a0b99e 100755 --- a/test/etc/run-test-jar +++ b/test/etc/run-test-jar @@ -30,7 +30,8 @@ FLAGS="" ANDROID_FLAGS="" GDB="" GDB_ARGS="" -GDB_SERVER="gdbserver" +GDBSERVER_DEVICE="gdbserver" +GDBSERVER_HOST="gdbserver" HAVE_IMAGE="y" HOST="n" BIONIC="n" @@ -60,6 +61,8 @@ else TIME_OUT_VALUE=1200 # 20 minutes. fi USE_GDB="n" +USE_GDBSERVER="n" +GDBSERVER_PORT=":5039" USE_JVM="n" USE_JVMTI="n" VERIFY="y" # y=yes,n=no,s=softfail @@ -267,6 +270,23 @@ while true; do DEBUGGER="y" TIME_OUT="n" shift + elif [ "x$1" = "x--gdbserver-port" ]; then + shift + GDBSERVER_PORT=$1 + shift + elif [ "x$1" = "x--gdbserver-bin" ]; then + shift + GDBSERVER_HOST=$1 + GDBSERVER_DEVICE=$1 + shift + elif [ "x$1" = "x--gdbserver" ]; then + USE_GDBSERVER="y" + DEV_MODE="y" + TIME_OUT="n" + HOST="y" + ANDROID_ROOT="${ANDROID_HOST_OUT}" + ANDROID_RUNTIME_ROOT="${ANDROID_HOST_OUT}/com.android.runtime" + shift elif [ "x$1" = "x--gdb" ]; then USE_GDB="y" DEV_MODE="y" @@ -342,7 +362,7 @@ while true; do break elif [ "x$1" = "x--64" ]; then ISA="x86_64" - GDB_SERVER="gdbserver64" + GDBSERVER_DEVICE="gdbserver64" DALVIKVM="dalvikvm64" LIBRARY_DIRECTORY="lib64" TEST_DIRECTORY="nativetest64" @@ -611,8 +631,11 @@ fi if [ "$USE_GDB" = "y" ]; then - if [ "$HOST" = "n" ]; then - GDB="$GDB_SERVER :5039" + if [ "$USE_GDBSERVER" = "y" ]; then + echo "Cannot pass both --gdb and --gdbserver at the same time!" >&2 + exit 1 + elif [ "$HOST" = "n" ]; then + GDB="$GDBSERVER_DEVICE $GDBSERVER_PORT" else if [ `uname` = "Darwin" ]; then GDB=lldb @@ -625,6 +648,12 @@ if [ "$USE_GDB" = "y" ]; then # gdbargs="--annotate=3 $gdbargs" fi fi +elif [ "$USE_GDBSERVER" = "y" ]; then + if [ "$HOST" = "n" ]; then + echo "Cannot use --gdbserver in non-host configs" >&2 + exit 1 + fi + GDB="$GDBSERVER_HOST $GDBSERVER_PORT" fi if [ "$INTERPRETER" = "y" ]; then @@ -1084,7 +1113,10 @@ else if [ "$USE_GDB" = "y" ]; then # When running under gdb, we cannot do piping and grepping... - echo "Run 'gdbclient.py -p <pid printed below>' to debug." + $cmdline "$@" + elif [ "$USE_GDBSERVER" = "y" ]; then + echo "Connect to $GDBSERVER_PORT" + # When running under gdb, we cannot do piping and grepping... $cmdline "$@" else if [ "$TIME_OUT" != "gdb" ]; then diff --git a/test/run-test b/test/run-test index 67bcce7deb..5f78d1779d 100755 --- a/test/run-test +++ b/test/run-test @@ -306,6 +306,18 @@ while true; do run_args="${run_args} --gdb" dev_mode="yes" shift + elif [ "x$1" = "x--gdbserver-bin" ]; then + shift + run_args="${run_args} --gdbserver-bin $1" + shift + elif [ "x$1" = "x--gdbserver-port" ]; then + shift + run_args="${run_args} --gdbserver-port $1" + shift + elif [ "x$1" = "x--gdbserver" ]; then + run_args="${run_args} --gdbserver" + dev_mode="yes" + shift elif [ "x$1" = "x--strace" ]; then strace="yes" run_args="${run_args} --timeout 1800 --invoke-with strace --invoke-with -o --invoke-with $tmp_dir/$strace_output" @@ -716,7 +728,12 @@ if [ "$usage" = "yes" ]; then echo " --with-agent <agent> Run the test with the given agent loaded with -agentpath:" echo " --debuggable Whether to compile Java code for a debugger." echo " --gdb Run under gdb; incompatible with some tests." - echo " --gdb-arg Pass an option to gdb." + echo " --gdbserver Start gdbserver (defaults to port :5039)." + echo " --gdbserver-port <port>" + echo " Start gdbserver with the given COMM (see man gdbserver)." + echo " --gdbserver-bin <binary>" + echo " Use the given binary as gdbserver." + echo " --gdb-arg Pass an option to gdb or gdbserver." echo " --build-only Build test files only (off by default)." echo " --interpreter Enable interpreter only mode (off by default)." echo " --jit Enable jit (off by default)." diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh index 6be243aaf2..e63e6f122e 100755 --- a/tools/buildbot-build.sh +++ b/tools/buildbot-build.sh @@ -77,7 +77,7 @@ elif [[ $mode == "target" ]]; then make_command+=" debuggerd su" make_command+=" libstdc++ " make_command+=" ${ANDROID_PRODUCT_OUT#"${ANDROID_BUILD_TOP}/"}/system/etc/public.libraries.txt" - make_command+=" art-bionic-files" + make_command+=" standalone-apex-files" if [[ -n "$ART_TEST_CHROOT" ]]; then # These targets are needed for the chroot environment. make_command+=" crash_dump event-log-tags" |