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, &param), 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, &param), 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