• 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 <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