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 #include "bta_gatt_queue.h"
18 
19 #include <list>
20 #include <unordered_map>
21 #include <unordered_set>
22 
23 using gatt_operation = BtaGattQueue::gatt_operation;
24 
25 constexpr uint8_t GATT_READ_CHAR = 1;
26 constexpr uint8_t GATT_READ_DESC = 2;
27 constexpr uint8_t GATT_WRITE_CHAR = 3;
28 constexpr uint8_t GATT_WRITE_DESC = 4;
29 
30 struct gatt_read_op_data {
31   GATT_READ_OP_CB cb;
32   void* cb_data;
33 };
34 
35 std::unordered_map<uint16_t, std::list<gatt_operation>>
36     BtaGattQueue::gatt_op_queue;
37 std::unordered_set<uint16_t> BtaGattQueue::gatt_op_queue_executing;
38 
mark_as_not_executing(uint16_t conn_id)39 void BtaGattQueue::mark_as_not_executing(uint16_t conn_id) {
40   gatt_op_queue_executing.erase(conn_id);
41 }
42 
gatt_read_op_finished(uint16_t conn_id,tGATT_STATUS status,uint16_t handle,uint16_t len,uint8_t * value,void * data)43 void BtaGattQueue::gatt_read_op_finished(uint16_t conn_id, tGATT_STATUS status,
44                                          uint16_t handle, uint16_t len,
45                                          uint8_t* value, void* data) {
46   gatt_read_op_data* tmp = (gatt_read_op_data*)data;
47   GATT_READ_OP_CB tmp_cb = tmp->cb;
48   void* tmp_cb_data = tmp->cb_data;
49 
50   osi_free(data);
51 
52   mark_as_not_executing(conn_id);
53   gatt_execute_next_op(conn_id);
54 
55   if (tmp_cb) {
56     tmp_cb(conn_id, status, handle, len, value, tmp_cb_data);
57     return;
58   }
59 }
60 
61 struct gatt_write_op_data {
62   GATT_WRITE_OP_CB cb;
63   void* cb_data;
64 };
65 
gatt_write_op_finished(uint16_t conn_id,tGATT_STATUS status,uint16_t handle,void * data)66 void BtaGattQueue::gatt_write_op_finished(uint16_t conn_id, tGATT_STATUS status,
67                                           uint16_t handle, void* data) {
68   gatt_write_op_data* tmp = (gatt_write_op_data*)data;
69   GATT_WRITE_OP_CB tmp_cb = tmp->cb;
70   void* tmp_cb_data = tmp->cb_data;
71 
72   osi_free(data);
73 
74   mark_as_not_executing(conn_id);
75   gatt_execute_next_op(conn_id);
76 
77   if (tmp_cb) {
78     tmp_cb(conn_id, status, handle, tmp_cb_data);
79     return;
80   }
81 }
82 
gatt_execute_next_op(uint16_t conn_id)83 void BtaGattQueue::gatt_execute_next_op(uint16_t conn_id) {
84   APPL_TRACE_DEBUG("%s: conn_id=0x%x", __func__, conn_id);
85   if (gatt_op_queue.empty()) {
86     APPL_TRACE_DEBUG("%s: op queue is empty", __func__);
87     return;
88   }
89 
90   auto map_ptr = gatt_op_queue.find(conn_id);
91   if (map_ptr == gatt_op_queue.end() || map_ptr->second.empty()) {
92     APPL_TRACE_DEBUG("%s: no more operations queued for conn_id %d", __func__,
93                      conn_id);
94     return;
95   }
96 
97   if (gatt_op_queue_executing.count(conn_id)) {
98     APPL_TRACE_DEBUG("%s: can't enqueue next op, already executing", __func__);
99     return;
100   }
101 
102   gatt_op_queue_executing.insert(conn_id);
103 
104   std::list<gatt_operation>& gatt_ops = map_ptr->second;
105 
106   gatt_operation& op = gatt_ops.front();
107 
108   if (op.type == GATT_READ_CHAR) {
109     gatt_read_op_data* data =
110         (gatt_read_op_data*)osi_malloc(sizeof(gatt_read_op_data));
111     data->cb = op.read_cb;
112     data->cb_data = op.read_cb_data;
113     BTA_GATTC_ReadCharacteristic(conn_id, op.handle, GATT_AUTH_REQ_NONE,
114                                  gatt_read_op_finished, data);
115 
116   } else if (op.type == GATT_READ_DESC) {
117     gatt_read_op_data* data =
118         (gatt_read_op_data*)osi_malloc(sizeof(gatt_read_op_data));
119     data->cb = op.read_cb;
120     data->cb_data = op.read_cb_data;
121     BTA_GATTC_ReadCharDescr(conn_id, op.handle, GATT_AUTH_REQ_NONE,
122                             gatt_read_op_finished, data);
123 
124   } else if (op.type == GATT_WRITE_CHAR) {
125     gatt_write_op_data* data =
126         (gatt_write_op_data*)osi_malloc(sizeof(gatt_write_op_data));
127     data->cb = op.write_cb;
128     data->cb_data = op.write_cb_data;
129     BTA_GATTC_WriteCharValue(conn_id, op.handle, op.write_type,
130                              std::move(op.value), GATT_AUTH_REQ_NONE,
131                              gatt_write_op_finished, data);
132 
133   } else if (op.type == GATT_WRITE_DESC) {
134     gatt_write_op_data* data =
135         (gatt_write_op_data*)osi_malloc(sizeof(gatt_write_op_data));
136     data->cb = op.write_cb;
137     data->cb_data = op.write_cb_data;
138     BTA_GATTC_WriteCharDescr(conn_id, op.handle, std::move(op.value),
139                              GATT_AUTH_REQ_NONE, gatt_write_op_finished, data);
140   }
141 
142   gatt_ops.pop_front();
143 }
144 
Clean(uint16_t conn_id)145 void BtaGattQueue::Clean(uint16_t conn_id) {
146   gatt_op_queue.erase(conn_id);
147   gatt_op_queue_executing.erase(conn_id);
148 }
149 
ReadCharacteristic(uint16_t conn_id,uint16_t handle,GATT_READ_OP_CB cb,void * cb_data)150 void BtaGattQueue::ReadCharacteristic(uint16_t conn_id, uint16_t handle,
151                                       GATT_READ_OP_CB cb, void* cb_data) {
152   gatt_op_queue[conn_id].push_back({.type = GATT_READ_CHAR,
153                                     .handle = handle,
154                                     .read_cb = cb,
155                                     .read_cb_data = cb_data});
156   gatt_execute_next_op(conn_id);
157 }
158 
ReadDescriptor(uint16_t conn_id,uint16_t handle,GATT_READ_OP_CB cb,void * cb_data)159 void BtaGattQueue::ReadDescriptor(uint16_t conn_id, uint16_t handle,
160                                   GATT_READ_OP_CB cb, void* cb_data) {
161   gatt_op_queue[conn_id].push_back({.type = GATT_READ_DESC,
162                                     .handle = handle,
163                                     .read_cb = cb,
164                                     .read_cb_data = cb_data});
165   gatt_execute_next_op(conn_id);
166 }
167 
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)168 void BtaGattQueue::WriteCharacteristic(uint16_t conn_id, uint16_t handle,
169                                        std::vector<uint8_t> value,
170                                        tGATT_WRITE_TYPE write_type,
171                                        GATT_WRITE_OP_CB cb, void* cb_data) {
172   gatt_op_queue[conn_id].push_back({.type = GATT_WRITE_CHAR,
173                                     .handle = handle,
174                                     .write_cb = cb,
175                                     .write_cb_data = cb_data,
176                                     .write_type = write_type,
177                                     .value = std::move(value)});
178   gatt_execute_next_op(conn_id);
179 }
180 
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)181 void BtaGattQueue::WriteDescriptor(uint16_t conn_id, uint16_t handle,
182                                    std::vector<uint8_t> value,
183                                    tGATT_WRITE_TYPE write_type,
184                                    GATT_WRITE_OP_CB cb, void* cb_data) {
185   gatt_op_queue[conn_id].push_back({.type = GATT_WRITE_DESC,
186                                     .handle = handle,
187                                     .write_cb = cb,
188                                     .write_cb_data = cb_data,
189                                     .write_type = write_type,
190                                     .value = std::move(value)});
191   gatt_execute_next_op(conn_id);
192 }
193