ART: Refactor JVMTI run tests
In preparation for code deduplication with CTS.
Bug: 32072923
Test: m
Change-Id: Ibbe005c94252bd29eae7f88aad301b0b20ddb80d
(cherry picked from commit 3f46c96568bef650ba6d9ce6ac8835d30877f243)
diff --git a/test/901-hello-ti-agent/basics.cc b/test/901-hello-ti-agent/basics.cc
index cbd7686..00776ca 100644
--- a/test/901-hello-ti-agent/basics.cc
+++ b/test/901-hello-ti-agent/basics.cc
@@ -24,8 +24,9 @@
#include "base/macros.h"
#include "jvmti.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "jvmti_helper.h"
+#include "test_env.h"
namespace art {
namespace Test901HelloTi {
@@ -148,14 +149,14 @@
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jint iflag, jboolean val) {
jvmtiVerboseFlag flag = static_cast<jvmtiVerboseFlag>(iflag);
jvmtiError result = jvmti_env->SetVerboseFlag(flag, val);
- JvmtiErrorToException(env, result);
+ JvmtiErrorToException(env, jvmti_env, result);
}
extern "C" JNIEXPORT jboolean JNICALL Java_Main_checkLivePhase(
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
jvmtiPhase current_phase;
jvmtiError phase_result = jvmti_env->GetPhase(¤t_phase);
- if (JvmtiErrorToException(env, phase_result)) {
+ if (JvmtiErrorToException(env, jvmti_env, phase_result)) {
return JNI_FALSE;
}
return (current_phase == JVMTI_PHASE_LIVE) ? JNI_TRUE : JNI_FALSE;
diff --git a/test/903-hello-tagging/tagging.cc b/test/903-hello-tagging/tagging.cc
index b85ed48..7f079a2 100644
--- a/test/903-hello-tagging/tagging.cc
+++ b/test/903-hello-tagging/tagging.cc
@@ -26,36 +26,25 @@
#include "art_method-inl.h"
#include "base/logging.h"
#include "jvmti.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
#include "utils.h"
+// Test infrastructure
+#include "jvmti_helper.h"
+#include "test_env.h"
+
namespace art {
namespace Test903HelloTagging {
-extern "C" JNIEXPORT void JNICALL Java_Main_setTag(JNIEnv* env ATTRIBUTE_UNUSED,
- jclass,
- jobject obj,
- jlong tag) {
+extern "C" JNIEXPORT void JNICALL Java_Main_setTag(JNIEnv* env, jclass, jobject obj, jlong tag) {
jvmtiError ret = jvmti_env->SetTag(obj, tag);
- if (ret != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(ret, &err);
- printf("Error setting tag: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
- }
+ JvmtiErrorToException(env, jvmti_env, ret);
}
-extern "C" JNIEXPORT jlong JNICALL Java_Main_getTag(JNIEnv* env ATTRIBUTE_UNUSED,
- jclass,
- jobject obj) {
+extern "C" JNIEXPORT jlong JNICALL Java_Main_getTag(JNIEnv* env, jclass, jobject obj) {
jlong tag = 0;
jvmtiError ret = jvmti_env->GetTag(obj, &tag);
- if (ret != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(ret, &err);
- printf("Error getting tag: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
+ return 0;
}
return tag;
}
@@ -86,11 +75,7 @@
&result_count,
result_object_array_ptr,
result_tag_array_ptr);
- if (ret != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(ret, &err);
- printf("Failure running GetLoadedClasses: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
return nullptr;
}
@@ -197,4 +182,3 @@
} // namespace Test903HelloTagging
} // namespace art
-
diff --git a/test/904-object-allocation/tracking.cc b/test/904-object-allocation/tracking.cc
index cc6f681..303f954 100644
--- a/test/904-object-allocation/tracking.cc
+++ b/test/904-object-allocation/tracking.cc
@@ -24,10 +24,12 @@
#include "jvmti.h"
#include "ScopedLocalRef.h"
#include "ScopedUtfChars.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
#include "utils.h"
+// Test infrastructure
+#include "jvmti_helper.h"
+#include "test_env.h"
+
namespace art {
namespace Test904ObjectAllocation {
@@ -57,21 +59,16 @@
}
extern "C" JNIEXPORT void JNICALL Java_Main_setupObjectAllocCallback(
- JNIEnv* env ATTRIBUTE_UNUSED, jclass klass ATTRIBUTE_UNUSED, jboolean enable) {
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jboolean enable) {
jvmtiEventCallbacks callbacks;
memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
callbacks.VMObjectAlloc = enable ? ObjectAllocated : nullptr;
jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
- if (ret != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(ret, &err);
- printf("Error setting callbacks: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
- }
+ JvmtiErrorToException(env, jvmti_env, ret);
}
-extern "C" JNIEXPORT void JNICALL Java_Main_enableAllocationTracking(JNIEnv* env ATTRIBUTE_UNUSED,
+extern "C" JNIEXPORT void JNICALL Java_Main_enableAllocationTracking(JNIEnv* env,
jclass,
jthread thread,
jboolean enable) {
@@ -79,14 +76,8 @@
enable ? JVMTI_ENABLE : JVMTI_DISABLE,
JVMTI_EVENT_VM_OBJECT_ALLOC,
thread);
- if (ret != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(ret, &err);
- printf("Error enabling/disabling allocation tracking: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
- }
+ JvmtiErrorToException(env, jvmti_env, ret);
}
} // namespace Test904ObjectAllocation
} // namespace art
-
diff --git a/test/905-object-free/tracking_free.cc b/test/905-object-free/tracking_free.cc
index c489309..68ce38d 100644
--- a/test/905-object-free/tracking_free.cc
+++ b/test/905-object-free/tracking_free.cc
@@ -24,10 +24,12 @@
#include "jvmti.h"
#include "ScopedLocalRef.h"
#include "ScopedUtfChars.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
#include "utils.h"
+// Test infrastructure
+#include "jvmti_helper.h"
+#include "test_env.h"
+
namespace art {
namespace Test905ObjectFree {
@@ -46,52 +48,39 @@
collected_tags2.push_back(tag);
}
-static void setupObjectFreeCallback(jvmtiEnv* env, jvmtiEventObjectFree callback) {
+static void setupObjectFreeCallback(JNIEnv* env, jvmtiEnv* jenv, jvmtiEventObjectFree callback) {
jvmtiEventCallbacks callbacks;
memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
callbacks.ObjectFree = callback;
- jvmtiError ret = env->SetEventCallbacks(&callbacks, sizeof(callbacks));
- if (ret != JVMTI_ERROR_NONE) {
- char* err;
- env->GetErrorName(ret, &err);
- printf("Error setting callbacks: %s\n", err);
- env->Deallocate(reinterpret_cast<unsigned char*>(err));
- }
+ jvmtiError ret = jenv->SetEventCallbacks(&callbacks, sizeof(callbacks));
+ JvmtiErrorToException(env, jenv, ret);
}
extern "C" JNIEXPORT void JNICALL Java_Main_setupObjectFreeCallback(
JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
- setupObjectFreeCallback(jvmti_env, ObjectFree1);
+ setupObjectFreeCallback(env, jvmti_env, ObjectFree1);
JavaVM* jvm = nullptr;
env->GetJavaVM(&jvm);
CHECK_EQ(jvm->GetEnv(reinterpret_cast<void**>(&jvmti_env2), JVMTI_VERSION_1_2), 0);
SetAllCapabilities(jvmti_env2);
- setupObjectFreeCallback(jvmti_env2, ObjectFree2);
+ setupObjectFreeCallback(env, jvmti_env2, ObjectFree2);
}
-extern "C" JNIEXPORT void JNICALL Java_Main_enableFreeTracking(JNIEnv* env ATTRIBUTE_UNUSED,
+extern "C" JNIEXPORT void JNICALL Java_Main_enableFreeTracking(JNIEnv* env,
jclass klass ATTRIBUTE_UNUSED,
jboolean enable) {
jvmtiError ret = jvmti_env->SetEventNotificationMode(
enable ? JVMTI_ENABLE : JVMTI_DISABLE,
JVMTI_EVENT_OBJECT_FREE,
nullptr);
- if (ret != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(ret, &err);
- printf("Error enabling/disabling object-free callbacks: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
+ return;
}
ret = jvmti_env2->SetEventNotificationMode(
enable ? JVMTI_ENABLE : JVMTI_DISABLE,
JVMTI_EVENT_OBJECT_FREE,
nullptr);
- if (ret != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env2->GetErrorName(ret, &err);
- printf("Error enabling/disabling object-free callbacks: %s\n", err);
- jvmti_env2->Deallocate(reinterpret_cast<unsigned char*>(err));
- }
+ JvmtiErrorToException(env, jvmti_env, ret);
}
extern "C" JNIEXPORT jlongArray JNICALL Java_Main_getCollectedTags(JNIEnv* env,
@@ -114,7 +103,7 @@
jobject obj,
jlong tag) {
jvmtiError ret = jvmti_env2->SetTag(obj, tag);
- JvmtiErrorToException(env, ret);
+ JvmtiErrorToException(env, jvmti_env, ret);
}
} // namespace Test905ObjectFree
diff --git a/test/906-iterate-heap/iterate_heap.cc b/test/906-iterate-heap/iterate_heap.cc
index f2532de..74cb1e9 100644
--- a/test/906-iterate-heap/iterate_heap.cc
+++ b/test/906-iterate-heap/iterate_heap.cc
@@ -28,10 +28,12 @@
#include "jni.h"
#include "jvmti.h"
#include "ScopedPrimitiveArray.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
#include "utf.h"
+// Test infrastructure
+#include "jvmti_helper.h"
+#include "test_env.h"
+
namespace art {
namespace Test906IterateHeap {
@@ -52,7 +54,7 @@
return config->Handle(class_tag, size, tag_ptr, length);
}
-static bool Run(jint heap_filter, jclass klass_filter, IterationConfig* config) {
+static bool Run(JNIEnv* env, jint heap_filter, jclass klass_filter, IterationConfig* config) {
jvmtiHeapCallbacks callbacks;
memset(&callbacks, 0, sizeof(jvmtiHeapCallbacks));
callbacks.heap_iteration_callback = HeapIterationCallback;
@@ -61,17 +63,13 @@
klass_filter,
&callbacks,
config);
- if (ret != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(ret, &err);
- printf("Failure running IterateThroughHeap: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
return false;
}
return true;
}
-extern "C" JNIEXPORT jint JNICALL Java_Main_iterateThroughHeapCount(JNIEnv* env ATTRIBUTE_UNUSED,
+extern "C" JNIEXPORT jint JNICALL Java_Main_iterateThroughHeapCount(JNIEnv* env,
jclass klass ATTRIBUTE_UNUSED,
jint heap_filter,
jclass klass_filter,
@@ -99,7 +97,7 @@
};
CountIterationConfig config(0, stop_after);
- Run(heap_filter, klass_filter, &config);
+ Run(env, heap_filter, klass_filter, &config);
if (config.counter > config.stop_after) {
printf("Error: more objects visited than signaled.");
@@ -135,7 +133,7 @@
};
DataIterationConfig config;
- if (!Run(heap_filter, klass_filter, &config)) {
+ if (!Run(env, heap_filter, klass_filter, &config)) {
return -1;
}
@@ -154,7 +152,7 @@
return static_cast<jint>(config.class_tags_.size());
}
-extern "C" JNIEXPORT void JNICALL Java_Main_iterateThroughHeapAdd(JNIEnv* env ATTRIBUTE_UNUSED,
+extern "C" JNIEXPORT void JNICALL Java_Main_iterateThroughHeapAdd(JNIEnv* env,
jclass klass ATTRIBUTE_UNUSED,
jint heap_filter,
jclass klass_filter) {
@@ -175,7 +173,7 @@
};
AddIterationConfig config;
- Run(heap_filter, klass_filter, &config);
+ Run(env, heap_filter, klass_filter, &config);
}
extern "C" JNIEXPORT jstring JNICALL Java_Main_iterateThroughHeapString(
@@ -228,7 +226,7 @@
FindStringCallbacks fsc(tag);
jvmtiError ret = jvmti_env->IterateThroughHeap(0, nullptr, &callbacks, &fsc);
- if (JvmtiErrorToException(env, ret)) {
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
return nullptr;
}
return env->NewStringUTF(fsc.data.c_str());
@@ -316,7 +314,7 @@
FindArrayCallbacks fac(tag);
jvmtiError ret = jvmti_env->IterateThroughHeap(0, nullptr, &callbacks, &fac);
- if (JvmtiErrorToException(env, ret)) {
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
return nullptr;
}
return env->NewStringUTF(fac.data.c_str());
@@ -403,7 +401,7 @@
FindFieldCallbacks ffc(tag);
jvmtiError ret = jvmti_env->IterateThroughHeap(0, nullptr, &callbacks, &ffc);
- if (JvmtiErrorToException(env, ret)) {
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
return nullptr;
}
return env->NewStringUTF(ffc.data.c_str());
diff --git a/test/907-get-loaded-classes/get_loaded_classes.cc b/test/907-get-loaded-classes/get_loaded_classes.cc
index 48ce2e2..1b973bf 100644
--- a/test/907-get-loaded-classes/get_loaded_classes.cc
+++ b/test/907-get-loaded-classes/get_loaded_classes.cc
@@ -25,8 +25,9 @@
#include "ScopedLocalRef.h"
#include "ScopedUtfChars.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "jni_helper.h"
+#include "test_env.h"
namespace art {
namespace Test907GetLoadedClasses {
diff --git a/test/908-gc-start-finish/gc_callbacks.cc b/test/908-gc-start-finish/gc_callbacks.cc
index 45148f8..4b9a23c 100644
--- a/test/908-gc-start-finish/gc_callbacks.cc
+++ b/test/908-gc-start-finish/gc_callbacks.cc
@@ -20,8 +20,10 @@
#include "base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+
+// Test infrastructure
+#include "jvmti_helper.h"
+#include "test_env.h"
namespace art {
namespace Test908GcStartFinish {
@@ -45,7 +47,7 @@
callbacks.GarbageCollectionStart = GarbageCollectionStart;
jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
- JvmtiErrorToException(env, ret);
+ JvmtiErrorToException(env, jvmti_env, ret);
}
extern "C" JNIEXPORT void JNICALL Java_Main_enableGcTracking(JNIEnv* env,
@@ -55,14 +57,14 @@
enable ? JVMTI_ENABLE : JVMTI_DISABLE,
JVMTI_EVENT_GARBAGE_COLLECTION_START,
nullptr);
- if (JvmtiErrorToException(env, ret)) {
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
return;
}
ret = jvmti_env->SetEventNotificationMode(
enable ? JVMTI_ENABLE : JVMTI_DISABLE,
JVMTI_EVENT_GARBAGE_COLLECTION_FINISH,
nullptr);
- if (JvmtiErrorToException(env, ret)) {
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
return;
}
}
diff --git a/test/910-methods/methods.cc b/test/910-methods/methods.cc
index fdc4cdb..429076c 100644
--- a/test/910-methods/methods.cc
+++ b/test/910-methods/methods.cc
@@ -21,8 +21,10 @@
#include "jvmti.h"
#include "ScopedLocalRef.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "jni_helper.h"
+#include "jvmti_helper.h"
+#include "test_env.h"
namespace art {
namespace Test910Methods {
@@ -35,11 +37,7 @@
char* sig;
char* gen;
jvmtiError result = jvmti_env->GetMethodName(id, &name, &sig, &gen);
- if (result != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(result, &err);
- printf("Failure running GetMethodName: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
@@ -67,11 +65,7 @@
// Also run GetMethodName with all parameter pointers null to check for segfaults.
jvmtiError result2 = jvmti_env->GetMethodName(id, nullptr, nullptr, nullptr);
- if (result2 != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(result2, &err);
- printf("Failure running GetMethodName(null, null, null): %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ if (JvmtiErrorToException(env, jvmti_env, result2)) {
return nullptr;
}
@@ -84,11 +78,7 @@
jclass declaring_class;
jvmtiError result = jvmti_env->GetMethodDeclaringClass(id, &declaring_class);
- if (result != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(result, &err);
- printf("Failure running GetMethodDeclaringClass: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
@@ -101,11 +91,7 @@
jint modifiers;
jvmtiError result = jvmti_env->GetMethodModifiers(id, &modifiers);
- if (result != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(result, &err);
- printf("Failure running GetMethodModifiers: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return 0;
}
@@ -118,7 +104,7 @@
jint max_locals;
jvmtiError result = jvmti_env->GetMaxLocals(id, &max_locals);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return -1;
}
@@ -131,7 +117,7 @@
jint arguments;
jvmtiError result = jvmti_env->GetArgumentsSize(id, &arguments);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return -1;
}
@@ -145,7 +131,7 @@
jlong start;
jlong end;
jvmtiError result = jvmti_env->GetMethodLocation(id, &start, &end);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return -1;
}
@@ -159,7 +145,7 @@
jlong start;
jlong end;
jvmtiError result = jvmti_env->GetMethodLocation(id, &start, &end);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return -1;
}
@@ -172,7 +158,7 @@
jboolean is_native;
jvmtiError result = jvmti_env->IsMethodNative(id, &is_native);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return JNI_FALSE;
}
@@ -185,7 +171,7 @@
jboolean is_obsolete;
jvmtiError result = jvmti_env->IsMethodObsolete(id, &is_obsolete);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return JNI_FALSE;
}
@@ -198,7 +184,7 @@
jboolean is_synthetic;
jvmtiError result = jvmti_env->IsMethodSynthetic(id, &is_synthetic);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return JNI_FALSE;
}
diff --git a/test/911-get-stack-trace/stack_trace.cc b/test/911-get-stack-trace/stack_trace.cc
index 5a3a311..49cbb7e 100644
--- a/test/911-get-stack-trace/stack_trace.cc
+++ b/test/911-get-stack-trace/stack_trace.cc
@@ -26,8 +26,12 @@
#include "jni.h"
#include "jvmti.h"
#include "ScopedLocalRef.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+
+// Test infrastructure
+#include "jni_binder.h"
+#include "jni_helper.h"
+#include "jvmti_helper.h"
+#include "test_env.h"
namespace art {
namespace Test911GetStackTrace {
@@ -68,7 +72,7 @@
char* gen;
{
jvmtiError result2 = jvmti_env->GetMethodName(frames[method_index].method, &name, &sig, &gen);
- if (JvmtiErrorToException(env, result2)) {
+ if (JvmtiErrorToException(env, jvmti_env, result2)) {
return nullptr;
}
}
@@ -83,10 +87,7 @@
// Accept absent info and native method errors.
if (line_result != JVMTI_ERROR_ABSENT_INFORMATION &&
line_result != JVMTI_ERROR_NATIVE_METHOD) {
- char* err;
- jvmti_env->GetErrorName(line_result, &err);
- printf("Failure running GetLineNumberTable: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ JvmtiErrorToException(env, jvmti_env, line_result);
return nullptr;
}
line_number_table = nullptr;
@@ -139,7 +140,7 @@
jint count;
{
jvmtiError result = jvmti_env->GetStackTrace(thread, start, max, frames.get(), &count);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
}
@@ -153,7 +154,7 @@
jvmtiStackInfo* stack_infos;
{
jvmtiError result = jvmti_env->GetAllStackTraces(max, &stack_infos, &thread_count);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
}
@@ -189,7 +190,7 @@
threads.get(),
max,
&stack_infos);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
}
@@ -215,7 +216,7 @@
JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thread) {
jint count;
jvmtiError result = jvmti_env->GetFrameCount(thread, &count);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return -1;
}
return count;
@@ -227,7 +228,7 @@
jlocation location;
jvmtiError result = jvmti_env->GetFrameLocation(thread, depth, &method, &location);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
@@ -237,12 +238,12 @@
{
jclass decl_class;
jvmtiError class_result = jvmti_env->GetMethodDeclaringClass(method, &decl_class);
- if (JvmtiErrorToException(env, class_result)) {
+ if (JvmtiErrorToException(env, jvmti_env, class_result)) {
return nullptr;
}
jint modifiers;
jvmtiError mod_result = jvmti_env->GetMethodModifiers(method, &modifiers);
- if (JvmtiErrorToException(env, mod_result)) {
+ if (JvmtiErrorToException(env, jvmti_env, mod_result)) {
return nullptr;
}
constexpr jint kStatic = 0x8;
diff --git a/test/912-classes/classes.cc b/test/912-classes/classes.cc
index 5bd34f6..4d84e39 100644
--- a/test/912-classes/classes.cc
+++ b/test/912-classes/classes.cc
@@ -27,8 +27,10 @@
#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "jni_helper.h"
+#include "jvmti_helper.h"
+#include "test_env.h"
namespace art {
namespace Test912Classes {
@@ -233,7 +235,7 @@
jint count = 0;
jclass* classes = nullptr;
jvmtiError result = jvmti_env->GetClassLoaderClasses(jclassloader, &count, &classes);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
@@ -251,7 +253,7 @@
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) {
jint major, minor;
jvmtiError result = jvmti_env->GetClassVersionNumbers(klass, &minor, &major);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
@@ -270,7 +272,7 @@
jvmtiError result = jenv->GetClassSignature(klass, &name, nullptr);
if (result != JVMTI_ERROR_NONE) {
if (jni_env != nullptr) {
- JvmtiErrorToException(jni_env, result);
+ JvmtiErrorToException(jni_env, jenv, result);
} else {
printf("Failed to get class signature.\n");
}
@@ -291,13 +293,13 @@
jvmtiError ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
JVMTI_EVENT_CLASS_LOAD,
nullptr);
- if (JvmtiErrorToException(env, ret)) {
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
return;
}
ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
JVMTI_EVENT_CLASS_PREPARE,
nullptr);
- JvmtiErrorToException(env, ret);
+ JvmtiErrorToException(env, jvmti_env, ret);
return;
}
@@ -306,20 +308,20 @@
callbacks.ClassLoad = class_load;
callbacks.ClassPrepare = class_prepare;
jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
- if (JvmtiErrorToException(env, ret)) {
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
return;
}
ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
JVMTI_EVENT_CLASS_LOAD,
nullptr);
- if (JvmtiErrorToException(env, ret)) {
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
return;
}
ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
JVMTI_EVENT_CLASS_PREPARE,
nullptr);
- JvmtiErrorToException(env, ret);
+ JvmtiErrorToException(env, jvmti_env, ret);
}
class ClassLoadPreparePrinter {
@@ -364,7 +366,7 @@
jvmtiError result = jenv->GetThreadInfo(thread, &info);
if (result != JVMTI_ERROR_NONE) {
if (jni_env != nullptr) {
- JvmtiErrorToException(jni_env, result);
+ JvmtiErrorToException(jni_env, jenv, result);
} else {
printf("Failed to get thread name.\n");
}
diff --git a/test/913-heaps/heaps.cc b/test/913-heaps/heaps.cc
index 66fc7be..999467f 100644
--- a/test/913-heaps/heaps.cc
+++ b/test/913-heaps/heaps.cc
@@ -34,8 +34,10 @@
#include "thread-inl.h"
#include "thread_list.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "jni_helper.h"
+#include "jvmti_helper.h"
+#include "test_env.h"
namespace art {
namespace Test913Heaps {
@@ -550,7 +552,7 @@
FindStringCallbacks fsc;
jvmtiError ret = jvmti_env->FollowReferences(0, nullptr, initial_object, &callbacks, &fsc);
- if (JvmtiErrorToException(env, ret)) {
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
return nullptr;
}
@@ -648,7 +650,7 @@
FindArrayCallbacks fac;
jvmtiError ret = jvmti_env->FollowReferences(0, nullptr, initial_object, &callbacks, &fac);
- if (JvmtiErrorToException(env, ret)) {
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
return nullptr;
}
return env->NewStringUTF(fac.data.c_str());
@@ -738,7 +740,7 @@
FindFieldCallbacks ffc;
jvmtiError ret = jvmti_env->FollowReferences(0, nullptr, initial_object, &callbacks, &ffc);
- if (JvmtiErrorToException(env, ret)) {
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
return nullptr;
}
return env->NewStringUTF(ffc.data.c_str());
diff --git a/test/918-fields/fields.cc b/test/918-fields/fields.cc
index c659126..0c019e3 100644
--- a/test/918-fields/fields.cc
+++ b/test/918-fields/fields.cc
@@ -21,8 +21,9 @@
#include "jvmti.h"
#include "ScopedLocalRef.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "jni_helper.h"
+#include "test_env.h"
namespace art {
namespace Test918Fields {
diff --git a/test/920-objects/objects.cc b/test/920-objects/objects.cc
index ad1431e..1dfb516 100644
--- a/test/920-objects/objects.cc
+++ b/test/920-objects/objects.cc
@@ -21,8 +21,8 @@
#include "jvmti.h"
#include "ScopedLocalRef.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "test_env.h"
namespace art {
namespace Test920Objects {
diff --git a/test/922-properties/properties.cc b/test/922-properties/properties.cc
index 3fd274e..948da6a 100644
--- a/test/922-properties/properties.cc
+++ b/test/922-properties/properties.cc
@@ -21,8 +21,10 @@
#include "jvmti.h"
#include "ScopedUtfChars.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "jni_helper.h"
+#include "jvmti_helper.h"
+#include "test_env.h"
namespace art {
namespace Test922Properties {
@@ -32,7 +34,7 @@
jint count;
char** properties;
jvmtiError result = jvmti_env->GetSystemProperties(&count, &properties);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
@@ -61,7 +63,7 @@
char* value = nullptr;
jvmtiError result = jvmti_env->GetSystemProperty(string.c_str(), &value);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
@@ -84,7 +86,7 @@
}
jvmtiError result = jvmti_env->SetSystemProperty(key_string.c_str(), value_string.c_str());
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return;
}
}
diff --git a/test/923-monitors/monitors.cc b/test/923-monitors/monitors.cc
index 131fc6a..60d5b5a 100644
--- a/test/923-monitors/monitors.cc
+++ b/test/923-monitors/monitors.cc
@@ -21,8 +21,9 @@
#include "jvmti.h"
#include "ScopedUtfChars.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "jvmti_helper.h"
+#include "test_env.h"
namespace art {
namespace Test923Monitors {
@@ -40,7 +41,7 @@
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
jrawMonitorID id;
jvmtiError result = jvmti_env->CreateRawMonitor("dummy", &id);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return 0;
}
return MonitorToLong(id);
@@ -49,37 +50,37 @@
extern "C" JNIEXPORT void JNICALL Java_Main_destroyRawMonitor(
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jlong l) {
jvmtiError result = jvmti_env->DestroyRawMonitor(LongToMonitor(l));
- JvmtiErrorToException(env, result);
+ JvmtiErrorToException(env, jvmti_env, result);
}
extern "C" JNIEXPORT void JNICALL Java_Main_rawMonitorEnter(
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jlong l) {
jvmtiError result = jvmti_env->RawMonitorEnter(LongToMonitor(l));
- JvmtiErrorToException(env, result);
+ JvmtiErrorToException(env, jvmti_env, result);
}
extern "C" JNIEXPORT void JNICALL Java_Main_rawMonitorExit(
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jlong l) {
jvmtiError result = jvmti_env->RawMonitorExit(LongToMonitor(l));
- JvmtiErrorToException(env, result);
+ JvmtiErrorToException(env, jvmti_env, result);
}
extern "C" JNIEXPORT void JNICALL Java_Main_rawMonitorWait(
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jlong l, jlong millis) {
jvmtiError result = jvmti_env->RawMonitorWait(LongToMonitor(l), millis);
- JvmtiErrorToException(env, result);
+ JvmtiErrorToException(env, jvmti_env, result);
}
extern "C" JNIEXPORT void JNICALL Java_Main_rawMonitorNotify(
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jlong l) {
jvmtiError result = jvmti_env->RawMonitorNotify(LongToMonitor(l));
- JvmtiErrorToException(env, result);
+ JvmtiErrorToException(env, jvmti_env, result);
}
extern "C" JNIEXPORT void JNICALL Java_Main_rawMonitorNotifyAll(
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jlong l) {
jvmtiError result = jvmti_env->RawMonitorNotifyAll(LongToMonitor(l));
- JvmtiErrorToException(env, result);
+ JvmtiErrorToException(env, jvmti_env, result);
}
} // namespace Test923Monitors
diff --git a/test/924-threads/threads.cc b/test/924-threads/threads.cc
index 14ea5af..bb040bd 100644
--- a/test/924-threads/threads.cc
+++ b/test/924-threads/threads.cc
@@ -23,8 +23,10 @@
#include "jvmti.h"
#include "ScopedLocalRef.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "jni_helper.h"
+#include "jvmti_helper.h"
+#include "test_env.h"
namespace art {
namespace Test924Threads {
@@ -36,7 +38,7 @@
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
jthread thread = nullptr;
jvmtiError result = jvmti_env->GetCurrentThread(&thread);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
return thread;
@@ -48,7 +50,7 @@
memset(&info, 0, sizeof(jvmtiThreadInfo));
jvmtiError result = jvmti_env->GetThreadInfo(thread, &info);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
@@ -94,7 +96,7 @@
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jthread thread) {
jint state;
jvmtiError result = jvmti_env->GetThreadState(thread, &state);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return 0;
}
return state;
@@ -106,7 +108,7 @@
jthread* threads;
jvmtiError result = jvmti_env->GetAllThreads(&thread_count, &threads);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
@@ -124,7 +126,7 @@
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jthread thread) {
void* tls;
jvmtiError result = jvmti_env->GetThreadLocalStorage(thread, &tls);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return 0;
}
return static_cast<jlong>(reinterpret_cast<uintptr_t>(tls));
@@ -134,7 +136,7 @@
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jthread thread, jlong val) {
const void* tls = reinterpret_cast<void*>(static_cast<uintptr_t>(val));
jvmtiError result = jvmti_env->SetThreadLocalStorage(thread, tls);
- JvmtiErrorToException(env, result);
+ JvmtiErrorToException(env, jvmti_env, result);
}
static void JNICALL ThreadEvent(jvmtiEnv* jvmti_env,
@@ -172,13 +174,13 @@
jvmtiError ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
JVMTI_EVENT_THREAD_START,
nullptr);
- if (JvmtiErrorToException(env, ret)) {
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
return;
}
ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
JVMTI_EVENT_THREAD_END,
nullptr);
- JvmtiErrorToException(env, ret);
+ JvmtiErrorToException(env, jvmti_env, ret);
return;
}
@@ -187,20 +189,20 @@
callbacks.ThreadStart = ThreadStart;
callbacks.ThreadEnd = ThreadEnd;
jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
- if (JvmtiErrorToException(env, ret)) {
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
return;
}
ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
JVMTI_EVENT_THREAD_START,
nullptr);
- if (JvmtiErrorToException(env, ret)) {
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
return;
}
ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
JVMTI_EVENT_THREAD_END,
nullptr);
- JvmtiErrorToException(env, ret);
+ JvmtiErrorToException(env, jvmti_env, ret);
}
} // namespace Test924Threads
diff --git a/test/925-threadgroups/threadgroups.cc b/test/925-threadgroups/threadgroups.cc
index 2feaab0..1cd93be 100644
--- a/test/925-threadgroups/threadgroups.cc
+++ b/test/925-threadgroups/threadgroups.cc
@@ -23,8 +23,10 @@
#include "jvmti.h"
#include "ScopedLocalRef.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "jni_helper.h"
+#include "jvmti_helper.h"
+#include "test_env.h"
namespace art {
namespace Test925ThreadGroups {
@@ -38,7 +40,7 @@
jthreadGroup* groups;
jint group_count;
jvmtiError result = jvmti_env->GetTopThreadGroups(&group_count, &groups);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
@@ -56,7 +58,7 @@
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jthreadGroup group) {
jvmtiThreadGroupInfo info;
jvmtiError result = jvmti_env->GetThreadGroupInfo(group, &info);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
@@ -96,7 +98,7 @@
&threads,
&threadgroup_count,
&groups);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
diff --git a/test/927-timers/timers.cc b/test/927-timers/timers.cc
index 7b1d5c3..a67f5b4 100644
--- a/test/927-timers/timers.cc
+++ b/test/927-timers/timers.cc
@@ -22,8 +22,10 @@
#include "jni.h"
#include "jvmti.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "jni_helper.h"
+#include "jvmti_helper.h"
+#include "test_env.h"
namespace art {
namespace Test926Timers {
@@ -32,7 +34,7 @@
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
jint count;
jvmtiError result = jvmti_env->GetAvailableProcessors(&count);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return -1;
}
return count;
@@ -42,7 +44,7 @@
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
jlong time;
jvmtiError result = jvmti_env->GetTime(&time);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return -1;
}
return time;
@@ -52,7 +54,7 @@
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
jvmtiTimerInfo info;
jvmtiError result = jvmti_env->GetTimerInfo(&info);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return nullptr;
}
diff --git a/test/928-jni-table/jni_table.cc b/test/928-jni-table/jni_table.cc
index b5c0efd..3f4a93e 100644
--- a/test/928-jni-table/jni_table.cc
+++ b/test/928-jni-table/jni_table.cc
@@ -22,8 +22,9 @@
#include "base/logging.h"
#include "base/macros.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "jvmti_helper.h"
+#include "test_env.h"
namespace art {
namespace Test927JNITable {
@@ -42,14 +43,14 @@
JNIEnv* env, jclass klass) {
// Get the current table, as the delegate.
jvmtiError getorig_result = jvmti_env->GetJNIFunctionTable(&gOriginalEnv);
- if (JvmtiErrorToException(env, getorig_result)) {
+ if (JvmtiErrorToException(env, jvmti_env, getorig_result)) {
return;
}
// Get the current table, as the override we'll install.
JNINativeInterface* env_override;
jvmtiError getoverride_result = jvmti_env->GetJNIFunctionTable(&env_override);
- if (JvmtiErrorToException(env, getoverride_result)) {
+ if (JvmtiErrorToException(env, jvmti_env, getoverride_result)) {
return;
}
@@ -58,7 +59,7 @@
// Install the override.
jvmtiError setoverride_result = jvmti_env->SetJNIFunctionTable(env_override);
- if (JvmtiErrorToException(env, setoverride_result)) {
+ if (JvmtiErrorToException(env, jvmti_env, setoverride_result)) {
return;
}
@@ -68,7 +69,7 @@
// Install the "original." There is no real reset.
jvmtiError setoverride2_result = jvmti_env->SetJNIFunctionTable(gOriginalEnv);
- if (JvmtiErrorToException(env, setoverride2_result)) {
+ if (JvmtiErrorToException(env, jvmti_env, setoverride2_result)) {
return;
}
diff --git a/test/929-search/search.cc b/test/929-search/search.cc
index ad7a053..bed4dfe 100644
--- a/test/929-search/search.cc
+++ b/test/929-search/search.cc
@@ -23,8 +23,9 @@
#include "jvmti.h"
#include "ScopedUtfChars.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "jvmti_helper.h"
+#include "test_env.h"
namespace art {
namespace Test929Search {
@@ -36,7 +37,7 @@
return;
}
jvmtiError result = jvmti_env->AddToBootstrapClassLoaderSearch(utf.c_str());
- JvmtiErrorToException(env, result);
+ JvmtiErrorToException(env, jvmti_env, result);
}
extern "C" JNIEXPORT void JNICALL Java_Main_addToSystemClassLoader(
@@ -46,7 +47,7 @@
return;
}
jvmtiError result = jvmti_env->AddToSystemClassLoaderSearch(utf.c_str());
- JvmtiErrorToException(env, result);
+ JvmtiErrorToException(env, jvmti_env, result);
}
} // namespace Test929Search
diff --git a/test/931-agent-thread/agent_thread.cc b/test/931-agent-thread/agent_thread.cc
index 2e6bd46..3ec8793 100644
--- a/test/931-agent-thread/agent_thread.cc
+++ b/test/931-agent-thread/agent_thread.cc
@@ -27,8 +27,9 @@
#include "thread-inl.h"
#include "well_known_classes.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "jvmti_helper.h"
+#include "test_env.h"
namespace art {
namespace Test930AgentThread {
@@ -53,13 +54,13 @@
// This thread is not the main thread.
jthread this_thread;
jvmtiError this_thread_result = jenv->GetCurrentThread(&this_thread);
- CHECK(!JvmtiErrorToException(env, this_thread_result));
+ CHECK(!JvmtiErrorToException(env, jenv, this_thread_result));
CHECK(!env->IsSameObject(this_thread, data->main_thread));
// The thread is a daemon.
jvmtiThreadInfo info;
jvmtiError info_result = jenv->GetThreadInfo(this_thread, &info);
- CHECK(!JvmtiErrorToException(env, info_result));
+ CHECK(!JvmtiErrorToException(env, jenv, info_result));
CHECK(info.is_daemon);
// The thread has the requested priority.
@@ -70,7 +71,7 @@
jint thread_count;
jthread* threads;
jvmtiError threads_result = jenv->GetAllThreads(&thread_count, &threads);
- CHECK(!JvmtiErrorToException(env, threads_result));
+ CHECK(!JvmtiErrorToException(env, jenv, threads_result));
bool found = false;
for (jint i = 0; i != thread_count; ++i) {
if (env->IsSameObject(threads[i], this_thread)) {
@@ -111,7 +112,7 @@
jthread main_thread;
jvmtiError main_thread_result = jvmti_env->GetCurrentThread(&main_thread);
- if (JvmtiErrorToException(env, main_thread_result)) {
+ if (JvmtiErrorToException(env, jvmti_env, main_thread_result)) {
return;
}
@@ -121,7 +122,7 @@
data.priority = JVMTI_THREAD_MIN_PRIORITY;
jvmtiError result = jvmti_env->RunAgentThread(thread.get(), AgentMain, &data, data.priority);
- if (JvmtiErrorToException(env, result)) {
+ if (JvmtiErrorToException(env, jvmti_env, result)) {
return;
}
@@ -133,7 +134,7 @@
NanoSleep(1000 * 1000);
jint thread_state;
jvmtiError state_result = jvmti_env->GetThreadState(thread.get(), &thread_state);
- if (JvmtiErrorToException(env, state_result)) {
+ if (JvmtiErrorToException(env, jvmti_env, state_result)) {
return;
}
if (thread_state == 0 || // Was never alive.
diff --git a/test/933-misc-events/misc_events.cc b/test/933-misc-events/misc_events.cc
index 7043350..7b6c64d 100644
--- a/test/933-misc-events/misc_events.cc
+++ b/test/933-misc-events/misc_events.cc
@@ -23,8 +23,9 @@
#include "jni.h"
#include "jvmti.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "jvmti_helper.h"
+#include "test_env.h"
namespace art {
namespace Test933MiscEvents {
@@ -42,14 +43,14 @@
memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
callbacks.DataDumpRequest = DumpRequestCallback;
jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
- if (JvmtiErrorToException(env, ret)) {
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
return;
}
ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
JVMTI_EVENT_DATA_DUMP_REQUEST,
nullptr);
- if (JvmtiErrorToException(env, ret)) {
+ if (JvmtiErrorToException(env, jvmti_env, ret)) {
return;
}
@@ -65,7 +66,7 @@
}
ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_DATA_DUMP_REQUEST, nullptr);
- JvmtiErrorToException(env, ret);
+ JvmtiErrorToException(env, jvmti_env, ret);
}
} // namespace Test933MiscEvents
diff --git a/test/936-search-onload/search_onload.cc b/test/936-search-onload/search_onload.cc
index 3b19ca5..72987eb 100644
--- a/test/936-search-onload/search_onload.cc
+++ b/test/936-search-onload/search_onload.cc
@@ -25,8 +25,9 @@
#include "jvmti.h"
#include "ScopedUtfChars.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "jvmti_helper.h"
+#include "test_env.h"
namespace art {
namespace Test936SearchOnload {
diff --git a/test/944-transform-classloaders/classloader.cc b/test/944-transform-classloaders/classloader.cc
index 7cb3c08..f46763c 100644
--- a/test/944-transform-classloaders/classloader.cc
+++ b/test/944-transform-classloaders/classloader.cc
@@ -20,8 +20,8 @@
#include "mirror/class-inl.h"
#include "ScopedLocalRef.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "test_env.h"
namespace art {
namespace Test944TransformClassloaders {
diff --git a/test/945-obsolete-native/obsolete_native.cc b/test/945-obsolete-native/obsolete_native.cc
index 442836b..b9303dd 100644
--- a/test/945-obsolete-native/obsolete_native.cc
+++ b/test/945-obsolete-native/obsolete_native.cc
@@ -26,8 +26,10 @@
#include "jni.h"
#include "jvmti.h"
#include "ScopedLocalRef.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+
+// Test infrastructure
+#include "jni_binder.h"
+#include "test_env.h"
namespace art {
namespace Test945ObsoleteNative {
diff --git a/test/980-redefine-object/redefine_object.cc b/test/980-redefine-object/redefine_object.cc
index daae087..6c8c4bd 100644
--- a/test/980-redefine-object/redefine_object.cc
+++ b/test/980-redefine-object/redefine_object.cc
@@ -24,8 +24,10 @@
#include "jvmti.h"
#include "ScopedUtfChars.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "jni_binder.h"
+#include "jvmti_helper.h"
+#include "test_env.h"
namespace art {
namespace Test980RedefineObjects {
@@ -39,9 +41,11 @@
JNIEnv* env, jclass TestWatcherClass ATTRIBUTE_UNUSED, jobject constructed) {
char* sig = nullptr;
char* generic_sig = nullptr;
- if (JvmtiErrorToException(env, jvmti_env->GetClassSignature(env->GetObjectClass(constructed),
- &sig,
- &generic_sig))) {
+ if (JvmtiErrorToException(env,
+ jvmti_env,
+ jvmti_env->GetClassSignature(env->GetObjectClass(constructed),
+ &sig,
+ &generic_sig))) {
// Exception.
return;
}
diff --git a/test/983-source-transform-verify/source_transform.cc b/test/983-source-transform-verify/source_transform.cc
index e8b7e13..3ef3c7c 100644
--- a/test/983-source-transform-verify/source_transform.cc
+++ b/test/983-source-transform-verify/source_transform.cc
@@ -37,8 +37,9 @@
#include "thread-inl.h"
#include "thread_list.h"
-#include "ti-agent/common_helper.h"
-#include "ti-agent/common_load.h"
+// Test infrastructure
+#include "jvmti_helper.h"
+#include "test_env.h"
namespace art {
namespace Test983SourceTransformVerify {
diff --git a/test/Android.bp b/test/Android.bp
index ec40acf..2e8f5bb 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -249,6 +249,9 @@
"common/runtime_state.cc",
"ti-agent/common_load.cc",
"ti-agent/common_helper.cc",
+ "ti-agent/jni_binder.cc",
+ "ti-agent/jvmti_helper.cc",
+ "ti-agent/test_env.cc",
"901-hello-ti-agent/basics.cc",
"903-hello-tagging/tagging.cc",
"904-object-allocation/tracking.cc",
@@ -282,6 +285,7 @@
"libbase",
],
header_libs: ["libopenjdkjvmti_headers"],
+ include_dirs: ["art/test/ti-agent"],
}
art_cc_test_library {
diff --git a/test/ti-agent/common_helper.cc b/test/ti-agent/common_helper.cc
index 6316a9c..ab5dbcc 100644
--- a/test/ti-agent/common_helper.cc
+++ b/test/ti-agent/common_helper.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "ti-agent/common_helper.h"
+#include "common_helper.h"
#include <dlfcn.h>
#include <stdio.h>
@@ -27,44 +27,15 @@
#include "jni_internal.h"
#include "jvmti.h"
#include "scoped_thread_state_change-inl.h"
-#include "ScopedLocalRef.h"
#include "stack.h"
-#include "ti-agent/common_load.h"
#include "utils.h"
+#include "jni_binder.h"
+#include "jvmti_helper.h"
+#include "scoped_local_ref.h"
+#include "test_env.h"
+
namespace art {
-bool RuntimeIsJVM;
-
-bool IsJVM() {
- return RuntimeIsJVM;
-}
-
-void SetAllCapabilities(jvmtiEnv* env) {
- jvmtiCapabilities caps;
- env->GetPotentialCapabilities(&caps);
- env->AddCapabilities(&caps);
-}
-
-bool JvmtiErrorToException(JNIEnv* env, jvmtiError error) {
- if (error == JVMTI_ERROR_NONE) {
- return false;
- }
-
- ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
- if (rt_exception.get() == nullptr) {
- // CNFE should be pending.
- return true;
- }
-
- char* err;
- jvmti_env->GetErrorName(error, &err);
-
- env->ThrowNew(rt_exception.get(), err);
-
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
- return true;
-}
-
template <bool is_redefine>
static void throwCommonRedefinitionError(jvmtiEnv* jvmti,
@@ -303,7 +274,7 @@
JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
nullptr);
if (res != JVMTI_ERROR_NONE) {
- JvmtiErrorToException(env, res);
+ JvmtiErrorToException(env, jvmti_env, res);
}
}
@@ -412,140 +383,4 @@
} // namespace common_transform
-static void BindMethod(jvmtiEnv* jenv,
- JNIEnv* env,
- jclass klass,
- jmethodID method) {
- char* name;
- char* signature;
- jvmtiError name_result = jenv->GetMethodName(method, &name, &signature, nullptr);
- if (name_result != JVMTI_ERROR_NONE) {
- LOG(FATAL) << "Could not get methods";
- }
-
- std::string names[2];
- if (IsJVM()) {
- // TODO Get the JNI long name
- char* klass_name;
- jvmtiError klass_result = jenv->GetClassSignature(klass, &klass_name, nullptr);
- if (klass_result == JVMTI_ERROR_NONE) {
- std::string name_str(name);
- std::string klass_str(klass_name);
- names[0] = GetJniShortName(klass_str, name_str);
- jenv->Deallocate(reinterpret_cast<unsigned char*>(klass_name));
- } else {
- LOG(FATAL) << "Could not get class name!";
- }
- } else {
- ScopedObjectAccess soa(Thread::Current());
- ArtMethod* m = jni::DecodeArtMethod(method);
- names[0] = m->JniShortName();
- names[1] = m->JniLongName();
- }
- for (const std::string& mangled_name : names) {
- if (mangled_name == "") {
- continue;
- }
- void* sym = dlsym(RTLD_DEFAULT, mangled_name.c_str());
- if (sym == nullptr) {
- continue;
- }
-
- JNINativeMethod native_method;
- native_method.fnPtr = sym;
- native_method.name = name;
- native_method.signature = signature;
-
- env->RegisterNatives(klass, &native_method, 1);
-
- jenv->Deallocate(reinterpret_cast<unsigned char*>(name));
- jenv->Deallocate(reinterpret_cast<unsigned char*>(signature));
- return;
- }
-
- LOG(FATAL) << "Could not find " << names[0];
-}
-
-static jclass FindClassWithSystemClassLoader(JNIEnv* env, const char* class_name) {
- // Find the system classloader.
- ScopedLocalRef<jclass> cl_klass(env, env->FindClass("java/lang/ClassLoader"));
- if (cl_klass.get() == nullptr) {
- return nullptr;
- }
- jmethodID getsystemclassloader_method = env->GetStaticMethodID(cl_klass.get(),
- "getSystemClassLoader",
- "()Ljava/lang/ClassLoader;");
- if (getsystemclassloader_method == nullptr) {
- return nullptr;
- }
- ScopedLocalRef<jobject> cl(env, env->CallStaticObjectMethod(cl_klass.get(),
- getsystemclassloader_method));
- if (cl.get() == nullptr) {
- return nullptr;
- }
-
- // Create a String of the name.
- std::string descriptor = android::base::StringPrintf("L%s;", class_name);
- std::string dot_name = DescriptorToDot(descriptor.c_str());
- ScopedLocalRef<jstring> name_str(env, env->NewStringUTF(dot_name.c_str()));
-
- // Call Class.forName with it.
- ScopedLocalRef<jclass> c_klass(env, env->FindClass("java/lang/Class"));
- if (c_klass.get() == nullptr) {
- return nullptr;
- }
- jmethodID forname_method = env->GetStaticMethodID(
- c_klass.get(),
- "forName",
- "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
- if (forname_method == nullptr) {
- return nullptr;
- }
-
- return reinterpret_cast<jclass>(env->CallStaticObjectMethod(c_klass.get(),
- forname_method,
- name_str.get(),
- JNI_FALSE,
- cl.get()));
-}
-
-void BindFunctions(jvmtiEnv* jenv, JNIEnv* env, const char* class_name) {
- // Use JNI to load the class.
- ScopedLocalRef<jclass> klass(env, env->FindClass(class_name));
- if (klass.get() == nullptr) {
- // We may be called with the wrong classloader. Try explicitly using the system classloader.
- env->ExceptionClear();
- klass.reset(FindClassWithSystemClassLoader(env, class_name));
- if (klass.get() == nullptr) {
- LOG(FATAL) << "Could not load " << class_name;
- }
- }
- BindFunctionsOnClass(jenv, env, klass.get());
-}
-
-void BindFunctionsOnClass(jvmtiEnv* jenv, JNIEnv* env, jclass klass) {
- // Use JVMTI to get the methods.
- jint method_count;
- jmethodID* methods;
- jvmtiError methods_result = jenv->GetClassMethods(klass, &method_count, &methods);
- if (methods_result != JVMTI_ERROR_NONE) {
- LOG(FATAL) << "Could not get methods";
- }
-
- // Check each method.
- for (jint i = 0; i < method_count; ++i) {
- jint modifiers;
- jvmtiError mod_result = jenv->GetMethodModifiers(methods[i], &modifiers);
- if (mod_result != JVMTI_ERROR_NONE) {
- LOG(FATAL) << "Could not get methods";
- }
- constexpr jint kNative = static_cast<jint>(kAccNative);
- if ((modifiers & kNative) != 0) {
- BindMethod(jenv, env, klass, methods[i]);
- }
- }
-
- jenv->Deallocate(reinterpret_cast<unsigned char*>(methods));
-}
-
} // namespace art
diff --git a/test/ti-agent/common_helper.h b/test/ti-agent/common_helper.h
index f10356d..610019e 100644
--- a/test/ti-agent/common_helper.h
+++ b/test/ti-agent/common_helper.h
@@ -19,13 +19,11 @@
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
namespace art {
+
namespace common_redefine {
-
jint OnLoad(JavaVM* vm, char* options, void* reserved);
-
} // namespace common_redefine
namespace common_retransform {
@@ -36,53 +34,6 @@
jint OnLoad(JavaVM* vm, char* options, void* reserved);
} // namespace common_transform
-
-extern bool RuntimeIsJVM;
-
-bool IsJVM();
-
-template <typename T>
-static jobjectArray CreateObjectArray(JNIEnv* env,
- jint length,
- const char* component_type_descriptor,
- T src) {
- if (length < 0) {
- return nullptr;
- }
-
- ScopedLocalRef<jclass> obj_class(env, env->FindClass(component_type_descriptor));
- if (obj_class.get() == nullptr) {
- return nullptr;
- }
-
- ScopedLocalRef<jobjectArray> ret(env, env->NewObjectArray(length, obj_class.get(), nullptr));
- if (ret.get() == nullptr) {
- return nullptr;
- }
-
- for (jint i = 0; i < length; ++i) {
- jobject element = src(i);
- env->SetObjectArrayElement(ret.get(), static_cast<jint>(i), element);
- env->DeleteLocalRef(element);
- if (env->ExceptionCheck()) {
- return nullptr;
- }
- }
-
- return ret.release();
-}
-
-void SetAllCapabilities(jvmtiEnv* env);
-
-bool JvmtiErrorToException(JNIEnv* env, jvmtiError error);
-
-// Load the class through JNI. Inspect it, find all native methods. Construct the corresponding
-// mangled name, run dlsym and bind the method.
-//
-// This will abort on failure.
-void BindFunctions(jvmtiEnv* jvmti_env, JNIEnv* env, const char* class_name);
-void BindFunctionsOnClass(jvmtiEnv* jvmti_env, JNIEnv* env, jclass klass);
-
} // namespace art
#endif // ART_TEST_TI_AGENT_COMMON_HELPER_H_
diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc
index 303e824..c5d75c9 100644
--- a/test/ti-agent/common_load.cc
+++ b/test/ti-agent/common_load.cc
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-#include "common_load.h"
-
#include <jni.h>
#include <stdio.h>
-#include "art_method-inl.h"
#include "base/logging.h"
#include "base/macros.h"
#include "common_helper.h"
+#include "jni_binder.h"
+#include "jvmti_helper.h"
+#include "test_env.h"
#include "901-hello-ti-agent/basics.h"
#include "909-attach-agent/attach.h"
@@ -31,8 +31,6 @@
namespace art {
-jvmtiEnv* jvmti_env;
-
namespace {
using OnLoad = jint (*)(JavaVM* vm, char* options, void* reserved);
@@ -154,8 +152,8 @@
return true;
}
-static void SetIsJVM(char* options) {
- RuntimeIsJVM = strncmp(options, "jvm", 3) == 0;
+static void SetIsJVM(const char* options) {
+ SetJVM(strncmp(options, "jvm", 3) == 0);
}
static bool BindFunctionsAttached(JavaVM* vm, const char* class_name) {
diff --git a/test/ti-agent/jni_binder.cc b/test/ti-agent/jni_binder.cc
new file mode 100644
index 0000000..efc2af8
--- /dev/null
+++ b/test/ti-agent/jni_binder.cc
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni_binder.h"
+
+#include <dlfcn.h>
+#include <inttypes.h>
+#include <stdio.h>
+
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+
+#include "jvmti_helper.h"
+#include "scoped_local_ref.h"
+#include "scoped_utf_chars.h"
+
+namespace art {
+
+size_t CountModifiedUtf8Chars(const char* utf8, size_t byte_count) {
+ DCHECK_LE(byte_count, strlen(utf8));
+ size_t len = 0;
+ const char* end = utf8 + byte_count;
+ for (; utf8 < end; ++utf8) {
+ int ic = *utf8;
+ len++;
+ if (LIKELY((ic & 0x80) == 0)) {
+ // One-byte encoding.
+ continue;
+ }
+ // Two- or three-byte encoding.
+ utf8++;
+ if ((ic & 0x20) == 0) {
+ // Two-byte encoding.
+ continue;
+ }
+ utf8++;
+ if ((ic & 0x10) == 0) {
+ // Three-byte encoding.
+ continue;
+ }
+
+ // Four-byte encoding: needs to be converted into a surrogate
+ // pair.
+ utf8++;
+ len++;
+ }
+ return len;
+}
+
+static uint16_t GetTrailingUtf16Char(uint32_t maybe_pair) {
+ return static_cast<uint16_t>(maybe_pair >> 16);
+}
+
+static uint16_t GetLeadingUtf16Char(uint32_t maybe_pair) {
+ return static_cast<uint16_t>(maybe_pair & 0x0000FFFF);
+}
+
+static uint32_t GetUtf16FromUtf8(const char** utf8_data_in) {
+ const uint8_t one = *(*utf8_data_in)++;
+ if ((one & 0x80) == 0) {
+ // one-byte encoding
+ return one;
+ }
+
+ const uint8_t two = *(*utf8_data_in)++;
+ if ((one & 0x20) == 0) {
+ // two-byte encoding
+ return ((one & 0x1f) << 6) | (two & 0x3f);
+ }
+
+ const uint8_t three = *(*utf8_data_in)++;
+ if ((one & 0x10) == 0) {
+ return ((one & 0x0f) << 12) | ((two & 0x3f) << 6) | (three & 0x3f);
+ }
+
+ // Four byte encodings need special handling. We'll have
+ // to convert them into a surrogate pair.
+ const uint8_t four = *(*utf8_data_in)++;
+
+ // Since this is a 4 byte UTF-8 sequence, it will lie between
+ // U+10000 and U+1FFFFF.
+ //
+ // TODO: What do we do about values in (U+10FFFF, U+1FFFFF) ? The
+ // spec says they're invalid but nobody appears to check for them.
+ const uint32_t code_point = ((one & 0x0f) << 18) | ((two & 0x3f) << 12)
+ | ((three & 0x3f) << 6) | (four & 0x3f);
+
+ uint32_t surrogate_pair = 0;
+ // Step two: Write out the high (leading) surrogate to the bottom 16 bits
+ // of the of the 32 bit type.
+ surrogate_pair |= ((code_point >> 10) + 0xd7c0) & 0xffff;
+ // Step three : Write out the low (trailing) surrogate to the top 16 bits.
+ surrogate_pair |= ((code_point & 0x03ff) + 0xdc00) << 16;
+
+ return surrogate_pair;
+}
+
+static std::string MangleForJni(const std::string& s) {
+ std::string result;
+ size_t char_count = CountModifiedUtf8Chars(s.c_str(), s.length());
+ const char* cp = &s[0];
+ for (size_t i = 0; i < char_count; ++i) {
+ uint32_t ch = GetUtf16FromUtf8(&cp);
+ if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) {
+ result.push_back(ch);
+ } else if (ch == '.' || ch == '/') {
+ result += "_";
+ } else if (ch == '_') {
+ result += "_1";
+ } else if (ch == ';') {
+ result += "_2";
+ } else if (ch == '[') {
+ result += "_3";
+ } else {
+ const uint16_t leading = GetLeadingUtf16Char(ch);
+ const uint32_t trailing = GetTrailingUtf16Char(ch);
+
+ android::base::StringAppendF(&result, "_0%04x", leading);
+ if (trailing != 0) {
+ android::base::StringAppendF(&result, "_0%04x", trailing);
+ }
+ }
+ }
+ return result;
+}
+
+static std::string GetJniShortName(const std::string& class_descriptor, const std::string& method) {
+ // Remove the leading 'L' and trailing ';'...
+ std::string class_name(class_descriptor);
+ CHECK_EQ(class_name[0], 'L') << class_name;
+ CHECK_EQ(class_name[class_name.size() - 1], ';') << class_name;
+ class_name.erase(0, 1);
+ class_name.erase(class_name.size() - 1, 1);
+
+ std::string short_name;
+ short_name += "Java_";
+ short_name += MangleForJni(class_name);
+ short_name += "_";
+ short_name += MangleForJni(method);
+ return short_name;
+}
+
+static void BindMethod(jvmtiEnv* jvmti_env, JNIEnv* env, jclass klass, jmethodID method) {
+ std::string name;
+ std::string signature;
+ std::string mangled_names[2];
+ {
+ char* name_cstr;
+ char* sig_cstr;
+ jvmtiError name_result = jvmti_env->GetMethodName(method, &name_cstr, &sig_cstr, nullptr);
+ CheckJvmtiError(jvmti_env, name_result);
+ CHECK(name_cstr != nullptr);
+ CHECK(sig_cstr != nullptr);
+ name = name_cstr;
+ signature = sig_cstr;
+
+ char* klass_name;
+ jvmtiError klass_result = jvmti_env->GetClassSignature(klass, &klass_name, nullptr);
+ CheckJvmtiError(jvmti_env, klass_result);
+
+ mangled_names[0] = GetJniShortName(klass_name, name);
+ // TODO: Long JNI name.
+
+ CheckJvmtiError(jvmti_env, Deallocate(jvmti_env, name_cstr));
+ CheckJvmtiError(jvmti_env, Deallocate(jvmti_env, sig_cstr));
+ CheckJvmtiError(jvmti_env, Deallocate(jvmti_env, klass_name));
+ }
+
+ for (const std::string& mangled_name : mangled_names) {
+ if (mangled_name.empty()) {
+ continue;
+ }
+ void* sym = dlsym(RTLD_DEFAULT, mangled_name.c_str());
+ if (sym == nullptr) {
+ continue;
+ }
+
+ JNINativeMethod native_method;
+ native_method.fnPtr = sym;
+ native_method.name = name.c_str();
+ native_method.signature = signature.c_str();
+
+ env->RegisterNatives(klass, &native_method, 1);
+
+ return;
+ }
+
+ LOG(FATAL) << "Could not find " << mangled_names[0];
+}
+
+static std::string DescriptorToDot(const char* descriptor) {
+ size_t length = strlen(descriptor);
+ if (length > 1) {
+ if (descriptor[0] == 'L' && descriptor[length - 1] == ';') {
+ // Descriptors have the leading 'L' and trailing ';' stripped.
+ std::string result(descriptor + 1, length - 2);
+ std::replace(result.begin(), result.end(), '/', '.');
+ return result;
+ } else {
+ // For arrays the 'L' and ';' remain intact.
+ std::string result(descriptor);
+ std::replace(result.begin(), result.end(), '/', '.');
+ return result;
+ }
+ }
+ // Do nothing for non-class/array descriptors.
+ return descriptor;
+}
+
+static jobject GetSystemClassLoader(JNIEnv* env) {
+ ScopedLocalRef<jclass> cl_klass(env, env->FindClass("java/lang/ClassLoader"));
+ CHECK(cl_klass.get() != nullptr);
+ jmethodID getsystemclassloader_method = env->GetStaticMethodID(cl_klass.get(),
+ "getSystemClassLoader",
+ "()Ljava/lang/ClassLoader;");
+ CHECK(getsystemclassloader_method != nullptr);
+ return env->CallStaticObjectMethod(cl_klass.get(), getsystemclassloader_method);
+}
+
+static jclass FindClassWithClassLoader(JNIEnv* env, const char* class_name, jobject class_loader) {
+ // Create a String of the name.
+ std::string descriptor = android::base::StringPrintf("L%s;", class_name);
+ std::string dot_name = DescriptorToDot(descriptor.c_str());
+ ScopedLocalRef<jstring> name_str(env, env->NewStringUTF(dot_name.c_str()));
+
+ // Call Class.forName with it.
+ ScopedLocalRef<jclass> c_klass(env, env->FindClass("java/lang/Class"));
+ CHECK(c_klass.get() != nullptr);
+ jmethodID forname_method = env->GetStaticMethodID(
+ c_klass.get(),
+ "forName",
+ "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
+ CHECK(forname_method != nullptr);
+
+ return static_cast<jclass>(env->CallStaticObjectMethod(c_klass.get(),
+ forname_method,
+ name_str.get(),
+ JNI_FALSE,
+ class_loader));
+}
+
+// Find the given classname. First try the implied classloader, then the system classloader,
+// then use JVMTI to find all classloaders.
+static jclass FindClass(jvmtiEnv* jvmti_env,
+ JNIEnv* env,
+ const char* class_name,
+ jobject class_loader) {
+ if (class_loader != nullptr) {
+ return FindClassWithClassLoader(env, class_name, class_loader);
+ }
+
+ jclass from_implied = env->FindClass(class_name);
+ if (from_implied != nullptr) {
+ return from_implied;
+ }
+ env->ExceptionClear();
+
+ ScopedLocalRef<jobject> system_class_loader(env, GetSystemClassLoader(env));
+ CHECK(system_class_loader.get() != nullptr);
+ jclass from_system = FindClassWithClassLoader(env, class_name, system_class_loader.get());
+ if (from_system != nullptr) {
+ return from_system;
+ }
+ env->ExceptionClear();
+
+ // Look at the context classloaders of all threads.
+ jint thread_count;
+ jthread* threads;
+ CheckJvmtiError(jvmti_env, jvmti_env->GetAllThreads(&thread_count, &threads));
+ JvmtiUniquePtr threads_uptr = MakeJvmtiUniquePtr(jvmti_env, threads);
+
+ jclass result = nullptr;
+ for (jint t = 0; t != thread_count; ++t) {
+ // Always loop over all elements, as we need to free the local references.
+ if (result == nullptr) {
+ jvmtiThreadInfo info;
+ CheckJvmtiError(jvmti_env, jvmti_env->GetThreadInfo(threads[t], &info));
+ CheckJvmtiError(jvmti_env, Deallocate(jvmti_env, info.name));
+ if (info.thread_group != nullptr) {
+ env->DeleteLocalRef(info.thread_group);
+ }
+ if (info.context_class_loader != nullptr) {
+ result = FindClassWithClassLoader(env, class_name, info.context_class_loader);
+ env->ExceptionClear();
+ env->DeleteLocalRef(info.context_class_loader);
+ }
+ }
+ env->DeleteLocalRef(threads[t]);
+ }
+
+ if (result != nullptr) {
+ return result;
+ }
+
+ // TODO: Implement scanning *all* classloaders.
+ LOG(FATAL) << "Unimplemented";
+
+ return nullptr;
+}
+
+void BindFunctionsOnClass(jvmtiEnv* jvmti_env, JNIEnv* env, jclass klass) {
+ // Use JVMTI to get the methods.
+ jint method_count;
+ jmethodID* methods;
+ jvmtiError methods_result = jvmti_env->GetClassMethods(klass, &method_count, &methods);
+ CheckJvmtiError(jvmti_env, methods_result);
+
+ // Check each method.
+ for (jint i = 0; i < method_count; ++i) {
+ jint modifiers;
+ jvmtiError mod_result = jvmti_env->GetMethodModifiers(methods[i], &modifiers);
+ CheckJvmtiError(jvmti_env, mod_result);
+ constexpr jint kNative = static_cast<jint>(0x0100);
+ if ((modifiers & kNative) != 0) {
+ BindMethod(jvmti_env, env, klass, methods[i]);
+ }
+ }
+
+ CheckJvmtiError(jvmti_env, Deallocate(jvmti_env, methods));
+}
+
+void BindFunctions(jvmtiEnv* jvmti_env, JNIEnv* env, const char* class_name, jobject class_loader) {
+ // Use JNI to load the class.
+ ScopedLocalRef<jclass> klass(env, FindClass(jvmti_env, env, class_name, class_loader));
+ CHECK(klass.get() != nullptr) << class_name;
+ BindFunctionsOnClass(jvmti_env, env, klass.get());
+}
+
+} // namespace art
diff --git a/test/ti-agent/jni_binder.h b/test/ti-agent/jni_binder.h
new file mode 100644
index 0000000..6f96257
--- /dev/null
+++ b/test/ti-agent/jni_binder.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_TEST_TI_AGENT_JNI_BINDER_H_
+#define ART_TEST_TI_AGENT_JNI_BINDER_H_
+
+#include "jni.h"
+#include "jvmti.h"
+
+namespace art {
+
+// Load the class through JNI. Inspect it, find all native methods. Construct the corresponding
+// mangled name, run dlsym and bind the method.
+//
+// This will abort on failure.
+void BindFunctions(jvmtiEnv* jvmti_env,
+ JNIEnv* env,
+ const char* class_name,
+ jobject class_loader = nullptr);
+
+void BindFunctionsOnClass(jvmtiEnv* jvmti_env, JNIEnv* env, jclass klass);
+
+} // namespace art
+
+#endif // ART_TEST_TI_AGENT_JNI_BINDER_H_
diff --git a/test/ti-agent/jni_helper.h b/test/ti-agent/jni_helper.h
new file mode 100644
index 0000000..c48b0c0
--- /dev/null
+++ b/test/ti-agent/jni_helper.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_TEST_TI_AGENT_JNI_HELPER_H_
+#define ART_TEST_TI_AGENT_JNI_HELPER_H_
+
+#include "jni.h"
+#include "scoped_local_ref.h"
+
+namespace art {
+
+// Create an object array using a lambda that returns a local ref for each element.
+template <typename T>
+static inline jobjectArray CreateObjectArray(JNIEnv* env,
+ jint length,
+ const char* component_type_descriptor,
+ T src) {
+ if (length < 0) {
+ return nullptr;
+ }
+
+ ScopedLocalRef<jclass> obj_class(env, env->FindClass(component_type_descriptor));
+ if (obj_class.get() == nullptr) {
+ return nullptr;
+ }
+
+ ScopedLocalRef<jobjectArray> ret(env, env->NewObjectArray(length, obj_class.get(), nullptr));
+ if (ret.get() == nullptr) {
+ return nullptr;
+ }
+
+ for (jint i = 0; i < length; ++i) {
+ jobject element = src(i);
+ env->SetObjectArrayElement(ret.get(), static_cast<jint>(i), element);
+ env->DeleteLocalRef(element);
+ if (env->ExceptionCheck()) {
+ return nullptr;
+ }
+ }
+
+ return ret.release();
+}
+
+} // namespace art
+
+#endif // ART_TEST_TI_AGENT_JNI_HELPER_H_
diff --git a/test/ti-agent/jvmti_helper.cc b/test/ti-agent/jvmti_helper.cc
new file mode 100644
index 0000000..598a30f
--- /dev/null
+++ b/test/ti-agent/jvmti_helper.cc
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jvmti_helper.h"
+
+#include <algorithm>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <sstream>
+#include <string.h>
+
+#include "android-base/logging.h"
+#include "scoped_local_ref.h"
+
+namespace art {
+
+void CheckJvmtiError(jvmtiEnv* env, jvmtiError error) {
+ if (error != JVMTI_ERROR_NONE) {
+ char* error_name;
+ jvmtiError name_error = env->GetErrorName(error, &error_name);
+ if (name_error != JVMTI_ERROR_NONE) {
+ LOG(FATAL) << "Unable to get error name for " << error;
+ }
+ LOG(FATAL) << "Unexpected error: " << error_name;
+ }
+}
+
+void SetAllCapabilities(jvmtiEnv* env) {
+ jvmtiCapabilities caps;
+ jvmtiError error1 = env->GetPotentialCapabilities(&caps);
+ CheckJvmtiError(env, error1);
+ jvmtiError error2 = env->AddCapabilities(&caps);
+ CheckJvmtiError(env, error2);
+}
+
+bool JvmtiErrorToException(JNIEnv* env, jvmtiEnv* jvmti_env, jvmtiError error) {
+ if (error == JVMTI_ERROR_NONE) {
+ return false;
+ }
+
+ ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
+ if (rt_exception.get() == nullptr) {
+ // CNFE should be pending.
+ return true;
+ }
+
+ char* err;
+ CheckJvmtiError(jvmti_env, jvmti_env->GetErrorName(error, &err));
+
+ env->ThrowNew(rt_exception.get(), err);
+
+ Deallocate(jvmti_env, err);
+ return true;
+}
+
+std::ostream& operator<<(std::ostream& os, const jvmtiError& rhs) {
+ switch (rhs) {
+ case JVMTI_ERROR_NONE:
+ return os << "NONE";
+ case JVMTI_ERROR_INVALID_THREAD:
+ return os << "INVALID_THREAD";
+ case JVMTI_ERROR_INVALID_THREAD_GROUP:
+ return os << "INVALID_THREAD_GROUP";
+ case JVMTI_ERROR_INVALID_PRIORITY:
+ return os << "INVALID_PRIORITY";
+ case JVMTI_ERROR_THREAD_NOT_SUSPENDED:
+ return os << "THREAD_NOT_SUSPENDED";
+ case JVMTI_ERROR_THREAD_SUSPENDED:
+ return os << "THREAD_SUSPENDED";
+ case JVMTI_ERROR_THREAD_NOT_ALIVE:
+ return os << "THREAD_NOT_ALIVE";
+ case JVMTI_ERROR_INVALID_OBJECT:
+ return os << "INVALID_OBJECT";
+ case JVMTI_ERROR_INVALID_CLASS:
+ return os << "INVALID_CLASS";
+ case JVMTI_ERROR_CLASS_NOT_PREPARED:
+ return os << "CLASS_NOT_PREPARED";
+ case JVMTI_ERROR_INVALID_METHODID:
+ return os << "INVALID_METHODID";
+ case JVMTI_ERROR_INVALID_LOCATION:
+ return os << "INVALID_LOCATION";
+ case JVMTI_ERROR_INVALID_FIELDID:
+ return os << "INVALID_FIELDID";
+ case JVMTI_ERROR_NO_MORE_FRAMES:
+ return os << "NO_MORE_FRAMES";
+ case JVMTI_ERROR_OPAQUE_FRAME:
+ return os << "OPAQUE_FRAME";
+ case JVMTI_ERROR_TYPE_MISMATCH:
+ return os << "TYPE_MISMATCH";
+ case JVMTI_ERROR_INVALID_SLOT:
+ return os << "INVALID_SLOT";
+ case JVMTI_ERROR_DUPLICATE:
+ return os << "DUPLICATE";
+ case JVMTI_ERROR_NOT_FOUND:
+ return os << "NOT_FOUND";
+ case JVMTI_ERROR_INVALID_MONITOR:
+ return os << "INVALID_MONITOR";
+ case JVMTI_ERROR_NOT_MONITOR_OWNER:
+ return os << "NOT_MONITOR_OWNER";
+ case JVMTI_ERROR_INTERRUPT:
+ return os << "INTERRUPT";
+ case JVMTI_ERROR_INVALID_CLASS_FORMAT:
+ return os << "INVALID_CLASS_FORMAT";
+ case JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION:
+ return os << "CIRCULAR_CLASS_DEFINITION";
+ case JVMTI_ERROR_FAILS_VERIFICATION:
+ return os << "FAILS_VERIFICATION";
+ case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED:
+ return os << "UNSUPPORTED_REDEFINITION_METHOD_ADDED";
+ case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED:
+ return os << "UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED";
+ case JVMTI_ERROR_INVALID_TYPESTATE:
+ return os << "INVALID_TYPESTATE";
+ case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED:
+ return os << "UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED";
+ case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED:
+ return os << "UNSUPPORTED_REDEFINITION_METHOD_DELETED";
+ case JVMTI_ERROR_UNSUPPORTED_VERSION:
+ return os << "UNSUPPORTED_VERSION";
+ case JVMTI_ERROR_NAMES_DONT_MATCH:
+ return os << "NAMES_DONT_MATCH";
+ case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED:
+ return os << "UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED";
+ case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED:
+ return os << "UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED";
+ case JVMTI_ERROR_UNMODIFIABLE_CLASS:
+ return os << "JVMTI_ERROR_UNMODIFIABLE_CLASS";
+ case JVMTI_ERROR_NOT_AVAILABLE:
+ return os << "NOT_AVAILABLE";
+ case JVMTI_ERROR_MUST_POSSESS_CAPABILITY:
+ return os << "MUST_POSSESS_CAPABILITY";
+ case JVMTI_ERROR_NULL_POINTER:
+ return os << "NULL_POINTER";
+ case JVMTI_ERROR_ABSENT_INFORMATION:
+ return os << "ABSENT_INFORMATION";
+ case JVMTI_ERROR_INVALID_EVENT_TYPE:
+ return os << "INVALID_EVENT_TYPE";
+ case JVMTI_ERROR_ILLEGAL_ARGUMENT:
+ return os << "ILLEGAL_ARGUMENT";
+ case JVMTI_ERROR_NATIVE_METHOD:
+ return os << "NATIVE_METHOD";
+ case JVMTI_ERROR_CLASS_LOADER_UNSUPPORTED:
+ return os << "CLASS_LOADER_UNSUPPORTED";
+ case JVMTI_ERROR_OUT_OF_MEMORY:
+ return os << "OUT_OF_MEMORY";
+ case JVMTI_ERROR_ACCESS_DENIED:
+ return os << "ACCESS_DENIED";
+ case JVMTI_ERROR_WRONG_PHASE:
+ return os << "WRONG_PHASE";
+ case JVMTI_ERROR_INTERNAL:
+ return os << "INTERNAL";
+ case JVMTI_ERROR_UNATTACHED_THREAD:
+ return os << "UNATTACHED_THREAD";
+ case JVMTI_ERROR_INVALID_ENVIRONMENT:
+ return os << "INVALID_ENVIRONMENT";
+ }
+ LOG(FATAL) << "Unexpected error type " << static_cast<int>(rhs);
+ __builtin_unreachable();
+}
+
+} // namespace art
diff --git a/test/ti-agent/jvmti_helper.h b/test/ti-agent/jvmti_helper.h
new file mode 100644
index 0000000..66d88d0
--- /dev/null
+++ b/test/ti-agent/jvmti_helper.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_TEST_TI_AGENT_JVMTI_HELPER_H_
+#define ART_TEST_TI_AGENT_JVMTI_HELPER_H_
+
+#include "jni.h"
+#include "jvmti.h"
+#include <memory>
+#include <ostream>
+
+#include "android-base/logging.h"
+
+namespace art {
+
+// Add all capabilities to the given env.
+void SetAllCapabilities(jvmtiEnv* env);
+
+// Check whether the given error is NONE. If not, print out the corresponding error message
+// and abort.
+void CheckJvmtiError(jvmtiEnv* env, jvmtiError error);
+
+// Convert the given error to a RuntimeException with a message derived from the error. Returns
+// true on error, false if error is JVMTI_ERROR_NONE.
+bool JvmtiErrorToException(JNIEnv* env, jvmtiEnv* jvmti_env, jvmtiError error);
+
+class JvmtiDeleter {
+ public:
+ JvmtiDeleter() : env_(nullptr) {}
+ explicit JvmtiDeleter(jvmtiEnv* env) : env_(env) {}
+
+ JvmtiDeleter(JvmtiDeleter&) = default;
+ JvmtiDeleter(JvmtiDeleter&&) = default;
+ JvmtiDeleter& operator=(const JvmtiDeleter&) = default;
+
+ void operator()(unsigned char* ptr) const {
+ CHECK(env_ != nullptr);
+ jvmtiError ret = env_->Deallocate(ptr);
+ CheckJvmtiError(env_, ret);
+ }
+
+ private:
+ mutable jvmtiEnv* env_;
+};
+
+using JvmtiUniquePtr = std::unique_ptr<unsigned char, JvmtiDeleter>;
+
+template <typename T>
+static inline JvmtiUniquePtr MakeJvmtiUniquePtr(jvmtiEnv* env, T* mem) {
+ return JvmtiUniquePtr(reinterpret_cast<unsigned char*>(mem), JvmtiDeleter(env));
+}
+
+template <typename T>
+static inline jvmtiError Deallocate(jvmtiEnv* env, T* mem) {
+ return env->Deallocate(reinterpret_cast<unsigned char*>(mem));
+}
+
+// To print jvmtiError. Does not rely on GetErrorName, so is an approximation.
+std::ostream& operator<<(std::ostream& os, const jvmtiError& rhs);
+
+} // namespace art
+
+#endif // ART_TEST_TI_AGENT_JVMTI_HELPER_H_
diff --git a/test/ti-agent/scoped_local_ref.h b/test/ti-agent/scoped_local_ref.h
new file mode 100644
index 0000000..0cd9891
--- /dev/null
+++ b/test/ti-agent/scoped_local_ref.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ART_TEST_TI_AGENT_SCOPED_LOCAL_REF_H_
+#define ART_TEST_TI_AGENT_SCOPED_LOCAL_REF_H_
+
+#include "jni.h"
+
+#include <stddef.h>
+
+#include "android-base/macros.h"
+
+namespace art {
+
+template<typename T>
+class ScopedLocalRef {
+ public:
+ ScopedLocalRef(JNIEnv* env, T localRef) : mEnv(env), mLocalRef(localRef) {
+ }
+
+ ~ScopedLocalRef() {
+ reset();
+ }
+
+ void reset(T ptr = NULL) {
+ if (ptr != mLocalRef) {
+ if (mLocalRef != NULL) {
+ mEnv->DeleteLocalRef(mLocalRef);
+ }
+ mLocalRef = ptr;
+ }
+ }
+
+ T release() __attribute__((warn_unused_result)) {
+ T localRef = mLocalRef;
+ mLocalRef = NULL;
+ return localRef;
+ }
+
+ T get() const {
+ return mLocalRef;
+ }
+
+ private:
+ JNIEnv* const mEnv;
+ T mLocalRef;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedLocalRef);
+};
+
+} // namespace art
+
+#endif // ART_TEST_TI_AGENT_SCOPED_LOCAL_REF_H_
diff --git a/test/ti-agent/scoped_utf_chars.h b/test/ti-agent/scoped_utf_chars.h
new file mode 100644
index 0000000..e8c9a11
--- /dev/null
+++ b/test/ti-agent/scoped_utf_chars.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ART_TEST_TI_AGENT_SCOPED_UTF_CHARS_H_
+#define ART_TEST_TI_AGENT_SCOPED_UTF_CHARS_H_
+
+#include "jni.h"
+
+#include <string.h>
+
+#include "android-base/macros.h"
+
+namespace art {
+
+class ScopedUtfChars {
+ public:
+ ScopedUtfChars(JNIEnv* env, jstring s) : env_(env), string_(s) {
+ if (s == nullptr) {
+ utf_chars_ = nullptr;
+ // TODO: JniThrowNullPointerException(env, nullptr);
+ } else {
+ utf_chars_ = env->GetStringUTFChars(s, nullptr);
+ }
+ }
+
+ ScopedUtfChars(ScopedUtfChars&& rhs) :
+ env_(rhs.env_), string_(rhs.string_), utf_chars_(rhs.utf_chars_) {
+ rhs.env_ = nullptr;
+ rhs.string_ = nullptr;
+ rhs.utf_chars_ = nullptr;
+ }
+
+ ~ScopedUtfChars() {
+ if (utf_chars_) {
+ env_->ReleaseStringUTFChars(string_, utf_chars_);
+ }
+ }
+
+ ScopedUtfChars& operator=(ScopedUtfChars&& rhs) {
+ if (this != &rhs) {
+ // Delete the currently owned UTF chars.
+ this->~ScopedUtfChars();
+
+ // Move the rhs ScopedUtfChars and zero it out.
+ env_ = rhs.env_;
+ string_ = rhs.string_;
+ utf_chars_ = rhs.utf_chars_;
+ rhs.env_ = nullptr;
+ rhs.string_ = nullptr;
+ rhs.utf_chars_ = nullptr;
+ }
+ return *this;
+ }
+
+ const char* c_str() const {
+ return utf_chars_;
+ }
+
+ size_t size() const {
+ return strlen(utf_chars_);
+ }
+
+ const char& operator[](size_t n) const {
+ return utf_chars_[n];
+ }
+
+ private:
+ JNIEnv* env_;
+ jstring string_;
+ const char* utf_chars_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedUtfChars);
+};
+
+} // namespace art
+
+#endif // ART_TEST_TI_AGENT_SCOPED_UTF_CHARS_H_
diff --git a/test/ti-agent/common_load.h b/test/ti-agent/test_env.cc
similarity index 78%
copy from test/ti-agent/common_load.h
copy to test/ti-agent/test_env.cc
index e79a006..cf47f22 100644
--- a/test/ti-agent/common_load.h
+++ b/test/ti-agent/test_env.cc
@@ -14,15 +14,20 @@
* limitations under the License.
*/
-#ifndef ART_TEST_TI_AGENT_COMMON_LOAD_H_
-#define ART_TEST_TI_AGENT_COMMON_LOAD_H_
-
-#include "jvmti.h"
+#include "test_env.h"
namespace art {
-extern jvmtiEnv* jvmti_env;
+jvmtiEnv* jvmti_env = nullptr;
+
+static bool gRuntimeIsJVM = false;
+
+bool IsJVM() {
+ return gRuntimeIsJVM;
+}
+
+void SetJVM(bool b) {
+ gRuntimeIsJVM = b;
+}
} // namespace art
-
-#endif // ART_TEST_TI_AGENT_COMMON_LOAD_H_
diff --git a/test/ti-agent/common_load.h b/test/ti-agent/test_env.h
similarity index 81%
rename from test/ti-agent/common_load.h
rename to test/ti-agent/test_env.h
index e79a006..2eb631c 100644
--- a/test/ti-agent/common_load.h
+++ b/test/ti-agent/test_env.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ART_TEST_TI_AGENT_COMMON_LOAD_H_
-#define ART_TEST_TI_AGENT_COMMON_LOAD_H_
+#ifndef ART_TEST_TI_AGENT_TEST_ENV_H_
+#define ART_TEST_TI_AGENT_TEST_ENV_H_
#include "jvmti.h"
@@ -23,6 +23,9 @@
extern jvmtiEnv* jvmti_env;
+bool IsJVM();
+void SetJVM(bool b);
+
} // namespace art
-#endif // ART_TEST_TI_AGENT_COMMON_LOAD_H_
+#endif // ART_TEST_TI_AGENT_TEST_ENV_H_