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