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 <stdio.h> 18 19 #include <mutex> 20 #include <vector> 21 22 #include "android-base/macros.h" 23 #include "android-base/stringprintf.h" 24 25 #include "jni.h" 26 #include "jvmti.h" 27 28 // Test infrastructure 29 #include "jni_helper.h" 30 #include "jvmti_helper.h" 31 #include "scoped_local_ref.h" 32 #include "scoped_utf_chars.h" 33 #include "test_env.h" 34 35 namespace art { 36 namespace Test912Classes { 37 38 extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912_isModifiableClass( 39 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { 40 jboolean res = JNI_FALSE; 41 jvmtiError result = jvmti_env->IsModifiableClass(klass, &res); 42 JvmtiErrorToException(env, jvmti_env, result); 43 return res; 44 } 45 46 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassSignature( 47 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { 48 char* sig; 49 char* gen; 50 jvmtiError result = jvmti_env->GetClassSignature(klass, &sig, &gen); 51 if (JvmtiErrorToException(env, jvmti_env, result)) { 52 return nullptr; 53 } 54 55 auto callback = [&](jint i) { 56 if (i == 0) { 57 return sig == nullptr ? nullptr : env->NewStringUTF(sig); 58 } else { 59 return gen == nullptr ? nullptr : env->NewStringUTF(gen); 60 } 61 }; 62 jobjectArray ret = CreateObjectArray(env, 2, "java/lang/String", callback); 63 64 // Need to deallocate the strings. 65 if (sig != nullptr) { 66 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(sig)); 67 } 68 if (gen != nullptr) { 69 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(gen)); 70 } 71 72 return ret; 73 } 74 75 extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912_isInterface( 76 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { 77 jboolean is_interface = JNI_FALSE; 78 jvmtiError result = jvmti_env->IsInterface(klass, &is_interface); 79 JvmtiErrorToException(env, jvmti_env, result); 80 return is_interface; 81 } 82 83 extern "C" JNIEXPORT jboolean JNICALL Java_art_Test912_isArrayClass( 84 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { 85 jboolean is_array_class = JNI_FALSE; 86 jvmtiError result = jvmti_env->IsArrayClass(klass, &is_array_class); 87 JvmtiErrorToException(env, jvmti_env, result); 88 return is_array_class; 89 } 90 91 extern "C" JNIEXPORT jint JNICALL Java_art_Test912_getClassModifiers( 92 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { 93 jint mod; 94 jvmtiError result = jvmti_env->GetClassModifiers(klass, &mod); 95 JvmtiErrorToException(env, jvmti_env, result); 96 return mod; 97 } 98 99 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassFields( 100 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { 101 jint count = 0; 102 jfieldID* fields = nullptr; 103 jvmtiError result = jvmti_env->GetClassFields(klass, &count, &fields); 104 if (JvmtiErrorToException(env, jvmti_env, result)) { 105 return nullptr; 106 } 107 108 auto callback = [&](jint i) { 109 jint modifiers; 110 // Ignore any errors for simplicity. 111 jvmti_env->GetFieldModifiers(klass, fields[i], &modifiers); 112 constexpr jint kStatic = 0x8; 113 return env->ToReflectedField(klass, 114 fields[i], 115 (modifiers & kStatic) != 0 ? JNI_TRUE : JNI_FALSE); 116 }; 117 jobjectArray ret = CreateObjectArray(env, count, "java/lang/Object", callback); 118 if (fields != nullptr) { 119 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(fields)); 120 } 121 return ret; 122 } 123 124 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassMethods( 125 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { 126 jint count = 0; 127 jmethodID* methods = nullptr; 128 jvmtiError result = jvmti_env->GetClassMethods(klass, &count, &methods); 129 if (JvmtiErrorToException(env, jvmti_env, result)) { 130 return nullptr; 131 } 132 133 auto callback = [&](jint i) { 134 jint modifiers; 135 // Ignore any errors for simplicity. 136 jvmti_env->GetMethodModifiers(methods[i], &modifiers); 137 constexpr jint kStatic = 0x8; 138 return env->ToReflectedMethod(klass, 139 methods[i], 140 (modifiers & kStatic) != 0 ? JNI_TRUE : JNI_FALSE); 141 }; 142 jobjectArray ret = CreateObjectArray(env, count, "java/lang/Object", callback); 143 if (methods != nullptr) { 144 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(methods)); 145 } 146 return ret; 147 } 148 149 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getImplementedInterfaces( 150 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { 151 jint count = 0; 152 jclass* classes = nullptr; 153 jvmtiError result = jvmti_env->GetImplementedInterfaces(klass, &count, &classes); 154 if (JvmtiErrorToException(env, jvmti_env, result)) { 155 return nullptr; 156 } 157 158 auto callback = [&](jint i) { 159 return classes[i]; 160 }; 161 jobjectArray ret = CreateObjectArray(env, count, "java/lang/Class", callback); 162 if (classes != nullptr) { 163 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(classes)); 164 } 165 return ret; 166 } 167 168 extern "C" JNIEXPORT jint JNICALL Java_art_Test912_getClassStatus( 169 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { 170 jint status; 171 jvmtiError result = jvmti_env->GetClassStatus(klass, &status); 172 JvmtiErrorToException(env, jvmti_env, result); 173 return status; 174 } 175 176 extern "C" JNIEXPORT jobject JNICALL Java_art_Test912_getClassLoader( 177 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { 178 jobject classloader; 179 jvmtiError result = jvmti_env->GetClassLoader(klass, &classloader); 180 JvmtiErrorToException(env, jvmti_env, result); 181 return classloader; 182 } 183 184 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassLoaderClasses( 185 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jobject jclassloader) { 186 jint count = 0; 187 jclass* classes = nullptr; 188 jvmtiError result = jvmti_env->GetClassLoaderClasses(jclassloader, &count, &classes); 189 if (JvmtiErrorToException(env, jvmti_env, result)) { 190 return nullptr; 191 } 192 193 auto callback = [&](jint i) { 194 return classes[i]; 195 }; 196 jobjectArray ret = CreateObjectArray(env, count, "java/lang/Class", callback); 197 if (classes != nullptr) { 198 jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(classes)); 199 } 200 return ret; 201 } 202 203 extern "C" JNIEXPORT jintArray JNICALL Java_art_Test912_getClassVersion( 204 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { 205 jint major, minor; 206 jvmtiError result = jvmti_env->GetClassVersionNumbers(klass, &minor, &major); 207 if (JvmtiErrorToException(env, jvmti_env, result)) { 208 return nullptr; 209 } 210 211 jintArray int_array = env->NewIntArray(2); 212 if (int_array == nullptr) { 213 return nullptr; 214 } 215 jint buf[2] = { major, minor }; 216 env->SetIntArrayRegion(int_array, 0, 2, buf); 217 218 return int_array; 219 } 220 221 static std::string GetClassName(jvmtiEnv* jenv, JNIEnv* jni_env, jclass klass) { 222 char* name; 223 jvmtiError result = jenv->GetClassSignature(klass, &name, nullptr); 224 if (result != JVMTI_ERROR_NONE) { 225 if (jni_env != nullptr) { 226 JvmtiErrorToException(jni_env, jenv, result); 227 } else { 228 printf("Failed to get class signature.\n"); 229 } 230 return ""; 231 } 232 233 std::string tmp(name); 234 jenv->Deallocate(reinterpret_cast<unsigned char*>(name)); 235 236 return tmp; 237 } 238 239 static void EnableEvents(JNIEnv* env, 240 jboolean enable, 241 decltype(jvmtiEventCallbacks().ClassLoad) class_load, 242 decltype(jvmtiEventCallbacks().ClassPrepare) class_prepare) { 243 if (enable == JNI_FALSE) { 244 jvmtiError ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, 245 JVMTI_EVENT_CLASS_LOAD, 246 nullptr); 247 if (JvmtiErrorToException(env, jvmti_env, ret)) { 248 return; 249 } 250 ret = jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, 251 JVMTI_EVENT_CLASS_PREPARE, 252 nullptr); 253 JvmtiErrorToException(env, jvmti_env, ret); 254 return; 255 } 256 257 jvmtiEventCallbacks callbacks; 258 memset(&callbacks, 0, sizeof(jvmtiEventCallbacks)); 259 callbacks.ClassLoad = class_load; 260 callbacks.ClassPrepare = class_prepare; 261 jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); 262 if (JvmtiErrorToException(env, jvmti_env, ret)) { 263 return; 264 } 265 266 ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, 267 JVMTI_EVENT_CLASS_LOAD, 268 nullptr); 269 if (JvmtiErrorToException(env, jvmti_env, ret)) { 270 return; 271 } 272 ret = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, 273 JVMTI_EVENT_CLASS_PREPARE, 274 nullptr); 275 JvmtiErrorToException(env, jvmti_env, ret); 276 } 277 278 static std::mutex gEventsMutex; 279 static std::vector<std::string> gEvents; 280 281 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test912_getClassLoadMessages( 282 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) { 283 std::lock_guard<std::mutex> guard(gEventsMutex); 284 jobjectArray ret = CreateObjectArray(env, 285 static_cast<jint>(gEvents.size()), 286 "java/lang/String", 287 [&](jint i) { 288 return env->NewStringUTF(gEvents[i].c_str()); 289 }); 290 gEvents.clear(); 291 return ret; 292 } 293 294 class ClassLoadPreparePrinter { 295 public: 296 static void JNICALL ClassLoadCallback(jvmtiEnv* jenv, 297 JNIEnv* jni_env, 298 jthread thread, 299 jclass klass) { 300 std::string name = GetClassName(jenv, jni_env, klass); 301 if (name == "") { 302 return; 303 } 304 std::string thread_name = GetThreadName(jenv, jni_env, thread); 305 if (thread_name == "") { 306 return; 307 } 308 if (thread_name_filter_ != "" && thread_name_filter_ != thread_name) { 309 return; 310 } 311 312 std::lock_guard<std::mutex> guard(gEventsMutex); 313 gEvents.push_back(android::base::StringPrintf("Load: %s on %s", 314 name.c_str(), 315 thread_name.c_str())); 316 } 317 318 static void JNICALL ClassPrepareCallback(jvmtiEnv* jenv, 319 JNIEnv* jni_env, 320 jthread thread, 321 jclass klass) { 322 std::string name = GetClassName(jenv, jni_env, klass); 323 if (name == "") { 324 return; 325 } 326 std::string thread_name = GetThreadName(jenv, jni_env, thread); 327 if (thread_name == "") { 328 return; 329 } 330 if (thread_name_filter_ != "" && thread_name_filter_ != thread_name) { 331 return; 332 } 333 std::string cur_thread_name = GetThreadName(jenv, jni_env, nullptr); 334 335 std::lock_guard<std::mutex> guard(gEventsMutex); 336 gEvents.push_back(android::base::StringPrintf("Prepare: %s on %s (cur=%s)", 337 name.c_str(), 338 thread_name.c_str(), 339 cur_thread_name.c_str())); 340 } 341 342 static std::string GetThreadName(jvmtiEnv* jenv, JNIEnv* jni_env, jthread thread) { 343 jvmtiThreadInfo info; 344 jvmtiError result = jenv->GetThreadInfo(thread, &info); 345 if (result != JVMTI_ERROR_NONE) { 346 if (jni_env != nullptr) { 347 JvmtiErrorToException(jni_env, jenv, result); 348 } else { 349 printf("Failed to get thread name.\n"); 350 } 351 return ""; 352 } 353 354 std::string tmp(info.name); 355 jenv->Deallocate(reinterpret_cast<unsigned char*>(info.name)); 356 jni_env->DeleteLocalRef(info.context_class_loader); 357 jni_env->DeleteLocalRef(info.thread_group); 358 359 return tmp; 360 } 361 362 static std::string thread_name_filter_; 363 }; 364 std::string ClassLoadPreparePrinter::thread_name_filter_; 365 366 extern "C" JNIEXPORT void JNICALL Java_art_Test912_enableClassLoadPreparePrintEvents( 367 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean enable, jthread thread) { 368 if (thread != nullptr) { 369 ClassLoadPreparePrinter::thread_name_filter_ = 370 ClassLoadPreparePrinter::GetThreadName(jvmti_env, env, thread); 371 } else { 372 ClassLoadPreparePrinter::thread_name_filter_ = ""; 373 } 374 375 EnableEvents(env, 376 enable, 377 ClassLoadPreparePrinter::ClassLoadCallback, 378 ClassLoadPreparePrinter::ClassPrepareCallback); 379 } 380 381 class ClassLoadPrepareEquality { 382 public: 383 static constexpr const char* kClassName = "Lart/Test912$ClassE;"; 384 static constexpr const char* kStorageFieldName = "STATIC"; 385 static constexpr const char* kStorageFieldSig = "Ljava/lang/Object;"; 386 static constexpr const char* kStorageWeakFieldName = "WEAK"; 387 static constexpr const char* kStorageWeakFieldSig = "Ljava/lang/ref/Reference;"; 388 static constexpr const char* kWeakClassName = "java/lang/ref/WeakReference"; 389 static constexpr const char* kWeakInitSig = "(Ljava/lang/Object;)V"; 390 static constexpr const char* kWeakGetSig = "()Ljava/lang/Object;"; 391 392 static void JNICALL ClassLoadCallback(jvmtiEnv* jenv, 393 JNIEnv* jni_env, 394 jthread thread ATTRIBUTE_UNUSED, 395 jclass klass) { 396 std::string name = GetClassName(jenv, jni_env, klass); 397 if (name == kClassName) { 398 found_ = true; 399 stored_class_ = jni_env->NewGlobalRef(klass); 400 weakly_stored_class_ = jni_env->NewWeakGlobalRef(klass); 401 // The following is bad and relies on implementation details. But otherwise a test would be 402 // a lot more complicated. 403 local_stored_class_ = jni_env->NewLocalRef(klass); 404 // Store the value into a field in the heap. 405 SetOrCompare(jni_env, klass, true); 406 } 407 } 408 409 static void JNICALL ClassPrepareCallback(jvmtiEnv* jenv, 410 JNIEnv* jni_env, 411 jthread thread ATTRIBUTE_UNUSED, 412 jclass klass) { 413 std::string name = GetClassName(jenv, jni_env, klass); 414 if (name == kClassName) { 415 CHECK(stored_class_ != nullptr); 416 CHECK(jni_env->IsSameObject(stored_class_, klass)); 417 CHECK(jni_env->IsSameObject(weakly_stored_class_, klass)); 418 CHECK(jni_env->IsSameObject(local_stored_class_, klass)); 419 // Look up the value in a field in the heap. 420 SetOrCompare(jni_env, klass, false); 421 compared_ = true; 422 } 423 } 424 425 static void SetOrCompare(JNIEnv* jni_env, jobject value, bool set) { 426 CHECK(storage_class_ != nullptr); 427 428 // Simple direct storage. 429 jfieldID field = jni_env->GetStaticFieldID(storage_class_, kStorageFieldName, kStorageFieldSig); 430 CHECK(field != nullptr); 431 432 if (set) { 433 jni_env->SetStaticObjectField(storage_class_, field, value); 434 CHECK(!jni_env->ExceptionCheck()); 435 } else { 436 ScopedLocalRef<jobject> stored(jni_env, jni_env->GetStaticObjectField(storage_class_, field)); 437 CHECK(jni_env->IsSameObject(value, stored.get())); 438 } 439 440 // Storage as a reference. 441 ScopedLocalRef<jclass> weak_ref_class(jni_env, jni_env->FindClass(kWeakClassName)); 442 CHECK(weak_ref_class.get() != nullptr); 443 jfieldID weak_field = jni_env->GetStaticFieldID(storage_class_, 444 kStorageWeakFieldName, 445 kStorageWeakFieldSig); 446 CHECK(weak_field != nullptr); 447 if (set) { 448 // Create a WeakReference. 449 jmethodID weak_init = jni_env->GetMethodID(weak_ref_class.get(), "<init>", kWeakInitSig); 450 CHECK(weak_init != nullptr); 451 ScopedLocalRef<jobject> weak_obj(jni_env, jni_env->NewObject(weak_ref_class.get(), 452 weak_init, 453 value)); 454 CHECK(weak_obj.get() != nullptr); 455 jni_env->SetStaticObjectField(storage_class_, weak_field, weak_obj.get()); 456 CHECK(!jni_env->ExceptionCheck()); 457 } else { 458 // Check the reference value. 459 jmethodID get_referent = jni_env->GetMethodID(weak_ref_class.get(), "get", kWeakGetSig); 460 CHECK(get_referent != nullptr); 461 ScopedLocalRef<jobject> weak_obj(jni_env, jni_env->GetStaticObjectField(storage_class_, 462 weak_field)); 463 CHECK(weak_obj.get() != nullptr); 464 ScopedLocalRef<jobject> weak_referent(jni_env, jni_env->CallObjectMethod(weak_obj.get(), 465 get_referent)); 466 CHECK(weak_referent.get() != nullptr); 467 CHECK(jni_env->IsSameObject(value, weak_referent.get())); 468 } 469 } 470 471 static void CheckFound() { 472 CHECK(found_); 473 CHECK(compared_); 474 } 475 476 static void Free(JNIEnv* env) { 477 if (stored_class_ != nullptr) { 478 env->DeleteGlobalRef(stored_class_); 479 DCHECK(weakly_stored_class_ != nullptr); 480 env->DeleteWeakGlobalRef(weakly_stored_class_); 481 // Do not attempt to delete the local ref. It will be out of date by now. 482 } 483 } 484 485 static jclass storage_class_; 486 487 private: 488 static jobject stored_class_; 489 static jweak weakly_stored_class_; 490 static jobject local_stored_class_; 491 static bool found_; 492 static bool compared_; 493 }; 494 jclass ClassLoadPrepareEquality::storage_class_ = nullptr; 495 jobject ClassLoadPrepareEquality::stored_class_ = nullptr; 496 jweak ClassLoadPrepareEquality::weakly_stored_class_ = nullptr; 497 jobject ClassLoadPrepareEquality::local_stored_class_ = nullptr; 498 bool ClassLoadPrepareEquality::found_ = false; 499 bool ClassLoadPrepareEquality::compared_ = false; 500 501 extern "C" JNIEXPORT void JNICALL Java_art_Test912_setEqualityEventStorageClass( 502 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jclass klass) { 503 ClassLoadPrepareEquality::storage_class_ = 504 reinterpret_cast<jclass>(env->NewGlobalRef(klass)); 505 } 506 507 extern "C" JNIEXPORT void JNICALL Java_art_Test912_enableClassLoadPrepareEqualityEvents( 508 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED, jboolean b) { 509 EnableEvents(env, 510 b, 511 ClassLoadPrepareEquality::ClassLoadCallback, 512 ClassLoadPrepareEquality::ClassPrepareCallback); 513 if (b == JNI_FALSE) { 514 ClassLoadPrepareEquality::Free(env); 515 ClassLoadPrepareEquality::CheckFound(); 516 env->DeleteGlobalRef(ClassLoadPrepareEquality::storage_class_); 517 ClassLoadPrepareEquality::storage_class_ = nullptr; 518 } 519 } 520 521 } // namespace Test912Classes 522 } // namespace art 523