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 35namespace art { 36namespace Test1919VMInitThreadStart { 37 38struct EventData { 39 std::string event; 40 jobject data; 41}; 42 43struct EventList { 44 jrawMonitorID events_mutex; 45 std::vector<EventData> events; 46}; 47 48 49static void EnableEvent(jvmtiEnv* env, jvmtiEvent evt) { 50 jvmtiError error = env->SetEventNotificationMode(JVMTI_ENABLE, evt, nullptr); 51 if (error != JVMTI_ERROR_NONE) { 52 printf("Failed to enable event"); 53 } 54} 55 56static void JNICALL ThreadStartCallback(jvmtiEnv *jvmti, JNIEnv* env, jthread thread) { 57 EventList* list = nullptr; 58 CheckJvmtiError(jvmti, jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&list))); 59 CheckJvmtiError(jvmti, jvmti->RawMonitorEnter(list->events_mutex)); 60 list->events.push_back({ "ThreadStart", env->NewGlobalRef(thread) }); 61 CheckJvmtiError(jvmti, jvmti->RawMonitorExit(list->events_mutex)); 62} 63 64static void JNICALL Test1919AgentThread(jvmtiEnv* jvmti, 65 JNIEnv* env, 66 void* arg ATTRIBUTE_UNUSED) { 67 EventList* list = nullptr; 68 CheckJvmtiError(jvmti, jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&list))); 69 CheckJvmtiError(jvmti, jvmti->RawMonitorEnter(list->events_mutex)); 70 jthread cur; 71 CheckJvmtiError(jvmti, jvmti->GetCurrentThread(&cur)); 72 list->events.push_back({ "Test1919AgentThread", env->NewGlobalRef(cur) }); 73 env->DeleteLocalRef(cur); 74 // Wake up VMInit 75 CheckJvmtiError(jvmti, jvmti->RawMonitorNotify(list->events_mutex)); 76 CheckJvmtiError(jvmti, jvmti->RawMonitorExit(list->events_mutex)); 77} 78 79static void CreateAgentThread(jvmtiEnv* jvmti, JNIEnv* env) { 80 // Create a Thread object. 81 ScopedLocalRef<jobject> thread_name(env, env->NewStringUTF("JVMTI_THREAD-Test1919")); 82 CHECK(thread_name.get() != nullptr); 83 84 ScopedLocalRef<jclass> thread_klass(env, env->FindClass("java/lang/Thread")); 85 CHECK(thread_klass.get() != nullptr); 86 87 ScopedLocalRef<jobject> thread(env, env->AllocObject(thread_klass.get())); 88 CHECK(thread.get() != nullptr); 89 90 jmethodID initID = env->GetMethodID(thread_klass.get(), "<init>", "(Ljava/lang/String;)V"); 91 CHECK(initID != nullptr); 92 93 env->CallNonvirtualVoidMethod(thread.get(), thread_klass.get(), initID, thread_name.get()); 94 CHECK(!env->ExceptionCheck()); 95 96 // Run agent thread. 97 CheckJvmtiError(jvmti, jvmti->RunAgentThread(thread.get(), 98 Test1919AgentThread, 99 nullptr, 100 JVMTI_THREAD_NORM_PRIORITY)); 101} 102 103static void JNICALL VMInitCallback(jvmtiEnv *jvmti, JNIEnv* env, jthread thread) { 104 EventList* list = nullptr; 105 CheckJvmtiError(jvmti, jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&list))); 106 CheckJvmtiError(jvmti, jvmti->RawMonitorEnter(list->events_mutex)); 107 list->events.push_back({ "VMInit", env->NewGlobalRef(thread) }); 108 // Create a new thread. 109 CreateAgentThread(jvmti, env); 110 // Wait for new thread to run. 111 CheckJvmtiError(jvmti, jvmti->RawMonitorWait(list->events_mutex, 0)); 112 CheckJvmtiError(jvmti, jvmti->RawMonitorExit(list->events_mutex)); 113} 114 115static void InstallVMEvents(jvmtiEnv* env) { 116 jvmtiEventCallbacks callbacks; 117 memset(&callbacks, 0, sizeof(jvmtiEventCallbacks)); 118 callbacks.VMInit = VMInitCallback; 119 callbacks.ThreadStart = ThreadStartCallback; 120 jvmtiError ret = env->SetEventCallbacks(&callbacks, sizeof(callbacks)); 121 if (ret != JVMTI_ERROR_NONE) { 122 printf("Failed to install callbacks"); 123 } 124 125 EnableEvent(env, JVMTI_EVENT_VM_INIT); 126 EnableEvent(env, JVMTI_EVENT_THREAD_START); 127} 128 129static void InstallEventList(jvmtiEnv* env) { 130 EventList* list = nullptr; 131 CheckJvmtiError(env, env->Allocate(sizeof(EventList), reinterpret_cast<unsigned char**>(&list))); 132 memset(list, 0, sizeof(EventList)); 133 CheckJvmtiError(env, env->CreateRawMonitor("Test1919 Monitor", &list->events_mutex)); 134 CheckJvmtiError(env, env->SetEnvironmentLocalStorage(list)); 135} 136 137jint OnLoad(JavaVM* vm, 138 char* options ATTRIBUTE_UNUSED, 139 void* reserved ATTRIBUTE_UNUSED) { 140 if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0) != 0) { 141 printf("Unable to get jvmti env!\n"); 142 return 1; 143 } 144 InstallVMEvents(jvmti_env); 145 InstallEventList(jvmti_env); 146 return 0; 147} 148 149extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test1919_getEventNames(JNIEnv* env, jclass) { 150 EventList* list = nullptr; 151 if (JvmtiErrorToException(env, 152 jvmti_env, 153 jvmti_env->GetEnvironmentLocalStorage( 154 reinterpret_cast<void**>(&list)))) { 155 return nullptr; 156 } 157 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(list->events_mutex))) { 158 return nullptr; 159 } 160 jobjectArray ret = CreateObjectArray(env, list->events.size(), "java/lang/String", 161 [&](jint i) { 162 return env->NewStringUTF(list->events[i].event.c_str()); 163 }); 164 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(list->events_mutex))) { 165 return nullptr; 166 } 167 return ret; 168} 169 170extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test1919_getEventThreads(JNIEnv* env, jclass) { 171 EventList* list = nullptr; 172 if (JvmtiErrorToException(env, 173 jvmti_env, 174 jvmti_env->GetEnvironmentLocalStorage( 175 reinterpret_cast<void**>(&list)))) { 176 return nullptr; 177 } 178 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(list->events_mutex))) { 179 return nullptr; 180 } 181 jobjectArray ret = CreateObjectArray(env, list->events.size(), "java/lang/Thread", 182 [&](jint i) { 183 return env->NewLocalRef(list->events[i].data); 184 }); 185 if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(list->events_mutex))) { 186 return nullptr; 187 } 188 return ret; 189} 190 191} // namespace Test1919VMInitThreadStart 192} // namespace art 193