Merge "Revert^2: Deopt does not throw"
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc
index ee89717..4c2d4d7 100644
--- a/adbconnection/adbconnection.cc
+++ b/adbconnection/adbconnection.cc
@@ -825,20 +825,10 @@
 
 void AdbConnectionState::AttachJdwpAgent(art::Thread* self) {
   art::Runtime* runtime = art::Runtime::Current();
-  if (runtime->GetJit() == nullptr && !runtime->GetInstrumentation()->IsForcedInterpretOnly()) {
-    // If we don't have a JIT we should try to start the jit for performance reasons.
-    runtime->CreateJit();
-    if (runtime->GetJit() == nullptr) {
-      LOG(WARNING) << "Could not start jit for debugging. This process might be quite slow as it "
-                   << "is running entirely in the interpreter. Try running 'setenforce 0' and "
-                   << "starting the debugging session over.";
-    }
-  }
   self->AssertNoPendingException();
   runtime->AttachAgent(/* JNIEnv */ nullptr,
                        MakeAgentArg(),
-                       /* classloader */ nullptr,
-                       /*allow_non_debuggable_tooling*/ true);
+                       /* classloader */ nullptr);
   if (self->IsExceptionPending()) {
     LOG(ERROR) << "Failed to load agent " << agent_name_;
     art::ScopedObjectAccess soa(self);
diff --git a/openjdkjvmti/deopt_manager.cc b/openjdkjvmti/deopt_manager.cc
index a6f1207..d4e5df1 100644
--- a/openjdkjvmti/deopt_manager.cc
+++ b/openjdkjvmti/deopt_manager.cc
@@ -40,6 +40,7 @@
 #include "dex/dex_file_annotations.h"
 #include "dex/modifiers.h"
 #include "events-inl.h"
+#include "jit/jit.h"
 #include "jni_internal.h"
 #include "mirror/class-inl.h"
 #include "mirror/object_array-inl.h"
@@ -127,6 +128,22 @@
                    << "loaded too late to change runtime state to DEBUGGABLE. Only kArtTiVersion "
                    << "(0x" << std::hex << kArtTiVersion << ") environments are available. Some "
                    << "functionality might not work properly.";
+      if (runtime->GetJit() == nullptr &&
+          runtime->GetJITOptions()->UseJitCompilation() &&
+          !runtime->GetInstrumentation()->IsForcedInterpretOnly()) {
+        // If we don't have a jit we should try to start the jit for performance reasons. We only
+        // need to do this for late attach on non-debuggable processes because for debuggable
+        // processes we already rely on jit and we cannot force this jit to start if we are still in
+        // OnLoad since the runtime hasn't started up sufficiently. This is only expected to happen
+        // on userdebug/eng builds.
+        LOG(INFO) << "Attempting to start jit for openjdkjvmti plugin.";
+        runtime->CreateJit();
+        if (runtime->GetJit() == nullptr) {
+          LOG(WARNING) << "Could not start jit for openjdkjvmti plugin. This process might be "
+                       << "quite slow as it is running entirely in the interpreter. Try running "
+                       << "'setenforce 0' and restarting this process.";
+        }
+      }
     }
     runtime->DeoptimizeBootImage();
   }
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index c625a97..9a43790 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -275,6 +275,43 @@
   };
 };
 
+// Check whether the current thread is attached. This is usually required
+// to be the first check, as ScopedCheck needs a ScopedObjectAccess for
+// checking heap values (and that will fail with unattached threads).
+bool CheckAttachedThread(const char* function_name) {
+  Thread* self = Thread::Current();
+  if (UNLIKELY(self == nullptr)) {
+    // Need to attach this thread for a proper abort to work. We prefer this
+    // to get reasonable stacks and environment, rather than relying on
+    // tombstoned.
+    JNIEnv* env;
+    Runtime::Current()->GetJavaVM()->AttachCurrentThread(&env, /* thread_args */ nullptr);
+
+    std::string tmp = android::base::StringPrintf(
+        "a thread (tid %" PRId64 " is making JNI calls without being attached",
+        static_cast<int64_t>(GetTid()));
+    Runtime::Current()->GetJavaVM()->JniAbort(function_name, tmp.c_str());
+
+    CHECK_NE(Runtime::Current()->GetJavaVM()->DetachCurrentThread(), JNI_ERR);
+    return false;
+  }
+  return true;
+}
+
+// Macro helpers for the above.
+#define CHECK_ATTACHED_THREAD(function_name, fail_val)  \
+  do {                                                  \
+    if (!CheckAttachedThread((function_name))) {        \
+      return fail_val;                                  \
+    }                                                   \
+  } while (false)
+#define CHECK_ATTACHED_THREAD_VOID(function_name)       \
+  do {                                                  \
+    if (!CheckAttachedThread((function_name))) {        \
+      return;                                           \
+    }                                                   \
+  } while (false)
+
 class ScopedCheck {
  public:
   ScopedCheck(uint16_t flags, const char* functionName, bool has_method = true)
@@ -1255,10 +1292,7 @@
 
   bool CheckThread(JNIEnv* env) REQUIRES_SHARED(Locks::mutator_lock_) {
     Thread* self = Thread::Current();
-    if (self == nullptr) {
-      AbortF("a thread (tid %d) is making JNI calls without being attached", GetTid());
-      return false;
-    }
+    CHECK(self != nullptr);
 
     // Get the current thread's JNIEnv by going through our TLS pointer.
     JNIEnvExt* threadEnv = self->GetJniEnv();
@@ -1708,6 +1742,7 @@
 class CheckJNI {
  public:
   static jint GetVersion(JNIEnv* env) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_ERR);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[1] = {{.E = env }};
@@ -1722,6 +1757,7 @@
   }
 
   static jint GetJavaVM(JNIEnv *env, JavaVM **vm) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_ERR);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[2] = {{.E = env }, {.p = vm}};
