• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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