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