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