blob: 62729cafe0504ab19f72c1d0f349eb467f70c15e [file] [log] [blame]
Andreas Gampe04bbb5b2017-01-19 17:49:03 +00001/*
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 "runtime_callbacks.h"
18
19#include "jni.h"
20#include <memory>
21#include <string>
22
23#include "art_method-inl.h"
24#include "base/mutex.h"
25#include "mirror/class-inl.h"
26#include "common_runtime_test.h"
27#include "mem_map.h"
28#include "obj_ptr.h"
29#include "runtime.h"
30#include "scoped_thread_state_change-inl.h"
31#include "ScopedLocalRef.h"
32#include "thread-inl.h"
33#include "thread_list.h"
34#include "well_known_classes.h"
35
36namespace art {
37
38class RuntimeCallbacksTest : public CommonRuntimeTest {
39 protected:
40 void SetUp() OVERRIDE {
41 CommonRuntimeTest::SetUp();
42
43 Thread* self = Thread::Current();
44 ScopedObjectAccess soa(self);
45 ScopedThreadSuspension sts(self, kWaitingForDebuggerToAttach);
46 ScopedSuspendAll ssa("RuntimeCallbacksTest SetUp");
47 AddListener();
48 }
49
50 void TearDown() OVERRIDE {
51 {
52 Thread* self = Thread::Current();
53 ScopedObjectAccess soa(self);
54 ScopedThreadSuspension sts(self, kWaitingForDebuggerToAttach);
55 ScopedSuspendAll ssa("RuntimeCallbacksTest TearDown");
56 AddListener();
57 RemoveListener();
58 }
59
60 CommonRuntimeTest::TearDown();
61 }
62
63 virtual void AddListener() REQUIRES(Locks::mutator_lock_) = 0;
64 virtual void RemoveListener() REQUIRES(Locks::mutator_lock_) = 0;
65
66 void MakeExecutable(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
67 CHECK(klass != nullptr);
68 PointerSize pointer_size = class_linker_->GetImagePointerSize();
69 for (auto& m : klass->GetMethods(pointer_size)) {
70 if (!m.IsAbstract()) {
71 class_linker_->SetEntryPointsToInterpreter(&m);
72 }
73 }
74 }
75};
76
77class ThreadLifecycleCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
78 public:
79 static void* PthreadsCallback(void* arg ATTRIBUTE_UNUSED) {
80 // Attach.
81 Runtime* runtime = Runtime::Current();
82 CHECK(runtime->AttachCurrentThread("ThreadLifecycle test thread", true, nullptr, false));
83
84 // Detach.
85 runtime->DetachCurrentThread();
86
87 // Die...
88 return nullptr;
89 }
90
91 protected:
92 void AddListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
93 Runtime::Current()->GetRuntimeCallbacks().AddThreadLifecycleCallback(&cb_);
94 }
95 void RemoveListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
96 Runtime::Current()->GetRuntimeCallbacks().RemoveThreadLifecycleCallback(&cb_);
97 }
98
99 enum CallbackState {
100 kBase,
101 kStarted,
102 kDied,
103 kWrongStart,
104 kWrongDeath,
105 };
106
107 struct Callback : public ThreadLifecycleCallback {
108 void ThreadStart(Thread* self) OVERRIDE {
109 if (state == CallbackState::kBase) {
110 state = CallbackState::kStarted;
111 stored_self = self;
112 } else {
113 state = CallbackState::kWrongStart;
114 }
115 }
116
117 void ThreadDeath(Thread* self) OVERRIDE {
118 if (state == CallbackState::kStarted && self == stored_self) {
119 state = CallbackState::kDied;
120 } else {
121 state = CallbackState::kWrongDeath;
122 }
123 }
124
125 Thread* stored_self;
126 CallbackState state = CallbackState::kBase;
127 };
128
129 Callback cb_;
130};
131
132
133TEST_F(ThreadLifecycleCallbackRuntimeCallbacksTest, ThreadLifecycleCallbackJava) {
134 Thread* self = Thread::Current();
135
136 self->TransitionFromSuspendedToRunnable();
137 bool started = runtime_->Start();
138 ASSERT_TRUE(started);
139
140 cb_.state = CallbackState::kBase; // Ignore main thread attach.
141
142 {
143 ScopedObjectAccess soa(self);
144 MakeExecutable(soa.Decode<mirror::Class>(WellKnownClasses::java_lang_Thread));
145 }
146
147 JNIEnv* env = self->GetJniEnv();
148
149 ScopedLocalRef<jobject> thread_name(env,
150 env->NewStringUTF("ThreadLifecycleCallback test thread"));
151 ASSERT_TRUE(thread_name.get() != nullptr);
152
153 ScopedLocalRef<jobject> thread(env, env->AllocObject(WellKnownClasses::java_lang_Thread));
154 ASSERT_TRUE(thread.get() != nullptr);
155
156 env->CallNonvirtualVoidMethod(thread.get(),
157 WellKnownClasses::java_lang_Thread,
158 WellKnownClasses::java_lang_Thread_init,
159 runtime_->GetMainThreadGroup(),
160 thread_name.get(),
161 kMinThreadPriority,
162 JNI_FALSE);
163 ASSERT_FALSE(env->ExceptionCheck());
164
165 jmethodID start_id = env->GetMethodID(WellKnownClasses::java_lang_Thread, "start", "()V");
166 ASSERT_TRUE(start_id != nullptr);
167
168 env->CallVoidMethod(thread.get(), start_id);
169 ASSERT_FALSE(env->ExceptionCheck());
170
171 jmethodID join_id = env->GetMethodID(WellKnownClasses::java_lang_Thread, "join", "()V");
172 ASSERT_TRUE(join_id != nullptr);
173
174 env->CallVoidMethod(thread.get(), join_id);
175 ASSERT_FALSE(env->ExceptionCheck());
176
177 EXPECT_TRUE(cb_.state == CallbackState::kDied) << static_cast<int>(cb_.state);
178}
179
180TEST_F(ThreadLifecycleCallbackRuntimeCallbacksTest, ThreadLifecycleCallbackAttach) {
181 std::string error_msg;
182 std::unique_ptr<MemMap> stack(MemMap::MapAnonymous("ThreadLifecycleCallback Thread",
183 nullptr,
184 128 * kPageSize, // Just some small stack.
185 PROT_READ | PROT_WRITE,
186 false,
187 false,
188 &error_msg));
189 ASSERT_FALSE(stack == nullptr) << error_msg;
190
191 const char* reason = "ThreadLifecycleCallback test thread";
192 pthread_attr_t attr;
193 CHECK_PTHREAD_CALL(pthread_attr_init, (&attr), reason);
194 CHECK_PTHREAD_CALL(pthread_attr_setstack, (&attr, stack->Begin(), stack->Size()), reason);
195 pthread_t pthread;
196 CHECK_PTHREAD_CALL(pthread_create,
197 (&pthread,
198 &attr,
199 &ThreadLifecycleCallbackRuntimeCallbacksTest::PthreadsCallback,
200 this),
201 reason);
202 CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), reason);
203
204 CHECK_PTHREAD_CALL(pthread_join, (pthread, nullptr), "ThreadLifecycleCallback test shutdown");
205
206 // Detach is not a ThreadDeath event, so we expect to be in state Started.
207 EXPECT_TRUE(cb_.state == CallbackState::kStarted) << static_cast<int>(cb_.state);
208}
209
210} // namespace art