/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <jni.h> #include <jvmti.h> #include <algorithm> #include <mutex> #include <vector> #include "android-base/logging.h" #include "jvmti_helper.h" #include "scoped_utf_chars.h" #include "test_env.h" namespace art { static std::mutex gVectorMutex; static std::vector<std::string> gLoadedDescriptors; static std::string GetClassName(jvmtiEnv* jenv, JNIEnv* jni_env, jclass klass) { char* name; jvmtiError result = jenv->GetClassSignature(klass, &name, nullptr); if (result != JVMTI_ERROR_NONE) { if (jni_env != nullptr) { JvmtiErrorToException(jni_env, jenv, result); } else { printf("Failed to get class signature.\n"); } return ""; } std::string tmp(name); jenv->Deallocate(reinterpret_cast<unsigned char*>(name)); return tmp; } static void EnableEvents(JNIEnv* env, jboolean enable, decltype(jvmtiEventCallbacks().ClassLoad) class_load, decltype(jvmtiEventCallbacks().ClassPrepare) class_prepare) { if (enable == JNI_FALSE) { jvmtiError ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_CLASS_LOAD, nullptr); if (JvmtiErrorToException(env, jvmti_env, ret)) { return; } ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_CLASS_PREPARE, nullptr); JvmtiErrorToException(env, jvmti_env, ret); return; } jvmtiEventCallbacks callbacks; memset(&callbacks, 0, sizeof(jvmtiEventCallbacks)); callbacks.ClassLoad = class_load; callbacks.ClassPrepare = class_prepare; jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); if (JvmtiErrorToException(env, jvmti_env, ret)) { return; } ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, nullptr); if (JvmtiErrorToException(env, jvmti_env, ret)) { return; } ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, nullptr); JvmtiErrorToException(env, jvmti_env, ret); } static void JNICALL ClassPrepareCallback(jvmtiEnv* jenv, JNIEnv* jni_env, jthread thread ATTRIBUTE_UNUSED, jclass klass) { std::string name = GetClassName(jenv, jni_env, klass); if (name == "") { return; } std::lock_guard<std::mutex> guard(gVectorMutex); gLoadedDescriptors.push_back(name); } extern "C" JNIEXPORT jboolean JNICALL Java_android_jvmti_JvmtiActivity_didSeeLoadOf( JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jstring descriptor) { std::lock_guard<std::mutex> guard(gVectorMutex); ScopedUtfChars str(env, descriptor); std::string tmp = str.c_str(); bool found = std::find(gLoadedDescriptors.begin(), gLoadedDescriptors.end(), tmp) != gLoadedDescriptors.end(); return found ? JNI_TRUE : JNI_FALSE; } extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options ATTRIBUTE_UNUSED, void* reserved ATTRIBUTE_UNUSED) { if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0) != 0) { LOG(FATAL) << "Could not get shared jvmtiEnv"; } SetAllCapabilities(jvmti_env); return 0; } extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options ATTRIBUTE_UNUSED, void* reserved ATTRIBUTE_UNUSED) { JNIEnv* env; CHECK_EQ(0, vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)) << "Could not get JNIEnv"; if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0) != 0) { LOG(FATAL) << "Could not get shared jvmtiEnv"; } SetAllCapabilities(jvmti_env); EnableEvents(env, JNI_TRUE, nullptr, ClassPrepareCallback); return 0; } } // namespace art