blob: 60852332d96608e98e6dbe23c900852fd1b93227 [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* 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 "hci/le_address_manager.h"
#include <gtest/gtest.h>
#include "common/init_flags.h"
#include "os/log.h"
#include "packet/raw_builder.h"
using ::bluetooth::crypto_toolbox::Octet16;
using ::bluetooth::os::Handler;
using ::bluetooth::os::Thread;
namespace bluetooth {
namespace hci {
using packet::kLittleEndian;
using packet::PacketView;
using packet::RawBuilder;
PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
auto bytes = std::make_shared<std::vector<uint8_t>>();
BitInserter i(*bytes);
bytes->reserve(packet->size());
packet->Serialize(i);
return packet::PacketView<packet::kLittleEndian>(bytes);
}
class TestHciLayer : public HciLayer {
public:
void EnqueueCommand(
std::unique_ptr<CommandBuilder> command,
common::ContextualOnceCallback<void(CommandCompleteView)> on_complete) override {
std::lock_guard<std::mutex> lock(mutex_);
command_queue_.push(std::move(command));
command_complete_callbacks.push_back(std::move(on_complete));
if (command_promise_ != nullptr) {
command_promise_->set_value();
command_promise_.reset();
}
}
void SetCommandFuture() {
ASSERT_LOG(command_promise_ == nullptr, "Promises, Promises, ... Only one at a time.");
command_promise_ = std::make_unique<std::promise<void>>();
command_future_ = std::make_unique<std::future<void>>(command_promise_->get_future());
}
CommandView GetLastCommand() {
if (command_queue_.size() == 0) {
return CommandView::Create(PacketView<kLittleEndian>(std::make_shared<std::vector<uint8_t>>()));
}
auto last = std::move(command_queue_.front());
command_queue_.pop();
return CommandView::Create(GetPacketView(std::move(last)));
}
CommandView GetCommand(OpCode op_code) {
if (!command_queue_.empty()) {
std::lock_guard<std::mutex> lock(mutex_);
if (command_future_ != nullptr) {
command_future_.reset();
command_promise_.reset();
}
} else if (command_future_ != nullptr) {
auto result = command_future_->wait_for(std::chrono::milliseconds(1000));
EXPECT_NE(std::future_status::timeout, result);
}
std::lock_guard<std::mutex> lock(mutex_);
ASSERT_LOG(
!command_queue_.empty(), "Expecting command %s but command queue was empty", OpCodeText(op_code).c_str());
CommandView command_packet_view = GetLastCommand();
EXPECT_TRUE(command_packet_view.IsValid());
EXPECT_EQ(command_packet_view.GetOpCode(), op_code);
return command_packet_view;
}
void IncomingEvent(std::unique_ptr<EventBuilder> event_builder) {
auto packet = GetPacketView(std::move(event_builder));
EventView event = EventView::Create(packet);
ASSERT_TRUE(event.IsValid());
CommandCompleteCallback(event);
}
void CommandCompleteCallback(EventView event) {
CommandCompleteView complete_view = CommandCompleteView::Create(event);
ASSERT_TRUE(complete_view.IsValid());
std::move(command_complete_callbacks.front()).Invoke(complete_view);
command_complete_callbacks.pop_front();
}
void ListDependencies(ModuleList* list) const {}
void Start() override {}
void Stop() override {}
private:
std::list<common::ContextualOnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
std::queue<std::unique_ptr<CommandBuilder>> command_queue_;
std::unique_ptr<std::promise<void>> command_promise_;
std::unique_ptr<std::future<void>> command_future_;
mutable std::mutex mutex_;
};
class RotatorClient : public LeAddressManagerCallback {
public:
RotatorClient(LeAddressManager* le_address_manager, size_t id) : le_address_manager_(le_address_manager), id_(id){};
void OnPause() {
paused = true;
le_address_manager_->AckPause(this);
}
void OnResume() {
paused = false;
le_address_manager_->AckResume(this);
if (resume_promise_ != nullptr) {
resume_promise_->set_value();
resume_promise_.reset();
}
}
void WaitForResume() {
if (paused) {
resume_promise_ = std::make_unique<std::promise<void>>();
auto resume_future = resume_promise_->get_future();
auto result = resume_future.wait_for(std::chrono::milliseconds(1000));
EXPECT_NE(std::future_status::timeout, result);
}
}
bool paused{false};
LeAddressManager* le_address_manager_;
size_t id_;
std::unique_ptr<std::promise<void>> resume_promise_;
};
class LeAddressManagerTest : public ::testing::Test {
public:
void SetUp() override {
thread_ = new Thread("thread", Thread::Priority::NORMAL);
handler_ = new Handler(thread_);
test_hci_layer_ = new TestHciLayer;
Address address({0x01, 0x02, 0x03, 0x04, 0x05, 0x06});
le_address_manager_ = new LeAddressManager(
common::Bind(&LeAddressManagerTest::enqueue_command, common::Unretained(this)), handler_, address, 0x3F, 0x3F);
AllocateClients(1);
}
void sync_handler(os::Handler* handler) {
std::promise<void> promise;
auto future = promise.get_future();
handler_->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
auto future_status = future.wait_for(std::chrono::seconds(1));
EXPECT_EQ(future_status, std::future_status::ready);
}
void TearDown() override {
sync_handler(handler_);
delete le_address_manager_;
delete test_hci_layer_;
handler_->Clear();
delete handler_;
delete thread_;
}
void AllocateClients(size_t num_clients) {
size_t first_id = clients.size();
for (size_t i = 0; i < num_clients; i++) {
clients.emplace_back(std::make_unique<RotatorClient>(le_address_manager_, first_id + i));
}
}
void enqueue_command(std::unique_ptr<CommandBuilder> command_packet) {
test_hci_layer_->EnqueueCommand(
std::move(command_packet),
handler_->BindOnce(&LeAddressManager::OnCommandComplete, common::Unretained(le_address_manager_)));
}
Thread* thread_;
Handler* handler_;
TestHciLayer* test_hci_layer_ = nullptr;
LeAddressManager* le_address_manager_;
std::vector<std::unique_ptr<RotatorClient>> clients;
};
TEST_F(LeAddressManagerTest, startup_teardown) {}
TEST_F(LeAddressManagerTest, register_unregister_callback) {
le_address_manager_->Register(clients[0].get());
sync_handler(handler_);
le_address_manager_->Unregister(clients[0].get());
sync_handler(handler_);
}
TEST_F(LeAddressManagerTest, rotator_address_for_single_client) {
Octet16 irk = {0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
auto minimum_rotation_time = std::chrono::milliseconds(1000);
auto maximum_rotation_time = std::chrono::milliseconds(3000);
AddressWithType remote_address(Address::kEmpty, AddressType::RANDOM_DEVICE_ADDRESS);
le_address_manager_->SetPrivacyPolicyForInitiatorAddress(
LeAddressManager::AddressPolicy::USE_RESOLVABLE_ADDRESS,
remote_address,
irk,
minimum_rotation_time,
maximum_rotation_time);
test_hci_layer_->SetCommandFuture();
le_address_manager_->Register(clients[0].get());
sync_handler(handler_);
test_hci_layer_->GetCommand(OpCode::LE_SET_RANDOM_ADDRESS);
test_hci_layer_->IncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
clients[0].get()->WaitForResume();
le_address_manager_->Unregister(clients[0].get());
sync_handler(handler_);
}
TEST_F(LeAddressManagerTest, rotator_non_resolvable_address_for_single_client) {
Octet16 irk = {};
auto minimum_rotation_time = std::chrono::milliseconds(1000);
auto maximum_rotation_time = std::chrono::milliseconds(3000);
AddressWithType remote_address(Address::kEmpty, AddressType::RANDOM_DEVICE_ADDRESS);
le_address_manager_->SetPrivacyPolicyForInitiatorAddress(
LeAddressManager::AddressPolicy::USE_NON_RESOLVABLE_ADDRESS,
remote_address,
irk,
minimum_rotation_time,
maximum_rotation_time);
test_hci_layer_->SetCommandFuture();
le_address_manager_->Register(clients[0].get());
sync_handler(handler_);
test_hci_layer_->GetCommand(OpCode::LE_SET_RANDOM_ADDRESS);
test_hci_layer_->IncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
clients[0].get()->WaitForResume();
le_address_manager_->Unregister(clients[0].get());
sync_handler(handler_);
}
// TODO handle the case "register during rotate_random_address" and enable this
TEST_F(LeAddressManagerTest, DISABLED_rotator_address_for_multiple_clients) {
AllocateClients(2);
Octet16 irk = {0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
auto minimum_rotation_time = std::chrono::milliseconds(1000);
auto maximum_rotation_time = std::chrono::milliseconds(3000);
AddressWithType remote_address(Address::kEmpty, AddressType::RANDOM_DEVICE_ADDRESS);
le_address_manager_->SetPrivacyPolicyForInitiatorAddress(
LeAddressManager::AddressPolicy::USE_RESOLVABLE_ADDRESS,
remote_address,
irk,
minimum_rotation_time,
maximum_rotation_time);
le_address_manager_->Register(clients[0].get());
le_address_manager_->Register(clients[1].get());
le_address_manager_->Register(clients[2].get());
sync_handler(handler_);
le_address_manager_->Unregister(clients[0].get());
le_address_manager_->Unregister(clients[1].get());
le_address_manager_->Unregister(clients[2].get());
sync_handler(handler_);
}
class LeAddressManagerWithSingleClientTest : public LeAddressManagerTest {
public:
void SetUp() override {
bluetooth::common::InitFlags::SetAllForTesting();
thread_ = new Thread("thread", Thread::Priority::NORMAL);
handler_ = new Handler(thread_);
test_hci_layer_ = new TestHciLayer;
Address address({0x01, 0x02, 0x03, 0x04, 0x05, 0x06});
le_address_manager_ = new LeAddressManager(
common::Bind(&LeAddressManagerWithSingleClientTest::enqueue_command, common::Unretained(this)),
handler_,
address,
0x3F,
0x3F);
AllocateClients(1);
Octet16 irk = {0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
auto minimum_rotation_time = std::chrono::milliseconds(1000);
auto maximum_rotation_time = std::chrono::milliseconds(3000);
AddressWithType remote_address(Address::kEmpty, AddressType::RANDOM_DEVICE_ADDRESS);
le_address_manager_->SetPrivacyPolicyForInitiatorAddress(
LeAddressManager::AddressPolicy::USE_RESOLVABLE_ADDRESS,
remote_address,
irk,
minimum_rotation_time,
maximum_rotation_time);
test_hci_layer_->SetCommandFuture();
le_address_manager_->Register(clients[0].get());
sync_handler(handler_);
test_hci_layer_->GetCommand(OpCode::LE_SET_RANDOM_ADDRESS);
test_hci_layer_->IncomingEvent(LeSetRandomAddressCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
}
void enqueue_command(std::unique_ptr<CommandBuilder> command_packet) {
test_hci_layer_->EnqueueCommand(
std::move(command_packet),
handler_->BindOnce(&LeAddressManager::OnCommandComplete, common::Unretained(le_address_manager_)));
}
void TearDown() override {
le_address_manager_->Unregister(clients[0].get());
sync_handler(handler_);
delete le_address_manager_;
delete test_hci_layer_;
handler_->Clear();
delete handler_;
delete thread_;
}
};
TEST_F(LeAddressManagerWithSingleClientTest, add_device_to_connect_list) {
Address address;
Address::FromString("01:02:03:04:05:06", address);
test_hci_layer_->SetCommandFuture();
le_address_manager_->AddDeviceToConnectList(ConnectListAddressType::RANDOM, address);
auto packet = test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_CONNECT_LIST);
auto packet_view =
LeAddDeviceToConnectListView::Create(LeConnectionManagementCommandView::Create(AclCommandView::Create(packet)));
ASSERT_TRUE(packet_view.IsValid());
ASSERT_EQ(ConnectListAddressType::RANDOM, packet_view.GetAddressType());
ASSERT_EQ(address, packet_view.GetAddress());
test_hci_layer_->IncomingEvent(LeAddDeviceToConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
clients[0].get()->WaitForResume();
}
TEST_F(LeAddressManagerWithSingleClientTest, remove_device_from_connect_list) {
Address address;
Address::FromString("01:02:03:04:05:06", address);
test_hci_layer_->SetCommandFuture();
le_address_manager_->AddDeviceToConnectList(ConnectListAddressType::RANDOM, address);
test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_CONNECT_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
test_hci_layer_->SetCommandFuture();
le_address_manager_->RemoveDeviceFromConnectList(ConnectListAddressType::RANDOM, address);
auto packet = test_hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_CONNECT_LIST);
auto packet_view = LeRemoveDeviceFromConnectListView::Create(
LeConnectionManagementCommandView::Create(AclCommandView::Create(packet)));
ASSERT_TRUE(packet_view.IsValid());
ASSERT_EQ(ConnectListAddressType::RANDOM, packet_view.GetAddressType());
ASSERT_EQ(address, packet_view.GetAddress());
test_hci_layer_->IncomingEvent(LeRemoveDeviceFromConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
clients[0].get()->WaitForResume();
}
TEST_F(LeAddressManagerWithSingleClientTest, clear_connect_list) {
Address address;
Address::FromString("01:02:03:04:05:06", address);
test_hci_layer_->SetCommandFuture();
le_address_manager_->AddDeviceToConnectList(ConnectListAddressType::RANDOM, address);
test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_CONNECT_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
test_hci_layer_->SetCommandFuture();
le_address_manager_->ClearConnectList();
test_hci_layer_->GetCommand(OpCode::LE_CLEAR_CONNECT_LIST);
test_hci_layer_->IncomingEvent(LeClearConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
clients[0].get()->WaitForResume();
}
TEST_F(LeAddressManagerWithSingleClientTest, add_device_to_resolving_list) {
Address address;
Address::FromString("01:02:03:04:05:06", address);
Octet16 peer_irk = {0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
Octet16 local_irk = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
test_hci_layer_->SetCommandFuture();
le_address_manager_->AddDeviceToResolvingList(
PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, address, peer_irk, local_irk);
auto packet = test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST);
auto packet_view = LeAddDeviceToResolvingListView::Create(LeSecurityCommandView::Create(packet));
ASSERT_TRUE(packet_view.IsValid());
ASSERT_EQ(PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, packet_view.GetPeerIdentityAddressType());
ASSERT_EQ(address, packet_view.GetPeerIdentityAddress());
ASSERT_EQ(peer_irk, packet_view.GetPeerIrk());
ASSERT_EQ(local_irk, packet_view.GetLocalIrk());
test_hci_layer_->IncomingEvent(LeAddDeviceToResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
clients[0].get()->WaitForResume();
}
TEST_F(LeAddressManagerWithSingleClientTest, remove_device_from_resolving_list) {
Address address;
Address::FromString("01:02:03:04:05:06", address);
Octet16 peer_irk = {0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
Octet16 local_irk = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
test_hci_layer_->SetCommandFuture();
le_address_manager_->AddDeviceToResolvingList(
PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, address, peer_irk, local_irk);
test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
test_hci_layer_->SetCommandFuture();
le_address_manager_->RemoveDeviceFromResolvingList(PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, address);
auto packet = test_hci_layer_->GetCommand(OpCode::LE_REMOVE_DEVICE_FROM_RESOLVING_LIST);
auto packet_view = LeRemoveDeviceFromResolvingListView::Create(LeSecurityCommandView::Create(packet));
ASSERT_TRUE(packet_view.IsValid());
ASSERT_EQ(PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, packet_view.GetPeerIdentityAddressType());
ASSERT_EQ(address, packet_view.GetPeerIdentityAddress());
test_hci_layer_->IncomingEvent(LeRemoveDeviceFromResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
clients[0].get()->WaitForResume();
}
TEST_F(LeAddressManagerWithSingleClientTest, clear_resolving_list) {
Address address;
Address::FromString("01:02:03:04:05:06", address);
Octet16 peer_irk = {0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
Octet16 local_irk = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
test_hci_layer_->SetCommandFuture();
le_address_manager_->AddDeviceToResolvingList(
PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS, address, peer_irk, local_irk);
test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST);
test_hci_layer_->IncomingEvent(LeAddDeviceToResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
test_hci_layer_->SetCommandFuture();
le_address_manager_->ClearResolvingList();
auto packet = test_hci_layer_->GetCommand(OpCode::LE_CLEAR_RESOLVING_LIST);
auto packet_view = LeClearResolvingListView::Create(LeSecurityCommandView::Create(packet));
ASSERT_TRUE(packet_view.IsValid());
test_hci_layer_->IncomingEvent(LeClearResolvingListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
clients[0].get()->WaitForResume();
}
TEST_F(LeAddressManagerWithSingleClientTest, register_during_command_complete) {
Address address;
Address::FromString("01:02:03:04:05:06", address);
test_hci_layer_->SetCommandFuture();
le_address_manager_->AddDeviceToConnectList(ConnectListAddressType::RANDOM, address);
auto packet = test_hci_layer_->GetCommand(OpCode::LE_ADD_DEVICE_TO_CONNECT_LIST);
auto packet_view =
LeAddDeviceToConnectListView::Create(LeConnectionManagementCommandView::Create(AclCommandView::Create(packet)));
ASSERT_TRUE(packet_view.IsValid());
ASSERT_EQ(ConnectListAddressType::RANDOM, packet_view.GetAddressType());
ASSERT_EQ(address, packet_view.GetAddress());
test_hci_layer_->IncomingEvent(LeAddDeviceToConnectListCompleteBuilder::Create(0x01, ErrorCode::SUCCESS));
AllocateClients(1);
test_hci_layer_->SetCommandFuture();
le_address_manager_->Register(clients[1].get());
clients[0].get()->WaitForResume();
clients[1].get()->WaitForResume();
}
} // namespace hci
} // namespace bluetooth