1 /* 2 * Copyright (C) 2013 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 <pthread.h> 18 19 #include <cstdio> 20 #include <iostream> 21 #include <mutex> 22 #include <vector> 23 24 #include "android-base/logging.h" 25 #include "android-base/stringprintf.h" 26 #include "jni.h" 27 #include "jvmti.h" 28 #include "scoped_local_ref.h" 29 #include "scoped_utf_chars.h" 30 31 // Test infrastructure 32 #include "jvmti_helper.h" 33 #include "test_env.h" 34 35 namespace art { 36 namespace Test904ObjectAllocation { 37 38 static JavaVM* vm; 39 40 static std::string GetClassName(JNIEnv* jni_env, jclass cls) { 41 ScopedLocalRef<jclass> class_class(jni_env, jni_env->GetObjectClass(cls)); 42 jmethodID mid = jni_env->GetMethodID(class_class.get(), "getName", "()Ljava/lang/String;"); 43 ScopedLocalRef<jstring> str( 44 jni_env, reinterpret_cast<jstring>(jni_env->CallObjectMethod(cls, mid))); 45 ScopedUtfChars utf_chars(jni_env, str.get()); 46 return utf_chars.c_str(); 47 } 48 49 template <typename T> 50 class ScopedGlobalRef { 51 public: 52 ScopedGlobalRef(JNIEnv* env, T obj) : obj_(env->NewGlobalRef(obj)) {} 53 ScopedGlobalRef(const ScopedGlobalRef<T>& src) noexcept 54 : obj_(GetEnv()->NewGlobalRef(src.obj_)) {} 55 ScopedGlobalRef(ScopedGlobalRef<T>&& src) noexcept : obj_(src.obj_) { 56 src.obj_ = nullptr; 57 } 58 59 ~ScopedGlobalRef() { 60 GetEnv()->DeleteGlobalRef(obj_); 61 } 62 63 T Get(JNIEnv* env) const { 64 return env->NewLocalRef(obj_); 65 } 66 67 private: 68 JNIEnv* GetEnv() const { 69 JNIEnv* env = nullptr; 70 CHECK_EQ(vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6), 0); 71 return env; 72 } 73 74 jobject obj_; 75 }; 76 77 struct EventLog { 78 std::string msg_; 79 ScopedGlobalRef<jthread> thr_; 80 }; 81 82 static std::mutex gEventsMutex; 83 static std::vector<EventLog> gEvents; 84 85 static void JNICALL ObjectAllocated(jvmtiEnv* ti_env ATTRIBUTE_UNUSED, 86 JNIEnv* jni_env, 87 jthread thread, 88 jobject object, 89 jclass object_klass, 90 jlong size) { 91 std::string object_klass_descriptor = GetClassName(jni_env, object_klass); 92 ScopedLocalRef<jclass> object_klass2(jni_env, jni_env->GetObjectClass(object)); 93 std::string object_klass_descriptor2 = GetClassName(jni_env, object_klass2.get()); 94 95 std::lock_guard<std::mutex> guard(gEventsMutex); 96 gEvents.push_back({android::base::StringPrintf("ObjectAllocated type %s/%s size %zu", 97 object_klass_descriptor.c_str(), 98 object_klass_descriptor2.c_str(), 99 static_cast<size_t>(size)), 100 ScopedGlobalRef<jthread>(jni_env, thread)}); 101 } 102 103 extern "C" JNIEXPORT void JNICALL Java_art_Test904_setupObjectAllocCallback( 104 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jboolean enable) { 105 env->GetJavaVM(&vm); 106 jvmtiEventCallbacks callbacks; 107 memset(&callbacks, 0, sizeof(jvmtiEventCallbacks)); 108 callbacks.VMObjectAlloc = enable ? ObjectAllocated : nullptr; 109 110 jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); 111 JvmtiErrorToException(env, jvmti_env, ret); 112 } 113 114 extern "C" JNIEXPORT void JNICALL Java_art_Test904_enableAllocationTracking( 115 JNIEnv* env, jclass, jthread thread, jboolean enable) { 116 jvmtiError ret = jvmti_env->SetEventNotificationMode( 117 enable ? JVMTI_ENABLE : JVMTI_DISABLE, 118 JVMTI_EVENT_VM_OBJECT_ALLOC, 119 thread); 120 JvmtiErrorToException(env, jvmti_env, ret); 121 } 122 123 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test904_getTrackingEventMessages( 124 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jobjectArray threads) { 125 std::lock_guard<std::mutex> guard(gEventsMutex); 126 std::vector<std::string> real_events; 127 std::vector<jthread> thread_lst; 128 jint nthreads = env->GetArrayLength(threads); 129 { 130 env->PushLocalFrame(nthreads + 1); 131 for (jint i = 0; i < nthreads; i++) { 132 thread_lst.push_back(reinterpret_cast<jthread>(env->GetObjectArrayElement(threads, i))); 133 } 134 for (const EventLog& ev : gEvents) { 135 ScopedLocalRef<jthread> thr(env, ev.thr_.Get(env)); 136 for (jthread req_thread : thread_lst) { 137 if (env->IsSameObject(req_thread, thr.get())) { 138 real_events.push_back(ev.msg_); 139 break; 140 } 141 } 142 } 143 env->PopLocalFrame(nullptr); 144 } 145 jobjectArray ret = CreateObjectArray(env, 146 static_cast<jint>(real_events.size()), 147 "java/lang/String", 148 [&](jint i) { 149 return env->NewStringUTF(real_events[i].c_str()); 150 }); 151 gEvents.clear(); 152 return ret; 153 } 154 155 } // namespace Test904ObjectAllocation 156 } // namespace art 157