Home | History | Annotate | Download | only in 912-classes
      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