Skip to content

Commit

Permalink
OS-Upgrade: Add a BT storage transformation tool.
Browse files Browse the repository at this point in the history
bug: v/47945

Rootcause: Due to the differences in the storage format of Bluetooth information in different system versions, in order to ensure that saved information can continue to be used after system upgrades, the storage transformation tool has been added.

Signed-off-by: chejinxian1 <[email protected]>
  • Loading branch information
chejinxian authored and hyson710 committed Jan 3, 2025
1 parent dbde6f0 commit a08d305
Show file tree
Hide file tree
Showing 4 changed files with 371 additions and 0 deletions.
18 changes: 18 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,24 @@ if(CONFIG_BLUETOOTH)
libbluetooth)
endif()

if(CONFIG_BLUETOOTH_UPGRADE)
nuttx_add_application(
NAME
bt_upgrade
SRCS
${BLUETOOTH_DIR}/tools/storage_transform.c
INCLUDE_DIRECTORIES
${INCDIR}
STACKSIZE
8192
PRIORITY
${SCHED_PRIORITY_DEFAULT}
COMPILE_FLAGS
${CFLAGS}
DEPENDS
libbluetooth)
endif()

if(CONFIG_BLUETOOTH_FEATURE)
include(nuttx_add_jidl)
set(PY_SCRIPT ${FEATURE_TOP}/tools/jidl/jsongensource.py)
Expand Down
6 changes: 6 additions & 0 deletions Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -658,4 +658,10 @@ config BLUETOOTH_LEAUDIO_CLIENT_METADATA_MAX_NUMBER

endif # BLUETOOTH_LEAUDIO_CLIENT

config BLUETOOTH_UPGRADE
bool "Enable Bluetooth storage transformation tool for upgrading OS"
default n
depends on KVDB
depends on UNQLITE

endif #BLUETOOTH
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,11 @@ ifeq ($(CONFIG_BLUETOOTH_TOOLS), y)
PROGNAME += adapter_test
MAINSRC += tests/adapter_test.c
endif

ifeq ($(CONFIG_BLUETOOTH_UPGRADE), y)
PROGNAME += bt_upgrade
MAINSRC += tools/storage_transform.c
endif
endif

