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 <mutex> 18 19 #include "jni.h" 20 #include "jvmti.h" 21 22 #include "android-base/logging.h" 23 #include "android-base/stringprintf.h" 24 #include "jni_binder.h" 25 #include "jvmti_helper.h" 26 #include "scoped_local_ref.h" 27 #include "scoped_utf_chars.h" 28 #include "test_env.h" 29 30 namespace art { 31 32 static std::string GetClassName(JNIEnv* jni_env, jclass cls) { 33 ScopedLocalRef<jclass> class_class(jni_env, jni_env->GetObjectClass(cls)); 34 jmethodID mid = jni_env->GetMethodID(class_class.get(), "getName", "()Ljava/lang/String;"); 35 ScopedLocalRef<jstring> str( 36 jni_env, reinterpret_cast<jstring>(jni_env->CallObjectMethod(cls, mid))); 37 ScopedUtfChars utf_chars(jni_env, str.get()); 38 return utf_chars.c_str(); 39 } 40 41 static std::mutex gLock; 42 static std::string gCollection; 43 44 static void JNICALL ObjectAllocated(jvmtiEnv* ti_env ATTRIBUTE_UNUSED, 45 JNIEnv* jni_env, 46 jthread thread ATTRIBUTE_UNUSED, 47 jobject object, 48 jclass object_klass, 49 jlong size) { 50 std::string object_klass_descriptor = GetClassName(jni_env, object_klass); 51 ScopedLocalRef<jclass> object_klass2(jni_env, jni_env->GetObjectClass(object)); 52 std::string object_klass_descriptor2 = GetClassName(jni_env, object_klass2.get()); 53 std::string result = android::base::StringPrintf("ObjectAllocated type %s/%s size %zu", 54 object_klass_descriptor.c_str(), 55 object_klass_descriptor2.c_str(), 56 static_cast<size_t>(size)); 57 std::unique_lock<std::mutex> mu(gLock); 58 gCollection += result + "#"; 59 } 60 61 extern "C" JNIEXPORT void JNICALL Java_android_jvmti_cts_JvmtiTrackingTest_setupObjectAllocCallback( 62 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jboolean enable) { 63 jvmtiEventCallbacks callbacks; 64 memset(&callbacks, 0, sizeof(jvmtiEventCallbacks)); 65 callbacks.VMObjectAlloc = enable ? ObjectAllocated : nullptr; 66 67 jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); 68 JvmtiErrorToException(env, jvmti_env, ret); 69 } 70 71 extern "C" JNIEXPORT void JNICALL Java_android_jvmti_cts_JvmtiTrackingTest_enableAllocationTracking( 72 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thread, jboolean enable) { 73 jvmtiError ret = jvmti_env->SetEventNotificationMode( 74 enable ? JVMTI_ENABLE : JVMTI_DISABLE, 75 JVMTI_EVENT_VM_OBJECT_ALLOC, 76 thread); 77 JvmtiErrorToException(env, jvmti_env, ret); 78 } 79 80 extern "C" JNIEXPORT 81 jstring JNICALL Java_android_jvmti_cts_JvmtiTrackingTest_getAndResetAllocationTrackingString( 82 JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { 83 // We will have a string allocation. So only do the C++ string retrieval under lock. 84 std::string result; 85 { 86 std::unique_lock<std::mutex> mu(gLock); 87 result.swap(gCollection); 88 } 89 // Make sure we give any other threads that might have been waiting to get a last crack time to 90 // run. We will ignore their additions however. 91 bool is_empty = false; 92 do { 93 { 94 std::unique_lock<std::mutex> mu(gLock); 95 is_empty = gCollection.empty(); 96 gCollection.clear(); 97 } 98 sched_yield(); 99 } while (!is_empty); 100 101 if (result.empty()) { 102 return nullptr; 103 } 104 105 return env->NewStringUTF(result.c_str()); 106 } 107 108 static JNINativeMethod gMethods[] = { 109 { "setupObjectAllocCallback", "(Z)V", 110 (void*)Java_android_jvmti_cts_JvmtiTrackingTest_setupObjectAllocCallback }, 111 112 { "enableAllocationTracking", "(Ljava/lang/Thread;Z)V", 113 (void*)Java_android_jvmti_cts_JvmtiTrackingTest_enableAllocationTracking }, 114 115 { "getAndResetAllocationTrackingString", "()Ljava/lang/String;", 116 (void*)Java_android_jvmti_cts_JvmtiTrackingTest_getAndResetAllocationTrackingString }, 117 }; 118 119 void register_android_jvmti_cts_JvmtiTrackingTest(jvmtiEnv* jenv, JNIEnv* env) { 120 ScopedLocalRef<jclass> klass(env, GetClass(jenv, env, 121 "android/jvmti/cts/JvmtiTrackingTest", nullptr)); 122 if (klass.get() == nullptr) { 123 env->ExceptionClear(); 124 return; 125 } 126 127 env->RegisterNatives(klass.get(), gMethods, sizeof(gMethods) / sizeof(JNINativeMethod)); 128 if (env->ExceptionCheck()) { 129 env->ExceptionClear(); 130 LOG(ERROR) << "Could not register natives for JvmtiTrackingTest class"; 131 } 132 } 133 134 } // namespace art 135