blob: f8f9e486575f9ae9a0bac0032657e1f55db45bce [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
30#include "ti-agent/common_helper.h"
31#include "ti-agent/common_load.h"
32
33namespace art {
34namespace Test930AgentThread {
35
36struct AgentData {
37 AgentData() : main_thread(nullptr),
38 jvmti_env(nullptr),
39 b(2) {
40 }
41
42 jthread main_thread;
43 jvmtiEnv* jvmti_env;
44 Barrier b;
45 jint priority;
46};
47
48static void AgentMain(jvmtiEnv* jenv, JNIEnv* env, void* arg) {
49 AgentData* data = reinterpret_cast<AgentData*>(arg);
50
51 // Check some basics.
52 // This thread is not the main thread.
53 jthread this_thread;
54 jvmtiError this_thread_result = jenv->GetCurrentThread(&this_thread);
55 CHECK(!JvmtiErrorToException(env, this_thread_result));
56 CHECK(!env->IsSameObject(this_thread, data->main_thread));
57
58 // The thread is a daemon.
59 jvmtiThreadInfo info;
60 jvmtiError info_result = jenv->GetThreadInfo(this_thread, &info);
61 CHECK(!JvmtiErrorToException(env, info_result));
62 CHECK(info.is_daemon);
63
64 // The thread has the requested priority.
65 // TODO: Our thread priorities do not work on the host.
66 // CHECK_EQ(info.priority, data->priority);
67
68 // Check further parts of the thread:
69 jint thread_count;
70 jthread* threads;
71 jvmtiError threads_result = jenv->GetAllThreads(&thread_count, &threads);
72 CHECK(!JvmtiErrorToException(env, threads_result));
73 bool found = false;
74 for (jint i = 0; i != thread_count; ++i) {
75 if (env->IsSameObject(threads[i], this_thread)) {
76 found = true;
77 break;
78 }
79 }
80 CHECK(found);
81
82 // Done, let the main thread progress.
83 data->b.Pass(Thread::Current());
84}
85
86extern "C" JNIEXPORT void JNICALL Java_Main_testAgentThread(
87 JNIEnv* env, jclass Main_klass ATTRIBUTE_UNUSED) {
88 // Create a Thread object.
89 ScopedLocalRef<jobject> thread_name(env,
90 env->NewStringUTF("Agent Thread"));
91 if (thread_name.get() == nullptr) {
92 return;
93 }
94
95 ScopedLocalRef<jobject> thread(env, env->AllocObject(WellKnownClasses::java_lang_Thread));
96 if (thread.get() == nullptr) {
97 return;
98 }
99
100 env->CallNonvirtualVoidMethod(thread.get(),
101 WellKnownClasses::java_lang_Thread,
102 WellKnownClasses::java_lang_Thread_init,
103 Runtime::Current()->GetMainThreadGroup(),
104 thread_name.get(),
105 kMinThreadPriority,
106 JNI_FALSE);
107 if (env->ExceptionCheck()) {
108 return;
109 }
110
111 jthread main_thread;
112 jvmtiError main_thread_result = jvmti_env->GetCurrentThread(&main_thread);
113 if (JvmtiErrorToException(env, main_thread_result)) {
114 return;
115 }
116
117 AgentData data;
118 data.main_thread = env->NewGlobalRef(main_thread);
119 data.jvmti_env = jvmti_env;
120 data.priority = JVMTI_THREAD_MIN_PRIORITY;
121
122 jvmtiError result = jvmti_env->RunAgentThread(thread.get(), AgentMain, &data, data.priority);
123 if (JvmtiErrorToException(env, result)) {
124 return;
125 }
126
127 data.b.Wait(Thread::Current());
128
Andreas Gampee0220152017-02-07 14:59:08 -0800129 // Scheduling may mean that the agent thread is put to sleep. Wait until it's dead in an effort
130 // to not unload the plugin and crash.
131 for (;;) {
132 NanoSleep(1000 * 1000);
133 jint thread_state;
134 jvmtiError state_result = jvmti_env->GetThreadState(thread.get(), &thread_state);
135 if (JvmtiErrorToException(env, state_result)) {
136 return;
137 }
138 if (thread_state == 0 || // Was never alive.
139 (thread_state & JVMTI_THREAD_STATE_TERMINATED) != 0) { // Was alive and died.
140 break;
141 }
142 }
143 // Yield and sleep a bit more, to give the plugin time to tear down the native thread structure.
144 sched_yield();
145 NanoSleep(100 * 1000 * 1000);
146
Andreas Gampe732b0ac2017-01-18 15:23:39 -0800147 env->DeleteGlobalRef(data.main_thread);
148}
149
150} // namespace Test930AgentThread
151} // namespace art