blob: 983278d97e05aff034245b4be7e7f4c8e2712308 [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
Andreas Gampea5814f92017-01-18 21:43:16 -080019#include <signal.h>
20#include <sys/types.h>
21#include <unistd.h>
Andreas Gampe0f01b582017-01-18 15:22:37 -080022
23#include <initializer_list>
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000024#include <memory>
25#include <string>
26
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070027#include "jni.h"
28
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000029#include "art_method-inl.h"
30#include "base/mutex.h"
Andreas Gampe0f01b582017-01-18 15:22:37 -080031#include "class_linker.h"
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000032#include "common_runtime_test.h"
Andreas Gampe0f01b582017-01-18 15:22:37 -080033#include "handle.h"
34#include "handle_scope-inl.h"
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000035#include "mem_map.h"
Andreas Gampe0f01b582017-01-18 15:22:37 -080036#include "mirror/class-inl.h"
37#include "mirror/class_loader.h"
Steven Morelande431e272017-07-18 16:53:49 -070038#include "nativehelper/ScopedLocalRef.h"
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000039#include "obj_ptr.h"
40#include "runtime.h"
41#include "scoped_thread_state_change-inl.h"
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000042#include "thread-inl.h"
43#include "thread_list.h"
44#include "well_known_classes.h"
45
46namespace art {
47
48class RuntimeCallbacksTest : public CommonRuntimeTest {
49 protected:
50 void SetUp() OVERRIDE {
51 CommonRuntimeTest::SetUp();
52
53 Thread* self = Thread::Current();
54 ScopedObjectAccess soa(self);
55 ScopedThreadSuspension sts(self, kWaitingForDebuggerToAttach);
56 ScopedSuspendAll ssa("RuntimeCallbacksTest SetUp");
57 AddListener();
58 }
59
60 void TearDown() OVERRIDE {
61 {
62 Thread* self = Thread::Current();
63 ScopedObjectAccess soa(self);
64 ScopedThreadSuspension sts(self, kWaitingForDebuggerToAttach);
65 ScopedSuspendAll ssa("RuntimeCallbacksTest TearDown");
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000066 RemoveListener();
67 }
68
69 CommonRuntimeTest::TearDown();
70 }
71
72 virtual void AddListener() REQUIRES(Locks::mutator_lock_) = 0;
73 virtual void RemoveListener() REQUIRES(Locks::mutator_lock_) = 0;
74
75 void MakeExecutable(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
76 CHECK(klass != nullptr);
77 PointerSize pointer_size = class_linker_->GetImagePointerSize();
78 for (auto& m : klass->GetMethods(pointer_size)) {
79 if (!m.IsAbstract()) {
80 class_linker_->SetEntryPointsToInterpreter(&m);
81 }
82 }
83 }
84};
85
86class ThreadLifecycleCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
87 public:
88 static void* PthreadsCallback(void* arg ATTRIBUTE_UNUSED) {
89 // Attach.
90 Runtime* runtime = Runtime::Current();
91 CHECK(runtime->AttachCurrentThread("ThreadLifecycle test thread", true, nullptr, false));
92
93 // Detach.
94 runtime->DetachCurrentThread();
95
96 // Die...
97 return nullptr;
98 }
99
100 protected:
101 void AddListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800102 Runtime::Current()->GetRuntimeCallbacks()->AddThreadLifecycleCallback(&cb_);
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000103 }
104 void RemoveListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800105 Runtime::Current()->GetRuntimeCallbacks()->RemoveThreadLifecycleCallback(&cb_);
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000106 }
107
108 enum CallbackState {
109 kBase,
110 kStarted,
111 kDied,
112 kWrongStart,
113 kWrongDeath,
114 };
115
116 struct Callback : public ThreadLifecycleCallback {
117 void ThreadStart(Thread* self) OVERRIDE {
118 if (state == CallbackState::kBase) {
119 state = CallbackState::kStarted;
120 stored_self = self;
121 } else {
122 state = CallbackState::kWrongStart;
123 }
124 }
125
126 void ThreadDeath(Thread* self) OVERRIDE {
127 if (state == CallbackState::kStarted && self == stored_self) {
128 state = CallbackState::kDied;
129 } else {
130 state = CallbackState::kWrongDeath;
131 }
132 }
133
134 Thread* stored_self;
135 CallbackState state = CallbackState::kBase;
136 };
137
138 Callback cb_;
139};
140
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000141TEST_F(ThreadLifecycleCallbackRuntimeCallbacksTest, ThreadLifecycleCallbackJava) {
142 Thread* self = Thread::Current();
143
144 self->TransitionFromSuspendedToRunnable();
145 bool started = runtime_->Start();
146 ASSERT_TRUE(started);
147
148 cb_.state = CallbackState::kBase; // Ignore main thread attach.
149
150 {
151 ScopedObjectAccess soa(self);
152 MakeExecutable(soa.Decode<mirror::Class>(WellKnownClasses::java_lang_Thread));
153 }
154
155 JNIEnv* env = self->GetJniEnv();
156
157 ScopedLocalRef<jobject> thread_name(env,
158 env->NewStringUTF("ThreadLifecycleCallback test thread"));
159 ASSERT_TRUE(thread_name.get() != nullptr);
160
161 ScopedLocalRef<jobject> thread(env, env->AllocObject(WellKnownClasses::java_lang_Thread));
162 ASSERT_TRUE(thread.get() != nullptr);
163
164 env->CallNonvirtualVoidMethod(thread.get(),
165 WellKnownClasses::java_lang_Thread,
166 WellKnownClasses::java_lang_Thread_init,
167 runtime_->GetMainThreadGroup(),
168 thread_name.get(),
169 kMinThreadPriority,
170 JNI_FALSE);
171 ASSERT_FALSE(env->ExceptionCheck());
172
173 jmethodID start_id = env->GetMethodID(WellKnownClasses::java_lang_Thread, "start", "()V");
174 ASSERT_TRUE(start_id != nullptr);
175
176 env->CallVoidMethod(thread.get(), start_id);
177 ASSERT_FALSE(env->ExceptionCheck());
178
179 jmethodID join_id = env->GetMethodID(WellKnownClasses::java_lang_Thread, "join", "()V");
180 ASSERT_TRUE(join_id != nullptr);
181
182 env->CallVoidMethod(thread.get(), join_id);
183 ASSERT_FALSE(env->ExceptionCheck());
184
185 EXPECT_TRUE(cb_.state == CallbackState::kDied) << static_cast<int>(cb_.state);
186}
187
188TEST_F(ThreadLifecycleCallbackRuntimeCallbacksTest, ThreadLifecycleCallbackAttach) {
189 std::string error_msg;
190 std::unique_ptr<MemMap> stack(MemMap::MapAnonymous("ThreadLifecycleCallback Thread",
191 nullptr,
192 128 * kPageSize, // Just some small stack.
193 PROT_READ | PROT_WRITE,
194 false,
195 false,
196 &error_msg));
197 ASSERT_FALSE(stack == nullptr) << error_msg;
198
199 const char* reason = "ThreadLifecycleCallback test thread";
200 pthread_attr_t attr;
201 CHECK_PTHREAD_CALL(pthread_attr_init, (&attr), reason);
202 CHECK_PTHREAD_CALL(pthread_attr_setstack, (&attr, stack->Begin(), stack->Size()), reason);
203 pthread_t pthread;
204 CHECK_PTHREAD_CALL(pthread_create,
205 (&pthread,
206 &attr,
207 &ThreadLifecycleCallbackRuntimeCallbacksTest::PthreadsCallback,
208 this),
209 reason);
210 CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), reason);
211
212 CHECK_PTHREAD_CALL(pthread_join, (pthread, nullptr), "ThreadLifecycleCallback test shutdown");
213
214 // Detach is not a ThreadDeath event, so we expect to be in state Started.
215 EXPECT_TRUE(cb_.state == CallbackState::kStarted) << static_cast<int>(cb_.state);
216}
217
Andreas Gampe0f01b582017-01-18 15:22:37 -0800218class ClassLoadCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
219 protected:
220 void AddListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800221 Runtime::Current()->GetRuntimeCallbacks()->AddClassLoadCallback(&cb_);
Andreas Gampe0f01b582017-01-18 15:22:37 -0800222 }
223 void RemoveListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800224 Runtime::Current()->GetRuntimeCallbacks()->RemoveClassLoadCallback(&cb_);
Andreas Gampe0f01b582017-01-18 15:22:37 -0800225 }
226
227 bool Expect(std::initializer_list<const char*> list) {
228 if (cb_.data.size() != list.size()) {
229 PrintError(list);
230 return false;
231 }
232
233 if (!std::equal(cb_.data.begin(), cb_.data.end(), list.begin())) {
234 PrintError(list);
235 return false;
236 }
237
238 return true;
239 }
240
241 void PrintError(std::initializer_list<const char*> list) {
242 LOG(ERROR) << "Expected:";
243 for (const char* expected : list) {
244 LOG(ERROR) << " " << expected;
245 }
246 LOG(ERROR) << "Found:";
247 for (const auto& s : cb_.data) {
248 LOG(ERROR) << " " << s;
249 }
250 }
251
252 struct Callback : public ClassLoadCallback {
Alex Lightb0f11922017-01-23 14:25:17 -0800253 virtual void ClassPreDefine(const char* descriptor,
254 Handle<mirror::Class> klass ATTRIBUTE_UNUSED,
255 Handle<mirror::ClassLoader> class_loader ATTRIBUTE_UNUSED,
256 const DexFile& initial_dex_file,
257 const DexFile::ClassDef& initial_class_def ATTRIBUTE_UNUSED,
258 /*out*/DexFile const** final_dex_file ATTRIBUTE_UNUSED,
Alex Light4b0cedf2017-01-24 11:15:20 -0800259 /*out*/DexFile::ClassDef const** final_class_def ATTRIBUTE_UNUSED)
Alex Lightb0f11922017-01-23 14:25:17 -0800260 OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
261 std::string location(initial_dex_file.GetLocation());
262 std::string event =
263 std::string("PreDefine:") + descriptor + " <" +
264 location.substr(location.rfind("/") + 1, location.size()) + ">";
265 data.push_back(event);
266 }
267
Andreas Gampe0f01b582017-01-18 15:22:37 -0800268 void ClassLoad(Handle<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
269 std::string tmp;
270 std::string event = std::string("Load:") + klass->GetDescriptor(&tmp);
271 data.push_back(event);
272 }
273
274 void ClassPrepare(Handle<mirror::Class> temp_klass,
275 Handle<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
276 std::string tmp, tmp2;
277 std::string event = std::string("Prepare:") + klass->GetDescriptor(&tmp)
278 + "[" + temp_klass->GetDescriptor(&tmp2) + "]";
279 data.push_back(event);
280 }
281
282 std::vector<std::string> data;
283 };
284
285 Callback cb_;
286};
287
288TEST_F(ClassLoadCallbackRuntimeCallbacksTest, ClassLoadCallback) {
289 ScopedObjectAccess soa(Thread::Current());
290 jobject jclass_loader = LoadDex("XandY");
291 VariableSizedHandleScope hs(soa.Self());
292 Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
293 soa.Decode<mirror::ClassLoader>(jclass_loader)));
294
295 const char* descriptor_y = "LY;";
296 Handle<mirror::Class> h_Y(
297 hs.NewHandle(class_linker_->FindClass(soa.Self(), descriptor_y, class_loader)));
Andreas Gampefa4333d2017-02-14 11:10:34 -0800298 ASSERT_TRUE(h_Y != nullptr);
Andreas Gampe0f01b582017-01-18 15:22:37 -0800299
Alex Lightb0f11922017-01-23 14:25:17 -0800300 bool expect1 = Expect({ "PreDefine:LY; <art-gtest-XandY.jar>",
301 "PreDefine:LX; <art-gtest-XandY.jar>",
302 "Load:LX;",
303 "Prepare:LX;[LX;]",
304 "Load:LY;",
305 "Prepare:LY;[LY;]" });
Andreas Gampe0f01b582017-01-18 15:22:37 -0800306 EXPECT_TRUE(expect1);
307
308 cb_.data.clear();
309
310 ASSERT_TRUE(class_linker_->EnsureInitialized(Thread::Current(), h_Y, true, true));
311
Alex Lightb0f11922017-01-23 14:25:17 -0800312 bool expect2 = Expect({ "PreDefine:LY$Z; <art-gtest-XandY.jar>",
313 "Load:LY$Z;",
314 "Prepare:LY$Z;[LY$Z;]" });
Andreas Gampe0f01b582017-01-18 15:22:37 -0800315 EXPECT_TRUE(expect2);
316}
317
Andreas Gampea5814f92017-01-18 21:43:16 -0800318class RuntimeSigQuitCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
319 protected:
320 void AddListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
321 Runtime::Current()->GetRuntimeCallbacks()->AddRuntimeSigQuitCallback(&cb_);
322 }
323 void RemoveListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
324 Runtime::Current()->GetRuntimeCallbacks()->RemoveRuntimeSigQuitCallback(&cb_);
325 }
326
327 struct Callback : public RuntimeSigQuitCallback {
328 void SigQuit() OVERRIDE {
329 ++sigquit_count;
330 }
331
332 size_t sigquit_count = 0;
333 };
334
335 Callback cb_;
336};
337
338TEST_F(RuntimeSigQuitCallbackRuntimeCallbacksTest, SigQuit) {
Andreas Gampef4a67fd2017-05-04 09:55:36 -0700339 // SigQuit induces a dump. ASAN isn't happy with libunwind reading memory.
340 TEST_DISABLED_FOR_MEMORY_TOOL_ASAN();
341
Andreas Gampea5814f92017-01-18 21:43:16 -0800342 // The runtime needs to be started for the signal handler.
343 Thread* self = Thread::Current();
344
345 self->TransitionFromSuspendedToRunnable();
346 bool started = runtime_->Start();
347 ASSERT_TRUE(started);
348
349 EXPECT_EQ(0u, cb_.sigquit_count);
350
351 kill(getpid(), SIGQUIT);
352
353 // Try a few times.
354 for (size_t i = 0; i != 30; ++i) {
355 if (cb_.sigquit_count == 0) {
356 sleep(1);
357 } else {
358 break;
359 }
360 }
361 EXPECT_EQ(1u, cb_.sigquit_count);
362}
363
Andreas Gampe48864112017-01-19 17:23:17 -0800364class RuntimePhaseCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
365 protected:
366 void AddListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
367 Runtime::Current()->GetRuntimeCallbacks()->AddRuntimePhaseCallback(&cb_);
368 }
369 void RemoveListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
370 Runtime::Current()->GetRuntimeCallbacks()->RemoveRuntimePhaseCallback(&cb_);
371 }
372
373 void TearDown() OVERRIDE {
374 // Bypass RuntimeCallbacksTest::TearDown, as the runtime is already gone.
375 CommonRuntimeTest::TearDown();
376 }
377
378 struct Callback : public RuntimePhaseCallback {
379 void NextRuntimePhase(RuntimePhaseCallback::RuntimePhase p) OVERRIDE {
Andreas Gampe96eca782017-01-19 19:45:30 -0800380 if (p == RuntimePhaseCallback::RuntimePhase::kInitialAgents) {
381 if (start_seen > 0 || init_seen > 0 || death_seen > 0) {
382 LOG(FATAL) << "Unexpected order";
383 }
384 ++initial_agents_seen;
385 } else if (p == RuntimePhaseCallback::RuntimePhase::kStart) {
386 if (init_seen > 0 || death_seen > 0) {
Andreas Gampe48864112017-01-19 17:23:17 -0800387 LOG(FATAL) << "Init seen before start.";
388 }
389 ++start_seen;
390 } else if (p == RuntimePhaseCallback::RuntimePhase::kInit) {
391 ++init_seen;
392 } else if (p == RuntimePhaseCallback::RuntimePhase::kDeath) {
393 ++death_seen;
394 } else {
395 LOG(FATAL) << "Unknown phase " << static_cast<uint32_t>(p);
396 }
397 }
398
Andreas Gampe96eca782017-01-19 19:45:30 -0800399 size_t initial_agents_seen = 0;
Andreas Gampe48864112017-01-19 17:23:17 -0800400 size_t start_seen = 0;
401 size_t init_seen = 0;
402 size_t death_seen = 0;
403 };
404
405 Callback cb_;
406};
407
408TEST_F(RuntimePhaseCallbackRuntimeCallbacksTest, Phases) {
Andreas Gampe96eca782017-01-19 19:45:30 -0800409 ASSERT_EQ(0u, cb_.initial_agents_seen);
Andreas Gampe48864112017-01-19 17:23:17 -0800410 ASSERT_EQ(0u, cb_.start_seen);
411 ASSERT_EQ(0u, cb_.init_seen);
412 ASSERT_EQ(0u, cb_.death_seen);
413
414 // Start the runtime.
415 {
416 Thread* self = Thread::Current();
417 self->TransitionFromSuspendedToRunnable();
418 bool started = runtime_->Start();
419 ASSERT_TRUE(started);
420 }
421
Andreas Gampe96eca782017-01-19 19:45:30 -0800422 ASSERT_EQ(0u, cb_.initial_agents_seen);
Andreas Gampe48864112017-01-19 17:23:17 -0800423 ASSERT_EQ(1u, cb_.start_seen);
424 ASSERT_EQ(1u, cb_.init_seen);
425 ASSERT_EQ(0u, cb_.death_seen);
426
427 // Delete the runtime.
428 runtime_.reset();
429
Andreas Gampe96eca782017-01-19 19:45:30 -0800430 ASSERT_EQ(0u, cb_.initial_agents_seen);
Andreas Gampe48864112017-01-19 17:23:17 -0800431 ASSERT_EQ(1u, cb_.start_seen);
432 ASSERT_EQ(1u, cb_.init_seen);
433 ASSERT_EQ(1u, cb_.death_seen);
434}
435
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000436} // namespace art