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"
+ ]
}
]