1 /*
2 * Copyright 2018 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 #include "message_loop_thread.h"
17
18 #include <base/functional/bind.h>
19 #include <base/threading/platform_thread.h>
20 #include <bluetooth/log.h>
21 #include <gtest/gtest.h>
22 #include <sys/capability.h>
23 #include <syscall.h>
24
25 #include <condition_variable>
26 #include <memory>
27 #include <mutex>
28
29 using bluetooth::common::MessageLoopThread;
30 using namespace bluetooth;
31
32 /**
33 * Unit tests to verify MessageLoopThread. Must have CAP_SYS_NICE capability.
34 */
35 class MessageLoopThreadTest : public ::testing::Test {
36 public:
ShouldNotHappen()37 void ShouldNotHappen() { FAIL() << "Should not happen"; }
38
GetThreadId(std::promise<base::PlatformThreadId> thread_id_promise)39 void GetThreadId(std::promise<base::PlatformThreadId> thread_id_promise) {
40 thread_id_promise.set_value(base::PlatformThread::CurrentId());
41 }
42
GetLinuxTid(std::promise<pid_t> tid_promise)43 void GetLinuxTid(std::promise<pid_t> tid_promise) {
44 tid_promise.set_value(static_cast<pid_t>(syscall(SYS_gettid)));
45 }
46
GetName(std::promise<std::string> name_promise)47 void GetName(std::promise<std::string> name_promise) {
48 char my_name[256];
49 pthread_getname_np(pthread_self(), my_name, sizeof(my_name));
50 name_promise.set_value(my_name);
51 }
52
GetSchedulingPolicyAndPriority(int * scheduling_policy,int * schedule_priority,std::promise<void> execution_promise)53 void GetSchedulingPolicyAndPriority(int* scheduling_policy,
54 int* schedule_priority,
55 std::promise<void> execution_promise) {
56 *scheduling_policy = sched_getscheduler(0);
57 struct sched_param param = {};
58 ASSERT_EQ(sched_getparam(0, ¶m), 0);
59 *schedule_priority = param.sched_priority;
60 execution_promise.set_value();
61 }
62
SleepAndGetName(std::promise<std::string> name_promise,int sleep_ms)63 void SleepAndGetName(std::promise<std::string> name_promise, int sleep_ms) {
64 std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms));
65 GetName(std::move(name_promise));
66 }
67
68 protected:
CanSetCurrentThreadPriority()69 static bool CanSetCurrentThreadPriority() {
70 struct __user_cap_header_struct linux_user_header = {
71 .version = _LINUX_CAPABILITY_VERSION_3};
72 struct __user_cap_data_struct linux_user_data[2] = {};
73 if (capget(&linux_user_header, linux_user_data) != 0) {
74 log::error("Failed to get capability for current thread, error: {}",
75 strerror(errno));
76 // Log record in XML
77 RecordProperty("MessageLoopThreadTestCannotGetCapabilityReason",
78 strerror(errno));
79 return false;
80 }
81 return ((linux_user_data[0].permitted >> CAP_SYS_NICE) & 0x1) != 0;
82 }
83 };
84
TEST_F(MessageLoopThreadTest,get_weak_ptr)85 TEST_F(MessageLoopThreadTest, get_weak_ptr) {
86 base::WeakPtr<MessageLoopThread> message_loop_thread_ptr;
87 {
88 MessageLoopThread message_loop_thread("test_thread");
89 message_loop_thread_ptr = message_loop_thread.GetWeakPtr();
90 ASSERT_NE(message_loop_thread_ptr, nullptr);
91 }
92 ASSERT_EQ(message_loop_thread_ptr, nullptr);
93 }
94
TEST_F(MessageLoopThreadTest,test_running_thread)95 TEST_F(MessageLoopThreadTest, test_running_thread) {
96 MessageLoopThread message_loop_thread("test_thread");
97 message_loop_thread.StartUp();
98 ASSERT_GE(message_loop_thread.GetThreadId(), 0);
99 ASSERT_TRUE(message_loop_thread.IsRunning());
100 message_loop_thread.ShutDown();
101 ASSERT_LT(message_loop_thread.GetThreadId(), 0);
102 ASSERT_FALSE(message_loop_thread.IsRunning());
103 }
104
TEST_F(MessageLoopThreadTest,test_not_self)105 TEST_F(MessageLoopThreadTest, test_not_self) {
106 MessageLoopThread message_loop_thread("test_thread");
107 message_loop_thread.StartUp();
108 ASSERT_GE(message_loop_thread.GetThreadId(), 0);
109 ASSERT_NE(message_loop_thread.GetThreadId(),
110 base::PlatformThread::CurrentId());
111 }
112
TEST_F(MessageLoopThreadTest,test_shutdown_without_start)113 TEST_F(MessageLoopThreadTest, test_shutdown_without_start) {
114 MessageLoopThread message_loop_thread("test_thread");
115 message_loop_thread.ShutDown();
116 ASSERT_LT(message_loop_thread.GetThreadId(), 0);
117 }
118
TEST_F(MessageLoopThreadTest,test_do_in_thread_before_start)119 TEST_F(MessageLoopThreadTest, test_do_in_thread_before_start) {
120 std::string name = "test_thread";
121 MessageLoopThread message_loop_thread(name);
122 ASSERT_FALSE(message_loop_thread.DoInThread(
123 FROM_HERE, base::BindOnce(&MessageLoopThreadTest::ShouldNotHappen,
124 base::Unretained(this))));
125 }
126
TEST_F(MessageLoopThreadTest,test_do_in_thread_after_shutdown)127 TEST_F(MessageLoopThreadTest, test_do_in_thread_after_shutdown) {
128 std::string name = "test_thread";
129 MessageLoopThread message_loop_thread(name);
130 message_loop_thread.StartUp();
131 message_loop_thread.ShutDown();
132 ASSERT_FALSE(message_loop_thread.DoInThread(
133 FROM_HERE, base::BindOnce(&MessageLoopThreadTest::ShouldNotHappen,
134 base::Unretained(this))));
135 }
136
TEST_F(MessageLoopThreadTest,test_name)137 TEST_F(MessageLoopThreadTest, test_name) {
138 std::string name = "test_thread";
139 MessageLoopThread message_loop_thread(name);
140 message_loop_thread.StartUp();
141 ASSERT_GE(message_loop_thread.GetThreadId(), 0);
142 std::promise<std::string> name_promise;
143 std::future<std::string> name_future = name_promise.get_future();
144 message_loop_thread.DoInThread(
145 FROM_HERE,
146 base::BindOnce(&MessageLoopThreadTest::GetName, base::Unretained(this),
147 std::move(name_promise)));
148 std::string my_name = name_future.get();
149 ASSERT_EQ(name, my_name);
150 ASSERT_EQ(name, message_loop_thread.GetName());
151 }
152
TEST_F(MessageLoopThreadTest,test_thread_id)153 TEST_F(MessageLoopThreadTest, test_thread_id) {
154 std::string name = "test_thread";
155 MessageLoopThread message_loop_thread(name);
156 message_loop_thread.StartUp();
157 base::PlatformThreadId thread_id = message_loop_thread.GetThreadId();
158 ASSERT_GE(thread_id, 0);
159 std::promise<base::PlatformThreadId> thread_id_promise;
160 std::future<base::PlatformThreadId> thread_id_future =
161 thread_id_promise.get_future();
162 message_loop_thread.DoInThread(
163 FROM_HERE,
164 base::BindOnce(&MessageLoopThreadTest::GetThreadId,
165 base::Unretained(this), std::move(thread_id_promise)));
166 base::PlatformThreadId my_thread_id = thread_id_future.get();
167 ASSERT_EQ(thread_id, my_thread_id);
168 }
169
TEST_F(MessageLoopThreadTest,test_set_realtime_priority_fail_before_start)170 TEST_F(MessageLoopThreadTest, test_set_realtime_priority_fail_before_start) {
171 std::string name = "test_thread";
172 MessageLoopThread message_loop_thread(name);
173 ASSERT_FALSE(message_loop_thread.EnableRealTimeScheduling());
174 }
175
TEST_F(MessageLoopThreadTest,test_set_realtime_priority_success)176 TEST_F(MessageLoopThreadTest, test_set_realtime_priority_success) {
177 std::string name = "test_thread";
178 MessageLoopThread message_loop_thread(name);
179 message_loop_thread.StartUp();
180 bool ret = message_loop_thread.EnableRealTimeScheduling();
181 if (!ret) {
182 if (CanSetCurrentThreadPriority()) {
183 FAIL() << "Cannot set real time priority even though we have permission";
184 } else {
185 log::warn(
186 "Allowing EnableRealTimeScheduling to fail because we don't have "
187 "CAP_SYS_NICE capability");
188 // Log record in XML
189 RecordProperty("MessageLoopThreadTestConditionalSuccess",
190 "Mark test as success even though EnableRealTimeScheduling"
191 " failed because we don't have CAP_SYS_NICE capability");
192 // Quit early since further verification is no longer needed
193 return;
194 }
195 }
196 std::promise<void> execution_promise;
197 std::future<void> execution_future = execution_promise.get_future();
198 int scheduling_policy = -1;
199 int scheduling_priority = -1;
200 message_loop_thread.DoInThread(
201 FROM_HERE,
202 base::BindOnce(&MessageLoopThreadTest::GetSchedulingPolicyAndPriority,
203 base::Unretained(this), &scheduling_policy,
204 &scheduling_priority, std::move(execution_promise)));
205 execution_future.wait();
206 ASSERT_EQ(scheduling_policy, SCHED_FIFO);
207 // Internal implementation verified here
208 ASSERT_EQ(scheduling_priority, 1);
209 std::promise<pid_t> tid_promise;
210 std::future<pid_t> tid_future = tid_promise.get_future();
211 message_loop_thread.DoInThread(
212 FROM_HERE,
213 base::BindOnce(&MessageLoopThreadTest::GetLinuxTid,
214 base::Unretained(this), std::move(tid_promise)));
215 pid_t linux_tid = tid_future.get();
216 ASSERT_GT(linux_tid, 0);
217 ASSERT_EQ(sched_getscheduler(linux_tid), SCHED_FIFO);
218 struct sched_param param = {};
219 ASSERT_EQ(sched_getparam(linux_tid, ¶m), 0);
220 // Internal implementation verified here
221 ASSERT_EQ(param.sched_priority, 1);
222 }
223
TEST_F(MessageLoopThreadTest,test_message_loop_null_before_start)224 TEST_F(MessageLoopThreadTest, test_message_loop_null_before_start) {
225 std::string name = "test_thread";
226 MessageLoopThread message_loop_thread(name);
227 ASSERT_EQ(message_loop_thread.message_loop(), nullptr);
228 }
229
TEST_F(MessageLoopThreadTest,test_message_loop_not_null_start)230 TEST_F(MessageLoopThreadTest, test_message_loop_not_null_start) {
231 std::string name = "test_thread";
232 MessageLoopThread message_loop_thread(name);
233 message_loop_thread.StartUp();
234 ASSERT_NE(message_loop_thread.message_loop(), nullptr);
235 }
236
TEST_F(MessageLoopThreadTest,test_message_loop_null_after_stop)237 TEST_F(MessageLoopThreadTest, test_message_loop_null_after_stop) {
238 std::string name = "test_thread";
239 MessageLoopThread message_loop_thread(name);
240 message_loop_thread.StartUp();
241 ASSERT_NE(message_loop_thread.message_loop(), nullptr);
242 message_loop_thread.ShutDown();
243 ASSERT_EQ(message_loop_thread.message_loop(), nullptr);
244 }
245
TEST_F(MessageLoopThreadTest,test_to_string_method)246 TEST_F(MessageLoopThreadTest, test_to_string_method) {
247 std::string name = "test_thread";
248 MessageLoopThread message_loop_thread(name);
249 std::string thread_string_before_start = message_loop_thread.ToString();
250 ASSERT_FALSE(thread_string_before_start.empty());
251 log::info("Before start: {}", message_loop_thread);
252 message_loop_thread.StartUp();
253 std::string thread_string_running = message_loop_thread.ToString();
254 ASSERT_FALSE(thread_string_running.empty());
255 log::info("Running: {}", message_loop_thread);
256 // String representation should look different when thread is not running
257 ASSERT_STRNE(thread_string_running.c_str(),
258 thread_string_before_start.c_str());
259 message_loop_thread.ShutDown();
260 std::string thread_string_after_shutdown = message_loop_thread.ToString();
261 log::info("After shutdown: {}", message_loop_thread);
262 // String representation should look the same when thread is not running
263 ASSERT_STREQ(thread_string_after_shutdown.c_str(),
264 thread_string_before_start.c_str());
265 }
266
267 // Verify the message loop thread will shutdown after callback finishes
TEST_F(MessageLoopThreadTest,shut_down_while_in_callback)268 TEST_F(MessageLoopThreadTest, shut_down_while_in_callback) {
269 std::string name = "test_thread";
270 MessageLoopThread message_loop_thread(name);
271 message_loop_thread.StartUp();
272 std::promise<std::string> name_promise;
273 std::future<std::string> name_future = name_promise.get_future();
274 uint32_t delay_ms = 5;
275 message_loop_thread.DoInThread(
276 FROM_HERE, base::BindOnce(&MessageLoopThreadTest::SleepAndGetName,
277 base::Unretained(this), std::move(name_promise),
278 delay_ms));
279 message_loop_thread.ShutDown();
280 std::string my_name = name_future.get();
281 ASSERT_EQ(name, my_name);
282 }
283
284 // Verify the message loop thread will shutdown after callback finishes
TEST_F(MessageLoopThreadTest,shut_down_while_in_callback_check_lock)285 TEST_F(MessageLoopThreadTest, shut_down_while_in_callback_check_lock) {
286 std::string name = "test_thread";
287 MessageLoopThread message_loop_thread(name);
288 message_loop_thread.StartUp();
289 message_loop_thread.DoInThread(
290 FROM_HERE,
291 base::BindOnce([](MessageLoopThread* thread) { thread->IsRunning(); },
292 &message_loop_thread));
293 message_loop_thread.ShutDown();
294 }
295
296 // Verify multiple threads try shutdown, no deadlock/crash
TEST_F(MessageLoopThreadTest,shut_down_multi_thread)297 TEST_F(MessageLoopThreadTest, shut_down_multi_thread) {
298 std::string name = "test_thread";
299 MessageLoopThread message_loop_thread(name);
300 message_loop_thread.StartUp();
301 auto thread = std::thread(&MessageLoopThread::ShutDown, &message_loop_thread);
302 message_loop_thread.ShutDown();
303 thread.join();
304 }
305
306 // Verify multiple threads try startup, no deadlock/crash
TEST_F(MessageLoopThreadTest,start_up_multi_thread)307 TEST_F(MessageLoopThreadTest, start_up_multi_thread) {
308 std::string name = "test_thread";
309 MessageLoopThread message_loop_thread(name);
310 message_loop_thread.StartUp();
311 auto thread = std::thread(&MessageLoopThread::StartUp, &message_loop_thread);
312 thread.join();
313 }
314
315 // Verify multiple threads try startup/shutdown, no deadlock/crash
TEST_F(MessageLoopThreadTest,start_up_shut_down_multi_thread)316 TEST_F(MessageLoopThreadTest, start_up_shut_down_multi_thread) {
317 std::string name = "test_thread";
318 MessageLoopThread message_loop_thread(name);
319 message_loop_thread.StartUp();
320 auto thread = std::thread(&MessageLoopThread::ShutDown, &message_loop_thread);
321 thread.join();
322 }
323
324 // Verify multiple threads try shutdown/startup, no deadlock/crash
TEST_F(MessageLoopThreadTest,shut_down_start_up_multi_thread)325 TEST_F(MessageLoopThreadTest, shut_down_start_up_multi_thread) {
326 std::string name = "test_thread";
327 MessageLoopThread message_loop_thread(name);
328 message_loop_thread.StartUp();
329 message_loop_thread.ShutDown();
330 auto thread = std::thread(&MessageLoopThread::StartUp, &message_loop_thread);
331 thread.join();
332 }
333
334 // Verify that Post executes in order
TEST_F(MessageLoopThreadTest,test_post_twice)335 TEST_F(MessageLoopThreadTest, test_post_twice) {
336 std::string name = "test_thread";
337 MessageLoopThread message_loop_thread(name);
338 int counter = 0;
339 message_loop_thread.StartUp();
340 message_loop_thread.Post(
341 base::BindOnce([](MessageLoopThread* thread,
342 int* counter) { ASSERT_EQ((*counter)++, 0); },
343 &message_loop_thread, &counter));
344 message_loop_thread.Post(
345 base::BindOnce([](MessageLoopThread* thread,
346 int* counter) { ASSERT_EQ((*counter)++, 1); },
347 &message_loop_thread, &counter));
348 message_loop_thread.ShutDown();
349 ASSERT_EQ(counter, 2);
350 }
351