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 <algorithm>
20 #include <cstdint>
21 #include <list>
22 #include <string>
23 #include <utility>
24 #include <vector>
25
26 #include "bt_target.h" // Must be first to define build configuration
27
28 #include "bta/gatt/database.h"
29 #include "bta/gatt/database_builder.h"
30 #include "stack/include/gattdefs.h"
31 #include "types/bluetooth/uuid.h"
32
33 #include <base/logging.h>
34
35 using bluetooth::Uuid;
36
37 namespace gatt {
38
AddService(uint16_t handle,uint16_t end_handle,const Uuid & uuid,bool is_primary)39 void DatabaseBuilder::AddService(uint16_t handle, uint16_t end_handle,
40 const Uuid& uuid, bool is_primary) {
41 // general case optimization - we add services in order
42 if (database.services.empty() ||
43 database.services.back().end_handle < handle) {
44 database.services.emplace_back(Service{
45 .handle = handle,
46 .uuid = uuid,
47 .is_primary = is_primary,
48 .end_handle = end_handle,
49 });
50 } else {
51 auto& vec = database.services;
52
53 // Find first service whose start handle is bigger than new service handle
54 auto it = std::lower_bound(
55 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,
71 uint16_t start_handle,
72 uint16_t end_handle) {
73 Service* service = FindService(database.services, handle);
74 if (!service) {
75 LOG(ERROR) << "Illegal action to add to non-existing service!";
76 return;
77 }
78
79 /* We discover all Primary Services first. If included service was not seen
80 * before, it must be a Secondary Service */
81 if (!FindService(database.services, start_handle)) {
82 AddService(start_handle, end_handle, uuid, false /* not primary */);
83 }
84
85 service->included_services.push_back(IncludedService{
86 .handle = handle,
87 .uuid = uuid,
88 .start_handle = start_handle,
89 .end_handle = end_handle,
90 });
91 }
92
AddCharacteristic(uint16_t handle,uint16_t value_handle,const Uuid & uuid,uint8_t properties)93 void DatabaseBuilder::AddCharacteristic(uint16_t handle, uint16_t value_handle,
94 const Uuid& uuid, uint8_t properties) {
95 Service* service = FindService(database.services, handle);
96 if (!service) {
97 LOG(ERROR) << "Illegal action to add to non-existing service!";
98 return;
99 }
100
101 if (service->end_handle < value_handle)
102 LOG(WARNING) << "Remote device violates spec: value_handle="
103 << loghex(value_handle) << " is after service end_handle="
104 << loghex(service->end_handle);
105
106 service->characteristics.emplace_back(Characteristic{
107 .declaration_handle = handle,
108 .uuid = uuid,
109 .value_handle = value_handle,
110 .properties = properties,
111 });
112 return;
113 }
114
AddDescriptor(uint16_t handle,const Uuid & uuid)115 void DatabaseBuilder::AddDescriptor(uint16_t handle, const Uuid& uuid) {
116 Service* service = FindService(database.services, handle);
117 if (!service) {
118 LOG(ERROR) << "Illegal action to add to non-existing service!";
119 return;
120 }
121
122 if (service->characteristics.empty()) {
123 LOG(ERROR) << __func__
124 << ": Illegal action to add to non-existing characteristic!";
125 return;
126 }
127
128 Characteristic* char_node = &service->characteristics.front();
129 for (auto it = service->characteristics.begin();
130 it != service->characteristics.end(); it++) {
131 if (it->declaration_handle > handle) break;
132 char_node = &(*it);
133 }
134
135 char_node->descriptors.emplace_back(
136 gatt::Descriptor{.handle = handle, .uuid = uuid});
137
138 // We must read value for Characteristic Extended Properties
139 if (uuid == Uuid::From16Bit(GATT_UUID_CHAR_EXT_PROP)) {
140 descriptor_handles_to_read.emplace_back(handle);
141 }
142 }
143
StartNextServiceExploration()144 bool DatabaseBuilder::StartNextServiceExploration() {
145 while (!services_to_discover.empty()) {
146 auto handle_range = services_to_discover.begin();
147 pending_service = *handle_range;
148 services_to_discover.erase(handle_range);
149
150 // Empty service declaration, nothing to explore, skip to next.
151 if (pending_service.first == pending_service.second) continue;
152
153 pending_characteristic = HANDLE_MIN;
154 return true;
155 }
156 return false;
157 }
158
159 const std::pair<uint16_t, uint16_t>&
CurrentlyExploredService()160 DatabaseBuilder::CurrentlyExploredService() {
161 return pending_service;
162 }
163
NextDescriptorRangeToExplore()164 std::pair<uint16_t, uint16_t> DatabaseBuilder::NextDescriptorRangeToExplore() {
165 Service* service = FindService(database.services, pending_service.first);
166 if (!service || service->characteristics.empty()) {
167 return {HANDLE_MAX, HANDLE_MAX};
168 }
169
170 for (auto it = service->characteristics.cbegin();
171 it != service->characteristics.cend(); it++) {
172 if (it->declaration_handle > pending_characteristic) {
173 auto next = std::next(it);
174
175 /* Characteristic Declaration is followed by Characteristic Value
176 * Declaration, first descriptor is after that, see BT Spect 5.0 Vol 3,
177 * Part G 3.3.2 and 3.3.3 */
178 uint16_t start = it->declaration_handle + 2;
179 uint16_t end;
180 if (next != service->characteristics.end())
181 end = next->declaration_handle - 1;
182 else
183 end = service->end_handle;
184
185 // No place for descriptor - skip to next characteristic
186 if (start > end) continue;
187
188 pending_characteristic = start;
189 return {start, end};
190 }
191 }
192
193 pending_characteristic = HANDLE_MAX;
194 return {HANDLE_MAX, HANDLE_MAX};
195 }
196
FindDescriptorByHandle(std::list<Service> & services,uint16_t handle)197 Descriptor* FindDescriptorByHandle(std::list<Service>& services,
198 uint16_t handle) {
199 Service* service = FindService(services, handle);
200 if (!service) return nullptr;
201
202 Characteristic* char_node = &service->characteristics.front();
203 for (auto it = service->characteristics.begin();
204 it != service->characteristics.end(); it++) {
205 if (it->declaration_handle > handle) break;
206 char_node = &(*it);
207 }
208
209 for (auto& descriptor : char_node->descriptors) {
210 if (descriptor.handle == handle) return &descriptor;
211 }
212
213 return nullptr;
214 }
215
SetValueOfDescriptors(const std::vector<uint16_t> & values)216 bool DatabaseBuilder::SetValueOfDescriptors(
217 const std::vector<uint16_t>& values) {
218 if (values.size() > descriptor_handles_to_read.size()) {
219 LOG(ERROR) << "values.size() <= descriptors.size() expected";
220 descriptor_handles_to_read.clear();
221 return false;
222 }
223
224 for (size_t i = 0; i < values.size(); i++) {
225 Descriptor* d = FindDescriptorByHandle(database.services,
226 descriptor_handles_to_read[i]);
227 if (!d) {
228 LOG(ERROR) << __func__ << "non-existing descriptor!";
229 descriptor_handles_to_read.clear();
230 return false;
231 }
232
233 d->characteristic_extended_properties = values[i];
234 }
235
236 descriptor_handles_to_read.erase(
237 descriptor_handles_to_read.begin(),
238 descriptor_handles_to_read.begin() + values.size());
239 return true;
240 }
241
InProgress() const242 bool DatabaseBuilder::InProgress() const { return !database.services.empty(); }
243
Build()244 Database DatabaseBuilder::Build() {
245 Database tmp = database;
246 database.Clear();
247 return tmp;
248 }
249
Clear()250 void DatabaseBuilder::Clear() { database.Clear(); }
251
ToString() const252 std::string DatabaseBuilder::ToString() const { return database.ToString(); }
253
254 } // namespace gatt
255