xref: /aosp_15_r20/art/test/912-classes/classes.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2013 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 <stdio.h>
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <condition_variable>
20*795d594fSAndroid Build Coastguard Worker #include <mutex>
21*795d594fSAndroid Build Coastguard Worker #include <vector>
22*795d594fSAndroid Build Coastguard Worker 
23*795d594fSAndroid Build Coastguard Worker #include "android-base/macros.h"
24*795d594fSAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
25*795d594fSAndroid Build Coastguard Worker 
26*795d594fSAndroid Build Coastguard Worker #include "jni.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 "jni_helper.h"
31*795d594fSAndroid Build Coastguard Worker #include "jvmti_helper.h"
32*795d594fSAndroid Build Coastguard Worker #include "scoped_local_ref.h"
33*795d594fSAndroid Build Coastguard Worker #include "scoped_utf_chars.h"
34*795d594fSAndroid Build Coastguard Worker #include "test_env.h"
35*795d594fSAndroid Build Coastguard Worker 
36*795d594fSAndroid Build Coastguard Worker namespace art {
37*795d594fSAndroid Build Coastguard Worker namespace Test912Classes {
38*795d594fSAndroid Build Coastguard Worker 
Java_art_Test912_isModifiableClass(JNIEnv * env,jclass Main_klass,jclass klass)39*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912_isModifiableClass(
40*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass Main_klass, jclass klass) {
41*795d594fSAndroid Build Coastguard Worker   jboolean res = JNI_FALSE;
42*795d594fSAndroid Build Coastguard Worker   jvmtiError result = jvmti_env->IsModifiableClass(klass, &res);
43*795d594fSAndroid Build Coastguard Worker   JvmtiErrorToException(env, jvmti_env, result);
44*795d594fSAndroid Build Coastguard Worker   return res;
45*795d594fSAndroid Build Coastguard Worker }
46*795d594fSAndroid Build Coastguard Worker 
Java_art_Test912_getClassSignature(JNIEnv * env,jclass Main_klass,jclass klass)47*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassSignature(
48*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass Main_klass, jclass klass) {
49*795d594fSAndroid Build Coastguard Worker   char* sig;
50*795d594fSAndroid Build Coastguard Worker   char* gen;
51*795d594fSAndroid Build Coastguard Worker   jvmtiError result = jvmti_env->GetClassSignature(klass, &sig, &gen);
52*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, result)) {
53*795d594fSAndroid Build Coastguard Worker     return nullptr;
54*795d594fSAndroid Build Coastguard Worker   }
55*795d594fSAndroid Build Coastguard Worker 
56*795d594fSAndroid Build Coastguard Worker   auto callback = [&](jint i) {
57*795d594fSAndroid Build Coastguard Worker     if (i == 0) {
58*795d594fSAndroid Build Coastguard Worker       return sig == nullptr ? nullptr : env->NewStringUTF(sig);
59*795d594fSAndroid Build Coastguard Worker     } else {
60*795d594fSAndroid Build Coastguard Worker       return gen == nullptr ? nullptr : env->NewStringUTF(gen);
61*795d594fSAndroid Build Coastguard Worker     }
62*795d594fSAndroid Build Coastguard Worker   };
63*795d594fSAndroid Build Coastguard Worker   jobjectArray ret = CreateObjectArray(env, 2, "java/lang/String", callback);
64*795d594fSAndroid Build Coastguard Worker 
65*795d594fSAndroid Build Coastguard Worker   // Need to deallocate the strings.
66*795d594fSAndroid Build Coastguard Worker   if (sig != nullptr) {
67*795d594fSAndroid Build Coastguard Worker     jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(sig));
68*795d594fSAndroid Build Coastguard Worker   }
69*795d594fSAndroid Build Coastguard Worker   if (gen != nullptr) {
70*795d594fSAndroid Build Coastguard Worker     jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(gen));
71*795d594fSAndroid Build Coastguard Worker   }
72*795d594fSAndroid Build Coastguard Worker 
73*795d594fSAndroid Build Coastguard Worker   return ret;
74*795d594fSAndroid Build Coastguard Worker }
75*795d594fSAndroid Build Coastguard Worker 
Java_art_Test912_isInterface(JNIEnv * env,jclass Main_klass,jclass klass)76*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912_isInterface(
77*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass Main_klass, jclass klass) {
78*795d594fSAndroid Build Coastguard Worker   jboolean is_interface = JNI_FALSE;
79*795d594fSAndroid Build Coastguard Worker   jvmtiError result = jvmti_env->IsInterface(klass, &is_interface);
80*795d594fSAndroid Build Coastguard Worker   JvmtiErrorToException(env, jvmti_env, result);
81*795d594fSAndroid Build Coastguard Worker   return is_interface;
82*795d594fSAndroid Build Coastguard Worker }
83*795d594fSAndroid Build Coastguard Worker 
Java_art_Test912_isArrayClass(JNIEnv * env,jclass Main_klass,jclass klass)84*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912_isArrayClass(
85*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass Main_klass, jclass klass) {
86*795d594fSAndroid Build Coastguard Worker   jboolean is_array_class = JNI_FALSE;
87*795d594fSAndroid Build Coastguard Worker   jvmtiError result = jvmti_env->IsArrayClass(klass, &is_array_class);
88*795d594fSAndroid Build Coastguard Worker   JvmtiErrorToException(env, jvmti_env, result);
89*795d594fSAndroid Build Coastguard Worker   return is_array_class;
90*795d594fSAndroid Build Coastguard Worker }
91*795d594fSAndroid Build Coastguard Worker 
Java_art_Test912_getClassModifiers(JNIEnv * env,jclass Main_klass,jclass klass)92*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNICALL Java_art_Test912_getClassModifiers(
93*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass Main_klass, jclass klass) {
94*795d594fSAndroid Build Coastguard Worker   jint mod;
95*795d594fSAndroid Build Coastguard Worker   jvmtiError result = jvmti_env->GetClassModifiers(klass, &mod);
96*795d594fSAndroid Build Coastguard Worker   JvmtiErrorToException(env, jvmti_env, result);
97*795d594fSAndroid Build Coastguard Worker   return mod;
98*795d594fSAndroid Build Coastguard Worker }
99*795d594fSAndroid Build Coastguard Worker 
Java_art_Test912_getClassFields(JNIEnv * env,jclass Main_klass,jclass klass)100*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassFields(
101*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass Main_klass, jclass klass) {
102*795d594fSAndroid Build Coastguard Worker   jint count = 0;
103*795d594fSAndroid Build Coastguard Worker   jfieldID* fields = nullptr;
104*795d594fSAndroid Build Coastguard Worker   jvmtiError result = jvmti_env->GetClassFields(klass, &count, &fields);
105*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, result)) {
106*795d594fSAndroid Build Coastguard Worker     return nullptr;
107*795d594fSAndroid Build Coastguard Worker   }
108*795d594fSAndroid Build Coastguard Worker 
109*795d594fSAndroid Build Coastguard Worker   auto callback = [&](jint i) {
110*795d594fSAndroid Build Coastguard Worker     jint modifiers;
111*795d594fSAndroid Build Coastguard Worker     // Ignore any errors for simplicity.
112*795d594fSAndroid Build Coastguard Worker     jvmti_env->GetFieldModifiers(klass, fields[i], &modifiers);
113*795d594fSAndroid Build Coastguard Worker     constexpr jint kStatic = 0x8;
114*795d594fSAndroid Build Coastguard Worker     return env->ToReflectedField(klass,
115*795d594fSAndroid Build Coastguard Worker                                  fields[i],
116*795d594fSAndroid Build Coastguard Worker                                  (modifiers & kStatic) != 0 ? JNI_TRUE : JNI_FALSE);
117*795d594fSAndroid Build Coastguard Worker   };
118*795d594fSAndroid Build Coastguard Worker   jobjectArray ret = CreateObjectArray(env, count, "java/lang/Object", callback);
119*795d594fSAndroid Build Coastguard Worker   if (fields != nullptr) {
120*795d594fSAndroid Build Coastguard Worker     jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(fields));
121*795d594fSAndroid Build Coastguard Worker   }
122*795d594fSAndroid Build Coastguard Worker   return ret;
123*795d594fSAndroid Build Coastguard Worker }
124*795d594fSAndroid Build Coastguard Worker 
Java_art_Test912_getClassMethods(JNIEnv * env,jclass Main_klass,jclass klass)125*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassMethods(
126*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass Main_klass, jclass klass) {
127*795d594fSAndroid Build Coastguard Worker   jint count = 0;
128*795d594fSAndroid Build Coastguard Worker   jmethodID* methods = nullptr;
129*795d594fSAndroid Build Coastguard Worker   jvmtiError result = jvmti_env->GetClassMethods(klass, &count, &methods);
130*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, result)) {
131*795d594fSAndroid Build Coastguard Worker     return nullptr;
132*795d594fSAndroid Build Coastguard Worker   }
133*795d594fSAndroid Build Coastguard Worker 
134*795d594fSAndroid Build Coastguard Worker   auto callback = [&](jint i) {
135*795d594fSAndroid Build Coastguard Worker     jint modifiers;
136*795d594fSAndroid Build Coastguard Worker     // Ignore any errors for simplicity.
137*795d594fSAndroid Build Coastguard Worker     jvmti_env->GetMethodModifiers(methods[i], &modifiers);
138*795d594fSAndroid Build Coastguard Worker     constexpr jint kStatic = 0x8;
139*795d594fSAndroid Build Coastguard Worker     return env->ToReflectedMethod(klass,
140*795d594fSAndroid Build Coastguard Worker                                   methods[i],
141*795d594fSAndroid Build Coastguard Worker                                   (modifiers & kStatic) != 0 ? JNI_TRUE : JNI_FALSE);
142*795d594fSAndroid Build Coastguard Worker   };
143*795d594fSAndroid Build Coastguard Worker   jobjectArray ret = CreateObjectArray(env, count, "java/lang/Object", callback);
144*795d594fSAndroid Build Coastguard Worker   if (methods != nullptr) {
145*795d594fSAndroid Build Coastguard Worker     jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(methods));
146*795d594fSAndroid Build Coastguard Worker   }
147*795d594fSAndroid Build Coastguard Worker   return ret;
148*795d594fSAndroid Build Coastguard Worker }
149*795d594fSAndroid Build Coastguard Worker 
Java_art_Test912_getImplementedInterfaces(JNIEnv * env,jclass Main_klass,jclass klass)150*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getImplementedInterfaces(
151*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass Main_klass, jclass klass) {
152*795d594fSAndroid Build Coastguard Worker   jint count = 0;
153*795d594fSAndroid Build Coastguard Worker   jclass* classes = nullptr;
154*795d594fSAndroid Build Coastguard Worker   jvmtiError result = jvmti_env->GetImplementedInterfaces(klass, &count, &classes);
155*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, result)) {
156*795d594fSAndroid Build Coastguard Worker     return nullptr;
157*795d594fSAndroid Build Coastguard Worker   }
158*795d594fSAndroid Build Coastguard Worker 
159*795d594fSAndroid Build Coastguard Worker   auto callback = [&](jint i) {
160*795d594fSAndroid Build Coastguard Worker     return classes[i];
161*795d594fSAndroid Build Coastguard Worker   };
162*795d594fSAndroid Build Coastguard Worker   jobjectArray ret = CreateObjectArray(env, count, "java/lang/Class", callback);
163*795d594fSAndroid Build Coastguard Worker   if (classes != nullptr) {
164*795d594fSAndroid Build Coastguard Worker     jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(classes));
165*795d594fSAndroid Build Coastguard Worker   }
166*795d594fSAndroid Build Coastguard Worker   return ret;
167*795d594fSAndroid Build Coastguard Worker }
168*795d594fSAndroid Build Coastguard Worker 
Java_art_Test912_getClassStatus(JNIEnv * env,jclass Main_klass,jclass klass)169*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNICALL Java_art_Test912_getClassStatus(
170*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass Main_klass , jclass klass) {
171*795d594fSAndroid Build Coastguard Worker   jint status;
172*795d594fSAndroid Build Coastguard Worker   jvmtiError result = jvmti_env->GetClassStatus(klass, &status);
173*795d594fSAndroid Build Coastguard Worker   JvmtiErrorToException(env, jvmti_env, result);
174*795d594fSAndroid Build Coastguard Worker   return status;
175*795d594fSAndroid Build Coastguard Worker }
176*795d594fSAndroid Build Coastguard Worker 
Java_art_Test912_getClassLoader(JNIEnv * env,jclass Main_klass,jclass klass)177*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jobject JNICALL Java_art_Test912_getClassLoader(
178*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass Main_klass , jclass klass) {
179*795d594fSAndroid Build Coastguard Worker   jobject classloader;
180*795d594fSAndroid Build Coastguard Worker   jvmtiError result = jvmti_env->GetClassLoader(klass, &classloader);
181*795d594fSAndroid Build Coastguard Worker   JvmtiErrorToException(env, jvmti_env, result);
182*795d594fSAndroid Build Coastguard Worker   return classloader;
183*795d594fSAndroid Build Coastguard Worker }
184*795d594fSAndroid Build Coastguard Worker 
Java_art_Test912_getClassLoaderClasses(JNIEnv * env,jclass Main_klass,jobject jclassloader)185*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassLoaderClasses(
186*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass Main_klass , jobject jclassloader) {
187*795d594fSAndroid Build Coastguard Worker   jint count = 0;
188*795d594fSAndroid Build Coastguard Worker   jclass* classes = nullptr;
189*795d594fSAndroid Build Coastguard Worker   jvmtiError result = jvmti_env->GetClassLoaderClasses(jclassloader, &count, &classes);
190*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, result)) {
191*795d594fSAndroid Build Coastguard Worker     return nullptr;
192*795d594fSAndroid Build Coastguard Worker   }
193*795d594fSAndroid Build Coastguard Worker 
194*795d594fSAndroid Build Coastguard Worker   auto callback = [&](jint i) {
195*795d594fSAndroid Build Coastguard Worker     return classes[i];
196*795d594fSAndroid Build Coastguard Worker   };
197*795d594fSAndroid Build Coastguard Worker   jobjectArray ret = CreateObjectArray(env, count, "java/lang/Class", callback);
198*795d594fSAndroid Build Coastguard Worker   if (classes != nullptr) {
199*795d594fSAndroid Build Coastguard Worker     jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(classes));
200*795d594fSAndroid Build Coastguard Worker   }
201*795d594fSAndroid Build Coastguard Worker   return ret;
202*795d594fSAndroid Build Coastguard Worker }
203*795d594fSAndroid Build Coastguard Worker 
Java_art_Test912_getClassVersion(JNIEnv * env,jclass Main_klass,jclass klass)204*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jintArray JNICALL Java_art_Test912_getClassVersion(
205*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass Main_klass , jclass klass) {
206*795d594fSAndroid Build Coastguard Worker   jint major, minor;
207*795d594fSAndroid Build Coastguard Worker   jvmtiError result = jvmti_env->GetClassVersionNumbers(klass, &minor, &major);
208*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, result)) {
209*795d594fSAndroid Build Coastguard Worker     return nullptr;
210*795d594fSAndroid Build Coastguard Worker   }
211*795d594fSAndroid Build Coastguard Worker 
212*795d594fSAndroid Build Coastguard Worker   jintArray int_array = env->NewIntArray(2);
213*795d594fSAndroid Build Coastguard Worker   if (int_array == nullptr) {
214*795d594fSAndroid Build Coastguard Worker     return nullptr;
215*795d594fSAndroid Build Coastguard Worker   }
216*795d594fSAndroid Build Coastguard Worker   jint buf[2] = { major, minor };
217*795d594fSAndroid Build Coastguard Worker   env->SetIntArrayRegion(int_array, 0, 2, buf);
218*795d594fSAndroid Build Coastguard Worker 
219*795d594fSAndroid Build Coastguard Worker   return int_array;
220*795d594fSAndroid Build Coastguard Worker }
221*795d594fSAndroid Build Coastguard Worker 
GetClassName(jvmtiEnv * jenv,JNIEnv * jni_env,jclass klass)222*795d594fSAndroid Build Coastguard Worker static std::string GetClassName(jvmtiEnv* jenv, JNIEnv* jni_env, jclass klass) {
223*795d594fSAndroid Build Coastguard Worker   char* name;
224*795d594fSAndroid Build Coastguard Worker   jvmtiError result = jenv->GetClassSignature(klass, &name, nullptr);
225*795d594fSAndroid Build Coastguard Worker   if (result != JVMTI_ERROR_NONE) {
226*795d594fSAndroid Build Coastguard Worker     if (jni_env != nullptr) {
227*795d594fSAndroid Build Coastguard Worker       JvmtiErrorToException(jni_env, jenv, result);
228*795d594fSAndroid Build Coastguard Worker     } else {
229*795d594fSAndroid Build Coastguard Worker       printf("Failed to get class signature.\n");
230*795d594fSAndroid Build Coastguard Worker     }
231*795d594fSAndroid Build Coastguard Worker     return "";
232*795d594fSAndroid Build Coastguard Worker   }
233*795d594fSAndroid Build Coastguard Worker 
234*795d594fSAndroid Build Coastguard Worker   std::string tmp(name);
235*795d594fSAndroid Build Coastguard Worker   jenv->Deallocate(reinterpret_cast<unsigned char*>(name));
236*795d594fSAndroid Build Coastguard Worker 
237*795d594fSAndroid Build Coastguard Worker   return tmp;
238*795d594fSAndroid Build Coastguard Worker }
239*795d594fSAndroid Build Coastguard Worker 
240*795d594fSAndroid Build Coastguard Worker static void EnableEvents(JNIEnv* env,
241*795d594fSAndroid Build Coastguard Worker                          jboolean enable,
242*795d594fSAndroid Build Coastguard Worker                          decltype(jvmtiEventCallbacks().ClassLoad) class_load,
243*795d594fSAndroid Build Coastguard Worker                          decltype(jvmtiEventCallbacks().ClassPrepare) class_prepare) {
244*795d594fSAndroid Build Coastguard Worker   if (enable == JNI_FALSE) {
245*795d594fSAndroid Build Coastguard Worker     jvmtiError ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
246*795d594fSAndroid Build Coastguard Worker                                                          JVMTI_EVENT_CLASS_LOAD,
247*795d594fSAndroid Build Coastguard Worker                                                          nullptr);
248*795d594fSAndroid Build Coastguard Worker     if (JvmtiErrorToException(env, jvmti_env, ret)) {
249*795d594fSAndroid Build Coastguard Worker       return;
250*795d594fSAndroid Build Coastguard Worker     }
251*795d594fSAndroid Build Coastguard Worker     ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
252*795d594fSAndroid Build Coastguard Worker                                               JVMTI_EVENT_CLASS_PREPARE,
253*795d594fSAndroid Build Coastguard Worker                                               nullptr);
254*795d594fSAndroid Build Coastguard Worker     JvmtiErrorToException(env, jvmti_env, ret);
255*795d594fSAndroid Build Coastguard Worker     return;
256*795d594fSAndroid Build Coastguard Worker   }
257*795d594fSAndroid Build Coastguard Worker 
258*795d594fSAndroid Build Coastguard Worker   jvmtiEventCallbacks callbacks;
259*795d594fSAndroid Build Coastguard Worker   memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
260*795d594fSAndroid Build Coastguard Worker   callbacks.ClassLoad = class_load;
261*795d594fSAndroid Build Coastguard Worker   callbacks.ClassPrepare = class_prepare;
262*795d594fSAndroid Build Coastguard Worker   jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
263*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, ret)) {
264*795d594fSAndroid Build Coastguard Worker     return;
265*795d594fSAndroid Build Coastguard Worker   }
266*795d594fSAndroid Build Coastguard Worker 
267*795d594fSAndroid Build Coastguard Worker   ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
268*795d594fSAndroid Build Coastguard Worker                                             JVMTI_EVENT_CLASS_LOAD,
269*795d594fSAndroid Build Coastguard Worker                                             nullptr);
270*795d594fSAndroid Build Coastguard Worker   if (JvmtiErrorToException(env, jvmti_env, ret)) {
271*795d594fSAndroid Build Coastguard Worker     return;
272*795d594fSAndroid Build Coastguard Worker   }
273*795d594fSAndroid Build Coastguard Worker   ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
274*795d594fSAndroid Build Coastguard Worker                                             JVMTI_EVENT_CLASS_PREPARE,
275*795d594fSAndroid Build Coastguard Worker                                             nullptr);
276*795d594fSAndroid Build Coastguard Worker   JvmtiErrorToException(env, jvmti_env, ret);
277*795d594fSAndroid Build Coastguard Worker }
278*795d594fSAndroid Build Coastguard Worker 
279*795d594fSAndroid Build Coastguard Worker static std::mutex gEventsMutex;
280*795d594fSAndroid Build Coastguard Worker static std::vector<std::string> gEvents;
281*795d594fSAndroid Build Coastguard Worker 
Java_art_Test912_getClassLoadMessages(JNIEnv * env,jclass Main_klass)282*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassLoadMessages(
283*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass Main_klass) {
284*795d594fSAndroid Build Coastguard Worker   std::lock_guard<std::mutex> guard(gEventsMutex);
285*795d594fSAndroid Build Coastguard Worker   jobjectArray ret = CreateObjectArray(env,
286*795d594fSAndroid Build Coastguard Worker                                        static_cast<jint>(gEvents.size()),
287*795d594fSAndroid Build Coastguard Worker                                        "java/lang/String",
288*795d594fSAndroid Build Coastguard Worker                                        [&](jint i) {
289*795d594fSAndroid Build Coastguard Worker     return env->NewStringUTF(gEvents[i].c_str());
290*795d594fSAndroid Build Coastguard Worker   });
291*795d594fSAndroid Build Coastguard Worker   gEvents.clear();
292*795d594fSAndroid Build Coastguard Worker   return ret;
293*795d594fSAndroid Build Coastguard Worker }
294*795d594fSAndroid Build Coastguard Worker 
295*795d594fSAndroid Build Coastguard Worker class ClassLoadPreparePrinter {
296*795d594fSAndroid Build Coastguard Worker  public:
ClassLoadCallback(jvmtiEnv * jenv,JNIEnv * jni_env,jthread thread,jclass klass)297*795d594fSAndroid Build Coastguard Worker   static void JNICALL ClassLoadCallback(jvmtiEnv* jenv,
298*795d594fSAndroid Build Coastguard Worker                                         JNIEnv* jni_env,
299*795d594fSAndroid Build Coastguard Worker                                         jthread thread,
300*795d594fSAndroid Build Coastguard Worker                                         jclass klass) {
301*795d594fSAndroid Build Coastguard Worker     std::string name = GetClassName(jenv, jni_env, klass);
302*795d594fSAndroid Build Coastguard Worker     if (name == "") {
303*795d594fSAndroid Build Coastguard Worker       return;
304*795d594fSAndroid Build Coastguard Worker     }
305*795d594fSAndroid Build Coastguard Worker     std::string thread_name = GetThreadName(jenv, jni_env, thread);
306*795d594fSAndroid Build Coastguard Worker     if (thread_name == "") {
307*795d594fSAndroid Build Coastguard Worker       return;
308*795d594fSAndroid Build Coastguard Worker     }
309*795d594fSAndroid Build Coastguard Worker     if (thread_name_filter_ != "" && thread_name_filter_ != thread_name) {
310*795d594fSAndroid Build Coastguard Worker       return;
311*795d594fSAndroid Build Coastguard Worker     }
312*795d594fSAndroid Build Coastguard Worker 
313*795d594fSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> guard(gEventsMutex);
314*795d594fSAndroid Build Coastguard Worker     gEvents.push_back(android::base::StringPrintf("Load: %s on %s",
315*795d594fSAndroid Build Coastguard Worker                                                   name.c_str(),
316*795d594fSAndroid Build Coastguard Worker                                                   thread_name.c_str()));
317*795d594fSAndroid Build Coastguard Worker   }
318*795d594fSAndroid Build Coastguard Worker 
ClassPrepareCallback(jvmtiEnv * jenv,JNIEnv * jni_env,jthread thread,jclass klass)319*795d594fSAndroid Build Coastguard Worker   static void JNICALL ClassPrepareCallback(jvmtiEnv* jenv,
320*795d594fSAndroid Build Coastguard Worker                                            JNIEnv* jni_env,
321*795d594fSAndroid Build Coastguard Worker                                            jthread thread,
322*795d594fSAndroid Build Coastguard Worker                                            jclass klass) {
323*795d594fSAndroid Build Coastguard Worker     std::string name = GetClassName(jenv, jni_env, klass);
324*795d594fSAndroid Build Coastguard Worker     if (name == "") {
325*795d594fSAndroid Build Coastguard Worker       return;
326*795d594fSAndroid Build Coastguard Worker     }
327*795d594fSAndroid Build Coastguard Worker     std::string thread_name = GetThreadName(jenv, jni_env, thread);
328*795d594fSAndroid Build Coastguard Worker     if (thread_name == "") {
329*795d594fSAndroid Build Coastguard Worker       return;
330*795d594fSAndroid Build Coastguard Worker     }
331*795d594fSAndroid Build Coastguard Worker     if (thread_name_filter_ != "" && thread_name_filter_ != thread_name) {
332*795d594fSAndroid Build Coastguard Worker       return;
333*795d594fSAndroid Build Coastguard Worker     }
334*795d594fSAndroid Build Coastguard Worker     std::string cur_thread_name = GetThreadName(jenv, jni_env, nullptr);
335*795d594fSAndroid Build Coastguard Worker 
336*795d594fSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> guard(gEventsMutex);
337*795d594fSAndroid Build Coastguard Worker     gEvents.push_back(android::base::StringPrintf("Prepare: %s on %s (cur=%s)",
338*795d594fSAndroid Build Coastguard Worker                                                   name.c_str(),
339*795d594fSAndroid Build Coastguard Worker                                                   thread_name.c_str(),
340*795d594fSAndroid Build Coastguard Worker                                                   cur_thread_name.c_str()));
341*795d594fSAndroid Build Coastguard Worker   }
342*795d594fSAndroid Build Coastguard Worker 
GetThreadName(jvmtiEnv * jenv,JNIEnv * jni_env,jthread thread)343*795d594fSAndroid Build Coastguard Worker   static std::string GetThreadName(jvmtiEnv* jenv, JNIEnv* jni_env, jthread thread) {
344*795d594fSAndroid Build Coastguard Worker     jvmtiThreadInfo info;
345*795d594fSAndroid Build Coastguard Worker     jvmtiError result = jenv->GetThreadInfo(thread, &info);
346*795d594fSAndroid Build Coastguard Worker     if (result != JVMTI_ERROR_NONE) {
347*795d594fSAndroid Build Coastguard Worker       if (jni_env != nullptr) {
348*795d594fSAndroid Build Coastguard Worker         JvmtiErrorToException(jni_env, jenv, result);
349*795d594fSAndroid Build Coastguard Worker       } else {
350*795d594fSAndroid Build Coastguard Worker         printf("Failed to get thread name.\n");
351*795d594fSAndroid Build Coastguard Worker       }
352*795d594fSAndroid Build Coastguard Worker       return "";
353*795d594fSAndroid Build Coastguard Worker     }
354*795d594fSAndroid Build Coastguard Worker 
355*795d594fSAndroid Build Coastguard Worker     std::string tmp(info.name);
356*795d594fSAndroid Build Coastguard Worker     jenv->Deallocate(reinterpret_cast<unsigned char*>(info.name));
357*795d594fSAndroid Build Coastguard Worker     jni_env->DeleteLocalRef(info.context_class_loader);
358*795d594fSAndroid Build Coastguard Worker     jni_env->DeleteLocalRef(info.thread_group);
359*795d594fSAndroid Build Coastguard Worker 
360*795d594fSAndroid Build Coastguard Worker     return tmp;
361*795d594fSAndroid Build Coastguard Worker   }
362*795d594fSAndroid Build Coastguard Worker 
363*795d594fSAndroid Build Coastguard Worker   static std::string thread_name_filter_;
364*795d594fSAndroid Build Coastguard Worker };
365*795d594fSAndroid Build Coastguard Worker std::string ClassLoadPreparePrinter::thread_name_filter_;  // NOLINT [runtime/string] [4]
366*795d594fSAndroid Build Coastguard Worker 
Java_art_Test912_enableClassLoadPreparePrintEvents(JNIEnv * env,jclass Main_klass,jboolean enable,jthread thread)367*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_art_Test912_enableClassLoadPreparePrintEvents(
368*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass Main_klass , jboolean enable, jthread thread) {
369*795d594fSAndroid Build Coastguard Worker   if (thread != nullptr) {
370*795d594fSAndroid Build Coastguard Worker     ClassLoadPreparePrinter::thread_name_filter_ =
371*795d594fSAndroid Build Coastguard Worker         ClassLoadPreparePrinter::GetThreadName(jvmti_env, env, thread);
372*795d594fSAndroid Build Coastguard Worker   } else {
373*795d594fSAndroid Build Coastguard Worker     ClassLoadPreparePrinter::thread_name_filter_ = "";
374*795d594fSAndroid Build Coastguard Worker   }
375*795d594fSAndroid Build Coastguard Worker 
376*795d594fSAndroid Build Coastguard Worker   EnableEvents(env,
377*795d594fSAndroid Build Coastguard Worker                enable,
378*795d594fSAndroid Build Coastguard Worker                ClassLoadPreparePrinter::ClassLoadCallback,
379*795d594fSAndroid Build Coastguard Worker                ClassLoadPreparePrinter::ClassPrepareCallback);
380*795d594fSAndroid Build Coastguard Worker }
381*795d594fSAndroid Build Coastguard Worker 
382*795d594fSAndroid Build Coastguard Worker template<typename T>
RunEventThread(const std::string & name,jvmtiEnv * jvmti,JNIEnv * env,void (* func)(jvmtiEnv *,JNIEnv *,T *),T * data)383*795d594fSAndroid Build Coastguard Worker static jthread RunEventThread(const std::string& name,
384*795d594fSAndroid Build Coastguard Worker                               jvmtiEnv* jvmti,
385*795d594fSAndroid Build Coastguard Worker                               JNIEnv* env,
386*795d594fSAndroid Build Coastguard Worker                               void (*func)(jvmtiEnv*, JNIEnv*, T*),
387*795d594fSAndroid Build Coastguard Worker                               T* data) {
388*795d594fSAndroid Build Coastguard Worker   // Create a Thread object.
389*795d594fSAndroid Build Coastguard Worker   std::string name_str = name;
390*795d594fSAndroid Build Coastguard Worker   name_str += ": JVMTI_THREAD-Test912";
391*795d594fSAndroid Build Coastguard Worker   ScopedLocalRef<jobject> thread_name(env, env->NewStringUTF(name_str.c_str()));
392*795d594fSAndroid Build Coastguard Worker   CHECK(thread_name.get() != nullptr);
393*795d594fSAndroid Build Coastguard Worker 
394*795d594fSAndroid Build Coastguard Worker   ScopedLocalRef<jclass> thread_klass(env, env->FindClass("java/lang/Thread"));
395*795d594fSAndroid Build Coastguard Worker   CHECK(thread_klass.get() != nullptr);
396*795d594fSAndroid Build Coastguard Worker 
397*795d594fSAndroid Build Coastguard Worker   ScopedLocalRef<jobject> thread(env, env->AllocObject(thread_klass.get()));
398*795d594fSAndroid Build Coastguard Worker   CHECK(thread.get() != nullptr);
399*795d594fSAndroid Build Coastguard Worker 
400*795d594fSAndroid Build Coastguard Worker   jmethodID initID = env->GetMethodID(thread_klass.get(), "<init>", "(Ljava/lang/String;)V");
401*795d594fSAndroid Build Coastguard Worker   CHECK(initID != nullptr);
402*795d594fSAndroid Build Coastguard Worker 
403*795d594fSAndroid Build Coastguard Worker   env->CallNonvirtualVoidMethod(thread.get(), thread_klass.get(), initID, thread_name.get());
404*795d594fSAndroid Build Coastguard Worker   CHECK(!env->ExceptionCheck());
405*795d594fSAndroid Build Coastguard Worker 
406*795d594fSAndroid Build Coastguard Worker   // Run agent thread.
407*795d594fSAndroid Build Coastguard Worker   CheckJvmtiError(jvmti, jvmti->RunAgentThread(thread.get(),
408*795d594fSAndroid Build Coastguard Worker                                                reinterpret_cast<jvmtiStartFunction>(func),
409*795d594fSAndroid Build Coastguard Worker                                                reinterpret_cast<void*>(data),
410*795d594fSAndroid Build Coastguard Worker                                                JVMTI_THREAD_NORM_PRIORITY));
411*795d594fSAndroid Build Coastguard Worker   return thread.release();
412*795d594fSAndroid Build Coastguard Worker }
413*795d594fSAndroid Build Coastguard Worker 
JoinTread(JNIEnv * env,jthread thr)414*795d594fSAndroid Build Coastguard Worker static void JoinTread(JNIEnv* env, jthread thr) {
415*795d594fSAndroid Build Coastguard Worker   ScopedLocalRef<jclass> thread_klass(env, env->FindClass("java/lang/Thread"));
416*795d594fSAndroid Build Coastguard Worker   CHECK(thread_klass.get() != nullptr);
417*795d594fSAndroid Build Coastguard Worker 
418*795d594fSAndroid Build Coastguard Worker   jmethodID joinID = env->GetMethodID(thread_klass.get(), "join", "()V");
419*795d594fSAndroid Build Coastguard Worker   CHECK(joinID != nullptr);
420*795d594fSAndroid Build Coastguard Worker 
421*795d594fSAndroid Build Coastguard Worker   env->CallVoidMethod(thr, joinID);
422*795d594fSAndroid Build Coastguard Worker }
423*795d594fSAndroid Build Coastguard Worker 
424*795d594fSAndroid Build Coastguard Worker class ClassLoadPrepareEquality {
425*795d594fSAndroid Build Coastguard Worker  public:
426*795d594fSAndroid Build Coastguard Worker   static constexpr const char* kClassName = "Lart/Test912$ClassE;";
427*795d594fSAndroid Build Coastguard Worker   static constexpr const char* kStorageFieldName = "STATIC";
428*795d594fSAndroid Build Coastguard Worker   static constexpr const char* kStorageFieldSig = "Ljava/lang/Object;";
429*795d594fSAndroid Build Coastguard Worker   static constexpr const char* kStorageWeakFieldName = "WEAK";
430*795d594fSAndroid Build Coastguard Worker   static constexpr const char* kStorageWeakFieldSig = "Ljava/lang/ref/Reference;";
431*795d594fSAndroid Build Coastguard Worker   static constexpr const char* kWeakClassName = "java/lang/ref/WeakReference";
432*795d594fSAndroid Build Coastguard Worker   static constexpr const char* kWeakInitSig = "(Ljava/lang/Object;)V";
433*795d594fSAndroid Build Coastguard Worker   static constexpr const char* kWeakGetSig = "()Ljava/lang/Object;";
434*795d594fSAndroid Build Coastguard Worker 
AgentThreadTest(jvmtiEnv * jvmti,JNIEnv * env,jobject * obj_global)435*795d594fSAndroid Build Coastguard Worker   static void AgentThreadTest([[maybe_unused]] jvmtiEnv* jvmti,
436*795d594fSAndroid Build Coastguard Worker                               JNIEnv* env,
437*795d594fSAndroid Build Coastguard Worker                               jobject* obj_global) {
438*795d594fSAndroid Build Coastguard Worker     jobject target = *obj_global;
439*795d594fSAndroid Build Coastguard Worker     jobject target_local = env->NewLocalRef(target);
440*795d594fSAndroid Build Coastguard Worker     {
441*795d594fSAndroid Build Coastguard Worker       std::unique_lock<std::mutex> lk(mutex_);
442*795d594fSAndroid Build Coastguard Worker       started_ = true;
443*795d594fSAndroid Build Coastguard Worker       cond_started_.notify_all();
444*795d594fSAndroid Build Coastguard Worker       cond_finished_.wait(lk, [] { return finished_; });
445*795d594fSAndroid Build Coastguard Worker       CHECK(finished_);
446*795d594fSAndroid Build Coastguard Worker     }
447*795d594fSAndroid Build Coastguard Worker     CHECK(env->IsSameObject(target, target_local));
448*795d594fSAndroid Build Coastguard Worker   }
449*795d594fSAndroid Build Coastguard Worker 
ClassLoadCallback(jvmtiEnv * jenv,JNIEnv * jni_env,jthread thread,jclass klass)450*795d594fSAndroid Build Coastguard Worker   static void JNICALL ClassLoadCallback(jvmtiEnv* jenv,
451*795d594fSAndroid Build Coastguard Worker                                         JNIEnv* jni_env,
452*795d594fSAndroid Build Coastguard Worker                                         [[maybe_unused]] jthread thread,
453*795d594fSAndroid Build Coastguard Worker                                         jclass klass) {
454*795d594fSAndroid Build Coastguard Worker     std::string name = GetClassName(jenv, jni_env, klass);
455*795d594fSAndroid Build Coastguard Worker     if (name == kClassName) {
456*795d594fSAndroid Build Coastguard Worker       found_ = true;
457*795d594fSAndroid Build Coastguard Worker       stored_class_ = jni_env->NewGlobalRef(klass);
458*795d594fSAndroid Build Coastguard Worker       weakly_stored_class_ = jni_env->NewWeakGlobalRef(klass);
459*795d594fSAndroid Build Coastguard Worker       // Check that we update the local refs.
460*795d594fSAndroid Build Coastguard Worker       agent_thread_ = static_cast<jthread>(jni_env->NewGlobalRef(RunEventThread<jobject>(
461*795d594fSAndroid Build Coastguard Worker           "local-ref", jenv, jni_env, &AgentThreadTest, static_cast<jobject*>(&stored_class_))));
462*795d594fSAndroid Build Coastguard Worker       {
463*795d594fSAndroid Build Coastguard Worker         std::unique_lock<std::mutex> lk(mutex_);
464*795d594fSAndroid Build Coastguard Worker         cond_started_.wait(lk, [] { return started_; });
465*795d594fSAndroid Build Coastguard Worker       }
466*795d594fSAndroid Build Coastguard Worker       // Store the value into a field in the heap.
467*795d594fSAndroid Build Coastguard Worker       SetOrCompare(jni_env, klass, true);
468*795d594fSAndroid Build Coastguard Worker     }
469*795d594fSAndroid Build Coastguard Worker   }
470*795d594fSAndroid Build Coastguard Worker 
ClassPrepareCallback(jvmtiEnv * jenv,JNIEnv * jni_env,jthread thread,jclass klass)471*795d594fSAndroid Build Coastguard Worker   static void JNICALL ClassPrepareCallback(jvmtiEnv* jenv,
472*795d594fSAndroid Build Coastguard Worker                                            JNIEnv* jni_env,
473*795d594fSAndroid Build Coastguard Worker                                            [[maybe_unused]] jthread thread,
474*795d594fSAndroid Build Coastguard Worker                                            jclass klass) {
475*795d594fSAndroid Build Coastguard Worker     std::string name = GetClassName(jenv, jni_env, klass);
476*795d594fSAndroid Build Coastguard Worker     if (name == kClassName) {
477*795d594fSAndroid Build Coastguard Worker       CHECK(stored_class_ != nullptr);
478*795d594fSAndroid Build Coastguard Worker       CHECK(jni_env->IsSameObject(stored_class_, klass));
479*795d594fSAndroid Build Coastguard Worker       CHECK(jni_env->IsSameObject(weakly_stored_class_, klass));
480*795d594fSAndroid Build Coastguard Worker       {
481*795d594fSAndroid Build Coastguard Worker         std::unique_lock<std::mutex> lk(mutex_);
482*795d594fSAndroid Build Coastguard Worker         finished_ = true;
483*795d594fSAndroid Build Coastguard Worker         cond_finished_.notify_all();
484*795d594fSAndroid Build Coastguard Worker       }
485*795d594fSAndroid Build Coastguard Worker       // Look up the value in a field in the heap.
486*795d594fSAndroid Build Coastguard Worker       SetOrCompare(jni_env, klass, false);
487*795d594fSAndroid Build Coastguard Worker       JoinTread(jni_env, agent_thread_);
488*795d594fSAndroid Build Coastguard Worker       compared_ = true;
489*795d594fSAndroid Build Coastguard Worker     }
490*795d594fSAndroid Build Coastguard Worker   }
491*795d594fSAndroid Build Coastguard Worker 
SetOrCompare(JNIEnv * jni_env,jobject value,bool set)492*795d594fSAndroid Build Coastguard Worker   static void SetOrCompare(JNIEnv* jni_env, jobject value, bool set) {
493*795d594fSAndroid Build Coastguard Worker     CHECK(storage_class_ != nullptr);
494*795d594fSAndroid Build Coastguard Worker 
495*795d594fSAndroid Build Coastguard Worker     // Simple direct storage.
496*795d594fSAndroid Build Coastguard Worker     jfieldID field = jni_env->GetStaticFieldID(storage_class_, kStorageFieldName, kStorageFieldSig);
497*795d594fSAndroid Build Coastguard Worker     CHECK(field != nullptr);
498*795d594fSAndroid Build Coastguard Worker 
499*795d594fSAndroid Build Coastguard Worker     if (set) {
500*795d594fSAndroid Build Coastguard Worker       jni_env->SetStaticObjectField(storage_class_, field, value);
501*795d594fSAndroid Build Coastguard Worker       CHECK(!jni_env->ExceptionCheck());
502*795d594fSAndroid Build Coastguard Worker     } else {
503*795d594fSAndroid Build Coastguard Worker       ScopedLocalRef<jobject> stored(jni_env, jni_env->GetStaticObjectField(storage_class_, field));
504*795d594fSAndroid Build Coastguard Worker       CHECK(jni_env->IsSameObject(value, stored.get()));
505*795d594fSAndroid Build Coastguard Worker     }
506*795d594fSAndroid Build Coastguard Worker 
507*795d594fSAndroid Build Coastguard Worker     // Storage as a reference.
508*795d594fSAndroid Build Coastguard Worker     ScopedLocalRef<jclass> weak_ref_class(jni_env, jni_env->FindClass(kWeakClassName));
509*795d594fSAndroid Build Coastguard Worker     CHECK(weak_ref_class.get() != nullptr);
510*795d594fSAndroid Build Coastguard Worker     jfieldID weak_field = jni_env->GetStaticFieldID(storage_class_,
511*795d594fSAndroid Build Coastguard Worker                                                     kStorageWeakFieldName,
512*795d594fSAndroid Build Coastguard Worker                                                     kStorageWeakFieldSig);
513*795d594fSAndroid Build Coastguard Worker     CHECK(weak_field != nullptr);
514*795d594fSAndroid Build Coastguard Worker     if (set) {
515*795d594fSAndroid Build Coastguard Worker       // Create a WeakReference.
516*795d594fSAndroid Build Coastguard Worker       jmethodID weak_init = jni_env->GetMethodID(weak_ref_class.get(), "<init>", kWeakInitSig);
517*795d594fSAndroid Build Coastguard Worker       CHECK(weak_init != nullptr);
518*795d594fSAndroid Build Coastguard Worker       ScopedLocalRef<jobject> weak_obj(jni_env, jni_env->NewObject(weak_ref_class.get(),
519*795d594fSAndroid Build Coastguard Worker                                                                    weak_init,
520*795d594fSAndroid Build Coastguard Worker                                                                    value));
521*795d594fSAndroid Build Coastguard Worker       CHECK(weak_obj.get() != nullptr);
522*795d594fSAndroid Build Coastguard Worker       jni_env->SetStaticObjectField(storage_class_, weak_field, weak_obj.get());
523*795d594fSAndroid Build Coastguard Worker       CHECK(!jni_env->ExceptionCheck());
524*795d594fSAndroid Build Coastguard Worker     } else {
525*795d594fSAndroid Build Coastguard Worker       // Check the reference value.
526*795d594fSAndroid Build Coastguard Worker       jmethodID get_referent = jni_env->GetMethodID(weak_ref_class.get(), "get", kWeakGetSig);
527*795d594fSAndroid Build Coastguard Worker       CHECK(get_referent != nullptr);
528*795d594fSAndroid Build Coastguard Worker       ScopedLocalRef<jobject> weak_obj(jni_env, jni_env->GetStaticObjectField(storage_class_,
529*795d594fSAndroid Build Coastguard Worker                                                                               weak_field));
530*795d594fSAndroid Build Coastguard Worker       CHECK(weak_obj.get() != nullptr);
531*795d594fSAndroid Build Coastguard Worker       ScopedLocalRef<jobject> weak_referent(jni_env, jni_env->CallObjectMethod(weak_obj.get(),
532*795d594fSAndroid Build Coastguard Worker                                                                                get_referent));
533*795d594fSAndroid Build Coastguard Worker       CHECK(weak_referent.get() != nullptr);
534*795d594fSAndroid Build Coastguard Worker       CHECK(jni_env->IsSameObject(value, weak_referent.get()));
535*795d594fSAndroid Build Coastguard Worker     }
536*795d594fSAndroid Build Coastguard Worker   }
537*795d594fSAndroid Build Coastguard Worker 
CheckFound()538*795d594fSAndroid Build Coastguard Worker   static void CheckFound() {
539*795d594fSAndroid Build Coastguard Worker     CHECK(found_);
540*795d594fSAndroid Build Coastguard Worker     CHECK(compared_);
541*795d594fSAndroid Build Coastguard Worker   }
542*795d594fSAndroid Build Coastguard Worker 
Free(JNIEnv * env)543*795d594fSAndroid Build Coastguard Worker   static void Free(JNIEnv* env) {
544*795d594fSAndroid Build Coastguard Worker     if (stored_class_ != nullptr) {
545*795d594fSAndroid Build Coastguard Worker       env->DeleteGlobalRef(stored_class_);
546*795d594fSAndroid Build Coastguard Worker       DCHECK(weakly_stored_class_ != nullptr);
547*795d594fSAndroid Build Coastguard Worker       env->DeleteWeakGlobalRef(weakly_stored_class_);
548*795d594fSAndroid Build Coastguard Worker       // Do not attempt to delete the local ref. It will be out of date by now.
549*795d594fSAndroid Build Coastguard Worker     }
550*795d594fSAndroid Build Coastguard Worker   }
551*795d594fSAndroid Build Coastguard Worker 
552*795d594fSAndroid Build Coastguard Worker   static jclass storage_class_;
553*795d594fSAndroid Build Coastguard Worker 
554*795d594fSAndroid Build Coastguard Worker  private:
555*795d594fSAndroid Build Coastguard Worker   static jobject stored_class_;
556*795d594fSAndroid Build Coastguard Worker   static jweak weakly_stored_class_;
557*795d594fSAndroid Build Coastguard Worker   static jthread agent_thread_;
558*795d594fSAndroid Build Coastguard Worker   static std::mutex mutex_;
559*795d594fSAndroid Build Coastguard Worker   static bool started_;
560*795d594fSAndroid Build Coastguard Worker   static std::condition_variable cond_finished_;
561*795d594fSAndroid Build Coastguard Worker   static bool finished_;
562*795d594fSAndroid Build Coastguard Worker   static std::condition_variable cond_started_;
563*795d594fSAndroid Build Coastguard Worker   static bool found_;
564*795d594fSAndroid Build Coastguard Worker   static bool compared_;
565*795d594fSAndroid Build Coastguard Worker };
566*795d594fSAndroid Build Coastguard Worker 
567*795d594fSAndroid Build Coastguard Worker jclass ClassLoadPrepareEquality::storage_class_ = nullptr;
568*795d594fSAndroid Build Coastguard Worker jobject ClassLoadPrepareEquality::stored_class_ = nullptr;
569*795d594fSAndroid Build Coastguard Worker jweak ClassLoadPrepareEquality::weakly_stored_class_ = nullptr;
570*795d594fSAndroid Build Coastguard Worker jthread ClassLoadPrepareEquality::agent_thread_ = nullptr;
571*795d594fSAndroid Build Coastguard Worker std::mutex ClassLoadPrepareEquality::mutex_;
572*795d594fSAndroid Build Coastguard Worker bool ClassLoadPrepareEquality::started_ = false;
573*795d594fSAndroid Build Coastguard Worker std::condition_variable ClassLoadPrepareEquality::cond_started_;
574*795d594fSAndroid Build Coastguard Worker bool ClassLoadPrepareEquality::finished_ = false;
575*795d594fSAndroid Build Coastguard Worker std::condition_variable ClassLoadPrepareEquality::cond_finished_;
576*795d594fSAndroid Build Coastguard Worker bool ClassLoadPrepareEquality::found_ = false;
577*795d594fSAndroid Build Coastguard Worker bool ClassLoadPrepareEquality::compared_ = false;
578*795d594fSAndroid Build Coastguard Worker 
Java_art_Test912_setEqualityEventStorageClass(JNIEnv * env,jclass Main_klass,jclass klass)579*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_art_Test912_setEqualityEventStorageClass(
580*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass Main_klass, jclass klass) {
581*795d594fSAndroid Build Coastguard Worker   ClassLoadPrepareEquality::storage_class_ =
582*795d594fSAndroid Build Coastguard Worker       reinterpret_cast<jclass>(env->NewGlobalRef(klass));
583*795d594fSAndroid Build Coastguard Worker }
584*795d594fSAndroid Build Coastguard Worker 
Java_art_Test912_enableClassLoadPrepareEqualityEvents(JNIEnv * env,jclass Main_klass,jboolean b)585*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_art_Test912_enableClassLoadPrepareEqualityEvents(
586*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass Main_klass, jboolean b) {
587*795d594fSAndroid Build Coastguard Worker   EnableEvents(env,
588*795d594fSAndroid Build Coastguard Worker                b,
589*795d594fSAndroid Build Coastguard Worker                ClassLoadPrepareEquality::ClassLoadCallback,
590*795d594fSAndroid Build Coastguard Worker                ClassLoadPrepareEquality::ClassPrepareCallback);
591*795d594fSAndroid Build Coastguard Worker   if (b == JNI_FALSE) {
592*795d594fSAndroid Build Coastguard Worker     ClassLoadPrepareEquality::Free(env);
593*795d594fSAndroid Build Coastguard Worker     ClassLoadPrepareEquality::CheckFound();
594*795d594fSAndroid Build Coastguard Worker     env->DeleteGlobalRef(ClassLoadPrepareEquality::storage_class_);
595*795d594fSAndroid Build Coastguard Worker     ClassLoadPrepareEquality::storage_class_ = nullptr;
596*795d594fSAndroid Build Coastguard Worker   }
597*795d594fSAndroid Build Coastguard Worker }
598*795d594fSAndroid Build Coastguard Worker 
599*795d594fSAndroid Build Coastguard Worker // Global to pass information to the ClassPrepare event.
600*795d594fSAndroid Build Coastguard Worker static jobject gRunnableGlobal = nullptr;
Java_art_Test912_runRecursiveClassPrepareEvents(JNIEnv * env,jclass klass,jobject runnable)601*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_art_Test912_runRecursiveClassPrepareEvents(
602*795d594fSAndroid Build Coastguard Worker     JNIEnv* env, [[maybe_unused]] jclass klass, jobject runnable) {
603*795d594fSAndroid Build Coastguard Worker   CHECK(gRunnableGlobal == nullptr);
604*795d594fSAndroid Build Coastguard Worker   gRunnableGlobal = env->NewGlobalRef(runnable);
605*795d594fSAndroid Build Coastguard Worker   EnableEvents(
606*795d594fSAndroid Build Coastguard Worker       env,
607*795d594fSAndroid Build Coastguard Worker       true,
608*795d594fSAndroid Build Coastguard Worker       nullptr,
609*795d594fSAndroid Build Coastguard Worker       []([[maybe_unused]] jvmtiEnv* jenv,
610*795d594fSAndroid Build Coastguard Worker          JNIEnv* jni_env,
611*795d594fSAndroid Build Coastguard Worker          [[maybe_unused]] jthread thread,
612*795d594fSAndroid Build Coastguard Worker          [[maybe_unused]] jclass klass) -> void {
613*795d594fSAndroid Build Coastguard Worker         jclass runnable_class = jni_env->FindClass("java/lang/Runnable");
614*795d594fSAndroid Build Coastguard Worker         jni_env->CallVoidMethod(
615*795d594fSAndroid Build Coastguard Worker             gRunnableGlobal, jni_env->GetMethodID(runnable_class, "run", "()V"));
616*795d594fSAndroid Build Coastguard Worker       });
617*795d594fSAndroid Build Coastguard Worker   jclass runnable_class = env->FindClass("java/lang/Runnable");
618*795d594fSAndroid Build Coastguard Worker   env->CallVoidMethod(
619*795d594fSAndroid Build Coastguard Worker       runnable, env->GetMethodID(runnable_class, "run", "()V"));
620*795d594fSAndroid Build Coastguard Worker   EnableEvents(env, false, nullptr, nullptr);
621*795d594fSAndroid Build Coastguard Worker   env->DeleteGlobalRef(gRunnableGlobal);
622*795d594fSAndroid Build Coastguard Worker   gRunnableGlobal = nullptr;
623*795d594fSAndroid Build Coastguard Worker }
624*795d594fSAndroid Build Coastguard Worker 
625*795d594fSAndroid Build Coastguard Worker }  // namespace Test912Classes
626*795d594fSAndroid Build Coastguard Worker }  // namespace art
627