blob: e49deaec4934d89a375de603a9d3ec066fde3201 [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>
Igor Murashkin5573c372017-11-16 13:34:30 -080025#include <mutex>
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000026#include <string>
27
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070028#include "jni.h"
29
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000030#include "art_method-inl.h"
David Sehr79e26072018-04-06 17:58:50 -070031#include "base/mem_map.h"
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000032#include "base/mutex.h"
Andreas Gampe0f01b582017-01-18 15:22:37 -080033#include "class_linker.h"
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000034#include "common_runtime_test.h"
David Sehr312f3b22018-03-19 08:39:26 -070035#include "dex/class_reference.h"
Andreas Gampe0f01b582017-01-18 15:22:37 -080036#include "handle.h"
37#include "handle_scope-inl.h"
Andreas Gampe0f01b582017-01-18 15:22:37 -080038#include "mirror/class-inl.h"
39#include "mirror/class_loader.h"
Vladimir Markof52d92f2019-03-29 12:33:02 +000040#include "monitor-inl.h"
Andreas Gampe373a9b52017-10-18 09:01:57 -070041#include "nativehelper/scoped_local_ref.h"
Vladimir Markof52d92f2019-03-29 12:33:02 +000042#include "obj_ptr-inl.h"
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000043#include "runtime.h"
44#include "scoped_thread_state_change-inl.h"
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000045#include "thread-inl.h"
46#include "thread_list.h"
47#include "well_known_classes.h"
48
49namespace art {
50
51class RuntimeCallbacksTest : public CommonRuntimeTest {
52 protected:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010053 void SetUp() override {
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000054 CommonRuntimeTest::SetUp();
55
56 Thread* self = Thread::Current();
57 ScopedObjectAccess soa(self);
58 ScopedThreadSuspension sts(self, kWaitingForDebuggerToAttach);
59 ScopedSuspendAll ssa("RuntimeCallbacksTest SetUp");
60 AddListener();
61 }
62
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010063 void TearDown() override {
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000064 {
65 Thread* self = Thread::Current();
66 ScopedObjectAccess soa(self);
67 ScopedThreadSuspension sts(self, kWaitingForDebuggerToAttach);
68 ScopedSuspendAll ssa("RuntimeCallbacksTest TearDown");
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000069 RemoveListener();
70 }
71
72 CommonRuntimeTest::TearDown();
73 }
74
75 virtual void AddListener() REQUIRES(Locks::mutator_lock_) = 0;
76 virtual void RemoveListener() REQUIRES(Locks::mutator_lock_) = 0;
77
78 void MakeExecutable(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
79 CHECK(klass != nullptr);
80 PointerSize pointer_size = class_linker_->GetImagePointerSize();
81 for (auto& m : klass->GetMethods(pointer_size)) {
82 if (!m.IsAbstract()) {
83 class_linker_->SetEntryPointsToInterpreter(&m);
84 }
85 }
86 }
87};
88
89class ThreadLifecycleCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
90 public:
91 static void* PthreadsCallback(void* arg ATTRIBUTE_UNUSED) {
92 // Attach.
93 Runtime* runtime = Runtime::Current();
94 CHECK(runtime->AttachCurrentThread("ThreadLifecycle test thread", true, nullptr, false));
95
96 // Detach.
97 runtime->DetachCurrentThread();
98
99 // Die...
100 return nullptr;
101 }
102
103 protected:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100104 void AddListener() override REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800105 Runtime::Current()->GetRuntimeCallbacks()->AddThreadLifecycleCallback(&cb_);
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000106 }
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100107 void RemoveListener() override REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800108 Runtime::Current()->GetRuntimeCallbacks()->RemoveThreadLifecycleCallback(&cb_);
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000109 }
110
111 enum CallbackState {
112 kBase,
113 kStarted,
114 kDied,
115 kWrongStart,
116 kWrongDeath,
117 };
118
119 struct Callback : public ThreadLifecycleCallback {
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100120 void ThreadStart(Thread* self) override {
Eric Holk27dc8772021-03-12 21:23:42 +0000121 {
122 ScopedObjectAccess soa(self);
123 LOG(DEBUG) << "ThreadStart callback for thread: " << self->GetThreadName();
124 }
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000125 if (state == CallbackState::kBase) {
126 state = CallbackState::kStarted;
127 stored_self = self;
128 } else {
129 state = CallbackState::kWrongStart;
130 }
131 }
132
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100133 void ThreadDeath(Thread* self) override {
Eric Holk27dc8772021-03-12 21:23:42 +0000134 {
135 ScopedObjectAccess soa(self);
136 LOG(DEBUG) << "ThreadDeath callback for thread: " << self->GetThreadName();
137 }
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000138 if (state == CallbackState::kStarted && self == stored_self) {
139 state = CallbackState::kDied;
140 } else {
141 state = CallbackState::kWrongDeath;
142 }
143 }
144
145 Thread* stored_self;
146 CallbackState state = CallbackState::kBase;
147 };
148
149 Callback cb_;
150};
151
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000152TEST_F(ThreadLifecycleCallbackRuntimeCallbacksTest, ThreadLifecycleCallbackJava) {
153 Thread* self = Thread::Current();
154
155 self->TransitionFromSuspendedToRunnable();
156 bool started = runtime_->Start();
157 ASSERT_TRUE(started);
Mathieu Chartierada33d72018-12-17 13:17:30 -0800158 // Make sure the workers are done starting so we don't get callbacks for them.
159 runtime_->WaitForThreadPoolWorkersToStart();
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000160
Eric Holk27dc8772021-03-12 21:23:42 +0000161 // The metrics reporting thread will sometimes be slow to start. Synchronously requesting a
162 // metrics report forces us to wait until the thread has started.
163 runtime_->RequestMetricsReport(/*synchronous=*/true);
164
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000165 cb_.state = CallbackState::kBase; // Ignore main thread attach.
166
167 {
168 ScopedObjectAccess soa(self);
169 MakeExecutable(soa.Decode<mirror::Class>(WellKnownClasses::java_lang_Thread));
170 }
171
172 JNIEnv* env = self->GetJniEnv();
173
174 ScopedLocalRef<jobject> thread_name(env,
175 env->NewStringUTF("ThreadLifecycleCallback test thread"));
176 ASSERT_TRUE(thread_name.get() != nullptr);
177
178 ScopedLocalRef<jobject> thread(env, env->AllocObject(WellKnownClasses::java_lang_Thread));
179 ASSERT_TRUE(thread.get() != nullptr);
180
181 env->CallNonvirtualVoidMethod(thread.get(),
182 WellKnownClasses::java_lang_Thread,
183 WellKnownClasses::java_lang_Thread_init,
184 runtime_->GetMainThreadGroup(),
185 thread_name.get(),
186 kMinThreadPriority,
187 JNI_FALSE);
188 ASSERT_FALSE(env->ExceptionCheck());
189
190 jmethodID start_id = env->GetMethodID(WellKnownClasses::java_lang_Thread, "start", "()V");
191 ASSERT_TRUE(start_id != nullptr);
192
193 env->CallVoidMethod(thread.get(), start_id);
194 ASSERT_FALSE(env->ExceptionCheck());
195
196 jmethodID join_id = env->GetMethodID(WellKnownClasses::java_lang_Thread, "join", "()V");
197 ASSERT_TRUE(join_id != nullptr);
198
199 env->CallVoidMethod(thread.get(), join_id);
200 ASSERT_FALSE(env->ExceptionCheck());
201
Eric Holk27dc8772021-03-12 21:23:42 +0000202 EXPECT_EQ(cb_.state, CallbackState::kDied);
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000203}
204
205TEST_F(ThreadLifecycleCallbackRuntimeCallbacksTest, ThreadLifecycleCallbackAttach) {
206 std::string error_msg;
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100207 MemMap stack = MemMap::MapAnonymous("ThreadLifecycleCallback Thread",
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100208 128 * kPageSize, // Just some small stack.
209 PROT_READ | PROT_WRITE,
Vladimir Marko11306592018-10-26 14:22:59 +0100210 /*low_4gb=*/ false,
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100211 &error_msg);
212 ASSERT_TRUE(stack.IsValid()) << error_msg;
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000213
214 const char* reason = "ThreadLifecycleCallback test thread";
215 pthread_attr_t attr;
216 CHECK_PTHREAD_CALL(pthread_attr_init, (&attr), reason);
Vladimir Markoc34bebf2018-08-16 16:12:49 +0100217 CHECK_PTHREAD_CALL(pthread_attr_setstack, (&attr, stack.Begin(), stack.Size()), reason);
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000218 pthread_t pthread;
219 CHECK_PTHREAD_CALL(pthread_create,
220 (&pthread,
221 &attr,
222 &ThreadLifecycleCallbackRuntimeCallbacksTest::PthreadsCallback,
223 this),
224 reason);
225 CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), reason);
226
227 CHECK_PTHREAD_CALL(pthread_join, (pthread, nullptr), "ThreadLifecycleCallback test shutdown");
228
229 // Detach is not a ThreadDeath event, so we expect to be in state Started.
230 EXPECT_TRUE(cb_.state == CallbackState::kStarted) << static_cast<int>(cb_.state);
231}
232
Andreas Gampe0f01b582017-01-18 15:22:37 -0800233class ClassLoadCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
234 protected:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100235 void AddListener() override REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800236 Runtime::Current()->GetRuntimeCallbacks()->AddClassLoadCallback(&cb_);
Andreas Gampe0f01b582017-01-18 15:22:37 -0800237 }
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100238 void RemoveListener() override REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800239 Runtime::Current()->GetRuntimeCallbacks()->RemoveClassLoadCallback(&cb_);
Andreas Gampe0f01b582017-01-18 15:22:37 -0800240 }
241
242 bool Expect(std::initializer_list<const char*> list) {
243 if (cb_.data.size() != list.size()) {
244 PrintError(list);
245 return false;
246 }
247
248 if (!std::equal(cb_.data.begin(), cb_.data.end(), list.begin())) {
249 PrintError(list);
250 return false;
251 }
252
253 return true;
254 }
255
256 void PrintError(std::initializer_list<const char*> list) {
257 LOG(ERROR) << "Expected:";
258 for (const char* expected : list) {
259 LOG(ERROR) << " " << expected;
260 }
261 LOG(ERROR) << "Found:";
262 for (const auto& s : cb_.data) {
263 LOG(ERROR) << " " << s;
264 }
265 }
266
267 struct Callback : public ClassLoadCallback {
Roland Levillainf73caca2018-08-24 17:19:07 +0100268 void ClassPreDefine(const char* descriptor,
269 Handle<mirror::Class> klass ATTRIBUTE_UNUSED,
270 Handle<mirror::ClassLoader> class_loader ATTRIBUTE_UNUSED,
271 const DexFile& initial_dex_file,
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800272 const dex::ClassDef& initial_class_def ATTRIBUTE_UNUSED,
Roland Levillainf73caca2018-08-24 17:19:07 +0100273 /*out*/DexFile const** final_dex_file ATTRIBUTE_UNUSED,
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800274 /*out*/dex::ClassDef const** final_class_def ATTRIBUTE_UNUSED) override
Roland Levillainf73caca2018-08-24 17:19:07 +0100275 REQUIRES_SHARED(Locks::mutator_lock_) {
Andreas Gampe641a4732017-08-24 13:21:35 -0700276 const std::string& location = initial_dex_file.GetLocation();
Alex Lightb0f11922017-01-23 14:25:17 -0800277 std::string event =
278 std::string("PreDefine:") + descriptor + " <" +
Andreas Gampe5555dd12017-08-24 13:50:21 -0700279 location.substr(location.rfind('/') + 1, location.size()) + ">";
Alex Lightb0f11922017-01-23 14:25:17 -0800280 data.push_back(event);
281 }
282
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100283 void ClassLoad(Handle<mirror::Class> klass) override REQUIRES_SHARED(Locks::mutator_lock_) {
Andreas Gampe0f01b582017-01-18 15:22:37 -0800284 std::string tmp;
285 std::string event = std::string("Load:") + klass->GetDescriptor(&tmp);
286 data.push_back(event);
287 }
288
289 void ClassPrepare(Handle<mirror::Class> temp_klass,
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100290 Handle<mirror::Class> klass) override REQUIRES_SHARED(Locks::mutator_lock_) {
Andreas Gampe0f01b582017-01-18 15:22:37 -0800291 std::string tmp, tmp2;
292 std::string event = std::string("Prepare:") + klass->GetDescriptor(&tmp)
293 + "[" + temp_klass->GetDescriptor(&tmp2) + "]";
294 data.push_back(event);
295 }
296
297 std::vector<std::string> data;
298 };
299
300 Callback cb_;
301};
302
303TEST_F(ClassLoadCallbackRuntimeCallbacksTest, ClassLoadCallback) {
304 ScopedObjectAccess soa(Thread::Current());
305 jobject jclass_loader = LoadDex("XandY");
306 VariableSizedHandleScope hs(soa.Self());
307 Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
308 soa.Decode<mirror::ClassLoader>(jclass_loader)));
309
310 const char* descriptor_y = "LY;";
311 Handle<mirror::Class> h_Y(
312 hs.NewHandle(class_linker_->FindClass(soa.Self(), descriptor_y, class_loader)));
Andreas Gampefa4333d2017-02-14 11:10:34 -0800313 ASSERT_TRUE(h_Y != nullptr);
Andreas Gampe0f01b582017-01-18 15:22:37 -0800314
David Srbecky4a88a5a2020-05-05 16:21:57 +0100315 bool expect1 = Expect({ "PreDefine:LY; <art-gtest-jars-XandY.jar>",
316 "PreDefine:LX; <art-gtest-jars-XandY.jar>",
Alex Lightb0f11922017-01-23 14:25:17 -0800317 "Load:LX;",
318 "Prepare:LX;[LX;]",
319 "Load:LY;",
320 "Prepare:LY;[LY;]" });
Andreas Gampe0f01b582017-01-18 15:22:37 -0800321 EXPECT_TRUE(expect1);
322
323 cb_.data.clear();
324
325 ASSERT_TRUE(class_linker_->EnsureInitialized(Thread::Current(), h_Y, true, true));
326
David Srbecky4a88a5a2020-05-05 16:21:57 +0100327 bool expect2 = Expect({ "PreDefine:LY$Z; <art-gtest-jars-XandY.jar>",
Alex Lightb0f11922017-01-23 14:25:17 -0800328 "Load:LY$Z;",
329 "Prepare:LY$Z;[LY$Z;]" });
Andreas Gampe0f01b582017-01-18 15:22:37 -0800330 EXPECT_TRUE(expect2);
331}
332
Andreas Gampea5814f92017-01-18 21:43:16 -0800333class RuntimeSigQuitCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
334 protected:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100335 void AddListener() override REQUIRES(Locks::mutator_lock_) {
Andreas Gampea5814f92017-01-18 21:43:16 -0800336 Runtime::Current()->GetRuntimeCallbacks()->AddRuntimeSigQuitCallback(&cb_);
337 }
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100338 void RemoveListener() override REQUIRES(Locks::mutator_lock_) {
Andreas Gampea5814f92017-01-18 21:43:16 -0800339 Runtime::Current()->GetRuntimeCallbacks()->RemoveRuntimeSigQuitCallback(&cb_);
340 }
341
342 struct Callback : public RuntimeSigQuitCallback {
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100343 void SigQuit() override {
Andreas Gampea5814f92017-01-18 21:43:16 -0800344 ++sigquit_count;
345 }
346
347 size_t sigquit_count = 0;
348 };
349
350 Callback cb_;
351};
352
353TEST_F(RuntimeSigQuitCallbackRuntimeCallbacksTest, SigQuit) {
354 // The runtime needs to be started for the signal handler.
355 Thread* self = Thread::Current();
356
357 self->TransitionFromSuspendedToRunnable();
358 bool started = runtime_->Start();
359 ASSERT_TRUE(started);
360
361 EXPECT_EQ(0u, cb_.sigquit_count);
362
363 kill(getpid(), SIGQUIT);
364
365 // Try a few times.
366 for (size_t i = 0; i != 30; ++i) {
367 if (cb_.sigquit_count == 0) {
368 sleep(1);
369 } else {
370 break;
371 }
372 }
373 EXPECT_EQ(1u, cb_.sigquit_count);
374}
375
Andreas Gampe48864112017-01-19 17:23:17 -0800376class RuntimePhaseCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
377 protected:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100378 void AddListener() override REQUIRES(Locks::mutator_lock_) {
Andreas Gampe48864112017-01-19 17:23:17 -0800379 Runtime::Current()->GetRuntimeCallbacks()->AddRuntimePhaseCallback(&cb_);
380 }
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100381 void RemoveListener() override REQUIRES(Locks::mutator_lock_) {
Andreas Gampe48864112017-01-19 17:23:17 -0800382 Runtime::Current()->GetRuntimeCallbacks()->RemoveRuntimePhaseCallback(&cb_);
383 }
384
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100385 void TearDown() override {
Andreas Gampe48864112017-01-19 17:23:17 -0800386 // Bypass RuntimeCallbacksTest::TearDown, as the runtime is already gone.
387 CommonRuntimeTest::TearDown();
388 }
389
390 struct Callback : public RuntimePhaseCallback {
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100391 void NextRuntimePhase(RuntimePhaseCallback::RuntimePhase p) override {
Andreas Gampe96eca782017-01-19 19:45:30 -0800392 if (p == RuntimePhaseCallback::RuntimePhase::kInitialAgents) {
393 if (start_seen > 0 || init_seen > 0 || death_seen > 0) {
394 LOG(FATAL) << "Unexpected order";
395 }
396 ++initial_agents_seen;
397 } else if (p == RuntimePhaseCallback::RuntimePhase::kStart) {
398 if (init_seen > 0 || death_seen > 0) {
Andreas Gampe48864112017-01-19 17:23:17 -0800399 LOG(FATAL) << "Init seen before start.";
400 }
401 ++start_seen;
402 } else if (p == RuntimePhaseCallback::RuntimePhase::kInit) {
403 ++init_seen;
404 } else if (p == RuntimePhaseCallback::RuntimePhase::kDeath) {
405 ++death_seen;
406 } else {
407 LOG(FATAL) << "Unknown phase " << static_cast<uint32_t>(p);
408 }
409 }
410
Andreas Gampe96eca782017-01-19 19:45:30 -0800411 size_t initial_agents_seen = 0;
Andreas Gampe48864112017-01-19 17:23:17 -0800412 size_t start_seen = 0;
413 size_t init_seen = 0;
414 size_t death_seen = 0;
415 };
416
417 Callback cb_;
418};
419
420TEST_F(RuntimePhaseCallbackRuntimeCallbacksTest, Phases) {
Andreas Gampe96eca782017-01-19 19:45:30 -0800421 ASSERT_EQ(0u, cb_.initial_agents_seen);
Andreas Gampe48864112017-01-19 17:23:17 -0800422 ASSERT_EQ(0u, cb_.start_seen);
423 ASSERT_EQ(0u, cb_.init_seen);
424 ASSERT_EQ(0u, cb_.death_seen);
425
426 // Start the runtime.
427 {
428 Thread* self = Thread::Current();
429 self->TransitionFromSuspendedToRunnable();
430 bool started = runtime_->Start();
431 ASSERT_TRUE(started);
432 }
433
Andreas Gampe96eca782017-01-19 19:45:30 -0800434 ASSERT_EQ(0u, cb_.initial_agents_seen);
Andreas Gampe48864112017-01-19 17:23:17 -0800435 ASSERT_EQ(1u, cb_.start_seen);
436 ASSERT_EQ(1u, cb_.init_seen);
437 ASSERT_EQ(0u, cb_.death_seen);
438
439 // Delete the runtime.
440 runtime_.reset();
441
Andreas Gampe96eca782017-01-19 19:45:30 -0800442 ASSERT_EQ(0u, cb_.initial_agents_seen);
Andreas Gampe48864112017-01-19 17:23:17 -0800443 ASSERT_EQ(1u, cb_.start_seen);
444 ASSERT_EQ(1u, cb_.init_seen);
445 ASSERT_EQ(1u, cb_.death_seen);
446}
447
Alex Light77fee872017-09-05 14:51:49 -0700448class MonitorWaitCallbacksTest : public RuntimeCallbacksTest {
449 protected:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100450 void AddListener() override REQUIRES(Locks::mutator_lock_) {
Alex Light77fee872017-09-05 14:51:49 -0700451 Runtime::Current()->GetRuntimeCallbacks()->AddMonitorCallback(&cb_);
452 }
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100453 void RemoveListener() override REQUIRES(Locks::mutator_lock_) {
Alex Light77fee872017-09-05 14:51:49 -0700454 Runtime::Current()->GetRuntimeCallbacks()->RemoveMonitorCallback(&cb_);
455 }
456
457 struct Callback : public MonitorCallback {
Vladimir Markof52d92f2019-03-29 12:33:02 +0000458 bool IsInterestingObject(ObjPtr<mirror::Object> obj)
459 REQUIRES_SHARED(art::Locks::mutator_lock_) {
Alex Light77fee872017-09-05 14:51:49 -0700460 if (!obj->IsClass()) {
461 return false;
462 }
463 std::lock_guard<std::mutex> lock(ref_guard_);
Vladimir Marko4617d582019-03-28 13:48:31 +0000464 ObjPtr<mirror::Class> k = obj->AsClass();
Alex Light77fee872017-09-05 14:51:49 -0700465 ClassReference test = { &k->GetDexFile(), k->GetDexClassDefIndex() };
466 return ref_ == test;
467 }
468
Vladimir Markof52d92f2019-03-29 12:33:02 +0000469 void SetInterestingObject(ObjPtr<mirror::Object> obj)
470 REQUIRES_SHARED(art::Locks::mutator_lock_) {
Alex Light77fee872017-09-05 14:51:49 -0700471 std::lock_guard<std::mutex> lock(ref_guard_);
Vladimir Marko4617d582019-03-28 13:48:31 +0000472 ObjPtr<mirror::Class> k = obj->AsClass();
Alex Light77fee872017-09-05 14:51:49 -0700473 ref_ = { &k->GetDexFile(), k->GetDexClassDefIndex() };
474 }
475
Andreas Gampefa6a1b02018-09-07 08:11:55 -0700476 void MonitorContendedLocking(Monitor* mon ATTRIBUTE_UNUSED) override
Alex Light77fee872017-09-05 14:51:49 -0700477 REQUIRES_SHARED(Locks::mutator_lock_) { }
478
Andreas Gampefa6a1b02018-09-07 08:11:55 -0700479 void MonitorContendedLocked(Monitor* mon ATTRIBUTE_UNUSED) override
Alex Light77fee872017-09-05 14:51:49 -0700480 REQUIRES_SHARED(Locks::mutator_lock_) { }
481
Andreas Gampefa6a1b02018-09-07 08:11:55 -0700482 void ObjectWaitStart(Handle<mirror::Object> obj, int64_t millis ATTRIBUTE_UNUSED) override
Alex Light77fee872017-09-05 14:51:49 -0700483 REQUIRES_SHARED(Locks::mutator_lock_) {
484 if (IsInterestingObject(obj.Get())) {
485 saw_wait_start_ = true;
486 }
487 }
488
Andreas Gampefa6a1b02018-09-07 08:11:55 -0700489 void MonitorWaitFinished(Monitor* m, bool timed_out ATTRIBUTE_UNUSED) override
Alex Light77fee872017-09-05 14:51:49 -0700490 REQUIRES_SHARED(Locks::mutator_lock_) {
491 if (IsInterestingObject(m->GetObject())) {
492 saw_wait_finished_ = true;
493 }
494 }
495
496 std::mutex ref_guard_;
497 ClassReference ref_ = {nullptr, 0};
498 bool saw_wait_start_ = false;
499 bool saw_wait_finished_ = false;
500 };
501
502 Callback cb_;
503};
504
505// TODO It would be good to have more tests for this but due to the multi-threaded nature of the
506// callbacks this is difficult. For now the run-tests 1931 & 1932 should be sufficient.
507TEST_F(MonitorWaitCallbacksTest, WaitUnlocked) {
508 ASSERT_FALSE(cb_.saw_wait_finished_);
509 ASSERT_FALSE(cb_.saw_wait_start_);
510 {
511 Thread* self = Thread::Current();
512 self->TransitionFromSuspendedToRunnable();
513 bool started = runtime_->Start();
514 ASSERT_TRUE(started);
515 {
516 ScopedObjectAccess soa(self);
517 cb_.SetInterestingObject(
Vladimir Markof52d92f2019-03-29 12:33:02 +0000518 soa.Decode<mirror::Class>(WellKnownClasses::java_util_Collections));
Alex Light77fee872017-09-05 14:51:49 -0700519 Monitor::Wait(
520 self,
521 // Just a random class
Vladimir Markof52d92f2019-03-29 12:33:02 +0000522 soa.Decode<mirror::Class>(WellKnownClasses::java_util_Collections),
Andreas Gampe98ea9d92018-10-19 14:06:15 -0700523 /*ms=*/0,
524 /*ns=*/0,
525 /*interruptShouldThrow=*/false,
526 /*why=*/kWaiting);
Alex Light77fee872017-09-05 14:51:49 -0700527 }
528 }
529 ASSERT_TRUE(cb_.saw_wait_start_);
530 ASSERT_FALSE(cb_.saw_wait_finished_);
531}
532
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000533} // namespace art