Implement PairerBroker for fast pair windows

PiperOrigin-RevId: 537982117
This commit is contained in:
Qin Wang
2023-06-05 14:29:36 -07:00
committed by Copybara-Service
parent 1d68d2fe10
commit 94b3263b63
8 changed files with 1256 additions and 3 deletions
@@ -473,7 +473,7 @@ void FastPairGattServiceClientImpl::WriteAccountKey(
return;
}
NEARBY_LOGS(INFO) << __func__
<< ": Failed to write the passkey characteristic ";
<< ": Failed to write the accoutkey characteristic ";
NotifyWriteAccountKeyError(PairFailure::kAccountKeyCharacteristicWrite);
}
@@ -129,7 +129,7 @@ void FastPairHandshakeImpl::OnParseDecryptedResponse(
device.SetPublicAddress(
device::CanonicalizeBluetoothAddress(response->address_bytes));
completed_successfully_ = true;
std::move(on_complete_callback_)(device, absl::nullopt);
std::move(on_complete_callback_)(device, std::nullopt);
}
} // namespace fastpair
+68
View File
@@ -0,0 +1,68 @@
# Copyright 2023 Google LLC
#
# 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
#
# https://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.
licenses(["notice"])
cc_library(
name = "pairing",
srcs = [
"pairer_broker_impl.cc",
],
hdrs = [
"pairer_broker.h",
"pairer_broker_impl.h",
],
compatible_with = ["//buildenv/target:non_prod"],
visibility = [
"//fastpair:__subpackages__",
"//internal:__subpackages__",
],
deps = [
"//fastpair/common",
"//fastpair/handshake",
"//fastpair/internal/mediums",
"//fastpair/pairing/fastpair:pairing",
"//internal/base",
"//internal/platform:types",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/functional:bind_front",
"@com_google_absl//absl/synchronization",
],
)
cc_test(
name = "pairer_broker_impl_test",
size = "small",
srcs = [
"pairer_broker_impl_test.cc",
],
shard_count = 16,
deps = [
":pairing",
"//fastpair/common",
"//fastpair/handshake",
"//fastpair/internal/mediums",
"//fastpair/pairing/fastpair:pairing",
"//fastpair/server_access:test_support",
"//internal/base:bluetooth_address",
"//internal/platform:comm",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform/implementation/g3", # build_cleaner: keep
"@boringssl//:crypto",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/functional:bind_front",
"@com_google_googletest//:gtest_main",
],
)
@@ -314,9 +314,10 @@ void FastPairPairerImpl::NotifyPaired() {
}
void FastPairPairerImpl::NotifyPairingFailed(PairFailure failure) {
NEARBY_LOGS(WARNING) << __func__ << failure;
NEARBY_LOGS(WARNING) << __func__ << ": " << failure;
// Stop initiate pairing timer as piaring is terminate this time.
initiate_pairing_timer_.Stop();
if (!on_pair_failed_cb_) return;
executor_->Execute("NotifyPairingFailed",
[&, on_pair_failed_cb = std::move(on_pair_failed_cb_),
failure = std::move(failure)]() mutable {
+55
View File
@@ -0,0 +1,55 @@
// Copyright 2023 Google LLC
//
// 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
//
// https://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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_PAIRING_PAIRER_BROKER_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_PAIRING_PAIRER_BROKER_H_
#include <optional>
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/common/pair_failure.h"
namespace nearby {
namespace fastpair {
// The PairerBroker is the entry point for the Fast Pair Pairing component.
// It is responsible for brokering the 'pair to device' calls to
// the correct concrete Pairer implementation, and exposing an observer pattern
// for other components to become aware of pairing results.
class PairerBroker {
public:
class Observer {
public:
virtual ~Observer() = default;
virtual void OnHandshakeComplete(FastPairDevice& device) {}
virtual void OnDevicePaired(FastPairDevice& device) {}
virtual void OnAccountKeyWrite(FastPairDevice& device,
std::optional<PairFailure> error) {}
virtual void OnPairingComplete(FastPairDevice& device) {}
virtual void OnPairFailure(FastPairDevice& device, PairFailure failure) {}
};
virtual ~PairerBroker() = default;
virtual void AddObserver(Observer* observer) = 0;
virtual void RemoveObserver(Observer* observer) = 0;
virtual void PairDevice(FastPairDevice& device) = 0;
virtual bool IsPairing() = 0;
virtual void StopPairing() = 0;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_PAIRING_PAIRER_BROKER_H_
+333
View File
@@ -0,0 +1,333 @@
// Copyright 2023 Google LLC
//
// 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
//
// https://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 "fastpair/pairing/pairer_broker_impl.h"
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include "absl/synchronization/mutex.h"
#include "fastpair//handshake/fast_pair_handshake_lookup.h"
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/pairing/fastpair/fast_pair_pairer_impl.h"
#include "internal/platform/single_thread_executor.h"
#include "internal/platform/timer_impl.h"
namespace nearby {
namespace fastpair {
namespace {
constexpr int kMaxFailureRetryCount = 3;
constexpr int kMaxNumHandshakeAttempts = 3;
constexpr absl::Duration kCancelPairingRetryDelay = absl::Seconds(1);
constexpr absl::Duration kRetryHandshakeDelay = absl::Seconds(1);
} // namespace
PairerBrokerImpl::PairerBrokerImpl(Mediums& medium,
SingleThreadExecutor* executor)
: medium_(medium), executor_(executor) {}
void PairerBrokerImpl::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void PairerBrokerImpl::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void PairerBrokerImpl::PairDevice(FastPairDevice& device) {
NEARBY_LOGS(INFO) << __func__ << ": Start to pair with device=" << device;
{
MutexLock lock(&mutex_);
model_id_to_current_ble_address_map_.insert_or_assign(
std::string(device.GetModelId()), std::string(device.GetBleAddress()));
did_handshake_previously_complete_successfully_map_.insert_or_assign(
std::string(device.GetModelId()), false);
}
PairFastPairDevice(device);
}
void PairerBrokerImpl::PairFastPairDevice(FastPairDevice& device) {
NEARBY_LOGS(INFO) << __func__;
{
MutexLock lock(&mutex_);
if (fast_pair_pairers_.contains(device.GetModelId())) {
NEARBY_LOGS(WARNING) << __func__ << ": Already pairing with device"
<< device;
return;
}
}
CHECK(device.GetVersion().has_value());
if (device.GetVersion().value() == DeviceFastPairVersion::kV1) {
// For v1 headsets, the ble address is the same as the public address.
// So skip straight to 'StartBondingAttempt'.
NEARBY_LOGS(INFO) << __func__ << " : Pairing with v1 device.";
device.SetPublicAddress(device.GetBleAddress());
StartPairingAttempt(device);
return;
}
NEARBY_LOGS(INFO) << __func__ << " : Pairing with device higher than v1.";
// For headsets higher than v1, try to create a handshake with the remote
// device to request its public address.
CreateHandshake(device);
}
void PairerBrokerImpl::CreateHandshake(FastPairDevice& device) {
NEARBY_LOGS(INFO) << __func__;
{
MutexLock lock(&mutex_);
if (device.GetBleAddress() !=
model_id_to_current_ble_address_map_[device.GetModelId()]) {
// If the current |device| has a different BLE Address than the address in
// the map, abort creating the handshake and return early;
NEARBY_LOGS(INFO)
<< __func__
<< ": The device's BLE did not match the expected value, returning.";
return;
}
}
auto* fast_pair_handshake =
FastPairHandshakeLookup::GetInstance()->Get(&device);
if (fast_pair_handshake) {
if (fast_pair_handshake->completed_successfully()) {
NEARBY_LOGS(INFO) << __func__
<< ": Reusing existing handshake for pair attempt.";
StartPairingAttempt(device);
return;
}
// If the previous handshake did not complete successfully, erase it
// before attempting to create a new handshake for the device.
FastPairHandshakeLookup::GetInstance()->Erase(&device);
}
NEARBY_LOGS(INFO) << __func__ << ": Creating new handshake for pair attempt.";
FastPairHandshakeLookup::GetInstance()->Create(
device, medium_,
[&](FastPairDevice& cb_device, std::optional<PairFailure> failure) {
executor_->Execute("OnHandshakeComplete",
[&, failure = std::move(failure)]()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
OnHandshakeComplete(cb_device, failure);
});
});
}
void PairerBrokerImpl::OnHandshakeComplete(FastPairDevice& device,
std::optional<PairFailure> failure) {
NEARBY_LOGS(INFO) << __func__;
if (failure.has_value()) {
OnHandshakeFailure(device, failure.value());
return;
}
if (!device.GetPublicAddress().has_value()) {
NEARBY_LOGS(WARNING) << __func__ << ": Device lost during handshake.";
OnHandshakeFailure(device, PairFailure::kDeviceLostMidPairing);
return;
}
{
MutexLock lock(&mutex_);
if (!did_handshake_previously_complete_successfully_map_
[device.GetModelId()]) {
for (auto& observer : observers_.GetObservers()) {
observer->OnHandshakeComplete(device);
}
did_handshake_previously_complete_successfully_map_.insert_or_assign(
device.GetModelId(), true);
}
// Reset |num_handshake_attempts_|
num_handshake_attempts_[device.GetModelId()] = 0;
}
StartPairingAttempt(device);
}
void PairerBrokerImpl::OnHandshakeFailure(FastPairDevice& device,
PairFailure failure) {
NEARBY_LOGS(WARNING) << __func__
<< ": Handshake failed with device because: " << failure;
{
MutexLock lock(&mutex_);
if (++num_handshake_attempts_[device.GetModelId()] <
kMaxNumHandshakeAttempts) {
retry_handshake_timer_ = std::make_unique<TimerImpl>();
retry_handshake_timer_->Start(
kRetryHandshakeDelay / absl::Milliseconds(1), 0,
[&]() { CreateHandshake(device); });
return;
}
}
NEARBY_LOGS(WARNING)
<< __func__ << ": Handshake failed to be created. Notifying observers.";
for (auto& observer : observers_.GetObservers()) {
observer->OnPairFailure(device, failure);
}
FastPairHandshakeLookup::GetInstance()->Erase(&device);
}
void PairerBrokerImpl::StartPairingAttempt(FastPairDevice& device) {
{
MutexLock lock(&mutex_);
if (!pair_failure_counts_.contains(device.GetModelId())) {
pair_failure_counts_[device.GetModelId()] = 0;
}
}
NEARBY_LOGS(INFO) << __func__ << ": " << device;
MutexLock lock(&mutex_);
// Create FastPairPairer instance and start pairing.
fast_pair_pairers_[device.GetModelId()] = FastPairPairerImpl::Factory::Create(
device, medium_, executor_,
[&](FastPairDevice& cb_device) {
executor_->Execute("OnFastPairDevicePaired",
[&]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
OnFastPairDevicePaired(cb_device);
});
},
[&](FastPairDevice& cb_device, PairFailure failure) {
executor_->Execute("OnFastPairPairingFailure",
[&, failure = std::move(failure)]()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
OnFastPairPairingFailure(cb_device, failure);
});
},
[&](FastPairDevice& cb_device, PairFailure failure) {
executor_->Execute("OnAccountKeyFailure",
[&, failure = std::move(failure)]()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
OnAccountKeyFailure(cb_device, failure);
});
},
[&](FastPairDevice& cb_device) {
executor_->Execute("OnFastPairProcedureComplete",
[&]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
OnFastPairProcedureComplete(cb_device);
});
});
fast_pair_pairers_[device.GetModelId()]->StartPairing();
}
void PairerBrokerImpl::OnFastPairDevicePaired(FastPairDevice& device) {
NEARBY_LOGS(INFO) << __func__ << ": Device=" << device;
for (auto& observer : observers_.GetObservers()) {
observer->OnDevicePaired(device);
}
MutexLock lock(&mutex_);
pair_failure_counts_.erase(device.GetModelId());
}
void PairerBrokerImpl::OnFastPairPairingFailure(FastPairDevice& device,
PairFailure failure) {
MutexLock lock(&mutex_);
++pair_failure_counts_[device.GetModelId()];
NEARBY_LOGS(INFO) << __func__ << ": Device=" << device
<< ", Failure=" << failure << ", Failure Count = "
<< pair_failure_counts_[device.GetModelId()];
if (pair_failure_counts_[device.GetModelId()] == kMaxFailureRetryCount) {
NEARBY_LOGS(INFO) << __func__
<< ": Reached max failure count. Notifying observers.";
for (auto& observer : observers_.GetObservers()) {
observer->OnPairFailure(device, failure);
}
if (!fast_pair_pairers_[device.GetModelId()]->IsPaired()) {
fast_pair_pairers_[device.GetModelId()]->CancelPairing();
}
executor_->Execute("EraseHandshakeAndPairers",
[&]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
EraseHandshakeAndPairers(device);
});
return;
}
if (!fast_pair_pairers_[device.GetModelId()]->IsPaired()) {
NEARBY_LOGS(INFO) << __func__
<< ": Cancelling pairing and scheduling retry "
"for failed pair attempt.";
fast_pair_pairers_[device.GetModelId()]->CancelPairing();
fast_pair_pairers_.erase(device.GetModelId());
// Create a timer to wait |kCancelPairingRetryDelay| after cancelling
// pairing to retry the pairing attempt.
cancel_pairing_timer_ = std::make_unique<TimerImpl>();
cancel_pairing_timer_->Start(
kCancelPairingRetryDelay / absl::Milliseconds(1), 0,
[&]() { PairFastPairDevice(device); });
return;
}
fast_pair_pairers_.erase(device.GetModelId());
PairFastPairDevice(device);
}
void PairerBrokerImpl::OnAccountKeyFailure(FastPairDevice& device,
PairFailure failure) {
NEARBY_LOGS(INFO) << __func__ << ": Device=" << device
<< ", Failure=" << failure;
for (auto& observer : observers_.GetObservers()) {
observer->OnAccountKeyWrite(device, failure);
}
executor_->Execute("EraseHandshakeAndPairers",
[&]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
EraseHandshakeAndPairers(device);
});
}
void PairerBrokerImpl::OnFastPairProcedureComplete(FastPairDevice& device) {
NEARBY_LOGS(INFO) << __func__ << ": Device=" << device;
for (auto& observer : observers_.GetObservers()) {
observer->OnPairingComplete(device);
}
// If we get to this point in the flow for the initial and retroactive
// pairing scenarios, this means that the account key has successfully
// been written for devices with a version of V2 or higher.
if (device.GetVersion().has_value() &&
device.GetVersion().value() == DeviceFastPairVersion::kHigherThanV1 &&
(device.GetProtocol() == Protocol::kFastPairInitialPairing ||
device.GetProtocol() == Protocol::kFastPairRetroactivePairing)) {
for (auto& observer : observers_.GetObservers()) {
observer->OnAccountKeyWrite(device, /*error=*/absl::nullopt);
}
}
executor_->Execute("EraseHandshakeAndPairers",
[&]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
EraseHandshakeAndPairers(device);
});
}
void PairerBrokerImpl::EraseHandshakeAndPairers(FastPairDevice& device) {
MutexLock lock(&mutex_);
NEARBY_LOGS(WARNING) << __func__;
// |fast_pair_pairers_| and its children objects depend on the handshake
// instance. Shut them down before destroying the handshake.
pair_failure_counts_.erase(device.GetModelId());
fast_pair_pairers_.erase(device.GetModelId());
FastPairHandshakeLookup::GetInstance()->Erase(&device);
did_handshake_previously_complete_successfully_map_.insert_or_assign(
std::string(device.GetModelId()), false);
}
bool PairerBrokerImpl::IsPairing() {
MutexLock lock(&mutex_);
// We are guaranteed to not be pairing when the following two maps are
// empty.
return !fast_pair_pairers_.empty() || !pair_failure_counts_.empty();
}
void PairerBrokerImpl::StopPairing() {
MutexLock lock(&mutex_);
fast_pair_pairers_.clear();
pair_failure_counts_.clear();
}
} // namespace fastpair
} // namespace nearby
+101
View File
@@ -0,0 +1,101 @@
// Copyright 2023 Google LLC
//
// 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
//
// https://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.
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_PAIRING_PAIRER_BROKER_IMPL_H_
#define THIRD_PARTY_NEARBY_FASTPAIR_PAIRING_PAIRER_BROKER_IMPL_H_
#include <memory>
#include <optional>
#include <string>
#include "absl/container/flat_hash_map.h"
#include "fastpair/common/fast_pair_device.h"
#include "fastpair/internal/mediums/mediums.h"
#include "fastpair/pairing/fastpair/fast_pair_pairer.h"
#include "fastpair/pairing/pairer_broker.h"
#include "internal/base/observer_list.h"
#include "internal/platform/single_thread_executor.h"
#include "internal/platform/timer_impl.h"
namespace nearby {
namespace fastpair {
class PairerBrokerImpl : public PairerBroker {
public:
explicit PairerBrokerImpl(Mediums& medium, SingleThreadExecutor* executor);
PairerBrokerImpl(const PairerBrokerImpl&) = delete;
PairerBrokerImpl& operator=(const PairerBrokerImpl&) = delete;
// PairingBroker:
void AddObserver(Observer* observer) override;
// The `observer` can still be called after removing if it has already
// been scheduled to run (or is running) on the background thread.
void RemoveObserver(Observer* observer) override;
void PairDevice(FastPairDevice& device) override;
bool IsPairing() override;
void StopPairing() override;
friend class PairerBrokerImplTest;
private:
mutable Mutex mutex_;
void PairFastPairDevice(FastPairDevice& device);
void CreateHandshake(FastPairDevice& device);
void OnHandshakeComplete(FastPairDevice& device,
std::optional<PairFailure> failure)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
void OnHandshakeFailure(FastPairDevice& device, PairFailure failure)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
void StartPairingAttempt(FastPairDevice& device);
void OnFastPairDevicePaired(FastPairDevice& device)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
void OnFastPairPairingFailure(FastPairDevice& device, PairFailure failure)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
void OnFastPairProcedureComplete(FastPairDevice& device)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
void OnAccountKeyFailure(FastPairDevice& device, PairFailure failure)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
void EraseHandshakeAndPairers(FastPairDevice& device)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
Mediums& medium_;
SingleThreadExecutor* executor_;
// The key for all the following maps is a device model id.
absl::flat_hash_map<std::string, std::unique_ptr<FastPairPairer>>
fast_pair_pairers_ ABSL_GUARDED_BY(mutex_);
absl::flat_hash_map<std::string, int> pair_failure_counts_
ABSL_GUARDED_BY(mutex_);
absl::flat_hash_map<std::string, bool>
did_handshake_previously_complete_successfully_map_
ABSL_GUARDED_BY(mutex_);
absl::flat_hash_map<std::string, int> num_handshake_attempts_
ABSL_GUARDED_BY(mutex_);
absl::flat_hash_map<std::string, std::string>
model_id_to_current_ble_address_map_ ABSL_GUARDED_BY(mutex_);
// Timer
std::unique_ptr<TimerImpl> cancel_pairing_timer_;
std::unique_ptr<TimerImpl> retry_handshake_timer_;
ObserverList<Observer> observers_;
};
} // namespace fastpair
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_FASTPAIR_PAIRING_PAIRER_BROKER_IMPL_H_
+695
View File
@@ -0,0 +1,695 @@
// Copyright 2023 Google LLC
//
// 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
//
// https://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 "fastpair/pairing/pairer_broker_impl.h"
#include <algorithm>
#include <array>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "absl/functional/bind_front.h"
#include "fastpair//handshake/fast_pair_handshake_lookup.h"
#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/internal/mediums/mediums.h"
#include "fastpair/pairing/fastpair/fast_pair_pairer.h"
#include "fastpair/server_access/fake_fast_pair_repository.h"
#include "internal/base/bluetooth_address.h"
#include "internal/platform/ble_v2.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/medium_environment.h"
#include <openssl/rand.h>
namespace nearby {
namespace fastpair {
namespace {
using Property = nearby::api::ble_v2::GattCharacteristic::Property;
using Permission = nearby::api::ble_v2::GattCharacteristic::Permission;
using ::nearby::api::ble_v2::GattCharacteristic;
using DiscoveryCallback = BluetoothClassicMedium::DiscoveryCallback;
constexpr absl::string_view kMetadataId("718c17");
constexpr absl::string_view kPublicAntiSpoof =
"Wuyr48lD3txnUhGiMF1IfzlTwRxxe+wMB1HLzP+"
"0wVcljfT3XPoiy1fntlneziyLD5knDVAJSE+RM/zlPRP/Jg==";
constexpr std::array<uint8_t, kAesBlockByteSize> kRawResponseBytes = {
0x01, 0x5E, 0x3F, 0x45, 0x61, 0xC3, 0x32, 0x1D,
0xA0, 0xBA, 0xF0, 0xBB, 0x95, 0x1F, 0xF7, 0xB6};
constexpr Uuid kFastPairServiceUuid(0x0000FE2C00001000, 0x800000805F9B34FB);
constexpr Uuid kKeyBasedCharacteristicUuidV2(0xFE2C123483664814,
0x8EB001DE32100BEA);
constexpr Uuid kPasskeyCharacteristicUuidV2(0xFE2C123583664814,
0x8EB001DE32100BEA);
constexpr Uuid kAccountKeyCharacteristicUuidV2(0xFE2C123683664814,
0x8EB001DE32100BEA);
constexpr absl::string_view kPasskey("123456");
constexpr absl::string_view kWrongResponse("wrongresponse");
constexpr absl::Duration kWaitTimeout = absl::Milliseconds(200);
struct CharacteristicData {
// Write result returned to the gatt client.
absl::Status write_result = absl::OkStatus();
};
} // namespace
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)
: 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);
}
~PairerBrokerObserver() override { pairer_broker_->RemoveObserver(this); }
void OnHandshakeComplete(FastPairDevice& device) override {
NEARBY_LOGS(INFO) << __func__;
handshake_completed_ = true;
}
void OnDevicePaired(FastPairDevice& device) override {
NEARBY_LOGS(INFO) << __func__;
device_paired_latch_->CountDown();
}
void OnAccountKeyWrite(FastPairDevice& device,
std::optional<PairFailure> error) override {
NEARBY_LOGS(INFO) << __func__;
if (error.has_value()) {
account_key_failure_ = error.value();
}
account_key_writed_latch_->CountDown();
}
void OnPairingComplete(FastPairDevice& device) override {
NEARBY_LOGS(INFO) << __func__;
pairing_completed_latch_->CountDown();
}
void OnPairFailure(FastPairDevice& device, PairFailure failure) override {
pair_failure_ = failure;
pairing_failure_latch_->CountDown();
}
PairerBroker* pairer_broker_;
bool handshake_completed_ = false;
CountDownLatch* device_paired_latch_ = nullptr;
CountDownLatch* account_key_writed_latch_ = nullptr;
CountDownLatch* pairing_completed_latch_ = nullptr;
CountDownLatch* pairing_failure_latch_ = nullptr;
PairFailure account_key_failure_ = PairFailure::kUnknown;
PairFailure pair_failure_ = PairFailure::kUnknown;
};
class PairerBrokerImplTest : public testing::Test {
public:
void SetUp() override {
env_.Start();
// Setups seeker device.
mediums_ = std::make_unique<Mediums>();
// Setups provider device.
adapter_provider_ = std::make_unique<BluetoothAdapter>();
adapter_provider_->SetStatus(BluetoothAdapter::Status::kEnabled);
adapter_provider_->SetName("Device-Provider");
adapter_provider_->SetScanMode(
BluetoothAdapter::ScanMode::kConnectableDiscoverable);
bt_provider_ = std::make_unique<BluetoothClassicMedium>(*adapter_provider_);
// Discovering provider device.
CountDownLatch found_latch(1);
mediums_->GetBluetoothClassic().GetMedium().StartDiscovery(
DiscoveryCallback{.device_discovered_cb = [&](BluetoothDevice& device) {
remote_device_ = &device;
found_latch.CountDown();
}});
found_latch.Await();
env_.Sync();
}
void TearDown() override {
env_.Sync(false);
executor_.Shutdown();
mediums_.reset();
device_.reset();
repository_.reset();
handshake_ = nullptr;
remote_device_ = nullptr;
key_based_characteristic_ = std::nullopt;
passkey_characteristic_ = std::nullopt;
adapter_provider_->SetStatus(BluetoothAdapter::Status::kDisabled);
gatt_server_->Stop();
gatt_server_.reset();
bt_provider_.reset();
ble_provider_.reset();
env_.Sync(false);
adapter_provider_.reset();
env_.Stop();
}
void CreateMockDevice(DeviceFastPairVersion version, Protocol protocol) {
device_ = std::make_unique<FastPairDevice>(
kMetadataId, remote_device_->GetMacAddress(), protocol);
device_->SetVersion(version);
if (version == DeviceFastPairVersion::kV1) {
device_->SetPublicAddress(remote_device_->GetMacAddress());
}
if (protocol == Protocol::kFastPairSubsequentPairing) {
device_->SetAccountKey(AccountKey(account_key_));
}
}
void ConfigurePairingContext() {
api::PairingParams pairing_params;
pairing_params.pairing_type =
api::PairingParams::PairingType::kConfirmPasskey;
pairing_params.passkey = kPasskey;
env_.ConfigBluetoothPairingContext(&remote_device_->GetImpl(),
pairing_params);
}
void CreateFastPairHandshakeInstanceForDevice() {
FastPairHandshakeLookup::SetCreateFunctionForTesting(absl::bind_front(
&PairerBrokerImplTest::CreateConnectedHandshake, this));
CountDownLatch latch(1);
EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Create(
*device_, *mediums_,
[&](FastPairDevice& cb_device, std::optional<PairFailure> failure) {
EXPECT_EQ(device_.get(), &cb_device);
EXPECT_EQ(failure, std::nullopt);
latch.CountDown();
}));
latch.Await();
EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(device_.get()));
EXPECT_TRUE(handshake_->completed_successfully());
EXPECT_EQ(
device_->GetPublicAddress().value(),
device::CanonicalizeBluetoothAddress(remote_device_->GetMacAddress()));
}
std::unique_ptr<FastPairHandshake> CreateConnectedHandshake(
FastPairDevice& device, Mediums& mediums,
FastPairHandshake::OnCompleteCallback callback) {
CountDownLatch latch(1);
auto handshake = std::make_unique<FastPairHandshakeImpl>(
device, mediums,
[&](FastPairDevice& callback_device,
std::optional<PairFailure> failure) {
callback(callback_device, failure);
latch.CountDown();
});
handshake_ = handshake.get();
latch.Await();
return handshake;
}
// Sets up provider's metadata information.
void SetUpFastPairRepository() {
repository_ = FakeFastPairRepository::Create(kMetadataId, kPublicAntiSpoof);
}
// Sets upprovider's gatt_server.
void SetupProviderGattServer(
absl::AnyInvocable<void()> trigger_keybase_value_change,
absl::AnyInvocable<void()> trigger_passkey_value_change) {
ble_provider_ = std::make_unique<BleV2Medium>(*adapter_provider_);
gatt_server_ = ble_provider_->StartGattServer(
/*ServerGattConnectionCallback=*/{
.on_characteristic_write_cb =
[&](const api::ble_v2::BlePeripheral& remote_device,
const api::ble_v2::GattCharacteristic& characteristic,
int offset, absl::string_view data,
BleV2Medium::ServerGattConnectionCallback::
WriteValueCallback callback) {
auto it = characteristics_.find(characteristic);
if (it == characteristics_.end()) {
callback(absl::NotFoundError("characteristic not found"));
return;
}
if (characteristic == *key_based_characteristic_) {
trigger_keybase_value_change();
} else if (characteristic == *passkey_characteristic_) {
trigger_passkey_value_change();
}
callback(it->second.write_result);
}});
// Insert fast pair related gatt characteristics
key_based_characteristic_ = gatt_server_->CreateCharacteristic(
kFastPairServiceUuid, kKeyBasedCharacteristicUuidV2, permissions_,
properties_);
characteristics_[*key_based_characteristic_].write_result =
absl::OkStatus();
passkey_characteristic_ = gatt_server_->CreateCharacteristic(
kFastPairServiceUuid, kPasskeyCharacteristicUuidV2, permissions_,
properties_);
characteristics_[*passkey_characteristic_].write_result = absl::OkStatus();
accountkey_characteristic_ = gatt_server_->CreateCharacteristic(
kFastPairServiceUuid, kAccountKeyCharacteristicUuidV2, permissions_,
properties_);
characteristics_[*accountkey_characteristic_].write_result =
absl::OkStatus();
}
// Triggers provider's gatt_server to response with public address
absl::Status TriggerKeyBasedGattChanged() {
std::unique_ptr<FastPairDataEncryptor> fast_pair_data_encryptor_unique_ptr;
FastPairDataEncryptor* fast_pair_data_encryptor_;
if (device_->GetAccountKey().Ok()) {
CountDownLatch latch(1);
FastPairDataEncryptorImpl::Factory::CreateAsync(
*device_,
[&](std::unique_ptr<FastPairDataEncryptor> fast_pair_data_encryptor) {
fast_pair_data_encryptor_unique_ptr =
std::move(fast_pair_data_encryptor);
latch.CountDown();
});
latch.Await();
fast_pair_data_encryptor_ = fast_pair_data_encryptor_unique_ptr.get();
} else {
fast_pair_data_encryptor_ = handshake_->fast_pair_data_encryptor();
}
std::array<uint8_t, kAesBlockByteSize> raw_response = kRawResponseBytes;
std::array<uint8_t, 6> provider_address_bytes;
device::ParseBluetoothAddress(
device_->GetBleAddress(),
absl::MakeSpan(provider_address_bytes.data(),
provider_address_bytes.size()));
std::copy(provider_address_bytes.begin(), provider_address_bytes.end(),
std::begin(raw_response) + 1);
std::array<uint8_t, kAesBlockByteSize> encryptedResponse =
fast_pair_data_encryptor_->EncryptBytes(raw_response);
std::array<char, kAesBlockByteSize> response;
std::copy(encryptedResponse.begin(), encryptedResponse.end(),
response.begin());
return gatt_server_->NotifyCharacteristicChanged(
key_based_characteristic_.value(), false, ByteArray(response));
}
// Triggers provider's gatt_server to response with passkey
// success == true, response with correct passkey,
// otherwise, response with wrong passkey.
absl::Status TriggerPasskeyGattChanged(absl::string_view pin_code,
uint8_t fast_pair_message_type) {
std::unique_ptr<FastPairDataEncryptor> fast_pair_data_encryptor_unique_ptr;
FastPairDataEncryptor* fast_pair_data_encryptor_;
if (device_->GetAccountKey().Ok()) {
CountDownLatch latch(1);
FastPairDataEncryptorImpl::Factory::CreateAsync(
*device_,
[&](std::unique_ptr<FastPairDataEncryptor> fast_pair_data_encryptor) {
fast_pair_data_encryptor_unique_ptr =
std::move(fast_pair_data_encryptor);
latch.CountDown();
});
latch.Await();
fast_pair_data_encryptor_ = fast_pair_data_encryptor_unique_ptr.get();
} else {
fast_pair_data_encryptor_ = handshake_->fast_pair_data_encryptor();
}
std::array<uint8_t, kAesBlockByteSize> raw_response;
RAND_bytes(raw_response.data(), kAesBlockByteSize);
raw_response[0] = fast_pair_message_type;
uint32_t passkey = 0;
passkey = std::stoi(std::string(pin_code));
// Need to convert the uint_32 to uint_8 to use in our data vector.
raw_response[1] = (passkey & 0x00ff0000) >> 16;
raw_response[2] = (passkey & 0x0000ff00) >> 8;
raw_response[3] = passkey & 0x000000ff;
std::array<uint8_t, kAesBlockByteSize> encryptedResponse =
fast_pair_data_encryptor_->EncryptBytes(raw_response);
std::array<char, kAesBlockByteSize> response;
std::copy(encryptedResponse.begin(), encryptedResponse.end(),
response.begin());
return gatt_server_->NotifyCharacteristicChanged(
passkey_characteristic_.value(), false, ByteArray(response));
}
absl::Status TriggerPasskeyGattChangedWithWrongResponse() {
return gatt_server_->NotifyCharacteristicChanged(
passkey_characteristic_.value(), false,
ByteArray(std::string(kWrongResponse)));
}
bool SetPairingResult(
std::optional<api::BluetoothPairingCallback::PairingError> error) {
return env_.SetPairingResult(&remote_device_->GetImpl(), error);
}
void SetPasskeyCharacteristicsWriteResultToFailure() {
auto it = characteristics_.find(*passkey_characteristic_);
it->second.write_result = absl::UnknownError("Failed to write account key");
}
void SetAccountkeyCharacteristicsWriteResultToFailure() {
auto it = characteristics_.find(*accountkey_characteristic_);
it->second.write_result = absl::UnknownError("Failed to write account key");
}
protected:
const std::vector<uint8_t> account_key_{0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
0x77, 0x88, 0x99, 0x00, 0xAA, 0xBB,
0xCC, 0xDD, 0xEE, 0xFF};
std::unique_ptr<Mediums> mediums_;
std::unique_ptr<FastPairDevice> device_;
BluetoothDevice* remote_device_ = nullptr;
std::unique_ptr<FastPairPairer> fast_pair_pairer_;
SingleThreadExecutor executor_;
private:
MediumEnvironment& env_{MediumEnvironment::Instance()};
std::unique_ptr<FakeFastPairRepository> repository_;
std::unique_ptr<BluetoothClassicMedium> bt_provider_;
std::unique_ptr<BluetoothAdapter> adapter_provider_;
std::unique_ptr<GattServer> gatt_server_;
std::unique_ptr<BleV2Medium> ble_provider_;
FastPairHandshake* handshake_ = nullptr;
std::optional<GattCharacteristic> key_based_characteristic_;
std::optional<GattCharacteristic> passkey_characteristic_;
std::optional<GattCharacteristic> accountkey_characteristic_;
absl::flat_hash_map<GattCharacteristic, CharacteristicData> characteristics_;
Property properties_ = Property::kWrite | Property::kNotify;
Permission permissions_ = Permission::kWrite;
};
TEST_F(PairerBrokerImplTest, SuccessInitialPairingWithDeviceV1) {
ConfigurePairingContext();
CreateMockDevice(DeviceFastPairVersion::kV1,
Protocol::kFastPairInitialPairing);
bool triggered_keybase_value_change = false;
bool triggered_passkey_value_change = false;
SetUpFastPairRepository();
SetupProviderGattServer(
[&]() {
triggered_keybase_value_change = true;
EXPECT_OK(TriggerKeyBasedGattChanged());
},
[&]() {
triggered_passkey_value_change = true;
EXPECT_OK(TriggerPasskeyGattChanged(kPasskey, kProviderPasskeyType));
});
SetPairingResult(std::nullopt);
CountDownLatch device_paired_latch(1);
CountDownLatch account_key_writed_latch(1);
CountDownLatch pairing_completed_latch(1);
CountDownLatch pairing_failure_latch(1);
EXPECT_FALSE(device_->GetAccountKey().Ok());
auto pairer_broker =
std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
PairerBrokerObserver pairer_broker_observer(
pairer_broker.get(), &device_paired_latch, &account_key_writed_latch,
&pairing_completed_latch, &pairing_failure_latch);
pairer_broker->PairDevice(*device_);
device_paired_latch.Await();
pairing_completed_latch.Await();
EXPECT_FALSE(account_key_writed_latch.Await(kWaitTimeout).result());
EXPECT_FALSE(pairing_failure_latch.Await(kWaitTimeout).result());
EXPECT_FALSE(triggered_keybase_value_change);
EXPECT_FALSE(triggered_passkey_value_change);
EXPECT_FALSE(device_->GetAccountKey().Ok());
}
TEST_F(PairerBrokerImplTest, SuccessInitialPairingWithDevice) {
bool triggered_keybase_value_change = false;
bool triggered_passkey_value_change = false;
CountDownLatch device_paired_latch(1);
CountDownLatch account_key_writed_latch(1);
CountDownLatch pairing_completed_latch(1);
CountDownLatch pairing_failure_latch(1);
ConfigurePairingContext();
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
Protocol::kFastPairInitialPairing);
SetUpFastPairRepository();
SetupProviderGattServer(
[&]() {
triggered_keybase_value_change = true;
EXPECT_OK(TriggerKeyBasedGattChanged());
},
[&]() {
triggered_passkey_value_change = true;
EXPECT_OK(TriggerPasskeyGattChanged(kPasskey, kProviderPasskeyType));
});
CreateFastPairHandshakeInstanceForDevice();
SetPairingResult(std::nullopt);
EXPECT_FALSE(device_->GetAccountKey().Ok());
auto pairer_broker =
std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
PairerBrokerObserver pairer_broker_observer(
pairer_broker.get(), &device_paired_latch, &account_key_writed_latch,
&pairing_completed_latch, &pairing_failure_latch);
pairer_broker->PairDevice(*device_);
device_paired_latch.Await();
pairing_completed_latch.Await();
account_key_writed_latch.Await();
EXPECT_FALSE(pairing_failure_latch.Await(kWaitTimeout).result());
EXPECT_TRUE(triggered_keybase_value_change);
EXPECT_TRUE(triggered_passkey_value_change);
EXPECT_TRUE(device_->GetAccountKey().Ok());
pairer_broker->StopPairing();
EXPECT_FALSE(pairer_broker->IsPairing());
}
TEST_F(PairerBrokerImplTest, SuccessSubsequentPairingWithDevice) {
bool triggered_keybase_value_change = false;
bool triggered_passkey_value_change = false;
CountDownLatch device_paired_latch(1);
CountDownLatch account_key_writed_latch(1);
CountDownLatch pairing_completed_latch(1);
CountDownLatch pairing_failure_latch(1);
ConfigurePairingContext();
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
Protocol::kFastPairSubsequentPairing);
SetUpFastPairRepository();
auto pairer_broker =
std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
PairerBrokerObserver pairer_broker_observer(
pairer_broker.get(), &device_paired_latch, &account_key_writed_latch,
&pairing_completed_latch, &pairing_failure_latch);
SetupProviderGattServer(
[&]() {
triggered_keybase_value_change = true;
EXPECT_OK(TriggerKeyBasedGattChanged());
},
[&]() {
triggered_passkey_value_change = true;
EXPECT_OK(TriggerPasskeyGattChanged(kPasskey, kProviderPasskeyType));
});
SetPairingResult(std::nullopt);
pairer_broker->PairDevice(*device_);
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());
EXPECT_FALSE(pairing_failure_latch.Await(kWaitTimeout).result());
EXPECT_TRUE(pairer_broker_observer.handshake_completed_);
EXPECT_TRUE(triggered_keybase_value_change);
EXPECT_TRUE(triggered_passkey_value_change);
}
TEST_F(PairerBrokerImplTest, SuccessRetroactivePairingWithDevice) {
ConfigurePairingContext();
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
Protocol::kFastPairRetroactivePairing);
bool triggered_keybase_value_change = false;
bool triggered_passkey_value_change = false;
SetUpFastPairRepository();
SetupProviderGattServer(
[&]() {
triggered_keybase_value_change = true;
EXPECT_OK(TriggerKeyBasedGattChanged());
},
[&]() {
triggered_passkey_value_change = true;
EXPECT_OK(TriggerPasskeyGattChanged(kPasskey, kProviderPasskeyType));
});
CreateFastPairHandshakeInstanceForDevice();
SetPairingResult(std::nullopt);
CountDownLatch device_paired_latch(1);
CountDownLatch account_key_writed_latch(1);
CountDownLatch pairing_completed_latch(1);
CountDownLatch pairing_failure_latch(1);
EXPECT_FALSE(device_->GetAccountKey().Ok());
auto pairer_broker =
std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
PairerBrokerObserver pairer_broker_observer(
pairer_broker.get(), &device_paired_latch, &account_key_writed_latch,
&pairing_completed_latch, &pairing_failure_latch);
pairer_broker->PairDevice(*device_);
EXPECT_FALSE(device_paired_latch.Await(kWaitTimeout).result());
pairing_completed_latch.Await();
account_key_writed_latch.Await();
EXPECT_FALSE(pairing_failure_latch.Await(kWaitTimeout).result());
EXPECT_TRUE(triggered_keybase_value_change);
EXPECT_FALSE(triggered_passkey_value_change);
EXPECT_TRUE(device_->GetAccountKey().Ok());
}
TEST_F(PairerBrokerImplTest, FaileToCreateHandshakeRetryThreeTimes) {
bool triggered_keybase_value_change = false;
bool triggered_passkey_value_change = false;
CountDownLatch device_paired_latch(1);
CountDownLatch account_key_writed_latch(1);
CountDownLatch pairing_completed_latch(1);
CountDownLatch pairing_failure_latch(1);
ConfigurePairingContext();
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
Protocol::kFastPairSubsequentPairing);
SetUpFastPairRepository();
auto pairer_broker =
std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
PairerBrokerObserver pairer_broker_observer(
pairer_broker.get(), &device_paired_latch, &account_key_writed_latch,
&pairing_completed_latch, &pairing_failure_latch);
SetupProviderGattServer(
[&]() { triggered_keybase_value_change = true; },
[&]() {
triggered_passkey_value_change = true;
EXPECT_OK(TriggerPasskeyGattChanged(kPasskey, kProviderPasskeyType));
});
SetPairingResult(std::nullopt);
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());
pairing_failure_latch.Await();
EXPECT_FALSE(pairer_broker_observer.handshake_completed_);
EXPECT_TRUE(triggered_keybase_value_change);
EXPECT_FALSE(triggered_passkey_value_change);
EXPECT_EQ(pairer_broker_observer.pair_failure_,
PairFailure::kKeyBasedPairingResponseTimeout);
}
TEST_F(PairerBrokerImplTest, FaileToWriteAccountkey) {
bool triggered_keybase_value_change = false;
bool triggered_passkey_value_change = false;
CountDownLatch device_paired_latch(1);
CountDownLatch account_key_writed_latch(1);
CountDownLatch pairing_completed_latch(1);
CountDownLatch pairing_failure_latch(1);
ConfigurePairingContext();
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
Protocol::kFastPairInitialPairing);
SetUpFastPairRepository();
SetupProviderGattServer(
[&]() {
triggered_keybase_value_change = true;
EXPECT_OK(TriggerKeyBasedGattChanged());
},
[&]() {
triggered_passkey_value_change = true;
EXPECT_OK(TriggerPasskeyGattChanged(kPasskey, kProviderPasskeyType));
});
CreateFastPairHandshakeInstanceForDevice();
SetPairingResult(std::nullopt);
SetAccountkeyCharacteristicsWriteResultToFailure();
EXPECT_FALSE(device_->GetAccountKey().Ok());
auto pairer_broker =
std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
PairerBrokerObserver pairer_broker_observer(
pairer_broker.get(), &device_paired_latch, &account_key_writed_latch,
&pairing_completed_latch, &pairing_failure_latch);
pairer_broker->PairDevice(*device_);
device_paired_latch.Await();
EXPECT_FALSE(pairing_completed_latch.Await(kWaitTimeout).result());
account_key_writed_latch.Await();
EXPECT_FALSE(pairing_failure_latch.Await(kWaitTimeout).result());
EXPECT_TRUE(triggered_keybase_value_change);
EXPECT_TRUE(triggered_passkey_value_change);
EXPECT_FALSE(device_->GetAccountKey().Ok());
EXPECT_EQ(pairer_broker_observer.account_key_failure_,
PairFailure::kAccountKeyCharacteristicWrite);
}
TEST_F(PairerBrokerImplTest, FailToPairRetryThreeTimes) {
bool triggered_keybase_value_change = false;
bool triggered_passkey_value_change = false;
CountDownLatch device_paired_latch(1);
CountDownLatch account_key_writed_latch(1);
CountDownLatch pairing_completed_latch(1);
CountDownLatch pairing_failure_latch(1);
ConfigurePairingContext();
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
Protocol::kFastPairInitialPairing);
SetUpFastPairRepository();
SetupProviderGattServer(
[&]() {
triggered_keybase_value_change = true;
EXPECT_OK(TriggerKeyBasedGattChanged());
},
[&]() {
triggered_passkey_value_change = true;
EXPECT_OK(TriggerPasskeyGattChanged("654321", kProviderPasskeyType));
});
CreateFastPairHandshakeInstanceForDevice();
SetPairingResult(std::nullopt);
EXPECT_FALSE(device_->GetAccountKey().Ok());
auto pairer_broker =
std::make_unique<PairerBrokerImpl>(*mediums_, &executor_);
PairerBrokerObserver pairer_broker_observer(
pairer_broker.get(), &device_paired_latch, &account_key_writed_latch,
&pairing_completed_latch, &pairing_failure_latch);
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());
pairing_failure_latch.Await();
EXPECT_TRUE(triggered_keybase_value_change);
EXPECT_TRUE(triggered_passkey_value_change);
EXPECT_FALSE(device_->GetAccountKey().Ok());
EXPECT_EQ(pairer_broker_observer.pair_failure_,
PairFailure::kPairingAndConnect);
}
} // namespace fastpair
} // namespace nearby