mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-15 07:06:11 -04:00
Implement FastPairPairer to handle the pairing process
PiperOrigin-RevId: 537124512
This commit is contained in:
committed by
Copybara-Service
parent
7c931aa9c7
commit
3dd893dd4c
@@ -3,6 +3,7 @@ cc_library(
|
||||
srcs = [
|
||||
"fast_pair_decryption.cc",
|
||||
"fast_pair_encryption.cc",
|
||||
"fast_pair_message_type.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"decrypted_passkey.h",
|
||||
@@ -102,3 +103,18 @@ cc_test(
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "fast_pair_message_type_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"fast_pair_message_type_test.cc",
|
||||
],
|
||||
shard_count = 1,
|
||||
deps = [
|
||||
":crypto",
|
||||
"//internal/platform/implementation/g3", # build_cleaner: keep
|
||||
"@com_github_protobuf_matchers//protobuf-matchers",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright 2022 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/crypto/fast_pair_message_type.h"
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream,
|
||||
FastPairMessageType message_type) {
|
||||
switch (message_type) {
|
||||
case FastPairMessageType::kKeyBasedPairingRequest:
|
||||
stream << "[Key-Based Pairing Request]";
|
||||
break;
|
||||
case FastPairMessageType::kKeyBasedPairingResponse:
|
||||
stream << "[Key-Based Pairing Response]";
|
||||
break;
|
||||
case FastPairMessageType::kSeekersPasskey:
|
||||
stream << "[Seeker's Passkey]";
|
||||
break;
|
||||
case FastPairMessageType::kProvidersPasskey:
|
||||
stream << "[Providers' Passkey]";
|
||||
break;
|
||||
default:
|
||||
stream << "[Unknown]";
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
@@ -15,23 +15,28 @@
|
||||
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_FAST_PAIR_MESSAGE_TYPE_H_
|
||||
#define THIRD_PARTY_NEARBY_FASTPAIR_CRYPTO_FAST_PAIR_MESSAGE_TYPE_H_
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
|
||||
// Type values for Fast Pair messages.
|
||||
enum class FastPairMessageType {
|
||||
// Key-based Pairing Request.
|
||||
kKeyBasedPairingRequest,
|
||||
// Key-based Pairing Response.
|
||||
kKeyBasedPairingResponse,
|
||||
// Seeker's passkey.
|
||||
kSeekersPasskey,
|
||||
// Provider's passkey.
|
||||
kProvidersPasskey,
|
||||
// Unknown message type.
|
||||
kUnknown,
|
||||
kUnknown = 0,
|
||||
// Key-based Pairing Request.
|
||||
kKeyBasedPairingRequest = 1,
|
||||
// Key-based Pairing Response.
|
||||
kKeyBasedPairingResponse = 2,
|
||||
// Seeker's passkey.
|
||||
kSeekersPasskey = 3,
|
||||
// Provider's passkey.
|
||||
kProvidersPasskey = 4,
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream,
|
||||
FastPairMessageType message_type);
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// 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/crypto/fast_pair_message_type.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
namespace {
|
||||
|
||||
TEST(FastPairMessageTypeTest, FastPairMessageTypeValue) {
|
||||
EXPECT_EQ(static_cast<int>(FastPairMessageType::kUnknown), 0);
|
||||
EXPECT_EQ(static_cast<int>(FastPairMessageType::kKeyBasedPairingRequest), 1);
|
||||
EXPECT_EQ(static_cast<int>(FastPairMessageType::kKeyBasedPairingResponse), 2);
|
||||
EXPECT_EQ(static_cast<int>(FastPairMessageType::kSeekersPasskey), 3);
|
||||
EXPECT_EQ(static_cast<int>(FastPairMessageType::kProvidersPasskey), 4);
|
||||
}
|
||||
} // namespace
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
@@ -15,18 +15,22 @@
|
||||
#include "fastpair/handshake/fast_pair_handshake_lookup.h"
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "fastpair/handshake/fast_pair_handshake_impl.h"
|
||||
#include "internal/platform/logging.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
|
||||
FastPairHandshakeLookup* FastPairHandshakeLookup::instance_ = nullptr;
|
||||
absl::Mutex FastPairHandshakeLookup::mutex_(absl::kConstInit);
|
||||
namespace {
|
||||
absl::optional<FastPairHandshakeLookup::CreateFunction> g_test_create_function =
|
||||
std::nullopt;
|
||||
}
|
||||
|
||||
// static
|
||||
FastPairHandshakeLookup* FastPairHandshakeLookup::GetInstance() {
|
||||
@@ -37,6 +41,12 @@ FastPairHandshakeLookup* FastPairHandshakeLookup::GetInstance() {
|
||||
return instance_;
|
||||
}
|
||||
|
||||
// static Create function override which can be set by tests.
|
||||
void FastPairHandshakeLookup::SetCreateFunctionForTesting(
|
||||
CreateFunction create_function) {
|
||||
g_test_create_function = std::move(create_function);
|
||||
}
|
||||
|
||||
FastPairHandshake* FastPairHandshakeLookup::Get(FastPairDevice* device) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
auto it = fast_pair_handshakes_.find(device);
|
||||
@@ -80,8 +90,11 @@ FastPairHandshake* FastPairHandshakeLookup::Create(
|
||||
FastPairDevice& device, Mediums& mediums, OnCompleteCallback on_complete) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
auto it = fast_pair_handshakes_.emplace(
|
||||
&device, std::make_unique<FastPairHandshakeImpl>(device, mediums,
|
||||
std::move(on_complete)));
|
||||
&device, g_test_create_function.has_value()
|
||||
? g_test_create_function.value()(device, mediums,
|
||||
std::move(on_complete))
|
||||
: std::make_unique<FastPairHandshakeImpl>(
|
||||
device, mediums, std::move(on_complete)));
|
||||
DCHECK(it.second);
|
||||
return it.first->second.get();
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_HANDSHAKE_LOOKUP_H_
|
||||
#define THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_HANDSHAKE_LOOKUP_H_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
@@ -35,12 +36,17 @@ class FastPairHandshakeLookup {
|
||||
using OnCompleteCallback = absl::AnyInvocable<void(
|
||||
FastPairDevice& device, std::optional<PairFailure> failure)>;
|
||||
|
||||
using CreateFunction = absl::AnyInvocable<std::unique_ptr<FastPairHandshake>(
|
||||
FastPairDevice& device, Mediums& mediums, OnCompleteCallback callback)>;
|
||||
|
||||
// This is the static method that controls the access to the singleton
|
||||
// instance. On the first run, it creates a singleton object and places it
|
||||
// into the static field. On subsequent runs, it returns the existing object
|
||||
// stored in the static field.
|
||||
static FastPairHandshakeLookup* GetInstance();
|
||||
|
||||
static void SetCreateFunctionForTesting(CreateFunction create_function);
|
||||
|
||||
// Singletons should not be cloneable.
|
||||
FastPairHandshakeLookup(const FastPairHandshakeLookup&) = delete;
|
||||
// Singletons should not be assignable.
|
||||
|
||||
@@ -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 = [
|
||||
"fast_pair_pairer_impl.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"fast_pair_pairer.h",
|
||||
"fast_pair_pairer_impl.h",
|
||||
],
|
||||
compatible_with = ["//buildenv/target:non_prod"],
|
||||
visibility = [
|
||||
"//fastpair:__subpackages__",
|
||||
"//internal:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//fastpair/common",
|
||||
"//fastpair/crypto",
|
||||
"//fastpair/handshake",
|
||||
"//fastpair/internal/mediums",
|
||||
"//internal/platform:comm",
|
||||
"//internal/platform:types",
|
||||
"@com_google_absl//absl/functional:any_invocable",
|
||||
"@com_google_absl//absl/time",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "fast_pair_pairer_impl_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"fast_pair_pairer_impl_test.cc",
|
||||
],
|
||||
shard_count = 16,
|
||||
deps = [
|
||||
":pairing",
|
||||
"//fastpair/common",
|
||||
"//fastpair/handshake",
|
||||
"//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:any_invocable",
|
||||
"@com_google_absl//absl/functional:bind_front",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/time",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,51 @@
|
||||
// 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_FASTPAIR_FAST_PAIR_PAIRER_H_
|
||||
#define THIRD_PARTY_NEARBY_FASTPAIR_PAIRING_FASTPAIR_FAST_PAIR_PAIRER_H_
|
||||
|
||||
#include "absl/functional/any_invocable.h"
|
||||
#include "fastpair/common/fast_pair_device.h"
|
||||
#include "fastpair/common/pair_failure.h"
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
|
||||
// A FastPairPairer instance is responsible for the pairing procedure to a
|
||||
// single device. Pairing begins on instantiation.
|
||||
class FastPairPairer {
|
||||
public:
|
||||
// Triggered when paired with the remote device.
|
||||
using OnPairedCallback = absl::AnyInvocable<void(FastPairDevice& device)>;
|
||||
// Triggered when failed to pair with the remote device.
|
||||
using OnPairingFailedCallback =
|
||||
absl::AnyInvocable<void(FastPairDevice& device, PairFailure failure)>;
|
||||
// Triggered when completed the whole pairing process,
|
||||
// including pairing with the remote device and writing the accountkey to it.
|
||||
using OnPairingCompletedCallback =
|
||||
absl::AnyInvocable<void(FastPairDevice& device)>;
|
||||
// Triggered when failed to write accountkey to the remote device.
|
||||
using OnAccountKeyFailureCallback =
|
||||
absl::AnyInvocable<void(FastPairDevice& device, PairFailure failure)>;
|
||||
|
||||
virtual ~FastPairPairer() = default;
|
||||
|
||||
virtual void StartPairing() = 0;
|
||||
virtual bool IsPaired() = 0;
|
||||
virtual bool CancelPairing() = 0;
|
||||
};
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_FASTPAIR_PAIRING_FASTPAIR_FAST_PAIR_PAIRER_H_
|
||||
@@ -0,0 +1,350 @@
|
||||
// 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/fastpair/fast_pair_pairer_impl.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/time/time.h"
|
||||
#include "fastpair/common/fast_pair_device.h"
|
||||
#include "fastpair/common/pair_failure.h"
|
||||
#include "fastpair/crypto/fast_pair_message_type.h"
|
||||
#include "fastpair/handshake/fast_pair_handshake_lookup.h"
|
||||
#include "fastpair/internal/mediums/mediums.h"
|
||||
#include "internal/platform/bluetooth_classic.h"
|
||||
#include "internal/platform/single_thread_executor.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
namespace {
|
||||
constexpr absl::Duration kInitiatePairingTimeout = absl::Seconds(20);
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
FastPairPairerImpl::Factory* FastPairPairerImpl::Factory::g_test_factory_ =
|
||||
nullptr;
|
||||
|
||||
// static
|
||||
std::unique_ptr<FastPairPairer> FastPairPairerImpl::Factory::Create(
|
||||
FastPairDevice& device, Mediums& medium, SingleThreadExecutor* executor,
|
||||
OnPairedCallback on_paired_cb, OnPairingFailedCallback on_pair_failed_cb,
|
||||
OnAccountKeyFailureCallback on_account_failure_cb,
|
||||
OnPairingCompletedCallback on_pairing_completed_cb) {
|
||||
if (g_test_factory_) {
|
||||
return g_test_factory_->CreateInstance(
|
||||
device, medium, executor, std::move(on_paired_cb),
|
||||
std::move(on_pair_failed_cb), std::move(on_account_failure_cb),
|
||||
std::move(on_pairing_completed_cb));
|
||||
}
|
||||
return std::make_unique<FastPairPairerImpl>(
|
||||
device, medium, executor, std::move(on_paired_cb),
|
||||
std::move(on_pair_failed_cb), std::move(on_account_failure_cb),
|
||||
std::move(on_pairing_completed_cb));
|
||||
}
|
||||
|
||||
// static
|
||||
void FastPairPairerImpl::Factory::SetFactoryForTesting(
|
||||
Factory* g_test_factory) {
|
||||
g_test_factory_ = g_test_factory;
|
||||
}
|
||||
|
||||
FastPairPairerImpl::FastPairPairerImpl(
|
||||
FastPairDevice& device, Mediums& medium, SingleThreadExecutor* executor,
|
||||
OnPairedCallback on_paired_cb, OnPairingFailedCallback on_pair_failed_cb,
|
||||
OnAccountKeyFailureCallback on_account_failure_cb,
|
||||
OnPairingCompletedCallback on_pairing_completed_cb)
|
||||
: device_(device),
|
||||
mediums_(medium),
|
||||
executor_(executor),
|
||||
on_paired_cb_(std::move(on_paired_cb)),
|
||||
on_pair_failed_cb_(std::move(on_pair_failed_cb)),
|
||||
on_account_key_failure_cb_(std::move(on_account_failure_cb)),
|
||||
on_pairing_completed_cb_(std::move(on_pairing_completed_cb)) {
|
||||
if (device_.GetVersion().value() == DeviceFastPairVersion::kHigherThanV1) {
|
||||
// Obtains the established GATT connection for use in the pairing process:
|
||||
// confirm the passkey, write the account key, etc.
|
||||
fast_pair_handshake_ =
|
||||
FastPairHandshakeLookup::GetInstance()->Get(&device_);
|
||||
CHECK(fast_pair_handshake_);
|
||||
CHECK(fast_pair_handshake_->completed_successfully());
|
||||
fast_pair_gatt_service_client_ =
|
||||
fast_pair_handshake_->fast_pair_gatt_service_client();
|
||||
}
|
||||
}
|
||||
|
||||
void FastPairPairerImpl::StartPairing() {
|
||||
executor_->Execute(
|
||||
"Start Pairing", [&]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
|
||||
NEARBY_LOGS(INFO) << __func__ << device_;
|
||||
switch (device_.GetProtocol()) {
|
||||
case Protocol::kFastPairInitialPairing:
|
||||
case Protocol::kFastPairSubsequentPairing:
|
||||
// This timer captures a pairing timeout.
|
||||
initiate_pairing_timer_.Start(
|
||||
kInitiatePairingTimeout / absl::Milliseconds(1), 0, [&]() {
|
||||
NEARBY_LOGS(WARNING)
|
||||
<< __func__
|
||||
<< ": Timeout while attempting to initiate "
|
||||
"pairing with device.";
|
||||
NotifyPairingFailed(PairFailure::kPairingTimeout);
|
||||
});
|
||||
InitiatePairing();
|
||||
break;
|
||||
case Protocol::kFastPairRetroactivePairing:
|
||||
// Because the devices are already paired, we will directly write an
|
||||
// account key to the Provider after a shared secret is established.
|
||||
AttemptSendAccountKey();
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Blocking functions
|
||||
void FastPairPairerImpl::InitiatePairing() {
|
||||
NEARBY_LOGS(INFO) << __func__;
|
||||
// TODO(b/278810942) : Check if device lost first
|
||||
if (mediums_.GetBluetoothRadio().Enable() &&
|
||||
mediums_.GetBluetoothClassic().IsAvailable()) {
|
||||
bluetooth_pairing_ = mediums_.GetBluetoothClassic().CreatePairing(
|
||||
device_.GetPublicAddress().value());
|
||||
}
|
||||
if (!bluetooth_pairing_) {
|
||||
NotifyPairingFailed(PairFailure::kPairingAndConnect);
|
||||
return;
|
||||
}
|
||||
// Unpair with the remote device before initializing a new pairing request
|
||||
if (!bluetooth_pairing_->Unpair()) {
|
||||
NotifyPairingFailed(PairFailure::kPairingAndConnect);
|
||||
return;
|
||||
}
|
||||
if (!bluetooth_pairing_->InitiatePairing({
|
||||
.on_paired_cb =
|
||||
[&]() {
|
||||
if (!initiate_pairing_timer_.IsRunning()) {
|
||||
NEARBY_LOGS(INFO)
|
||||
<< __func__ << " Initiating pairing has timed out.";
|
||||
return;
|
||||
}
|
||||
initiate_pairing_timer_.Stop();
|
||||
NEARBY_LOGS(INFO) << __func__ << " Paired with " << device_;
|
||||
// On Windows, Pair is exactly the same as Connect.
|
||||
NotifyPaired();
|
||||
executor_->Execute(
|
||||
"Write Accountkey",
|
||||
[&]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) {
|
||||
AttemptSendAccountKey();
|
||||
});
|
||||
},
|
||||
.on_pairing_error_cb =
|
||||
[&](api::BluetoothPairingCallback::PairingError error) {
|
||||
NEARBY_LOGS(INFO)
|
||||
<< __func__ << "Failed to pair with device due to error "
|
||||
<< static_cast<int>(error);
|
||||
NotifyPairingFailed(PairFailure::kPairingAndConnect);
|
||||
},
|
||||
.on_pairing_initiated_cb =
|
||||
[&](api::PairingParams pairingParams) {
|
||||
if (!initiate_pairing_timer_.IsRunning()) {
|
||||
NEARBY_LOGS(INFO)
|
||||
<< __func__ << " Initiating pairing has timed out.";
|
||||
return;
|
||||
}
|
||||
NEARBY_LOGS(INFO) << __func__ << "Initiated pairing request.";
|
||||
if (device_.GetVersion().value() ==
|
||||
DeviceFastPairVersion::kV1) {
|
||||
NEARBY_LOGS(INFO)
|
||||
<< __func__
|
||||
<< ": For v1 headset, skip passkey confirmation.";
|
||||
bluetooth_pairing_->FinishPairing(std::nullopt);
|
||||
} else {
|
||||
NEARBY_LOGS(INFO)
|
||||
<< __func__ << ": For headsets higher than v1, "
|
||||
<< "confirm passkey before accepting pairing.";
|
||||
ConfirmPasskey(pairingParams);
|
||||
}
|
||||
},
|
||||
})) {
|
||||
NotifyPairingFailed(PairFailure::kPairingAndConnect);
|
||||
}
|
||||
}
|
||||
|
||||
void FastPairPairerImpl::ConfirmPasskey(api::PairingParams pairingParams) {
|
||||
if (!FastPairHandshakeLookup::GetInstance()->Get(&device_)) {
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< ": BLE device instance lost during passkey exchange";
|
||||
bluetooth_pairing_->CancelPairing();
|
||||
NotifyPairingFailed(PairFailure::kDeviceLostMidPairing);
|
||||
return;
|
||||
}
|
||||
expected_passkey_ = pairingParams.passkey;
|
||||
NEARBY_LOGS(INFO) << __func__
|
||||
<< " Star to confirm passkey: " << expected_passkey_;
|
||||
fast_pair_gatt_service_client_->WritePasskeyAsync(
|
||||
/*message_type=*/0x02, std::stoi(expected_passkey_),
|
||||
*fast_pair_handshake_->fast_pair_data_encryptor(),
|
||||
[&](absl::string_view response,
|
||||
std::optional<fastpair::PairFailure> failure) {
|
||||
OnPasskeyResponse(response, failure);
|
||||
});
|
||||
}
|
||||
|
||||
void FastPairPairerImpl::OnPasskeyResponse(absl::string_view response,
|
||||
std::optional<PairFailure> failure) {
|
||||
NEARBY_LOGS(INFO) << __func__;
|
||||
if (failure.has_value()) {
|
||||
NotifyPairingFailed(failure.value());
|
||||
return;
|
||||
}
|
||||
std::vector<uint8_t> response_bytes(response.begin(), response.end());
|
||||
fast_pair_handshake_->fast_pair_data_encryptor()->ParseDecryptPasskey(
|
||||
response_bytes, [&](const std::optional<DecryptedPasskey> passkey) {
|
||||
OnParseDecryptedPasskey(passkey);
|
||||
});
|
||||
}
|
||||
|
||||
void FastPairPairerImpl::OnParseDecryptedPasskey(
|
||||
std::optional<DecryptedPasskey> passkey) {
|
||||
if (!passkey.has_value()) {
|
||||
NotifyPairingFailed(PairFailure::kPasskeyDecryptFailure);
|
||||
return;
|
||||
}
|
||||
if (passkey->message_type != FastPairMessageType::kProvidersPasskey) {
|
||||
NEARBY_LOGS(WARNING)
|
||||
<< "Incorrect message type from decrypted passkey. Expected: "
|
||||
<< FastPairMessageType::kProvidersPasskey
|
||||
<< ". Actual: " << passkey->message_type;
|
||||
NotifyPairingFailed(PairFailure::kIncorrectPasskeyResponseType);
|
||||
return;
|
||||
}
|
||||
|
||||
if (passkey->passkey != std::stoi(expected_passkey_)) {
|
||||
NEARBY_LOGS(ERROR) << "Passkeys do not match. "
|
||||
<< "Expected: " << expected_passkey_
|
||||
<< ". Actual: " << std::to_string(passkey->passkey);
|
||||
NotifyPairingFailed(PairFailure::kPasskeyMismatch);
|
||||
return;
|
||||
}
|
||||
// TODO(b/278810942) : Check if device lost
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Passkeys match, confirming pairing";
|
||||
bluetooth_pairing_->FinishPairing(std::nullopt);
|
||||
}
|
||||
|
||||
bool FastPairPairerImpl::CancelPairing() {
|
||||
if (!bluetooth_pairing_) {
|
||||
NEARBY_LOGS(WARNING) << __func__ << ": No on-going pairing process.";
|
||||
return false;
|
||||
}
|
||||
return bluetooth_pairing_->CancelPairing();
|
||||
}
|
||||
|
||||
bool FastPairPairerImpl::IsPaired() {
|
||||
if (!bluetooth_pairing_) {
|
||||
return false;
|
||||
}
|
||||
return bluetooth_pairing_->IsPaired();
|
||||
}
|
||||
|
||||
void FastPairPairerImpl::AttemptSendAccountKey() {
|
||||
if (device_.GetVersion().value() == DeviceFastPairVersion::kV1) {
|
||||
NotifyPairingCompleted();
|
||||
return;
|
||||
}
|
||||
|
||||
// We only send the account key if we're doing an initial or retroactive
|
||||
// pairing. For subsequent pairing, we have to save the account key
|
||||
// locally so that we can refer to it in API calls to the server.
|
||||
if (device_.GetProtocol() == Protocol::kFastPairSubsequentPairing) {
|
||||
NEARBY_LOGS(VERBOSE) << __func__
|
||||
<< ": Saving Account Key locally for subsequent pair";
|
||||
// TODO(b/278807993): Saving Account Key locally for subsequent pair
|
||||
NotifyPairingCompleted();
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(b/281781730) : Check if we need to send account key
|
||||
// TODO(b/281782018) : Handle BLE address rotation
|
||||
fast_pair_gatt_service_client_->WriteAccountKey(
|
||||
*fast_pair_handshake_->fast_pair_data_encryptor(),
|
||||
[&](const std::optional<AccountKey> account_key,
|
||||
const std::optional<PairFailure> failure) {
|
||||
OnWriteAccountKey(account_key, failure);
|
||||
});
|
||||
}
|
||||
|
||||
void FastPairPairerImpl::OnWriteAccountKey(
|
||||
std::optional<AccountKey> account_key, std::optional<PairFailure> failure) {
|
||||
if (failure.has_value()) {
|
||||
NEARBY_LOGS(WARNING)
|
||||
<< __func__ << "Failed to write account key to device due to error: "
|
||||
<< failure.value();
|
||||
NotifyAccountKeyFailure(failure.value());
|
||||
return;
|
||||
}
|
||||
if (!account_key.has_value()) {
|
||||
NotifyAccountKeyFailure(PairFailure::kAccountKeyCharacteristicWrite);
|
||||
return;
|
||||
}
|
||||
device_.SetAccountKey(account_key.value());
|
||||
// // TODO(b/281785681): Write account association to footprints
|
||||
NotifyPairingCompleted();
|
||||
}
|
||||
|
||||
void FastPairPairerImpl::NotifyPaired() {
|
||||
NEARBY_LOGS(INFO) << __func__ << device_;
|
||||
executor_->Execute("NotifyPaired",
|
||||
[&, on_paired_cb = std::move(on_paired_cb_)]() mutable {
|
||||
on_paired_cb(device_);
|
||||
});
|
||||
}
|
||||
|
||||
void FastPairPairerImpl::NotifyPairingFailed(PairFailure failure) {
|
||||
NEARBY_LOGS(WARNING) << __func__ << failure;
|
||||
// Stop initiate pairing timer as piaring is terminate this time.
|
||||
initiate_pairing_timer_.Stop();
|
||||
executor_->Execute("NotifyPairingFailed",
|
||||
[&, on_pair_failed_cb = std::move(on_pair_failed_cb_),
|
||||
failure = std::move(failure)]() mutable {
|
||||
on_pair_failed_cb(device_, failure);
|
||||
});
|
||||
}
|
||||
|
||||
void FastPairPairerImpl::NotifyPairingCompleted() {
|
||||
NEARBY_LOGS(INFO)
|
||||
<< __func__
|
||||
<< "Account key written to device. Pairing procedure complete.";
|
||||
executor_->Execute("Notify Pairing Completed",
|
||||
[&, on_pairing_completed_cb =
|
||||
std::move(on_pairing_completed_cb_)]() mutable {
|
||||
on_pairing_completed_cb(device_);
|
||||
});
|
||||
}
|
||||
|
||||
void FastPairPairerImpl::NotifyAccountKeyFailure(PairFailure failure) {
|
||||
NEARBY_LOGS(WARNING) << __func__
|
||||
<< "Failed to write account key to device due to error: "
|
||||
<< failure;
|
||||
executor_->Execute(
|
||||
"Notify AccountKey Failure",
|
||||
[&, on_account_key_failure_cb = std::move(on_account_key_failure_cb_),
|
||||
failure = std::move(failure)]() mutable {
|
||||
on_account_key_failure_cb(device_, failure);
|
||||
});
|
||||
}
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,119 @@
|
||||
// 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_FASTPAIR_FAST_PAIR_PAIRER_IMPL_H_
|
||||
#define THIRD_PARTY_NEARBY_FASTPAIR_PAIRING_FASTPAIR_FAST_PAIR_PAIRER_IMPL_H_
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "fastpair/common/fast_pair_device.h"
|
||||
#include "fastpair/common/pair_failure.h"
|
||||
#include "fastpair/crypto/decrypted_passkey.h"
|
||||
#include "fastpair/handshake/fast_pair_gatt_service_client.h"
|
||||
#include "fastpair/handshake/fast_pair_handshake.h"
|
||||
#include "fastpair/internal/mediums/mediums.h"
|
||||
#include "fastpair/pairing/fastpair/fast_pair_pairer.h"
|
||||
#include "internal/platform/bluetooth_classic.h"
|
||||
#include "internal/platform/single_thread_executor.h"
|
||||
#include "internal/platform/timer_impl.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace fastpair {
|
||||
|
||||
class FastPairPairerImpl : public FastPairPairer {
|
||||
public:
|
||||
class Factory {
|
||||
public:
|
||||
static std::unique_ptr<FastPairPairer> Create(
|
||||
FastPairDevice& device, Mediums& medium, SingleThreadExecutor* executor,
|
||||
OnPairedCallback on_paired_cb,
|
||||
OnPairingFailedCallback on_pair_failed_cb,
|
||||
OnAccountKeyFailureCallback on_account_failure_cb,
|
||||
OnPairingCompletedCallback on_pairing_completed_cb);
|
||||
|
||||
static void SetFactoryForTesting(Factory* test_factory);
|
||||
|
||||
protected:
|
||||
virtual ~Factory() = default;
|
||||
|
||||
virtual std::unique_ptr<FastPairPairer> CreateInstance(
|
||||
FastPairDevice& device, Mediums& medium, SingleThreadExecutor* executor,
|
||||
OnPairedCallback on_paired_cb,
|
||||
OnPairingFailedCallback on_pair_failed_cb,
|
||||
OnAccountKeyFailureCallback on_account_failure_cb,
|
||||
OnPairingCompletedCallback on_pairing_completed_cb) = 0;
|
||||
|
||||
private:
|
||||
static Factory* g_test_factory_;
|
||||
};
|
||||
|
||||
FastPairPairerImpl(FastPairDevice& device, Mediums& medium,
|
||||
SingleThreadExecutor* executor,
|
||||
OnPairedCallback on_paired_cb,
|
||||
OnPairingFailedCallback on_pair_failed_cb,
|
||||
OnAccountKeyFailureCallback on_account_failure_cb,
|
||||
OnPairingCompletedCallback on_pairing_completed_cb);
|
||||
FastPairPairerImpl(const FastPairPairerImpl&) = delete;
|
||||
FastPairPairerImpl& operator=(const FastPairPairerImpl&) = delete;
|
||||
FastPairPairerImpl(FastPairPairerImpl&&) = delete;
|
||||
FastPairPairerImpl& operator=(FastPairPairerImpl&&) = delete;
|
||||
bool CancelPairing() override;
|
||||
bool IsPaired() override;
|
||||
void StartPairing() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) override;
|
||||
|
||||
private:
|
||||
void InitiatePairing();
|
||||
|
||||
void ConfirmPasskey(api::PairingParams pairingParams);
|
||||
// FastPairGattServiceClient::WritePasskey callback
|
||||
void OnPasskeyResponse(absl::string_view response,
|
||||
std::optional<PairFailure> failure);
|
||||
// FastPairDataEncryptor::ParseDecryptedPasskey callback
|
||||
void OnParseDecryptedPasskey(std::optional<DecryptedPasskey> passkey);
|
||||
|
||||
// Attempts to write account key to remote device
|
||||
void AttemptSendAccountKey() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
|
||||
// FastPairDataEncryptor::WriteAccountKey callback
|
||||
void OnWriteAccountKey(std::optional<AccountKey> account_key,
|
||||
std::optional<PairFailure> failure);
|
||||
|
||||
// Notify the result of pairing and writing accoutkey.
|
||||
void NotifyPaired();
|
||||
void NotifyPairingFailed(PairFailure failure);
|
||||
void NotifyPairingCompleted();
|
||||
void NotifyAccountKeyFailure(PairFailure failure);
|
||||
|
||||
std::string expected_passkey_;
|
||||
FastPairHandshake* fast_pair_handshake_;
|
||||
FastPairGattServiceClient* fast_pair_gatt_service_client_;
|
||||
std::unique_ptr<BluetoothPairing> bluetooth_pairing_;
|
||||
FastPairDevice& device_;
|
||||
Mediums& mediums_;
|
||||
SingleThreadExecutor* executor_;
|
||||
OnPairedCallback on_paired_cb_ ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
|
||||
OnPairingFailedCallback on_pair_failed_cb_
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
|
||||
OnAccountKeyFailureCallback on_account_key_failure_cb_
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
|
||||
OnPairingCompletedCallback on_pairing_completed_cb_
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_);
|
||||
TimerImpl initiate_pairing_timer_;
|
||||
};
|
||||
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_FASTPAIR_PAIRING_FASTPAIR_FAST_PAIR_PAIRER_IMPL_H_
|
||||
@@ -0,0 +1,937 @@
|
||||
// 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/fastpair/fast_pair_pairer_impl.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#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/any_invocable.h"
|
||||
#include "absl/functional/bind_front.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "fastpair//handshake/fast_pair_handshake_lookup.h"
|
||||
#include "fastpair/common/account_key.h"
|
||||
#include "fastpair/common/constant.h"
|
||||
#include "fastpair/common/fast_pair_device.h"
|
||||
#include "fastpair/common/protocol.h"
|
||||
#include "fastpair/handshake/fast_pair_data_encryptor_impl.h"
|
||||
#include "fastpair/handshake/fast_pair_handshake_impl.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/bluetooth_adapter.h"
|
||||
#include "internal/platform/count_down_latch.h"
|
||||
#include "internal/platform/medium_environment.h"
|
||||
#include "internal/platform/single_thread_executor.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 FastPairPairerImplTest : 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(
|
||||
&FastPairPairerImplTest::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) {
|
||||
FastPairDataEncryptor* 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(FastPairPairerImplTest,
|
||||
SuccessInitialPairingWithDeviceVersionHigherThanV1) {
|
||||
ConfigurePairingContext();
|
||||
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
|
||||
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));
|
||||
});
|
||||
CreateFastPairHandshakeInstanceForDevice();
|
||||
SetPairingResult(std::nullopt);
|
||||
CountDownLatch paired_latch(1);
|
||||
CountDownLatch complete_latch(1);
|
||||
CountDownLatch failure_latch(1);
|
||||
CountDownLatch account_failure_latch(1);
|
||||
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
|
||||
fast_pair_pairer_ = FastPairPairerImpl::Factory::Create(
|
||||
*device_, *mediums_, &executor_,
|
||||
[&](FastPairDevice& cb_device) { paired_latch.CountDown(); },
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
account_failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device) {
|
||||
EXPECT_TRUE(device.GetAccountKey().Ok());
|
||||
complete_latch.CountDown();
|
||||
});
|
||||
fast_pair_pairer_->StartPairing();
|
||||
paired_latch.Await();
|
||||
EXPECT_FALSE(failure_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_FALSE(account_failure_latch.Await(kWaitTimeout).result());
|
||||
complete_latch.Await();
|
||||
|
||||
EXPECT_TRUE(triggered_keybase_value_change);
|
||||
EXPECT_TRUE(triggered_passkey_value_change);
|
||||
EXPECT_TRUE(fast_pair_pairer_->IsPaired());
|
||||
EXPECT_TRUE(device_->GetAccountKey().Ok());
|
||||
}
|
||||
|
||||
TEST_F(FastPairPairerImplTest, 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 paired_latch(1);
|
||||
CountDownLatch complete_latch(1);
|
||||
CountDownLatch failure_latch(1);
|
||||
CountDownLatch account_failure_latch(1);
|
||||
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
|
||||
fast_pair_pairer_ = FastPairPairerImpl::Factory::Create(
|
||||
*device_, *mediums_, &executor_,
|
||||
[&](FastPairDevice& cb_device) { paired_latch.CountDown(); },
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
account_failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device) {
|
||||
EXPECT_FALSE(device.GetAccountKey().Ok());
|
||||
complete_latch.CountDown();
|
||||
});
|
||||
fast_pair_pairer_->StartPairing();
|
||||
paired_latch.Await();
|
||||
EXPECT_FALSE(failure_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_FALSE(account_failure_latch.Await(kWaitTimeout).result());
|
||||
complete_latch.Await();
|
||||
EXPECT_FALSE(triggered_keybase_value_change);
|
||||
EXPECT_FALSE(triggered_passkey_value_change);
|
||||
EXPECT_TRUE(fast_pair_pairer_->IsPaired());
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
}
|
||||
|
||||
TEST_F(FastPairPairerImplTest, SuccessSubsequentPairingWithDevice) {
|
||||
ConfigurePairingContext();
|
||||
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
|
||||
Protocol::kFastPairSubsequentPairing);
|
||||
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 paired_latch(1);
|
||||
CountDownLatch complete_latch(1);
|
||||
CountDownLatch failure_latch(1);
|
||||
CountDownLatch account_failure_latch(1);
|
||||
|
||||
fast_pair_pairer_ = FastPairPairerImpl::Factory::Create(
|
||||
*device_, *mediums_, &executor_,
|
||||
[&](FastPairDevice& cb_device) { paired_latch.CountDown(); },
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
account_failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device) {
|
||||
EXPECT_TRUE(device.GetAccountKey().Ok());
|
||||
complete_latch.CountDown();
|
||||
});
|
||||
fast_pair_pairer_->StartPairing();
|
||||
paired_latch.Await();
|
||||
EXPECT_FALSE(failure_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_FALSE(account_failure_latch.Await(kWaitTimeout).result());
|
||||
complete_latch.Await();
|
||||
|
||||
EXPECT_TRUE(triggered_keybase_value_change);
|
||||
EXPECT_TRUE(triggered_passkey_value_change);
|
||||
EXPECT_TRUE(fast_pair_pairer_->IsPaired());
|
||||
}
|
||||
|
||||
TEST_F(FastPairPairerImplTest, 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 paired_latch(1);
|
||||
CountDownLatch complete_latch(1);
|
||||
CountDownLatch failure_latch(1);
|
||||
CountDownLatch account_failure_latch(1);
|
||||
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
|
||||
fast_pair_pairer_ = FastPairPairerImpl::Factory::Create(
|
||||
*device_, *mediums_, &executor_,
|
||||
[&](FastPairDevice& cb_device) { paired_latch.CountDown(); },
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
account_failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device) {
|
||||
EXPECT_TRUE(device.GetAccountKey().Ok());
|
||||
complete_latch.CountDown();
|
||||
});
|
||||
fast_pair_pairer_->StartPairing();
|
||||
EXPECT_FALSE(paired_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_FALSE(failure_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_FALSE(account_failure_latch.Await(kWaitTimeout).result());
|
||||
complete_latch.Await();
|
||||
|
||||
EXPECT_TRUE(triggered_keybase_value_change);
|
||||
EXPECT_FALSE(triggered_passkey_value_change);
|
||||
EXPECT_TRUE(device_->GetAccountKey().Ok());
|
||||
}
|
||||
|
||||
TEST_F(FastPairPairerImplTest, FailedToUnPair) {
|
||||
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
|
||||
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));
|
||||
});
|
||||
CreateFastPairHandshakeInstanceForDevice();
|
||||
CountDownLatch paired_latch(1);
|
||||
CountDownLatch complete_latch(1);
|
||||
CountDownLatch failure_latch(1);
|
||||
CountDownLatch account_failure_latch(1);
|
||||
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
|
||||
fast_pair_pairer_ = FastPairPairerImpl::Factory::Create(
|
||||
*device_, *mediums_, &executor_,
|
||||
[&](FastPairDevice& cb_device) { paired_latch.CountDown(); },
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
EXPECT_EQ(failure, PairFailure::kPairingAndConnect);
|
||||
failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
account_failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device) {
|
||||
EXPECT_TRUE(device.GetAccountKey().Ok());
|
||||
complete_latch.CountDown();
|
||||
});
|
||||
fast_pair_pairer_->StartPairing();
|
||||
EXPECT_FALSE(paired_latch.Await(kWaitTimeout).result());
|
||||
failure_latch.Await();
|
||||
EXPECT_FALSE(complete_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_FALSE(account_failure_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_TRUE(triggered_keybase_value_change);
|
||||
EXPECT_FALSE(triggered_passkey_value_change);
|
||||
EXPECT_FALSE(fast_pair_pairer_->IsPaired());
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
}
|
||||
|
||||
TEST_F(FastPairPairerImplTest, FailedToPairingWithAuthTimeout) {
|
||||
ConfigurePairingContext();
|
||||
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
|
||||
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));
|
||||
});
|
||||
CreateFastPairHandshakeInstanceForDevice();
|
||||
SetPairingResult(api::BluetoothPairingCallback::PairingError::kAuthTimeout);
|
||||
CountDownLatch paired_latch(1);
|
||||
CountDownLatch complete_latch(1);
|
||||
CountDownLatch failure_latch(1);
|
||||
CountDownLatch account_failure_latch(1);
|
||||
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
|
||||
fast_pair_pairer_ = FastPairPairerImpl::Factory::Create(
|
||||
*device_, *mediums_, &executor_,
|
||||
[&](FastPairDevice& cb_device) { paired_latch.CountDown(); },
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
EXPECT_EQ(failure, PairFailure::kPairingAndConnect);
|
||||
failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
account_failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device) {
|
||||
EXPECT_TRUE(device.GetAccountKey().Ok());
|
||||
complete_latch.CountDown();
|
||||
});
|
||||
fast_pair_pairer_->StartPairing();
|
||||
EXPECT_FALSE(paired_latch.Await(kWaitTimeout).result());
|
||||
failure_latch.Await();
|
||||
EXPECT_FALSE(complete_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_FALSE(account_failure_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_TRUE(triggered_keybase_value_change);
|
||||
EXPECT_TRUE(triggered_passkey_value_change);
|
||||
EXPECT_FALSE(fast_pair_pairer_->IsPaired());
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
}
|
||||
|
||||
TEST_F(FastPairPairerImplTest, NoPasskeyResponse) {
|
||||
ConfigurePairingContext();
|
||||
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
|
||||
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; });
|
||||
CreateFastPairHandshakeInstanceForDevice();
|
||||
SetPairingResult(std::nullopt);
|
||||
CountDownLatch paired_latch(1);
|
||||
CountDownLatch complete_latch(1);
|
||||
CountDownLatch failure_latch(1);
|
||||
CountDownLatch account_failure_latch(1);
|
||||
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
|
||||
fast_pair_pairer_ = FastPairPairerImpl::Factory::Create(
|
||||
*device_, *mediums_, &executor_,
|
||||
[&](FastPairDevice& cb_device) { paired_latch.CountDown(); },
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
EXPECT_EQ(failure, PairFailure::kPasskeyResponseTimeout);
|
||||
failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
account_failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device) {
|
||||
EXPECT_TRUE(device.GetAccountKey().Ok());
|
||||
complete_latch.CountDown();
|
||||
});
|
||||
fast_pair_pairer_->StartPairing();
|
||||
EXPECT_FALSE(paired_latch.Await(kWaitTimeout).result());
|
||||
failure_latch.Await();
|
||||
EXPECT_FALSE(complete_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_FALSE(account_failure_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_TRUE(triggered_keybase_value_change);
|
||||
EXPECT_TRUE(triggered_passkey_value_change);
|
||||
EXPECT_FALSE(fast_pair_pairer_->IsPaired());
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
}
|
||||
|
||||
TEST_F(FastPairPairerImplTest, PasskeyMismatch) {
|
||||
ConfigurePairingContext();
|
||||
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
|
||||
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("654321", kProviderPasskeyType));
|
||||
});
|
||||
CreateFastPairHandshakeInstanceForDevice();
|
||||
SetPairingResult(std::nullopt);
|
||||
CountDownLatch paired_latch(1);
|
||||
CountDownLatch complete_latch(1);
|
||||
CountDownLatch failure_latch(1);
|
||||
CountDownLatch account_failure_latch(1);
|
||||
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
|
||||
fast_pair_pairer_ = FastPairPairerImpl::Factory::Create(
|
||||
*device_, *mediums_, &executor_,
|
||||
[&](FastPairDevice& cb_device) { paired_latch.CountDown(); },
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
EXPECT_EQ(failure, PairFailure::kPasskeyMismatch);
|
||||
failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
account_failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device) {
|
||||
EXPECT_TRUE(device.GetAccountKey().Ok());
|
||||
complete_latch.CountDown();
|
||||
});
|
||||
fast_pair_pairer_->StartPairing();
|
||||
EXPECT_FALSE(paired_latch.Await(kWaitTimeout).result());
|
||||
failure_latch.Await();
|
||||
EXPECT_FALSE(complete_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_FALSE(account_failure_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_TRUE(triggered_keybase_value_change);
|
||||
EXPECT_TRUE(triggered_passkey_value_change);
|
||||
EXPECT_FALSE(fast_pair_pairer_->IsPaired());
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
}
|
||||
|
||||
TEST_F(FastPairPairerImplTest, ReceiveWithWrongPasskeyResponse) {
|
||||
ConfigurePairingContext();
|
||||
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
|
||||
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(TriggerPasskeyGattChangedWithWrongResponse());
|
||||
});
|
||||
CreateFastPairHandshakeInstanceForDevice();
|
||||
SetPairingResult(std::nullopt);
|
||||
CountDownLatch paired_latch(1);
|
||||
CountDownLatch complete_latch(1);
|
||||
CountDownLatch failure_latch(1);
|
||||
CountDownLatch account_failure_latch(1);
|
||||
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
|
||||
fast_pair_pairer_ = FastPairPairerImpl::Factory::Create(
|
||||
*device_, *mediums_, &executor_,
|
||||
[&](FastPairDevice& cb_device) { paired_latch.CountDown(); },
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
EXPECT_EQ(failure, PairFailure::kPasskeyDecryptFailure);
|
||||
failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
account_failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device) {
|
||||
EXPECT_TRUE(device.GetAccountKey().Ok());
|
||||
complete_latch.CountDown();
|
||||
});
|
||||
fast_pair_pairer_->StartPairing();
|
||||
EXPECT_FALSE(paired_latch.Await(kWaitTimeout).result());
|
||||
failure_latch.Await();
|
||||
EXPECT_FALSE(complete_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_FALSE(account_failure_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_TRUE(triggered_keybase_value_change);
|
||||
EXPECT_TRUE(triggered_passkey_value_change);
|
||||
EXPECT_FALSE(fast_pair_pairer_->IsPaired());
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
}
|
||||
|
||||
TEST_F(FastPairPairerImplTest, ReceiveWithWrongPasskeyMessageType) {
|
||||
ConfigurePairingContext();
|
||||
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
|
||||
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, kSeekerPasskeyType));
|
||||
});
|
||||
CreateFastPairHandshakeInstanceForDevice();
|
||||
SetPairingResult(std::nullopt);
|
||||
CountDownLatch paired_latch(1);
|
||||
CountDownLatch complete_latch(1);
|
||||
CountDownLatch failure_latch(1);
|
||||
CountDownLatch account_failure_latch(1);
|
||||
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
|
||||
fast_pair_pairer_ = FastPairPairerImpl::Factory::Create(
|
||||
*device_, *mediums_, &executor_,
|
||||
[&](FastPairDevice& cb_device) { paired_latch.CountDown(); },
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
EXPECT_EQ(failure, PairFailure::kIncorrectPasskeyResponseType);
|
||||
failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
account_failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device) {
|
||||
EXPECT_TRUE(device.GetAccountKey().Ok());
|
||||
complete_latch.CountDown();
|
||||
});
|
||||
fast_pair_pairer_->StartPairing();
|
||||
EXPECT_FALSE(paired_latch.Await(kWaitTimeout).result());
|
||||
failure_latch.Await();
|
||||
EXPECT_FALSE(complete_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_FALSE(account_failure_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_TRUE(triggered_keybase_value_change);
|
||||
EXPECT_TRUE(triggered_passkey_value_change);
|
||||
EXPECT_FALSE(fast_pair_pairer_->IsPaired());
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
}
|
||||
|
||||
TEST_F(FastPairPairerImplTest,
|
||||
SuccessPairingWithDeviceButFailedToWriteAccountkey) {
|
||||
ConfigurePairingContext();
|
||||
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
|
||||
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));
|
||||
});
|
||||
CreateFastPairHandshakeInstanceForDevice();
|
||||
SetPairingResult(std::nullopt);
|
||||
SetAccountkeyCharacteristicsWriteResultToFailure();
|
||||
CountDownLatch paired_latch(1);
|
||||
CountDownLatch complete_latch(1);
|
||||
CountDownLatch failure_latch(1);
|
||||
CountDownLatch account_failure_latch(1);
|
||||
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
|
||||
fast_pair_pairer_ = FastPairPairerImpl::Factory::Create(
|
||||
*device_, *mediums_, &executor_,
|
||||
[&](FastPairDevice& cb_device) { paired_latch.CountDown(); },
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
account_failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device) {
|
||||
EXPECT_TRUE(device.GetAccountKey().Ok());
|
||||
complete_latch.CountDown();
|
||||
});
|
||||
fast_pair_pairer_->StartPairing();
|
||||
paired_latch.Await();
|
||||
EXPECT_FALSE(failure_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_FALSE(complete_latch.Await(kWaitTimeout).result());
|
||||
account_failure_latch.Await();
|
||||
EXPECT_TRUE(triggered_keybase_value_change);
|
||||
EXPECT_TRUE(triggered_passkey_value_change);
|
||||
EXPECT_TRUE(fast_pair_pairer_->IsPaired());
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
}
|
||||
|
||||
TEST_F(FastPairPairerImplTest, TestCancelPairing) {
|
||||
ConfigurePairingContext();
|
||||
CreateMockDevice(DeviceFastPairVersion::kHigherThanV1,
|
||||
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;
|
||||
fast_pair_pairer_->CancelPairing();
|
||||
});
|
||||
CreateFastPairHandshakeInstanceForDevice();
|
||||
SetPairingResult(std::nullopt);
|
||||
CountDownLatch paired_latch(1);
|
||||
CountDownLatch complete_latch(1);
|
||||
CountDownLatch failure_latch(1);
|
||||
CountDownLatch account_failure_latch(1);
|
||||
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
|
||||
fast_pair_pairer_ = FastPairPairerImpl::Factory::Create(
|
||||
*device_, *mediums_, &executor_,
|
||||
[&](FastPairDevice& cb_device) { paired_latch.CountDown(); },
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
EXPECT_EQ(failure, PairFailure::kPairingAndConnect);
|
||||
failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device, PairFailure failure) {
|
||||
account_failure_latch.CountDown();
|
||||
},
|
||||
[&](FastPairDevice& device) { complete_latch.CountDown(); });
|
||||
fast_pair_pairer_->StartPairing();
|
||||
EXPECT_FALSE(paired_latch.Await(kWaitTimeout).result());
|
||||
failure_latch.Await();
|
||||
EXPECT_FALSE(account_failure_latch.Await(kWaitTimeout).result());
|
||||
EXPECT_FALSE(complete_latch.Await(kWaitTimeout).result());
|
||||
|
||||
EXPECT_TRUE(triggered_keybase_value_change);
|
||||
EXPECT_TRUE(triggered_passkey_value_change);
|
||||
EXPECT_FALSE(device_->GetAccountKey().Ok());
|
||||
}
|
||||
} // namespace fastpair
|
||||
} // namespace nearby
|
||||
@@ -143,7 +143,7 @@ bool BluetoothPairing::FinishPairing(
|
||||
|
||||
bool BluetoothPairing::CancelPairing() {
|
||||
NEARBY_LOGS(VERBOSE) << __func__
|
||||
<< "Start to cancel ongoing pairing process.";
|
||||
<< " Start to cancel ongoing pairing process.";
|
||||
try {
|
||||
if (!pairing_deferral_) {
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << "No ongoing pairing process.";
|
||||
@@ -156,7 +156,7 @@ bool BluetoothPairing::CancelPairing() {
|
||||
// |was_cancelled_| is set so that OnPair(), which is called when the
|
||||
// deferral is completed, will know that cancellation was the actual result.
|
||||
was_cancelled_ = true;
|
||||
pairing_deferral_.Complete();
|
||||
pairing_deferral_.Close();
|
||||
NEARBY_LOGS(VERBOSE) << __func__ << "Canceled ongoing pairing process.";
|
||||
return true;
|
||||
} catch (std::exception exception) {
|
||||
@@ -202,7 +202,7 @@ bool BluetoothPairing::Unpair() {
|
||||
bool BluetoothPairing::IsPaired() {
|
||||
try {
|
||||
bool is_paired = bluetooth_device_.DeviceInformation().Pairing().IsPaired();
|
||||
NEARBY_LOGS(INFO) << __func__ << (is_paired ? "True" : "False");
|
||||
NEARBY_LOGS(INFO) << __func__ << (is_paired ? " True" : " False");
|
||||
return is_paired;
|
||||
} catch (std::exception exception) {
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": Failed to get IsPaired. exception: "
|
||||
|
||||
Reference in New Issue
Block a user