• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
EnableEvent(jvmtiEnv * env,jvmtiEvent evt)49 static 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 
ThreadStartCallback(jvmtiEnv * jvmti,JNIEnv * env,jthread thread)56 static 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 
Test1919AgentThread(jvmtiEnv * jvmti,JNIEnv * env,void * arg ATTRIBUTE_UNUSED)64 static 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 
CreateAgentThread(jvmtiEnv * jvmti,JNIEnv * env)79 static 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 
VMInitCallback(jvmtiEnv * jvmti,JNIEnv * env,jthread thread)103 static 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 
InstallVMEvents(jvmtiEnv * env)115 static 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 
InstallEventList(jvmtiEnv * env)129 static 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 
OnLoad(JavaVM * vm,char * options ATTRIBUTE_UNUSED,void * reserved ATTRIBUTE_UNUSED)137 jint 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 
Java_art_Test1919_getEventNames(JNIEnv * env,jclass)149 extern "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 
Java_art_Test1919_getEventThreads(JNIEnv * env,jclass)170 extern "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