1 /******************************************************************************
2 *
3 * Copyright 2022 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 #define LOG_TAG "bt_bta_gattc"
20
21 #include <base/strings/string_number_conversions.h>
22 #include <bluetooth/log.h>
23 #include <dirent.h>
24 #include <sys/stat.h>
25
26 #include <string>
27 #include <vector>
28
29 #include "bta/gatt/bta_gattc_int.h"
30 #include "gatt/database.h"
31 #include "stack/include/gattdefs.h"
32 #include "types/bluetooth/uuid.h"
33
34 using namespace bluetooth;
35
36 using gatt::StoredAttribute;
37 using std::string;
38 using std::vector;
39
40 #ifdef TARGET_FLOSS
41 #define GATT_CACHE_PREFIX "/var/lib/bluetooth/gatt/gatt_cache_"
42 #define GATT_CACHE_VERSION 6
43
44 #define GATT_HASH_MAX_SIZE 30
45 #define GATT_HASH_PATH_PREFIX "/var/lib/bluetooth/gatt/gatt_hash_"
46 #define GATT_HASH_PATH "/var/lib/bluetooth/gatt"
47 #define GATT_HASH_FILE_PREFIX "gatt_hash_"
48 #else
49 #define GATT_CACHE_PREFIX "/data/misc/bluetooth/gatt_cache_"
50 #define GATT_CACHE_VERSION 6
51
52 #define GATT_HASH_MAX_SIZE 30
53 #define GATT_HASH_PATH_PREFIX "/data/misc/bluetooth/gatt_hash_"
54 #define GATT_HASH_PATH "/data/misc/bluetooth"
55 #define GATT_HASH_FILE_PREFIX "gatt_hash_"
56 #endif
57
58 // Default expired time is 7 days
59 #define GATT_HASH_EXPIRED_TIME 604800
60
61 static void bta_gattc_hash_remove_least_recently_used_if_possible();
62
bta_gattc_generate_cache_file_name(char * buffer,size_t buffer_len,const RawAddress & bda)63 static void bta_gattc_generate_cache_file_name(char* buffer, size_t buffer_len,
64 const RawAddress& bda) {
65 snprintf(buffer, buffer_len, "%s%02x%02x%02x%02x%02x%02x", GATT_CACHE_PREFIX, bda.address[0],
66 bda.address[1], bda.address[2], bda.address[3], bda.address[4], bda.address[5]);
67 }
68
bta_gattc_generate_hash_file_name(char * buffer,size_t buffer_len,const Octet16 & hash)69 static void bta_gattc_generate_hash_file_name(char* buffer, size_t buffer_len,
70 const Octet16& hash) {
71 snprintf(buffer, buffer_len, "%s%s", GATT_HASH_PATH_PREFIX,
72 base::HexEncode(hash.data(), 16).c_str());
73 }
74
75 static gatt::Database EMPTY_DB;
76
77 /*******************************************************************************
78 *
79 * Function bta_gattc_load_db
80 *
81 * Description Load GATT database from storage.
82 *
83 * Parameter fname: input file name
84 *
85 * Returns non-empty GATT database on success, empty GATT database
86 * otherwise
87 *
88 ******************************************************************************/
bta_gattc_load_db(const char * fname)89 static gatt::Database bta_gattc_load_db(const char* fname) {
90 FILE* fd = fopen(fname, "rb");
91 if (!fd) {
92 log::error("can't open GATT cache file {} for reading, error: {}", fname, strerror(errno));
93 return EMPTY_DB;
94 }
95
96 uint16_t cache_ver = 0;
97 uint16_t num_attr = 0;
98
99 if (fread(&cache_ver, sizeof(uint16_t), 1, fd) != 1) {
100 log::error("can't read GATT cache version from: {}", fname);
101 goto done;
102 }
103
104 if (cache_ver != GATT_CACHE_VERSION) {
105 log::error("wrong GATT cache version: {}", fname);
106 goto done;
107 }
108
109 if (fread(&num_attr, sizeof(uint16_t), 1, fd) != 1) {
110 log::error("can't read number of GATT attributes: {}", fname);
111 goto done;
112 }
113
114 {
115 std::vector<StoredAttribute> attr(num_attr);
116
117 if (fread(attr.data(), sizeof(StoredAttribute), num_attr, fd) != num_attr) {
118 log::error("can't read GATT attributes: {}", fname);
119 goto done;
120 }
121 fclose(fd);
122
123 bool success = false;
124 gatt::Database result = gatt::Database::Deserialize(attr, &success);
125 return success ? result : EMPTY_DB;
126 }
127
128 done:
129 fclose(fd);
130 return EMPTY_DB;
131 }
132
133 /*******************************************************************************
134 *
135 * Function bta_gattc_cache_load
136 *
137 * Description Load GATT cache from storage for server.
138 *
139 * Parameter bd_address: remote device address
140 *
141 * Returns non-empty GATT database on success, empty GATT database
142 * otherwise
143 *
144 ******************************************************************************/
bta_gattc_cache_load(const RawAddress & server_bda)145 gatt::Database bta_gattc_cache_load(const RawAddress& server_bda) {
146 char fname[255] = {0};
147 bta_gattc_generate_cache_file_name(fname, sizeof(fname), server_bda);
148 return bta_gattc_load_db(fname);
149 }
150
151 /*******************************************************************************
152 *
153 * Function bta_gattc_hash_load
154 *
155 * Description Load GATT cache from storage for server.
156 *
157 * Parameter hash: 16-byte value
158 *
159 * Returns non-empty GATT database on success, empty GATT database
160 * otherwise
161 *
162 ******************************************************************************/
bta_gattc_hash_load(const Octet16 & hash)163 gatt::Database bta_gattc_hash_load(const Octet16& hash) {
164 char fname[255] = {0};
165 bta_gattc_generate_hash_file_name(fname, sizeof(fname), hash);
166 return bta_gattc_load_db(fname);
167 }
168
SerializeStoredAttribute(const StoredAttribute & attr,std::vector<uint8_t> & bytes)169 void StoredAttribute::SerializeStoredAttribute(const StoredAttribute& attr,
170 std::vector<uint8_t>& bytes) {
171 size_t original_size = bytes.size();
172 // handle
173 bytes.push_back(attr.handle & 0xff);
174 bytes.push_back(attr.handle >> 8);
175 auto uuid = attr.type.To128BitBE();
176 bytes.insert(bytes.cend(), uuid.cbegin(), uuid.cend());
177
178 if (attr.type.Is16Bit()) {
179 switch (attr.type.As16Bit()) {
180 /* primary or secondary service definition */
181 case GATT_UUID_PRI_SERVICE:
182 case GATT_UUID_SEC_SERVICE:
183 uuid = attr.value.service.uuid.To128BitBE();
184 bytes.insert(bytes.cend(), uuid.cbegin(), uuid.cend());
185 bytes.push_back(attr.value.service.end_handle & 0xff);
186 bytes.push_back(attr.value.service.end_handle >> 8);
187 break;
188 case GATT_UUID_INCLUDE_SERVICE:
189 /* included service definition */
190 bytes.push_back(attr.value.included_service.handle & 0xff);
191 bytes.push_back(attr.value.included_service.handle >> 8);
192 bytes.push_back(attr.value.included_service.end_handle & 0xff);
193 bytes.push_back(attr.value.included_service.end_handle >> 8);
194 uuid = attr.value.included_service.uuid.To128BitBE();
195 bytes.insert(bytes.cend(), uuid.cbegin(), uuid.cend());
196 break;
197 case GATT_UUID_CHAR_DECLARE:
198 /* characteristic definition */
199 bytes.push_back(attr.value.characteristic.properties);
200 bytes.push_back(0); // Padding byte
201 bytes.push_back(attr.value.characteristic.value_handle & 0xff);
202 bytes.push_back(attr.value.characteristic.value_handle >> 8);
203 uuid = attr.value.characteristic.uuid.To128BitBE();
204 bytes.insert(bytes.cend(), uuid.cbegin(), uuid.cend());
205 break;
206 case GATT_UUID_CHAR_EXT_PROP:
207 /* for descriptor we store value only for
208 * «Characteristic Extended Properties» */
209 bytes.push_back(attr.value.characteristic_extended_properties & 0xff);
210 bytes.push_back(attr.value.characteristic_extended_properties >> 8);
211 break;
212 default:
213 // log::verbose("Unhandled type UUID 0x{:04x}", attr.type.As16Bit());
214 break;
215 }
216 }
217 // padding
218 for (size_t i = bytes.size() - original_size; i < StoredAttribute::kSizeOnDisk; i++) {
219 bytes.push_back(0);
220 }
221 }
222
223 /*******************************************************************************
224 *
225 * Function bta_gattc_store_db
226 *
227 * Description Storess GATT db.
228 *
229 * Parameter fname: output file name
230 * attr: attributes to save.
231 *
232 * Returns true on success, false otherwise
233 *
234 ******************************************************************************/
bta_gattc_store_db(const char * fname,const std::vector<StoredAttribute> & attr)235 static bool bta_gattc_store_db(const char* fname, const std::vector<StoredAttribute>& attr) {
236 FILE* fd = fopen(fname, "wb");
237 if (!fd) {
238 log::error("can't open GATT cache file for writing: {}", fname);
239 return false;
240 }
241
242 uint16_t cache_ver = GATT_CACHE_VERSION;
243 if (fwrite(&cache_ver, sizeof(uint16_t), 1, fd) != 1) {
244 log::error("can't write GATT cache version: {}", fname);
245 fclose(fd);
246 return false;
247 }
248
249 uint16_t num_attr = attr.size();
250 if (fwrite(&num_attr, sizeof(uint16_t), 1, fd) != 1) {
251 log::error("can't write GATT cache attribute count: {}", fname);
252 fclose(fd);
253 return false;
254 }
255
256 std::vector<uint8_t> db_bytes;
257 db_bytes.reserve(num_attr * StoredAttribute::kSizeOnDisk);
258 for (const auto attribute : attr) {
259 StoredAttribute::SerializeStoredAttribute(attribute, db_bytes);
260 }
261
262 if (fwrite(db_bytes.data(), sizeof(uint8_t), db_bytes.size(), fd) != db_bytes.size()) {
263 log::error("can't write GATT cache attributes: {}", fname);
264 fclose(fd);
265 return false;
266 }
267
268 fclose(fd);
269 return true;
270 }
271
272 /*******************************************************************************
273 *
274 * Function bta_gattc_cache_write
275 *
276 * Description This callout function is executed by GATT when a server
277 * cache is available to save. Before calling this API, make
278 * sure the device is bonded. Otherwise you might get lots of
279 * address caches for unbonded devices.
280 *
281 * Parameter server_bda: server bd address of this cache belongs to
282 * database: attributes to save.
283 * Returns
284 *
285 ******************************************************************************/
bta_gattc_cache_write(const RawAddress & server_bda,const gatt::Database & database)286 void bta_gattc_cache_write(const RawAddress& server_bda, const gatt::Database& database) {
287 char addr_file[255] = {0};
288 char hash_file[255] = {0};
289 Octet16 hash = database.Hash();
290 bta_gattc_generate_cache_file_name(addr_file, sizeof(addr_file), server_bda);
291 bta_gattc_generate_hash_file_name(hash_file, sizeof(hash_file), hash);
292
293 bool result = bta_gattc_hash_write(hash, database);
294 // Only link addr_file to hash file when hash_file is created successfully.
295 if (result) {
296 bta_gattc_cache_link(server_bda, hash);
297 }
298 }
299
300 /*******************************************************************************
301 *
302 * Function bta_gattc_cache_link
303 *
304 * Description Link address-database file to hash-database file
305 *
306 * Parameter server_bda: server bd address of this cache belongs to
307 * hash: 16-byte value
308 *
309 * Returns true on success, false otherwise
310 *
311 ******************************************************************************/
bta_gattc_cache_link(const RawAddress & server_bda,const Octet16 & hash)312 void bta_gattc_cache_link(const RawAddress& server_bda, const Octet16& hash) {
313 char addr_file[255] = {0};
314 char hash_file[255] = {0};
315 bta_gattc_generate_cache_file_name(addr_file, sizeof(addr_file), server_bda);
316 bta_gattc_generate_hash_file_name(hash_file, sizeof(hash_file), hash);
317
318 unlink(addr_file); // remove addr file first if the file exists
319 if (link(hash_file, addr_file) == -1) {
320 log::error("link {} to {}, errno={}", addr_file, hash_file, errno);
321 }
322 }
323
324 /*******************************************************************************
325 *
326 * Function bta_gattc_hash_write
327 *
328 * Description This callout function is executed by GATT when a server
329 * cache is available to save for specific hash.
330 *
331 * Parameter hash: 16-byte value
332 * database: gatt::Database instance.
333 *
334 * Returns true on success, false otherwise
335 *
336 ******************************************************************************/
bta_gattc_hash_write(const Octet16 & hash,const gatt::Database & database)337 bool bta_gattc_hash_write(const Octet16& hash, const gatt::Database& database) {
338 char fname[255] = {0};
339 bta_gattc_generate_hash_file_name(fname, sizeof(fname), hash);
340 bta_gattc_hash_remove_least_recently_used_if_possible();
341 return bta_gattc_store_db(fname, database.Serialize());
342 }
343
344 /*******************************************************************************
345 *
346 * Function bta_gattc_cache_reset
347 *
348 * Description This callout function is executed by GATTC to reset cache in
349 * application
350 *
351 * Parameter server_bda: server bd address of this cache belongs to
352 *
353 * Returns void.
354 *
355 ******************************************************************************/
bta_gattc_cache_reset(const RawAddress & server_bda)356 void bta_gattc_cache_reset(const RawAddress& server_bda) {
357 log::verbose("");
358 char fname[255] = {0};
359 bta_gattc_generate_cache_file_name(fname, sizeof(fname), server_bda);
360 unlink(fname);
361 }
362
363 /*******************************************************************************
364 *
365 * Function bta_gattc_hash_remove_least_recently_used_if_possible
366 *
367 * Description When the max size reaches, find the oldest item and remove
368 * it if possible
369 *
370 * Parameter
371 *
372 * Returns void
373 *
374 ******************************************************************************/
bta_gattc_hash_remove_least_recently_used_if_possible()375 static void bta_gattc_hash_remove_least_recently_used_if_possible() {
376 std::unique_ptr<DIR, decltype(&closedir)> dirp(opendir(GATT_HASH_PATH), &closedir);
377 if (dirp == nullptr) {
378 log::error("open dir error, dir={}", GATT_HASH_PATH);
379 return;
380 }
381
382 time_t current_time = time(NULL);
383 time_t lru_time = current_time;
384 size_t count = 0;
385 string candidate_item;
386 vector<string> expired_items;
387
388 log::debug("<-----------Start Local Hash Cache---------->");
389 dirent* dp;
390 while ((dp = readdir(dirp.get())) != nullptr) {
391 if (strncmp(".", dp->d_name, 1) == 0 || strncmp("..", dp->d_name, 2) == 0) {
392 continue;
393 }
394
395 // pattern match: gatt_hash_
396 size_t fname_len = strlen(dp->d_name);
397 size_t pattern_len = strlen(GATT_HASH_FILE_PREFIX);
398 if (pattern_len > fname_len) {
399 continue;
400 }
401
402 // check if the file name has gatt_hash_ as prefix
403 char tmp[255] = {0};
404 strncpy(tmp, dp->d_name, pattern_len);
405 if (strncmp(tmp, GATT_HASH_FILE_PREFIX, pattern_len) != 0) {
406 continue;
407 }
408
409 // increase hash file count
410 count++;
411
412 // generate the full path, in order to get the state of the file
413 snprintf(tmp, 255, "%s/%s", GATT_HASH_PATH, dp->d_name);
414
415 struct stat buf;
416 int result = lstat(tmp, &buf);
417 log::debug("name={}, result={}, linknum={}, mtime={}", dp->d_name, result, buf.st_nlink,
418 buf.st_mtime);
419
420 // if hard link count of the file is 1, it means no trusted device links to
421 // the inode. It is safe to be a candidate to be removed
422 if (buf.st_nlink == 1) {
423 if (buf.st_mtime < lru_time) {
424 lru_time = buf.st_mtime;
425 // Find the LRU candidate during for-loop itreation.
426 candidate_item.assign(tmp);
427 }
428
429 if (buf.st_mtime + GATT_HASH_EXPIRED_TIME < current_time) {
430 // Add expired item.
431 expired_items.emplace_back(tmp);
432 }
433 }
434 }
435 log::debug("<-----------End Local Hash Cache------------>");
436
437 // if the number of hash files exceeds the limit, remove the candidate item.
438 if (count > GATT_HASH_MAX_SIZE && !candidate_item.empty()) {
439 unlink(candidate_item.c_str());
440 log::debug("delete hash file (size), name={}", candidate_item);
441 }
442
443 // If there is any file expired, also delete it.
444 for (string expired_item : expired_items) {
445 unlink(expired_item.c_str());
446 log::debug("delete hash file (expired), name={}", expired_item);
447 }
448 }
449