Home | History | Annotate | Download | only in 931-agent-thread
      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 <inttypes.h>
     18 #include <pthread.h>
     19 #include <sched.h>
     20 
     21 #include "android-base/logging.h"
     22 #include "android-base/macros.h"
     23 #include "jni.h"
     24 #include "jvmti.h"
     25 #include "scoped_local_ref.h"
     26 
     27 // Test infrastructure
     28 #include "jvmti_helper.h"
     29 #include "test_env.h"
     30 
     31 namespace art {
     32 namespace Test930AgentThread {
     33 
     34 struct AgentData {
     35   AgentData() : main_thread(nullptr),
     36                 jvmti_env(nullptr),
     37                 priority(0) {
     38   }
     39 
     40   jthread main_thread;
     41   jvmtiEnv* jvmti_env;
     42   pthread_barrier_t b;
     43   jint priority;
     44 };
     45 
     46 static void AgentMain(jvmtiEnv* jenv, JNIEnv* env, void* arg) {
     47   AgentData* data = reinterpret_cast<AgentData*>(arg);
     48 
     49   // Check some basics.
     50   // This thread is not the main thread.
     51   jthread this_thread;
     52   jvmtiError this_thread_result = jenv->GetCurrentThread(&this_thread);
     53   CheckJvmtiError(jenv, this_thread_result);
     54   CHECK(!env->IsSameObject(this_thread, data->main_thread));
     55 
     56   // The thread is a daemon.
     57   jvmtiThreadInfo info;
     58   jvmtiError info_result = jenv->GetThreadInfo(this_thread, &info);
     59   CheckJvmtiError(jenv, info_result);
     60   CHECK(info.is_daemon);
     61   CheckJvmtiError(jenv, jenv->Deallocate(reinterpret_cast<unsigned char*>(info.name)));
     62   if (info.thread_group != nullptr) {
     63     env->DeleteLocalRef(info.thread_group);
     64   }
     65   if (info.context_class_loader != nullptr) {
     66     env->DeleteLocalRef(info.context_class_loader);
     67   }
     68 
     69   // The thread has the requested priority.
     70   // TODO: Our thread priorities do not work on the host.
     71   // CHECK_EQ(info.priority, data->priority);
     72 
     73   // Check further parts of the thread:
     74   jint thread_count;
     75   jthread* threads;
     76   jvmtiError threads_result = jenv->GetAllThreads(&thread_count, &threads);
     77   CheckJvmtiError(jenv, threads_result);
     78   bool found = false;
     79   for (jint i = 0; i != thread_count; ++i) {
     80     if (env->IsSameObject(threads[i], this_thread)) {
     81       found = true;
     82       break;
     83     }
     84   }
     85   CHECK(found);
     86 
     87   // Done, let the main thread progress.
     88   int wait_result = pthread_barrier_wait(&data->b);
     89   CHECK(wait_result == PTHREAD_BARRIER_SERIAL_THREAD || wait_result == 0);
     90 }
     91 
     92 extern "C" JNIEXPORT void JNICALL Java_art_Test931_testAgentThread(
     93     JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
     94   // Create a Thread object.
     95   ScopedLocalRef<jobject> thread_name(env, env->NewStringUTF("Agent Thread"));
     96   if (thread_name.get() == nullptr) {
     97     return;
     98   }
     99 
    100   ScopedLocalRef<jclass> thread_klass(env, env->FindClass("java/lang/Thread"));
    101   if (thread_klass.get() == nullptr) {
    102     return;
    103   }
    104   ScopedLocalRef<jobject> thread(env, env->AllocObject(thread_klass.get()));
    105   if (thread.get() == nullptr) {
    106     return;
    107   }
    108 
    109   // Get a ThreadGroup from the current thread. We need a non-null one as we're gonna call a
    110   // runtime-only constructor (so we can set priority and daemon state).
    111   jvmtiThreadInfo cur_thread_info;
    112   jvmtiError info_result = jvmti_env->GetThreadInfo(nullptr, &cur_thread_info);
    113   if (JvmtiErrorToException(env, jvmti_env, info_result)) {
    114     return;
    115   }
    116   CheckJvmtiError(jvmti_env,
    117                   jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(cur_thread_info.name)));
    118   ScopedLocalRef<jobject> thread_group(env, cur_thread_info.thread_group);
    119   if (cur_thread_info.context_class_loader != nullptr) {
    120     env->DeleteLocalRef(cur_thread_info.context_class_loader);
    121   }
    122 
    123   jmethodID initID = env->GetMethodID(thread_klass.get(),
    124                                       "<init>",
    125                                       "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
    126   if (initID == nullptr) {
    127     return;
    128   }
    129   env->CallNonvirtualVoidMethod(thread.get(),
    130                                 thread_klass.get(),
    131                                 initID,
    132                                 thread_group.get(),
    133                                 thread_name.get(),
    134                                 0,
    135                                 JNI_FALSE);
    136   if (env->ExceptionCheck()) {
    137     return;
    138   }
    139 
    140   jthread main_thread;
    141   jvmtiError main_thread_result = jvmti_env->GetCurrentThread(&main_thread);
    142   if (JvmtiErrorToException(env, jvmti_env, main_thread_result)) {
    143     return;
    144   }
    145 
    146   AgentData data;
    147   data.main_thread = env->NewGlobalRef(main_thread);
    148   data.jvmti_env = jvmti_env;
    149   data.priority = JVMTI_THREAD_MIN_PRIORITY;
    150   CHECK_EQ(0, pthread_barrier_init(&data.b, nullptr, 2));
    151 
    152   jvmtiError result = jvmti_env->RunAgentThread(thread.get(), AgentMain, &data, data.priority);
    153   if (JvmtiErrorToException(env, jvmti_env, result)) {
    154     return;
    155   }
    156 
    157   int wait_result = pthread_barrier_wait(&data.b);
    158   CHECK(wait_result == PTHREAD_BARRIER_SERIAL_THREAD || wait_result == 0);
    159 
    160   // Scheduling may mean that the agent thread is put to sleep. Wait until it's dead in an effort
    161   // to not unload the plugin and crash.
    162   for (;;) {
    163     sleep(1);
    164     jint thread_state;
    165     jvmtiError state_result = jvmti_env->GetThreadState(thread.get(), &thread_state);
    166     if (JvmtiErrorToException(env, jvmti_env, state_result)) {
    167       return;
    168     }
    169     if (thread_state == 0 ||                                    // Was never alive.
    170         (thread_state & JVMTI_THREAD_STATE_TERMINATED) != 0) {  // Was alive and died.
    171       break;
    172     }
    173   }
    174   // Yield and sleep a bit more, to give the plugin time to tear down the native thread structure.
    175   sched_yield();
    176   sleep(1);
    177 
    178   env->DeleteGlobalRef(data.main_thread);
    179 
    180   pthread_barrier_destroy(&data.b);
    181 }
    182 
    183 }  // namespace Test930AgentThread
    184 }  // namespace art
    185