#include <string.h>
#include <time.h>
#include <unistd.h>
+#include <functional>
#include <mutex>
#include <sstream>
#include <string>
+#include <unordered_map>
#include "bt_types.h"
#include "btcore/include/module.h"
//#include "btif_keystore.h"
#include "btif_util.h"
#include "common/address_obfuscator.h"
+#include "common/metric_id_allocator.h"
#include "main/shim/config.h"
#include "main/shim/shim.h"
#include "osi/include/alarm.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
#include "osi/include/properties.h"
+#include "raw_address.h"
#define BT_CONFIG_SOURCE_TAG_NUM 1010001
#define BT_CONFIG_METRICS_SECTION "Metrics"
#define BT_CONFIG_METRICS_SALT_256BIT "Salt256Bit"
+#define BT_CONFIG_METRICS_ID_KEY "MetricsId"
+
// using bluetooth::BtifKeystore;
using bluetooth::common::AddressObfuscator;
+using bluetooth::common::MetricIdAllocator;
// TODO(armansito): Find a better way than searching by a hardcoded path.
#if defined(OS_GENERIC)
AddressObfuscator::GetInstance()->Initialize(metrics_salt);
}
+/**
+ * Initialize metric id allocator by reading metric_id from config by mac
+ * address. If there is no metric id for a mac address, then allocate it a new
+ * metric id.
+ */
+static void init_metric_id_allocator() {
+ std::unordered_map<RawAddress, int> paired_device_map;
+
+ // When user update the system, there will be devices paired with older
+ // version of android without a metric id.
+ std::vector<RawAddress> addresses_without_id;
+
+ for (auto& section : btif_config_sections()) {
+ auto& section_name = section.name;
+ RawAddress mac_address;
+ if (!RawAddress::FromString(section_name, mac_address)) {
+ continue;
+ }
+ // if the section name is a mac address
+ bool is_valid_id_found = false;
+ if (btif_config_exist(section_name, BT_CONFIG_METRICS_ID_KEY)) {
+ // there is one metric id under this mac_address
+ int id = 0;
+ btif_config_get_int(section_name, BT_CONFIG_METRICS_ID_KEY, &id);
+ if (MetricIdAllocator::IsValidId(id)) {
+ paired_device_map[mac_address] = id;
+ is_valid_id_found = true;
+ }
+ }
+ if (!is_valid_id_found) {
+ addresses_without_id.push_back(mac_address);
+ }
+ }
+
+ // Initialize MetricIdAllocator
+ MetricIdAllocator::Callback save_device_callback =
+ [](const RawAddress& address, const int id) {
+ return btif_config_set_int(address.ToString(), BT_CONFIG_METRICS_ID_KEY,
+ id);
+ };
+ MetricIdAllocator::Callback forget_device_callback =
+ [](const RawAddress& address, const int id) {
+ return btif_config_remove(address.ToString(), BT_CONFIG_METRICS_ID_KEY);
+ };
+ if (!MetricIdAllocator::GetInstance().Init(
+ paired_device_map, std::move(save_device_callback),
+ std::move(forget_device_callback))) {
+ LOG(FATAL) << __func__ << "Failed to initialize MetricIdAllocator";
+ }
+
+ // Add device_without_id
+ for (auto& address : addresses_without_id) {
+ MetricIdAllocator::GetInstance().AllocateId(address);
+ MetricIdAllocator::GetInstance().SaveDevice(address);
+ }
+}
+
static std::recursive_mutex config_lock; // protects operations on |config|.
static std::unique_ptr<config_t> config;
static alarm_t* config_timer;
// Read or set metrics 256 bit hashing salt
read_or_set_metrics_salt();
+ // Initialize MetricIdAllocator
+ init_metric_id_allocator();
+
// TODO(sharvil): use a non-wake alarm for this once we have
// API support for it. There's no need to wake the system to
// write back to disk.
config_timer = NULL;
std::unique_lock<std::recursive_mutex> lock(config_lock);
+ MetricIdAllocator::GetInstance().Close();
config.reset();
return future_new_immediate(FUTURE_SUCCESS);
}
#include "btif_storage.h"
#include "btif_util.h"
#include "btu.h"
+#include "common/metric_id_allocator.h"
#include "common/metrics.h"
#include "device/include/controller.h"
#include "device/include/interop.h"
#include "stack_config.h"
using bluetooth::Uuid;
+using bluetooth::common::MetricIdAllocator;
/******************************************************************************
* Constants & Macros
*****************************************************************************/
BTIF_TRACE_DEBUG("%s: state=%d, prev_state=%d, sdp_attempts = %d", __func__,
state, pairing_cb.state, pairing_cb.sdp_attempts);
+ if (state == BT_BOND_STATE_NONE) {
+ MetricIdAllocator::GetInstance().ForgetDevice(bd_addr);
+ } else if (state == BT_BOND_STATE_BONDED) {
+ MetricIdAllocator::GetInstance().AllocateId(bd_addr);
+ if (!MetricIdAllocator::GetInstance().SaveDevice(bd_addr)) {
+ LOG(FATAL) << __func__ << ": Fail to save metric id for device "
+ << bd_addr;
+ }
+ }
auto tmp = bd_addr;
HAL_CBACK(bt_hal_cbacks, bond_state_changed_cb, status, &tmp, state);
const std::string MetricIdAllocator::LOGGING_TAG = "BluetoothMetricIdAllocator";
const size_t MetricIdAllocator::kMaxNumUnpairedDevicesInMemory = 200;
-const size_t MetricIdAllocator::kMaxNumPairedDevicesInMemory = 400;
+const size_t MetricIdAllocator::kMaxNumPairedDevicesInMemory = 65000;
const int MetricIdAllocator::kMinId = 1;
const int MetricIdAllocator::kMaxId = 65534; // 2^16 - 2
MetricIdAllocator::MetricIdAllocator()
: paired_device_cache_(kMaxNumPairedDevicesInMemory, LOGGING_TAG,
- [this](RawAddress dummy, int to_remove) {
- this->id_set_.erase(to_remove);
+ [this](RawAddress mac_address, int id) {
+ ForgetDevicePostprocess(mac_address, id);
}),
- temporary_device_cache_(kMaxNumUnpairedDevicesInMemory, LOGGING_TAG,
- [this](RawAddress dummy, int to_remove) {
- this->id_set_.erase(to_remove);
- }) {}
+ temporary_device_cache_(
+ kMaxNumUnpairedDevicesInMemory, LOGGING_TAG,
+ [this](RawAddress dummy, int id) { this->id_set_.erase(id); }) {}
bool MetricIdAllocator::Init(
const std::unordered_map<RawAddress, int>& paired_device_map,
}
// call this function when a device is forgotten
-bool MetricIdAllocator::ForgetDevice(const RawAddress& mac_address) {
+void MetricIdAllocator::ForgetDevice(const RawAddress& mac_address) {
std::lock_guard<std::mutex> lock(id_allocator_mutex_);
int id = 0;
bool success = paired_device_cache_.Get(mac_address, &id);
success &= paired_device_cache_.Remove(mac_address);
if (success) {
- id_set_.erase(id);
- success = forget_device_callback_(mac_address, id);
+ ForgetDevicePostprocess(mac_address, id);
}
- return success;
+}
+
+bool MetricIdAllocator::IsValidId(const int id) {
+ return id >= kMinId && id <= kMaxId;
+}
+
+void MetricIdAllocator::ForgetDevicePostprocess(const RawAddress& mac_address,
+ const int id) {
+ id_set_.erase(id);
+ forget_device_callback_(mac_address, id);
}
} // namespace common
* Delete the id for a device to be forgotten
*
* @param mac_address mac address of Bluetooth device
+ */
+ void ForgetDevice(const RawAddress& mac_address);
+
+ /**
+ * Check if an id is valid.
+ * The id should be less than or equal to kMaxId and bigger than or equal to
+ * kMinId
+ *
+ * @param mac_address mac address of Bluetooth device
* @return true if delete successfully
*/
- bool ForgetDevice(const RawAddress& mac_address);
+ static bool IsValidId(const int id);
protected:
// Singleton
Callback save_id_callback_;
Callback forget_device_callback_;
+ void ForgetDevicePostprocess(const RawAddress& mac_address, const int id);
+
// delete copy constructor for singleton
MetricIdAllocator(MetricIdAllocator const&) = delete;
MetricIdAllocator& operator=(MetricIdAllocator const&) = delete;
EXPECT_EQ(dummy, 176);
// forget
- EXPECT_FALSE(allocator.ForgetDevice(RawAddress({0, 0, 0, 0, 0, 1})));
+ allocator.ForgetDevice(RawAddress({0, 0, 0, 0, 0, 1}));
EXPECT_EQ(dummy, 176);
- EXPECT_TRUE(allocator.ForgetDevice(RawAddress({0, 0, 0, 0, 0, 2})));
+ allocator.ForgetDevice(RawAddress({0, 0, 0, 0, 0, 2}));
EXPECT_EQ(dummy, 88);
EXPECT_TRUE(allocator.Close());
// preset a full map
std::unordered_map<RawAddress, int> paired_device_map =
generateAddresses(MetricIdAllocator::kMaxNumPairedDevicesInMemory);
- int dummy = 22;
+ int dummy = 243;
int* pointer = &dummy;
MetricIdAllocator::Callback save_callback = [pointer](const RawAddress&,
const int) {
};
MetricIdAllocator::Callback forget_callback = [pointer](const RawAddress&,
const int) {
- *pointer = *pointer / 2;
+ *pointer = *pointer / 3;
return true;
};
// save it and make sure the callback is called
EXPECT_TRUE(allocator.SaveDevice(kthAddress(key)));
- EXPECT_EQ(dummy, 44);
+ EXPECT_EQ(dummy, 162); // one key is evicted, another key is saved so *2/3
+
// paired: 1, 2 ... 199, 200,
// scanned:
// key == 200
// should fail, since id of device is not allocated
EXPECT_FALSE(allocator.SaveDevice(kthAddress(key + 1)));
- EXPECT_EQ(dummy, 44);
+ EXPECT_EQ(dummy, 162);
// paired: 1, 2 ... 199, 200,
// scanned: 0
EXPECT_EQ(allocator.AllocateId(kthAddress(key + 1)), id++);
EXPECT_TRUE(allocator.SaveDevice(kthAddress(key + 1)));
- EXPECT_EQ(dummy, 88);
+ EXPECT_EQ(dummy, 108); // one key is evicted, another key is saved so *2/3,
// paired: 2 ... 199, 200, 201
// scanned: 0
// paired: 2 ... 199, 200, 201,
// scanned: 0, 1, 202, 203
- dummy = 44;
+ dummy = 9;
EXPECT_TRUE(allocator.SaveDevice(kthAddress(key + 2)));
- EXPECT_EQ(dummy, 88);
+ EXPECT_EQ(dummy, 6); // one key is evicted, another key is saved so *2/3,
EXPECT_TRUE(allocator.SaveDevice(kthAddress(key + 3)));
- EXPECT_EQ(dummy, 176);
+ EXPECT_EQ(dummy, 4); // one key is evicted, another key is saved so *2/3,
// paired: 4 ... 199, 200, 201, 202, 203
// scanned: 0, 1
// should fail, since id had been saved
EXPECT_FALSE(allocator.SaveDevice(kthAddress(key + 2)));
- EXPECT_EQ(dummy, 176);
+ EXPECT_EQ(dummy, 4);
+ dummy = 27;
// forget
- EXPECT_FALSE(allocator.ForgetDevice(kthAddress(key + 200)));
- EXPECT_EQ(dummy, 176);
- EXPECT_TRUE(allocator.ForgetDevice(kthAddress(key + 2)));
- EXPECT_EQ(dummy, 88);
+ allocator.ForgetDevice(kthAddress(key + 200));
+ EXPECT_EQ(dummy, 27); // should fail, no such a key
+ allocator.ForgetDevice(kthAddress(key + 2));
+ EXPECT_EQ(dummy, 9);
// paired: 4 ... 199, 200, 201, 203
// scanned: 0, 1
// scanned: 0, 1, 202, 204, 205
EXPECT_TRUE(allocator.SaveDevice(kthAddress(key + 2)));
- EXPECT_EQ(dummy, 176);
+ EXPECT_EQ(dummy, 18); // no key is evicted, a key is saved so *2,
EXPECT_FALSE(allocator.SaveDevice(kthAddress(key + 3)));
- EXPECT_EQ(dummy, 176);
+ EXPECT_EQ(dummy, 18); // no such a key in scanned
EXPECT_TRUE(allocator.SaveDevice(kthAddress(key + 4)));
- EXPECT_EQ(dummy, 352);
- // paired: 6 ... 199, 200, 201, 203, 202, 204
+ EXPECT_EQ(dummy, 12); // one key is evicted, another key is saved so *2/3,
+ // paired: 5 6 ... 199, 200, 201, 203, 202, 204
// scanned: 0, 1, 205
// verify paired:
- for (key = 6; key <= 199; key++) {
- dummy = 10;
- EXPECT_TRUE(allocator.ForgetDevice(kthAddress(key)));
- EXPECT_EQ(dummy, 5);
+ for (key = 5; key <= 199; key++) {
+ dummy = 3;
+ allocator.ForgetDevice(kthAddress(key));
+ EXPECT_EQ(dummy, 1);
}
for (size_t k = MetricIdAllocator::kMaxNumPairedDevicesInMemory;
k <= MetricIdAllocator::kMaxNumPairedDevicesInMemory + 4; k++) {
- dummy = 10;
- EXPECT_TRUE(allocator.ForgetDevice(kthAddress(k)));
- EXPECT_EQ(dummy, 5);
+ dummy = 3;
+ allocator.ForgetDevice(kthAddress(k));
+ EXPECT_EQ(dummy, 1);
}
// verify scanned
// make sure no deadlock
std::vector<std::thread> workers;
for (int key = 0;
- key < static_cast<int>(MetricIdAllocator::kMaxNumPairedDevicesInMemory);
+ key <
+ static_cast<int>(MetricIdAllocator::kMaxNumUnpairedDevicesInMemory);
key++) {
workers.push_back(std::thread([key]() {
auto& allocator = MetricIdAllocator::GetInstance();
RawAddress fake_mac_address = kthAddress(key);
allocator.AllocateId(fake_mac_address);
EXPECT_TRUE(allocator.SaveDevice(fake_mac_address));
- EXPECT_TRUE(allocator.ForgetDevice(fake_mac_address));
+ allocator.ForgetDevice(fake_mac_address);
}));
}
for (auto& worker : workers) {