1 /*
2  *  Copyright 2024 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 
17 #include <bluetooth/log.h>
18 #include <gmock/gmock.h>
19 #include <gtest/gtest.h>
20 #include <unistd.h>
21 
22 #include <cstdlib>
23 #include <memory>
24 
25 #include "common/circular_buffer.h"
26 #include "common/strings.h"
27 #include "gd/module_jniloop.h"
28 #include "gd/module_mainloop.h"
29 #include "hci/include/packet_fragmenter.h"
30 #include "main/shim/dumpsys.h"
31 #include "main/shim/entry.h"
32 #include "main/shim/stack.h"
33 #include "module.h"
34 #include "os/thread.h"
35 #include "shim/dumpsys.h"
36 #include "stack/btm/btm_int_types.h"
37 #include "stack/btm/btm_sec_cb.h"
38 #include "stack/include/main_thread.h"
39 #include "test/mock/mock_main_shim_entry.h"
40 
41 using ::testing::_;
42 
43 using namespace bluetooth;
44 using namespace testing;
45 
46 tBTM_CB btm_cb{};          // main::shim::le_scanning_manager
47 tBTM_SEC_CB btm_sec_cb{};  // main::shim::acl
48 
packet_fragmenter_get_interface()49 const packet_fragmenter_t* packet_fragmenter_get_interface() {
50   return nullptr;
51 }  // main::shim::hci_layer
52 bluetooth::common::TimestamperInMilliseconds
53     timestamper_in_milliseconds;  // main::shim::le_scanning_manager
54 
55 namespace {
56 constexpr char kLogTagStopped[] = "STOPPED";
57 constexpr char kLogTagStarting[] = "STARTING";
58 constexpr char kLogTagStarted[] = "STARTED";
59 constexpr char kLogTagQuiescing[] = "QUIESCING";
60 constexpr char kLogTagQuiesced[] = "QUIESCED";
61 
62 constexpr char kTestStackThreadName[] = "test_stack_thread";
63 constexpr int kSyncMainLoopTimeoutMs = 3000;
64 constexpr int kWaitUntilHandlerStoppedMs = 2000;
65 constexpr size_t kNumTestClients = 10;
66 
67 constexpr size_t kTagLength = 48 + sizeof(' ') + sizeof(' ');
log_tag(std::string tag)68 inline void log_tag(std::string tag) {
69   std::string prepend(kTagLength / 2 - tag.size() / 2, '=');
70   std::string append(kTagLength / 2 - tag.size() / 2, '=');
71   log::info("{} {} {}", prepend, tag, append);
72 }
73 
74 class MainThread {
75  public:
MainThread()76   MainThread() {
77     main_thread_start_up();
78     post_on_bt_main([]() { log::info("<=== tid Main loop started"); });
79   }
80 
~MainThread()81   ~MainThread() {
82     sync_main_handler();
83     main_thread_shut_down();
84   }
85 
86  private:
sync_main_handler()87   void sync_main_handler() {
88     std::promise promise = std::promise<void>();
89     std::future future = promise.get_future();
90     post_on_bt_main([&promise]() { promise.set_value(); });
91     future.wait_for(std::chrono::milliseconds(kSyncMainLoopTimeoutMs));
92   }
93 };
94 
95 class TestStackManager {
96  public:
TestStackManager()97   TestStackManager() {
98     // Stack manager is started in the test after each test uses the default
99     // or adds their own modules
100   }
101 
~TestStackManager()102   ~TestStackManager() {
103     log::debug("Deleting stack manager");
104     Stop();
105   }
106 
107   TestStackManager(const TestStackManager&) = delete;
108 
109   template <typename T>
AddModule()110   void AddModule() {
111     modules_.add<T>();
112   }
113 
Start()114   void Start() {
115     if (stack_started_) return;
116     log::info("Starting up stack manager");
117     stack_started_ = true;
118     bluetooth::os::Thread* stack_thread = new bluetooth::os::Thread(
119         kTestStackThreadName, bluetooth::os::Thread::Priority::NORMAL);
120     bluetooth::shim::Stack::GetInstance()->StartModuleStack(&modules_,
121                                                             stack_thread);
122     bluetooth::shim::Stack::GetInstance()->GetHandler()->Call(
123         []() { log::info("<=== tid GD Event loop started"); });
124   }
125 
Stop()126   void Stop() {
127     if (!stack_started_) return;
128     stack_started_ = false;
129     bluetooth::shim::Stack::GetInstance()->Stop();
130   }
131 
132   // NOTE: Stack manager *must* be active else method returns nullptr
133   // if stack manager has not started or shutdown
134   template <typename T>
GetUnsafeModule()135   static T* GetUnsafeModule() {
136     return bluetooth::shim::Stack::GetInstance()
137         ->GetStackManager()
138         ->GetInstance<T>();
139   }
140 
NumModules() const141   size_t NumModules() const { return modules_.NumModules(); }
142 
143  private:
144   bluetooth::ModuleList modules_;
145   bool stack_started_{false};
146 };
147 
148 // Data returned via callback from a stack managed module
149 struct TestCallbackData {
150   int iter;
151   std::string tag;
152 };
153 
154 // Data sent to a stack managed module via a module API
155 struct TestData {
156   int iter;
157   std::string tag;
158   std::function<void(TestCallbackData callback_data)> callback;
159 };
160 
161 }  // namespace
162 
163 class TestStackDumpsysBase : public bluetooth::Module,
164                              public ModuleMainloop,
165                              public ModuleJniloop {
166  public:
167   TestStackDumpsysBase(const TestStackDumpsysBase&) = delete;
168   TestStackDumpsysBase& operator=(const TestStackDumpsysBase&) = delete;
169 
~TestStackDumpsysBase()170   virtual ~TestStackDumpsysBase(){};
171   static const ModuleFactory Factory;
172 
TestMethod(TestData test_data) const173   virtual void TestMethod(TestData test_data) const {
174     log::info("Test base class iter:{} tag:{}", test_data.iter, test_data.tag);
175   }
176 
177  protected:
ListDependencies(ModuleList *) const178   void ListDependencies(ModuleList* /* list */) const override{};
Start()179   void Start() override { log::error("Started TestStackDumpsysBase"); };
Stop()180   void Stop() override { log::error("Stopped TestStackDumpsysBase"); };
ToString() const181   std::string ToString() const override { return std::string("TestFunction"); }
182 
183   TestStackDumpsysBase() = default;
184 };
185 
186 struct StackRunningData {
187   std::function<void(bool is_running)> cb;
188 };
189 
190 class TestStackDumpsys1 : public TestStackDumpsysBase {
191  public:
192   TestStackDumpsys1(const TestStackDumpsys1&) = delete;
193   TestStackDumpsys1& operator=(const TestStackDumpsys1&) = delete;
194   virtual ~TestStackDumpsys1() = default;
195 
196   static const ModuleFactory Factory;
197 
198   void TestMethod(TestData test_data) const override;
199   void IsStackRunning(StackRunningData stack_running_data) const;
200 
201  private:
202   struct impl;
203   std::shared_ptr<impl> impl_;
204   TestStackDumpsys1();
205 };
206 
207 struct TestStackDumpsys1::impl : public ModuleMainloop, public ModuleJniloop {
testTestStackDumpsys1::impl208   void test(TestData test_data) {
209     TestCallbackData callback_data{
210         .iter = test_data.iter,
211         .tag = std::string(__func__),
212     };
213     PostFunctionOnMain(
214         [](std::function<void(TestCallbackData callback_data)> callback,
215            TestCallbackData data) { callback(data); },
216         test_data.callback, callback_data);
217   }
is_stack_runningTestStackDumpsys1::impl218   void is_stack_running(StackRunningData stack_running_data) const {
219     bool is_running = bluetooth::shim::Stack::GetInstance()->IsRunning();
220     if (stack_running_data.cb) {
221       stack_running_data.cb(is_running);
222     }
223   }
224 };
225 
TestStackDumpsys1()226 TestStackDumpsys1::TestStackDumpsys1() : TestStackDumpsysBase() {
227   impl_ = std::make_shared<impl>();
228 }
229 
TestMethod(TestData test_data) const230 void TestStackDumpsys1::TestMethod(TestData test_data) const {
231   PostMethodOnMain(impl_, &impl::test, test_data);
232 }
233 
IsStackRunning(StackRunningData stack_running_data) const234 void TestStackDumpsys1::IsStackRunning(
235     StackRunningData stack_running_data) const {
236   GetHandler()->CallOn(impl_.get(), &impl::is_stack_running,
237                        stack_running_data);
238 }
239 
240 class TestStackDumpsys2 : public TestStackDumpsysBase {
241  public:
242   TestStackDumpsys2(const TestStackDumpsys2&) = delete;
243   TestStackDumpsys2& operator=(const TestStackDumpsys2&) = delete;
244   virtual ~TestStackDumpsys2() = default;
245 
246   static const ModuleFactory Factory;
247 
248   void TestMethod(TestData test_data) const override;
249 
250  private:
251   struct impl;
252   std::shared_ptr<impl> impl_;
253   TestStackDumpsys2();
254 };
255 
256 struct TestStackDumpsys2::impl : public ModuleMainloop, public ModuleJniloop {
testTestStackDumpsys2::impl257   void test(TestData test_data) {
258     TestCallbackData callback_data{
259         .iter = test_data.iter,
260         .tag = std::string(__func__),
261     };
262     PostFunctionOnMain(
263         [](std::function<void(TestCallbackData callback_data)> callback,
264            TestCallbackData data) { callback(data); },
265         test_data.callback, callback_data);
266   }
267 };
268 
TestStackDumpsys2()269 TestStackDumpsys2::TestStackDumpsys2() : TestStackDumpsysBase() {
270   impl_ = std::make_shared<impl>();
271 }
272 
TestMethod(TestData test_data) const273 void TestStackDumpsys2::TestMethod(TestData test_data) const {
274   PostMethodOnMain(impl_, &impl::test, test_data);
275 }
276 
277 class TestStackDumpsys3 : public TestStackDumpsysBase {
278  public:
279   TestStackDumpsys3(const TestStackDumpsys3&) = delete;
280   TestStackDumpsys3& operator=(const TestStackDumpsys3&) = delete;
281   virtual ~TestStackDumpsys3() = default;
282 
283   static const ModuleFactory Factory;
284 
285   void TestMethod(TestData test_data) const override;
286 
287  private:
288   struct impl;
289   std::shared_ptr<impl> impl_;
290   TestStackDumpsys3();
291 };
292 
293 struct TestStackDumpsys3::impl : public ModuleMainloop, public ModuleJniloop {
testTestStackDumpsys3::impl294   void test(TestData test_data) {
295     TestCallbackData callback_data{
296         .iter = test_data.iter,
297         .tag = std::string(__func__),
298     };
299     PostFunctionOnMain(
300         [](std::function<void(TestCallbackData callback_data)> callback,
301            TestCallbackData data) { callback(data); },
302         test_data.callback, callback_data);
303   }
304 };
305 
TestStackDumpsys3()306 TestStackDumpsys3::TestStackDumpsys3() : TestStackDumpsysBase() {
307   impl_ = std::make_shared<impl>();
308 }
309 
TestMethod(TestData test_data) const310 void TestStackDumpsys3::TestMethod(TestData test_data) const {
311   PostMethodOnMain(impl_, &impl::test, test_data);
312 }
313 
314 class TestStackDumpsys4 : public TestStackDumpsysBase {
315  public:
316   TestStackDumpsys4(const TestStackDumpsys4&) = delete;
317   TestStackDumpsys4& operator=(const TestStackDumpsys3&) = delete;
318   virtual ~TestStackDumpsys4() = default;
319 
320   static const ModuleFactory Factory;
321 
TestMethod(TestData test_data) const322   void TestMethod(TestData test_data) const override {
323     log::info("mod:{} iter:{} tag:{}", __func__, test_data.iter, test_data.tag);
324   }
325 
326  private:
327   struct impl;
328   std::shared_ptr<impl> impl_;
TestStackDumpsys4()329   TestStackDumpsys4() : TestStackDumpsysBase() {}
330 };
331 
332 struct TestStackDumpsys4::impl : public ModuleMainloop, public ModuleJniloop {};
333 
334 const ModuleFactory TestStackDumpsysBase::Factory =
__anonc942baa20802() 335     ModuleFactory([]() { return new TestStackDumpsysBase(); });
336 
337 const ModuleFactory TestStackDumpsys1::Factory =
__anonc942baa20902() 338     ModuleFactory([]() { return new TestStackDumpsys1(); });
339 const ModuleFactory TestStackDumpsys2::Factory =
__anonc942baa20a02() 340     ModuleFactory([]() { return new TestStackDumpsys2(); });
341 const ModuleFactory TestStackDumpsys3::Factory =
__anonc942baa20b02() 342     ModuleFactory([]() { return new TestStackDumpsys3(); });
343 const ModuleFactory TestStackDumpsys4::Factory =
__anonc942baa20c02() 344     ModuleFactory([]() { return new TestStackDumpsys4(); });
345 
346 class StackWithMainThreadUnitTest : public ::testing::Test {
347  protected:
SetUp()348   void SetUp() override { main_thread_ = std::make_unique<MainThread>(); }
TearDown()349   void TearDown() override { main_thread_.reset(); }
350 
351  private:
352   std::unique_ptr<MainThread> main_thread_;
353 };
354 
355 class StackLifecycleUnitTest : public StackWithMainThreadUnitTest {
356  public:
StackManager() const357   std::shared_ptr<TestStackManager> StackManager() const {
358     return stack_manager_;
359   }
360 
361  protected:
SetUp()362   void SetUp() override {
363     StackWithMainThreadUnitTest::SetUp();
364     stack_manager_ = std::make_shared<TestStackManager>();
365   }
366 
TearDown()367   void TearDown() override {
368     stack_manager_.reset();
369     StackWithMainThreadUnitTest::TearDown();
370   }
371 
372  private:
373   std::shared_ptr<TestStackManager> stack_manager_;
374 };
375 
376 class MainShimStackDumpsysTest : public StackLifecycleUnitTest {
377  protected:
SetUp()378   void SetUp() override {
379     StackLifecycleUnitTest::SetUp();
380     StackManager()->AddModule<TestStackDumpsys1>();
381     StackManager()->AddModule<TestStackDumpsys2>();
382     StackManager()->AddModule<TestStackDumpsys3>();
383     StackManager()->AddModule<bluetooth::shim::Dumpsys>();
384     StackManager()->Start();
385     ASSERT_EQ(4U, StackManager()->NumModules());
386 
387     bluetooth::shim::RegisterDumpsysFunction((void*)this, [](int fd) {
388       log::info("Callback to dump legacy data fd:{}", fd);
389     });
390   }
391 
TearDown()392   void TearDown() override {
393     bluetooth::shim::UnregisterDumpsysFunction((void*)this);
394     StackLifecycleUnitTest::TearDown();
395   }
396 };
397 
398 struct CallablePostCnt {
399   size_t success{0};
400   size_t misses{0};
operator +=CallablePostCnt401   CallablePostCnt operator+=(const CallablePostCnt& post_cnt) {
402     return CallablePostCnt(
403         {success += post_cnt.success, misses += post_cnt.misses});
404   }
405 };
406 
407 // Provide a client user of the stack manager module services
408 class Client {
409  public:
Client(int id)410   Client(int id) : id_(id) {}
411   Client(const Client&) = default;
412   virtual ~Client() = default;
413 
414   // Start up the client a thread and handler
Start()415   void Start() {
416     thread_ = new os::Thread(common::StringFormat("ClientThread%d", id_),
417                              os::Thread::Priority::NORMAL);
418     handler_ = new os::Handler(thread_);
419     handler_->Post(common::BindOnce(
420         [](int id) { log::info("<=== tid Started client id:{}", id); }, id_));
421   }
422 
423   // Ensure all the client handlers are running
Await()424   void Await() {
425     std::promise<void> promise;
426     std::future future = promise.get_future();
427     handler_->Post(
428         base::BindOnce([](std::promise<void> promise) { promise.set_value(); },
429                        std::move(promise)));
430     future.wait();
431   }
432 
433   // Post a work task on behalf of this client
Post(common::OnceClosure closure)434   void Post(common::OnceClosure closure) {
435     if (quiesced_) {
436       post_cnt_.misses++;
437     } else {
438       post_cnt_.success++;
439       handler_->Post(std::move(closure));
440     }
441   }
442 
443   // Safely prevent new work tasks from being posted
Quiesce()444   void Quiesce() {
445     if (quiesced_) return;
446     quiesced_ = true;
447     std::promise promise = std::promise<void>();
448     std::future future = promise.get_future();
449     handler_->Post(common::BindOnce(
450         [](std::promise<void> promise, int id) {
451           promise.set_value();
452           log::info("<=== tid Quiesced client id:{}", id);
453         },
454         std::move(promise), id_));
455     future.wait_for(std::chrono::milliseconds(kSyncMainLoopTimeoutMs));
456   }
457 
458   // Queisces if needed and stops the client then releases associated resources
Stop()459   void Stop() {
460     if (!quiesced_) {
461       Quiesce();
462     }
463     handler_->Clear();
464     handler_->WaitUntilStopped(
465         std::chrono::milliseconds(kWaitUntilHandlerStoppedMs));
466     delete handler_;
467     delete thread_;
468   }
469 
Id() const470   int Id() const { return id_; }
471 
GetCallablePostCnt() const472   CallablePostCnt GetCallablePostCnt() const { return post_cnt_; }
473 
Name() const474   std::string Name() const {
475     return common::StringFormat("%s%d", __func__, id_);
476   }
477 
478  private:
479   int id_{0};
480   CallablePostCnt post_cnt_{};
481   bool quiesced_{false};
482   os::Handler* handler_{nullptr};
483   os::Thread* thread_{nullptr};
484 };
485 
486 // Convenience object to handle multiple clients with logging
487 class ClientGroup {
488  public:
ClientGroup(size_t num_clients)489   explicit ClientGroup(size_t num_clients) {
490     for (size_t i = 0; i < num_clients; i++) {
491       clients_.emplace_back(std::make_unique<Client>(i));
492     }
493   }
494 
Start()495   void Start() {
496     log_tag(kLogTagStarting);
497     for (auto& c : clients_) {
498       c->Start();
499     }
500   }
501 
Await()502   void Await() {
503     for (auto& c : clients_) {
504       c->Await();
505     }
506     log_tag(kLogTagStarted);
507   }
508 
Quiesce()509   void Quiesce() {
510     log_tag(kLogTagQuiescing);
511     for (auto& c : clients_) {
512       c->Quiesce();
513     }
514     log_tag(kLogTagQuiesced);
515   }
516 
Stop()517   void Stop() {
518     for (auto& c : clients_) {
519       c->Stop();
520     }
521     log_tag(kLogTagStopped);
522   }
523 
Dump() const524   void Dump() const {
525     for (auto& c : clients_) {
526       log::info("Callable post cnt client_id:{} success:{} misses:{}", c->Id(),
527                 c->GetCallablePostCnt().success,
528                 c->GetCallablePostCnt().misses);
529     }
530   }
531 
GetCallablePostCnt() const532   CallablePostCnt GetCallablePostCnt() const {
533     CallablePostCnt post_cnt{};
534     for (auto& c : clients_) {
535       post_cnt += c->GetCallablePostCnt();
536     }
537     return post_cnt;
538   }
539 
NumClients() const540   size_t NumClients() const { return clients_.size(); }
541 
542   std::vector<std::unique_ptr<Client>> clients_;
543 };
544 
545 class MainShimStackDumpsysWithClientsTest : public MainShimStackDumpsysTest {
546  protected:
SetUp()547   void SetUp() override {
548     MainShimStackDumpsysTest::SetUp();
549     client_group_.Start();
550     client_group_.Await();
551   }
552 
TearDown()553   void TearDown() override {
554     client_group_.Quiesce();
555     client_group_.Stop();
556     MainShimStackDumpsysTest::TearDown();
557   }
558   ClientGroup client_group_ = ClientGroup(kNumTestClients);
559 };
560 
TEST_F(MainShimStackDumpsysWithClientsTest,all_clients_check_stack_running)561 TEST_F(MainShimStackDumpsysWithClientsTest, all_clients_check_stack_running) {
562   StackRunningData stack_running_data = {
563       .cb =
564           [](bool is_stack_running) {
565             log::info("Stack is running:{}", (is_stack_running) ? 'T' : 'F');
566           },
567   };
568 
569   // Ensure the dumpsys instance is included within the stack
570   ASSERT_NE(nullptr, bluetooth::shim::GetDumpsys());
571 
572   for (auto& c : client_group_.clients_) {
573     c->Post(base::BindOnce(
574         [](StackRunningData stack_running_data) {
575           bluetooth::shim::Stack::GetInstance()
576               ->GetStackManager()
577               ->GetInstance<TestStackDumpsys1>()
578               ->IsStackRunning(stack_running_data);
579         },
580         stack_running_data));
581   }
582 }
583 
TEST_F(MainShimStackDumpsysWithClientsTest,all_clients_check_stack_running_with_iterations)584 TEST_F(MainShimStackDumpsysWithClientsTest,
585        all_clients_check_stack_running_with_iterations) {
586   StackRunningData stack_running_data = {
587       .cb =
588           [](bool is_stack_running) {
589             log::info("Run on mainloop: Stack is running:{}",
590                       (is_stack_running) ? 'T' : 'F');
591           },
592   };
593 
594   // Ensure the dumpsys instance is included within the stack
595   ASSERT_NE(nullptr, bluetooth::shim::GetDumpsys());
596 
597   for (int i = 0; i < 2; i++) {
598     log::info("Iteration:{}", i);
599     for (auto& c : client_group_.clients_) {
600       c->Post(base::BindOnce(
601           [](StackRunningData stack_running_data) {
602             bluetooth::shim::Stack::GetInstance()
603                 ->GetStackManager()
604                 ->GetInstance<TestStackDumpsys1>()
605                 ->IsStackRunning(stack_running_data);
606           },
607           stack_running_data));
608     }
609   }
610 }
611 
TEST_F(MainShimStackDumpsysWithClientsTest,dumpsys_single_client)612 TEST_F(MainShimStackDumpsysWithClientsTest, dumpsys_single_client) {
613   // Ensure the dumpsys instance is included within the stack
614   ASSERT_NE(nullptr, bluetooth::shim::GetDumpsys());
615 
616   const int fd = 1;
617   client_group_.clients_[0]->Post(
618       base::BindOnce([](int fd) { bluetooth::shim::Dump(fd, nullptr); }, fd));
619 }
620 
TEST_F(MainShimStackDumpsysWithClientsTest,dumpsys_single_client_with_running_check)621 TEST_F(MainShimStackDumpsysWithClientsTest,
622        dumpsys_single_client_with_running_check) {
623   StackRunningData stack_running_data = {
624       .cb =
625           [](bool is_stack_running) {
626             log::info("Stack is running:{}", (is_stack_running) ? 'T' : 'F');
627           },
628   };
629 
630   // Ensure the dumpsys instance is included within the stack
631   ASSERT_NE(nullptr, bluetooth::shim::GetDumpsys());
632 
633   const int fd = 1;
634   client_group_.clients_[0]->Post(base::BindOnce(
635       [](StackRunningData stack_running_data) {
636         bluetooth::shim::Stack::GetInstance()
637             ->GetStackManager()
638             ->GetInstance<TestStackDumpsys1>()
639             ->IsStackRunning(stack_running_data);
640       },
641       stack_running_data));
642   client_group_.clients_[0]->Post(
643       base::BindOnce([](int fd) { bluetooth::shim::Dump(fd, nullptr); }, fd));
644 }
645 
TEST_F(MainShimStackDumpsysWithClientsTest,dumpsys_many_clients)646 TEST_F(MainShimStackDumpsysWithClientsTest, dumpsys_many_clients) {
647   StackRunningData stack_running_data = {
648       .cb =
649           [](bool is_stack_running) {
650             log::info("Stack is running:{}", (is_stack_running) ? 'T' : 'F');
651           },
652   };
653 
654   const int fd = 1;
655   for (auto& c : client_group_.clients_) {
656     c->Post(
657         base::BindOnce([](int fd) { bluetooth::shim::Dump(fd, nullptr); }, fd));
658   }
659 }
660