Snap for 4739962 from 8917309cc1096d898d2c90847b8e969891a8ddf0 to pi-release
Change-Id: I1fdc3c856b70d3f02b6dd119c1ca8648a5123da9
diff --git a/compiler/Android.bp b/compiler/Android.bp
index e42261c..32e42bc 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -218,7 +218,10 @@
art_cc_library {
name: "libart-compiler",
- defaults: ["libart-compiler-defaults"],
+ defaults: [
+ "libart-compiler-defaults",
+ "dex2oat-pgo-defaults",
+ ],
codegen: {
arm: {
// VIXL assembly support for ARM targets.
@@ -252,11 +255,6 @@
"libdexfile",
],
- pgo: {
- instrumentation: true,
- profile_file: "art/dex2oat.profdata",
- benchmarks: ["dex2oat"],
- },
target: {
android: {
lto: {
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index b158231..b793406 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -112,10 +112,51 @@
],
}
+cc_defaults {
+ name: "dex2oat-pgo-defaults",
+ pgo: {
+ instrumentation: true,
+ benchmarks: ["dex2oat"],
+ },
+ target: {
+ android_arm64: {
+ pgo: {
+ profile_file: "art/dex2oat_arm_arm64.profdata",
+ },
+ },
+ android_arm: {
+ pgo: {
+ profile_file: "art/dex2oat_arm_arm64.profdata",
+ },
+ },
+ android_x86_64: {
+ pgo: {
+ profile_file: "art/dex2oat_x86_x86_64.profdata",
+ },
+ },
+ android_x86: {
+ pgo: {
+ profile_file: "art/dex2oat_x86_x86_64.profdata",
+ },
+ },
+ android_mips64: {
+ pgo: {
+ profile_file: "art/dex2oat_mips_mips64.profdata",
+ },
+ },
+ android_mips: {
+ pgo: {
+ profile_file: "art/dex2oat_mips_mips64.profdata",
+ },
+ },
+ },
+}
+
art_cc_binary {
name: "dex2oat",
defaults: [
"dex2oat-defaults",
+ "dex2oat-pgo-defaults",
],
shared_libs: [
"libart-compiler",
@@ -131,9 +172,7 @@
],
pgo: {
- instrumentation: true,
- profile_file: "art/dex2oat.profdata",
- benchmarks: ["dex2oat"],
+ // Additional cflags just for dex2oat during PGO instrumentation
cflags: [
// Ignore frame-size increase resulting from instrumentation.
"-Wno-frame-larger-than=",
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index facda11..33ba58f 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -34,17 +34,15 @@
art_cc_library {
name: "libart-dexlayout",
- defaults: ["libart-dexlayout-defaults"],
+ defaults: [
+ "libart-dexlayout-defaults",
+ "dex2oat-pgo-defaults",
+ ],
shared_libs: [
"libart",
"libdexfile",
],
- pgo: {
- instrumentation: true,
- profile_file: "art/dex2oat.profdata",
- benchmarks: ["dex2oat"],
- },
target: {
android: {
lto: {
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index 900ce0e..b1ededf 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -273,6 +273,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)
@@ -1254,10 +1291,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();
@@ -1707,6 +1741,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 }};
@@ -1721,6 +1756,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}};
@@ -1735,6 +1771,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}};
@@ -1749,6 +1786,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}};
@@ -1763,6 +1801,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.
@@ -1781,6 +1820,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}};
@@ -1795,6 +1835,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}};
@@ -1809,6 +1850,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}};
@@ -1823,6 +1865,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}};
@@ -1837,6 +1880,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}};
@@ -1851,6 +1895,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}};
@@ -1865,6 +1910,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}};
@@ -1880,6 +1926,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}};
@@ -1895,6 +1942,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}};
@@ -1909,6 +1957,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}};
@@ -1923,6 +1972,7 @@
}
static jthrowable ExceptionOccurred(JNIEnv* env) {
+ CHECK_ATTACHED_THREAD(__FUNCTION__, nullptr);
ScopedObjectAccess soa(env);
ScopedCheck sc(kFlag_ExcepOkay, __FUNCTION__);
JniValueType args[1] = {{.E = env}};
@@ -1937,6 +1987,7 @@
}
static void ExceptionDescribe(JNIEnv* env) {
+ CHECK_ATTACHED_THREAD_VOID(__FUNCTION__);
ScopedObjectAccess soa(env);
ScopedCheck sc(kFlag_ExcepOkay, __FUNCTION__);
JniValueType args[1] = {{.E = env}};
@@ -1949,6 +2000,7 @@
}
static void ExceptionClear(JNIEnv* env) {
+ CHECK_ATTACHED_THREAD_VOID(__FUNCTION__);
ScopedObjectAccess soa(env);
ScopedCheck sc(kFlag_ExcepOkay, __FUNCTION__);
JniValueType args[1] = {{.E = env}};
@@ -1961,6 +2013,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}};
@@ -1975,6 +2028,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.
@@ -1991,6 +2045,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}};
@@ -2005,6 +2060,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}};
@@ -2042,6 +2098,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}};
@@ -2056,6 +2113,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}};
@@ -2070,6 +2128,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}};
@@ -2084,6 +2143,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);
@@ -2100,6 +2160,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);
@@ -2108,6 +2169,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);
@@ -2124,6 +2186,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}};
@@ -2138,6 +2201,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}};
@@ -2313,6 +2377,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}};
@@ -2327,6 +2392,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}};
@@ -2342,6 +2408,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}};
@@ -2356,6 +2423,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}};
@@ -2397,6 +2465,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}};
@@ -2411,6 +2480,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}};
@@ -2425,6 +2495,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}};
@@ -2440,6 +2511,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] =
@@ -2456,6 +2528,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}};
@@ -2470,6 +2543,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}};
@@ -2556,6 +2630,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}};
@@ -2573,6 +2648,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}};
@@ -2590,6 +2666,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}};
@@ -2608,6 +2685,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);
@@ -2624,6 +2702,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}};
@@ -2639,6 +2718,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}};
@@ -2655,6 +2735,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}};
@@ -2680,6 +2761,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}};
@@ -2708,6 +2790,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}};
@@ -2734,6 +2817,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}};
@@ -2753,6 +2837,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}};
@@ -2772,6 +2857,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}};
@@ -2866,6 +2952,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};
@@ -2980,6 +3067,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;
@@ -3164,6 +3252,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;
@@ -3347,6 +3436,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);
@@ -3387,6 +3477,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) {
@@ -3419,6 +3510,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}};
@@ -3461,6 +3553,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}};
@@ -3512,6 +3605,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)) {
@@ -3567,6 +3661,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}};
@@ -3617,6 +3712,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/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/tools/veridex/flow_analysis.cc b/tools/veridex/flow_analysis.cc
index a4553f9..736abb7 100644
--- a/tools/veridex/flow_analysis.cc
+++ b/tools/veridex/flow_analysis.cc
@@ -262,8 +262,17 @@
last_result_ = GetReturnType(instruction.VRegB_35c());
} else if (method == VeriClass::getClass_) {
RegisterValue obj = GetRegister(args[0]);
- last_result_ = RegisterValue(
- obj.GetSource(), obj.GetDexFileReference(), VeriClass::class_);
+ const VeriClass* cls = obj.GetType();
+ if (cls != nullptr && cls->GetClassDef() != nullptr) {
+ const DexFile::ClassDef* def = cls->GetClassDef();
+ last_result_ = RegisterValue(
+ RegisterSource::kClass,
+ DexFileReference(&resolver_->GetDexFileOf(*cls), def->class_idx_.index_),
+ VeriClass::class_);
+ } else {
+ last_result_ = RegisterValue(
+ obj.GetSource(), obj.GetDexFileReference(), VeriClass::class_);
+ }
} else if (method == VeriClass::loadClass_) {
RegisterValue value = GetRegister(args[1]);
last_result_ = RegisterValue(
diff --git a/tools/veridex/hidden_api_finder.cc b/tools/veridex/hidden_api_finder.cc
index b1ae7dd..8c6139f 100644
--- a/tools/veridex/hidden_api_finder.cc
+++ b/tools/veridex/hidden_api_finder.cc
@@ -31,11 +31,8 @@
void HiddenApiFinder::CheckMethod(uint32_t method_id,
VeridexResolver* resolver,
MethodReference ref) {
- // Cheap check that the method is resolved. If it is, we know it's not in
- // a restricted list.
- if (resolver->GetMethod(method_id) != nullptr) {
- return;
- }
+ // Note: we always query whether a method is in a list, as the app
+ // might define blacklisted APIs (which won't be used at runtime).
std::string name = HiddenApi::GetApiMethodName(resolver->GetDexFile(), method_id);
if (hidden_api_.IsInRestrictionList(name)) {
method_locations_[name].push_back(ref);
@@ -45,11 +42,8 @@
void HiddenApiFinder::CheckField(uint32_t field_id,
VeridexResolver* resolver,
MethodReference ref) {
- // Cheap check that the field is resolved. If it is, we know it's not in
- // a restricted list.
- if (resolver->GetField(field_id) != nullptr) {
- return;
- }
+ // Note: we always query whether a field is in a list, as the app
+ // might define blacklisted APIs (which won't be used at runtime).
std::string name = HiddenApi::GetApiFieldName(resolver->GetDexFile(), field_id);
if (hidden_api_.IsInRestrictionList(name)) {
field_locations_[name].push_back(ref);
diff --git a/tools/veridex/precise_hidden_api_finder.cc b/tools/veridex/precise_hidden_api_finder.cc
index 2092af3..4ae5769 100644
--- a/tools/veridex/precise_hidden_api_finder.cc
+++ b/tools/veridex/precise_hidden_api_finder.cc
@@ -63,6 +63,7 @@
void PreciseHiddenApiFinder::Dump(std::ostream& os, HiddenApiStats* stats) {
static const char* kPrefix = " ";
+ std::map<std::string, std::vector<MethodReference>> uses;
for (auto kinds : { field_uses_, method_uses_ }) {
for (auto it : kinds) {
MethodReference ref = it.first;
@@ -74,19 +75,26 @@
std::string name(info.second.ToString());
std::string full_name = cls + "->" + name;
HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(full_name);
- stats->api_counts[api_list]++;
if (api_list != HiddenApiAccessFlags::kWhitelist) {
- ++stats->reflection_count;
- os << "#" << ++stats->count << ": Reflection " << api_list << " " << full_name
- << " use:";
- os << std::endl;
- os << kPrefix << HiddenApi::GetApiMethodName(ref) << std::endl;
- os << std::endl;
+ uses[full_name].push_back(ref);
}
}
}
}
}
+
+ for (auto it : uses) {
+ ++stats->reflection_count;
+ const std::string& full_name = it.first;
+ HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(full_name);
+ stats->api_counts[api_list]++;
+ os << "#" << ++stats->count << ": Reflection " << api_list << " " << full_name << " use(s):";
+ os << std::endl;
+ for (const MethodReference& ref : it.second) {
+ os << kPrefix << HiddenApi::GetApiMethodName(ref) << std::endl;
+ }
+ os << std::endl;
+ }
}
} // namespace art
diff --git a/tools/veridex/resolver.h b/tools/veridex/resolver.h
index 52b15fe..65b2961 100644
--- a/tools/veridex/resolver.h
+++ b/tools/veridex/resolver.h
@@ -79,6 +79,10 @@
return dex_file_;
}
+ const DexFile& GetDexFileOf(const VeriClass& kls) {
+ return GetResolverOf(kls)->dex_file_;
+ }
+
private:
// Return the resolver where `kls` is from.
VeridexResolver* GetResolverOf(const VeriClass& kls) const;