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 using bluetooth::Uuid;
34
35 namespace gatt {
36
AddService(uint16_t handle,uint16_t end_handle,const Uuid & uuid,bool is_primary)37 void DatabaseBuilder::AddService(uint16_t handle, uint16_t end_handle,
38 const Uuid& uuid, bool is_primary) {
39 // general case optimization - we add services in order
40 if (database.services.empty() ||
41 database.services.back().end_handle < handle) {
42 database.services.emplace_back(Service{
43 .handle = handle,
44 .uuid = uuid,
45 .is_primary = is_primary,
46 .end_handle = end_handle,
47 });
48 } else {
49 auto& vec = database.services;
50
51 // Find first service whose start handle is bigger than new service handle
52 auto it = std::lower_bound(
53 vec.begin(), vec.end(), handle,
54 [](Service s, uint16_t handle) { return s.end_handle < handle; });
55
56 // Insert new service just before it
57 vec.emplace(it, Service{
58 .handle = handle,
59 .uuid = uuid,
60 .is_primary = is_primary,
61 .end_handle = end_handle,
62 });
63 }
64
65 services_to_discover.insert({handle, end_handle});
66 }
67
AddIncludedService(uint16_t handle,const Uuid & uuid,uint16_t start_handle,uint16_t end_handle)68 void DatabaseBuilder::AddIncludedService(uint16_t handle, const Uuid& uuid,
69 uint16_t start_handle,
70 uint16_t end_handle) {
71 Service* service = FindService(database.services, handle);
72 if (!service) {
73 LOG(ERROR) << "Illegal action to add to non-existing service!";
74 return;
75 }
76
77 /* We discover all Primary Services first. If included service was not seen
78 * before, it must be a Secondary Service */
79 if (!FindService(database.services, start_handle)) {
80 AddService(start_handle, end_handle, uuid, false /* not primary */);
81 }
82
83 service->included_services.push_back(IncludedService{
84 .handle = handle,
85 .uuid = uuid,
86 .start_handle = start_handle,
87 .end_handle = end_handle,
88 });
89 }
90
AddCharacteristic(uint16_t handle,uint16_t value_handle,const Uuid & uuid,uint8_t properties)91 void DatabaseBuilder::AddCharacteristic(uint16_t handle, uint16_t value_handle,
92 const Uuid& uuid, uint8_t properties) {
93 Service* service = FindService(database.services, handle);
94 if (!service) {
95 LOG(ERROR) << "Illegal action to add to non-existing service!";
96 return;
97 }
98
99 if (service->end_handle < value_handle)
100 LOG(WARNING) << "Remote device violates spec: value_handle="
101 << loghex(value_handle) << " is after service end_handle="
102 << loghex(service->end_handle);
103
104 service->characteristics.emplace_back(Characteristic{
105 .declaration_handle = handle,
106 .uuid = uuid,
107 .value_handle = value_handle,
108 .properties = properties,
109 });
110 return;
111 }
112
AddDescriptor(uint16_t handle,const Uuid & uuid)113 void DatabaseBuilder::AddDescriptor(uint16_t handle, const Uuid& uuid) {
114 Service* service = FindService(database.services, handle);
115 if (!service) {
116 LOG(ERROR) << "Illegal action to add to non-existing service!";
117 return;
118 }
119
120 if (service->characteristics.empty()) {
121 LOG(ERROR) << __func__
122 << ": 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();
128 it != service->characteristics.end(); it++) {
129 if (it->declaration_handle > handle) break;
130 char_node = &(*it);
131 }
132
133 char_node->descriptors.emplace_back(
134 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) continue;
150
151 pending_characteristic = HANDLE_MIN;
152 return true;
153 }
154 return false;
155 }
156
157 const std::pair<uint16_t, uint16_t>&
CurrentlyExploredService()158 DatabaseBuilder::CurrentlyExploredService() {
159 return pending_service;
160 }
161
NextDescriptorRangeToExplore()162 std::pair<uint16_t, uint16_t> DatabaseBuilder::NextDescriptorRangeToExplore() {
163 Service* service = FindService(database.services, pending_service.first);
164 if (!service || service->characteristics.empty()) {
165 return {HANDLE_MAX, HANDLE_MAX};
166 }
167
168 for (auto it = service->characteristics.cbegin();
169 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 // No place for descriptor - skip to next characteristic
184 if (start > end) continue;
185
186 pending_characteristic = start;
187 return {start, end};
188 }
189 }
190
191 pending_characteristic = HANDLE_MAX;
192 return {HANDLE_MAX, HANDLE_MAX};
193 }
194
FindDescriptorByHandle(std::list<Service> & services,uint16_t handle)195 Descriptor* FindDescriptorByHandle(std::list<Service>& services,
196 uint16_t handle) {
197 Service* service = FindService(services, handle);
198 if (!service) return nullptr;
199
200 Characteristic* char_node = &service->characteristics.front();
201 for (auto it = service->characteristics.begin();
202 it != service->characteristics.end(); it++) {
203 if (it->declaration_handle > handle) break;
204 char_node = &(*it);
205 }
206
207 for (auto& descriptor : char_node->descriptors) {
208 if (descriptor.handle == handle) return &descriptor;
209 }
210
211 return nullptr;
212 }
213
SetValueOfDescriptors(const std::vector<uint16_t> & values)214 bool DatabaseBuilder::SetValueOfDescriptors(
215 const std::vector<uint16_t>& values) {
216 if (values.size() > descriptor_handles_to_read.size()) {
217 LOG(ERROR) << "values.size() <= descriptors.size() expected";
218 descriptor_handles_to_read.clear();
219 return false;
220 }
221
222 for (size_t i = 0; i < values.size(); i++) {
223 Descriptor* d = FindDescriptorByHandle(database.services,
224 descriptor_handles_to_read[i]);
225 if (!d) {
226 LOG(ERROR) << __func__ << "non-existing descriptor!";
227 descriptor_handles_to_read.clear();
228 return false;
229 }
230
231 d->characteristic_extended_properties = values[i];
232 }
233
234 descriptor_handles_to_read.erase(
235 descriptor_handles_to_read.begin(),
236 descriptor_handles_to_read.begin() + values.size());
237 return true;
238 }
239
InProgress() const240 bool DatabaseBuilder::InProgress() const { return !database.services.empty(); }
241
Build()242 Database DatabaseBuilder::Build() {
243 Database tmp = database;
244 database.Clear();
245 return tmp;
246 }
247
Clear()248 void DatabaseBuilder::Clear() { database.Clear(); }
249
ToString() const250 std::string DatabaseBuilder::ToString() const { return database.ToString(); }
251
252 } // namespace gatt
253