@@ -1736,6 +1772,7 @@
   }
 
   static jint RegisterNatives(JNIEnv* env, jclass c, const JNINativeMethod* methods, jint nMethods) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_ERR);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[4] = {{.E = env }, {.c = c}, {.p = methods}, {.I = nMethods}};
@@ -1750,6 +1787,7 @@
   }
 
   static jint UnregisterNatives(JNIEnv* env, jclass c) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_ERR);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[2] = {{.E = env }, {.c = c}};
@@ -1764,6 +1802,7 @@
   }
 
   static jobjectRefType GetObjectRefType(JNIEnv* env, jobject obj) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNIInvalidRefType);
     // Note: we use "EL" here but "Ep" has been used in the past on the basis that we'd like to
     // know the object is invalid. The spec says that passing invalid objects or even ones that
     // are deleted isn't supported.
@@ -1782,6 +1821,7 @@
 
   static jclass DefineClass(JNIEnv* env, const char* name, jobject loader, const jbyte* buf,
                             jsize bufLen) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[5] = {{.E = env}, {.u = name}, {.L = loader}, {.p = buf}, {.z = bufLen}};
@@ -1796,6 +1836,7 @@
   }
 
   static jclass FindClass(JNIEnv* env, const char* name) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[2] = {{.E = env}, {.u = name}};
@@ -1810,6 +1851,7 @@
   }
 
   static jclass GetSuperclass(JNIEnv* env, jclass c) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[2] = {{.E = env}, {.c = c}};
@@ -1824,6 +1866,7 @@
   }
 
   static jboolean IsAssignableFrom(JNIEnv* env, jclass c1, jclass c2) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_FALSE);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[3] = {{.E = env}, {.c = c1}, {.c = c2}};
@@ -1838,6 +1881,7 @@
   }
 
   static jmethodID FromReflectedMethod(JNIEnv* env, jobject method) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[2] = {{.E = env}, {.L = method}};
@@ -1852,6 +1896,7 @@
   }
 
   static jfieldID FromReflectedField(JNIEnv* env, jobject field) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[2] = {{.E = env}, {.L = field}};
@@ -1866,6 +1911,7 @@
   }
 
   static jobject ToReflectedMethod(JNIEnv* env, jclass cls, jmethodID mid, jboolean isStatic) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[4] = {{.E = env}, {.c = cls}, {.m = mid}, {.I = isStatic}};
@@ -1881,6 +1927,7 @@
   }
 
   static jobject ToReflectedField(JNIEnv* env, jclass cls, jfieldID fid, jboolean isStatic) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[4] = {{.E = env}, {.c = cls}, {.f = fid}, {.I = isStatic}};
@@ -1896,6 +1943,7 @@
   }
 
   static jint Throw(JNIEnv* env, jthrowable obj) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_ERR);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[2] = {{.E = env}, {.t = obj}};
@@ -1910,6 +1958,7 @@
   }
 
   static jint ThrowNew(JNIEnv* env, jclass c, const char* message) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_ERR);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_NullableUtf, __FUNCTION__);
     JniValueType args[3] = {{.E = env}, {.c = c}, {.u = message}};
@@ -1924,6 +1973,7 @@
   }
 
   static jthrowable ExceptionOccurred(JNIEnv* env) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_ExcepOkay, __FUNCTION__);
     JniValueType args[1] = {{.E = env}};
@@ -1938,6 +1988,7 @@
   }
 
   static void ExceptionDescribe(JNIEnv* env) {
+    CHECK_ATTACHED_THREAD_VOID(__FUNCTION__);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_ExcepOkay, __FUNCTION__);
     JniValueType args[1] = {{.E = env}};
@@ -1950,6 +2001,7 @@
   }
 
   static void ExceptionClear(JNIEnv* env) {
+    CHECK_ATTACHED_THREAD_VOID(__FUNCTION__);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_ExcepOkay, __FUNCTION__);
     JniValueType args[1] = {{.E = env}};
@@ -1962,6 +2014,7 @@
   }
 
   static jboolean ExceptionCheck(JNIEnv* env) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_FALSE);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_CritOkay | kFlag_ExcepOkay, __FUNCTION__);
     JniValueType args[1] = {{.E = env}};
