blob: 109c61f05cbf19db966277b9f33e694fb5b8468b [file] [log] [blame]
Alex Light1d8a9742017-08-17 11:12:06 -07001/*
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