blob: 8974b595de2c3d928930c3148513d45fde1a7a5d [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"
Andreas Gampea5814f92017-01-18 21:43:16 -080020#include <signal.h>
21#include <sys/types.h>
22#include <unistd.h>
Andreas Gampe0f01b582017-01-18 15:22:37 -080023
24#include <initializer_list>
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000025#include <memory>
26#include <string>
27
28#include "art_method-inl.h"
29#include "base/mutex.h"
Andreas Gampe0f01b582017-01-18 15:22:37 -080030#include "class_linker.h"
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000031#include "common_runtime_test.h"
Andreas Gampe0f01b582017-01-18 15:22:37 -080032#include "handle.h"
33#include "handle_scope-inl.h"
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000034#include "mem_map.h"
Andreas Gampe0f01b582017-01-18 15:22:37 -080035#include "mirror/class-inl.h"
36#include "mirror/class_loader.h"
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000037#include "obj_ptr.h"
38#include "runtime.h"
39#include "scoped_thread_state_change-inl.h"
40#include "ScopedLocalRef.h"
41#include "thread-inl.h"
42#include "thread_list.h"
43#include "well_known_classes.h"
44
45namespace art {
46
47class RuntimeCallbacksTest : public CommonRuntimeTest {
48 protected:
49 void SetUp() OVERRIDE {
50 CommonRuntimeTest::SetUp();
51
52 Thread* self = Thread::Current();
53 ScopedObjectAccess soa(self);
54 ScopedThreadSuspension sts(self, kWaitingForDebuggerToAttach);
55 ScopedSuspendAll ssa("RuntimeCallbacksTest SetUp");
56 AddListener();
57 }
58
59 void TearDown() OVERRIDE {
60 {
61 Thread* self = Thread::Current();
62 ScopedObjectAccess soa(self);
63 ScopedThreadSuspension sts(self, kWaitingForDebuggerToAttach);
64 ScopedSuspendAll ssa("RuntimeCallbacksTest TearDown");
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000065 RemoveListener();
66 }
67
68 CommonRuntimeTest::TearDown();
69 }
70
71 virtual void AddListener() REQUIRES(Locks::mutator_lock_) = 0;
72 virtual void RemoveListener() REQUIRES(Locks::mutator_lock_) = 0;
73
74 void MakeExecutable(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
75 CHECK(klass != nullptr);
76 PointerSize pointer_size = class_linker_->GetImagePointerSize();
77 for (auto& m : klass->GetMethods(pointer_size)) {
78 if (!m.IsAbstract()) {
79 class_linker_->SetEntryPointsToInterpreter(&m);
80 }
81 }
82 }
83};
84
85class ThreadLifecycleCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
86 public:
87 static void* PthreadsCallback(void* arg ATTRIBUTE_UNUSED) {
88 // Attach.
89 Runtime* runtime = Runtime::Current();
90 CHECK(runtime->AttachCurrentThread("ThreadLifecycle test thread", true, nullptr, false));
91
92 // Detach.
93 runtime->DetachCurrentThread();
94
95 // Die...
96 return nullptr;
97 }
98
99 protected:
100 void AddListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800101 Runtime::Current()->GetRuntimeCallbacks()->AddThreadLifecycleCallback(&cb_);
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000102 }
103 void RemoveListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800104 Runtime::Current()->GetRuntimeCallbacks()->RemoveThreadLifecycleCallback(&cb_);
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000105 }
106
107 enum CallbackState {
108 kBase,
109 kStarted,
110 kDied,
111 kWrongStart,
112 kWrongDeath,
113 };
114
115 struct Callback : public ThreadLifecycleCallback {
116 void ThreadStart(Thread* self) OVERRIDE {
117 if (state == CallbackState::kBase) {
118 state = CallbackState::kStarted;
119 stored_self = self;
120 } else {
121 state = CallbackState::kWrongStart;
122 }
123 }
124
125 void ThreadDeath(Thread* self) OVERRIDE {
126 if (state == CallbackState::kStarted && self == stored_self) {
127 state = CallbackState::kDied;
128 } else {
129 state = CallbackState::kWrongDeath;
130 }
131 }
132
133 Thread* stored_self;
134 CallbackState state = CallbackState::kBase;
135 };
136
137 Callback cb_;
138};
139
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000140TEST_F(ThreadLifecycleCallbackRuntimeCallbacksTest, ThreadLifecycleCallbackJava) {
141 Thread* self = Thread::Current();
142
143 self->TransitionFromSuspendedToRunnable();
144 bool started = runtime_->Start();
145 ASSERT_TRUE(started);
146
147 cb_.state = CallbackState::kBase; // Ignore main thread attach.
148
149 {
150 ScopedObjectAccess soa(self);
151 MakeExecutable(soa.Decode<mirror::Class>(WellKnownClasses::java_lang_Thread));
152 }
153
154 JNIEnv* env = self->GetJniEnv();
155
156 ScopedLocalRef<jobject> thread_name(env,
157 env->NewStringUTF("ThreadLifecycleCallback test thread"));
158 ASSERT_TRUE(thread_name.get() != nullptr);
159
160 ScopedLocalRef<jobject> thread(env, env->AllocObject(WellKnownClasses::java_lang_Thread));
161 ASSERT_TRUE(thread.get() != nullptr);
162
163 env->CallNonvirtualVoidMethod(thread.get(),
164 WellKnownClasses::java_lang_Thread,
165 WellKnownClasses::java_lang_Thread_init,
166 runtime_->GetMainThreadGroup(),
167 thread_name.get(),
168 kMinThreadPriority,
169 JNI_FALSE);
170 ASSERT_FALSE(env->ExceptionCheck());
171
172 jmethodID start_id = env->GetMethodID(WellKnownClasses::java_lang_Thread, "start", "()V");
173 ASSERT_TRUE(start_id != nullptr);
174
175 env->CallVoidMethod(thread.get(), start_id);
176 ASSERT_FALSE(env->ExceptionCheck());
177
178 jmethodID join_id = env->GetMethodID(WellKnownClasses::java_lang_Thread, "join", "()V");
179 ASSERT_TRUE(join_id != nullptr);
180
181 env->CallVoidMethod(thread.get(), join_id);
182 ASSERT_FALSE(env->ExceptionCheck());
183
184 EXPECT_TRUE(cb_.state == CallbackState::kDied) << static_cast<int>(cb_.state);
185}
186
187TEST_F(ThreadLifecycleCallbackRuntimeCallbacksTest, ThreadLifecycleCallbackAttach) {
188 std::string error_msg;
189 std::unique_ptr<MemMap> stack(MemMap::MapAnonymous("ThreadLifecycleCallback Thread",
190 nullptr,
191 128 * kPageSize, // Just some small stack.
192 PROT_READ | PROT_WRITE,
193 false,
194 false,
195 &error_msg));
196 ASSERT_FALSE(stack == nullptr) << error_msg;
197
198 const char* reason = "ThreadLifecycleCallback test thread";
199 pthread_attr_t attr;
200 CHECK_PTHREAD_CALL(pthread_attr_init, (&attr), reason);
201 CHECK_PTHREAD_CALL(pthread_attr_setstack, (&attr, stack->Begin(), stack->Size()), reason);
202 pthread_t pthread;
203 CHECK_PTHREAD_CALL(pthread_create,
204 (&pthread,
205 &attr,
206 &ThreadLifecycleCallbackRuntimeCallbacksTest::PthreadsCallback,
207 this),
208 reason);
209 CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), reason);
210
211 CHECK_PTHREAD_CALL(pthread_join, (pthread, nullptr), "ThreadLifecycleCallback test shutdown");
212
213 // Detach is not a ThreadDeath event, so we expect to be in state Started.
214 EXPECT_TRUE(cb_.state == CallbackState::kStarted) << static_cast<int>(cb_.state);
215}
216
Andreas Gampe0f01b582017-01-18 15:22:37 -0800217class ClassLoadCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
218 protected:
219 void AddListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800220 Runtime::Current()->GetRuntimeCallbacks()->AddClassLoadCallback(&cb_);
Andreas Gampe0f01b582017-01-18 15:22:37 -0800221 }
222 void RemoveListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800223 Runtime::Current()->GetRuntimeCallbacks()->RemoveClassLoadCallback(&cb_);
Andreas Gampe0f01b582017-01-18 15:22:37 -0800224 }
225
226 bool Expect(std::initializer_list<const char*> list) {
227 if (cb_.data.size() != list.size()) {
228 PrintError(list);
229 return false;
230 }
231
232 if (!std::equal(cb_.data.begin(), cb_.data.end(), list.begin())) {
233 PrintError(list);
234 return false;
235 }
236
237 return true;
238 }
239
240 void PrintError(std::initializer_list<const char*> list) {
241 LOG(ERROR) << "Expected:";
242 for (const char* expected : list) {
243 LOG(ERROR) << " " << expected;
244 }
245 LOG(ERROR) << "Found:";
246 for (const auto& s : cb_.data) {
247 LOG(ERROR) << " " << s;
248 }
249 }
250
251 struct Callback : public ClassLoadCallback {
252 void ClassLoad(Handle<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
253 std::string tmp;
254 std::string event = std::string("Load:") + klass->GetDescriptor(&tmp);
255 data.push_back(event);
256 }
257
258 void ClassPrepare(Handle<mirror::Class> temp_klass,
259 Handle<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
260 std::string tmp, tmp2;
261 std::string event = std::string("Prepare:") + klass->GetDescriptor(&tmp)
262 + "[" + temp_klass->GetDescriptor(&tmp2) + "]";
263 data.push_back(event);
264 }
265
266 std::vector<std::string> data;
267 };
268
269 Callback cb_;
270};
271
272TEST_F(ClassLoadCallbackRuntimeCallbacksTest, ClassLoadCallback) {
273 ScopedObjectAccess soa(Thread::Current());
274 jobject jclass_loader = LoadDex("XandY");
275 VariableSizedHandleScope hs(soa.Self());
276 Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
277 soa.Decode<mirror::ClassLoader>(jclass_loader)));
278
279 const char* descriptor_y = "LY;";
280 Handle<mirror::Class> h_Y(
281 hs.NewHandle(class_linker_->FindClass(soa.Self(), descriptor_y, class_loader)));
282 ASSERT_TRUE(h_Y.Get() != nullptr);
283
284 bool expect1 = Expect({ "Load:LX;", "Prepare:LX;[LX;]", "Load:LY;", "Prepare:LY;[LY;]" });
285 EXPECT_TRUE(expect1);
286
287 cb_.data.clear();
288
289 ASSERT_TRUE(class_linker_->EnsureInitialized(Thread::Current(), h_Y, true, true));
290
291 bool expect2 = Expect({ "Load:LY$Z;", "Prepare:LY$Z;[LY$Z;]" });
292 EXPECT_TRUE(expect2);
293}
294
Andreas Gampea5814f92017-01-18 21:43:16 -0800295class RuntimeSigQuitCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
296 protected:
297 void AddListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
298 Runtime::Current()->GetRuntimeCallbacks()->AddRuntimeSigQuitCallback(&cb_);
299 }
300 void RemoveListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
301 Runtime::Current()->GetRuntimeCallbacks()->RemoveRuntimeSigQuitCallback(&cb_);
302 }
303
304 struct Callback : public RuntimeSigQuitCallback {
305 void SigQuit() OVERRIDE {
306 ++sigquit_count;
307 }
308
309 size_t sigquit_count = 0;
310 };
311
312 Callback cb_;
313};
314
315TEST_F(RuntimeSigQuitCallbackRuntimeCallbacksTest, SigQuit) {
316 // The runtime needs to be started for the signal handler.
317 Thread* self = Thread::Current();
318
319 self->TransitionFromSuspendedToRunnable();
320 bool started = runtime_->Start();
321 ASSERT_TRUE(started);
322
323 EXPECT_EQ(0u, cb_.sigquit_count);
324
325 kill(getpid(), SIGQUIT);
326
327 // Try a few times.
328 for (size_t i = 0; i != 30; ++i) {
329 if (cb_.sigquit_count == 0) {
330 sleep(1);
331 } else {
332 break;
333 }
334 }
335 EXPECT_EQ(1u, cb_.sigquit_count);
336}
337
Andreas Gampe48864112017-01-19 17:23:17 -0800338class RuntimePhaseCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
339 protected:
340 void AddListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
341 Runtime::Current()->GetRuntimeCallbacks()->AddRuntimePhaseCallback(&cb_);
342 }
343 void RemoveListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
344 Runtime::Current()->GetRuntimeCallbacks()->RemoveRuntimePhaseCallback(&cb_);
345 }
346
347 void TearDown() OVERRIDE {
348 // Bypass RuntimeCallbacksTest::TearDown, as the runtime is already gone.
349 CommonRuntimeTest::TearDown();
350 }
351
352 struct Callback : public RuntimePhaseCallback {
353 void NextRuntimePhase(RuntimePhaseCallback::RuntimePhase p) OVERRIDE {
Andreas Gampe96eca782017-01-19 19:45:30 -0800354 if (p == RuntimePhaseCallback::RuntimePhase::kInitialAgents) {
355 if (start_seen > 0 || init_seen > 0 || death_seen > 0) {
356 LOG(FATAL) << "Unexpected order";
357 }
358 ++initial_agents_seen;
359 } else if (p == RuntimePhaseCallback::RuntimePhase::kStart) {
360 if (init_seen > 0 || death_seen > 0) {
Andreas Gampe48864112017-01-19 17:23:17 -0800361 LOG(FATAL) << "Init seen before start.";
362 }
363 ++start_seen;
364 } else if (p == RuntimePhaseCallback::RuntimePhase::kInit) {
365 ++init_seen;
366 } else if (p == RuntimePhaseCallback::RuntimePhase::kDeath) {
367 ++death_seen;
368 } else {
369 LOG(FATAL) << "Unknown phase " << static_cast<uint32_t>(p);
370 }
371 }
372
Andreas Gampe96eca782017-01-19 19:45:30 -0800373 size_t initial_agents_seen = 0;
Andreas Gampe48864112017-01-19 17:23:17 -0800374 size_t start_seen = 0;
375 size_t init_seen = 0;
376 size_t death_seen = 0;
377 };
378
379 Callback cb_;
380};
381
382TEST_F(RuntimePhaseCallbackRuntimeCallbacksTest, Phases) {
Andreas Gampe96eca782017-01-19 19:45:30 -0800383 ASSERT_EQ(0u, cb_.initial_agents_seen);
Andreas Gampe48864112017-01-19 17:23:17 -0800384 ASSERT_EQ(0u, cb_.start_seen);
385 ASSERT_EQ(0u, cb_.init_seen);
386 ASSERT_EQ(0u, cb_.death_seen);
387
388 // Start the runtime.
389 {
390 Thread* self = Thread::Current();
391 self->TransitionFromSuspendedToRunnable();
392 bool started = runtime_->Start();
393 ASSERT_TRUE(started);
394 }
395
Andreas Gampe96eca782017-01-19 19:45:30 -0800396 ASSERT_EQ(0u, cb_.initial_agents_seen);
Andreas Gampe48864112017-01-19 17:23:17 -0800397 ASSERT_EQ(1u, cb_.start_seen);
398 ASSERT_EQ(1u, cb_.init_seen);
399 ASSERT_EQ(0u, cb_.death_seen);
400
401 // Delete the runtime.
402 runtime_.reset();
403
Andreas Gampe96eca782017-01-19 19:45:30 -0800404 ASSERT_EQ(0u, cb_.initial_agents_seen);
Andreas Gampe48864112017-01-19 17:23:17 -0800405 ASSERT_EQ(1u, cb_.start_seen);
406 ASSERT_EQ(1u, cb_.init_seen);
407 ASSERT_EQ(1u, cb_.death_seen);
408}
409
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000410} // namespace art