@@ -1976,6 +2029,7 @@
   }
 
   static void FatalError(JNIEnv* env, const char* msg) {
+    CHECK_ATTACHED_THREAD_VOID(__FUNCTION__);
     // The JNI specification doesn't say it's okay to call FatalError with a pending exception,
     // but you're about to abort anyway, and it's quite likely that you have a pending exception,
     // and it's not unimaginable that you don't know that you do. So we allow it.
@@ -1992,6 +2046,7 @@
   }
 
   static jint PushLocalFrame(JNIEnv* env, jint capacity) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_ERR);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_ExcepOkay, __FUNCTION__);
     JniValueType args[2] = {{.E = env}, {.I = capacity}};
@@ -2006,6 +2061,7 @@
   }
 
   static jobject PopLocalFrame(JNIEnv* env, jobject res) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_ExcepOkay, __FUNCTION__);
     JniValueType args[2] = {{.E = env}, {.L = res}};
@@ -2043,6 +2099,7 @@
   }
 
   static jint EnsureLocalCapacity(JNIEnv *env, jint capacity) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_ERR);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[2] = {{.E = env}, {.I = capacity}};
@@ -2057,6 +2114,7 @@
   }
 
   static jboolean IsSameObject(JNIEnv* env, jobject ref1, jobject ref2) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_FALSE);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[3] = {{.E = env}, {.L = ref1}, {.L = ref2}};
@@ -2071,6 +2129,7 @@
   }
 
   static jobject AllocObject(JNIEnv* env, jclass c) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[2] = {{.E = env}, {.c = c}};
@@ -2085,6 +2144,7 @@
   }
 
   static jobject NewObjectV(JNIEnv* env, jclass c, jmethodID mid, va_list vargs) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     VarArgs rest(mid, vargs);
@@ -2101,6 +2161,7 @@
   }
 
   static jobject NewObject(JNIEnv* env, jclass c, jmethodID mid, ...) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     va_list args;
     va_start(args, mid);
     jobject result = NewObjectV(env, c, mid, args);
@@ -2109,6 +2170,7 @@
   }
 
   static jobject NewObjectA(JNIEnv* env, jclass c, jmethodID mid, jvalue* vargs) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     VarArgs rest(mid, vargs);
@@ -2125,6 +2187,7 @@
   }
 
   static jclass GetObjectClass(JNIEnv* env, jobject obj) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[2] = {{.E = env}, {.L = obj}};
@@ -2139,6 +2202,7 @@
   }
 
   static jboolean IsInstanceOf(JNIEnv* env, jobject obj, jclass c) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_FALSE);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[3] = {{.E = env}, {.L = obj}, {.c = c}};
@@ -2314,6 +2378,7 @@
 #undef CALL
 
   static jstring NewString(JNIEnv* env, const jchar* unicode_chars, jsize len) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[3] = {{.E = env}, {.p = unicode_chars}, {.z = len}};
@@ -2328,6 +2393,7 @@
   }
 
   static jstring NewStringUTF(JNIEnv* env, const char* chars) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_NullableUtf, __FUNCTION__);
     JniValueType args[2] = {{.E = env}, {.u = chars}};
@@ -2343,6 +2409,7 @@
   }
 
   static jsize GetStringLength(JNIEnv* env, jstring string) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_ERR);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_CritOkay, __FUNCTION__);
     JniValueType args[2] = {{.E = env}, {.s = string}};
@@ -2357,6 +2424,7 @@
   }
 
   static jsize GetStringUTFLength(JNIEnv* env, jstring string) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_ERR);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_CritOkay, __FUNCTION__);
     JniValueType args[2] = {{.E = env}, {.s = string}};
@@ -2398,6 +2466,7 @@
   }
 
   static void GetStringRegion(JNIEnv* env, jstring string, jsize start, jsize len, jchar* buf) {
+    CHECK_ATTACHED_THREAD_VOID(__FUNCTION__);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_CritOkay, __FUNCTION__);
     JniValueType args[5] = {{.E = env}, {.s = string}, {.z = start}, {.z = len}, {.p = buf}};
@@ -2412,6 +2481,7 @@
   }
 
   static void GetStringUTFRegion(JNIEnv* env, jstring string, jsize start, jsize len, char* buf) {
+    CHECK_ATTACHED_THREAD_VOID(__FUNCTION__);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_CritOkay, __FUNCTION__);
     JniValueType args[5] = {{.E = env}, {.s = string}, {.z = start}, {.z = len}, {.p = buf}};
@@ -2426,6 +2496,7 @@
   }
 
   static jsize GetArrayLength(JNIEnv* env, jarray array) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_ERR);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_CritOkay, __FUNCTION__);
     JniValueType args[2] = {{.E = env}, {.a = array}};
@@ -2441,6 +2512,7 @@
 
   static jobjectArray NewObjectArray(JNIEnv* env, jsize length, jclass element_class,
                                      jobject initial_element) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[4] =
