diff --git a/fastpair/BUILD b/fastpair/BUILD index f4285b79..248cddf5 100644 --- a/fastpair/BUILD +++ b/fastpair/BUILD @@ -34,6 +34,7 @@ cc_library( "//internal/platform:types", "@com_google_absl//absl/functional:any_invocable", "@com_google_absl//absl/status", + "@com_google_absl//absl/strings", ], ) diff --git a/fastpair/fast_pair_controller.cc b/fastpair/fast_pair_controller.cc index 40406930..cf3b6ce4 100644 --- a/fastpair/fast_pair_controller.cc +++ b/fastpair/fast_pair_controller.cc @@ -21,6 +21,7 @@ #include #include "absl/status/status.h" +#include "absl/strings/escaping.h" #include "fastpair/common/protocol.h" #include "fastpair/handshake/fast_pair_data_encryptor_impl.h" #include "fastpair/message_stream/message_stream.h" @@ -32,18 +33,13 @@ namespace nearby { namespace fastpair { -FastPairController::FastPairController(Mediums* mediums, - const BluetoothDevice& device, +FastPairController::FastPairController(Mediums* mediums, FastPairDevice* device, SingleThreadExecutor* executor) - : mediums_(mediums), - device_(Protocol::kFastPairRetroactivePairing), - executor_(executor) { - device_.SetPublicAddress(device.GetMacAddress()); -} + : mediums_(mediums), device_(device), executor_(executor) {} absl::Status FastPairController::OpenMessageStream() { message_stream_ = std::make_unique( - device_, &mediums_->GetBluetoothClassic().GetMedium(), *this); + *device_, &mediums_->GetBluetoothClassic().GetMedium(), *this); return message_stream_->OpenRfcomm(); } @@ -51,10 +47,10 @@ void FastPairController::AddMessageStreamConnectionObserver( MessageStreamConnectionObserver* observer) { connection_observers_.AddObserver(observer); if (message_stream_status_.ok() && observer->on_connected != nullptr) { - observer->on_connected(device_); + observer->on_connected(*device_); } else if (!message_stream_status_.ok() && observer->on_disconnected != nullptr) { - observer->on_disconnected(device_, message_stream_status_); + observer->on_disconnected(*device_, message_stream_status_); } } @@ -66,8 +62,8 @@ void FastPairController::RemoveMessageStreamConnectionObserver( void FastPairController::AddAddressRotationObserver( BleAddressRotationObserver* observer) { address_rotation_observers_.AddObserver(observer); - if (!device_.GetBleAddress().empty()) { - observer->on_ble_address_rotated(device_, device_.GetBleAddress()); + if (!device_->GetBleAddress().empty()) { + observer->on_ble_address_rotated(*device_, device_->GetBleAddress()); } } @@ -78,8 +74,8 @@ void FastPairController::RemoveAddressRotationObserver( void FastPairController::AddModelIdObserver(ModelIdObserver* observer) { model_id_observers_.AddObserver(observer); - if (!device_.GetModelId().empty()) { - observer->on_model_id(device_); + if (!device_->GetModelId().empty()) { + observer->on_model_id(*device_); } } @@ -92,12 +88,12 @@ FastPairController::GetDataEncryptor() { if (!encryptor_) { encryptor_ = std::make_unique>>(); - if (device_.GetMetadata()) { + if (device_->GetMetadata()) { CreateDataEncryptor(); } else { FastPairRepository::Get()->GetDeviceMetadata( - device_.GetModelId(), [this](DeviceMetadata& metadata) { - device_.SetMetadata(metadata); + device_->GetModelId(), [this](DeviceMetadata& metadata) { + device_->SetMetadata(metadata); CreateDataEncryptor(); }); } @@ -107,8 +103,8 @@ FastPairController::GetDataEncryptor() { void FastPairController::CreateDataEncryptor() { FastPairDataEncryptorImpl::Factory::CreateAsync( - device_, [borrowable = lender_.GetBorrowable()]( - std::unique_ptr encryptor) mutable { + *device_, [borrowable = lender_.GetBorrowable()]( + std::unique_ptr encryptor) mutable { auto borrowed = borrowable.Borrow(); if (borrowed) { (*borrowed)->SetDataEncryptor(std::move(encryptor)); @@ -122,7 +118,7 @@ FastPairController::GetGattClientRef() { if (gatt_client_ == nullptr) { gatt_client_ref_count_ = 0; gatt_client_ = FastPairGattServiceClientImpl::Factory::Create( - device_, *mediums_, executor_); + *device_, *mediums_, executor_); gatt_client_->InitializeGattConnection( [](std::optional result) { if (result.has_value()) { @@ -146,7 +142,7 @@ void FastPairController::OnConnectionResult(absl::Status result) { } for (auto* observer : connection_observers_.GetObservers()) { if (observer->on_connected != nullptr) { - observer->on_connected(device_); + observer->on_connected(*device_); } } } @@ -155,24 +151,25 @@ void FastPairController::OnDisconnected(absl::Status status) { message_stream_status_ = status; for (auto* observer : connection_observers_.GetObservers()) { if (observer->on_disconnected != nullptr) { - observer->on_disconnected(device_, status); + observer->on_disconnected(*device_, status); } } } void FastPairController::OnEnableSilenceMode(bool enable) {} void FastPairController::OnLogBufferFull() {} void FastPairController::OnModelId(absl::string_view model_id) { - device_.SetModelId(model_id); + device_->SetModelId(absl::BytesToHexString(model_id)); + NEARBY_LOGS(INFO) << "Setting model id: " << device_->GetModelId(); for (auto* observer : model_id_observers_.GetObservers()) { - observer->on_model_id(device_); + observer->on_model_id(*device_); } } void FastPairController::OnBleAddressUpdated(absl::string_view address) { - std::string old_address = std::string(device_.GetBleAddress()); - device_.SetBleAddress(address); + std::string old_address = std::string(device_->GetBleAddress()); + device_->SetBleAddress(address); for (auto* observer : address_rotation_observers_.GetObservers()) { - observer->on_ble_address_rotated(device_, old_address); + observer->on_ble_address_rotated(*device_, old_address); } } diff --git a/fastpair/fast_pair_controller.h b/fastpair/fast_pair_controller.h index b4dac03f..bcf69bd6 100644 --- a/fastpair/fast_pair_controller.h +++ b/fastpair/fast_pair_controller.h @@ -107,7 +107,7 @@ class FastPairController : public MessageStream::Observer { FastPairController* controller_ = nullptr; }; // Creates a device controller in retroactive pairing path. - FastPairController(Mediums* mediums, const BluetoothDevice& device, + FastPairController(Mediums* mediums, FastPairDevice* device, SingleThreadExecutor* executor); ~FastPairController() override { @@ -155,7 +155,10 @@ class FastPairController : public MessageStream::Observer { void OnRemainingBatteryTime(absl::Duration duration) override; bool OnRing(uint8_t components, absl::Duration duration) override; - const FastPairDevice& GetDevice() { return device_; } + FastPairDevice& GetDevice() { return *device_; } + std::string GetSeekerMacAddress() const { + return mediums_->GetBluetoothClassic().GetMedium().GetMacAddress(); + } private: void SetDataEncryptor(std::unique_ptr encryptor) { @@ -177,7 +180,7 @@ class FastPairController : public MessageStream::Observer { } void CreateDataEncryptor(); Mediums* mediums_; - FastPairDevice device_; + FastPairDevice* device_; SingleThreadExecutor* executor_; std::unique_ptr>> encryptor_; std::unique_ptr message_stream_; diff --git a/fastpair/fast_pair_controller_test.cc b/fastpair/fast_pair_controller_test.cc index 496c59a3..53d9642d 100644 --- a/fastpair/fast_pair_controller_test.cc +++ b/fastpair/fast_pair_controller_test.cc @@ -14,6 +14,7 @@ #include "fastpair/fast_pair_controller.h" +#include #include #include "gmock/gmock.h" @@ -45,6 +46,9 @@ class FastPairControllerTest : public testing::Test { NEARBY_LOGS(INFO) << "Provider address: " << address; remote_device_ = seeker_medium.GetRemoteDevice(provider_.GetMacAddress()); ASSERT_TRUE(remote_device_.IsValid()); + fast_pair_device_ = + std::make_unique(Protocol::kFastPairRetroactivePairing); + fast_pair_device_->SetPublicAddress(remote_device_.GetMacAddress()); } void TearDown() override { @@ -60,14 +64,15 @@ class FastPairControllerTest : public testing::Test { Mediums mediums_; FakeProvider provider_; BluetoothDevice remote_device_; + std::unique_ptr fast_pair_device_; }; TEST_F(FastPairControllerTest, Constructor) { - FastPairController controller(&mediums_, remote_device_, &executor_); + FastPairController controller(&mediums_, &*fast_pair_device_, &executor_); } TEST_F(FastPairControllerTest, OpenMessageStream) { - FastPairController controller(&mediums_, remote_device_, &executor_); + FastPairController controller(&mediums_, &*fast_pair_device_, &executor_); EXPECT_OK(controller.OpenMessageStream()); } diff --git a/fastpair/internal/BUILD b/fastpair/internal/BUILD index d02168ef..72516d51 100644 --- a/fastpair/internal/BUILD +++ b/fastpair/internal/BUILD @@ -11,14 +11,15 @@ cc_library( "//fastpair:__subpackages__", ], deps = [ + "//fastpair:fast_pair_controller", "//fastpair:fast_pair_events", "//fastpair:fast_pair_seeker", "//fastpair/internal/mediums", "//fastpair/pairing", "//fastpair/repository:device_repository", + "//fastpair/retroactive", "//fastpair/scanning:scanner", "//internal/platform:types", - "@com_google_absl//absl/functional:any_invocable", "@com_google_absl//absl/status", "@com_google_absl//absl/strings:str_format", ], diff --git a/fastpair/internal/fast_pair_seeker_impl.cc b/fastpair/internal/fast_pair_seeker_impl.cc index dd903fe1..f719a7ef 100644 --- a/fastpair/internal/fast_pair_seeker_impl.cc +++ b/fastpair/internal/fast_pair_seeker_impl.cc @@ -21,6 +21,7 @@ #include "absl/status/status.h" #include "absl/strings/str_format.h" +#include "fastpair/fast_pair_controller.h" #include "fastpair/fast_pair_events.h" #include "fastpair/pairing/pairer_broker_impl.h" #include "fastpair/scanning/scanner_broker_impl.h" @@ -36,6 +37,9 @@ FastPairSeekerImpl::FastPairSeekerImpl(ServiceCallbacks callbacks, pairer_broker_ = std::make_unique(mediums_, executor_); pairer_broker_->AddObserver(this); mediums_.GetBluetoothClassic().AddObserver(this); + retro_detector_ = std::make_unique( + mediums_, devices, executor); + retro_detector_->AddObserver(this); } FastPairSeekerImpl::~FastPairSeekerImpl() { @@ -67,7 +71,23 @@ absl::Status FastPairSeekerImpl::StartSubsequentPairing( absl::Status FastPairSeekerImpl::StartRetroactivePairing( const FastPairDevice& device, const RetroactivePairingParam& param, PairingCallback callback) { - return absl::UnimplementedError("StartRetroactivePairing"); + if (pairer_broker_->IsPairing()) { + return absl::AlreadyExistsError("Already pairing"); + } + + device_under_pairing_ = &const_cast(device); + controller_ = std::make_unique( + &mediums_, device_under_pairing_, executor_); + retroactive_pair_ = std::make_unique(controller_.get()); + pairing_callback_ = std::make_unique(std::move(callback)); + retroactive_pair_->Pair().AddListener( + [this](ExceptionOr result) { + retroactive_pair_.reset(); + controller_.reset(); + FinishPairing(result.result()); + }, + executor_); + return absl::OkStatus(); } absl::Status FastPairSeekerImpl::StartFastPairScan() { @@ -184,30 +204,35 @@ void FastPairSeekerImpl::InvalidateScanningState() { } void FastPairSeekerImpl::DeviceAdded(BluetoothDevice& device) { - NEARBY_LOGS(VERBOSE) << "__func__(" << device.GetMacAddress() << ")"; + NEARBY_LOGS(VERBOSE) << __func__ << "(" << device.GetMacAddress() << ")"; } void FastPairSeekerImpl::DeviceRemoved(BluetoothDevice& device) { - NEARBY_LOGS(VERBOSE) << "__func__(" << device.GetMacAddress() << ")"; + NEARBY_LOGS(VERBOSE) << __func__ << "(" << device.GetMacAddress() << ")"; } void FastPairSeekerImpl::DeviceAddressChanged(BluetoothDevice& device, absl::string_view old_address) { - NEARBY_LOGS(VERBOSE) << "__func__(" << device.GetMacAddress() << ", " + NEARBY_LOGS(VERBOSE) << __func__ << "(" << device.GetMacAddress() << ", " << old_address << ")"; } void FastPairSeekerImpl::DevicePairedChanged(BluetoothDevice& device, bool new_paired_status) { - NEARBY_LOGS(VERBOSE) << "__func__(" << device.GetMacAddress() << ", " + NEARBY_LOGS(VERBOSE) << __func__ << "(" << device.GetMacAddress() << ", " << new_paired_status << ")"; } void FastPairSeekerImpl::DeviceConnectedStateChanged(BluetoothDevice& device, bool connected) { - NEARBY_LOGS(VERBOSE) << "__func__(" << device.GetMacAddress() << ", " + NEARBY_LOGS(VERBOSE) << __func__ << "(" << device.GetMacAddress() << ", " << connected << ")"; } +void FastPairSeekerImpl::OnRetroactivePairFound(FastPairDevice& device) { + NEARBY_LOGS(VERBOSE) << __func__ << ": " << device; + callbacks_.on_pair_event(device, PairEvent{}); +} + } // namespace fastpair } // namespace nearby diff --git a/fastpair/internal/fast_pair_seeker_impl.h b/fastpair/internal/fast_pair_seeker_impl.h index c029bac8..968828ed 100644 --- a/fastpair/internal/fast_pair_seeker_impl.h +++ b/fastpair/internal/fast_pair_seeker_impl.h @@ -19,11 +19,14 @@ #include #include +#include "fastpair/fast_pair_controller.h" #include "fastpair/fast_pair_events.h" #include "fastpair/fast_pair_seeker.h" #include "fastpair/internal/mediums/mediums.h" #include "fastpair/pairing/pairer_broker_impl.h" #include "fastpair/repository/fast_pair_device_repository.h" +#include "fastpair/retroactive/retroactive.h" +#include "fastpair/retroactive/retroactive_pairing_detector_impl.h" #include "fastpair/scanning/scanner_broker_impl.h" #include "internal/platform/single_thread_executor.h" @@ -44,7 +47,8 @@ class FastPairSeekerExt : public FastPairSeeker { class FastPairSeekerImpl : public FastPairSeekerExt, ScannerBrokerImpl::Observer, PairerBroker::Observer, - BluetoothClassicMedium::Observer { + BluetoothClassicMedium::Observer, + RetroactivePairingDetector::Observer { public: struct ServiceCallbacks { absl::AnyInvocable @@ -91,6 +95,9 @@ class FastPairSeekerImpl : public FastPairSeekerExt, void DeviceConnectedStateChanged(BluetoothDevice& device, bool connected) override; + // From RetroactivePairingDetector::Observer. + void OnRetroactivePairFound(FastPairDevice& device) override; + // Internal methods, not exported to plugins. private: // From ScannerBrokerImpl::Observer. @@ -116,6 +123,9 @@ class FastPairSeekerImpl : public FastPairSeekerExt, std::unique_ptr scanning_session_; std::unique_ptr pairer_broker_; std::unique_ptr pairing_callback_; + std::unique_ptr retro_detector_; + std::unique_ptr controller_; + std::unique_ptr retroactive_pair_; FastPairDevice* device_under_pairing_ = nullptr; FastPairDevice* test_device_ = nullptr; bool is_screen_locked_ = false; diff --git a/fastpair/internal/fast_pair_seeker_impl_test.cc b/fastpair/internal/fast_pair_seeker_impl_test.cc index cc2fe7b0..28f22ced 100644 --- a/fastpair/internal/fast_pair_seeker_impl_test.cc +++ b/fastpair/internal/fast_pair_seeker_impl_test.cc @@ -187,6 +187,40 @@ TEST_F(FastPairSeekerImplTest, InitialPairing) { EXPECT_EQ(provider.GetAccountKey(), fp_device.value()->GetAccountKey()); } +TEST_F(FastPairSeekerImplTest, RetroactivePairing) { + NEARBY_LOG_SET_SEVERITY(VERBOSE); + FakeProvider provider; + CountDownLatch pair_latch(1); + CountDownLatch retro_latch(1); + fast_pair_seeker_ = std::make_unique( + FastPairSeekerImpl::ServiceCallbacks{ + .on_pair_event = + [&](const FastPairDevice& device, PairEvent event) { + NEARBY_LOGS(INFO) << "Pair callback"; + pair_latch.CountDown(); + EXPECT_OK(fast_pair_seeker_->StartRetroactivePairing( + device, RetroactivePairingParam{}, + {.on_pairing_result = [&](const FastPairDevice&, + absl::Status status) { + EXPECT_OK(status); + retro_latch.CountDown(); + }})); + }}, + &executor_, &devices_); + + provider.PrepareForRetroactivePairing( + {.private_key = absl::HexStringToBytes(kBobPrivateKey), + .public_key = absl::HexStringToBytes(kBobPublicKey), + .model_id = std::string(kModelId)}, + &fake_gatt_callbacks_); + + EXPECT_TRUE(pair_latch.Await().Ok()); + EXPECT_TRUE(retro_latch.Await().Ok()); + auto fp_device = devices_.FindDevice(provider.GetMacAddress()); + ASSERT_TRUE(fp_device.has_value()); + EXPECT_EQ(provider.GetAccountKey(), fp_device.value()->GetAccountKey()); +} + } // namespace } // namespace fastpair } // namespace nearby diff --git a/fastpair/message_stream/fake_provider.cc b/fastpair/message_stream/fake_provider.cc index 4116ba13..2c7030bd 100644 --- a/fastpair/message_stream/fake_provider.cc +++ b/fastpair/message_stream/fake_provider.cc @@ -13,6 +13,7 @@ // limitations under the License. #include "fastpair/message_stream/fake_provider.h" +#include #include #include @@ -20,6 +21,7 @@ #include "absl/strings/escaping.h" #include "absl/strings/numbers.h" #include "fastpair/common/constant.h" +#include "internal/platform/byte_array.h" #include "internal/platform/medium_environment.h" #include #include @@ -321,6 +323,13 @@ void FakeProvider::ConfigurePairingContext(absl::string_view pass_key) { CHECK(absl::SimpleAtoi(pass_key, &pass_key_)); } +void FakeProvider::SetPairedStatus(bool paired) { + auto device = MediumEnvironment::Instance().FindBluetoothDevice( + provider_medium_.GetMacAddress()); + CHECK_NE(device, nullptr); + MediumEnvironment::Instance().SetPairingState(device, paired); +} + void FakeProvider::PrepareForInitialPairing( PairingConfig config, FakeGattCallbacks *fake_gatt_callbacks) { LoadAntiSpoofingKey(config.private_key, config.public_key); @@ -335,5 +344,47 @@ void FakeProvider::PrepareForInitialPairing( StartDiscoverableAdvertisement(config.model_id); } +ByteArray FakeProvider::GetModelIdMessage(absl::string_view model_id) { + std::string binary_id = absl::HexStringToBytes(model_id); + std::array data = {3, 1, 0, 3, binary_id[0], binary_id[1], + binary_id[2]}; + return ByteArray(data); +} + +ByteArray FakeProvider::GetBleAddressMessage() { + std::string data = + absl::HexStringToBytes("03020006") + GetMacAddressAsBytes(); + return ByteArray(data); +} + +void FakeProvider::EnableProviderRfcommForRetro(PairingConfig &config) { + std::string service_name{"service"}; + std::string uuid(kRfcommUuid); + provider_server_socket_ = + provider_medium_.ListenForService(service_name, uuid); + model_id_ = config.model_id; + provider_thread_.Execute([this]() { + provider_socket_ = provider_server_socket_.Accept(); + if (provider_server_socket_.IsValid()) { + NEARBY_LOGS(VERBOSE) + << "Message stream connected. Sending Model Id and BLE address"; + provider_socket_.GetOutputStream().Write(GetModelIdMessage(model_id_)); + provider_socket_.GetOutputStream().Write(GetBleAddressMessage()); + } + }); +} + +void FakeProvider::PrepareForRetroactivePairing( + PairingConfig config, FakeGattCallbacks *fake_gatt_callbacks) { + LoadAntiSpoofingKey(config.private_key, config.public_key); + StartGattServer(fake_gatt_callbacks); + InsertCorrectGattCharacteristics(); + SetKeyBasedPairingCallback(); + SetAccountkeyCallback(); + EnableProviderRfcommForRetro(config); + provider_adapter_.SetScanMode(BluetoothAdapter::ScanMode::kConnectable); + SetPairedStatus(true); +} + } // namespace fastpair } // namespace nearby diff --git a/fastpair/message_stream/fake_provider.h b/fastpair/message_stream/fake_provider.h index 7813cb5b..47bd2bb2 100644 --- a/fastpair/message_stream/fake_provider.h +++ b/fastpair/message_stream/fake_provider.h @@ -85,6 +85,10 @@ class FakeProvider { void PrepareForInitialPairing(PairingConfig config, FakeGattCallbacks* fake_gatt_callbacks); + // Sets the fake provider up for retroactive pairing + void PrepareForRetroactivePairing(PairingConfig config, + FakeGattCallbacks* fake_gatt_callbacks); + void Shutdown() { StopAdvertising(); provider_thread_.Shutdown(); @@ -211,6 +215,10 @@ class FakeProvider { void SetKeyBasedPairingCallback(); void SetPasskeyCallback(); void SetAccountkeyCallback(); + void SetPairedStatus(bool paired); + void EnableProviderRfcommForRetro(PairingConfig& config); + ByteArray GetModelIdMessage(absl::string_view model_id); + ByteArray GetBleAddressMessage(); std::string GenSec256r1Secret(absl::string_view remote_party_public_key); std::string CreateSharedSecret(absl::string_view remote_public_key); BluetoothAdapter provider_adapter_; diff --git a/fastpair/retroactive/BUILD b/fastpair/retroactive/BUILD index fe9fe81a..ff25a0c0 100644 --- a/fastpair/retroactive/BUILD +++ b/fastpair/retroactive/BUILD @@ -36,6 +36,7 @@ cc_library( "//fastpair/internal/mediums", "//fastpair/message_stream", "//fastpair/pairing", + "//fastpair/repository:device_repository", "//internal/base", "//internal/platform:comm", "//internal/platform:types", @@ -54,6 +55,7 @@ cc_test( ], deps = [ ":retroactive", + "//fastpair/common", "//fastpair/message_stream:fake_gatt_callbacks", "//fastpair/message_stream:fake_provider", "//fastpair/proto:fastpair_cc_proto", diff --git a/fastpair/retroactive/retroactive.cc b/fastpair/retroactive/retroactive.cc index 44597c61..4581723a 100644 --- a/fastpair/retroactive/retroactive.cc +++ b/fastpair/retroactive/retroactive.cc @@ -120,7 +120,7 @@ void Retroactive::SetPairingStep(PairingStep step) { data_encryptor_.AddListener( [this](ExceptionOr> result) { if (result.ok() && result.result()) { - SetPairingStep(PairingStep::kSendAccountKeyToProvider); + SetPairingStep(PairingStep::kSendKeyBasedPairingRequest); } else { SetPairingStep(PairingStep::kFailed); } @@ -128,8 +128,8 @@ void Retroactive::SetPairingStep(PairingStep step) { &executor_); break; } - case PairingStep::kSendAccountKeyToProvider: { - // Open GATT connection and push the Account Key to provider. + case PairingStep::kSendKeyBasedPairingRequest: { + // Open GATT connection and send Key-based pairing request to provider. gatt_client_ = controller_->GetGattClientRef(); gatt_client_.AddListener( [this](ExceptionOr gatt) { @@ -140,12 +140,11 @@ void Retroactive::SetPairingStep(PairingStep step) { NEARBY_LOGS(INFO) << "Sending Key Based Pairing request to " << controller_->GetDevice().GetBleAddress(); auto decryptor = data_encryptor_.Get().result().get(); - // TODO(jsobczak): Use real seeker address (gatt.result()) ->WriteRequestAsync( kKeyBasedPairingType, kRetroactiveFlags, - controller_->GetDevice().GetBleAddress(), kSeekerAddress, - *decryptor, + controller_->GetDevice().GetBleAddress(), + controller_->GetSeekerMacAddress(), *decryptor, [this](absl::string_view response, std::optional failure) { if (failure.has_value()) { @@ -156,12 +155,32 @@ void Retroactive::SetPairingStep(PairingStep step) { } NEARBY_LOGS(INFO) << "key based pairing reply " << absl::BytesToHexString(response); - SetPairingStep(PairingStep::kAskForUserConfirmation); + SetPairingStep(PairingStep::kSendAccountKeyToProvider); }); }, &executor_); break; } + case PairingStep::kSendAccountKeyToProvider: { + auto decryptor = data_encryptor_.Get().result().get(); + gatt_client_.Get().result()->WriteAccountKey( + *decryptor, [this](std::optional account_key, + std::optional failure) { + if (failure.has_value()) { + NEARBY_LOGS(WARNING) + << "Account key write failed with: " << *failure; + SetPairingStep(PairingStep::kFailed); + return; + } + DCHECK(account_key.has_value()); + NEARBY_LOGS(INFO) + << "Sent account key: " + << absl::BytesToHexString(account_key->GetAsBytes()); + controller_->GetDevice().SetAccountKey(*account_key); + SetPairingStep(PairingStep::kAskForUserConfirmation); + }); + break; + } case PairingStep::kAskForUserConfirmation: { // TODO(jsobczak): Display UI to ask the user to confirm onboarding the // device. diff --git a/fastpair/retroactive/retroactive.h b/fastpair/retroactive/retroactive.h index ebf09d28..c46e62f6 100644 --- a/fastpair/retroactive/retroactive.h +++ b/fastpair/retroactive/retroactive.h @@ -42,6 +42,7 @@ class Retroactive { kWaitForModelIdAndBleAddress, kFetchAntiSpoofingKey, kOpenGattConnection, + kSendKeyBasedPairingRequest, kSendAccountKeyToProvider, kAskForUserConfirmation, kUploadAccountKeyToCloud, diff --git a/fastpair/retroactive/retroactive_pairing_detector_impl.cc b/fastpair/retroactive/retroactive_pairing_detector_impl.cc index 1464fe12..4aae90c5 100644 --- a/fastpair/retroactive/retroactive_pairing_detector_impl.cc +++ b/fastpair/retroactive/retroactive_pairing_detector_impl.cc @@ -15,6 +15,9 @@ #include "fastpair/retroactive/retroactive_pairing_detector_impl.h" #include +#include +#include +#include #include "fastpair/internal/mediums/mediums.h" #include "fastpair/pairing/pairer_broker.h" @@ -23,9 +26,9 @@ namespace nearby { namespace fastpair { RetroactivePairingDetectorImpl::RetroactivePairingDetectorImpl( - Mediums& mediums, PairerBroker* pairer_broker) - : mediums_(mediums) { - pairer_broker->AddObserver(this); + Mediums& mediums, FastPairDeviceRepository* repository, + SingleThreadExecutor* executor) + : mediums_(mediums), repository_(repository), executor_(executor) { mediums_.GetBluetoothClassic().AddObserver(this); mediums_.GetBluetoothClassic().StartDiscovery(); } @@ -45,30 +48,6 @@ void RetroactivePairingDetectorImpl::RemoveObserver( observers_.RemoveObserver(observer); } -void RetroactivePairingDetectorImpl::OnDevicePaired(FastPairDevice& device) { - // The classic address is assigned to the Device during the - // initial Fast Pair pairing protocol and if it doesn't exist, - // then it wasn't properly paired during initial Fast Pair - // pairing. - if (!device.GetPublicAddress().has_value()) { - return; - } - - // The Bluetooth Adapter system event `DevicePairedChanged` fires before - // Fast Pair's `OnDevicePaired`, and a Fast Pair pairing is expected to have - // both events. If a device is Fast Paired, it is already inserted in the - // |potential_retroactive_addresses_| in `DevicePairedChanged`; we need to - // remove it to prevent a false positive. - if (potential_retroactive_addresses_.contains( - device.GetPublicAddress().value())) { - NEARBY_LOGS(INFO) - << __func__ - << ": paired with initial pairing, removing device at address = " - << device.GetPublicAddress().value(); - potential_retroactive_addresses_.erase(device.GetPublicAddress().value()); - } -} - void RetroactivePairingDetectorImpl::DevicePairedChanged( BluetoothDevice& device, bool new_paired_status) { NEARBY_LOGS(INFO) << __func__ @@ -84,12 +63,13 @@ void RetroactivePairingDetectorImpl::DevicePairedChanged( return; } - // Both classic paired and Fast paired devices call this function, so we - // have to add the device to |potential_retroactive_addresses_|. We expect - // devices paired via Fast Pair to always call `OnDevicePaired` after calling - // this function, which will remove the device from - // |potential_retroactive_addresses_|. - potential_retroactive_addresses_.insert(device.GetMacAddress()); + std::optional existing_device = + repository_->FindDevice(device.GetMacAddress()); + if (existing_device.has_value()) { + // Both classic paired and Fast paired devices call this function, so we + // have to filter out pairing events for devices that we already know. + return; + } // In order to confirm that this device is a retroactive pairing, we need to // first check if it has already been saved to the user's account. If it has @@ -98,7 +78,19 @@ void RetroactivePairingDetectorImpl::DevicePairedChanged( // TODO(b/285047010): check if device has already been saved to the user's // account - // TODO(Janusz) Add implementation for AttemptRetroactivePairing + auto fast_pair_device = + std::make_unique(Protocol::kFastPairRetroactivePairing); + fast_pair_device->SetPublicAddress(device.GetMacAddress()); + repository_->AddDevice(std::move(fast_pair_device)); + executor_->Execute("notify-retro-candidate", + [this, address = device.GetMacAddress()]() { + std::optional fast_pair_device = + repository_->FindDevice(address); + if (!fast_pair_device) return; + for (auto observer : observers_.GetObservers()) { + observer->OnRetroactivePairFound(**fast_pair_device); + } + }); } } // namespace fastpair diff --git a/fastpair/retroactive/retroactive_pairing_detector_impl.h b/fastpair/retroactive/retroactive_pairing_detector_impl.h index e4baef38..a24d0617 100644 --- a/fastpair/retroactive/retroactive_pairing_detector_impl.h +++ b/fastpair/retroactive/retroactive_pairing_detector_impl.h @@ -19,18 +19,22 @@ #include "absl/container/flat_hash_set.h" #include "fastpair/internal/mediums/mediums.h" #include "fastpair/pairing/pairer_broker.h" +#include "fastpair/repository/fast_pair_device_repository.h" #include "fastpair/retroactive/retroactive_pairing_detector.h" #include "internal/base/observer_list.h" #include "internal/platform/bluetooth_classic.h" +#include "internal/platform/single_thread_executor.h" namespace nearby { namespace fastpair { -class RetroactivePairingDetectorImpl : public RetroactivePairingDetector, - public BluetoothClassicMedium ::Observer, - public PairerBroker::Observer { +class RetroactivePairingDetectorImpl + : public RetroactivePairingDetector, + public BluetoothClassicMedium ::Observer { public: - RetroactivePairingDetectorImpl(Mediums& mediums, PairerBroker* pairer_broker); + RetroactivePairingDetectorImpl(Mediums& mediums, + FastPairDeviceRepository* repository, + SingleThreadExecutor* executor); RetroactivePairingDetectorImpl(const RetroactivePairingDetectorImpl&) = delete; RetroactivePairingDetectorImpl& operator=( @@ -41,17 +45,15 @@ class RetroactivePairingDetectorImpl : public RetroactivePairingDetector, void AddObserver(RetroactivePairingDetector::Observer* observer) override; void RemoveObserver(RetroactivePairingDetector::Observer* observer) override; - // BluetoothClassicMedium :: Observer + // BluetoothClassicMedium::Observer void DevicePairedChanged(BluetoothDevice& device, bool new_paired_status) override; - // PairerBroker::Observer - void OnDevicePaired(FastPairDevice& device) override; - private: Mediums& mediums_; ObserverList observers_; - absl::flat_hash_set potential_retroactive_addresses_; + FastPairDeviceRepository* repository_; + SingleThreadExecutor* executor_; }; } // namespace fastpair diff --git a/fastpair/retroactive/retroactive_test.cc b/fastpair/retroactive/retroactive_test.cc index 65406496..477ec90f 100644 --- a/fastpair/retroactive/retroactive_test.cc +++ b/fastpair/retroactive/retroactive_test.cc @@ -14,6 +14,7 @@ #include "fastpair/retroactive/retroactive.h" +#include #include #include "gmock/gmock.h" @@ -21,6 +22,7 @@ #include "gtest/gtest.h" #include "absl/status/status.h" #include "absl/strings/escaping.h" +#include "fastpair/common/constant.h" #include "fastpair/message_stream/fake_gatt_callbacks.h" #include "fastpair/message_stream/fake_provider.h" #include "fastpair/proto/fastpair_rpcs.proto.h" @@ -34,7 +36,7 @@ namespace nearby { namespace fastpair { namespace { -constexpr char kModelId[] = {0xAB, 0xCD, 0xEF}; +constexpr char kModelId[] = "abcdef"; constexpr absl::string_view kBobPrivateKey = "02B437B0EDD6BBD429064A4E529FCBF1C48D0D624924D592274B7ED81193D763"; constexpr absl::string_view kBobPublicKey = @@ -58,6 +60,9 @@ class RetroactiveTest : public testing::Test { provider_.StartGattServer(&gatt_callbacks_); provider_.InsertCorrectGattCharacteristics(); ASSERT_TRUE(remote_device_.IsValid()); + fast_pair_device_ = + std::make_unique(Protocol::kFastPairRetroactivePairing); + fast_pair_device_->SetPublicAddress(remote_device_.GetMacAddress()); } void TearDown() override { @@ -83,20 +88,23 @@ class RetroactiveTest : public testing::Test { BluetoothDevice remote_device_; FakeFastPairRepository repository_; FakeGattCallbacks gatt_callbacks_; + std::unique_ptr fast_pair_device_; }; TEST_F(RetroactiveTest, Constructor) { - FastPairController controller(&mediums_, remote_device_, &executor_); + FastPairController controller(&mediums_, &*fast_pair_device_, &executor_); Retroactive retro(&controller); } TEST_F(RetroactiveTest, Pair) { SetUpFastPairRepository(kModelId, absl::HexStringToBytes(kBobPublicKey)); - FastPairController controller(&mediums_, remote_device_, &executor_); + FastPairController controller(&mediums_, &*fast_pair_device_, &executor_); provider_.EnableProviderRfcomm(); provider_.LoadAntiSpoofingKey(absl::HexStringToBytes(kBobPrivateKey), absl::HexStringToBytes(kBobPublicKey)); std::string provider_ble_address = provider_.GetMacAddressAsBytes(); + std::string seeker_address = + std::string(BluetoothUtils::FromString(controller.GetSeekerMacAddress())); gatt_callbacks_.characteristics_[*provider_.key_based_characteristic_] .write_callback = [&](absl::string_view request) { // https://developers.google.com/nearby/fast-pair/specifications/characteristics#table1.1 @@ -106,9 +114,8 @@ TEST_F(RetroactiveTest, Pair) { // Bytes 2 - 7, aabbccddeeff, provider's address // Bytes 8 - 13, 111213141516, seeker's address // Bytes 14 - 15, (not included), random salt - std::string expected_kbp_request = absl::HexStringToBytes("0010") + - provider_ble_address + - absl::HexStringToBytes("111213141516"); + std::string expected_kbp_request = + absl::HexStringToBytes("0010") + provider_ble_address + seeker_address; // https://developers.google.com/nearby/fast-pair/specifications/characteristics#table1.2.2 // Byte 0, 0x01 = Key-based Pairing Response @@ -143,6 +150,12 @@ TEST_F(RetroactiveTest, Pair) { provider_ble_address); EXPECT_TRUE(result.Get(absl::Minutes(5)).ok()); + EXPECT_EQ( + gatt_callbacks_.characteristics_[*provider_.accountkey_characteristic_] + .write_value.Get() + .result() + .size(), + kAccountKeySize); } } // namespace