ART: TI Agent test library refactor
More refactoring, lowering the reliance on ART-provided functionality
and adding a library that includes all the code that can run without
ART.
Bug: 32072923
Test: m test-art-host
Change-Id: I67d84056a6fd7722c58855fccbdea3f6869b2efb
(cherry picked from commit 027444b64dd52e1d2beea7aa525fbb8146a516bc)
diff --git a/test/901-hello-ti-agent/basics.cc b/test/901-hello-ti-agent/basics.cc
index 00776ca..20b227a 100644
--- a/test/901-hello-ti-agent/basics.cc
+++ b/test/901-hello-ti-agent/basics.cc
@@ -21,7 +21,7 @@
#include <jni.h>
#include <stdio.h>
#include <string.h>
-#include "base/macros.h"
+#include "android-base/macros.h"
#include "jvmti.h"
// Test infrastructure
diff --git a/test/903-hello-tagging/tagging.cc b/test/903-hello-tagging/tagging.cc
index 7f079a2..701b0c3 100644
--- a/test/903-hello-tagging/tagging.cc
+++ b/test/903-hello-tagging/tagging.cc
@@ -19,14 +19,12 @@
#include <stdio.h>
#include <vector>
+#include "android-base/logging.h"
#include "jni.h"
-#include "ScopedLocalRef.h"
-#include "ScopedPrimitiveArray.h"
+#include "scoped_local_ref.h"
+#include "scoped_primitive_array.h"
-#include "art_method-inl.h"
-#include "base/logging.h"
#include "jvmti.h"
-#include "utils.h"
// Test infrastructure
#include "jvmti_helper.h"
diff --git a/test/904-object-allocation/tracking.cc b/test/904-object-allocation/tracking.cc
index 303f954..c829496 100644
--- a/test/904-object-allocation/tracking.cc
+++ b/test/904-object-allocation/tracking.cc
@@ -19,12 +19,11 @@
#include <stdio.h>
#include <vector>
-#include "base/logging.h"
+#include "android-base/logging.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
-#include "ScopedUtfChars.h"
-#include "utils.h"
+#include "scoped_local_ref.h"
+#include "scoped_utf_chars.h"
// Test infrastructure
#include "jvmti_helper.h"
diff --git a/test/905-object-free/tracking_free.cc b/test/905-object-free/tracking_free.cc
index 68ce38d..59b429c 100644
--- a/test/905-object-free/tracking_free.cc
+++ b/test/905-object-free/tracking_free.cc
@@ -19,12 +19,11 @@
#include <stdio.h>
#include <vector>
-#include "base/logging.h"
+#include "android-base/logging.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
-#include "ScopedUtfChars.h"
-#include "utils.h"
+#include "scoped_local_ref.h"
+#include "scoped_utf_chars.h"
// Test infrastructure
#include "jvmti_helper.h"
diff --git a/test/906-iterate-heap/iterate_heap.cc b/test/906-iterate-heap/iterate_heap.cc
index 74cb1e9..bb30074 100644
--- a/test/906-iterate-heap/iterate_heap.cc
+++ b/test/906-iterate-heap/iterate_heap.cc
@@ -23,16 +23,18 @@
#include <stdio.h>
#include <vector>
+#include "android-base/logging.h"
#include "android-base/stringprintf.h"
-#include "base/logging.h"
+
#include "jni.h"
#include "jvmti.h"
-#include "ScopedPrimitiveArray.h"
-#include "utf.h"
+#include "scoped_primitive_array.h"
// Test infrastructure
#include "jvmti_helper.h"
#include "test_env.h"
+#include "ti_macros.h"
+#include "ti_utf.h"
namespace art {
namespace Test906IterateHeap {
@@ -197,10 +199,10 @@
void* user_data) {
FindStringCallbacks* p = reinterpret_cast<FindStringCallbacks*>(user_data);
if (*tag_ptr == p->tag_to_find) {
- size_t utf_byte_count = CountUtf8Bytes(value, value_length);
+ size_t utf_byte_count = ti::CountUtf8Bytes(value, value_length);
std::unique_ptr<char[]> mod_utf(new char[utf_byte_count + 1]);
memset(mod_utf.get(), 0, utf_byte_count + 1);
- ConvertUtf16ToModifiedUtf8(mod_utf.get(), utf_byte_count, value, value_length);
+ ti::ConvertUtf16ToModifiedUtf8(mod_utf.get(), utf_byte_count, value, value_length);
if (!p->data.empty()) {
p->data += "\n";
}
diff --git a/test/907-get-loaded-classes/get_loaded_classes.cc b/test/907-get-loaded-classes/get_loaded_classes.cc
index 1b973bf..5ec56c4 100644
--- a/test/907-get-loaded-classes/get_loaded_classes.cc
+++ b/test/907-get-loaded-classes/get_loaded_classes.cc
@@ -19,11 +19,12 @@
#include <stdio.h>
#include <vector>
-#include "base/macros.h"
+#include "android-base/macros.h"
+
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
-#include "ScopedUtfChars.h"
+#include "scoped_local_ref.h"
+#include "scoped_utf_chars.h"
// Test infrastructure
#include "jni_helper.h"
diff --git a/test/908-gc-start-finish/gc_callbacks.cc b/test/908-gc-start-finish/gc_callbacks.cc
index 4b9a23c..f186895 100644
--- a/test/908-gc-start-finish/gc_callbacks.cc
+++ b/test/908-gc-start-finish/gc_callbacks.cc
@@ -17,7 +17,8 @@
#include <stdio.h>
#include <string.h>
-#include "base/macros.h"
+#include "android-base/macros.h"
+
#include "jni.h"
#include "jvmti.h"
diff --git a/test/909-attach-agent/attach.cc b/test/909-attach-agent/attach.cc
index 67c7567..0150e09 100644
--- a/test/909-attach-agent/attach.cc
+++ b/test/909-attach-agent/attach.cc
@@ -19,7 +19,9 @@
#include <jni.h>
#include <stdio.h>
#include <string.h>
-#include "base/macros.h"
+
+#include "android-base/macros.h"
+
#include "jvmti.h"
namespace art {
diff --git a/test/910-methods/methods.cc b/test/910-methods/methods.cc
index 429076c..ded4f09 100644
--- a/test/910-methods/methods.cc
+++ b/test/910-methods/methods.cc
@@ -16,10 +16,11 @@
#include <stdio.h>
-#include "base/macros.h"
+#include "android-base/macros.h"
+
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
+#include "scoped_local_ref.h"
// Test infrastructure
#include "jni_helper.h"
diff --git a/test/911-get-stack-trace/stack_trace.cc b/test/911-get-stack-trace/stack_trace.cc
index 49cbb7e..a499e90 100644
--- a/test/911-get-stack-trace/stack_trace.cc
+++ b/test/911-get-stack-trace/stack_trace.cc
@@ -18,20 +18,19 @@
#include <memory>
#include <stdio.h>
+#include "android-base/logging.h"
#include "android-base/stringprintf.h"
-#include "android-base/stringprintf.h"
-#include "base/logging.h"
-#include "base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
+#include "scoped_local_ref.h"
// Test infrastructure
#include "jni_binder.h"
#include "jni_helper.h"
#include "jvmti_helper.h"
#include "test_env.h"
+#include "ti_macros.h"
namespace art {
namespace Test911GetStackTrace {
diff --git a/test/912-classes/classes.cc b/test/912-classes/classes.cc
index 4d84e39..2636367 100644
--- a/test/912-classes/classes.cc
+++ b/test/912-classes/classes.cc
@@ -16,14 +16,15 @@
#include <stdio.h>
-#include "base/macros.h"
+#include "android-base/macros.h"
+
#include "class_linker.h"
#include "jni.h"
#include "mirror/class_loader.h"
#include "jvmti.h"
#include "runtime.h"
-#include "ScopedLocalRef.h"
-#include "ScopedUtfChars.h"
+#include "scoped_local_ref.h"
+#include "scoped_utf_chars.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
diff --git a/test/913-heaps/heaps.cc b/test/913-heaps/heaps.cc
index 999467f..6a47ca1 100644
--- a/test/913-heaps/heaps.cc
+++ b/test/913-heaps/heaps.cc
@@ -21,10 +21,10 @@
#include <iostream>
#include <vector>
+#include "android-base/macros.h"
+#include "android-base/logging.h"
#include "android-base/stringprintf.h"
-#include "base/logging.h"
-#include "base/macros.h"
#include "jit/jit.h"
#include "jni.h"
#include "native_stack_dump.h"
diff --git a/test/918-fields/fields.cc b/test/918-fields/fields.cc
index 0c019e3..726c5cf 100644
--- a/test/918-fields/fields.cc
+++ b/test/918-fields/fields.cc
@@ -16,10 +16,10 @@
#include <stdio.h>
-#include "base/macros.h"
+#include "android-base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
+#include "scoped_local_ref.h"
// Test infrastructure
#include "jni_helper.h"
diff --git a/test/920-objects/objects.cc b/test/920-objects/objects.cc
index 1dfb516..5263e75 100644
--- a/test/920-objects/objects.cc
+++ b/test/920-objects/objects.cc
@@ -16,10 +16,10 @@
#include <stdio.h>
-#include "base/macros.h"
+#include "android-base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
+#include "scoped_local_ref.h"
// Test infrastructure
#include "test_env.h"
diff --git a/test/922-properties/properties.cc b/test/922-properties/properties.cc
index 948da6a..896e4c3 100644
--- a/test/922-properties/properties.cc
+++ b/test/922-properties/properties.cc
@@ -16,10 +16,10 @@
#include <stdio.h>
-#include "base/macros.h"
+#include "android-base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedUtfChars.h"
+#include "scoped_utf_chars.h"
// Test infrastructure
#include "jni_helper.h"
diff --git a/test/923-monitors/monitors.cc b/test/923-monitors/monitors.cc
index 60d5b5a..6369a74 100644
--- a/test/923-monitors/monitors.cc
+++ b/test/923-monitors/monitors.cc
@@ -16,10 +16,10 @@
#include <stdio.h>
-#include "base/macros.h"
+#include "android-base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedUtfChars.h"
+#include "scoped_utf_chars.h"
// Test infrastructure
#include "jvmti_helper.h"
diff --git a/test/924-threads/threads.cc b/test/924-threads/threads.cc
index bb040bd..a8b37ec 100644
--- a/test/924-threads/threads.cc
+++ b/test/924-threads/threads.cc
@@ -16,17 +16,17 @@
#include <stdio.h>
+#include "android-base/logging.h"
#include "android-base/stringprintf.h"
-#include "base/macros.h"
-#include "base/logging.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
+#include "scoped_local_ref.h"
// Test infrastructure
#include "jni_helper.h"
#include "jvmti_helper.h"
#include "test_env.h"
+#include "ti_macros.h"
namespace art {
namespace Test924Threads {
diff --git a/test/925-threadgroups/threadgroups.cc b/test/925-threadgroups/threadgroups.cc
index 1cd93be..d555553 100644
--- a/test/925-threadgroups/threadgroups.cc
+++ b/test/925-threadgroups/threadgroups.cc
@@ -16,17 +16,17 @@
#include <stdio.h>
+#include "android-base/logging.h"
#include "android-base/stringprintf.h"
-#include "base/macros.h"
-#include "base/logging.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
+#include "scoped_local_ref.h"
// Test infrastructure
#include "jni_helper.h"
#include "jvmti_helper.h"
#include "test_env.h"
+#include "ti_macros.h"
namespace art {
namespace Test925ThreadGroups {
diff --git a/test/927-timers/timers.cc b/test/927-timers/timers.cc
index a67f5b4..55d3921 100644
--- a/test/927-timers/timers.cc
+++ b/test/927-timers/timers.cc
@@ -16,9 +16,9 @@
#include <inttypes.h>
+#include "android-base/logging.h"
#include "android-base/stringprintf.h"
-#include "base/logging.h"
-#include "base/macros.h"
+
#include "jni.h"
#include "jvmti.h"
@@ -26,6 +26,7 @@
#include "jni_helper.h"
#include "jvmti_helper.h"
#include "test_env.h"
+#include "ti_macros.h"
namespace art {
namespace Test926Timers {
diff --git a/test/928-jni-table/jni_table.cc b/test/928-jni-table/jni_table.cc
index 3f4a93e..26a6707 100644
--- a/test/928-jni-table/jni_table.cc
+++ b/test/928-jni-table/jni_table.cc
@@ -19,8 +19,8 @@
#include "jni.h"
#include "jvmti.h"
-#include "base/logging.h"
-#include "base/macros.h"
+#include "android-base/logging.h"
+#include "android-base/macros.h"
// Test infrastructure
#include "jvmti_helper.h"
diff --git a/test/929-search/search.cc b/test/929-search/search.cc
index bed4dfe..5516105 100644
--- a/test/929-search/search.cc
+++ b/test/929-search/search.cc
@@ -16,12 +16,12 @@
#include <inttypes.h>
+#include "android-base/logging.h"
+#include "android-base/macros.h"
#include "android-base/stringprintf.h"
-#include "base/logging.h"
-#include "base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedUtfChars.h"
+#include "scoped_utf_chars.h"
// Test infrastructure
#include "jvmti_helper.h"
diff --git a/test/931-agent-thread/agent_thread.cc b/test/931-agent-thread/agent_thread.cc
index 3ec8793..f9af8cf 100644
--- a/test/931-agent-thread/agent_thread.cc
+++ b/test/931-agent-thread/agent_thread.cc
@@ -15,17 +15,14 @@
*/
#include <inttypes.h>
+#include <pthread.h>
#include <sched.h>
-#include "barrier.h"
-#include "base/logging.h"
-#include "base/macros.h"
+#include "android-base/logging.h"
+#include "android-base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "runtime.h"
-#include "ScopedLocalRef.h"
-#include "thread-inl.h"
-#include "well_known_classes.h"
+#include "scoped_local_ref.h"
// Test infrastructure
#include "jvmti_helper.h"
@@ -37,13 +34,12 @@
struct AgentData {
AgentData() : main_thread(nullptr),
jvmti_env(nullptr),
- b(2),
priority(0) {
}
jthread main_thread;
jvmtiEnv* jvmti_env;
- Barrier b;
+ pthread_barrier_t b;
jint priority;
};
@@ -54,14 +50,21 @@
// This thread is not the main thread.
jthread this_thread;
jvmtiError this_thread_result = jenv->GetCurrentThread(&this_thread);
- CHECK(!JvmtiErrorToException(env, jenv, this_thread_result));
+ CheckJvmtiError(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, jenv, info_result));
+ CheckJvmtiError(jenv, info_result);
CHECK(info.is_daemon);
+ CheckJvmtiError(jenv, jenv->Deallocate(reinterpret_cast<unsigned char*>(info.name)));
+ if (info.thread_group != nullptr) {
+ env->DeleteLocalRef(info.thread_group);
+ }
+ if (info.context_class_loader != nullptr) {
+ env->DeleteLocalRef(info.context_class_loader);
+ }
// The thread has the requested priority.
// TODO: Our thread priorities do not work on the host.
@@ -71,7 +74,7 @@
jint thread_count;
jthread* threads;
jvmtiError threads_result = jenv->GetAllThreads(&thread_count, &threads);
- CHECK(!JvmtiErrorToException(env, jenv, threads_result));
+ CheckJvmtiError(jenv, threads_result);
bool found = false;
for (jint i = 0; i != thread_count; ++i) {
if (env->IsSameObject(threads[i], this_thread)) {
@@ -82,29 +85,53 @@
CHECK(found);
// Done, let the main thread progress.
- data->b.Pass(Thread::Current());
+ int wait_result = pthread_barrier_wait(&data->b);
+ CHECK(wait_result == PTHREAD_BARRIER_SERIAL_THREAD || wait_result == 0);
}
extern "C" JNIEXPORT void JNICALL Java_Main_testAgentThread(
JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
// Create a Thread object.
- ScopedLocalRef<jobject> thread_name(env,
- env->NewStringUTF("Agent Thread"));
+ ScopedLocalRef<jobject> thread_name(env, env->NewStringUTF("Agent Thread"));
if (thread_name.get() == nullptr) {
return;
}
- ScopedLocalRef<jobject> thread(env, env->AllocObject(WellKnownClasses::java_lang_Thread));
+ ScopedLocalRef<jclass> thread_klass(env, env->FindClass("java/lang/Thread"));
+ if (thread_klass.get() == nullptr) {
+ return;
+ }
+ ScopedLocalRef<jobject> thread(env, env->AllocObject(thread_klass.get()));
if (thread.get() == nullptr) {
return;
}
+ // Get a ThreadGroup from the current thread. We need a non-null one as we're gonna call a
+ // runtime-only constructor (so we can set priority and daemon state).
+ jvmtiThreadInfo cur_thread_info;
+ jvmtiError info_result = jvmti_env->GetThreadInfo(nullptr, &cur_thread_info);
+ if (JvmtiErrorToException(env, jvmti_env, info_result)) {
+ return;
+ }
+ CheckJvmtiError(jvmti_env,
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(cur_thread_info.name)));
+ ScopedLocalRef<jobject> thread_group(env, cur_thread_info.thread_group);
+ if (cur_thread_info.context_class_loader != nullptr) {
+ env->DeleteLocalRef(cur_thread_info.context_class_loader);
+ }
+
+ jmethodID initID = env->GetMethodID(thread_klass.get(),
+ "<init>",
+ "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
+ if (initID == nullptr) {
+ return;
+ }
env->CallNonvirtualVoidMethod(thread.get(),
- WellKnownClasses::java_lang_Thread,
- WellKnownClasses::java_lang_Thread_init,
- Runtime::Current()->GetMainThreadGroup(),
+ thread_klass.get(),
+ initID,
+ thread_group.get(),
thread_name.get(),
- kMinThreadPriority,
+ 0,
JNI_FALSE);
if (env->ExceptionCheck()) {
return;
@@ -120,18 +147,20 @@
data.main_thread = env->NewGlobalRef(main_thread);
data.jvmti_env = jvmti_env;
data.priority = JVMTI_THREAD_MIN_PRIORITY;
+ CHECK_EQ(0, pthread_barrier_init(&data.b, nullptr, 2));
jvmtiError result = jvmti_env->RunAgentThread(thread.get(), AgentMain, &data, data.priority);
if (JvmtiErrorToException(env, jvmti_env, result)) {
return;
}
- data.b.Wait(Thread::Current());
+ int wait_result = pthread_barrier_wait(&data.b);
+ CHECK(wait_result == PTHREAD_BARRIER_SERIAL_THREAD || wait_result == 0);
// Scheduling may mean that the agent thread is put to sleep. Wait until it's dead in an effort
// to not unload the plugin and crash.
for (;;) {
- NanoSleep(1000 * 1000);
+ sleep(1);
jint thread_state;
jvmtiError state_result = jvmti_env->GetThreadState(thread.get(), &thread_state);
if (JvmtiErrorToException(env, jvmti_env, state_result)) {
@@ -144,9 +173,11 @@
}
// Yield and sleep a bit more, to give the plugin time to tear down the native thread structure.
sched_yield();
- NanoSleep(100 * 1000 * 1000);
+ sleep(1);
env->DeleteGlobalRef(data.main_thread);
+
+ pthread_barrier_destroy(&data.b);
}
} // namespace Test930AgentThread
diff --git a/test/933-misc-events/misc_events.cc b/test/933-misc-events/misc_events.cc
index 7b6c64d..2b74c40 100644
--- a/test/933-misc-events/misc_events.cc
+++ b/test/933-misc-events/misc_events.cc
@@ -18,8 +18,8 @@
#include <signal.h>
#include <sys/types.h>
-#include "base/logging.h"
-#include "base/macros.h"
+#include "android-base/logging.h"
+#include "android-base/macros.h"
#include "jni.h"
#include "jvmti.h"
diff --git a/test/936-search-onload/search_onload.cc b/test/936-search-onload/search_onload.cc
index 72987eb..b2ef056 100644
--- a/test/936-search-onload/search_onload.cc
+++ b/test/936-search-onload/search_onload.cc
@@ -23,7 +23,7 @@
#include "base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedUtfChars.h"
+#include "scoped_utf_chars.h"
// Test infrastructure
#include "jvmti_helper.h"
diff --git a/test/944-transform-classloaders/classloader.cc b/test/944-transform-classloaders/classloader.cc
index f46763c..698e023 100644
--- a/test/944-transform-classloaders/classloader.cc
+++ b/test/944-transform-classloaders/classloader.cc
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-#include "base/macros.h"
+#include "android-base/macros.h"
#include "jni.h"
#include "jvmti.h"
#include "mirror/class-inl.h"
-#include "ScopedLocalRef.h"
+#include "scoped_local_ref.h"
// Test infrastructure
#include "test_env.h"
@@ -26,7 +26,6 @@
namespace art {
namespace Test944TransformClassloaders {
-
extern "C" JNIEXPORT jlong JNICALL Java_Main_getDexFilePointer(JNIEnv* env, jclass, jclass klass) {
if (Runtime::Current() == nullptr) {
env->ThrowNew(env->FindClass("java/lang/Exception"),
diff --git a/test/945-obsolete-native/obsolete_native.cc b/test/945-obsolete-native/obsolete_native.cc
index b9303dd..ee653a4 100644
--- a/test/945-obsolete-native/obsolete_native.cc
+++ b/test/945-obsolete-native/obsolete_native.cc
@@ -25,7 +25,7 @@
#include "base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedLocalRef.h"
+#include "scoped_local_ref.h"
// Test infrastructure
#include "jni_binder.h"
diff --git a/test/980-redefine-object/redefine_object.cc b/test/980-redefine-object/redefine_object.cc
index 6c8c4bd..1faf1a1 100644
--- a/test/980-redefine-object/redefine_object.cc
+++ b/test/980-redefine-object/redefine_object.cc
@@ -22,7 +22,7 @@
#include "base/macros.h"
#include "jni.h"
#include "jvmti.h"
-#include "ScopedUtfChars.h"
+#include "scoped_utf_chars.h"
// Test infrastructure
#include "jni_binder.h"
diff --git a/test/Android.bp b/test/Android.bp
index 2e8f5bb..40f7edd 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -241,29 +241,24 @@
}
art_cc_defaults {
- name: "libtiagent-defaults",
+ name: "libtiagent-base-defaults",
defaults: ["libartagent-defaults"],
srcs: [
- // This is to get the IsInterpreted native method.
- "common/stack_inspect.cc",
- "common/runtime_state.cc",
- "ti-agent/common_load.cc",
- "ti-agent/common_helper.cc",
+ // These are the ART-independent parts.
+ "ti-agent/agent_startup.cc",
"ti-agent/jni_binder.cc",
"ti-agent/jvmti_helper.cc",
"ti-agent/test_env.cc",
- "901-hello-ti-agent/basics.cc",
+ // This is the list of non-special OnLoad things and excludes BCI and anything that depends
+ // on ART internals.
"903-hello-tagging/tagging.cc",
"904-object-allocation/tracking.cc",
"905-object-free/tracking_free.cc",
"906-iterate-heap/iterate_heap.cc",
"907-get-loaded-classes/get_loaded_classes.cc",
"908-gc-start-finish/gc_callbacks.cc",
- "909-attach-agent/attach.cc",
"910-methods/methods.cc",
"911-get-stack-trace/stack_trace.cc",
- "912-classes/classes.cc",
- "913-heaps/heaps.cc",
"918-fields/fields.cc",
"920-objects/objects.cc",
"922-properties/properties.cc",
@@ -275,11 +270,6 @@
"929-search/search.cc",
"931-agent-thread/agent_thread.cc",
"933-misc-events/misc_events.cc",
- "936-search-onload/search_onload.cc",
- "944-transform-classloaders/classloader.cc",
- "945-obsolete-native/obsolete_native.cc",
- "980-redefine-object/redefine_object.cc",
- "983-source-transform-verify/source_transform.cc",
],
shared_libs: [
"libbase",
@@ -288,6 +278,29 @@
include_dirs: ["art/test/ti-agent"],
}
+art_cc_defaults {
+ name: "libtiagent-defaults",
+ defaults: ["libtiagent-base-defaults"],
+ srcs: [
+ // This is to get the IsInterpreted native method.
+ "common/stack_inspect.cc",
+ "common/runtime_state.cc",
+ // This includes the remaining test functions. We should try to refactor things to
+ // make this list smaller.
+ "ti-agent/common_helper.cc",
+ "ti-agent/common_load.cc",
+ "901-hello-ti-agent/basics.cc",
+ "909-attach-agent/attach.cc",
+ "912-classes/classes.cc",
+ "913-heaps/heaps.cc",
+ "936-search-onload/search_onload.cc",
+ "944-transform-classloaders/classloader.cc",
+ "945-obsolete-native/obsolete_native.cc",
+ "980-redefine-object/redefine_object.cc",
+ "983-source-transform-verify/source_transform.cc",
+ ],
+}
+
art_cc_test_library {
name: "libtiagent",
defaults: ["libtiagent-defaults"],
@@ -303,6 +316,12 @@
shared_libs: ["libartd"],
}
+art_cc_test_library {
+ name: "libctstiagent",
+ defaults: ["libtiagent-base-defaults"],
+ export_include_dirs: ["ti-agent"],
+}
+
cc_defaults {
name: "libarttest-defaults",
defaults: [
diff --git a/test/ti-agent/agent_startup.cc b/test/ti-agent/agent_startup.cc
new file mode 100644
index 0000000..b55db7b
--- /dev/null
+++ b/test/ti-agent/agent_startup.cc
@@ -0,0 +1,95 @@
+/*
+ * 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 "agent_startup.h"
+
+#include "android-base/logging.h"
+#include "android-base/macros.h"
+
+#include "jni_binder.h"
+#include "jvmti_helper.h"
+
+namespace art {
+
+static constexpr const char* kMainClass = "Main";
+
+static StartCallback gCallback = nullptr;
+
+// TODO: Check this. This may not work on device. The classloader containing the app's classes
+// may not have been created at this point (i.e., if it's not the system classloader).
+static void JNICALL VMInitCallback(jvmtiEnv* jvmti_env,
+ JNIEnv* jni_env,
+ jthread thread ATTRIBUTE_UNUSED) {
+ // Bind kMainClass native methods.
+ BindFunctions(jvmti_env, jni_env, kMainClass);
+
+ if (gCallback != nullptr) {
+ gCallback(jvmti_env, jni_env);
+ gCallback = nullptr;
+ }
+
+ // And delete the jvmtiEnv.
+ jvmti_env->DisposeEnvironment();
+}
+
+// Install a phase callback that will bind JNI functions on VMInit.
+void BindOnLoad(JavaVM* vm, StartCallback callback) {
+ // Use a new jvmtiEnv. Otherwise we might collide with table changes.
+ jvmtiEnv* install_env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&install_env), JVMTI_VERSION_1_0) != 0) {
+ LOG(FATAL) << "Could not get jvmtiEnv";
+ }
+ SetAllCapabilities(install_env);
+
+ {
+ jvmtiEventCallbacks callbacks;
+ memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
+ callbacks.VMInit = VMInitCallback;
+
+ CheckJvmtiError(install_env, install_env->SetEventCallbacks(&callbacks, sizeof(callbacks)));
+ }
+
+ CheckJvmtiError(install_env, install_env->SetEventNotificationMode(JVMTI_ENABLE,
+ JVMTI_EVENT_VM_INIT,
+ nullptr));
+
+ gCallback = callback;
+}
+
+// Ensure binding of the Main class when the agent is started through OnAttach.
+void BindOnAttach(JavaVM* vm, StartCallback callback) {
+ // Get a JNIEnv. As the thread is attached, we must not destroy it.
+ JNIEnv* env;
+ CHECK_EQ(0, vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6))
+ << "Could not get JNIEnv";
+
+ jvmtiEnv* jvmti_env;
+ CHECK_EQ(0, vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0))
+ << "Could not get jvmtiEnv";
+ SetAllCapabilities(jvmti_env);
+
+ BindFunctions(jvmti_env, env, kMainClass);
+
+ if (callback != nullptr) {
+ callback(jvmti_env, env);
+ }
+
+ if (jvmti_env->DisposeEnvironment() != JVMTI_ERROR_NONE) {
+ LOG(FATAL) << "Could not dispose temporary jvmtiEnv";
+ }
+}
+
+} // namespace art
diff --git a/test/ti-agent/agent_startup.h b/test/ti-agent/agent_startup.h
new file mode 100644
index 0000000..4963320
--- /dev/null
+++ b/test/ti-agent/agent_startup.h
@@ -0,0 +1,37 @@
+/*
+ * 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_AGENT_STARTUP_H_
+#define ART_TEST_TI_AGENT_AGENT_STARTUP_H_
+
+#include <functional>
+
+#include "jni.h"
+#include "jvmti.h"
+
+namespace art {
+
+using StartCallback = void(*)(jvmtiEnv*, JNIEnv*);
+
+// Ensure binding of the Main class when the agent is started through OnLoad.
+void BindOnLoad(JavaVM* vm, StartCallback callback);
+
+// Ensure binding of the Main class when the agent is started through OnAttach.
+void BindOnAttach(JavaVM* vm, StartCallback callback);
+
+} // namespace art
+
+#endif // ART_TEST_TI_AGENT_AGENT_STARTUP_H_
diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc
index c5d75c9..9e7b75d 100644
--- a/test/ti-agent/common_load.cc
+++ b/test/ti-agent/common_load.cc
@@ -19,6 +19,8 @@
#include "base/logging.h"
#include "base/macros.h"
+
+#include "agent_startup.h"
#include "common_helper.h"
#include "jni_binder.h"
#include "jvmti_helper.h"
@@ -42,45 +44,6 @@
OnAttach attach;
};
-static void JNICALL VMInitCallback(jvmtiEnv *jvmti_env,
- JNIEnv* jni_env,
- jthread thread ATTRIBUTE_UNUSED) {
- // Bind Main native methods.
- BindFunctions(jvmti_env, jni_env, "Main");
-}
-
-// Install a phase callback that will bind JNI functions on VMInit.
-bool InstallBindCallback(JavaVM* vm) {
- // Use a new jvmtiEnv. Otherwise we might collide with table changes.
- jvmtiEnv* install_env;
- if (vm->GetEnv(reinterpret_cast<void**>(&install_env), JVMTI_VERSION_1_0) != 0) {
- return false;
- }
- SetAllCapabilities(install_env);
-
- {
- jvmtiEventCallbacks callbacks;
- memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
- callbacks.VMInit = VMInitCallback;
-
- jvmtiError install_error = install_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
- if (install_error != JVMTI_ERROR_NONE) {
- return false;
- }
- }
-
- {
- jvmtiError enable_error = install_env->SetEventNotificationMode(JVMTI_ENABLE,
- JVMTI_EVENT_VM_INIT,
- nullptr);
- if (enable_error != JVMTI_ERROR_NONE) {
- return false;
- }
- }
-
- return true;
-}
-
// A trivial OnLoad implementation that only initializes the global jvmti_env.
static jint MinimalOnLoad(JavaVM* vm,
char* options ATTRIBUTE_UNUSED,
@@ -156,26 +119,6 @@
SetJVM(strncmp(options, "jvm", 3) == 0);
}
-static bool BindFunctionsAttached(JavaVM* vm, const char* class_name) {
- // Get a JNIEnv. As the thread is attached, we must not destroy it.
- JNIEnv* env;
- if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != 0) {
- printf("Unable to get JNI env!\n");
- return false;
- }
-
- jvmtiEnv* jenv;
- if (vm->GetEnv(reinterpret_cast<void**>(&jenv), JVMTI_VERSION_1_0) != 0) {
- printf("Unable to get jvmti env!\n");
- return false;
- }
- SetAllCapabilities(jenv);
-
- BindFunctions(jenv, env, class_name);
-
- return true;
-}
-
} // namespace
extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
@@ -188,9 +131,7 @@
SetIsJVM(remaining_options);
- if (!InstallBindCallback(vm)) {
- return 1;
- }
+ BindOnLoad(vm, nullptr);
AgentLib* lib = FindAgent(name_option);
OnLoad fn = nullptr;
@@ -214,7 +155,7 @@
return -1;
}
- BindFunctionsAttached(vm, "Main");
+ BindOnAttach(vm, nullptr);
AgentLib* lib = FindAgent(name_option);
if (lib == nullptr) {
diff --git a/test/ti-agent/jni_binder.cc b/test/ti-agent/jni_binder.cc
index efc2af8..b66c2c7 100644
--- a/test/ti-agent/jni_binder.cc
+++ b/test/ti-agent/jni_binder.cc
@@ -26,94 +26,16 @@
#include "jvmti_helper.h"
#include "scoped_local_ref.h"
#include "scoped_utf_chars.h"
+#include "ti_utf.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());
+ size_t char_count = ti::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);
+ uint32_t ch = ti::GetUtf16FromUtf8(&cp);
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) {
result.push_back(ch);
} else if (ch == '.' || ch == '/') {
@@ -125,8 +47,8 @@
} else if (ch == '[') {
result += "_3";
} else {
- const uint16_t leading = GetLeadingUtf16Char(ch);
- const uint32_t trailing = GetTrailingUtf16Char(ch);
+ const uint16_t leading = ti::GetLeadingUtf16Char(ch);
+ const uint32_t trailing = ti::GetTrailingUtf16Char(ch);
android::base::StringAppendF(&result, "_0%04x", leading);
if (trailing != 0) {
diff --git a/test/ti-agent/jni_helper.h b/test/ti-agent/jni_helper.h
index c48b0c0..0cbc634 100644
--- a/test/ti-agent/jni_helper.h
+++ b/test/ti-agent/jni_helper.h
@@ -54,6 +54,19 @@
return ret.release();
}
+inline bool JniThrowNullPointerException(JNIEnv* env, const char* msg) {
+ if (env->ExceptionCheck()) {
+ env->ExceptionClear();
+ }
+
+ ScopedLocalRef<jclass> exc_class(env, env->FindClass("java/lang/NullPointerException"));
+ if (exc_class.get() == nullptr) {
+ return -1;
+ }
+
+ return env->ThrowNew(exc_class.get(), msg) == JNI_OK;
+}
+
} // namespace art
#endif // ART_TEST_TI_AGENT_JNI_HELPER_H_
diff --git a/test/ti-agent/scoped_local_ref.h b/test/ti-agent/scoped_local_ref.h
index 0cd9891..daa1583 100644
--- a/test/ti-agent/scoped_local_ref.h
+++ b/test/ti-agent/scoped_local_ref.h
@@ -35,9 +35,9 @@
reset();
}
- void reset(T ptr = NULL) {
+ void reset(T ptr = nullptr) {
if (ptr != mLocalRef) {
- if (mLocalRef != NULL) {
+ if (mLocalRef != nullptr) {
mEnv->DeleteLocalRef(mLocalRef);
}
mLocalRef = ptr;
@@ -46,7 +46,7 @@
T release() __attribute__((warn_unused_result)) {
T localRef = mLocalRef;
- mLocalRef = NULL;
+ mLocalRef = nullptr;
return localRef;
}
diff --git a/test/ti-agent/scoped_primitive_array.h b/test/ti-agent/scoped_primitive_array.h
new file mode 100644
index 0000000..1649ed9
--- /dev/null
+++ b/test/ti-agent/scoped_primitive_array.h
@@ -0,0 +1,154 @@
+/*
+ * 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_PRIMITIVE_ARRAY_H_
+#define ART_TEST_TI_AGENT_SCOPED_PRIMITIVE_ARRAY_H_
+
+#include "jni.h"
+
+#include "android-base/macros.h"
+
+#include "jni_helper.h"
+
+namespace art {
+
+#ifdef POINTER_TYPE
+#error POINTER_TYPE is defined.
+#else
+#define POINTER_TYPE(T) T* /* NOLINT */
+#endif
+
+#ifdef REFERENCE_TYPE
+#error REFERENCE_TYPE is defined.
+#else
+#define REFERENCE_TYPE(T) T& /* NOLINT */
+#endif
+
+// ScopedBooleanArrayRO, ScopedByteArrayRO, ScopedCharArrayRO, ScopedDoubleArrayRO,
+// ScopedFloatArrayRO, ScopedIntArrayRO, ScopedLongArrayRO, and ScopedShortArrayRO provide
+// convenient read-only access to Java arrays from JNI code. This is cheaper than read-write
+// access and should be used by default.
+#define INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(PRIMITIVE_TYPE, NAME) \
+ class Scoped ## NAME ## ArrayRO { \
+ public: \
+ explicit Scoped ## NAME ## ArrayRO(JNIEnv* env) \
+ : mEnv(env), mJavaArray(nullptr), mRawArray(nullptr), mSize(0) {} \
+ Scoped ## NAME ## ArrayRO(JNIEnv* env, PRIMITIVE_TYPE ## Array javaArray) \
+ : mEnv(env) { \
+ if (javaArray == nullptr) { \
+ mJavaArray = nullptr; \
+ mSize = 0; \
+ mRawArray = nullptr; \
+ JniThrowNullPointerException(env, nullptr); \
+ } else { \
+ reset(javaArray); \
+ } \
+ } \
+ ~Scoped ## NAME ## ArrayRO() { \
+ if (mRawArray != nullptr && mRawArray != mBuffer) { \
+ mEnv->Release ## NAME ## ArrayElements(mJavaArray, mRawArray, JNI_ABORT); \
+ } \
+ } \
+ void reset(PRIMITIVE_TYPE ## Array javaArray) { \
+ mJavaArray = javaArray; \
+ mSize = mEnv->GetArrayLength(mJavaArray); \
+ if (mSize <= kBufferSize) { \
+ mEnv->Get ## NAME ## ArrayRegion(mJavaArray, 0, mSize, mBuffer); \
+ mRawArray = mBuffer; \
+ } else { \
+ mRawArray = mEnv->Get ## NAME ## ArrayElements(mJavaArray, nullptr); \
+ } \
+ } \
+ const PRIMITIVE_TYPE* get() const { return mRawArray; } \
+ PRIMITIVE_TYPE ## Array getJavaArray() const { return mJavaArray; } \
+ const PRIMITIVE_TYPE& operator[](size_t n) const { return mRawArray[n]; } \
+ size_t size() const { return mSize; } \
+ private: \
+ static constexpr jsize kBufferSize = 1024; \
+ JNIEnv* const mEnv; \
+ PRIMITIVE_TYPE ## Array mJavaArray; \
+ POINTER_TYPE(PRIMITIVE_TYPE) mRawArray; \
+ jsize mSize; \
+ PRIMITIVE_TYPE mBuffer[kBufferSize]; \
+ DISALLOW_COPY_AND_ASSIGN(Scoped ## NAME ## ArrayRO); \
+ }
+
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jboolean, Boolean);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jbyte, Byte);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jchar, Char);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jdouble, Double);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jfloat, Float);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jint, Int);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jlong, Long);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jshort, Short);
+
+#undef INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO
+
+// ScopedBooleanArrayRW, ScopedByteArrayRW, ScopedCharArrayRW, ScopedDoubleArrayRW,
+// ScopedFloatArrayRW, ScopedIntArrayRW, ScopedLongArrayRW, and ScopedShortArrayRW provide
+// convenient read-write access to Java arrays from JNI code. These are more expensive,
+// since they entail a copy back onto the Java heap, and should only be used when necessary.
+#define INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(PRIMITIVE_TYPE, NAME) \
+ class Scoped ## NAME ## ArrayRW { \
+ public: \
+ explicit Scoped ## NAME ## ArrayRW(JNIEnv* env) \
+ : mEnv(env), mJavaArray(nullptr), mRawArray(nullptr) {} \
+ Scoped ## NAME ## ArrayRW(JNIEnv* env, PRIMITIVE_TYPE ## Array javaArray) \
+ : mEnv(env), mJavaArray(javaArray), mRawArray(nullptr) { \
+ if (mJavaArray == nullptr) { \
+ JniThrowNullPointerException(env, nullptr); \
+ } else { \
+ mRawArray = mEnv->Get ## NAME ## ArrayElements(mJavaArray, nullptr); \
+ } \
+ } \
+ ~Scoped ## NAME ## ArrayRW() { \
+ if (mRawArray) { \
+ mEnv->Release ## NAME ## ArrayElements(mJavaArray, mRawArray, 0); \
+ } \
+ } \
+ void reset(PRIMITIVE_TYPE ## Array javaArray) { \
+ mJavaArray = javaArray; \
+ mRawArray = mEnv->Get ## NAME ## ArrayElements(mJavaArray, nullptr); \
+ } \
+ const PRIMITIVE_TYPE* get() const { return mRawArray; } \
+ PRIMITIVE_TYPE ## Array getJavaArray() const { return mJavaArray; } \
+ const PRIMITIVE_TYPE& operator[](size_t n) const { return mRawArray[n]; } \
+ POINTER_TYPE(PRIMITIVE_TYPE) get() { return mRawArray; } \
+ REFERENCE_TYPE(PRIMITIVE_TYPE) operator[](size_t n) { return mRawArray[n]; } \
+ size_t size() const { return mEnv->GetArrayLength(mJavaArray); } \
+ private: \
+ JNIEnv* const mEnv; \
+ PRIMITIVE_TYPE ## Array mJavaArray; \
+ POINTER_TYPE(PRIMITIVE_TYPE) mRawArray; \
+ DISALLOW_COPY_AND_ASSIGN(Scoped ## NAME ## ArrayRW); \
+ }
+
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jboolean, Boolean);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jbyte, Byte);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jchar, Char);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jdouble, Double);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jfloat, Float);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jint, Int);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jlong, Long);
+INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jshort, Short);
+
+#undef INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW
+#undef POINTER_TYPE
+#undef REFERENCE_TYPE
+
+} // namespace art
+
+#endif // ART_TEST_TI_AGENT_SCOPED_PRIMITIVE_ARRAY_H_
diff --git a/test/ti-agent/scoped_utf_chars.h b/test/ti-agent/scoped_utf_chars.h
index e8c9a11..422caaf 100644
--- a/test/ti-agent/scoped_utf_chars.h
+++ b/test/ti-agent/scoped_utf_chars.h
@@ -23,6 +23,8 @@
#include "android-base/macros.h"
+#include "jni_helper.h"
+
namespace art {
class ScopedUtfChars {
@@ -30,7 +32,7 @@
ScopedUtfChars(JNIEnv* env, jstring s) : env_(env), string_(s) {
if (s == nullptr) {
utf_chars_ = nullptr;
- // TODO: JniThrowNullPointerException(env, nullptr);
+ JniThrowNullPointerException(env, nullptr);
} else {
utf_chars_ = env->GetStringUTFChars(s, nullptr);
}
diff --git a/test/ti-agent/ti_macros.h b/test/ti-agent/ti_macros.h
new file mode 100644
index 0000000..d913383
--- /dev/null
+++ b/test/ti-agent/ti_macros.h
@@ -0,0 +1,26 @@
+/*
+ * 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_TI_MACROS_H_
+#define ART_TEST_TI_AGENT_TI_MACROS_H_
+
+#include "android-base/macros.h"
+
+#define FINAL final
+#define OVERRIDE override
+#define UNREACHABLE __builtin_unreachable
+
+#endif // ART_TEST_TI_AGENT_TI_MACROS_H_
diff --git a/test/ti-agent/ti_utf.h b/test/ti-agent/ti_utf.h
new file mode 100644
index 0000000..341e106
--- /dev/null
+++ b/test/ti-agent/ti_utf.h
@@ -0,0 +1,196 @@
+/*
+ * 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_TI_UTF_H_
+#define ART_TEST_TI_AGENT_TI_UTF_H_
+
+#include <inttypes.h>
+#include <string.h>
+
+#include "android-base/logging.h"
+
+namespace art {
+namespace ti {
+
+inline 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;
+}
+
+inline uint16_t GetTrailingUtf16Char(uint32_t maybe_pair) {
+ return static_cast<uint16_t>(maybe_pair >> 16);
+}
+
+inline uint16_t GetLeadingUtf16Char(uint32_t maybe_pair) {
+ return static_cast<uint16_t>(maybe_pair & 0x0000FFFF);
+}
+
+inline 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;
+}
+
+inline void ConvertUtf16ToModifiedUtf8(char* utf8_out,
+ size_t byte_count,
+ const uint16_t* utf16_in,
+ size_t char_count) {
+ if (LIKELY(byte_count == char_count)) {
+ // Common case where all characters are ASCII.
+ const uint16_t *utf16_end = utf16_in + char_count;
+ for (const uint16_t *p = utf16_in; p < utf16_end;) {
+ *utf8_out++ = static_cast<char>(*p++);
+ }
+ return;
+ }
+
+ // String contains non-ASCII characters.
+ while (char_count--) {
+ const uint16_t ch = *utf16_in++;
+ if (ch > 0 && ch <= 0x7f) {
+ *utf8_out++ = ch;
+ } else {
+ // Char_count == 0 here implies we've encountered an unpaired
+ // surrogate and we have no choice but to encode it as 3-byte UTF
+ // sequence. Note that unpaired surrogates can occur as a part of
+ // "normal" operation.
+ if ((ch >= 0xd800 && ch <= 0xdbff) && (char_count > 0)) {
+ const uint16_t ch2 = *utf16_in;
+
+ // Check if the other half of the pair is within the expected
+ // range. If it isn't, we will have to emit both "halves" as
+ // separate 3 byte sequences.
+ if (ch2 >= 0xdc00 && ch2 <= 0xdfff) {
+ utf16_in++;
+ char_count--;
+ const uint32_t code_point = (ch << 10) + ch2 - 0x035fdc00;
+ *utf8_out++ = (code_point >> 18) | 0xf0;
+ *utf8_out++ = ((code_point >> 12) & 0x3f) | 0x80;
+ *utf8_out++ = ((code_point >> 6) & 0x3f) | 0x80;
+ *utf8_out++ = (code_point & 0x3f) | 0x80;
+ continue;
+ }
+ }
+
+ if (ch > 0x07ff) {
+ // Three byte encoding.
+ *utf8_out++ = (ch >> 12) | 0xe0;
+ *utf8_out++ = ((ch >> 6) & 0x3f) | 0x80;
+ *utf8_out++ = (ch & 0x3f) | 0x80;
+ } else /*(ch > 0x7f || ch == 0)*/ {
+ // Two byte encoding.
+ *utf8_out++ = (ch >> 6) | 0xc0;
+ *utf8_out++ = (ch & 0x3f) | 0x80;
+ }
+ }
+ }
+}
+
+inline size_t CountUtf8Bytes(const uint16_t* chars, size_t char_count) {
+ size_t result = 0;
+ const uint16_t *end = chars + char_count;
+ while (chars < end) {
+ const uint16_t ch = *chars++;
+ if (LIKELY(ch != 0 && ch < 0x80)) {
+ result++;
+ continue;
+ }
+ if (ch < 0x800) {
+ result += 2;
+ continue;
+ }
+ if (ch >= 0xd800 && ch < 0xdc00) {
+ if (chars < end) {
+ const uint16_t ch2 = *chars;
+ // If we find a properly paired surrogate, we emit it as a 4 byte
+ // UTF sequence. If we find an unpaired leading or trailing surrogate,
+ // we emit it as a 3 byte sequence like would have done earlier.
+ if (ch2 >= 0xdc00 && ch2 < 0xe000) {
+ chars++;
+ result += 4;
+ continue;
+ }
+ }
+ }
+ result += 3;
+ }
+ return result;
+}
+
+} // namespace ti
+} // namespace art
+
+#endif // ART_TEST_TI_AGENT_TI_UTF_H_