xref: /aosp_15_r20/art/test/ti-agent/monitors_helper.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2017 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 "jni.h"
18*795d594fSAndroid Build Coastguard Worker #include "jvmti.h"
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include <vector>
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker #include "jvmti_helper.h"
23*795d594fSAndroid Build Coastguard Worker #include "jni_helper.h"
24*795d594fSAndroid Build Coastguard Worker #include "test_env.h"
25*795d594fSAndroid Build Coastguard Worker #include "scoped_local_ref.h"
26*795d594fSAndroid Build Coastguard Worker 
27*795d594fSAndroid Build Coastguard Worker namespace art {
28*795d594fSAndroid Build Coastguard Worker namespace common_monitors {
29*795d594fSAndroid Build Coastguard Worker 
Java_art_Monitors_getCurrentContendedMonitor(JNIEnv * env,jclass,jthread thr)30*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jobject JNICALL Java_art_Monitors_getCurrentContendedMonitor(
31*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, jclass, jthread thr) {
32*795d594fSAndroid Build Coastguard Worker   jobject out = nullptr;
33*795d594fSAndroid Build Coastguard Worker   JvmtiErrorToException(env, jvmti_env, jvmti_env->GetCurrentContendedMonitor(thr, &out));
34*795d594fSAndroid Build Coastguard Worker   return out;
35*795d594fSAndroid Build Coastguard Worker }
36*795d594fSAndroid Build Coastguard Worker 
Java_art_Monitors_getObjectMonitorUsage(JNIEnv * env,jclass,jobject obj)37*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jobject JNICALL Java_art_Monitors_getObjectMonitorUsage(
38*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, jclass, jobject obj) {
39*795d594fSAndroid Build Coastguard Worker   ScopedLocalRef<jclass> klass(env, env->FindClass("art/Monitors$MonitorUsage"));
40*795d594fSAndroid Build Coastguard Worker   if (env->ExceptionCheck()) {
41*795d594fSAndroid Build Coastguard Worker     return nullptr;
42*795d594fSAndroid Build Coastguard Worker   }
43*795d594fSAndroid Build Coastguard Worker   jmethodID constructor = env->GetMethodID(
44*795d594fSAndroid Build Coastguard Worker       klass.get(),
45*795d594fSAndroid Build Coastguard Worker       "<init>",
46*795d594fSAndroid Build Coastguard Worker       "(Ljava/lang/Object;Ljava/lang/Thread;I[Ljava/lang/Thread;[Ljava/lang/Thread;)V");
47*795d594fSAndroid Build Coastguard Worker   if (env->ExceptionCheck()) {
48*795d594fSAndroid Build Coastguard Worker     return nullptr;
49*795d594fSAndroid Build Coastguard Worker   }
50*795d594fSAndroid Build Coastguard Worker   jvmtiMonitorUsage usage;
51*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetObjectMonitorUsage(obj, &usage))) {
52*795d594fSAndroid Build Coastguard Worker     return nullptr;
53*795d594fSAndroid Build Coastguard Worker   }
54*795d594fSAndroid Build Coastguard Worker   jobjectArray wait = CreateObjectArray(env, usage.waiter_count, "java/lang/Thread",
55*795d594fSAndroid Build Coastguard Worker                                         [&](jint i) { return usage.waiters[i]; });
56*795d594fSAndroid Build Coastguard Worker   if (env->ExceptionCheck()) {
57*795d594fSAndroid Build Coastguard Worker     jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(usage.waiters));
58*795d594fSAndroid Build Coastguard Worker     jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(usage.notify_waiters));
59*795d594fSAndroid Build Coastguard Worker     return nullptr;
60*795d594fSAndroid Build Coastguard Worker   }
61*795d594fSAndroid Build Coastguard Worker   jobjectArray notify_wait = CreateObjectArray(env, usage.notify_waiter_count, "java/lang/Thread",
62*795d594fSAndroid Build Coastguard Worker                                                [&](jint i) { return usage.notify_waiters[i]; });
63*795d594fSAndroid Build Coastguard Worker   if (env->ExceptionCheck()) {
64*795d594fSAndroid Build Coastguard Worker     jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(usage.waiters));
65*795d594fSAndroid Build Coastguard Worker     jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(usage.notify_waiters));
66*795d594fSAndroid Build Coastguard Worker     return nullptr;
67*795d594fSAndroid Build Coastguard Worker   }
68*795d594fSAndroid Build Coastguard Worker   return env->NewObject(klass.get(), constructor,
69*795d594fSAndroid Build Coastguard Worker                         obj, usage.owner, usage.entry_count, wait, notify_wait);
70*795d594fSAndroid Build Coastguard Worker }
71*795d594fSAndroid Build Coastguard Worker 
72*795d594fSAndroid Build Coastguard Worker struct MonitorsData {
73*795d594fSAndroid Build Coastguard Worker   jclass test_klass;
74*795d594fSAndroid Build Coastguard Worker   jmethodID monitor_enter;
75*795d594fSAndroid Build Coastguard Worker   jmethodID monitor_entered;
76*795d594fSAndroid Build Coastguard Worker   jmethodID monitor_wait;
77*795d594fSAndroid Build Coastguard Worker   jmethodID monitor_waited;
78*795d594fSAndroid Build Coastguard Worker   jclass monitor_klass;
79*795d594fSAndroid Build Coastguard Worker };
80*795d594fSAndroid Build Coastguard Worker 
monitorEnterCB(jvmtiEnv * jvmti,JNIEnv * jnienv,jthread thr,jobject obj)81*795d594fSAndroid Build Coastguard Worker static void monitorEnterCB(jvmtiEnv* jvmti,
82*795d594fSAndroid Build Coastguard Worker                            JNIEnv* jnienv,
83*795d594fSAndroid Build Coastguard Worker                            jthread thr,
84*795d594fSAndroid Build Coastguard Worker                            jobject obj) {
85*795d594fSAndroid Build Coastguard Worker   MonitorsData* data = nullptr;
86*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(jnienv, jvmti,
87*795d594fSAndroid Build Coastguard Worker                             jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
88*795d594fSAndroid Build Coastguard Worker     return;
89*795d594fSAndroid Build Coastguard Worker   }
90*795d594fSAndroid Build Coastguard Worker   if (!jnienv->IsInstanceOf(obj, data->monitor_klass)) {
91*795d594fSAndroid Build Coastguard Worker     return;
92*795d594fSAndroid Build Coastguard Worker   }
93*795d594fSAndroid Build Coastguard Worker   jnienv->CallStaticVoidMethod(data->test_klass, data->monitor_enter, thr, obj);
94*795d594fSAndroid Build Coastguard Worker }
monitorEnteredCB(jvmtiEnv * jvmti,JNIEnv * jnienv,jthread thr,jobject obj)95*795d594fSAndroid Build Coastguard Worker static void monitorEnteredCB(jvmtiEnv* jvmti,
96*795d594fSAndroid Build Coastguard Worker                              JNIEnv* jnienv,
97*795d594fSAndroid Build Coastguard Worker                              jthread thr,
98*795d594fSAndroid Build Coastguard Worker                              jobject obj) {
99*795d594fSAndroid Build Coastguard Worker   MonitorsData* data = nullptr;
100*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(jnienv, jvmti,
101*795d594fSAndroid Build Coastguard Worker                             jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
102*795d594fSAndroid Build Coastguard Worker     return;
103*795d594fSAndroid Build Coastguard Worker   }
104*795d594fSAndroid Build Coastguard Worker   if (!jnienv->IsInstanceOf(obj, data->monitor_klass)) {
105*795d594fSAndroid Build Coastguard Worker     return;
106*795d594fSAndroid Build Coastguard Worker   }
107*795d594fSAndroid Build Coastguard Worker   jnienv->CallStaticVoidMethod(data->test_klass, data->monitor_entered, thr, obj);
108*795d594fSAndroid Build Coastguard Worker }
monitorWaitCB(jvmtiEnv * jvmti,JNIEnv * jnienv,jthread thr,jobject obj,jlong timeout)109*795d594fSAndroid Build Coastguard Worker static void monitorWaitCB(jvmtiEnv* jvmti,
110*795d594fSAndroid Build Coastguard Worker                           JNIEnv* jnienv,
111*795d594fSAndroid Build Coastguard Worker                           jthread thr,
112*795d594fSAndroid Build Coastguard Worker                           jobject obj,
113*795d594fSAndroid Build Coastguard Worker                           jlong timeout) {
114*795d594fSAndroid Build Coastguard Worker   MonitorsData* data = nullptr;
115*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(jnienv, jvmti,
116*795d594fSAndroid Build Coastguard Worker                             jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
117*795d594fSAndroid Build Coastguard Worker     return;
118*795d594fSAndroid Build Coastguard Worker   }
119*795d594fSAndroid Build Coastguard Worker   if (!jnienv->IsInstanceOf(obj, data->monitor_klass)) {
120*795d594fSAndroid Build Coastguard Worker     return;
121*795d594fSAndroid Build Coastguard Worker   }
122*795d594fSAndroid Build Coastguard Worker   jnienv->CallStaticVoidMethod(data->test_klass, data->monitor_wait, thr, obj, timeout);
123*795d594fSAndroid Build Coastguard Worker }
monitorWaitedCB(jvmtiEnv * jvmti,JNIEnv * jnienv,jthread thr,jobject obj,jboolean timed_out)124*795d594fSAndroid Build Coastguard Worker static void monitorWaitedCB(jvmtiEnv* jvmti,
125*795d594fSAndroid Build Coastguard Worker                             JNIEnv* jnienv,
126*795d594fSAndroid Build Coastguard Worker                             jthread thr,
127*795d594fSAndroid Build Coastguard Worker                             jobject obj,
128*795d594fSAndroid Build Coastguard Worker                             jboolean timed_out) {
129*795d594fSAndroid Build Coastguard Worker   MonitorsData* data = nullptr;
130*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(jnienv, jvmti,
131*795d594fSAndroid Build Coastguard Worker                             jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
132*795d594fSAndroid Build Coastguard Worker     return;
133*795d594fSAndroid Build Coastguard Worker   }
134*795d594fSAndroid Build Coastguard Worker   if (!jnienv->IsInstanceOf(obj, data->monitor_klass)) {
135*795d594fSAndroid Build Coastguard Worker     return;
136*795d594fSAndroid Build Coastguard Worker   }
137*795d594fSAndroid Build Coastguard Worker   jnienv->CallStaticVoidMethod(data->test_klass, data->monitor_waited, thr, obj, timed_out);
138*795d594fSAndroid Build Coastguard Worker }
139*795d594fSAndroid Build Coastguard Worker 
Java_art_Monitors_setupMonitorEvents(JNIEnv * env,jclass,jclass test_klass,jobject monitor_enter,jobject monitor_entered,jobject monitor_wait,jobject monitor_waited,jclass monitor_klass,jthread thr)140*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_art_Monitors_setupMonitorEvents(
141*795d594fSAndroid Build Coastguard Worker     JNIEnv* env,
142*795d594fSAndroid Build Coastguard Worker     jclass,
143*795d594fSAndroid Build Coastguard Worker     jclass test_klass,
144*795d594fSAndroid Build Coastguard Worker     jobject monitor_enter,
145*795d594fSAndroid Build Coastguard Worker     jobject monitor_entered,
146*795d594fSAndroid Build Coastguard Worker     jobject monitor_wait,
147*795d594fSAndroid Build Coastguard Worker     jobject monitor_waited,
148*795d594fSAndroid Build Coastguard Worker     jclass monitor_klass,
149*795d594fSAndroid Build Coastguard Worker     jthread thr) {
150*795d594fSAndroid Build Coastguard Worker   MonitorsData* data = nullptr;
151*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env,
152*795d594fSAndroid Build Coastguard Worker                             jvmti_env,
153*795d594fSAndroid Build Coastguard Worker                             jvmti_env->Allocate(sizeof(MonitorsData),
154*795d594fSAndroid Build Coastguard Worker                                                 reinterpret_cast<unsigned char**>(&data)))) {
155*795d594fSAndroid Build Coastguard Worker     return;
156*795d594fSAndroid Build Coastguard Worker   }
157*795d594fSAndroid Build Coastguard Worker   jvmtiCapabilities caps;
158*795d594fSAndroid Build Coastguard Worker   memset(&caps, 0, sizeof(caps));
159*795d594fSAndroid Build Coastguard Worker   caps.can_generate_monitor_events = 1;
160*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, jvmti_env->AddCapabilities(&caps))) {
161*795d594fSAndroid Build Coastguard Worker     return;
162*795d594fSAndroid Build Coastguard Worker   }
163*795d594fSAndroid Build Coastguard Worker 
164*795d594fSAndroid Build Coastguard Worker   memset(data, 0, sizeof(MonitorsData));
165*795d594fSAndroid Build Coastguard Worker   data->test_klass = reinterpret_cast<jclass>(env->NewGlobalRef(test_klass));
166*795d594fSAndroid Build Coastguard Worker   data->monitor_enter = env->FromReflectedMethod(monitor_enter);
167*795d594fSAndroid Build Coastguard Worker   data->monitor_entered = env->FromReflectedMethod(monitor_entered);
168*795d594fSAndroid Build Coastguard Worker   data->monitor_wait = env->FromReflectedMethod(monitor_wait);
169*795d594fSAndroid Build Coastguard Worker   data->monitor_waited = env->FromReflectedMethod(monitor_waited);
170*795d594fSAndroid Build Coastguard Worker   data->monitor_klass = reinterpret_cast<jclass>(env->NewGlobalRef(monitor_klass));
171*795d594fSAndroid Build Coastguard Worker   MonitorsData* old_data = nullptr;
172*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env,
173*795d594fSAndroid Build Coastguard Worker                             jvmti_env->GetEnvironmentLocalStorage(
174*795d594fSAndroid Build Coastguard Worker                                 reinterpret_cast<void**>(&old_data)))) {
175*795d594fSAndroid Build Coastguard Worker     return;
176*795d594fSAndroid Build Coastguard Worker   } else if (old_data != nullptr && old_data->test_klass != nullptr) {
177*795d594fSAndroid Build Coastguard Worker     ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
178*795d594fSAndroid Build Coastguard Worker     env->ThrowNew(rt_exception.get(), "Environment already has local storage set!");
179*795d594fSAndroid Build Coastguard Worker     return;
180*795d594fSAndroid Build Coastguard Worker   }
181*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEnvironmentLocalStorage(data))) {
182*795d594fSAndroid Build Coastguard Worker     return;
183*795d594fSAndroid Build Coastguard Worker   }
184*795d594fSAndroid Build Coastguard Worker 
185*795d594fSAndroid Build Coastguard Worker   current_callbacks.MonitorContendedEnter = monitorEnterCB;
186*795d594fSAndroid Build Coastguard Worker   current_callbacks.MonitorContendedEntered = monitorEnteredCB;
187*795d594fSAndroid Build Coastguard Worker   current_callbacks.MonitorWait = monitorWaitCB;
188*795d594fSAndroid Build Coastguard Worker   current_callbacks.MonitorWaited = monitorWaitedCB;
189*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env,
190*795d594fSAndroid Build Coastguard Worker                             jvmti_env,
191*795d594fSAndroid Build Coastguard Worker                             jvmti_env->SetEventCallbacks(&current_callbacks,
192*795d594fSAndroid Build Coastguard Worker                                                          sizeof(current_callbacks)))) {
193*795d594fSAndroid Build Coastguard Worker     return;
194*795d594fSAndroid Build Coastguard Worker   }
195*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env,
196*795d594fSAndroid Build Coastguard Worker                             jvmti_env,
197*795d594fSAndroid Build Coastguard Worker                             jvmti_env->SetEventNotificationMode(
198*795d594fSAndroid Build Coastguard Worker                                 JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, thr))) {
199*795d594fSAndroid Build Coastguard Worker     return;
200*795d594fSAndroid Build Coastguard Worker   }
201*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env,
202*795d594fSAndroid Build Coastguard Worker                             jvmti_env,
203*795d594fSAndroid Build Coastguard Worker                             jvmti_env->SetEventNotificationMode(
204*795d594fSAndroid Build Coastguard Worker                                 JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, thr))) {
205*795d594fSAndroid Build Coastguard Worker     return;
206*795d594fSAndroid Build Coastguard Worker   }
207*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env,
208*795d594fSAndroid Build Coastguard Worker                             jvmti_env,
209*795d594fSAndroid Build Coastguard Worker                             jvmti_env->SetEventNotificationMode(
210*795d594fSAndroid Build Coastguard Worker                                 JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAIT, thr))) {
211*795d594fSAndroid Build Coastguard Worker     return;
212*795d594fSAndroid Build Coastguard Worker   }
213*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env,
214*795d594fSAndroid Build Coastguard Worker                             jvmti_env,
215*795d594fSAndroid Build Coastguard Worker                             jvmti_env->SetEventNotificationMode(
216*795d594fSAndroid Build Coastguard Worker                                 JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAITED, thr))) {
217*795d594fSAndroid Build Coastguard Worker     return;
218*795d594fSAndroid Build Coastguard Worker   }
219*795d594fSAndroid Build Coastguard Worker }
220*795d594fSAndroid Build Coastguard Worker 
221*795d594fSAndroid Build Coastguard Worker }  // namespace common_monitors
222*795d594fSAndroid Build Coastguard Worker }  // namespace art
223*795d594fSAndroid Build Coastguard Worker 
224