1 /*
2  * Copyright 2017 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 "gatt"
18 
19 #include <bluetooth/log.h>
20 
21 #include <list>
22 #include <unordered_map>
23 #include <unordered_set>
24 #include <vector>
25 
26 #include "bta_gatt_queue.h"
27 #include "os/log.h"
28 #include "osi/include/allocator.h"
29 
30 using gatt_operation = BtaGattQueue::gatt_operation;
31 using namespace bluetooth;
32 
33 constexpr uint8_t GATT_READ_CHAR = 1;
34 constexpr uint8_t GATT_READ_DESC = 2;
35 constexpr uint8_t GATT_WRITE_CHAR = 3;
36 constexpr uint8_t GATT_WRITE_DESC = 4;
37 constexpr uint8_t GATT_CONFIG_MTU = 5;
38 constexpr uint8_t GATT_READ_MULTI = 6;
39 
40 struct gatt_read_op_data {
41   GATT_READ_OP_CB cb;
42   void* cb_data;
43 };
44 
45 std::unordered_map<uint16_t, std::list<gatt_operation>>
46     BtaGattQueue::gatt_op_queue;
47 std::unordered_set<uint16_t> BtaGattQueue::gatt_op_queue_executing;
48 
mark_as_not_executing(uint16_t conn_id)49 void BtaGattQueue::mark_as_not_executing(uint16_t conn_id) {
50   gatt_op_queue_executing.erase(conn_id);
51 }
52 
gatt_read_op_finished(uint16_t conn_id,tGATT_STATUS status,uint16_t handle,uint16_t len,uint8_t * value,void * data)53 void BtaGattQueue::gatt_read_op_finished(uint16_t conn_id, tGATT_STATUS status,
54                                          uint16_t handle, uint16_t len,
55                                          uint8_t* value, void* data) {
56   gatt_read_op_data* tmp = (gatt_read_op_data*)data;
57   GATT_READ_OP_CB tmp_cb = tmp->cb;
58   void* tmp_cb_data = tmp->cb_data;
59 
60   osi_free(data);
61 
62   mark_as_not_executing(conn_id);
63   gatt_execute_next_op(conn_id);
64 
65   if (tmp_cb) {
66     tmp_cb(conn_id, status, handle, len, value, tmp_cb_data);
67     return;
68   }
69 }
70 
71 struct gatt_write_op_data {
72   GATT_WRITE_OP_CB cb;
73   void* cb_data;
74 };
75 
gatt_write_op_finished(uint16_t conn_id,tGATT_STATUS status,uint16_t handle,uint16_t len,const uint8_t * value,void * data)76 void BtaGattQueue::gatt_write_op_finished(uint16_t conn_id, tGATT_STATUS status,
77                                           uint16_t handle, uint16_t len,
78                                           const uint8_t* value, void* data) {
79   gatt_write_op_data* tmp = (gatt_write_op_data*)data;
80   GATT_WRITE_OP_CB tmp_cb = tmp->cb;
81   void* tmp_cb_data = tmp->cb_data;
82 
83   osi_free(data);
84 
85   mark_as_not_executing(conn_id);
86   gatt_execute_next_op(conn_id);
87 
88   if (tmp_cb) {
89     tmp_cb(conn_id, status, handle, len, value, tmp_cb_data);
90     return;
91   }
92 }
93 
94 struct gatt_configure_mtu_op_data {
95   GATT_CONFIGURE_MTU_OP_CB cb;
96   void* cb_data;
97 };
98 
gatt_configure_mtu_op_finished(uint16_t conn_id,tGATT_STATUS status,void * data)99 void BtaGattQueue::gatt_configure_mtu_op_finished(uint16_t conn_id,
100                                                   tGATT_STATUS status,
101                                                   void* data) {
102   gatt_configure_mtu_op_data* tmp = (gatt_configure_mtu_op_data*)data;
103   GATT_CONFIGURE_MTU_OP_CB tmp_cb = tmp->cb;
104   void* tmp_cb_data = tmp->cb_data;
105 
106   osi_free(data);
107 
108   mark_as_not_executing(conn_id);
109   gatt_execute_next_op(conn_id);
110 
111   if (tmp_cb) {
112     tmp_cb(conn_id, status, tmp_cb_data);
113     return;
114   }
115 }
116 
117 struct gatt_read_multi_op_data {
118   GATT_READ_MULTI_OP_CB cb;
119   void* cb_data;
120 };
121 
gatt_read_multi_op_finished(uint16_t conn_id,tGATT_STATUS status,tBTA_GATTC_MULTI & handles,uint16_t len,uint8_t * value,void * data)122 void BtaGattQueue::gatt_read_multi_op_finished(uint16_t conn_id,
123                                                tGATT_STATUS status,
124                                                tBTA_GATTC_MULTI& handles,
125                                                uint16_t len, uint8_t* value,
126                                                void* data) {
127   gatt_read_multi_op_data* tmp = (gatt_read_multi_op_data*)data;
128   GATT_READ_MULTI_OP_CB tmp_cb = tmp->cb;
129   void* tmp_cb_data = tmp->cb_data;
130 
131   osi_free(data);
132 
133   mark_as_not_executing(conn_id);
134   gatt_execute_next_op(conn_id);
135 
136   if (tmp_cb) {
137     tmp_cb(conn_id, status, handles, len, value, tmp_cb_data);
138     return;
139   }
140 }
141 
gatt_execute_next_op(uint16_t conn_id)142 void BtaGattQueue::gatt_execute_next_op(uint16_t conn_id) {
143   log::verbose("conn_id=0x{:x}", conn_id);
144   if (gatt_op_queue.empty()) {
145     log::verbose("op queue is empty");
146     return;
147   }
148 
149   auto map_ptr = gatt_op_queue.find(conn_id);
150   if (map_ptr == gatt_op_queue.end() || map_ptr->second.empty()) {
151     log::verbose("no more operations queued for conn_id {}", conn_id);
152     return;
153   }
154 
155   if (gatt_op_queue_executing.count(conn_id)) {
156     log::verbose("can't enqueue next op, already executing");
157     return;
158   }
159 
160   gatt_op_queue_executing.insert(conn_id);
161 
162   std::list<gatt_operation>& gatt_ops = map_ptr->second;
163 
164   gatt_operation& op = gatt_ops.front();
165 
166   if (op.type == GATT_READ_CHAR) {
167     gatt_read_op_data* data =
168         (gatt_read_op_data*)osi_malloc(sizeof(gatt_read_op_data));
169     data->cb = op.read_cb;
170     data->cb_data = op.read_cb_data;
171     BTA_GATTC_ReadCharacteristic(conn_id, op.handle, GATT_AUTH_REQ_NONE,
172                                  gatt_read_op_finished, data);
173 
174   } else if (op.type == GATT_READ_DESC) {
175     gatt_read_op_data* data =
176         (gatt_read_op_data*)osi_malloc(sizeof(gatt_read_op_data));
177     data->cb = op.read_cb;
178     data->cb_data = op.read_cb_data;
179     BTA_GATTC_ReadCharDescr(conn_id, op.handle, GATT_AUTH_REQ_NONE,
180                             gatt_read_op_finished, data);
181 
182   } else if (op.type == GATT_WRITE_CHAR) {
183     gatt_write_op_data* data =
184         (gatt_write_op_data*)osi_malloc(sizeof(gatt_write_op_data));
185     data->cb = op.write_cb;
186     data->cb_data = op.write_cb_data;
187     BTA_GATTC_WriteCharValue(conn_id, op.handle, op.write_type,
188                              std::move(op.value), GATT_AUTH_REQ_NONE,
189                              gatt_write_op_finished, data);
190 
191   } else if (op.type == GATT_WRITE_DESC) {
192     gatt_write_op_data* data =
193         (gatt_write_op_data*)osi_malloc(sizeof(gatt_write_op_data));
194     data->cb = op.write_cb;
195     data->cb_data = op.write_cb_data;
196     BTA_GATTC_WriteCharDescr(conn_id, op.handle, std::move(op.value),
197                              GATT_AUTH_REQ_NONE, gatt_write_op_finished, data);
198   } else if (op.type == GATT_CONFIG_MTU) {
199     gatt_configure_mtu_op_data* data =
200       (gatt_configure_mtu_op_data*)osi_malloc(sizeof(gatt_configure_mtu_op_data));
201     data->cb = op.mtu_cb;
202     data->cb_data = op.mtu_cb_data;
203     BTA_GATTC_ConfigureMTU(conn_id, static_cast<uint16_t>(op.value[0] |
204                                                           (op.value[1] << 8)),
205                            gatt_configure_mtu_op_finished, data);
206   } else if (op.type == GATT_READ_MULTI) {
207     gatt_read_multi_op_data* data =
208         (gatt_read_multi_op_data*)osi_malloc(sizeof(gatt_read_multi_op_data));
209     data->cb = op.read_multi_cb;
210     data->cb_data = op.read_cb_data;
211     BTA_GATTC_ReadMultiple(conn_id, op.handles, op.variable_len,
212                            GATT_AUTH_REQ_NONE, gatt_read_multi_op_finished,
213                            data);
214   }
215 
216   gatt_ops.pop_front();
217 }
218 
Clean(uint16_t conn_id)219 void BtaGattQueue::Clean(uint16_t conn_id) {
220   gatt_op_queue.erase(conn_id);
221   gatt_op_queue_executing.erase(conn_id);
222 }
223 
ReadCharacteristic(uint16_t conn_id,uint16_t handle,GATT_READ_OP_CB cb,void * cb_data)224 void BtaGattQueue::ReadCharacteristic(uint16_t conn_id, uint16_t handle,
225                                       GATT_READ_OP_CB cb, void* cb_data) {
226   gatt_op_queue[conn_id].push_back({.type = GATT_READ_CHAR,
227                                     .handle = handle,
228                                     .read_cb = cb,
229                                     .read_cb_data = cb_data});
230   gatt_execute_next_op(conn_id);
231 }
232 
ReadDescriptor(uint16_t conn_id,uint16_t handle,GATT_READ_OP_CB cb,void * cb_data)233 void BtaGattQueue::ReadDescriptor(uint16_t conn_id, uint16_t handle,
234                                   GATT_READ_OP_CB cb, void* cb_data) {
235   gatt_op_queue[conn_id].push_back({.type = GATT_READ_DESC,
236                                     .handle = handle,
237                                     .read_cb = cb,
238                                     .read_cb_data = cb_data});
239   gatt_execute_next_op(conn_id);
240 }
241 
WriteCharacteristic(uint16_t conn_id,uint16_t handle,std::vector<uint8_t> value,tGATT_WRITE_TYPE write_type,GATT_WRITE_OP_CB cb,void * cb_data)242 void BtaGattQueue::WriteCharacteristic(uint16_t conn_id, uint16_t handle,
243                                        std::vector<uint8_t> value,
244                                        tGATT_WRITE_TYPE write_type,
245                                        GATT_WRITE_OP_CB cb, void* cb_data) {
246   gatt_op_queue[conn_id].push_back({.type = GATT_WRITE_CHAR,
247                                     .handle = handle,
248                                     .write_cb = cb,
249                                     .write_cb_data = cb_data,
250                                     .write_type = write_type,
251                                     .value = std::move(value)});
252   gatt_execute_next_op(conn_id);
253 }
254 
WriteDescriptor(uint16_t conn_id,uint16_t handle,std::vector<uint8_t> value,tGATT_WRITE_TYPE write_type,GATT_WRITE_OP_CB cb,void * cb_data)255 void BtaGattQueue::WriteDescriptor(uint16_t conn_id, uint16_t handle,
256                                    std::vector<uint8_t> value,
257                                    tGATT_WRITE_TYPE write_type,
258                                    GATT_WRITE_OP_CB cb, void* cb_data) {
259   gatt_op_queue[conn_id].push_back({.type = GATT_WRITE_DESC,
260                                     .handle = handle,
261                                     .write_cb = cb,
262                                     .write_cb_data = cb_data,
263                                     .write_type = write_type,
264                                     .value = std::move(value)});
265   gatt_execute_next_op(conn_id);
266 }
267 
ConfigureMtu(uint16_t conn_id,uint16_t mtu)268 void BtaGattQueue::ConfigureMtu(uint16_t conn_id, uint16_t mtu) {
269   log::info("mtu: {}", static_cast<int>(mtu));
270   std::vector<uint8_t> value = {static_cast<uint8_t>(mtu & 0xff),
271                                 static_cast<uint8_t>(mtu >> 8)};
272   gatt_op_queue[conn_id].push_back({.type = GATT_CONFIG_MTU,
273                                     .value = std::move(value)});
274   gatt_execute_next_op(conn_id);
275 }
276 
ReadMultiCharacteristic(uint16_t conn_id,tBTA_GATTC_MULTI & handles,bool variable_len,GATT_READ_MULTI_OP_CB cb,void * cb_data)277 void BtaGattQueue::ReadMultiCharacteristic(uint16_t conn_id,
278                                            tBTA_GATTC_MULTI& handles,
279                                            bool variable_len,
280                                            GATT_READ_MULTI_OP_CB cb,
281                                            void* cb_data) {
282   gatt_op_queue[conn_id].push_back({.type = GATT_READ_MULTI,
283                                     .handles = handles,
284                                     .variable_len = variable_len,
285                                     .read_multi_cb = cb,
286                                     .read_cb_data = cb_data});
287   gatt_execute_next_op(conn_id);
288 }
289