ASRCS := $(wildcard $(ASRCS))
Expand Down
342 changes: 342 additions & 0 deletions tools/storage_transform.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
/****************************************************************************
* Copyright (C) 2024 Xiaomi Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#include <inttypes.h>
#include <kvdb.h>

#include "bluetooth_define.h"
#include "storage.h"
#include "syslog.h"
#include "uv_ext.h"

#define BLUETOOTH_V35_UPGRDE_TAG "persist.bluetooth.v35.upgraded"
#define BT_STORAGE_FILE_PATH "/data/misc/bt/bt_storage.db"

// Defined macro in rel-3.5
#define BT_DEVICE_NAME_MAX_LEN 63 // 63 used in rel-3.5
#define SMP_KEYS_MAX_SIZE 80
#define UUID_SIZE 16
#define BD_ADDR_SIZE 6

#define BT_CONFIG_FILE_PATH "/data/misc/bt/bt_config.db"
#define BT_KEY_DEVICE_INFO "key_deviceinfo"
#define BT_KEY_BTBOND "key_btbond"
#define BT_KEY_BLEBOND "key_blebond"
#define BT_KEY_BLEWHITELIST "key_blewhitelist"

// Type dependency for rel-3.5
typedef uint8_t BT_UUID_T[UUID_SIZE];
typedef uint8_t BD_ADDR[BD_ADDR_SIZE];

typedef enum {
STORAGE_TYPE_BT,
STORAGE_TYPE_BLE,
} storage_type;

typedef struct {
BD_ADDR bd_addr;
uint8_t addr_type;
} SERVICE_REMOTE_BLE_DEVICE_S;

typedef struct
{
uint8_t bd[6];
uint8_t atype;
uint8_t cap;
uint8_t ltk_len;
uint8_t div[2];
uint8_t ltk[16];
uint8_t ediv[2];
uint8_t rand[8];
uint8_t irk[16];
uint8_t csrk[16];
} smp_keys_parsing_t;

// Storage format in rel-3.5

typedef struct {
uint32_t size;
uint32_t check_sum;
uint8_t spk_volume;
uint8_t mic_volume;
uint16_t bonded_number;
storage_type type;
void* bonded_devices;
} bt_storage_t;

typedef struct gap_ble_whitelist_data {
uint32_t size;
uint32_t num;
SERVICE_REMOTE_BLE_DEVICE_S* devices;
} gap_ble_whitelist_data;

typedef struct {
uint32_t cod;
bt_io_capability_t io_capability; // undefined BT_IO_CAPABILITY_UNKNOW in rel-3.5
char bt_name[BT_DEVICE_NAME_MAX_LEN];
bt_scan_mode_t scan_mode;
bool bondable;
} bt_device_info_t;

typedef struct {
BD_ADDR bd_addr;
uint8_t addr_type; // 1 Byte
char bt_name[BT_DEVICE_NAME_MAX_LEN + 1];
BT_UUID_T uuids[10];
uint8_t link_key[16];
uint8_t link_key_type; // 1 Byte
uint16_t device_volume; // 2 Bytes
uint32_t device_profile; // 4 Bytes
uint32_t cod;
uint8_t device_type;
uint8_t rssi;
} SERVICE_REMOTE_DEVICE_S;

typedef struct {
uint8_t smp_keys[SMP_KEYS_MAX_SIZE];
} ble_keys_t;

typedef struct {
uv_loop_t* loop;
uv_db_t* read_db;
} bt_storage_transformer_t;

static void transform_deviceinfo_to_adapterinfo(bt_device_info_t* device_info, adapter_storage_t* adapter_info)
{
syslog(LOG_INFO, __func__);
strlcpy(adapter_info->name, device_info->bt_name, sizeof(adapter_info->name)); // shorter name
adapter_info->class_of_device = device_info->cod;
adapter_info->io_capability = device_info->io_capability;
adapter_info->scan_mode = device_info->scan_mode;
adapter_info->bondable = device_info->bondable;
}

static void transform_btbond_to_deviceproperty(SERVICE_REMOTE_DEVICE_S* remote_device, remote_device_properties_t* device_property)
{
syslog(LOG_INFO, __func__);
bt_addr_set(&device_property->addr, remote_device->bd_addr);
device_property->addr_type = remote_device->addr_type;
strlcpy(device_property->name, remote_device->bt_name, sizeof(device_property->name));
memset(&device_property->alias, 0, sizeof(device_property->alias));
device_property->class_of_device = remote_device->cod;
memcpy(device_property->link_key, remote_device->link_key, 16);
device_property->link_key_type = remote_device->link_key_type;
device_property->device_type = remote_device->device_type + 1; // +1 for adaption
}

static void transform_blebond_to_deviceleproperty(ble_keys_t* remote_device, remote_device_le_properties_t* device_property)
{
smp_keys_parsing_t* smp_keys = (smp_keys_parsing_t*)remote_device->smp_keys;

syslog(LOG_INFO, __func__);
bt_addr_set(&device_property->addr, smp_keys->bd);
device_property->addr_type = smp_keys->atype; // The correspondence of this field has not been confirmed.
memcpy(device_property->smp_key, smp_keys, sizeof(device_property->smp_key));
device_property->device_type = 0; // unknown
}

static void transform_blewhitelist_to_deviceleproperty(SERVICE_REMOTE_BLE_DEVICE_S* remote_device, remote_device_le_properties_t* device_property)
{
syslog(LOG_INFO, __func__);
bt_addr_set(&device_property->addr, remote_device->bd_addr);
device_property->addr_type = remote_device->addr_type;
}

static void load_device_info_cb(int status, const char* key, uv_buf_t value, void* cookie)
{
adapter_storage_t adapter_info;

syslog(LOG_INFO, __func__);
if (status != 0) {
syslog(LOG_WARNING, "adapter info load failed, status is %d\n", status); // There is no adapter info in rel-3.5 in default
return;
}

if (value.len != sizeof(bt_device_info_t)) {
syslog(LOG_ERR, "adapter info load error\n");
return;
}

transform_deviceinfo_to_adapterinfo((bt_device_info_t*)value.base, &adapter_info);
bt_storage_save_adapter_info(&adapter_info);
}

static void load_btbond_cb(int status, const char* key, uv_buf_t value, void* cookie)
{
uint16_t i;
bt_storage_t* bt_storage;
SERVICE_REMOTE_DEVICE_S* device;
remote_device_properties_t* device_properties;

syslog(LOG_INFO, __func__);
if (status != 0) {
syslog(LOG_WARNING, "bt bonded device load failed, status is %d\n", status);
return;
}

bt_storage = (bt_storage_t*)(value.base);
if (bt_storage->check_sum != (bt_storage->size + bt_storage->bonded_number)) {
syslog(LOG_ERR, "loaded bt bonded device info erro\n");
return;
}

syslog(LOG_DEBUG, "loaded %" PRIu32 "bytes info", bt_storage->size);
syslog(LOG_DEBUG, "device type size is %zu", sizeof(SERVICE_REMOTE_DEVICE_S));

device = (SERVICE_REMOTE_DEVICE_S*)(&bt_storage->bonded_devices);
device_properties = (remote_device_properties_t*)malloc(sizeof(remote_device_properties_t) * bt_storage->bonded_number);
if (!device_properties) {
syslog(LOG_ERR, "malloc failed");
return;
}

for (i = 0; i < bt_storage->bonded_number; i++)
transform_btbond_to_deviceproperty(device + i, device_properties + i);

bt_storage_save_bonded_device(device_properties, bt_storage->bonded_number);
free(device_properties);
}

static void load_blebond_cb(int status, const char* key, uv_buf_t value, void* cookie)
{
uint16_t i;
remote_device_le_properties_t* device_properties;
bt_storage_t* bt_storage;
ble_keys_t* keys;

syslog(LOG_INFO, __func__);
if (status != 0) {
syslog(LOG_WARNING, "ble bonded device load failed, status is %d", status);
return;
}

bt_storage = (bt_storage_t*)(value.base);
if (bt_storage->check_sum != (bt_storage->size + bt_storage->bonded_number)) {
syslog(LOG_ERR, "loaded ble bonded device info erro");
return;
}

keys = (ble_keys_t*)(&bt_storage->bonded_devices);
device_properties = (remote_device_le_properties_t*)malloc(sizeof(remote_device_le_properties_t) * bt_storage->bonded_number);
if (!device_properties) {
syslog(LOG_ERR, "malloc failed\n");
return;
}

for (i = 0; i < bt_storage->bonded_number; i++)
transform_blebond_to_deviceleproperty(keys + i, device_properties + i);

bt_storage_save_le_bonded_device(device_properties, bt_storage->bonded_number);
free(device_properties);
}

static void load_blewhitelist_cb(int status, const char* key, uv_buf_t value, void* cookie)
{
uint16_t i;
remote_device_le_properties_t* device_properties;
gap_ble_whitelist_data* ble_whitelist;
SERVICE_REMOTE_BLE_DEVICE_S* whitelist_device;

syslog(LOG_INFO, __func__);
if (status != 0) {
syslog(LOG_WARNING, "ble whitelist device load failed, status is %d\n", status);
return;
}

ble_whitelist = (gap_ble_whitelist_data*)(value.base);
if (ble_whitelist->size != value.len) {
syslog(LOG_ERR, "loaded ble whitelist device info erro\n");
return;
}

syslog(LOG_DEBUG, "loaded %zu bytes info", value.len);
syslog(LOG_DEBUG, "device type size is %zu", sizeof(SERVICE_REMOTE_BLE_DEVICE_S));

whitelist_device = (SERVICE_REMOTE_BLE_DEVICE_S*)(&ble_whitelist->devices); // obtain the address of the first device
device_properties = (remote_device_le_properties_t*)malloc(sizeof(remote_device_le_properties_t) * ble_whitelist->num);
if (!device_properties) {
syslog(LOG_ERR, "malloc failed\n");
return;
}

for (i = 0; i < ble_whitelist->num; i++)
transform_blewhitelist_to_deviceleproperty(whitelist_device + i, device_properties + i);

bt_storage_save_whitelist(device_properties, ble_whitelist->num);
free(device_properties);
}

static void load_from_db_with_key(uv_db_t* db, const char* key, void* cb, void* cookie)
{
uv_buf_t buf;
int res;

syslog(LOG_INFO, "load from db with key %s\n", key);
res = uv_db_get(db, key, &buf, cb, cookie);
assert(res == 0);
}

static void bt_storage_transformer_init(bt_storage_transformer_t* transformer)
{
syslog(LOG_INFO, __func__);
transformer->loop = uv_default_loop();
uv_db_init(transformer->loop, &transformer->read_db, BT_CONFIG_FILE_PATH);
bt_storage_init();
}

static void bt_storage_transformer_deinit(bt_storage_transformer_t* transformer)
{
syslog(LOG_INFO, __func__);

if (transformer->read_db)
uv_db_close(transformer->read_db);
bt_storage_cleanup();
uv_loop_close(transformer->loop);
}

static void bt_storage_transformer_work(bt_storage_transformer_t* transformer)
{
syslog(LOG_INFO, __func__);

load_from_db_with_key(transformer->read_db, BT_KEY_DEVICE_INFO, load_device_info_cb, NULL);
load_from_db_with_key(transformer->read_db, BT_KEY_BTBOND, load_btbond_cb, NULL);
load_from_db_with_key(transformer->read_db, BT_KEY_BLEBOND, load_blebond_cb, NULL);
load_from_db_with_key(transformer->read_db, BT_KEY_BLEWHITELIST, load_blewhitelist_cb, NULL);

uv_run(transformer->loop, UV_RUN_DEFAULT);
}

int main(void)
{
bt_storage_transformer_t transformer = { 0 };

if (!access(BT_STORAGE_FILE_PATH, F_OK)) {
syslog(LOG_INFO, "bt_storage.db exits\n");
return 0;
}

if (access(BT_CONFIG_FILE_PATH, F_OK)) {
syslog(LOG_INFO, "bt_config.db not exits\n");
return 0;
}

bt_storage_transformer_init(&transformer);
bt_storage_transformer_work(&transformer);
bt_storage_transformer_deinit(&transformer);
if (property_set_bool(BLUETOOTH_V35_UPGRDE_TAG, true))
syslog(LOG_ERR, "set %s failed\n", BLUETOOTH_V35_UPGRDE_TAG);

return 0;
}

0 comments on commit a08d305

Please sign in to comment.