blob: f05794dba6fbdbebf32ac259cf7573f5fc2f3440 [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 Gampe0f01b582017-01-18 15:22:37 -080020
21#include <initializer_list>
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000022#include <memory>
23#include <string>
24
25#include "art_method-inl.h"
26#include "base/mutex.h"
Andreas Gampe0f01b582017-01-18 15:22:37 -080027#include "class_linker.h"
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000028#include "common_runtime_test.h"
Andreas Gampe0f01b582017-01-18 15:22:37 -080029#include "handle.h"
30#include "handle_scope-inl.h"
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000031#include "mem_map.h"
Andreas Gampe0f01b582017-01-18 15:22:37 -080032#include "mirror/class-inl.h"
33#include "mirror/class_loader.h"
Andreas Gampe04bbb5b2017-01-19 17:49:03 +000034#include "obj_ptr.h"
35#include "runtime.h"
36#include "scoped_thread_state_change-inl.h"
37#include "ScopedLocalRef.h"
38#include "thread-inl.h"
39#include "thread_list.h"
40#include "well_known_classes.h"
41
42namespace art {
43
44class RuntimeCallbacksTest : public CommonRuntimeTest {
45 protected:
46 void SetUp() OVERRIDE {
47 CommonRuntimeTest::SetUp();
48
49 Thread* self = Thread::Current();
50 ScopedObjectAccess soa(self);
51 ScopedThreadSuspension sts(self, kWaitingForDebuggerToAttach);
52 ScopedSuspendAll ssa("RuntimeCallbacksTest SetUp");
53 AddListener();
54 }
55
56 void TearDown() OVERRIDE {
57 {
58 Thread* self = Thread::Current();
59 ScopedObjectAccess soa(self);
60 ScopedThreadSuspension sts(self, kWaitingForDebuggerToAttach);
61 ScopedSuspendAll ssa("RuntimeCallbacksTest TearDown");
62 AddListener();
63 RemoveListener();
64 }
65
66 CommonRuntimeTest::TearDown();
67 }
68
69 virtual void AddListener() REQUIRES(Locks::mutator_lock_) = 0;
70 virtual void RemoveListener() REQUIRES(Locks::mutator_lock_) = 0;
71
72 void MakeExecutable(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
73 CHECK(klass != nullptr);
74 PointerSize pointer_size = class_linker_->GetImagePointerSize();
75 for (auto& m : klass->GetMethods(pointer_size)) {
76 if (!m.IsAbstract()) {
77 class_linker_->SetEntryPointsToInterpreter(&m);
78 }
79 }
80 }
81};
82
83class ThreadLifecycleCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
84 public:
85 static void* PthreadsCallback(void* arg ATTRIBUTE_UNUSED) {
86 // Attach.
87 Runtime* runtime = Runtime::Current();
88 CHECK(runtime->AttachCurrentThread("ThreadLifecycle test thread", true, nullptr, false));
89
90 // Detach.
91 runtime->DetachCurrentThread();
92
93 // Die...
94 return nullptr;
95 }
96
97 protected:
98 void AddListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -080099 Runtime::Current()->GetRuntimeCallbacks()->AddThreadLifecycleCallback(&cb_);
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000100 }
101 void RemoveListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800102 Runtime::Current()->GetRuntimeCallbacks()->RemoveThreadLifecycleCallback(&cb_);
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000103 }
104
105 enum CallbackState {
106 kBase,
107 kStarted,
108 kDied,
109 kWrongStart,
110 kWrongDeath,
111 };
112
113 struct Callback : public ThreadLifecycleCallback {
114 void ThreadStart(Thread* self) OVERRIDE {
115 if (state == CallbackState::kBase) {
116 state = CallbackState::kStarted;
117 stored_self = self;
118 } else {
119 state = CallbackState::kWrongStart;
120 }
121 }
122
123 void ThreadDeath(Thread* self) OVERRIDE {
124 if (state == CallbackState::kStarted && self == stored_self) {
125 state = CallbackState::kDied;
126 } else {
127 state = CallbackState::kWrongDeath;
128 }
129 }
130
131 Thread* stored_self;
132 CallbackState state = CallbackState::kBase;
133 };
134
135 Callback cb_;
136};
137
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000138TEST_F(ThreadLifecycleCallbackRuntimeCallbacksTest, ThreadLifecycleCallbackJava) {
139 Thread* self = Thread::Current();
140
141 self->TransitionFromSuspendedToRunnable();
142 bool started = runtime_->Start();
143 ASSERT_TRUE(started);
144
145 cb_.state = CallbackState::kBase; // Ignore main thread attach.
146
147 {
148 ScopedObjectAccess soa(self);
149 MakeExecutable(soa.Decode<mirror::Class>(WellKnownClasses::java_lang_Thread));
150 }
151
152 JNIEnv* env = self->GetJniEnv();
153
154 ScopedLocalRef<jobject> thread_name(env,
155 env->NewStringUTF("ThreadLifecycleCallback test thread"));
156 ASSERT_TRUE(thread_name.get() != nullptr);
157
158 ScopedLocalRef<jobject> thread(env, env->AllocObject(WellKnownClasses::java_lang_Thread));
159 ASSERT_TRUE(thread.get() != nullptr);
160
161 env->CallNonvirtualVoidMethod(thread.get(),
162 WellKnownClasses::java_lang_Thread,
163 WellKnownClasses::java_lang_Thread_init,
164 runtime_->GetMainThreadGroup(),
165 thread_name.get(),
166 kMinThreadPriority,
167 JNI_FALSE);
168 ASSERT_FALSE(env->ExceptionCheck());
169
170 jmethodID start_id = env->GetMethodID(WellKnownClasses::java_lang_Thread, "start", "()V");
171 ASSERT_TRUE(start_id != nullptr);
172
173 env->CallVoidMethod(thread.get(), start_id);
174 ASSERT_FALSE(env->ExceptionCheck());
175
176 jmethodID join_id = env->GetMethodID(WellKnownClasses::java_lang_Thread, "join", "()V");
177 ASSERT_TRUE(join_id != nullptr);
178
179 env->CallVoidMethod(thread.get(), join_id);
180 ASSERT_FALSE(env->ExceptionCheck());
181
182 EXPECT_TRUE(cb_.state == CallbackState::kDied) << static_cast<int>(cb_.state);
183}
184
185TEST_F(ThreadLifecycleCallbackRuntimeCallbacksTest, ThreadLifecycleCallbackAttach) {
186 std::string error_msg;
187 std::unique_ptr<MemMap> stack(MemMap::MapAnonymous("ThreadLifecycleCallback Thread",
188 nullptr,
189 128 * kPageSize, // Just some small stack.
190 PROT_READ | PROT_WRITE,
191 false,
192 false,
193 &error_msg));
194 ASSERT_FALSE(stack == nullptr) << error_msg;
195
196 const char* reason = "ThreadLifecycleCallback test thread";
197 pthread_attr_t attr;
198 CHECK_PTHREAD_CALL(pthread_attr_init, (&attr), reason);
199 CHECK_PTHREAD_CALL(pthread_attr_setstack, (&attr, stack->Begin(), stack->Size()), reason);
200 pthread_t pthread;
201 CHECK_PTHREAD_CALL(pthread_create,
202 (&pthread,
203 &attr,
204 &ThreadLifecycleCallbackRuntimeCallbacksTest::PthreadsCallback,
205 this),
206 reason);
207 CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), reason);
208
209 CHECK_PTHREAD_CALL(pthread_join, (pthread, nullptr), "ThreadLifecycleCallback test shutdown");
210
211 // Detach is not a ThreadDeath event, so we expect to be in state Started.
212 EXPECT_TRUE(cb_.state == CallbackState::kStarted) << static_cast<int>(cb_.state);
213}
214
Andreas Gampe0f01b582017-01-18 15:22:37 -0800215class ClassLoadCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
216 protected:
217 void AddListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800218 Runtime::Current()->GetRuntimeCallbacks()->AddClassLoadCallback(&cb_);
Andreas Gampe0f01b582017-01-18 15:22:37 -0800219 }
220 void RemoveListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
Andreas Gampeac30fa22017-01-18 21:02:36 -0800221 Runtime::Current()->GetRuntimeCallbacks()->RemoveClassLoadCallback(&cb_);
Andreas Gampe0f01b582017-01-18 15:22:37 -0800222 }
223
224 bool Expect(std::initializer_list<const char*> list) {
225 if (cb_.data.size() != list.size()) {
226 PrintError(list);
227 return false;
228 }
229
230 if (!std::equal(cb_.data.begin(), cb_.data.end(), list.begin())) {
231 PrintError(list);
232 return false;
233 }
234
235 return true;
236 }
237
238 void PrintError(std::initializer_list<const char*> list) {
239 LOG(ERROR) << "Expected:";
240 for (const char* expected : list) {
241 LOG(ERROR) << " " << expected;
242 }
243 LOG(ERROR) << "Found:";
244 for (const auto& s : cb_.data) {
245 LOG(ERROR) << " " << s;
246 }
247 }
248
249 struct Callback : public ClassLoadCallback {
250 void ClassLoad(Handle<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
251 std::string tmp;
252 std::string event = std::string("Load:") + klass->GetDescriptor(&tmp);
253 data.push_back(event);
254 }
255
256 void ClassPrepare(Handle<mirror::Class> temp_klass,
257 Handle<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
258 std::string tmp, tmp2;
259 std::string event = std::string("Prepare:") + klass->GetDescriptor(&tmp)
260 + "[" + temp_klass->GetDescriptor(&tmp2) + "]";
261 data.push_back(event);
262 }
263
264 std::vector<std::string> data;
265 };
266
267 Callback cb_;
268};
269
270TEST_F(ClassLoadCallbackRuntimeCallbacksTest, ClassLoadCallback) {
271 ScopedObjectAccess soa(Thread::Current());
272 jobject jclass_loader = LoadDex("XandY");
273 VariableSizedHandleScope hs(soa.Self());
274 Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
275 soa.Decode<mirror::ClassLoader>(jclass_loader)));
276
277 const char* descriptor_y = "LY;";
278 Handle<mirror::Class> h_Y(
279 hs.NewHandle(class_linker_->FindClass(soa.Self(), descriptor_y, class_loader)));
280 ASSERT_TRUE(h_Y.Get() != nullptr);
281
282 bool expect1 = Expect({ "Load:LX;", "Prepare:LX;[LX;]", "Load:LY;", "Prepare:LY;[LY;]" });
283 EXPECT_TRUE(expect1);
284
285 cb_.data.clear();
286
287 ASSERT_TRUE(class_linker_->EnsureInitialized(Thread::Current(), h_Y, true, true));
288
289 bool expect2 = Expect({ "Load:LY$Z;", "Prepare:LY$Z;[LY$Z;]" });
290 EXPECT_TRUE(expect2);
291}
292
Andreas Gampe04bbb5b2017-01-19 17:49:03 +0000293} // namespace art