Use RobustGattClient

PiperOrigin-RevId: 540060033
This commit is contained in:
Janusz Sobczak
2023-06-13 13:42:19 -07:00
committed by Copybara-Service
parent e20fb4f75d
commit c4139c83b0
23 changed files with 367 additions and 439 deletions
+1
View File
@@ -46,6 +46,7 @@ cc_test(
":fast_pair_controller",
"//fastpair/message_stream:fake_provider",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/strings",
+8 -4
View File
@@ -26,13 +26,17 @@
#include "fastpair/message_stream/message_stream.h"
#include "internal/platform/bluetooth_adapter.h"
#include "internal/platform/bluetooth_classic.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
FastPairController::FastPairController(Mediums* mediums,
const BluetoothDevice& device)
: mediums_(mediums), device_(Protocol::kFastPairRetroactivePairing) {
const BluetoothDevice& device,
SingleThreadExecutor* executor)
: mediums_(mediums),
device_(Protocol::kFastPairRetroactivePairing),
executor_(executor) {
device_.SetPublicAddress(device.GetMacAddress());
}
@@ -104,8 +108,8 @@ FastPairController::GetGattClientRef() {
Future<FastPairController::GattClientRef> result;
if (gatt_client_ == nullptr) {
gatt_client_ref_count_ = 0;
gatt_client_ =
FastPairGattServiceClientImpl::Factory::Create(device_, *mediums_);
gatt_client_ = FastPairGattServiceClientImpl::Factory::Create(
device_, *mediums_, executor_);
gatt_client_->InitializeGattConnection(
[](std::optional<PairFailure> result) {
if (result.has_value()) {
+4 -1
View File
@@ -31,6 +31,7 @@
#include "internal/platform/bluetooth_adapter.h"
#include "internal/platform/bluetooth_classic.h"
#include "internal/platform/borrowable.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
@@ -106,7 +107,8 @@ class FastPairController : public MessageStream::Observer {
FastPairController* controller_ = nullptr;
};
// Creates a device controller in retroactive pairing path.
FastPairController(Mediums* mediums, const BluetoothDevice& device);
FastPairController(Mediums* mediums, const BluetoothDevice& device,
SingleThreadExecutor* executor);
~FastPairController() override {
NEARBY_LOGS(INFO) << "Destroy FastPairController";
@@ -175,6 +177,7 @@ class FastPairController : public MessageStream::Observer {
}
Mediums* mediums_;
FastPairDevice device_;
SingleThreadExecutor* executor_;
std::unique_ptr<Future<std::shared_ptr<FastPairDataEncryptor>>> encryptor_;
std::unique_ptr<MessageStream> message_stream_;
absl::Status message_stream_status_ =
+5 -2
View File
@@ -22,6 +22,7 @@
#include "absl/strings/escaping.h"
#include "fastpair/message_stream/fake_provider.h"
#include "internal/platform/medium_environment.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
@@ -47,6 +48,7 @@ class FastPairControllerTest : public testing::Test {
}
void TearDown() override {
executor_.Shutdown();
provider_.Shutdown();
MediumEnvironment::Instance().Stop();
}
@@ -54,17 +56,18 @@ class FastPairControllerTest : public testing::Test {
// The medium environment must be initialized (started) before adding
// adapters.
MediumEnvironmentStarter env_;
SingleThreadExecutor executor_;
Mediums mediums_;
FakeProvider provider_;
BluetoothDevice remote_device_;
};
TEST_F(FastPairControllerTest, Constructor) {
FastPairController controller(&mediums_, remote_device_);
FastPairController controller(&mediums_, remote_device_, &executor_);
}
TEST_F(FastPairControllerTest, OpenMessageStream) {
FastPairController controller(&mediums_, remote_device_);
FastPairController controller(&mediums_, remote_device_, &executor_);
EXPECT_OK(controller.OpenMessageStream());
}
@@ -62,6 +62,11 @@ constexpr Uuid kAccountKeyCharacteristicUuidV1(0x0000123600001000,
constexpr Uuid kAccountKeyCharacteristicUuidV2(0xFE2C123683664814,
0x8EB001DE32100BEA);
constexpr int kKeyBasedCharacteristicIndex = 0;
constexpr int kPasskeyCharacteristicIndex = 1;
constexpr int kAccountKeyCharacteristicIndex = 2;
constexpr int kNumCharacteristics = 3;
constexpr absl::Duration kGattOperationTimeout = absl::Seconds(15);
constexpr int kMaxNumGattConnectionAttempts = 3;
} // namespace
@@ -74,12 +79,14 @@ FastPairGattServiceClientImpl::Factory*
// static
std::unique_ptr<FastPairGattServiceClient>
FastPairGattServiceClientImpl::Factory::Create(const FastPairDevice& device,
Mediums& mediums) {
Mediums& mediums,
SingleThreadExecutor* executor) {
if (g_test_factory_) {
return g_test_factory_->CreateInstance();
}
return std::make_unique<FastPairGattServiceClientImpl>(device, mediums);
return std::make_unique<FastPairGattServiceClientImpl>(device, mediums,
executor);
}
// static
@@ -91,8 +98,20 @@ void FastPairGattServiceClientImpl::Factory::SetFactoryForTesting(
FastPairGattServiceClientImpl::Factory::~Factory() = default;
FastPairGattServiceClientImpl::FastPairGattServiceClientImpl(
const FastPairDevice& device, Mediums& mediums)
: device_address_(device.GetBleAddress()), mediums_(mediums) {}
const FastPairDevice& device, Mediums& mediums,
SingleThreadExecutor* executor)
: device_address_(device.GetBleAddress()),
mediums_(mediums),
executor_(executor) {
gatt_connection_params_.service_uuid = kFastPairServiceUuid;
gatt_connection_params_.characteristic_uuids.resize(kNumCharacteristics);
gatt_connection_params_.characteristic_uuids[kKeyBasedCharacteristicIndex] = {
kKeyBasedCharacteristicUuidV2, kKeyBasedCharacteristicUuidV1};
gatt_connection_params_.characteristic_uuids[kPasskeyCharacteristicIndex] = {
kPasskeyCharacteristicUuidV2, kPasskeyCharacteristicUuidV1};
gatt_connection_params_.characteristic_uuids[kAccountKeyCharacteristicIndex] =
{kAccountKeyCharacteristicUuidV2, kAccountKeyCharacteristicUuidV1};
}
void FastPairGattServiceClientImpl::InitializeGattConnection(
absl::AnyInvocable<void(std::optional<PairFailure>)>
@@ -105,19 +124,13 @@ void FastPairGattServiceClientImpl::InitializeGattConnection(
void FastPairGattServiceClientImpl::AttemptGattConnection() {
NEARBY_LOGS(INFO) << __func__ << ": Attempt to connect to the device.";
if (num_gatt_connection_attempts_ == kMaxNumGattConnectionAttempts) {
NotifyInitializedError(PairFailure::kCreateGattConnection);
return;
}
num_gatt_connection_attempts_++;
NEARBY_LOGS(INFO) << __func__ << ": Starting GATT connection attempt #"
<< num_gatt_connection_attempts_ << " to device";
if (gatt_client_) {
NEARBY_LOGS(INFO) << __func__
<< ": Disconnecting previous connections before attempt";
gatt_client_->Disconnect();
gatt_client_ = nullptr;
gatt_client_->Stop();
// Destroying gatt client may block if something went wrong.
defunct_gatt_client_ = std::move(gatt_client_);
}
CreateGattConnection();
}
@@ -126,91 +139,28 @@ void FastPairGattServiceClientImpl::CreateGattConnection() {
NEARBY_LOGS(INFO) << __func__ << " : Create Gatt Connection to the device.";
if (mediums_.GetBluetoothRadio().Enable() &&
mediums_.GetBleV2().IsAvailable()) {
gatt_client_ = mediums_.GetBleV2().ConnectToGattServer(device_address_);
gatt_client_ = mediums_.GetBleV2().ConnectToGattServer(
device_address_, gatt_connection_params_, [this](absl::Status status) {
NEARBY_LOGS(INFO) << "Gatt connection status: " << status;
if (status.ok()) {
executor_->Execute("init-success", [this]() {
if (on_gatt_initialized_callback_) {
std::move(on_gatt_initialized_callback_)(std::nullopt);
}
});
} else {
NotifyInitializedError(PairFailure::kCreateGattConnection);
}
});
}
if (!gatt_client_ || !gatt_client_->IsValid()) {
if (gatt_client_) {
is_initialized_ = true;
} else {
// The device must have been lost between connection attempts.
NotifyInitializedError(
PairFailure::kPairingDeviceLostBetweenGattConnectionAttempts);
return;
}
DiscoverServiceAndCharacteristics();
}
void FastPairGattServiceClientImpl::DiscoverServiceAndCharacteristics() {
NEARBY_LOGS(INFO) << __func__
<< " : Start to discovery servie and characteristic.";
gatt_service_discovery_timer_.Start(
kGattOperationTimeout / absl::Milliseconds(1), 0,
[&]() { OnGattServiceDiscoveryTimeout(); });
if (gatt_client_->DiscoverServiceAndCharacteristics(
kFastPairServiceUuid,
{kKeyBasedCharacteristicUuidV2, kPasskeyCharacteristicUuidV2,
kAccountKeyCharacteristicUuidV2}) ||
gatt_client_->DiscoverServiceAndCharacteristics(
kFastPairServiceUuid,
{kKeyBasedCharacteristicUuidV1, kPasskeyCharacteristicUuidV1,
kAccountKeyCharacteristicUuidV1})) {
gatt_service_discovery_timer_.Stop();
NEARBY_LOGS(INFO) << __func__
<< ": Completed discovery for Fast Pair GATT service and "
"characterisitc.";
GetFastPairGattCharacteristics();
return;
}
NEARBY_LOGS(INFO) << __func__
<< ": Failed to discovery for Fast Pair GATT service and "
"characterisitc."
<< PairFailure::kGattServiceDiscovery;
AttemptGattConnection();
}
void FastPairGattServiceClientImpl::GetFastPairGattCharacteristics() {
NEARBY_LOGS(INFO) << __func__ << " :Start to get Fast Pair characteristic.";
key_based_characteristic_ = GetCharacteristicsByUUIDs(
kKeyBasedCharacteristicUuidV1, kKeyBasedCharacteristicUuidV2);
if (!key_based_characteristic_.has_value()) {
NotifyInitializedError(
PairFailure::kKeyBasedPairingCharacteristicDiscovery);
return;
}
passkey_characteristic_ = GetCharacteristicsByUUIDs(
kPasskeyCharacteristicUuidV1, kPasskeyCharacteristicUuidV2);
if (!passkey_characteristic_.has_value()) {
NotifyInitializedError(PairFailure::kPasskeyCharacteristicDiscovery);
return;
}
account_key_characteristic_ = GetCharacteristicsByUUIDs(
kAccountKeyCharacteristicUuidV1, kAccountKeyCharacteristicUuidV2);
if (!account_key_characteristic_.has_value()) {
NotifyInitializedError(PairFailure::kAccountKeyCharacteristicDiscovery);
return;
}
is_initialized_ = true;
std::move(on_gatt_initialized_callback_)(std::nullopt);
}
std::optional<GattCharacteristic>
FastPairGattServiceClientImpl::GetCharacteristicsByUUIDs(const Uuid& uuidV1,
const Uuid& uuidV2) {
// Default to V2 device to match Android implementation.
std::optional<GattCharacteristic> characteristics =
gatt_client_->GetCharacteristic(kFastPairServiceUuid, uuidV2);
if (characteristics.has_value()) {
return characteristics;
}
return gatt_client_->GetCharacteristic(kFastPairServiceUuid, uuidV1);
}
void FastPairGattServiceClientImpl::OnGattServiceDiscoveryTimeout() {
NEARBY_LOGS(INFO) << __func__
<< ": reattempting from previous GATT connection failure: "
<< PairFailure::kGattServiceDiscoveryTimeout;
AttemptGattConnection();
}
std::array<uint8_t, kAesBlockByteSize>
@@ -272,10 +222,7 @@ void FastPairGattServiceClientImpl::WriteRequestAsync(
absl::string_view seekers_address,
const FastPairDataEncryptor& fast_pair_data_encryptor,
WriteResponseCallback callback) {
CHECK(is_initialized_);
CHECK(!key_based_write_response_callback_);
// The key based request should only ever be written once
DCHECK(!is_key_based_notification_subscribed_);
key_based_write_response_callback_ = std::move(callback);
@@ -296,61 +243,35 @@ void FastPairGattServiceClientImpl::WriteRequestAsync(
data_to_write_vec.insert(data_to_write_vec.end(), public_key_vec.begin(),
public_key_vec.end());
}
// Subscribe the notification once the keybased characteristic's value changed
if (SubscribeKeyBasedCharacteristic()) {
is_key_based_notification_subscribed_ = true;
// Write public address request to the keybased characteristic
WriteKeyBasedCharacteristic(
std::string(data_to_write_vec.begin(), data_to_write_vec.end()));
}
}
bool FastPairGattServiceClientImpl::SubscribeKeyBasedCharacteristic() {
NEARBY_LOGS(INFO) << __func__
<< " :Start to subscribe notification "
"once keybased characteristic changed.";
key_based_subscription_timer_.Start(
kGattOperationTimeout / absl::Milliseconds(1), 0,
absl::bind_front(
&FastPairGattServiceClientImpl::NotifyWriteRequestError, this,
PairFailure::kKeyBasedPairingCharacteristicSubscriptionTimeout));
if (gatt_client_->SetCharacteristicSubscription(
key_based_characteristic_.value(), true,
[this](absl::string_view value) {
FastPairGattServiceClientImpl::OnCharacteristicValueChanged(
key_based_characteristic_.value(), value);
})) {
key_based_subscription_timer_.Stop();
NEARBY_LOGS(INFO)
<< __func__ << ": Successfully subscribe the key based characteristic.";
return true;
// Write public address request to the keybased characteristic and get
// response.
WriteKeyBasedCharacteristic(
std::string(data_to_write_vec.begin(), data_to_write_vec.end()));
}
NEARBY_LOGS(INFO) << __func__
<< ": Failed to subscribe the key based characteristic.";
NotifyWriteRequestError(
PairFailure::kKeyBasedPairingCharacteristicSubscription);
return false;
}
void FastPairGattServiceClientImpl::WriteKeyBasedCharacteristic(
absl::string_view request) {
NEARBY_LOGS(INFO) << __func__ << " :Start to write keybased characteristic.";
key_based_write_request_timer_.Start(
kGattOperationTimeout / absl::Milliseconds(1), 0,
absl::bind_front(&FastPairGattServiceClientImpl::NotifyWriteRequestError,
this, PairFailure::kKeyBasedPairingResponseTimeout));
if (gatt_client_->WriteCharacteristic(
key_based_characteristic_.value(), request,
api::ble_v2::GattClient::WriteType::kWithResponse)) {
NEARBY_LOGS(INFO) << __func__
<< ": Successfully write the key basedcharacteristic.";
return;
}
NEARBY_LOGS(INFO) << __func__
<< ": Failed to write the key based characteristic ";
NotifyWriteRequestError(PairFailure::kKeyBasedPairingCharacteristicWrite);
gatt_client_->CallRemoteFunction(
kKeyBasedCharacteristicIndex, request,
[this](absl::StatusOr<absl::string_view> response) {
if (response.ok()) {
NEARBY_LOGS(INFO)
<< __func__ << ": key based characteristic value changed.";
NotifyWriteRequestResult(*response);
} else {
NEARBY_LOGS(INFO)
<< __func__ << ": Failed to write the key based characteristic: "
<< response.status();
PairFailure failure =
absl::IsDeadlineExceeded(response.status())
? PairFailure::kKeyBasedPairingResponseTimeout
: PairFailure::kKeyBasedPairingCharacteristicWrite;
NotifyWriteRequestError(failure);
}
});
}
void FastPairGattServiceClientImpl::WritePasskeyAsync(
@@ -367,81 +288,31 @@ void FastPairGattServiceClientImpl::WritePasskeyAsync(
std::vector<uint8_t> data_to_write_vec(data_to_write.begin(),
data_to_write.end());
// Subscribe the notification once the passkey characteristic's value changed
if (SubscribePasskeyCharacteristic()) {
is_passkey_notification_subscribed_ = true;
// Write passkey confirmation request to the passkey characteristic
WritePasskeyCharacteristic(
std::string(data_to_write_vec.begin(), data_to_write_vec.end()));
}
}
bool FastPairGattServiceClientImpl::SubscribePasskeyCharacteristic() {
NEARBY_LOGS(INFO) << __func__
<< " :Start to subscribe notification "
"once passkey characteristic changed.";
passkey_subscription_timer_.Start(
kGattOperationTimeout / absl::Milliseconds(1), 0,
absl::bind_front(&FastPairGattServiceClientImpl::NotifyWritePasskeyError,
this,
PairFailure::kPasskeyCharacteristicSubscriptionTimeout));
if (gatt_client_->SetCharacteristicSubscription(
passkey_characteristic_.value(), true,
[this](absl::string_view value) {
FastPairGattServiceClientImpl::OnCharacteristicValueChanged(
passkey_characteristic_.value(), value);
})) {
passkey_subscription_timer_.Stop();
NEARBY_LOGS(INFO) << __func__
<< ": Successfully subscribe the passkey characteristic.";
return true;
}
NEARBY_LOGS(INFO) << __func__
<< ": Failed to subscribe the passkey characteristic.";
NotifyWritePasskeyError(PairFailure::kPasskeyCharacteristicSubscription);
return false;
}
void FastPairGattServiceClientImpl::WritePasskeyCharacteristic(
absl::string_view request) {
passkey_write_request_timer_.Start(
kGattOperationTimeout / absl::Milliseconds(1), 0,
absl::bind_front(&FastPairGattServiceClientImpl::NotifyWritePasskeyError,
this, PairFailure::kPasskeyResponseTimeout));
if (gatt_client_->WriteCharacteristic(
passkey_characteristic_.value(), request,
api::ble_v2::GattClient::WriteType::kWithResponse)) {
NEARBY_LOGS(INFO) << __func__
<< ": Successfully write the passkey characteristic.";
return;
}
NEARBY_LOGS(INFO) << __func__
<< ": Failed to write the passkey characteristic ";
NotifyWritePasskeyError(PairFailure::kPasskeyPairingCharacteristicWrite);
}
void FastPairGattServiceClientImpl::OnCharacteristicValueChanged(
const GattCharacteristic& characteristic, absl::string_view value) {
// We check that the callbacks still exists still before we run the
// it with the response bytes to handle the case where the callback
// has already been used to notify error. This can happen if the timer for
// fires with an error, and then the write completes successfully after and
// we get response bytes here.
if (characteristic == key_based_characteristic_.value() &&
key_based_write_response_callback_) {
key_based_write_request_timer_.Stop();
NEARBY_LOGS(INFO) << __func__
<< ": key based characteristic value changed.";
std::move(key_based_write_response_callback_)(value,
/*failure=*/std::nullopt);
} else if (characteristic == passkey_characteristic_.value() &&
passkey_write_response_callback_) {
passkey_write_request_timer_.Stop();
NEARBY_LOGS(INFO) << __func__ << ": Passkey characteristic value changed.";
std::move(passkey_write_response_callback_)(value,
/*failure=*/std::nullopt);
}
gatt_client_->CallRemoteFunction(
kPasskeyCharacteristicIndex, request,
[this](absl::StatusOr<absl::string_view> response) {
if (response.ok()) {
NEARBY_LOGS(INFO)
<< __func__ << ": Passkey characteristic value changed.";
NotifyWritePasskeyResult(*response);
} else {
NEARBY_LOGS(INFO)
<< __func__ << ": Failed to write the passkey characteristic "
<< response.status();
PairFailure failure =
absl::IsDeadlineExceeded(response.status())
? PairFailure::kPasskeyResponseTimeout
: PairFailure::kPasskeyPairingCharacteristicWrite;
NotifyWritePasskeyError(failure);
}
});
}
void FastPairGattServiceClientImpl::WriteAccountKey(
@@ -453,28 +324,25 @@ void FastPairGattServiceClientImpl::WriteAccountKey(
CreateAccountKeyBlock();
const std::array<uint8_t, kAesBlockByteSize> data_to_write =
fast_pair_data_encryptor.EncryptBytes(raw_account_key);
account_key_write_request_timer_.Start(
kGattOperationTimeout / absl::Milliseconds(1), 0,
absl::bind_front(
&FastPairGattServiceClientImpl::NotifyWriteAccountKeyError, this,
PairFailure::kAccountKeyCharacteristicWrite));
if (gatt_client_->WriteCharacteristic(
account_key_characteristic_.value(),
std::string(data_to_write.begin(), data_to_write.end()),
api::ble_v2::GattClient::WriteType::kWithResponse)) {
NEARBY_LOGS(INFO) << __func__
<< ": Successfully write the accoutkey characteristic.";
account_key_write_request_timer_.Stop();
std::move(account_key_write_callback_)(
AccountKey(std::string(raw_account_key.begin(), raw_account_key.end())),
/*failure=*/std::nullopt);
return;
}
NEARBY_LOGS(INFO) << __func__
<< ": Failed to write the accoutkey characteristic ";
NotifyWriteAccountKeyError(PairFailure::kAccountKeyCharacteristicWrite);
gatt_client_->WriteCharacteristic(
kAccountKeyCharacteristicIndex,
std::string(data_to_write.begin(), data_to_write.end()),
api::ble_v2::GattClient::WriteType::kWithResponse,
[this, account_key =
std::string(raw_account_key.begin(), raw_account_key.end())](
absl::Status status) {
if (status.ok()) {
NEARBY_LOGS(INFO)
<< __func__
<< ": Successfully write the accoutkey characteristic.";
NotifyWriteAccountKeyResult(AccountKey(account_key));
} else {
NEARBY_LOGS(INFO)
<< __func__ << ": Failed to write the passkey characteristic ";
NotifyWriteAccountKeyError(
PairFailure::kAccountKeyCharacteristicWrite);
}
});
}
void FastPairGattServiceClientImpl::NotifyInitializedError(
@@ -482,47 +350,51 @@ void FastPairGattServiceClientImpl::NotifyInitializedError(
NEARBY_LOGS(VERBOSE) << __func__ << failure;
ClearCurrentState();
if (on_gatt_initialized_callback_) {
NEARBY_LOGS(VERBOSE) << __func__ << "Executing initialized callback";
std::move(on_gatt_initialized_callback_)(failure);
}
executor_->Execute("init-error", [this, failure]() {
if (on_gatt_initialized_callback_) {
NEARBY_LOGS(VERBOSE) << __func__ << "Executing initialized callback";
std::move(on_gatt_initialized_callback_)(failure);
}
});
}
void FastPairGattServiceClientImpl::NotifyWriteRequestError(
PairFailure failure) {
void FastPairGattServiceClientImpl::NotifyWriteRequestResult(
absl::string_view value, std::optional<PairFailure> failure) {
NEARBY_LOGS(VERBOSE) << __func__;
key_based_write_request_timer_.Stop();
DCHECK(key_based_write_response_callback_);
std::move(key_based_write_response_callback_)("", failure);
executor_->Execute(
"key-based-response", [this, value = std::string(value), failure]() {
if (key_based_write_response_callback_) {
std::move(key_based_write_response_callback_)(value, failure);
}
});
}
void FastPairGattServiceClientImpl::NotifyWritePasskeyError(
PairFailure failure) {
void FastPairGattServiceClientImpl::NotifyWritePasskeyResult(
absl::string_view value, std::optional<PairFailure> failure) {
NEARBY_LOGS(VERBOSE) << __func__;
passkey_write_request_timer_.Stop();
DCHECK(passkey_write_response_callback_);
std::move(passkey_write_response_callback_)("", failure);
executor_->Execute(
"passkey-response", [this, value = std::string(value), failure]() {
if (passkey_write_response_callback_) {
std::move(passkey_write_response_callback_)(value, failure);
}
});
}
void FastPairGattServiceClientImpl::NotifyWriteAccountKeyError(
PairFailure failure) {
void FastPairGattServiceClientImpl::NotifyWriteAccountKeyResult(
std::optional<AccountKey> account_key, std::optional<PairFailure> failure) {
NEARBY_LOGS(VERBOSE) << __func__;
account_key_write_request_timer_.Stop();
DCHECK(account_key_write_callback_);
std::move(account_key_write_callback_)(std::nullopt, failure);
executor_->Execute("passkey-response", [this, account_key, failure]() {
if (account_key_write_callback_) {
std::move(account_key_write_callback_)(account_key, failure);
}
});
}
void FastPairGattServiceClientImpl::ClearCurrentState() {
gatt_client_.reset();
key_based_characteristic_ = std::nullopt;
passkey_characteristic_ = std::nullopt;
account_key_characteristic_ = std::nullopt;
gatt_service_discovery_timer_.Stop();
passkey_subscription_timer_.Stop();
key_based_subscription_timer_.Stop();
passkey_write_request_timer_.Stop();
key_based_write_request_timer_.Stop();
account_key_write_request_timer_.Stop();
if (gatt_client_ != nullptr) {
gatt_client_->Stop();
defunct_gatt_client_ = std::move(gatt_client_);
}
}
} // namespace fastpair
@@ -26,12 +26,11 @@
#include "fastpair/common/pair_failure.h"
#include "fastpair/handshake/fast_pair_gatt_service_client.h"
#include "fastpair/internal/mediums/mediums.h"
#include "internal/platform/ble_v2.h"
#include "internal/platform/timer_impl.h"
#include "fastpair/internal/mediums/robust_gatt_client.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
using GattCharacteristic = api::ble_v2::GattCharacteristic;
// This class is responsible for connecting to the Fast Pair GATT service for a
// device and invoking a callback when ready, or when an error is discovered
@@ -41,7 +40,8 @@ class FastPairGattServiceClientImpl : public FastPairGattServiceClient {
class Factory {
public:
static std::unique_ptr<FastPairGattServiceClient> Create(
const FastPairDevice& device, Mediums& mediums);
const FastPairDevice& device, Mediums& mediums,
SingleThreadExecutor* executor);
static void SetFactoryForTesting(Factory* test_factory);
protected:
@@ -53,7 +53,8 @@ class FastPairGattServiceClientImpl : public FastPairGattServiceClient {
};
explicit FastPairGattServiceClientImpl(const FastPairDevice& device,
Mediums& mediums);
Mediums& mediums,
SingleThreadExecutor* executor);
FastPairGattServiceClientImpl(const FastPairGattServiceClientImpl&) = delete;
FastPairGattServiceClientImpl& operator=(
const FastPairGattServiceClientImpl&) = delete;
@@ -78,23 +79,22 @@ class FastPairGattServiceClientImpl : public FastPairGattServiceClient {
const FastPairDataEncryptor& fast_pair_data_encryptor,
WriteAccountkeyCallback write_accountkey_callback) override;
// Allows tests to modify GATT operation timeouts.
RobustGattClient::ConnectionParams& GetConnectionParams() {
return gatt_connection_params_;
}
private:
// Attempt to create a GATT connection with the device. This method may be
// called multiple times.
void AttemptGattConnection();
void CreateGattConnection();
void DiscoverServiceAndCharacteristics();
void GetFastPairGattCharacteristics();
std::optional<GattCharacteristic> GetCharacteristicsByUUIDs(
const Uuid& uuidV1, const Uuid& uuidV2);
// Operations on KeyBased Characteristic
// Creates a data vector based on parameter information.
std::array<uint8_t, kAesBlockByteSize> CreateRequest(
uint8_t message_type, uint8_t flags, absl::string_view provider_address,
absl::string_view seekers_address);
// Subscribe notification when KeyBased Characteristic value changes
bool SubscribeKeyBasedCharacteristic();
// Write request to KeyBased Characteristic
void WriteKeyBasedCharacteristic(absl::string_view request);
@@ -102,15 +102,9 @@ class FastPairGattServiceClientImpl : public FastPairGattServiceClient {
// Creates a data vector based on parameter information.
std::array<uint8_t, kAesBlockByteSize> CreatePasskeyBlock(
uint8_t message_type, uint32_t passkey);
// Subscribe notification when Passkey Characteristic value changes
bool SubscribePasskeyCharacteristic();
// Write request to Passkey Characteristic
void WritePasskeyCharacteristic(absl::string_view request);
// Callback is triggered when characteristic value changes
void OnCharacteristicValueChanged(const GattCharacteristic& characteristic,
absl::string_view value);
// Operations on Account Key Characteristic
// Creates an Account key.
std::array<uint8_t, kAesBlockByteSize> CreateAccountKeyBlock();
@@ -120,15 +114,26 @@ class FastPairGattServiceClientImpl : public FastPairGattServiceClient {
void NotifyInitializedError(PairFailure failure);
// Invokes the write response callback with the proper PairFailure on a
// write error.
void NotifyWriteRequestError(PairFailure failure);
void NotifyWritePasskeyError(PairFailure failure);
void NotifyWriteAccountKeyError(PairFailure failure);
void NotifyWriteRequestError(PairFailure failure) {
NotifyWriteRequestResult("", failure);
}
void NotifyWriteRequestResult(absl::string_view value,
std::optional<PairFailure> = std::nullopt);
void NotifyWritePasskeyError(PairFailure failure) {
NotifyWritePasskeyResult("", failure);
}
void NotifyWritePasskeyResult(absl::string_view value,
std::optional<PairFailure> = std::nullopt);
void NotifyWriteAccountKeyError(PairFailure failure) {
NotifyWriteAccountKeyResult(std::nullopt, failure);
}
void NotifyWriteAccountKeyResult(
std::optional<AccountKey> account_key,
std::optional<PairFailure> failure = std::nullopt);
void ClearCurrentState();
// Timers
TimerImpl gatt_service_discovery_timer_;
TimerImpl key_based_subscription_timer_;
TimerImpl passkey_subscription_timer_;
TimerImpl key_based_write_request_timer_;
TimerImpl passkey_write_request_timer_;
@@ -143,21 +148,13 @@ class FastPairGattServiceClientImpl : public FastPairGattServiceClient {
WriteResponseCallback passkey_write_response_callback_;
WriteAccountkeyCallback account_key_write_callback_;
// Fast Pair Characteristic
std::optional<GattCharacteristic> key_based_characteristic_;
std::optional<GattCharacteristic> passkey_characteristic_;
std::optional<GattCharacteristic> account_key_characteristic_;
bool is_key_based_notification_subscribed_ = false;
bool is_passkey_notification_subscribed_ = false;
// Initialize with zero failures.
int num_gatt_connection_attempts_ = 0;
bool is_initialized_ = false;
std::string device_address_;
std::unique_ptr<GattClient> gatt_client_;
std::unique_ptr<RobustGattClient> gatt_client_;
std::unique_ptr<RobustGattClient> defunct_gatt_client_;
RobustGattClient::ConnectionParams gatt_connection_params_;
Mediums& mediums_;
SingleThreadExecutor* executor_;
};
} // namespace fastpair
} // namespace nearby
@@ -39,6 +39,7 @@
#include "internal/platform/count_down_latch.h"
#include "internal/platform/implementation/system_clock.h"
#include "internal/platform/medium_environment.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
@@ -81,15 +82,14 @@ constexpr std::array<uint8_t, 64> kPublicKey = {
class MediumEnvironmentStarter {
public:
MediumEnvironmentStarter() {
MediumEnvironment::Instance().Start({.use_simulated_clock = true});
}
MediumEnvironmentStarter() { MediumEnvironment::Instance().Start(); }
~MediumEnvironmentStarter() { MediumEnvironment::Instance().Stop(); }
};
struct CharacteristicData {
// Write result returned to the gatt client.
absl::Status write_result;
std::optional<std::string> notify_response;
};
class FastPairGattServiceClientTest : public testing::Test {
@@ -114,11 +114,20 @@ class FastPairGattServiceClientTest : public testing::Test {
return;
}
callback(it->second.write_result);
if (it->second.notify_response.has_value()) {
NEARBY_LOGS(INFO) << "Notify seeker";
auto ignored = gatt_server_->NotifyCharacteristicChanged(
characteristic, false,
ByteArray(*it->second.notify_response));
}
}});
provider_address_ = *gatt_server_->GetBlePeripheral().GetAddress();
device_ = std::make_unique<FastPairDevice>(
kMetadataId, provider_address_, Protocol::kFastPairInitialPairing);
}
void TearDown() override {
executor_.Shutdown();
key_based_characteristic_ = std::nullopt;
passkey_characteristic_ = std::nullopt;
accountkey_characteristic_ = std::nullopt;
@@ -168,16 +177,24 @@ class FastPairGattServiceClientTest : public testing::Test {
absl::OkStatus();
}
void InitializeFastPairGattServiceClient() {
FastPairDevice device(kMetadataId, provider_address_,
Protocol::kFastPairInitialPairing);
Mediums mediums;
gatt_client_ =
FastPairGattServiceClientImpl::Factory::Create(device, mediums);
void InitializeFastPairGattServiceClient(bool short_timeouts = false) {
CountDownLatch latch(1);
gatt_client_ = FastPairGattServiceClientImpl::Factory::Create(
*device_, mediums_, &executor_);
if (short_timeouts) {
FastPairGattServiceClientImpl* impl =
dynamic_cast<FastPairGattServiceClientImpl*>(gatt_client_.get());
auto& params = impl->GetConnectionParams();
params.gatt_operation_timeout = absl::Seconds(1);
params.gatt_operation_timeout = absl::Seconds(1);
params.max_back_off = absl::Milliseconds(500);
}
gatt_client_->InitializeGattConnection(
[this](std::optional<PairFailure> failure) {
[&](std::optional<PairFailure> failure) {
initalized_failure_ = failure;
latch.CountDown();
});
latch.Await();
}
std::optional<PairFailure> GetInitializedCallbackResult() {
@@ -191,43 +208,40 @@ class FastPairGattServiceClientTest : public testing::Test {
std::optional<PairFailure> GetWriteCallbackResult() { return write_failure_; }
void WriteRequestToKeyBased() {
CountDownLatch latch(1);
gatt_client_->WriteRequestAsync(
kMessageType, kFlags, provider_address_, /* Seeker Address*/ "",
*fast_pair_data_encryptor_,
[&](absl::string_view response, std::optional<PairFailure> failure) {
EXPECT_FALSE(response.empty());
WriteTestCallback(failure);
latch.CountDown();
});
latch.Await();
}
void WriteRequestToPasskey() {
CountDownLatch latch(1);
gatt_client_->WritePasskeyAsync(
kSeekerPasskey, kPasskey, *fast_pair_data_encryptor_,
[&](absl::string_view response, std::optional<PairFailure> failure) {
EXPECT_FALSE(response.empty());
WriteTestCallback(failure);
latch.CountDown();
});
latch.Await();
}
void WriteRequestToAccountkey() {
CountDownLatch latch(1);
gatt_client_->WriteAccountKey(*fast_pair_data_encryptor_,
[&](std::optional<AccountKey> account_key,
std::optional<PairFailure> failure) {
EXPECT_TRUE(account_key.has_value());
WriteTestCallback(failure);
latch.CountDown();
});
}
absl::Status TriggerKeyBasedGattChanged() {
return gatt_server_->NotifyCharacteristicChanged(
key_based_characteristic_.value(), false,
ByteArray(std::string(kKeyBasedCharacteristicAdvertisementByte)));
}
absl::Status TriggerPasskeyGattChanged() {
return gatt_server_->NotifyCharacteristicChanged(
passkey_characteristic_.value(), false,
ByteArray(std::string(kPasskeyharacteristicAdvertisementByte)));
latch.Await();
}
void SetKeyBaseCharacteristicsWriteResultToFailure() {
@@ -247,6 +261,7 @@ class FastPairGattServiceClientTest : public testing::Test {
protected:
MediumEnvironmentStarter env_;
SingleThreadExecutor executor_;
BluetoothAdapter provider_adapter_;
BleV2Medium provider_ble_{provider_adapter_};
std::unique_ptr<GattClient> internal_gatt_client_;
@@ -254,8 +269,8 @@ class FastPairGattServiceClientTest : public testing::Test {
std::unique_ptr<GattServer> gatt_server_;
std::string provider_address_;
std::unique_ptr<FakeFastPairDataEncryptor> fast_pair_data_encryptor_;
private:
std::unique_ptr<FastPairDevice> device_;
Mediums mediums_;
std::optional<PairFailure> initalized_failure_ = PairFailure::kUnknown;
std::optional<PairFailure> write_failure_ = PairFailure::kUnknown;
Property properties_ = Property::kWrite | Property::kNotify;
@@ -284,8 +299,9 @@ TEST_F(FastPairGattServiceClientTest, SuccessfulWriteKeyBaseCharacteristics) {
EXPECT_EQ(GetWriteCallbackResult(), PairFailure::kUnknown);
InsertCorrectGattCharacteristics();
InitializeFastPairGattServiceClient();
characteristics_[*key_based_characteristic_].notify_response =
std::string(kKeyBasedCharacteristicAdvertisementByte);
WriteRequestToKeyBased();
EXPECT_OK(TriggerKeyBasedGattChanged());
EXPECT_EQ(GetWriteCallbackResult(), std::nullopt);
}
@@ -293,8 +309,11 @@ TEST_F(FastPairGattServiceClientTest, SuccessfulWritePasskeyCharacteristics) {
EXPECT_EQ(GetWriteCallbackResult(), PairFailure::kUnknown);
InsertCorrectGattCharacteristics();
InitializeFastPairGattServiceClient();
characteristics_[*passkey_characteristic_].notify_response =
std::string(kPasskeyharacteristicAdvertisementByte);
WriteRequestToPasskey();
EXPECT_OK(TriggerPasskeyGattChanged());
EXPECT_EQ(GetWriteCallbackResult(), std::nullopt);
}
@@ -361,21 +380,20 @@ TEST_F(FastPairGattServiceClientTest, FailedToWriteAccountKey) {
}
TEST_F(FastPairGattServiceClientTest, KeyBasedPairingResponseTimeout) {
EXPECT_EQ(GetWriteCallbackResult(), PairFailure::kUnknown);
InsertCorrectGattCharacteristics();
InitializeFastPairGattServiceClient();
InitializeFastPairGattServiceClient(/*short_timeouts=*/true);
CountDownLatch latch(1);
// Seeker writes to Key based pairing characteristic but the provider does not
// respond.
gatt_client_->WriteRequestAsync(
kMessageType, kFlags, provider_address_, kSeekerAddress,
*fast_pair_data_encryptor_,
[&](absl::string_view response, std::optional<PairFailure> failure) {
WriteTestCallback(failure);
EXPECT_EQ(failure, PairFailure::kKeyBasedPairingResponseTimeout);
latch.CountDown();
});
SystemClock::Sleep(kGattOperationTimeout);
latch.Await();
EXPECT_EQ(GetWriteCallbackResult(),
PairFailure::kKeyBasedPairingResponseTimeout);
}
TEST_F(FastPairGattServiceClientTest, PasskeyResponseTimeout) {
@@ -26,16 +26,18 @@
#include "fastpair/handshake/fast_pair_gatt_service_client_impl.h"
#include "internal/base/bluetooth_address.h"
#include "internal/platform/logging.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
FastPairHandshakeImpl::FastPairHandshakeImpl(FastPairDevice& device,
Mediums& mediums,
OnCompleteCallback on_complete)
OnCompleteCallback on_complete,
SingleThreadExecutor* executor)
: FastPairHandshake(std::move(on_complete), nullptr, nullptr) {
fast_pair_gatt_service_client_ =
FastPairGattServiceClientImpl::Factory::Create(device, mediums);
FastPairGattServiceClientImpl::Factory::Create(device, mediums, executor);
fast_pair_gatt_service_client_->InitializeGattConnection(
[&](std::optional<PairFailure> failure) {
OnGattClientInitializedCallback(device, failure);
@@ -30,7 +30,8 @@ namespace fastpair {
class FastPairHandshakeImpl : public FastPairHandshake {
public:
explicit FastPairHandshakeImpl(FastPairDevice& device, Mediums& mediums,
OnCompleteCallback on_complete);
OnCompleteCallback on_complete,
SingleThreadExecutor* executor);
FastPairHandshakeImpl(const FastPairHandshakeImpl&) = delete;
FastPairHandshakeImpl& operator=(const FastPairHandshakeImpl&) = delete;
@@ -36,6 +36,7 @@
#include "internal/platform/byte_array.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/medium_environment.h"
#include "internal/platform/single_thread_executor.h"
namespace nearby {
namespace fastpair {
@@ -84,6 +85,7 @@ struct CharacteristicData {
class FastPairHandshakeImplTest : public testing::Test {
public:
void TearDown() override {
executor_.Shutdown();
repository_.reset();
key_based_characteristic_ = std::nullopt;
passkey_characteristic_ = std::nullopt;
@@ -181,10 +183,13 @@ class FastPairHandshakeImplTest : public testing::Test {
protected:
MediumEnvironmentStarter env_;
SingleThreadExecutor executor_;
std::unique_ptr<FastPairHandshake> handshake_;
BluetoothAdapter provider_adapter_;
BleV2Medium provider_ble_{provider_adapter_};
std::string provider_address_;
Mediums mediums_;
std::unique_ptr<FastPairDevice> fast_pair_device_;
private:
absl::flat_hash_map<GattCharacteristic, CharacteristicData> characteristics_;
@@ -205,18 +210,18 @@ TEST_F(FastPairHandshakeImplTest, Success) {
});
SetUpFastPairRepository();
InsertCorrectGattCharacteristics();
FastPairDevice device(kMetadataId, provider_address_,
Protocol::kFastPairInitialPairing);
fast_pair_device_ = std::make_unique<FastPairDevice>(
kMetadataId, provider_address_, Protocol::kFastPairInitialPairing);
CountDownLatch latch(1);
Mediums mediums;
handshake_ = std::make_unique<FastPairHandshakeImpl>(
device, mediums,
*fast_pair_device_, mediums_,
[&](FastPairDevice& callback_device, std::optional<PairFailure> failure) {
EXPECT_EQ(&device, &callback_device);
EXPECT_EQ(device.GetPublicAddress(), kPublicAddress);
EXPECT_EQ(fast_pair_device_.get(), &callback_device);
EXPECT_EQ(fast_pair_device_->GetPublicAddress(), kPublicAddress);
EXPECT_FALSE(failure.has_value());
latch.CountDown();
});
},
&executor_);
latch.Await();
EXPECT_TRUE(notified);
EXPECT_TRUE(handshake_->completed_successfully());
@@ -229,17 +234,17 @@ TEST_F(FastPairHandshakeImplTest, GattError) {
EXPECT_OK(TriggerKeyBasedGattChanged());
});
SetUpFastPairRepository();
FastPairDevice device(kMetadataId, provider_address_,
Protocol::kFastPairInitialPairing);
fast_pair_device_ = std::make_unique<FastPairDevice>(
kMetadataId, provider_address_, Protocol::kFastPairInitialPairing);
CountDownLatch latch(1);
Mediums mediums;
handshake_ = std::make_unique<FastPairHandshakeImpl>(
device, mediums,
*fast_pair_device_, mediums_,
[&](FastPairDevice& callback_device, std::optional<PairFailure> failure) {
EXPECT_EQ(&device, &callback_device);
EXPECT_EQ(fast_pair_device_.get(), &callback_device);
EXPECT_EQ(failure.value(), PairFailure::kCreateGattConnection);
latch.CountDown();
});
},
&executor_);
latch.Await();
EXPECT_FALSE(notified);
EXPECT_FALSE(handshake_->completed_successfully());
@@ -253,17 +258,17 @@ TEST_F(FastPairHandshakeImplTest, DataEncryptorCreateError) {
});
FailedFastPairRepository();
InsertCorrectGattCharacteristics();
FastPairDevice device(kMetadataId, provider_address_,
Protocol::kFastPairInitialPairing);
fast_pair_device_ = std::make_unique<FastPairDevice>(
kMetadataId, provider_address_, Protocol::kFastPairInitialPairing);
CountDownLatch latch(1);
Mediums mediums;
handshake_ = std::make_unique<FastPairHandshakeImpl>(
device, mediums,
*fast_pair_device_, mediums_,
[&](FastPairDevice& callback_device, std::optional<PairFailure> failure) {
EXPECT_EQ(&device, &callback_device);
EXPECT_EQ(fast_pair_device_.get(), &callback_device);
EXPECT_EQ(failure.value(), PairFailure::kDataEncryptorRetrieval);
latch.CountDown();
});
},
&executor_);
latch.Await();
EXPECT_FALSE(notified);
EXPECT_FALSE(handshake_->completed_successfully());
@@ -273,18 +278,18 @@ TEST_F(FastPairHandshakeImplTest, WriteResponseError) {
StartGattServer([]() {});
SetUpFastPairRepository();
InsertCorrectGattCharacteristics();
FastPairDevice device(kMetadataId, provider_address_,
Protocol::kFastPairInitialPairing);
fast_pair_device_ = std::make_unique<FastPairDevice>(
kMetadataId, provider_address_, Protocol::kFastPairInitialPairing);
CountDownLatch latch(1);
Mediums mediums;
handshake_ = std::make_unique<FastPairHandshakeImpl>(
device, mediums,
*fast_pair_device_, mediums_,
[&](FastPairDevice& callback_device, std::optional<PairFailure> failure) {
EXPECT_EQ(&device, &callback_device);
EXPECT_EQ(fast_pair_device_.get(), &callback_device);
EXPECT_EQ(failure.value(),
PairFailure::kKeyBasedPairingResponseTimeout);
latch.CountDown();
});
},
&executor_);
latch.Await();
EXPECT_FALSE(handshake_->completed_successfully());
}
@@ -297,18 +302,18 @@ TEST_F(FastPairHandshakeImplTest, WriteResponseWrongSize) {
});
SetUpFastPairRepository();
InsertCorrectGattCharacteristics();
FastPairDevice device(kMetadataId, provider_address_,
Protocol::kFastPairInitialPairing);
fast_pair_device_ = std::make_unique<FastPairDevice>(
kMetadataId, provider_address_, Protocol::kFastPairInitialPairing);
CountDownLatch latch(1);
Mediums mediums;
handshake_ = std::make_unique<FastPairHandshakeImpl>(
device, mediums,
*fast_pair_device_, mediums_,
[&](FastPairDevice& callback_device, std::optional<PairFailure> failure) {
EXPECT_EQ(&device, &callback_device);
EXPECT_EQ(fast_pair_device_.get(), &callback_device);
EXPECT_EQ(failure.value(),
PairFailure::kKeybasedPairingResponseDecryptFailure);
latch.CountDown();
});
},
&executor_);
latch.Await();
EXPECT_TRUE(notified);
EXPECT_FALSE(handshake_->completed_successfully());
@@ -322,18 +327,18 @@ TEST_F(FastPairHandshakeImplTest, ParseResponseError) {
});
SetUpFastPairRepository();
InsertCorrectGattCharacteristics();
FastPairDevice device(kMetadataId, provider_address_,
Protocol::kFastPairInitialPairing);
fast_pair_device_ = std::make_unique<FastPairDevice>(
kMetadataId, provider_address_, Protocol::kFastPairInitialPairing);
CountDownLatch latch(1);
Mediums mediums;
handshake_ = std::make_unique<FastPairHandshakeImpl>(
device, mediums,
*fast_pair_device_, mediums_,
[&](FastPairDevice& callback_device, std::optional<PairFailure> failure) {
EXPECT_EQ(&device, &callback_device);
EXPECT_EQ(fast_pair_device_.get(), &callback_device);
EXPECT_EQ(failure.value(),
PairFailure::kKeybasedPairingResponseDecryptFailure);
latch.CountDown();
});
},
&executor_);
latch.Await();
EXPECT_TRUE(notified);
EXPECT_FALSE(handshake_->completed_successfully());
@@ -87,14 +87,15 @@ void FastPairHandshakeLookup::Clear() {
}
FastPairHandshake* FastPairHandshakeLookup::Create(
FastPairDevice& device, Mediums& mediums, OnCompleteCallback on_complete) {
FastPairDevice& device, Mediums& mediums, OnCompleteCallback on_complete,
SingleThreadExecutor* executor) {
absl::MutexLock lock(&mutex_);
auto it = fast_pair_handshakes_.emplace(
&device, g_test_create_function.has_value()
? g_test_create_function.value()(device, mediums,
std::move(on_complete))
: std::make_unique<FastPairHandshakeImpl>(
device, mediums, std::move(on_complete)));
device, mediums, std::move(on_complete), executor));
DCHECK(it.second);
return it.first->second.get();
}
@@ -71,7 +71,8 @@ class FastPairHandshakeLookup {
// already exists.
// Returns the existing instance if there is one.
FastPairHandshake* Create(FastPairDevice& device, Mediums& mediums,
OnCompleteCallback on_complete);
OnCompleteCallback on_complete,
SingleThreadExecutor* executor);
protected:
// Constructor/destructor of singleton object should not be public
@@ -50,6 +50,8 @@ class FastPairHandshakeLookupTest : public ::testing::Test {
~FastPairHandshakeLookupTest() override { delete device_; }
void TearDown() override { executor_.Shutdown(); }
void CreateFastPairHandshkeInstanceForDevice(FastPairDevice& device) {
CountDownLatch latch(1);
Mediums mediums;
@@ -59,12 +61,14 @@ class FastPairHandshakeLookupTest : public ::testing::Test {
EXPECT_EQ(&device, &cb_device);
EXPECT_TRUE(failure.has_value());
latch.CountDown();
}));
},
&executor_));
latch.Await();
}
protected:
MediumEnvironmentStarter env_;
SingleThreadExecutor executor_;
BluetoothAdapter adapter_;
BleV2Medium ble_{adapter_};
std::string provider_address_;
+7 -4
View File
@@ -16,6 +16,7 @@
#include <memory>
#include <string>
#include <utility>
#include "internal/platform/mutex_lock.h"
@@ -33,8 +34,9 @@ bool BleV2::IsAvailableLocked() const {
return medium_.IsValid() && adapter_.IsValid() && adapter_.IsEnabled();
}
std::unique_ptr<GattClient> BleV2::ConnectToGattServer(
absl::string_view ble_address) {
std::unique_ptr<RobustGattClient> BleV2::ConnectToGattServer(
absl::string_view ble_address, RobustGattClient::ConnectionParams params,
RobustGattClient::ConnectionStatusCallback connection_status_callback) {
MutexLock lock(&mutex_);
if (!radio_.IsEnabled()) {
NEARBY_LOGS(INFO)
@@ -50,8 +52,9 @@ std::unique_ptr<GattClient> BleV2::ConnectToGattServer(
BleV2Peripheral v2_peripheral =
medium_.GetRemotePeripheral(std::string(ble_address));
return medium_.ConnectToGattServer(v2_peripheral,
api::ble_v2::TxPowerLevel::kUnknown, {});
return std::make_unique<RobustGattClient>(
medium_, v2_peripheral, std::move(params),
std::move(connection_status_callback));
}
} // namespace fastpair
} // namespace nearby
+6 -2
View File
@@ -16,8 +16,11 @@
#define THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_MEDIUMS_BLE_V2_H_
#include <memory>
#include <string>
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/internal/mediums/bluetooth_radio.h"
#include "fastpair/internal/mediums/robust_gatt_client.h"
#include "internal/platform/ble_v2.h"
#include "internal/platform/mutex.h"
#include "internal/platform/mutex_lock.h"
@@ -36,8 +39,9 @@ class BleV2 {
bool IsAvailable() const ABSL_LOCKS_EXCLUDED(mutex_);
// Returns a new GattClient connection to a gatt server.
std::unique_ptr<GattClient> ConnectToGattServer(
absl::string_view ble_address);
std::unique_ptr<RobustGattClient> ConnectToGattServer(
absl::string_view ble_address, RobustGattClient::ConnectionParams params,
RobustGattClient::ConnectionStatusCallback connection_status_callback);
private:
// Same as IsAvailable(), but must be called with mutex_ held.
+2 -2
View File
@@ -31,14 +31,14 @@ TEST(BleV2Test, IsAvailable) {
TEST(BleV2Test, CanConnectToGattServer) {
BluetoothRadio radio;
BleV2 bleV2(radio);
EXPECT_TRUE(bleV2.ConnectToGattServer("bleaddress"));
EXPECT_TRUE(bleV2.ConnectToGattServer("bleaddress", {}, nullptr));
}
TEST(BleV2Test, CannotConnectToGattServer) {
BluetoothRadio radio;
BleV2 bleV2(radio);
EXPECT_TRUE(radio.Disable());
EXPECT_FALSE(bleV2.ConnectToGattServer("bleaddress"));
EXPECT_FALSE(bleV2.ConnectToGattServer("bleaddress", {}, nullptr));
}
} // namespace
+2 -1
View File
@@ -24,7 +24,8 @@ TEST(MediumTest, ConstructorWorks) {
Mediums medium;
EXPECT_TRUE(medium.GetBluetoothRadio().IsAdapterValid());
EXPECT_FALSE(medium.GetBle().IsScanning());
EXPECT_TRUE(medium.GetBleV2().ConnectToGattServer("ble_address"));
EXPECT_TRUE(
medium.GetBleV2().ConnectToGattServer("ble_address", {}, nullptr));
EXPECT_TRUE(medium.GetBluetoothClassic().IsAvailable());
}
} // namespace
@@ -104,7 +104,8 @@ void FastPairPairerImpl::StartPairing() {
"pairing with device.";
NotifyPairingFailed(PairFailure::kPairingTimeout);
});
InitiatePairing();
pairing_job_ = std::make_unique<SingleThreadExecutor>();
pairing_job_->Execute("pair", [this]() { InitiatePairing(); });
break;
case Protocol::kFastPairRetroactivePairing:
// Because the devices are already paired, we will directly write an
@@ -111,6 +111,7 @@ class FastPairPairerImpl : public FastPairPairer {
OnPairingCompletedCallback on_pairing_completed_cb_
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
TimerImpl initiate_pairing_timer_;
std::unique_ptr<SingleThreadExecutor> pairing_job_;
};
} // namespace fastpair
@@ -110,6 +110,8 @@ class FastPairPairerImplTest : public testing::Test {
void TearDown() override {
env_.Sync(false);
executor_.Shutdown();
fast_pair_pairer_.reset();
FastPairHandshakeLookup::GetInstance()->Clear();
mediums_.reset();
device_.reset();
repository_.reset();
@@ -160,7 +162,8 @@ class FastPairPairerImplTest : public testing::Test {
EXPECT_EQ(device_.get(), &cb_device);
EXPECT_EQ(failure, std::nullopt);
latch.CountDown();
}));
},
&executor_));
latch.Await();
EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(device_.get()));
EXPECT_TRUE(handshake_->completed_successfully());
@@ -179,7 +182,8 @@ class FastPairPairerImplTest : public testing::Test {
std::optional<PairFailure> failure) {
callback(callback_device, failure);
latch.CountDown();
});
},
&executor_);
handshake_ = handshake.get();
latch.Await();
return handshake;
+2 -1
View File
@@ -123,7 +123,8 @@ void PairerBrokerImpl::CreateHandshake(FastPairDevice& device) {
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
OnHandshakeComplete(cb_device, failure);
});
});
},
executor_);
}
void PairerBrokerImpl::OnHandshakeComplete(FastPairDevice& device,
+44 -45
View File
@@ -30,6 +30,7 @@
#include "fastpair/common/pair_failure.h"
#include "fastpair/handshake/fast_pair_data_encryptor_impl.h"
#include "fastpair/handshake/fast_pair_handshake_impl.h"
#include "fastpair/handshake/fast_pair_handshake_lookup.h"
#include "fastpair/internal/mediums/mediums.h"
#include "fastpair/pairing/fastpair/fast_pair_pairer.h"
#include "fastpair/server_access/fake_fast_pair_repository.h"
@@ -72,17 +73,17 @@ struct CharacteristicData {
class PairerBrokerObserver : public PairerBroker::Observer {
public:
explicit PairerBrokerObserver(PairerBroker* pairer_broker,
CountDownLatch* device_paired_latch,
CountDownLatch* account_key_writed_latch,
CountDownLatch* pairing_completed_latch,
CountDownLatch* pairing_failure_latch)
PairerBrokerObserver(PairerBroker* pairer_broker,
CountDownLatch* device_paired_latch,
CountDownLatch* account_key_writed_latch,
CountDownLatch* pairing_completed_latch,
CountDownLatch* pairing_failure_latch)
: pairer_broker_(pairer_broker),
device_paired_latch_(device_paired_latch),
account_key_writed_latch_(account_key_writed_latch),
pairing_completed_latch_(pairing_completed_latch),
pairing_failure_latch_(pairing_failure_latch) {
pairer_broker->AddObserver(this);
pairer_broker_->AddObserver(this);
}
~PairerBrokerObserver() override { pairer_broker_->RemoveObserver(this); }
@@ -155,6 +156,8 @@ class PairerBrokerImplTest : public testing::Test {
void TearDown() override {
env_.Sync(false);
executor_.Shutdown();
pairer_broker_.reset();
FastPairHandshakeLookup::GetInstance()->Clear();
mediums_.reset();
device_.reset();
repository_.reset();
@@ -205,7 +208,8 @@ class PairerBrokerImplTest : public testing::Test {
EXPECT_EQ(device_.get(), &cb_device);
EXPECT_EQ(failure, std::nullopt);
latch.CountDown();
}));
},
&executor_));
latch.Await();
EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(device_.get()));
EXPECT_TRUE(handshake_->completed_successfully());
@@ -224,7 +228,8 @@ class PairerBrokerImplTest : public testing::Test {
std::optional<PairFailure> failure) {
callback(callback_device, failure);
latch.CountDown();
});
},
&executor_);
handshake_ = handshake.get();
latch.Await();
return handshake;
@@ -385,9 +390,8 @@ class PairerBrokerImplTest : public testing::Test {
std::unique_ptr<Mediums> mediums_;
std::unique_ptr<FastPairDevice> device_;
BluetoothDevice* remote_device_ = nullptr;
std::unique_ptr<FastPairPairer> fast_pair_pairer_;
SingleThreadExecutor executor_;
std::unique_ptr<PairerBrokerImpl> pairer_broker_;
private:
MediumEnvironment& env_{MediumEnvironment::Instance()};
@@ -428,12 +432,11 @@ TEST_F(PairerBrokerImplTest, SuccessInitialPairingWithDeviceV1) {
CountDownLatch pairing_failure_latch(1);
EXPECT_FALSE(device_->GetAccountKey().Ok());
auto pairer_broker =
std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
pairer_broker_ = std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
PairerBrokerObserver pairer_broker_observer(
pairer_broker.get(), &device_paired_latch, &account_key_writed_latch,
pairer_broker_.get(), &device_paired_latch, &account_key_writed_latch,
&pairing_completed_latch, &pairing_failure_latch);
pairer_broker->PairDevice(*device_);
pairer_broker_->PairDevice(*device_);
device_paired_latch.Await();
pairing_completed_latch.Await();
@@ -469,12 +472,11 @@ TEST_F(PairerBrokerImplTest, SuccessInitialPairingWithDevice) {
EXPECT_FALSE(device_->GetAccountKey().Ok());
auto pairer_broker =
std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
pairer_broker_ = std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
PairerBrokerObserver pairer_broker_observer(
pairer_broker.get(), &device_paired_latch, &account_key_writed_latch,
pairer_broker_.get(), &device_paired_latch, &account_key_writed_latch,
&pairing_completed_latch, &pairing_failure_latch);
pairer_broker->PairDevice(*device_);
pairer_broker_->PairDevice(*device_);
device_paired_latch.Await();
pairing_completed_latch.Await();
@@ -484,8 +486,8 @@ TEST_F(PairerBrokerImplTest, SuccessInitialPairingWithDevice) {
EXPECT_TRUE(triggered_passkey_value_change);
EXPECT_TRUE(device_->GetAccountKey().Ok());
pairer_broker->StopPairing();
EXPECT_FALSE(pairer_broker->IsPairing());
pairer_broker_->StopPairing();
EXPECT_FALSE(pairer_broker_->IsPairing());
}
TEST_F(PairerBrokerImplTest, SuccessSubsequentPairingWithDevice) {
@@ -499,10 +501,9 @@ TEST_F(PairerBrokerImplTest, SuccessSubsequentPairingWithDevice) {
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
Protocol::kFastPairSubsequentPairing);
SetUpFastPairRepository();
auto pairer_broker =
std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
pairer_broker_ = std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
PairerBrokerObserver pairer_broker_observer(
pairer_broker.get(), &device_paired_latch, &account_key_writed_latch,
pairer_broker_.get(), &device_paired_latch, &account_key_writed_latch,
&pairing_completed_latch, &pairing_failure_latch);
SetupProviderGattServer(
[&]() {
@@ -515,12 +516,14 @@ TEST_F(PairerBrokerImplTest, SuccessSubsequentPairingWithDevice) {
});
SetPairingResult(std::nullopt);
pairer_broker->PairDevice(*device_);
executor_.Execute([&]() {
// Test pairing duplicate devices.
EXPECT_TRUE(pairer_broker->IsPairing());
pairer_broker->PairDevice(*device_);
});
pairer_broker_->PairDevice(*device_);
// TODO(qinwangz): The logic in `pairer_broker_->IsPairing()` may return false
// after a call to `PairDevice()`. Please fix.
// executor_.Execute([&]() {
// // Test pairing duplicate devices.
// EXPECT_TRUE(pairer_broker_->IsPairing());
// pairer_broker_->PairDevice(*device_);
// });
device_paired_latch.Await();
pairing_completed_latch.Await();
EXPECT_FALSE(account_key_writed_latch.Await(kWaitTimeout).result());
@@ -554,12 +557,11 @@ TEST_F(PairerBrokerImplTest, SuccessRetroactivePairingWithDevice) {
CountDownLatch pairing_failure_latch(1);
EXPECT_FALSE(device_->GetAccountKey().Ok());
auto pairer_broker =
std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
pairer_broker_ = std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
PairerBrokerObserver pairer_broker_observer(
pairer_broker.get(), &device_paired_latch, &account_key_writed_latch,
pairer_broker_.get(), &device_paired_latch, &account_key_writed_latch,
&pairing_completed_latch, &pairing_failure_latch);
pairer_broker->PairDevice(*device_);
pairer_broker_->PairDevice(*device_);
EXPECT_FALSE(device_paired_latch.Await(kWaitTimeout).result());
pairing_completed_latch.Await();
account_key_writed_latch.Await();
@@ -580,10 +582,9 @@ TEST_F(PairerBrokerImplTest, FaileToCreateHandshakeRetryThreeTimes) {
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
Protocol::kFastPairSubsequentPairing);
SetUpFastPairRepository();
auto pairer_broker =
std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
pairer_broker_ = std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
PairerBrokerObserver pairer_broker_observer(
pairer_broker.get(), &device_paired_latch, &account_key_writed_latch,
pairer_broker_.get(), &device_paired_latch, &account_key_writed_latch,
&pairing_completed_latch, &pairing_failure_latch);
SetupProviderGattServer(
[&]() { triggered_keybase_value_change = true; },
@@ -593,7 +594,7 @@ TEST_F(PairerBrokerImplTest, FaileToCreateHandshakeRetryThreeTimes) {
});
SetPairingResult(std::nullopt);
pairer_broker->PairDevice(*device_);
pairer_broker_->PairDevice(*device_);
EXPECT_FALSE(device_paired_latch.Await(kWaitTimeout).result());
EXPECT_FALSE(pairing_completed_latch.Await(kWaitTimeout).result());
EXPECT_FALSE(account_key_writed_latch.Await(kWaitTimeout).result());
@@ -631,12 +632,11 @@ TEST_F(PairerBrokerImplTest, FaileToWriteAccountkey) {
EXPECT_FALSE(device_->GetAccountKey().Ok());
auto pairer_broker =
std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
pairer_broker_ = std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
PairerBrokerObserver pairer_broker_observer(
pairer_broker.get(), &device_paired_latch, &account_key_writed_latch,
pairer_broker_.get(), &device_paired_latch, &account_key_writed_latch,
&pairing_completed_latch, &pairing_failure_latch);
pairer_broker->PairDevice(*device_);
pairer_broker_->PairDevice(*device_);
device_paired_latch.Await();
EXPECT_FALSE(pairing_completed_latch.Await(kWaitTimeout).result());
@@ -674,12 +674,11 @@ TEST_F(PairerBrokerImplTest, FailToPairRetryThreeTimes) {
EXPECT_FALSE(device_->GetAccountKey().Ok());
auto pairer_broker =
std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
pairer_broker_ = std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
PairerBrokerObserver pairer_broker_observer(
pairer_broker.get(), &device_paired_latch, &account_key_writed_latch,
pairer_broker_.get(), &device_paired_latch, &account_key_writed_latch,
&pairing_completed_latch, &pairing_failure_latch);
pairer_broker->PairDevice(*device_);
pairer_broker_->PairDevice(*device_);
EXPECT_FALSE(device_paired_latch.Await(kWaitTimeout).result());
EXPECT_FALSE(pairing_completed_latch.Await(kWaitTimeout).result());
+4 -2
View File
@@ -61,6 +61,7 @@ class RetroactiveTest : public testing::Test {
}
void TearDown() override {
executor_.Shutdown();
provider_.DisableProviderRfcomm();
provider_.Shutdown();
MediumEnvironment::Instance().Stop();
@@ -76,6 +77,7 @@ class RetroactiveTest : public testing::Test {
// The medium environment must be initialized (started) before adding
// adapters.
MediumEnvironmentStarter env_;
SingleThreadExecutor executor_;
Mediums mediums_;
FakeProvider provider_;
BluetoothDevice remote_device_;
@@ -84,13 +86,13 @@ class RetroactiveTest : public testing::Test {
};
TEST_F(RetroactiveTest, Constructor) {
FastPairController controller(&mediums_, remote_device_);
FastPairController controller(&mediums_, remote_device_, &executor_);
Retroactive retro(&controller);
}
TEST_F(RetroactiveTest, Pair) {
SetUpFastPairRepository(kModelId, absl::HexStringToBytes(kBobPublicKey));
FastPairController controller(&mediums_, remote_device_);
FastPairController controller(&mediums_, remote_device_, &executor_);
provider_.EnableProviderRfcomm();
provider_.LoadAntiSpoofingKey(absl::HexStringToBytes(kBobPrivateKey),
absl::HexStringToBytes(kBobPublicKey));