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 "database_builder.h"
20 
21 #include "bt_trace.h"
22 
23 #include <base/logging.h>
24 #include <algorithm>
25 
26 using bluetooth::Uuid;
27 
28 namespace gatt {
29 
AddService(uint16_t handle,uint16_t end_handle,const Uuid & uuid,bool is_primary)30 void DatabaseBuilder::AddService(uint16_t handle, uint16_t end_handle,
31                                  const Uuid& uuid, bool is_primary) {
32   // general case optimization - we add services in order
33   if (database.services.empty() ||
34       database.services.back().end_handle < handle) {
35     database.services.emplace_back(Service{
36         .handle = handle,
37         .uuid = uuid,
38         .is_primary = is_primary,
39         .end_handle = end_handle,
40     });
41   } else {
42     auto& vec = database.services;
43 
44     // Find first service whose start handle is bigger than new service handle
45     auto it = std::lower_bound(
46         vec.begin(), vec.end(), handle,
47         [](Service s, uint16_t handle) { return s.end_handle < handle; });
48 
49     // Insert new service just before it
50     vec.emplace(it, Service{
51                         .handle = handle,
52                         .uuid = uuid,
53                         .is_primary = is_primary,
54                         .end_handle = end_handle,
55                     });
56   }
57 
58   services_to_discover.insert({handle, end_handle});
59 }
60 
AddIncludedService(uint16_t handle,const Uuid & uuid,uint16_t start_handle,uint16_t end_handle)61 void DatabaseBuilder::AddIncludedService(uint16_t handle, const Uuid& uuid,
62                                          uint16_t start_handle,
63                                          uint16_t end_handle) {
64   Service* service = FindService(database.services, handle);
65   if (!service) {
66     LOG(ERROR) << "Illegal action to add to non-existing service!";
67     return;
68   }
69 
70   /* We discover all Primary Services first. If included service was not seen
71    * before, it must be a Secondary Service */
72   if (!FindService(database.services, start_handle)) {
73     AddService(start_handle, end_handle, uuid, false /* not primary */);
74   }
75 
76   service->included_services.push_back(IncludedService{
77       .handle = handle,
78       .uuid = uuid,
79       .start_handle = start_handle,
80       .end_handle = end_handle,
81   });
82 }
83 
AddCharacteristic(uint16_t handle,uint16_t value_handle,const Uuid & uuid,uint8_t properties)84 void DatabaseBuilder::AddCharacteristic(uint16_t handle, uint16_t value_handle,
85                                         const Uuid& uuid, uint8_t properties) {
86   Service* service = FindService(database.services, handle);
87   if (!service) {
88     LOG(ERROR) << "Illegal action to add to non-existing service!";
89     return;
90   }
91 
92   if (service->end_handle < value_handle)
93     LOG(WARNING) << "Remote device violates spec: value_handle="
94                  << loghex(value_handle) << " is after service end_handle="
95                  << loghex(service->end_handle);
96 
97   service->characteristics.emplace_back(Characteristic{
98       .declaration_handle = handle,
99       .uuid = uuid,
100       .value_handle = value_handle,
101       .properties = properties,
102   });
103   return;
104 }
105 
AddDescriptor(uint16_t handle,const Uuid & uuid)106 void DatabaseBuilder::AddDescriptor(uint16_t handle, const Uuid& uuid) {
107   Service* service = FindService(database.services, handle);
108   if (!service) {
109     LOG(ERROR) << "Illegal action to add to non-existing service!";
110     return;
111   }
112 
113   if (service->characteristics.empty()) {
114     LOG(ERROR) << __func__
115                << ": Illegal action to add to non-existing characteristic!";
116     return;
117   }
118 
119   Characteristic* char_node = &service->characteristics.front();
120   for (auto it = service->characteristics.begin();
121        it != service->characteristics.end(); it++) {
122     if (it->declaration_handle > handle) break;
123     char_node = &(*it);
124   }
125 
126   char_node->descriptors.emplace_back(
127       gatt::Descriptor{.handle = handle, .uuid = uuid});
128 }
129 
StartNextServiceExploration()130 bool DatabaseBuilder::StartNextServiceExploration() {
131   while (!services_to_discover.empty()) {
132     auto handle_range = services_to_discover.begin();
133     pending_service = *handle_range;
134     services_to_discover.erase(handle_range);
135 
136     // Empty service declaration, nothing to explore, skip to next.
137     if (pending_service.first == pending_service.second) continue;
138 
139     pending_characteristic = HANDLE_MIN;
140     return true;
141   }
142   return false;
143 }
144 
145 const std::pair<uint16_t, uint16_t>&
CurrentlyExploredService()146 DatabaseBuilder::CurrentlyExploredService() {
147   return pending_service;
148 }
149 
NextDescriptorRangeToExplore()150 std::pair<uint16_t, uint16_t> DatabaseBuilder::NextDescriptorRangeToExplore() {
151   Service* service = FindService(database.services, pending_service.first);
152   if (!service || service->characteristics.empty()) {
153     return {HANDLE_MAX, HANDLE_MAX};
154   }
155 
156   for (auto it = service->characteristics.cbegin();
157        it != service->characteristics.cend(); it++) {
158     if (it->declaration_handle > pending_characteristic) {
159       auto next = std::next(it);
160 
161       /* Characteristic Declaration is followed by Characteristic Value
162        * Declaration, first descriptor is after that, see BT Spect 5.0 Vol 3,
163        * Part G 3.3.2 and 3.3.3 */
164       uint16_t start = it->declaration_handle + 2;
165       uint16_t end;
166       if (next != service->characteristics.end())
167         end = next->declaration_handle - 1;
168       else
169         end = service->end_handle;
170 
171       // No place for descriptor - skip to next characteristic
172       if (start > end) continue;
173 
174       pending_characteristic = start;
175       return {start, end};
176     }
177   }
178 
179   pending_characteristic = HANDLE_MAX;
180   return {HANDLE_MAX, HANDLE_MAX};
181 }
182 
InProgress() const183 bool DatabaseBuilder::InProgress() const { return !database.services.empty(); }
184 
Build()185 Database DatabaseBuilder::Build() {
186   Database tmp = database;
187   database.Clear();
188   return tmp;
189 }
190 
Clear()191 void DatabaseBuilder::Clear() { database.Clear(); }
192 
ToString() const193 std::string DatabaseBuilder::ToString() const { return database.ToString(); }
194 
195 }  // namespace gatt
196