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 // TODO(b/369381361) Enfore -Wmissing-prototypes
37 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
38 
39 using bluetooth::Uuid;
40 using namespace bluetooth;
41 
42 namespace gatt {
43 
AddService(uint16_t handle,uint16_t end_handle,const Uuid & uuid,bool is_primary)44 void DatabaseBuilder::AddService(uint16_t handle, uint16_t end_handle, const Uuid& uuid,
45                                  bool is_primary) {
46   // general case optimization - we add services in order
47   if (database.services.empty() || database.services.back().end_handle < handle) {
48     database.services.emplace_back(Service{
49             .handle = handle,
50             .uuid = uuid,
51             .is_primary = is_primary,
52             .end_handle = end_handle,
53     });
54   } else {
55     auto& vec = database.services;
56 
57     // Find first service whose start handle is bigger than new service handle
58     auto it = std::lower_bound(vec.begin(), vec.end(), handle,
59                                [](Service s, uint16_t handle) { return s.end_handle < handle; });
60 
61     // Insert new service just before it
62     vec.emplace(it, Service{
63                             .handle = handle,
64                             .uuid = uuid,
65                             .is_primary = is_primary,
66                             .end_handle = end_handle,
67                     });
68   }
69 
70   services_to_discover.insert({handle, end_handle});
71 }
72 
AddIncludedService(uint16_t handle,const Uuid & uuid,uint16_t start_handle,uint16_t end_handle)73 void DatabaseBuilder::AddIncludedService(uint16_t handle, const Uuid& uuid, 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, const Uuid& uuid,
96                                         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("Remote device violates spec: value_handle=0x{:x} is after service end_handle=0x{:x}",
105               value_handle, service->end_handle);
106   }
107 
108   service->characteristics.emplace_back(Characteristic{
109           .declaration_handle = handle,
110           .uuid = uuid,
111           .value_handle = value_handle,
112           .properties = properties,
113   });
114   return;
115 }
116 
AddDescriptor(uint16_t handle,const Uuid & uuid)117 void DatabaseBuilder::AddDescriptor(uint16_t handle, const Uuid& uuid) {
118   Service* service = FindService(database.services, handle);
119   if (!service) {
120     log::error("Illegal action to add to non-existing service!");
121     return;
122   }
123 
124   if (service->characteristics.empty()) {
125     log::error("Illegal action to add to non-existing characteristic!");
126     return;
127   }
128 
129   Characteristic* char_node = &service->characteristics.front();
130   for (auto it = service->characteristics.begin(); it != service->characteristics.end(); it++) {
131     if (it->declaration_handle > handle) {
132       break;
133     }
134     char_node = &(*it);
135   }
136 
137   char_node->descriptors.emplace_back(gatt::Descriptor{.handle = handle, .uuid = uuid});
138 
139   // We must read value for Characteristic Extended Properties
140   if (uuid == Uuid::From16Bit(GATT_UUID_CHAR_EXT_PROP)) {
141     descriptor_handles_to_read.emplace_back(handle);
142   }
143 }
144 
StartNextServiceExploration()145 bool DatabaseBuilder::StartNextServiceExploration() {
146   while (!services_to_discover.empty()) {
147     auto handle_range = services_to_discover.begin();
148     pending_service = *handle_range;
149     services_to_discover.erase(handle_range);
150 
151     // Empty service declaration, nothing to explore, skip to next.
152     if (pending_service.first == pending_service.second) {
153       continue;
154     }
155 
156     pending_characteristic = HANDLE_MIN;
157     return true;
158   }
159   return false;
160 }
161 
CurrentlyExploredService()162 const std::pair<uint16_t, uint16_t>& 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(); it != service->characteristics.cend(); it++) {
173     if (it->declaration_handle > pending_characteristic) {
174       auto next = std::next(it);
175 
176       /* Characteristic Declaration is followed by Characteristic Value
177        * Declaration, first descriptor is after that, see BT Spect 5.0 Vol 3,
178        * Part G 3.3.2 and 3.3.3 */
179       uint16_t start = it->declaration_handle + 2;
180       uint16_t end;
181       if (next != service->characteristics.end()) {
182         end = next->declaration_handle - 1;
183       } else {
184         end = service->end_handle;
185       }
186 
187       // No place for descriptor - skip to next characteristic
188       if (start > end) {
189         continue;
190       }
191 
192       pending_characteristic = start;
193       return {start, end};
194     }
195   }
196 
197   pending_characteristic = HANDLE_MAX;
198   return {HANDLE_MAX, HANDLE_MAX};
199 }
200 
FindDescriptorByHandle(std::list<Service> & services,uint16_t handle)201 Descriptor* FindDescriptorByHandle(std::list<Service>& services, uint16_t handle) {
202   Service* service = FindService(services, handle);
203   if (!service) {
204     return nullptr;
205   }
206 
207   Characteristic* char_node = &service->characteristics.front();
208   for (auto it = service->characteristics.begin(); it != service->characteristics.end(); it++) {
209     if (it->declaration_handle > handle) {
210       break;
211     }
212     char_node = &(*it);
213   }
214 
215   for (auto& descriptor : char_node->descriptors) {
216     if (descriptor.handle == handle) {
217       return &descriptor;
218     }
219   }
220 
221   return nullptr;
222 }
223 
SetValueOfDescriptors(const std::vector<uint16_t> & values)224 bool DatabaseBuilder::SetValueOfDescriptors(const std::vector<uint16_t>& values) {
225   if (values.size() > descriptor_handles_to_read.size()) {
226     log::error("values.size() <= descriptors.size() expected");
227     descriptor_handles_to_read.clear();
228     return false;
229   }
230 
231   for (size_t i = 0; i < values.size(); i++) {
232     Descriptor* d = FindDescriptorByHandle(database.services, descriptor_handles_to_read[i]);
233     if (!d) {
234       log::error("non-existing descriptor!");
235       descriptor_handles_to_read.clear();
236       return false;
237     }
238 
239     d->characteristic_extended_properties = values[i];
240   }
241 
242   descriptor_handles_to_read.erase(descriptor_handles_to_read.begin(),
243                                    descriptor_handles_to_read.begin() + values.size());
244   return true;
245 }
246 
InProgress() const247 bool DatabaseBuilder::InProgress() const { return !database.services.empty(); }
248 
Build()249 Database DatabaseBuilder::Build() {
250   Database tmp = database;
251   database.Clear();
252   return tmp;
253 }
254 
Clear()255 void DatabaseBuilder::Clear() { database.Clear(); }
256 
ToString() const257 std::string DatabaseBuilder::ToString() const { return database.ToString(); }
258 
259 }  // namespace gatt
260