1 /*
2  * Copyright (C) 2019 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 <stdio.h>
18 
19 #include "android-base/macros.h"
20 
21 #include "jni.h"
22 #include "jvmti.h"
23 #include "scoped_local_ref.h"
24 
25 // Test infrastructure
26 #include "jni_helper.h"
27 #include "jvmti_helper.h"
28 #include "test_env.h"
29 
30 namespace art {
31 namespace Test1962MultiThreadEvents {
32 
33 struct BreakpointData {
34   jobject events;
35   jmethodID target;
36 };
cbMethodEntry(jvmtiEnv * jvmti,JNIEnv * env,jthread thread,jmethodID method,jboolean was_exception ATTRIBUTE_UNUSED,jvalue val ATTRIBUTE_UNUSED)37 void cbMethodEntry(jvmtiEnv* jvmti,
38                    JNIEnv* env,
39                    jthread thread,
40                    jmethodID method,
41                    jboolean was_exception ATTRIBUTE_UNUSED,
42                    jvalue val ATTRIBUTE_UNUSED) {
43   BreakpointData* data = nullptr;
44   if (JvmtiErrorToException(
45           env, jvmti, jvmti->GetThreadLocalStorage(thread, reinterpret_cast<void**>(&data)))) {
46     return;
47   }
48   if (data->target != method) {
49     return;
50   }
51   jclass klass = env->FindClass("art/Test1962");
52   jmethodID handler =
53       env->GetStaticMethodID(klass, "HandleEvent", "(Ljava/lang/Thread;Ljava/util/List;)V");
54   CHECK(data != nullptr);
55   env->CallStaticVoidMethod(klass, handler, thread, data->events);
56 }
57 
Java_art_Test1962_setupTest(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED)58 extern "C" JNIEXPORT void JNICALL Java_art_Test1962_setupTest(JNIEnv* env,
59                                                               jclass klass ATTRIBUTE_UNUSED) {
60   jvmtiCapabilities caps{
61     .can_generate_method_exit_events = 1,
62   };
63   if (JvmtiErrorToException(env, jvmti_env, jvmti_env->AddCapabilities(&caps))) {
64     return;
65   }
66   jvmtiEventCallbacks cb{
67     .MethodExit = cbMethodEntry,
68   };
69   JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventCallbacks(&cb, sizeof(cb)));
70 }
71 
Java_art_Test1962_setupThread(JNIEnv * env,jclass klass ATTRIBUTE_UNUSED,jthread thr,jobject events,jobject target)72 extern "C" JNIEXPORT void JNICALL Java_art_Test1962_setupThread(
73     JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr, jobject events, jobject target) {
74   BreakpointData* data = nullptr;
75   if (JvmtiErrorToException(
76           env, jvmti_env, jvmti_env->Allocate(sizeof(*data), reinterpret_cast<uint8_t**>(&data)))) {
77     return;
78   }
79   data->events = env->NewGlobalRef(events);
80   data->target = env->FromReflectedMethod(target);
81   if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
82     return;
83   }
84   JvmtiErrorToException(
85       env,
86       jvmti_env,
87       jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_METHOD_EXIT, thr));
88 }
89 
90 }  // namespace Test1962MultiThreadEvents
91 }  // namespace art
92