@@ -2457,6 +2529,7 @@
   }
 
   static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[3] = {{.E = env}, {.a = array}, {.z = index}};
@@ -2471,6 +2544,7 @@
   }
 
   static void SetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index, jobject value) {
+    CHECK_ATTACHED_THREAD_VOID(__FUNCTION__);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[4] = {{.E = env}, {.a = array}, {.z = index}, {.L = value}};
@@ -2557,6 +2631,7 @@
 #undef PRIMITIVE_ARRAY_FUNCTIONS
 
   static jint MonitorEnter(JNIEnv* env, jobject obj) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_ERR);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[2] = {{.E = env}, {.L = obj}};
@@ -2574,6 +2649,7 @@
   }
 
   static jint MonitorExit(JNIEnv* env, jobject obj) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_ERR);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_ExcepOkay, __FUNCTION__);
     JniValueType args[2] = {{.E = env}, {.L = obj}};
@@ -2591,6 +2667,7 @@
   }
 
   static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray array, jboolean* is_copy) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_CritGet, __FUNCTION__);
     JniValueType args[3] = {{.E = env}, {.a = array}, {.p = is_copy}};
@@ -2609,6 +2686,7 @@
   }
 
   static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void* carray, jint mode) {
+    CHECK_ATTACHED_THREAD_VOID(__FUNCTION__);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_CritRelease | kFlag_ExcepOkay, __FUNCTION__);
     sc.CheckNonNull(carray);
@@ -2625,6 +2703,7 @@
   }
 
   static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[3] = {{.E = env}, {.p = address}, {.J = capacity}};
@@ -2640,6 +2719,7 @@
   }
 
   static void* GetDirectBufferAddress(JNIEnv* env, jobject buf) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[2] = {{.E = env}, {.L = buf}};
@@ -2656,6 +2736,7 @@
   }
 
   static jlong GetDirectBufferCapacity(JNIEnv* env, jobject buf) {
+    CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_ERR);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, __FUNCTION__);
     JniValueType args[2] = {{.E = env}, {.L = buf}};
@@ -2681,6 +2762,7 @@
   }
 
   static jobject NewRef(const char* function_name, JNIEnv* env, jobject obj, IndirectRefKind kind) {
+    CHECK_ATTACHED_THREAD(function_name, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, function_name);
     JniValueType args[2] = {{.E = env}, {.L = obj}};
@@ -2709,6 +2791,7 @@
   }
 
   static void DeleteRef(const char* function_name, JNIEnv* env, jobject obj, IndirectRefKind kind) {
+    CHECK_ATTACHED_THREAD_VOID(function_name);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_ExcepOkay, function_name);
     JniValueType args[2] = {{.E = env}, {.L = obj}};
