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 "common_helper.h"
     18 
     19 #include "jni.h"
     20 #include "jvmti.h"
     21 
     22 #include "jvmti_helper.h"
     23 #include "scoped_local_ref.h"
     24 #include "test_env.h"
     25 
     26 namespace art {
     27 namespace common_frame_pop {
     28 
     29 struct FramePopData {
     30   jclass test_klass;
     31   jmethodID pop_method;
     32 };
     33 
     34 static void framePopCB(jvmtiEnv* jvmti,
     35                        JNIEnv* jnienv,
     36                        jthread thr,
     37                        jmethodID method ATTRIBUTE_UNUSED,
     38                        jboolean was_popped_by_exception) {
     39   FramePopData* data = nullptr;
     40   if (JvmtiErrorToException(jnienv, jvmti,
     41                             jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
     42     return;
     43   }
     44   jlong location;
     45   jmethodID frame_method;
     46   if (JvmtiErrorToException(jnienv,
     47                             jvmti,
     48                             jvmti->GetFrameLocation(thr, 0, &frame_method, &location))) {
     49     return;
     50   }
     51   CHECK(data->pop_method != nullptr);
     52   jobject method_arg = GetJavaMethod(jvmti, jnienv, frame_method);
     53   jnienv->CallStaticVoidMethod(data->test_klass,
     54                                data->pop_method,
     55                                method_arg,
     56                                was_popped_by_exception,
     57                                location);
     58   jnienv->DeleteLocalRef(method_arg);
     59 }
     60 
     61 extern "C" JNIEXPORT void JNICALL Java_art_FramePop_enableFramePopEvent(
     62     JNIEnv* env, jclass, jclass klass, jobject notify_method, jthread thr) {
     63   FramePopData* data = nullptr;
     64   if (JvmtiErrorToException(env,
     65                             jvmti_env,
     66                             jvmti_env->Allocate(sizeof(FramePopData),
     67                                                 reinterpret_cast<unsigned char**>(&data)))) {
     68     return;
     69   }
     70   memset(data, 0, sizeof(FramePopData));
     71   data->test_klass = reinterpret_cast<jclass>(env->NewGlobalRef(klass));
     72   data->pop_method = env->FromReflectedMethod(notify_method);
     73   if (env->ExceptionCheck()) {
     74     return;
     75   }
     76   void* old_data = nullptr;
     77   if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(&old_data))) {
     78     return;
     79   } else if (old_data != nullptr) {
     80     ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
     81     env->ThrowNew(rt_exception.get(), "Environment already has local storage set!");
     82     return;
     83   }
     84   if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEnvironmentLocalStorage(data))) {
     85     return;
     86   }
     87   jvmtiCapabilities caps;
     88   memset(&caps, 0, sizeof(caps));
     89   caps.can_generate_frame_pop_events = 1;
     90   if (JvmtiErrorToException(env, jvmti_env, jvmti_env->AddCapabilities(&caps))) {
     91     return;
     92   }
     93   current_callbacks.FramePop = framePopCB;
     94   if (JvmtiErrorToException(env,
     95                             jvmti_env,
     96                             jvmti_env->SetEventCallbacks(&current_callbacks,
     97                                                          sizeof(current_callbacks)))) {
     98     return;
     99   }
    100   JvmtiErrorToException(env,
    101                         jvmti_env,
    102                         jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
    103                                                             JVMTI_EVENT_FRAME_POP,
    104                                                             thr));
    105 }
    106 
    107 extern "C" JNIEXPORT jlong JNICALL Java_art_FramePop_makeJvmtiEnvForFramePop(JNIEnv* env, jclass) {
    108   JavaVM* vm;
    109   jvmtiEnv* out_jvmti_env = nullptr;
    110   if (env->GetJavaVM(&vm) != JNI_OK ||
    111       vm->GetEnv(reinterpret_cast<void**>(&out_jvmti_env), JVMTI_VERSION_1_0) != JNI_OK) {
    112     ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
    113     if (rt_exception.get() == nullptr) {
    114       // CNFE should be pending.
    115       return 0L;
    116     }
    117     env->ThrowNew(rt_exception.get(), "Unable to create new jvmti_env");
    118     return 0L;
    119   }
    120   SetAllCapabilities(out_jvmti_env);
    121   return static_cast<jlong>(reinterpret_cast<intptr_t>(out_jvmti_env));
    122 }
    123 
    124 extern "C" JNIEXPORT void JNICALL Java_art_FramePop_notifyFramePop(
    125     JNIEnv* env, jclass, jthread thr, jint depth) {
    126   JvmtiErrorToException(env, jvmti_env, jvmti_env->NotifyFramePop(thr, depth));
    127 }
    128 
    129 }  // namespace common_frame_pop
    130 }  // namespace art
    131 
    132