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 <algorithm>
21 #include <mutex>
22 #include <vector>
23 
24 #include "android-base/logging.h"
25 #include "jvmti_helper.h"
26 #include "scoped_utf_chars.h"
27 #include "test_env.h"
28 
29 namespace art {
30 
31 static std::mutex gVectorMutex;
32 static std::vector<std::string> gLoadedDescriptors;
33 
GetClassName(jvmtiEnv * jenv,JNIEnv * jni_env,jclass klass)34 static std::string GetClassName(jvmtiEnv* jenv, JNIEnv* jni_env, jclass klass) {
35   char* name;
36   jvmtiError result = jenv->GetClassSignature(klass, &name, nullptr);
37   if (result != JVMTI_ERROR_NONE) {
38     if (jni_env != nullptr) {
39       JvmtiErrorToException(jni_env, jenv, result);
40     } else {
41       printf("Failed to get class signature.\n");
42     }
43     return "";
44   }
45 
46   std::string tmp(name);
47   jenv->Deallocate(reinterpret_cast<unsigned char*>(name));
48 
49   return tmp;
50 }
51 
52 static void EnableEvents(JNIEnv* env,
53                          jboolean enable,
54                          decltype(jvmtiEventCallbacks().ClassLoad) class_load,
55                          decltype(jvmtiEventCallbacks().ClassPrepare) class_prepare) {
56   if (enable == JNI_FALSE) {
57     jvmtiError ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
58                                                          JVMTI_EVENT_CLASS_LOAD,
59                                                          nullptr);
60     if (JvmtiErrorToException(env, jvmti_env, ret)) {
61       return;
62     }
63     ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
64                                               JVMTI_EVENT_CLASS_PREPARE,
65                                               nullptr);
66     JvmtiErrorToException(env, jvmti_env, ret);
67     return;
68   }
69 
70   jvmtiEventCallbacks callbacks;
71   memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
72   callbacks.ClassLoad = class_load;
73   callbacks.ClassPrepare = class_prepare;
74   jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
75   if (JvmtiErrorToException(env, jvmti_env, ret)) {
76     return;
77   }
78 
79   ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
80                                             JVMTI_EVENT_CLASS_LOAD,
81                                             nullptr);
82   if (JvmtiErrorToException(env, jvmti_env, ret)) {
83     return;
84   }
85   ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
86                                             JVMTI_EVENT_CLASS_PREPARE,
87                                             nullptr);
88   JvmtiErrorToException(env, jvmti_env, ret);
89 }
90 
ClassPrepareCallback(jvmtiEnv * jenv,JNIEnv * jni_env,jthread thread ATTRIBUTE_UNUSED,jclass klass)91 static void JNICALL ClassPrepareCallback(jvmtiEnv* jenv,
92                                          JNIEnv* jni_env,
93                                          jthread thread ATTRIBUTE_UNUSED,
94                                          jclass klass) {
95   std::string name = GetClassName(jenv, jni_env, klass);
96   if (name == "") {
97     return;
98   }
99   std::lock_guard<std::mutex> guard(gVectorMutex);
100   gLoadedDescriptors.push_back(name);
101 }
102 
Java_android_jvmti_JvmtiActivity_didSeeLoadOf(JNIEnv * env,jclass Main_klass ATTRIBUTE_UNUSED,jstring descriptor)103 extern "C" JNIEXPORT jboolean JNICALL Java_android_jvmti_JvmtiActivity_didSeeLoadOf(
104     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jstring descriptor) {
105   std::lock_guard<std::mutex> guard(gVectorMutex);
106   ScopedUtfChars str(env, descriptor);
107   std::string tmp = str.c_str();
108   bool found = std::find(gLoadedDescriptors.begin(), gLoadedDescriptors.end(), tmp) !=
109       gLoadedDescriptors.end();
110   return found ? JNI_TRUE : JNI_FALSE;
111 }
112 
Agent_OnLoad(JavaVM * vm,char * options ATTRIBUTE_UNUSED,void * reserved ATTRIBUTE_UNUSED)113 extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm,
114                                                char* options ATTRIBUTE_UNUSED,
115                                                void* reserved ATTRIBUTE_UNUSED) {
116   if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0) != 0) {
117     LOG(FATAL) << "Could not get shared jvmtiEnv";
118   }
119 
120   SetAllCapabilities(jvmti_env);
121   return 0;
122 }
123 
Agent_OnAttach(JavaVM * vm,char * options ATTRIBUTE_UNUSED,void * reserved ATTRIBUTE_UNUSED)124 extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm,
125                                                  char* options ATTRIBUTE_UNUSED,
126                                                  void* reserved ATTRIBUTE_UNUSED) {
127   JNIEnv* env;
128   CHECK_EQ(0, vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6))
129       << "Could not get JNIEnv";
130 
131   if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0) != 0) {
132     LOG(FATAL) << "Could not get shared jvmtiEnv";
133   }
134 
135   SetAllCapabilities(jvmti_env);
136 
137   EnableEvents(env, JNI_TRUE, nullptr, ClassPrepareCallback);
138 
139   return 0;
140 }
141 
142 }  // namespace art
143