1 /*
2  * Copyright 2022 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 #define LOG_TAG "bt_headless_messenger"
18 
19 #include "test/headless/messenger.h"
20 
21 #include <condition_variable>
22 #include <deque>
23 #include <memory>
24 #include <mutex>
25 
26 #include "test/headless/interface.h"
27 #include "test/headless/log.h"
28 
29 // TODO(b/369381361) Enfore -Wmissing-prototypes
30 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
31 
32 using namespace bluetooth::test::headless;
33 using namespace std::chrono_literals;
34 
35 template <typename T>
36 struct callback_queue_t {
callback_queue_tcallback_queue_t37   callback_queue_t(const std::string name) : name_(name) {}
38   // Must be held with lock
sizecallback_queue_t39   size_t size() const { return callback_queue.size(); }
40 
41 private:
42   const std::string name_;
43   std::deque<T> callback_queue;
44 
45 public:
Pushcallback_queue_t46   void Push(T elem) { callback_queue.push_back(elem); }
47   // Must be held with lock
Popcallback_queue_t48   T Pop() {
49     T p = callback_queue.front();
50     callback_queue.pop_front();
51     return p;
52   }
53   // Must be held with lock
emptycallback_queue_t54   bool empty() const { return callback_queue.empty(); }
55 };
56 
57 struct messenger_t {
58   mutable std::mutex mutex;
59   std::condition_variable cv;
60   callback_queue_t<std::shared_ptr<callback_params_t>> callback_queue =
61           callback_queue_t<std::shared_ptr<callback_params_t>>("callbacks");
Pushmessenger_t62   void Push(std::shared_ptr<callback_params_t> elem) {
63     std::unique_lock<std::mutex> lk(mutex);
64     callback_queue.Push(elem);
65     cv.notify_all();
66   }
67 };
68 
69 namespace bluetooth {
70 namespace test {
71 namespace headless {
72 namespace messenger {
73 
74 // Called by client to await any callback for the given callbacks
75 messenger_t callback_data_;
76 
await_callback(Context & context)77 bool await_callback(Context& context) {
78   std::unique_lock<std::mutex> lk(callback_data_.mutex);
79   while (!callback_data_.callback_queue.empty()) {
80     std::shared_ptr<callback_params_t> cb = callback_data_.callback_queue.Pop();
81     if (std::find(context.callbacks.begin(), context.callbacks.end(), cb->CallbackType()) !=
82         context.callbacks.end()) {
83       context.callback_ready_q.push_back(cb);
84     }
85   }
86   if (context.callback_ready_q.size() == 0) {
87     callback_data_.cv.wait_for(lk, context.timeout);
88   }
89   return true;
90 }
91 
92 }  // namespace messenger
93 }  // namespace headless
94 }  // namespace test
95 }  // namespace bluetooth
96 
97 namespace bluetooth::test::headless {
98 
messenger_stats()99 void messenger_stats() {
100   //  LOG_CONSOLE("%30s cnt:%zu", "device_found",
101   //  discovered::device_found_.size()); LOG_CONSOLE("%30s cnt:%zu",
102   //  "remote_device_properties",
103   //              properties::remote_device_properties_.size());
104 }
105 
106 // Callbacks that the messenger will handle from the bluetooth stack
start_messenger()107 void start_messenger() {
108   headless_add_callback("acl_state_changed", [](callback_data_t* data) {
109     log::assert_that(data != nullptr, "Received nullptr callback data");
110     messenger::callback_data_.Push(std::make_shared<acl_state_changed_params_t>(
111             *(static_cast<acl_state_changed_params_t*>(data))));
112   });
113   headless_add_callback("adapter_properties", [](callback_data_t* data) {
114     log::assert_that(data != nullptr, "Received nullptr callback data");
115     messenger::callback_data_.Push(std::make_shared<adapter_properties_params_t>(
116             *(static_cast<adapter_properties_params_t*>(data))));
117   });
118   headless_add_callback("device_found", [](callback_data_t* data) {
119     log::assert_that(data != nullptr, "Received nullptr callback data");
120     messenger::callback_data_.Push(
121             std::make_shared<device_found_params_t>(*(static_cast<device_found_params_t*>(data))));
122   });
123   headless_add_callback("remote_device_properties", [](callback_data_t* data) {
124     log::assert_that(data != nullptr, "Received nullptr callback data");
125     messenger::callback_data_.Push(std::make_shared<remote_device_properties_params_t>(
126             *(static_cast<remote_device_properties_params_t*>(data))));
127   });
128   LOG_CONSOLE("Started messenger service");
129 }
130 
stop_messenger()131 void stop_messenger() {
132   headless_remove_callback("remote_device_properties");
133   headless_remove_callback("device_found");
134   headless_remove_callback("adapter_properties");
135   headless_remove_callback("acl_state_changed");
136 
137   LOG_CONSOLE("Stopped messenger service");
138 
139   messenger_stats();
140 }
141 
142 }  // namespace bluetooth::test::headless
143