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