1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "1919-vminit-thread-start-timing/vminit.h" 18 19 #include <mutex> 20 #include <thread> 21 #include <vector> 22 23 #include <jni.h> 24 #include <stdio.h> 25 #include <string.h> 26 #include "android-base/macros.h" 27 #include "jvmti.h" 28 29 // Test infrastructure 30 #include "scoped_local_ref.h" 31 #include "jvmti_helper.h" 32 #include "jni_helper.h" 33 #include "test_env.h" 34 35 namespace art { 36 namespace Test1919VMInitThreadStart { 37 38 struct EventData { 39 std::string event; 40 jobject data; 41 }; 42 43 struct EventList { 44 jrawMonitorID events_mutex; 45 std::vector<EventData> events; 46 }; 47 48 // The thread we started for testing. 49 static jthread the_thread; 50 51 static void EnableEvent(jvmtiEnv* env, jvmtiEvent evt) { 52 jvmtiError error = env->SetEventNotificationMode(JVMTI_ENABLE, evt, nullptr); 53 if (error != JVMTI_ERROR_NONE) { 54 printf("Failed to enable event"); 55 } 56 } 57 58 static void JNICALL ThreadStartCallback(jvmtiEnv *jvmti, JNIEnv* env, jthread thread) { 59 EventList* list = nullptr; 60 CheckJvmtiError(jvmti, jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&list))); 61 CheckJvmtiError(jvmti, jvmti->RawMonitorEnter(list->events_mutex)); 62 list->events.push_back({ "ThreadStart", env->NewGlobalRef(thread) }); 63 CheckJvmtiError(jvmti, jvmti->RawMonitorExit(list->events_mutex)); 64 } 65 66 static void JNICALL Test1919AgentThread(jvmtiEnv* jvmti, 67 JNIEnv* env, 68 void* arg ATTRIBUTE_UNUSED) { 69 EventList* list = nullptr; 70 CheckJvmtiError(jvmti, jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&list))); 71 CheckJvmtiError(jvmti, jvmti->RawMonitorEnter(list->events_mutex)); 72 jthread cur; 73 CheckJvmtiError(jvmti, jvmti->GetCurrentThread(&cur)); 74 list->events.push_back({ "Test1919AgentThread", env->NewGlobalRef(cur) }); 75 env->DeleteLocalRef(cur); 76 // Wake up VMInit 77 CheckJvmtiError(jvmti, jvmti->RawMonitorNotify(list->events_mutex)); 78 CheckJvmtiError(jvmti, jvmti->RawMonitorExit(list->events_mutex)); 79 } 80 81 static void CreateAgentThread(jvmtiEnv* jvmti, JNIEnv* env) { 82 // Create a Thread object. 83 ScopedLocalRef<jobject> thread_name(env, env->NewStringUTF("JVMTI_THREAD-Test1919")); 84 CHECK(thread_name.get() != nullptr); 85 86 ScopedLocalRef<jclass> thread_klass(env, env->FindClass("java/lang/Thread")); 87 CHECK(thread_klass.get() != nullptr); 88 89 ScopedLocalRef<jobject> thread(env, env->AllocObject(thread_klass.get())); 90 CHECK(thread.get() != nullptr); 91 92 jmethodID initID = env->GetMethodID(thread_klass.get(), "<init>", "(Ljava/lang/String;)V"); 93 CHECK(initID != nullptr); 94 95 env->CallNonvirtualVoidMethod(thread.get(), thread_klass.get(), initID, thread_name.get()); 96 CHECK(!env->ExceptionCheck()); 97 98 // Set the_thread. 99 the_thread = static_cast<jthread>(env->NewGlobalRef(thread.get())); 100 101 // Run agent thread. 102 CheckJvmtiError(jvmti, jvmti->RunAgentThread(thread.get(), 103 Test1919AgentThread, 104 nullptr, 105 JVMTI_THREAD_NORM_PRIORITY)); 106 } 107 108 static void JNICALL VMInitCallback(jvmtiEnv *jvmti, JNIEnv* env, jthread thread) { 109 EventList* list = nullptr; 110 CheckJvmtiError(jvmti, jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&list))); 111 CheckJvmtiError(jvmti, jvmti->RawMonitorEnter(list->events_mutex)); 112 list->events.push_back({ "VMInit", env->NewGlobalRef(thread) }); 113 // Create a new thread. 114 CreateAgentThread(jvmti, env); 115 // Wait for new thread to run. 116 CheckJvmtiError(jvmti, jvmti->RawMonitorWait(list->events_mutex, 0)); 117 CheckJvmtiError(jvmti, jvmti->RawMonitorExit(list->events_mutex)); 118 } 119 120 static void InstallVMEvents(jvmtiEnv* env) { 121 jvmtiEventCallbacks callbacks; 122 memset(&callbacks, 0, sizeof(jvmtiEventCallbacks)); 123 callbacks.VMInit = VMInitCallback; 124 callbacks.ThreadStart = ThreadStartCallback; 125 jvmtiError ret = env->SetEventCallbacks(&callbacks, sizeof(callbacks)); 126 if (ret != JVMTI_ERROR_NONE) { 127 printf("Failed to install callbacks"); 128 } 129 130 EnableEvent(env, JVMTI_EVENT_VM_INIT); 131 EnableEvent(env, JVMTI_EVENT_THREAD_START); 132 } 133 134 static void InstallEventList(jvmtiEnv* env) { 135 EventList* list = nullptr; 136 CheckJvmtiError(env, env->Allocate(sizeof(EventList), reinterpret_cast<unsigned char**>(&list))); 137 memset(list, 0, sizeof(EventList)); 138 CheckJvmtiError(env, env->CreateRawMonitor("Test1919 Monitor", &list->events_mutex)); 139 CheckJvmtiError(env, env->SetEnvironmentLocalStorage(list)); 140 } 141 142 jint OnLoad(JavaVM* vm, 143 char* options ATTRIBUTE_UNUSED, 144 void* reserved ATTRIBUTE_UNUSED) { 145 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0) != 0) { 146 printf("Unable to get jvmti env!\n"); 147 return 1; 148 } 149 InstallVMEvents(jvmti_env); 150 InstallEventList(jvmti_env); 151 return 0; 152 } 153 154 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test1919_getEventNames(JNIEnv* env, jclass) { 155 EventList* list = nullptr; 156 if (JvmtiErrorToException(env, 157 jvmti_env, 158 jvmti_env->GetEnvironmentLocalStorage( 159 reinterpret_cast<void**>(&list)))) { 160 return nullptr; 161 } 162 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(list->events_mutex))) { 163 return nullptr; 164 } 165 jobjectArray ret = CreateObjectArray(env, list->events.size(), "java/lang/String", 166 [&](jint i) { 167 return env->NewStringUTF(list->events[i].event.c_str()); 168 }); 169 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(list->events_mutex))) { 170 return nullptr; 171 } 172 return ret; 173 } 174 175 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test1919_getEventThreads(JNIEnv* env, jclass) { 176 EventList* list = nullptr; 177 if (JvmtiErrorToException(env, 178 jvmti_env, 179 jvmti_env->GetEnvironmentLocalStorage( 180 reinterpret_cast<void**>(&list)))) { 181 return nullptr; 182 } 183 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(list->events_mutex))) { 184 return nullptr; 185 } 186 jobjectArray ret = CreateObjectArray(env, list->events.size(), "java/lang/Thread", 187 [&](jint i) { 188 return env->NewLocalRef(list->events[i].data); 189 }); 190 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(list->events_mutex))) { 191 return nullptr; 192 } 193 return ret; 194 } 195 196 extern "C" JNIEXPORT jthread JNICALL Java_art_Test1919_getTestingThread(JNIEnv*, jclass) { 197 return the_thread; 198 } 199 200 } // namespace Test1919VMInitThreadStart 201 } // namespace art 202