mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 07:36:10 -04:00
Implement PairerBroker for fast pair windows
PiperOrigin-RevId: 537982117
This commit is contained in:
committed by
Copybara-Service
parent
1d68d2fe10
commit
94b3263b63
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user