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