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 
25 #include "bta_gatt_server_queue.h"
26 #include "os/log.h"
27 
28 using gatts_operation = BtaGattServerQueue::gatts_operation;
29 using bluetooth::Uuid;
30 using namespace bluetooth;
31 
32 constexpr uint8_t GATT_NOTIFY = 1;
33 
34 std::unordered_map<uint16_t, std::list<gatts_operation>>
35     BtaGattServerQueue::gatts_op_queue;
36 std::unordered_set<uint16_t> BtaGattServerQueue::gatts_op_queue_executing;
37 std::unordered_map<uint16_t, bool> BtaGattServerQueue::congestion_queue;
38 
mark_as_not_executing(uint16_t conn_id)39 void BtaGattServerQueue::mark_as_not_executing(uint16_t conn_id) {
40   gatts_op_queue_executing.erase(conn_id);
41 }
42 
gatts_execute_next_op(uint16_t conn_id)43 void BtaGattServerQueue::gatts_execute_next_op(uint16_t conn_id) {
44   log::verbose("conn_id=0x{:x}", conn_id);
45 
46   if (gatts_op_queue.empty()) {
47     log::verbose("op queue is empty");
48     return;
49   }
50 
51   auto ptr = congestion_queue.find(conn_id);
52 
53   if (ptr != congestion_queue.end()) {
54     bool is_congested = ptr->second;
55     log::verbose("congestion queue exist, conn_id: {}, is_congested: {}",
56                  conn_id, is_congested);
57     if (is_congested) {
58       log::verbose("lower layer is congested");
59       return;
60     }
61   }
62 
63   auto map_ptr = gatts_op_queue.find(conn_id);
64 
65   if (map_ptr == gatts_op_queue.end()) {
66     log::verbose("Queue is null");
67     return;
68   }
69 
70   if (map_ptr->second.empty()) {
71     log::verbose("queue is empty for conn_id: {}", conn_id);
72     return;
73   }
74 
75   if (gatts_op_queue_executing.count(conn_id)) {
76     log::verbose("can't enqueue next op, already executing");
77     return;
78   }
79 
80   gatts_operation op = map_ptr->second.front();
81   log::verbose("op.type={}, attr_id={}", op.type, op.attr_id);
82 
83   if (op.type == GATT_NOTIFY) {
84     BTA_GATTS_HandleValueIndication(conn_id, op.attr_id, op.value,
85                                     op.need_confirm);
86     gatts_op_queue_executing.insert(conn_id);
87   }
88 }
89 
Clean(uint16_t conn_id)90 void BtaGattServerQueue::Clean(uint16_t conn_id) {
91   log::verbose("conn_id=0x{:x}", conn_id);
92 
93   gatts_op_queue.erase(conn_id);
94   gatts_op_queue_executing.erase(conn_id);
95 }
96 
SendNotification(uint16_t conn_id,uint16_t handle,std::vector<uint8_t> value,bool need_confirm)97 void BtaGattServerQueue::SendNotification(uint16_t conn_id, uint16_t handle,
98                                           std::vector<uint8_t> value,
99                                           bool need_confirm) {
100   gatts_op_queue[conn_id].emplace_back(
101       gatts_operation{.type = GATT_NOTIFY,
102                       .attr_id = handle,
103                       .value = value,
104                       .need_confirm = need_confirm});
105   gatts_execute_next_op(conn_id);
106 }
107 
NotificationCallback(uint16_t conn_id)108 void BtaGattServerQueue::NotificationCallback(uint16_t conn_id) {
109   auto map_ptr = gatts_op_queue.find(conn_id);
110   if (map_ptr == gatts_op_queue.end() || map_ptr->second.empty()) {
111     log::verbose("no more operations queued for conn_id {}", conn_id);
112     return;
113   }
114 
115   gatts_operation op = map_ptr->second.front();
116   map_ptr->second.pop_front();
117   mark_as_not_executing(conn_id);
118   gatts_execute_next_op(conn_id);
119 }
120 
CongestionCallback(uint16_t conn_id,bool congested)121 void BtaGattServerQueue::CongestionCallback(uint16_t conn_id, bool congested) {
122   log::verbose("conn_id: {}, congested: {}", conn_id, congested);
123 
124   congestion_queue[conn_id] = congested;
125   if (!congested) {
126     gatts_execute_next_op(conn_id);
127   }
128 }
129