1 /******************************************************************************
2 *
3 * Copyright 2018 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #include "bta/gatt/database_builder.h"
20
21 #include <bluetooth/log.h>
22
23 #include <algorithm>
24 #include <cstdint>
25 #include <list>
26 #include <string>
27 #include <utility>
28 #include <vector>
29
30 #include "bta/gatt/database.h"
31 #include "internal_include/bt_target.h"
32 #include "internal_include/bt_trace.h"
33 #include "stack/include/gattdefs.h"
34 #include "types/bluetooth/uuid.h"
35
36 using bluetooth::Uuid;
37 using namespace bluetooth;
38
39 namespace gatt {
40
AddService(uint16_t handle,uint16_t end_handle,const Uuid & uuid,bool is_primary)41 void DatabaseBuilder::AddService(uint16_t handle, uint16_t end_handle, const Uuid& uuid,
42 bool is_primary) {
43 // general case optimization - we add services in order
44 if (database.services.empty() || database.services.back().end_handle < handle) {
45 database.services.emplace_back(Service{
46 .handle = handle,
47 .uuid = uuid,
48 .is_primary = is_primary,
49 .end_handle = end_handle,
50 });
51 } else {
52 auto& vec = database.services;
53
54 // Find first service whose start handle is bigger than new service handle
55 auto it = std::lower_bound(vec.begin(), vec.end(), handle,
56 [](Service s, uint16_t handle) { return s.end_handle < handle; });
57
58 // Insert new service just before it
59 vec.emplace(it, Service{
60 .handle = handle,
61 .uuid = uuid,
62 .is_primary = is_primary,
63 .end_handle = end_handle,
64 });
65 }
66
67 services_to_discover.insert({handle, end_handle});
68 }
69
AddIncludedService(uint16_t handle,const Uuid & uuid,uint16_t start_handle,uint16_t end_handle)70 void DatabaseBuilder::AddIncludedService(uint16_t handle, const Uuid& uuid, uint16_t start_handle,
71 uint16_t end_handle) {
72 Service* service = FindService(database.services, handle);
73 if (!service) {
74 log::error("Illegal action to add to non-existing service!");
75 return;
76 }
77
78 /* We discover all Primary Services first. If included service was not seen
79 * before, it must be a Secondary Service */
80 if (!FindService(database.services, start_handle)) {
81 AddService(start_handle, end_handle, uuid, false /* not primary */);
82 }
83
84 service->included_services.push_back(IncludedService{
85 .handle = handle,
86 .uuid = uuid,
87 .start_handle = start_handle,
88 .end_handle = end_handle,
89 });
90 }
91
AddCharacteristic(uint16_t handle,uint16_t value_handle,const Uuid & uuid,uint8_t properties)92 void DatabaseBuilder::AddCharacteristic(uint16_t handle, uint16_t value_handle, const Uuid& uuid,
93 uint8_t properties) {
94 Service* service = FindService(database.services, handle);
95 if (!service) {
96 log::error("Illegal action to add to non-existing service!");
97 return;
98 }
99
100 if (service->end_handle < value_handle) {
101 log::warn("Remote device violates spec: value_handle=0x{:x} is after service end_handle=0x{:x}",
102 value_handle, service->end_handle);
103 }
104
105 service->characteristics.emplace_back(Characteristic{
106 .declaration_handle = handle,
107 .uuid = uuid,
108 .value_handle = value_handle,
109 .properties = properties,
110 });
111 return;
112 }
113
AddDescriptor(uint16_t handle,const Uuid & uuid)114 void DatabaseBuilder::AddDescriptor(uint16_t handle, const Uuid& uuid) {
115 Service* service = FindService(database.services, handle);
116 if (!service) {
117 log::error("Illegal action to add to non-existing service!");
118 return;
119 }
120
121 if (service->characteristics.empty()) {
122 log::error("Illegal action to add to non-existing characteristic!");
123 return;
124 }
125
126 Characteristic* char_node = &service->characteristics.front();
127 for (auto it = service->characteristics.begin(); it != service->characteristics.end(); it++) {
128 if (it->declaration_handle > handle) {
129 break;
130 }
131 char_node = &(*it);
132 }
133
134 char_node->descriptors.emplace_back(gatt::Descriptor{.handle = handle, .uuid = uuid});
135
136 // We must read value for Characteristic Extended Properties
137 if (uuid == Uuid::From16Bit(GATT_UUID_CHAR_EXT_PROP)) {
138 descriptor_handles_to_read.emplace_back(handle);
139 }
140 }
141
StartNextServiceExploration()142 bool DatabaseBuilder::StartNextServiceExploration() {
143 while (!services_to_discover.empty()) {
144 auto handle_range = services_to_discover.begin();
145 pending_service = *handle_range;
146 services_to_discover.erase(handle_range);
147
148 // Empty service declaration, nothing to explore, skip to next.
149 if (pending_service.first == pending_service.second) {
150 continue;
151 }
152
153 pending_characteristic = HANDLE_MIN;
154 return true;
155 }
156 return false;
157 }
158
CurrentlyExploredService()159 const std::pair<uint16_t, uint16_t>& DatabaseBuilder::CurrentlyExploredService() {
160 return pending_service;
161 }
162
NextDescriptorRangeToExplore()163 std::pair<uint16_t, uint16_t> DatabaseBuilder::NextDescriptorRangeToExplore() {
164 Service* service = FindService(database.services, pending_service.first);
165 if (!service || service->characteristics.empty()) {
166 return {HANDLE_MAX, HANDLE_MAX};
167 }
168
169 for (auto it = service->characteristics.cbegin(); it != service->characteristics.cend(); it++) {
170 if (it->declaration_handle > pending_characteristic) {
171 auto next = std::next(it);
172
173 /* Characteristic Declaration is followed by Characteristic Value
174 * Declaration, first descriptor is after that, see BT Spect 5.0 Vol 3,
175 * Part G 3.3.2 and 3.3.3 */
176 uint16_t start = it->declaration_handle + 2;
177 uint16_t end;
178 if (next != service->characteristics.end()) {
179 end = next->declaration_handle - 1;
180 } else {
181 end = service->end_handle;
182 }
183
184 // No place for descriptor - skip to next characteristic
185 if (start > end) {
186 continue;
187 }
188
189 pending_characteristic = start;
190 return {start, end};
191 }
192 }
193
194 pending_characteristic = HANDLE_MAX;
195 return {HANDLE_MAX, HANDLE_MAX};
196 }
197
FindDescriptorByHandle(std::list<Service> & services,uint16_t handle)198 static Descriptor* FindDescriptorByHandle(std::list<Service>& services, uint16_t handle) {
199 Service* service = FindService(services, handle);
200 if (!service) {
201 return nullptr;
202 }
203
204 Characteristic* char_node = &service->characteristics.front();
205 for (auto it = service->characteristics.begin(); it != service->characteristics.end(); it++) {
206 if (it->declaration_handle > handle) {
207 break;
208 }
209 char_node = &(*it);
210 }
211
212 for (auto& descriptor : char_node->descriptors) {
213 if (descriptor.handle == handle) {
214 return &descriptor;
215 }
216 }
217
218 return nullptr;
219 }
220
SetValueOfDescriptors(const std::vector<uint16_t> & values)221 bool DatabaseBuilder::SetValueOfDescriptors(const std::vector<uint16_t>& values) {
222 if (values.size() > descriptor_handles_to_read.size()) {
223 log::error("values.size() <= descriptors.size() expected");
224 descriptor_handles_to_read.clear();
225 return false;
226 }
227
228 for (size_t i = 0; i < values.size(); i++) {
229 Descriptor* d = FindDescriptorByHandle(database.services, descriptor_handles_to_read[i]);
230 if (!d) {
231 log::error("non-existing descriptor!");
232 descriptor_handles_to_read.clear();
233 return false;
234 }
235
236 d->characteristic_extended_properties = values[i];
237 }
238
239 descriptor_handles_to_read.erase(descriptor_handles_to_read.begin(),
240 descriptor_handles_to_read.begin() + values.size());
241 return true;
242 }
243
InProgress() const244 bool DatabaseBuilder::InProgress() const { return !database.services.empty(); }
245
Build()246 Database DatabaseBuilder::Build() {
247 Database tmp = database;
248 database.Clear();
249 return tmp;
250 }
251
Clear()252 void DatabaseBuilder::Clear() { database.Clear(); }
253
ToString() const254 std::string DatabaseBuilder::ToString() const { return database.ToString(); }
255
256 } // namespace gatt
257