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