Home | History | Annotate | Download | only in 1919-vminit-thread-start-timing
      1 /*
      2  * Copyright (C) 2016 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 "1919-vminit-thread-start-timing/vminit.h"
     18 
     19 #include <mutex>
     20 #include <thread>
     21 #include <vector>
     22 
     23 #include <jni.h>
     24 #include <stdio.h>
     25 #include <string.h>
     26 #include "android-base/macros.h"
     27 #include "jvmti.h"
     28 
     29 // Test infrastructure
     30 #include "scoped_local_ref.h"
     31 #include "jvmti_helper.h"
     32 #include "jni_helper.h"
     33 #include "test_env.h"
     34 
     35 namespace art {
     36 namespace Test1919VMInitThreadStart {
     37 
     38 struct EventData {
     39   std::string event;
     40   jobject data;
     41 };
     42 
     43 struct EventList {
     44   jrawMonitorID events_mutex;
     45   std::vector<EventData> events;
     46 };
     47 
     48 // The thread we started for testing.
     49 static jthread the_thread;
     50 
     51 static void EnableEvent(jvmtiEnv* env, jvmtiEvent evt) {
     52   jvmtiError error = env->SetEventNotificationMode(JVMTI_ENABLE, evt, nullptr);
     53   if (error != JVMTI_ERROR_NONE) {
     54     printf("Failed to enable event");
     55   }
     56 }
     57 
     58 static void JNICALL ThreadStartCallback(jvmtiEnv *jvmti, JNIEnv* env, jthread thread) {
     59   EventList* list = nullptr;
     60   CheckJvmtiError(jvmti, jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&list)));
     61   CheckJvmtiError(jvmti, jvmti->RawMonitorEnter(list->events_mutex));
     62   list->events.push_back({ "ThreadStart", env->NewGlobalRef(thread) });
     63   CheckJvmtiError(jvmti, jvmti->RawMonitorExit(list->events_mutex));
     64 }
     65 
     66 static void JNICALL Test1919AgentThread(jvmtiEnv* jvmti,
     67                                         JNIEnv* env,
     68                                         void* arg ATTRIBUTE_UNUSED) {
     69   EventList* list = nullptr;
     70   CheckJvmtiError(jvmti, jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&list)));
     71   CheckJvmtiError(jvmti, jvmti->RawMonitorEnter(list->events_mutex));
     72   jthread cur;
     73   CheckJvmtiError(jvmti, jvmti->GetCurrentThread(&cur));
     74   list->events.push_back({ "Test1919AgentThread", env->NewGlobalRef(cur) });
     75   env->DeleteLocalRef(cur);
     76   // Wake up VMInit
     77   CheckJvmtiError(jvmti, jvmti->RawMonitorNotify(list->events_mutex));
     78   CheckJvmtiError(jvmti, jvmti->RawMonitorExit(list->events_mutex));
     79 }
     80 
     81 static void CreateAgentThread(jvmtiEnv* jvmti, JNIEnv* env) {
     82   // Create a Thread object.
     83   ScopedLocalRef<jobject> thread_name(env, env->NewStringUTF("JVMTI_THREAD-Test1919"));
     84   CHECK(thread_name.get() != nullptr);
     85 
     86   ScopedLocalRef<jclass> thread_klass(env, env->FindClass("java/lang/Thread"));
     87   CHECK(thread_klass.get() != nullptr);
     88 
     89   ScopedLocalRef<jobject> thread(env, env->AllocObject(thread_klass.get()));
     90   CHECK(thread.get() != nullptr);
     91 
     92   jmethodID initID = env->GetMethodID(thread_klass.get(), "<init>", "(Ljava/lang/String;)V");
     93   CHECK(initID != nullptr);
     94 
     95   env->CallNonvirtualVoidMethod(thread.get(), thread_klass.get(), initID, thread_name.get());
     96   CHECK(!env->ExceptionCheck());
     97 
     98   // Set the_thread.
     99   the_thread = static_cast<jthread>(env->NewGlobalRef(thread.get()));
    100 
    101   // Run agent thread.
    102   CheckJvmtiError(jvmti, jvmti->RunAgentThread(thread.get(),
    103                                                Test1919AgentThread,
    104                                                nullptr,
    105                                                JVMTI_THREAD_NORM_PRIORITY));
    106 }
    107 
    108 static void JNICALL VMInitCallback(jvmtiEnv *jvmti, JNIEnv* env, jthread thread) {
    109   EventList* list = nullptr;
    110   CheckJvmtiError(jvmti, jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&list)));
    111   CheckJvmtiError(jvmti, jvmti->RawMonitorEnter(list->events_mutex));
    112   list->events.push_back({ "VMInit", env->NewGlobalRef(thread) });
    113   // Create a new thread.
    114   CreateAgentThread(jvmti, env);
    115   // Wait for new thread to run.
    116   CheckJvmtiError(jvmti, jvmti->RawMonitorWait(list->events_mutex, 0));
    117   CheckJvmtiError(jvmti, jvmti->RawMonitorExit(list->events_mutex));
    118 }
    119 
    120 static void InstallVMEvents(jvmtiEnv* env) {
    121   jvmtiEventCallbacks callbacks;
    122   memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
    123   callbacks.VMInit = VMInitCallback;
    124   callbacks.ThreadStart = ThreadStartCallback;
    125   jvmtiError ret = env->SetEventCallbacks(&callbacks, sizeof(callbacks));
    126   if (ret != JVMTI_ERROR_NONE) {
    127     printf("Failed to install callbacks");
    128   }
    129 
    130   EnableEvent(env, JVMTI_EVENT_VM_INIT);
    131   EnableEvent(env, JVMTI_EVENT_THREAD_START);
    132 }
    133 
    134 static void InstallEventList(jvmtiEnv* env) {
    135   EventList* list = nullptr;
    136   CheckJvmtiError(env, env->Allocate(sizeof(EventList), reinterpret_cast<unsigned char**>(&list)));
    137   memset(list, 0, sizeof(EventList));
    138   CheckJvmtiError(env, env->CreateRawMonitor("Test1919 Monitor", &list->events_mutex));
    139   CheckJvmtiError(env, env->SetEnvironmentLocalStorage(list));
    140 }
    141 
    142 jint OnLoad(JavaVM* vm,
    143             char* options ATTRIBUTE_UNUSED,
    144             void* reserved ATTRIBUTE_UNUSED) {
    145   if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0) != 0) {
    146     printf("Unable to get jvmti env!\n");
    147     return 1;
    148   }
    149   InstallVMEvents(jvmti_env);
    150   InstallEventList(jvmti_env);
    151   return 0;
    152 }
    153 
    154 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test1919_getEventNames(JNIEnv* env, jclass) {
    155   EventList* list = nullptr;
    156   if (JvmtiErrorToException(env,
    157                             jvmti_env,
    158                             jvmti_env->GetEnvironmentLocalStorage(
    159                                 reinterpret_cast<void**>(&list)))) {
    160     return nullptr;
    161   }
    162   if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(list->events_mutex))) {
    163     return nullptr;
    164   }
    165   jobjectArray ret = CreateObjectArray(env, list->events.size(), "java/lang/String",
    166                                        [&](jint i) {
    167                                          return env->NewStringUTF(list->events[i].event.c_str());
    168                                        });
    169   if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(list->events_mutex))) {
    170     return nullptr;
    171   }
    172   return ret;
    173 }
    174 
    175 extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test1919_getEventThreads(JNIEnv* env, jclass) {
    176   EventList* list = nullptr;
    177   if (JvmtiErrorToException(env,
    178                             jvmti_env,
    179                             jvmti_env->GetEnvironmentLocalStorage(
    180                                 reinterpret_cast<void**>(&list)))) {
    181     return nullptr;
    182   }
    183   if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(list->events_mutex))) {
    184     return nullptr;
    185   }
    186   jobjectArray ret = CreateObjectArray(env, list->events.size(), "java/lang/Thread",
    187                                        [&](jint i) {
    188                                          return env->NewLocalRef(list->events[i].data);
    189                                        });
    190   if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(list->events_mutex))) {
    191     return nullptr;
    192   }
    193   return ret;
    194 }
    195 
    196 extern "C" JNIEXPORT jthread JNICALL Java_art_Test1919_getTestingThread(JNIEnv*, jclass) {
    197   return the_thread;
    198 }
    199 
    200 }  // namespace Test1919VMInitThreadStart
    201 }  // namespace art
    202