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,
42 const Uuid& uuid, bool is_primary) {
43 // general case optimization - we add services in order
44 if (database.services.empty() ||
45 database.services.back().end_handle < handle) {
46 database.services.emplace_back(Service{
47 .handle = handle,
48 .uuid = uuid,
49 .is_primary = is_primary,
50 .end_handle = end_handle,
51 });
52 } else {
53 auto& vec = database.services;
54
55 // Find first service whose start handle is bigger than new service handle
56 auto it = std::lower_bound(
57 vec.begin(), vec.end(), handle,
58 [](Service s, uint16_t handle) { return s.end_handle < handle; });
59
60 // Insert new service just before it
61 vec.emplace(it, Service{
62 .handle = handle,
63 .uuid = uuid,
64 .is_primary = is_primary,
65 .end_handle = end_handle,
66 });
67 }
68
69 services_to_discover.insert({handle, end_handle});
70 }
71
AddIncludedService(uint16_t handle,const Uuid & uuid,uint16_t start_handle,uint16_t end_handle)72 void DatabaseBuilder::AddIncludedService(uint16_t handle, const Uuid& uuid,
73 uint16_t start_handle,
74 uint16_t end_handle) {
75 Service* service = FindService(database.services, handle);
76 if (!service) {
77 log::error("Illegal action to add to non-existing service!");
78 return;
79 }
80
81 /* We discover all Primary Services first. If included service was not seen
82 * before, it must be a Secondary Service */
83 if (!FindService(database.services, start_handle)) {
84 AddService(start_handle, end_handle, uuid, false /* not primary */);
85 }
86
87 service->included_services.push_back(IncludedService{
88 .handle = handle,
89 .uuid = uuid,
90 .start_handle = start_handle,
91 .end_handle = end_handle,
92 });
93 }
94
AddCharacteristic(uint16_t handle,uint16_t value_handle,const Uuid & uuid,uint8_t properties)95 void DatabaseBuilder::AddCharacteristic(uint16_t handle, uint16_t value_handle,
96 const Uuid& uuid, uint8_t properties) {
97 Service* service = FindService(database.services, handle);
98 if (!service) {
99 log::error("Illegal action to add to non-existing service!");
100 return;
101 }
102
103 if (service->end_handle < value_handle)
104 log::warn(
105 "Remote device violates spec: value_handle=0x{:x} is after service "
106 "end_handle=0x{:x}",
107 value_handle, service->end_handle);
108
109 service->characteristics.emplace_back(Characteristic{
110 .declaration_handle = handle,
111 .uuid = uuid,
112 .value_handle = value_handle,
113 .properties = properties,
114 });
115 return;
116 }
117
AddDescriptor(uint16_t handle,const Uuid & uuid)118 void DatabaseBuilder::AddDescriptor(uint16_t handle, const Uuid& uuid) {
119 Service* service = FindService(database.services, handle);
120 if (!service) {
121 log::error("Illegal action to add to non-existing service!");
122 return;
123 }
124
125 if (service->characteristics.empty()) {
126 log::error("Illegal action to add to non-existing characteristic!");
127 return;
128 }
129
130 Characteristic* char_node = &service->characteristics.front();
131 for (auto it = service->characteristics.begin();
132 it != service->characteristics.end(); it++) {
133 if (it->declaration_handle > handle) break;
134 char_node = &(*it);
135 }
136
137 char_node->descriptors.emplace_back(
138 gatt::Descriptor{.handle = handle, .uuid = uuid});
139
140 // We must read value for Characteristic Extended Properties
141 if (uuid == Uuid::From16Bit(GATT_UUID_CHAR_EXT_PROP)) {
142 descriptor_handles_to_read.emplace_back(handle);
143 }
144 }
145
StartNextServiceExploration()146 bool DatabaseBuilder::StartNextServiceExploration() {
147 while (!services_to_discover.empty()) {
148 auto handle_range = services_to_discover.begin();
149 pending_service = *handle_range;
150 services_to_discover.erase(handle_range);
151
152 // Empty service declaration, nothing to explore, skip to next.
153 if (pending_service.first == pending_service.second) continue;
154
155 pending_characteristic = HANDLE_MIN;
156 return true;
157 }
158 return false;
159 }
160
161 const std::pair<uint16_t, uint16_t>&
CurrentlyExploredService()162 DatabaseBuilder::CurrentlyExploredService() {
163 return pending_service;
164 }
165
NextDescriptorRangeToExplore()166 std::pair<uint16_t, uint16_t> DatabaseBuilder::NextDescriptorRangeToExplore() {
167 Service* service = FindService(database.services, pending_service.first);
168 if (!service || service->characteristics.empty()) {
169 return {HANDLE_MAX, HANDLE_MAX};
170 }
171
172 for (auto it = service->characteristics.cbegin();
173 it != service->characteristics.cend(); it++) {
174 if (it->declaration_handle > pending_characteristic) {
175 auto next = std::next(it);
176
177 /* Characteristic Declaration is followed by Characteristic Value
178 * Declaration, first descriptor is after that, see BT Spect 5.0 Vol 3,
179 * Part G 3.3.2 and 3.3.3 */
180 uint16_t start = it->declaration_handle + 2;
181 uint16_t end;
182 if (next != service->characteristics.end())
183 end = next->declaration_handle - 1;
184 else
185 end = service->end_handle;
186
187 // No place for descriptor - skip to next characteristic
188 if (start > end) continue;
189
190 pending_characteristic = start;
191 return {start, end};
192 }
193 }
194
195 pending_characteristic = HANDLE_MAX;
196 return {HANDLE_MAX, HANDLE_MAX};
197 }
198
FindDescriptorByHandle(std::list<Service> & services,uint16_t handle)199 Descriptor* FindDescriptorByHandle(std::list<Service>& services,
200 uint16_t handle) {
201 Service* service = FindService(services, handle);
202 if (!service) return nullptr;
203
204 Characteristic* char_node = &service->characteristics.front();
205 for (auto it = service->characteristics.begin();
206 it != service->characteristics.end(); it++) {
207 if (it->declaration_handle > handle) break;
208 char_node = &(*it);
209 }
210
211 for (auto& descriptor : char_node->descriptors) {
212 if (descriptor.handle == handle) return &descriptor;
213 }
214
215 return nullptr;
216 }
217
SetValueOfDescriptors(const std::vector<uint16_t> & values)218 bool DatabaseBuilder::SetValueOfDescriptors(
219 const std::vector<uint16_t>& values) {
220 if (values.size() > descriptor_handles_to_read.size()) {
221 log::error("values.size() <= descriptors.size() expected");
222 descriptor_handles_to_read.clear();
223 return false;
224 }
225
226 for (size_t i = 0; i < values.size(); i++) {
227 Descriptor* d = FindDescriptorByHandle(database.services,
228 descriptor_handles_to_read[i]);
229 if (!d) {
230 log::error("non-existing descriptor!");
231 descriptor_handles_to_read.clear();
232 return false;
233 }
234
235 d->characteristic_extended_properties = values[i];
236 }
237
238 descriptor_handles_to_read.erase(
239 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