OSDN Git Service

GATT: Use a list for services in a GATT database
[android-x86/system-bt.git] / bta / gatt / database.cc
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.h"
20 #include "bt_trace.h"
21 #include "stack/include/gattdefs.h"
22
23 #include <base/logging.h>
24 #include <list>
25 #include <memory>
26 #include <sstream>
27
28 using bluetooth::Uuid;
29
30 namespace gatt {
31
32 namespace {
33 const Uuid PRIMARY_SERVICE = Uuid::From16Bit(GATT_UUID_PRI_SERVICE);
34 const Uuid SECONDARY_SERVICE = Uuid::From16Bit(GATT_UUID_SEC_SERVICE);
35 const Uuid INCLUDE = Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE);
36 const Uuid CHARACTERISTIC = Uuid::From16Bit(GATT_UUID_CHAR_DECLARE);
37
38 bool HandleInRange(const Service& svc, uint16_t handle) {
39   return handle >= svc.handle && handle <= svc.end_handle;
40 }
41 }  // namespace
42
43 Service* FindService(std::list<Service>& services, uint16_t handle) {
44   for (Service& service : services) {
45     if (handle >= service.handle && handle <= service.end_handle)
46       return &service;
47   }
48
49   return nullptr;
50 }
51
52 std::string Database::ToString() const {
53   std::stringstream tmp;
54
55   for (const Service& service : services) {
56     tmp << "Service: handle=" << loghex(service.handle)
57         << ", end_handle=" << loghex(service.end_handle)
58         << ", uuid=" << service.uuid << "\n";
59
60     for (const auto& is : service.included_services) {
61       tmp << "\t Included service: handle=" << loghex(is.handle)
62           << ", start_handle=" << loghex(is.start_handle)
63           << ", end_handle=" << loghex(is.end_handle) << ", uuid=" << is.uuid
64           << "\n";
65     }
66
67     for (const Characteristic& c : service.characteristics) {
68       tmp << "\t Characteristic: declaration_handle="
69           << loghex(c.declaration_handle)
70           << ", value_handle=" << loghex(c.value_handle) << ", uuid=" << c.uuid
71           << ", prop=" << loghex(c.properties) << "\n";
72
73       for (const Descriptor& d : c.descriptors) {
74         tmp << "\t\t Descriptor: handle=" << loghex(d.handle)
75             << ", uuid=" << d.uuid << "\n";
76       }
77     }
78   }
79   return tmp.str();
80 }
81
82 std::vector<StoredAttribute> Database::Serialize() const {
83   std::vector<StoredAttribute> nv_attr;
84
85   if (services.empty()) return std::vector<StoredAttribute>();
86
87   for (const Service& service : services) {
88     // TODO: add constructor to NV_ATTR, use emplace_back
89     nv_attr.push_back({service.handle,
90                        service.is_primary ? PRIMARY_SERVICE : SECONDARY_SERVICE,
91                        {.service = {.uuid = service.uuid,
92                                     .end_handle = service.end_handle}}});
93   }
94
95   for (const Service& service : services) {
96     for (const IncludedService& p_isvc : service.included_services) {
97       nv_attr.push_back({p_isvc.handle,
98                          INCLUDE,
99                          {.included_service = {.handle = p_isvc.start_handle,
100                                                .end_handle = p_isvc.end_handle,
101                                                .uuid = p_isvc.uuid}}});
102     }
103
104     for (const Characteristic& charac : service.characteristics) {
105       nv_attr.push_back(
106           {charac.declaration_handle,
107            CHARACTERISTIC,
108            {.characteristic = {.properties = charac.properties,
109                                .value_handle = charac.value_handle,
110                                .uuid = charac.uuid}}});
111
112       for (const Descriptor& desc : charac.descriptors) {
113         nv_attr.push_back({desc.handle, desc.uuid, {}});
114       }
115     }
116   }
117
118   return nv_attr;
119 }
120
121 Database Database::Deserialize(const std::vector<StoredAttribute>& nv_attr,
122                                bool* success) {
123   // clear reallocating
124   Database result;
125   auto it = nv_attr.cbegin();
126
127   for (; it != nv_attr.cend(); ++it) {
128     const auto& attr = *it;
129     if (attr.type != PRIMARY_SERVICE && attr.type != SECONDARY_SERVICE) break;
130     result.services.emplace_back(
131         Service{.handle = attr.handle,
132                 .end_handle = attr.value.service.end_handle,
133                 .is_primary = (attr.type == PRIMARY_SERVICE),
134                 .uuid = attr.value.service.uuid});
135   }
136
137   auto current_service_it = result.services.begin();
138   for (; it != nv_attr.cend(); it++) {
139     const auto& attr = *it;
140
141     // go to the service this attribute belongs to; attributes are stored in
142     // order, so iterating just forward is enough
143     while (current_service_it != result.services.end() &&
144            current_service_it->end_handle < attr.handle) {
145       current_service_it++;
146     }
147
148     if (current_service_it == result.services.end() ||
149         !HandleInRange(*current_service_it, attr.handle)) {
150       LOG(ERROR) << "Can't find service for attribute with handle: "
151                  << loghex(attr.handle);
152       *success = false;
153       return result;
154     }
155
156     if (attr.type == INCLUDE) {
157       Service* included_service =
158           FindService(result.services, attr.value.included_service.handle);
159       if (!included_service) {
160         LOG(ERROR) << __func__ << ": Non-existing included service!";
161         *success = false;
162         return result;
163       }
164       current_service_it->included_services.push_back(IncludedService{
165           .handle = attr.handle,
166           .uuid = attr.value.included_service.uuid,
167           .start_handle = attr.value.included_service.handle,
168           .end_handle = attr.value.included_service.end_handle,
169       });
170     } else if (attr.type == CHARACTERISTIC) {
171       current_service_it->characteristics.emplace_back(
172           Characteristic{.declaration_handle = attr.handle,
173                          .value_handle = attr.value.characteristic.value_handle,
174                          .properties = attr.value.characteristic.properties,
175                          .uuid = attr.value.characteristic.uuid});
176
177     } else {
178       current_service_it->characteristics.back().descriptors.emplace_back(
179           Descriptor{.handle = attr.handle, .uuid = attr.type});
180     }
181   }
182   *success = true;
183   return result;
184 }
185
186 }  // namespace gatt