blob: 3ec8793f896e12b1fb08b76a2f25708cad7c1811 [file] [log] [blame]
Andreas Gampe732b0ac2017-01-18 15:23:39 -08001/*
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>
Andreas Gampee0220152017-02-07 14:59:08 -080018#include <sched.h>
Andreas Gampe732b0ac2017-01-18 15:23:39 -080019
20#include "barrier.h"
21#include "base/logging.h"
22#include "base/macros.h"
23#include "jni.h"
Andreas Gampe5e03a302017-03-13 13:10:00 -070024#include "jvmti.h"
Andreas Gampe732b0ac2017-01-18 15:23:39 -080025#include "runtime.h"
26#include "ScopedLocalRef.h"
27#include "thread-inl.h"
28#include "well_known_classes.h"
29
Andreas Gampe3f46c962017-03-30 10:26:59 -070030// Test infrastructure
31#include "jvmti_helper.h"
32#include "test_env.h"
Andreas Gampe732b0ac2017-01-18 15:23:39 -080033
34namespace art {
35namespace Test930AgentThread {
36
37struct AgentData {
38 AgentData() : main_thread(nullptr),
39 jvmti_env(nullptr),
Andreas Gamped9911ee2017-03-27 13:27:24 -070040 b(2),
41 priority(0) {
Andreas Gampe732b0ac2017-01-18 15:23:39 -080042 }
43
44 jthread main_thread;
45 jvmtiEnv* jvmti_env;
46 Barrier b;
47 jint priority;
48};
49
50static void AgentMain(jvmtiEnv* jenv, JNIEnv* env, void* arg) {
51 AgentData* data = reinterpret_cast<AgentData*>(arg);
52
53 // Check some basics.
54 // This thread is not the main thread.
55 jthread this_thread;
56 jvmtiError this_thread_result = jenv->GetCurrentThread(&this_thread);
Andreas Gampe3f46c962017-03-30 10:26:59 -070057 CHECK(!JvmtiErrorToException(env, jenv, this_thread_result));
Andreas Gampe732b0ac2017-01-18 15:23:39 -080058 CHECK(!env->IsSameObject(this_thread, data->main_thread));
59
60 // The thread is a daemon.
61 jvmtiThreadInfo info;
62 jvmtiError info_result = jenv->GetThreadInfo(this_thread, &info);
Andreas Gampe3f46c962017-03-30 10:26:59 -070063 CHECK(!JvmtiErrorToException(env, jenv, info_result));
Andreas Gampe732b0ac2017-01-18 15:23:39 -080064 CHECK(info.is_daemon);
65
66 // The thread has the requested priority.
67 // TODO: Our thread priorities do not work on the host.
68 // CHECK_EQ(info.priority, data->priority);
69
70 // Check further parts of the thread:
71 jint thread_count;
72 jthread* threads;
73 jvmtiError threads_result = jenv->GetAllThreads(&thread_count, &threads);
Andreas Gampe3f46c962017-03-30 10:26:59 -070074 CHECK(!JvmtiErrorToException(env, jenv, threads_result));
Andreas Gampe732b0ac2017-01-18 15:23:39 -080075 bool found = false;
76 for (jint i = 0; i != thread_count; ++i) {
77 if (env->IsSameObject(threads[i], this_thread)) {
78 found = true;
79 break;
80 }
81 }
82 CHECK(found);
83
84 // Done, let the main thread progress.
85 data->b.Pass(Thread::Current());
86}
87
88extern "C" JNIEXPORT void JNICALL Java_Main_testAgentThread(
89 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
90 // Create a Thread object.
91 ScopedLocalRef<jobject> thread_name(env,
92 env->NewStringUTF("Agent Thread"));
93 if (thread_name.get() == nullptr) {
94 return;
95 }
96
97 ScopedLocalRef<jobject> thread(env, env->AllocObject(WellKnownClasses::java_lang_Thread));
98 if (thread.get() == nullptr) {
99 return;
100 }
101
102 env->CallNonvirtualVoidMethod(thread.get(),
103 WellKnownClasses::java_lang_Thread,
104 WellKnownClasses::java_lang_Thread_init,
105 Runtime::Current()->GetMainThreadGroup(),
106 thread_name.get(),
107 kMinThreadPriority,
108 JNI_FALSE);
109 if (env->ExceptionCheck()) {
110 return;
111 }
112
113 jthread main_thread;
114 jvmtiError main_thread_result = jvmti_env->GetCurrentThread(&main_thread);
Andreas Gampe3f46c962017-03-30 10:26:59 -0700115 if (JvmtiErrorToException(env, jvmti_env, main_thread_result)) {
Andreas Gampe732b0ac2017-01-18 15:23:39 -0800116 return;
117 }
118
119 AgentData data;
120 data.main_thread = env->NewGlobalRef(main_thread);
121 data.jvmti_env = jvmti_env;
122 data.priority = JVMTI_THREAD_MIN_PRIORITY;
123
124 jvmtiError result = jvmti_env->RunAgentThread(thread.get(), AgentMain, &data, data.priority);
Andreas Gampe3f46c962017-03-30 10:26:59 -0700125 if (JvmtiErrorToException(env, jvmti_env, result)) {
Andreas Gampe732b0ac2017-01-18 15:23:39 -0800126 return;
127 }
128
129 data.b.Wait(Thread::Current());
130
Andreas Gampee0220152017-02-07 14:59:08 -0800131 // Scheduling may mean that the agent thread is put to sleep. Wait until it's dead in an effort
132 // to not unload the plugin and crash.
133 for (;;) {
134 NanoSleep(1000 * 1000);
135 jint thread_state;
136 jvmtiError state_result = jvmti_env->GetThreadState(thread.get(), &thread_state);
Andreas Gampe3f46c962017-03-30 10:26:59 -0700137 if (JvmtiErrorToException(env, jvmti_env, state_result)) {
Andreas Gampee0220152017-02-07 14:59:08 -0800138 return;
139 }
140 if (thread_state == 0 || // Was never alive.
141 (thread_state & JVMTI_THREAD_STATE_TERMINATED) != 0) { // Was alive and died.
142 break;
143 }
144 }
145 // Yield and sleep a bit more, to give the plugin time to tear down the native thread structure.
146 sched_yield();
147 NanoSleep(100 * 1000 * 1000);
148
Andreas Gampe732b0ac2017-01-18 15:23:39 -0800149 env->DeleteGlobalRef(data.main_thread);
150}
151
152} // namespace Test930AgentThread
153} // namespace art