@@ -2735,6 +2818,7 @@
 
   static jmethodID GetMethodIDInternal(const char* function_name, JNIEnv* env, jclass c,
                                        const char* name, const char* sig, bool is_static) {
+    CHECK_ATTACHED_THREAD(function_name, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, function_name);
     JniValueType args[4] = {{.E = env}, {.c = c}, {.u = name}, {.u = sig}};
@@ -2754,6 +2838,7 @@
 
   static jfieldID GetFieldIDInternal(const char* function_name, JNIEnv* env, jclass c,
                                      const char* name, const char* sig, bool is_static) {
+    CHECK_ATTACHED_THREAD(function_name, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, function_name);
     JniValueType args[4] = {{.E = env}, {.c = c}, {.u = name}, {.u = sig}};
@@ -2773,6 +2858,7 @@
 
   static JniValueType GetField(const char* function_name, JNIEnv* env, jobject obj, jfieldID fid,
                                bool is_static, Primitive::Type type) {
+    CHECK_ATTACHED_THREAD(function_name, JniValueType());
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, function_name);
     JniValueType args[3] = {{.E = env}, {.L = obj}, {.f = fid}};
@@ -2867,6 +2953,7 @@
 
   static void SetField(const char* function_name, JNIEnv* env, jobject obj, jfieldID fid,
                        bool is_static, Primitive::Type type, JniValueType value) {
+    CHECK_ATTACHED_THREAD_VOID(function_name);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, function_name);
     JniValueType args[4] = {{.E = env}, {.L = obj}, {.f = fid}, value};
@@ -2981,6 +3068,7 @@
   static JniValueType CallMethodA(const char* function_name, JNIEnv* env, jobject obj, jclass c,
                                   jmethodID mid, jvalue* vargs, Primitive::Type type,
                                   InvokeType invoke) {
+    CHECK_ATTACHED_THREAD(function_name, JniValueType());
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, function_name);
     JniValueType result;
@@ -3165,6 +3253,7 @@
   static JniValueType CallMethodV(const char* function_name, JNIEnv* env, jobject obj, jclass c,
                                   jmethodID mid, va_list vargs, Primitive::Type type,
                                   InvokeType invoke) {
+    CHECK_ATTACHED_THREAD(function_name, JniValueType());
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, function_name);
     JniValueType result;
@@ -3348,6 +3437,7 @@
 
   static const void* GetStringCharsInternal(const char* function_name, JNIEnv* env, jstring string,
                                             jboolean* is_copy, bool utf, bool critical) {
+    CHECK_ATTACHED_THREAD(function_name, nullptr);
     ScopedObjectAccess soa(env);
     int flags = critical ? kFlag_CritGet : kFlag_CritOkay;
     ScopedCheck sc(flags, function_name);
@@ -3388,6 +3478,7 @@
 
   static void ReleaseStringCharsInternal(const char* function_name, JNIEnv* env, jstring string,
                                          const void* chars, bool utf, bool critical) {
+    CHECK_ATTACHED_THREAD_VOID(function_name);
     ScopedObjectAccess soa(env);
     int flags = kFlag_ExcepOkay | kFlag_Release;
     if (critical) {
@@ -3420,6 +3511,7 @@
 
   static jarray NewPrimitiveArray(const char* function_name, JNIEnv* env, jsize length,
                                   Primitive::Type type) {
+    CHECK_ATTACHED_THREAD(function_name, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, function_name);
     JniValueType args[2] = {{.E = env}, {.z = length}};
@@ -3462,6 +3554,7 @@
 
   static void* GetPrimitiveArrayElements(const char* function_name, Primitive::Type type,
                                          JNIEnv* env, jarray array, jboolean* is_copy) {
+    CHECK_ATTACHED_THREAD(function_name, nullptr);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, function_name);
     JniValueType args[3] = {{.E = env}, {.a = array}, {.p = is_copy}};
@@ -3513,6 +3606,7 @@
 
   static void ReleasePrimitiveArrayElements(const char* function_name, Primitive::Type type,
                                             JNIEnv* env, jarray array, void* elems, jint mode) {
+    CHECK_ATTACHED_THREAD_VOID(function_name);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_ExcepOkay, function_name);
     if (sc.CheckNonNull(elems) && sc.CheckPrimitiveArrayType(soa, array, type)) {
@@ -3568,6 +3662,7 @@
 
   static void GetPrimitiveArrayRegion(const char* function_name, Primitive::Type type, JNIEnv* env,
                                       jarray array, jsize start, jsize len, void* buf) {
+    CHECK_ATTACHED_THREAD_VOID(function_name);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, function_name);
     JniValueType args[5] = {{.E = env}, {.a = array}, {.z = start}, {.z = len}, {.p = buf}};
@@ -3618,6 +3713,7 @@
 
   static void SetPrimitiveArrayRegion(const char* function_name, Primitive::Type type, JNIEnv* env,
                                       jarray array, jsize start, jsize len, const void* buf) {
+    CHECK_ATTACHED_THREAD_VOID(function_name);
     ScopedObjectAccess soa(env);
     ScopedCheck sc(kFlag_Default, function_name);
     JniValueType args[5] = {{.E = env}, {.a = array}, {.z = start}, {.z = len}, {.p = buf}};
diff --git a/runtime/debug_print.cc b/runtime/debug_print.cc
index 6048767..7e075ce 100644
--- a/runtime/debug_print.cc
+++ b/runtime/debug_print.cc
@@ -97,14 +97,27 @@
       StackHandleScope<1> hs(soa.Self());
       Handle<mirror::ClassLoader> handle(hs.NewHandle(loader));
       const char* path_separator = "";
-      VisitClassLoaderDexFiles(soa,
-                               handle,
-                               [&](const DexFile* dex_file) {
-                                 oss << path_separator << dex_file->GetLocation()
-                                     << "/" << static_cast<const void*>(dex_file);
-                                 path_separator = ":";
-                                 return true;  // Continue with the next DexFile.
-                               });
+      const DexFile* base_dex_file = nullptr;
+      VisitClassLoaderDexFiles(
+          soa,
+          handle,
+          [&](const DexFile* dex_file) {
+              oss << path_separator;
+              path_separator = ":";
+              if (base_dex_file != nullptr &&
+                  dex_file->GetLocation().length() > base_dex_file->GetLocation().length() &&
+                  dex_file->GetLocation().compare(0u,
+                                                  base_dex_file->GetLocation().length(),
+                                                  base_dex_file->GetLocation()) == 0) {
+                // Replace the base location with "+" to shorten the output.
+                oss << "+" << dex_file->GetLocation().substr(base_dex_file->GetLocation().length());
+              } else {
+                oss << dex_file->GetLocation();
+                base_dex_file = dex_file;
+              }
+              oss << "/" << static_cast<const void*>(dex_file);
+              return true;  // Continue with the next DexFile.
+          });
       oss << ")";
     }
   }
@@ -132,13 +145,13 @@
   std::string source_descriptor_storage;
   const char* source_descriptor = src_class->GetDescriptor(&source_descriptor_storage);
 
+  LOG(ERROR) << "Maybe bug 77342775, looking for " << target_descriptor
+      << " with loader " << DescribeLoaders(target_class->GetClassLoader(), target_descriptor);
   if (target_class->IsInterface()) {
     ObjPtr<mirror::IfTable> iftable = src_class->GetIfTable();
     CHECK(iftable != nullptr);
     size_t ifcount = iftable->Count();
-    LOG(ERROR) << "Maybe bug 77342775, looking for " << target_descriptor
-        << " with loader " << DescribeLoaders(target_class->GetClassLoader(), target_descriptor)
-        << " in interface table for " << source_descriptor << " ifcount=" << ifcount
+    LOG(ERROR) << "  in interface table for " << source_descriptor << " ifcount=" << ifcount
         << " with loader " << DescribeLoaders(src_class->GetClassLoader(), source_descriptor);
     for (size_t i = 0; i != ifcount; ++i) {
       ObjPtr<mirror::Class> iface = iftable->GetInterface(i);
@@ -147,9 +160,7 @@
       matcher(iface);
     }
   } else {
-    LOG(ERROR) << "Maybe bug 77342775, looking for " << target_descriptor
-        << " with loader " << DescribeLoaders(target_class->GetClassLoader(), target_descriptor)
-        << " in superclass chain for " << source_descriptor
+    LOG(ERROR) << "  in superclass chain for " << source_descriptor
         << " with loader " << DescribeLoaders(src_class->GetClassLoader(), source_descriptor);
     for (ObjPtr<mirror::Class> klass = src_class;
          klass != nullptr;
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index 293e18a..5d74181 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -2517,4 +2517,32 @@
   env_->DeleteGlobalRef(global2);
 }
 
+TEST_F(JniInternalTest, NonAttachedThread) {
+  // This tests leads to warnings and errors in the log.
+  ScopedLogSeverity sls(LogSeverity::FATAL);
+  CheckJniAbortCatcher check_jni_abort_catcher;
+
+  auto callee = [](void* env_ptr) -> void* {
+    JNIEnv* env = reinterpret_cast<JNIEnv*>(env_ptr);
+    env->NewStringUTF("test");
+    return nullptr;
+  };
+
+  bool old_check_jni = vm_->SetCheckJniEnabled(false);
+  vm_->SetCheckJniEnabled(true);
+  {
+    pthread_t pthread;
+    int pthread_create_result = pthread_create(&pthread,
+                                               /* pthread_attr */ nullptr,
+                                               callee,
+                                               reinterpret_cast<void*>(env_));
+    CHECK_EQ(pthread_create_result, 0);
+    int pthread_join_result = pthread_join(pthread, /* thread_return */ nullptr);
+    CHECK_EQ(pthread_join_result, 0);
+  }
+  vm_->SetCheckJniEnabled(old_check_jni);
+
+  check_jni_abort_catcher.Check("is making JNI calls without being attached");
+}
+
 }  // namespace art
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index c394fef..8f5295c 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1619,7 +1619,6 @@
 }
 
 static bool EnsureJvmtiPlugin(Runtime* runtime,
-                              bool allow_non_debuggable_tooling,
                               std::vector<Plugin>* plugins,
                               std::string* error_msg) {
   constexpr const char* plugin_name = kIsDebugBuild ? "libopenjdkjvmtid.so" : "libopenjdkjvmti.so";
@@ -1631,10 +1630,13 @@
     }
   }
 
+  // TODO Rename Dbg::IsJdwpAllowed is IsDebuggingAllowed.
+  DCHECK(Dbg::IsJdwpAllowed() || !runtime->IsJavaDebuggable())
+      << "Being debuggable requires that jdwp (i.e. debugging) is allowed.";
   // Is the process debuggable? Otherwise, do not attempt to load the plugin unless we are
   // specifically allowed.
-  if (!allow_non_debuggable_tooling && !runtime->IsJavaDebuggable()) {
-    *error_msg = "Process is not debuggable.";
+  if (!Dbg::IsJdwpAllowed()) {
+    *error_msg = "Process is not allowed to load openjdkjvmti plugin. Process must be debuggable";
     return false;
   }
 
@@ -1654,12 +1656,9 @@
 //   revisit this and make sure we're doing this on the right thread
 //   (and we synchronize access to any shared data structures like "agents_")
 //
-void Runtime::AttachAgent(JNIEnv* env,
-                          const std::string& agent_arg,
-                          jobject class_loader,
-                          bool allow_non_debuggable_tooling) {
+void Runtime::AttachAgent(JNIEnv* env, const std::string& agent_arg, jobject class_loader) {
   std::string error_msg;
-  if (!EnsureJvmtiPlugin(this, allow_non_debuggable_tooling, &plugins_, &error_msg)) {
+  if (!EnsureJvmtiPlugin(this, &plugins_, &error_msg)) {
     LOG(WARNING) << "Could not load plugin: " << error_msg;
     ScopedObjectAccess soa(Thread::Current());
     ThrowIOException("%s", error_msg.c_str());
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 3d4b596..1b7663c 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -710,10 +710,7 @@
   void AddSystemWeakHolder(gc::AbstractSystemWeakHolder* holder);
   void RemoveSystemWeakHolder(gc::AbstractSystemWeakHolder* holder);
 
-  void AttachAgent(JNIEnv* env,
-                   const std::string& agent_arg,
-                   jobject class_loader,
-                   bool allow_non_debuggable_tooling = false);
+  void AttachAgent(JNIEnv* env, const std::string& agent_arg, jobject class_loader);
 
   const std::list<std::unique_ptr<ti::Agent>>& GetAgents() const {
     return agents_;
diff --git a/test/909-attach-agent/attach.cc b/test/909-attach-agent/attach.cc
index 3a6788a..50ab26a 100644
--- a/test/909-attach-agent/attach.cc
+++ b/test/909-attach-agent/attach.cc
@@ -32,6 +32,8 @@
   fflush(stdout);
 }
 
+static constexpr jint kArtTiVersion = JVMTI_VERSION_1_2 | 0x40000000;
+
 jint OnAttach(JavaVM* vm,
             char* options ATTRIBUTE_UNUSED,
             void* reserved ATTRIBUTE_UNUSED) {
@@ -47,7 +49,18 @@
     } \
   } while (false)
 
-  CHECK_CALL_SUCCESS(vm->GetEnv(reinterpret_cast<void**>(&env), JVMTI_VERSION_1_0));
+  if (vm->GetEnv(reinterpret_cast<void**>(&env), kArtTiVersion) == JNI_OK) {
+    Println("Created env for kArtTiVersion");
+    CHECK_CALL_SUCCESS(env->DisposeEnvironment());
+    env = nullptr;
+  } else {
+    Println("Failed to create env for kArtTiVersion");
+    return -1;
+  }
+  if (vm->GetEnv(reinterpret_cast<void**>(&env), JVMTI_VERSION_1_0) != JNI_OK) {
+    Println("Unable to create env for JVMTI_VERSION_1_0");
+    return 0;
+  }
   CHECK_CALL_SUCCESS(vm->GetEnv(reinterpret_cast<void**>(&env2), JVMTI_VERSION_1_0));
   if (env == env2) {
     Println("GetEnv returned same environment twice!");
diff --git a/test/909-attach-agent/disallow_debugging.cc b/test/909-attach-agent/disallow_debugging.cc
new file mode 100644
index 0000000..4c70f62
--- /dev/null
+++ b/test/909-attach-agent/disallow_debugging.cc
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include "debugger.h"
+
+namespace art {
+namespace Test909AttachAgent {
+
+extern "C" JNIEXPORT void JNICALL Java_Main_setDebuggingAllowed(JNIEnv*, jclass, jboolean val) {
+  Dbg::SetJdwpAllowed(val);
+}
+
+}  // namespace Test909AttachAgent
+}  // namespace art
diff --git a/test/909-attach-agent/expected.txt b/test/909-attach-agent/expected.txt
index 4d687f5..eec767d 100644
--- a/test/909-attach-agent/expected.txt
+++ b/test/909-attach-agent/expected.txt
@@ -1,12 +1,28 @@
+JNI_OnLoad called
 Hello, world!
 Attached Agent for test 909-attach-agent
+Created env for kArtTiVersion
 Attached Agent for test 909-attach-agent
+Created env for kArtTiVersion
 Goodbye!
+JNI_OnLoad called
 Hello, world!
 Attached Agent for test 909-attach-agent
+Created env for kArtTiVersion
 Attached Agent for test 909-attach-agent
+Created env for kArtTiVersion
 Goodbye!
+JNI_OnLoad called
 Hello, world!
-Process is not debuggable.
-Process is not debuggable.
+Attached Agent for test 909-attach-agent
+Created env for kArtTiVersion
+version 0x30010000 is not valid!Unable to create env for JVMTI_VERSION_1_0
+Attached Agent for test 909-attach-agent
+Created env for kArtTiVersion
+version 0x30010000 is not valid!Unable to create env for JVMTI_VERSION_1_0
+Goodbye!
+JNI_OnLoad called
+Hello, world!
+Can't attach agent, process is not debuggable.
+Can't attach agent, process is not debuggable.
 Goodbye!
diff --git a/test/909-attach-agent/interpreter-expected.patch b/test/909-attach-agent/interpreter-expected.patch
new file mode 100644
index 0000000..5035c6a
--- /dev/null
+++ b/test/909-attach-agent/interpreter-expected.patch
@@ -0,0 +1,4 @@
+19d18
+< version 0x30010000 is not valid!Unable to create env for JVMTI_VERSION_1_0
+22d20
+< version 0x30010000 is not valid!Unable to create env for JVMTI_VERSION_1_0
diff --git a/test/909-attach-agent/run b/test/909-attach-agent/run
index a556bba..fd45abd 100755
--- a/test/909-attach-agent/run
+++ b/test/909-attach-agent/run
@@ -21,6 +21,14 @@
   plugin=libopenjdkjvmti.so
 fi
 
+if [[ "$@" == *"--interpreter"* ]]; then
+  # On interpreter we are fully capable of providing the full jvmti api so we
+  # have a slightly different expected output.
+  # TODO We should really be changing this in the 'check' script.
+  patch -s expected.txt <interpreter-expected.patch
+fi
+
+export ANDROID_LOG_TAGS='*:f'
 ./default-run "$@" --android-runtime-option -Xplugin:${plugin} \
                    --android-runtime-option -Xcompiler-option \
                    --android-runtime-option --debuggable \
@@ -32,8 +40,16 @@
                    --args agent:${agent}=909-attach-agent
 return_status2=$?
 
-./default-run "$@" --args agent:${agent}=909-attach-agent
+./default-run "$@" --args agent:${agent}=909-attach-agent --external-log-tags
 return_status3=$?
 
+./default-run "$@" --args agent:${agent}=909-attach-agent \
+                   --args disallow-debugging \
+                   --external-log-tags
+return_status4=$?
+
 # Make sure we don't silently ignore an early failure.
-(exit $return_status1) && (exit $return_status2) && (exit $return_status3)
+(exit $return_status1) && \
+  (exit $return_status2) && \
+  (exit $return_status3) && \
+  (exit $return_status4)
diff --git a/test/909-attach-agent/src-art/Main.java b/test/909-attach-agent/src-art/Main.java
index 705e61e..6359f7e 100644
--- a/test/909-attach-agent/src-art/Main.java
+++ b/test/909-attach-agent/src-art/Main.java
@@ -24,23 +24,36 @@
 import java.io.IOException;
 
 public class Main {
-  public static void main(String[] args) {
+  public static void main(String[] args) throws Exception {
+    System.loadLibrary(args[0]);
     System.out.println("Hello, world!");
+    String agent = null;
+    // By default allow debugging
+    boolean debugging_allowed = true;
     for(String a : args) {
       if(a.startsWith("agent:")) {
-        String agent = a.substring(6);
-        try {
-          VMDebug.attachAgent(agent);
-        } catch(IOException e) {
-          System.out.println(e.getMessage());
-        }
+        agent = a.substring(6);
+      } else if (a.equals("disallow-debugging")) {
+        debugging_allowed = false;
       }
     }
+    if (agent == null) {
+      throw new Error("Could not find agent: argument!");
+    }
+    setDebuggingAllowed(debugging_allowed);
+    // Setup is finished. Try to attach agent in 2 ways.
+    try {
+      VMDebug.attachAgent(agent);
+    } catch(SecurityException e) {
+      System.out.println(e.getMessage());
+    }
     attachWithClassLoader(args);
     System.out.println("Goodbye!");
   }
 
-  private static void attachWithClassLoader(String[] args) {
+  private static native void setDebuggingAllowed(boolean val);
+
+  private static void attachWithClassLoader(String[] args) throws Exception {
     for(String a : args) {
       if(a.startsWith("agent:")) {
         String agentName = a.substring(6, a.indexOf('='));
@@ -56,7 +69,7 @@
               Main.class.getClassLoader());
           try {
             VMDebug.attachAgent(agent, cl);
-          } catch(IOException e) {
+          } catch(SecurityException e) {
             System.out.println(e.getMessage());
           }
         } catch (Exception e) {
diff --git a/test/Android.bp b/test/Android.bp
index bd13de2..b9312c8 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -440,6 +440,7 @@
         "667-jit-jni-stub/jit_jni_stub_test.cc",
         "674-hiddenapi/hiddenapi.cc",
         "708-jit-cache-churn/jit.cc",
+        "909-attach-agent/disallow_debugging.cc",
         "1947-breakpoint-redefine-deopt/check_deopt.cc",
         "common/runtime_state.cc",
         "common/stack_inspect.cc",
diff --git a/tools/libcore_gcstress_debug_failures.txt b/tools/libcore_gcstress_debug_failures.txt
index 0029b0a..06f6339 100644
--- a/tools/libcore_gcstress_debug_failures.txt
+++ b/tools/libcore_gcstress_debug_failures.txt
@@ -17,5 +17,22 @@
           "libcore.java.util.TimeZoneTest#testSetDefaultDeadlock",
           "libcore.javax.crypto.CipherBasicsTest#testBasicEncryption",
           "org.apache.harmony.tests.java.util.TimerTest#testThrowingTaskKillsTimerThread"]
+},
+{
+  description: "Sometimes times out with gcstress and debug.",
+  result: EXEC_FAILED,
+  bug: 78228743,
+  names: [
+    "libcore.libcore.icu.RelativeDateTimeFormatterTest#test_combineDateAndTime_apostrophe",
+    "libcore.libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeDateTimeString",
+    "libcore.libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeDateTimeStringCTS",
+    "libcore.libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeDateTimeStringDST",
+    "libcore.libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeDateTimeStringItalian",
+    "libcore.libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeTimeSpanString",
+    "libcore.libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeTimeSpanStringAbbrev",
+    "libcore.libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeTimeSpanStringCTS",
+    "libcore.libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeTimeSpanStringFrench",
+    "libcore.libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeTimeSpanStringGerman"
+  ]
 }
 ]