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