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