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