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