Commit 8b97e93a authored by Kyle Horimoto's avatar Kyle Horimoto Committed by Commit Bot

[CrOS Tether] Handle failed advertisement registration/unregistration.

Now, when RegisterAdvertisement() or Unregister() fail, the operation is
retried until it succeeds. This fixes several related issues which
result from getting stuck thinking that an advertisement is registered
or unregistered when it actually is not.

Bug: 767500, 672263
Change-Id: I73886e104dc64fbc3f307e3c834de873ddf85914
Reviewed-on: https://chromium-review.googlesource.com/677715Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Reviewed-by: default avatarRyan Hansberry <hansberry@chromium.org>
Commit-Queue: Kyle Horimoto <khorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#503626}
parent 4780f1dd
...@@ -16,7 +16,6 @@ static_library("tether") { ...@@ -16,7 +16,6 @@ static_library("tether") {
"ble_advertiser.h", "ble_advertiser.h",
"ble_connection_manager.cc", "ble_connection_manager.cc",
"ble_connection_manager.h", "ble_connection_manager.h",
"ble_constants.cc",
"ble_constants.h", "ble_constants.h",
"ble_scanner.cc", "ble_scanner.cc",
"ble_scanner.h", "ble_scanner.h",
...@@ -34,6 +33,10 @@ static_library("tether") { ...@@ -34,6 +33,10 @@ static_library("tether") {
"disconnect_tethering_request_sender.h", "disconnect_tethering_request_sender.h",
"disconnect_tethering_request_sender_impl.cc", "disconnect_tethering_request_sender_impl.cc",
"disconnect_tethering_request_sender_impl.h", "disconnect_tethering_request_sender_impl.h",
"error_tolerant_ble_advertisement.cc",
"error_tolerant_ble_advertisement.h",
"error_tolerant_ble_advertisement_impl.cc",
"error_tolerant_ble_advertisement_impl.h",
"host_connection_metrics_logger.cc", "host_connection_metrics_logger.cc",
"host_connection_metrics_logger.h", "host_connection_metrics_logger.h",
"host_scan_cache.cc", "host_scan_cache.cc",
...@@ -129,6 +132,8 @@ static_library("test_support") { ...@@ -129,6 +132,8 @@ static_library("test_support") {
"fake_ble_connection_manager.h", "fake_ble_connection_manager.h",
"fake_disconnect_tethering_request_sender.cc", "fake_disconnect_tethering_request_sender.cc",
"fake_disconnect_tethering_request_sender.h", "fake_disconnect_tethering_request_sender.h",
"fake_error_tolerant_ble_advertisement.cc",
"fake_error_tolerant_ble_advertisement.h",
"fake_host_scan_cache.cc", "fake_host_scan_cache.cc",
"fake_host_scan_cache.h", "fake_host_scan_cache.h",
"fake_initializer.cc", "fake_initializer.cc",
...@@ -187,6 +192,7 @@ source_set("unit_tests") { ...@@ -187,6 +192,7 @@ source_set("unit_tests") {
"device_status_util_unittest.cc", "device_status_util_unittest.cc",
"disconnect_tethering_operation_unittest.cc", "disconnect_tethering_operation_unittest.cc",
"disconnect_tethering_request_sender_impl_unittest.cc", "disconnect_tethering_request_sender_impl_unittest.cc",
"error_tolerant_ble_advertisement_impl_unittest.cc",
"host_connection_metrics_logger_unittest.cc", "host_connection_metrics_logger_unittest.cc",
"host_scan_cache_unittest.cc", "host_scan_cache_unittest.cc",
"host_scan_device_prioritizer_impl_unittest.cc", "host_scan_device_prioritizer_impl_unittest.cc",
......
...@@ -97,7 +97,7 @@ TEST_F(BleAdvertisementDeviceQueueTest, TestTwoDevices_MoveToEnd) { ...@@ -97,7 +97,7 @@ TEST_F(BleAdvertisementDeviceQueueTest, TestTwoDevices_MoveToEnd) {
TEST_F(BleAdvertisementDeviceQueueTest, TestThreeDevices) { TEST_F(BleAdvertisementDeviceQueueTest, TestThreeDevices) {
// Note: These tests need to be rewritten if |kMaxConcurrentAdvertisements| is // Note: These tests need to be rewritten if |kMaxConcurrentAdvertisements| is
// ever changed. // ever changed.
ASSERT_GT(3, kMaxConcurrentAdvertisements); ASSERT_GT(3u, kMaxConcurrentAdvertisements);
std::vector<cryptauth::RemoteDevice> devices = std::vector<cryptauth::RemoteDevice> devices =
cryptauth::GenerateTestRemoteDevices(3); cryptauth::GenerateTestRemoteDevices(3);
...@@ -124,7 +124,7 @@ TEST_F(BleAdvertisementDeviceQueueTest, TestThreeDevices) { ...@@ -124,7 +124,7 @@ TEST_F(BleAdvertisementDeviceQueueTest, TestThreeDevices) {
TEST_F(BleAdvertisementDeviceQueueTest, TestAddingDevices) { TEST_F(BleAdvertisementDeviceQueueTest, TestAddingDevices) {
// Note: These tests need to be rewritten if |kMaxConcurrentAdvertisements| is // Note: These tests need to be rewritten if |kMaxConcurrentAdvertisements| is
// ever changed. // ever changed.
ASSERT_GT(3, kMaxConcurrentAdvertisements); ASSERT_GT(3u, kMaxConcurrentAdvertisements);
std::vector<cryptauth::RemoteDevice> all_devices = std::vector<cryptauth::RemoteDevice> all_devices =
cryptauth::GenerateTestRemoteDevices(5); cryptauth::GenerateTestRemoteDevices(5);
......
...@@ -5,12 +5,14 @@ ...@@ -5,12 +5,14 @@
#ifndef CHROMEOS_COMPONENTS_TETHER_BLE_ADVERTISER_H_ #ifndef CHROMEOS_COMPONENTS_TETHER_BLE_ADVERTISER_H_
#define CHROMEOS_COMPONENTS_TETHER_BLE_ADVERTISER_H_ #define CHROMEOS_COMPONENTS_TETHER_BLE_ADVERTISER_H_
#include <array>
#include <map> #include <map>
#include <unordered_set> #include <unordered_set>
#include "base/callback_forward.h" #include "base/callback_forward.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "chromeos/components/tether/ble_constants.h"
#include "components/cryptauth/foreground_eid_generator.h" #include "components/cryptauth/foreground_eid_generator.h"
#include "components/cryptauth/remote_device.h" #include "components/cryptauth/remote_device.h"
#include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_adapter.h"
...@@ -25,6 +27,8 @@ namespace chromeos { ...@@ -25,6 +27,8 @@ namespace chromeos {
namespace tether { namespace tether {
class ErrorTolerantBleAdvertisement;
// Advertises to a given device. When StartAdvertisingToDevice() is called, a // Advertises to a given device. When StartAdvertisingToDevice() is called, a
// device-specific EID value is computed deterministically and is set as the // device-specific EID value is computed deterministically and is set as the
// service data of the advertisement. If that device is nearby and scanning, // service data of the advertisement. If that device is nearby and scanning,
...@@ -32,10 +36,9 @@ namespace tether { ...@@ -32,10 +36,9 @@ namespace tether {
// advertisement. // advertisement.
class BleAdvertiser { class BleAdvertiser {
public: public:
BleAdvertiser( BleAdvertiser(scoped_refptr<device::BluetoothAdapter> adapter,
scoped_refptr<device::BluetoothAdapter> adapter, cryptauth::LocalDeviceDataProvider* local_device_data_provider,
const cryptauth::LocalDeviceDataProvider* local_device_data_provider, cryptauth::RemoteBeaconSeedFetcher* remote_beacon_seed_fetcher);
const cryptauth::RemoteBeaconSeedFetcher* remote_beacon_seed_fetcher);
virtual ~BleAdvertiser(); virtual ~BleAdvertiser();
virtual bool StartAdvertisingToDevice( virtual bool StartAdvertisingToDevice(
...@@ -46,105 +49,39 @@ class BleAdvertiser { ...@@ -46,105 +49,39 @@ class BleAdvertiser {
private: private:
friend class BleAdvertiserTest; friend class BleAdvertiserTest;
// One IndividualAdvertisement is created for each device to which // Data needed to generate an advertisement.
// BleAdvertiser should be advertising. When an IndividualAdvertisement is struct AdvertisementMetadata {
// created, it starts trying to advertise to its associated device ID; AdvertisementMetadata(
// likewise, when it is destroyed, it stops advertising if necessary.
//
// However, because unregistering an advertisement is an asynchronous
// operation, it is possible that if an IndividualAdvertisement for one device
// is created just after another IndividualAdvertisement for the same device
// was destroyed, the previous advertisement was not fully unregistered.
// If that is the case, the newly-created IndividualAdvertisement must wait
// until OnPreviousAdvertisementUnregistered() is called.
class IndividualAdvertisement
: public device::BluetoothAdapter::Observer,
public device::BluetoothAdvertisement::Observer {
public:
static void OnAdvertisementRegistered(
base::WeakPtr<BleAdvertiser::IndividualAdvertisement>
individual_advertisement,
const std::string& associated_device_id,
scoped_refptr<device::BluetoothAdvertisement> advertisement);
IndividualAdvertisement(
const std::string& device_id, const std::string& device_id,
scoped_refptr<device::BluetoothAdapter> adapter, std::unique_ptr<cryptauth::DataWithTimestamp> service_data);
std::unique_ptr<cryptauth::DataWithTimestamp> advertisement_data, ~AdvertisementMetadata();
const base::Closure& on_unregister_advertisement_success_callback,
const base::Callback<void(device::BluetoothAdvertisement::ErrorCode)>&
on_unregister_advertisement_error_callback,
std::unordered_set<std::string>* active_advertisement_device_ids_set);
~IndividualAdvertisement() override;
// Callback for when a previously-registered advertisement corresponding to
// |device_id_| has been unregistered.
void OnPreviousAdvertisementUnregistered();
// device::BluetoothAdapter::Observer
void AdapterPoweredChanged(device::BluetoothAdapter* adapter,
bool powered) override;
// device::BluetoothAdvertisement::Observer
void AdvertisementReleased(
device::BluetoothAdvertisement* advertisement) override;
private:
friend class BleAdvertiserTest;
void AdvertiseIfPossible();
void OnAdvertisementRegisteredCallback(
scoped_refptr<device::BluetoothAdvertisement> advertisement);
void OnAdvertisementErrorCallback(
device::BluetoothAdvertisement::ErrorCode error_code);
void OnAdvertisementUnregisterFailure(
device::BluetoothAdvertisement::ErrorCode error_code);
std::unique_ptr<device::BluetoothAdvertisement::UUIDList>
CreateServiceUuids() const;
std::unique_ptr<device::BluetoothAdvertisement::ServiceData>
CreateServiceData() const;
std::string device_id_;
scoped_refptr<device::BluetoothAdapter> adapter_;
std::unique_ptr<cryptauth::DataWithTimestamp> advertisement_data_;
bool is_initializing_advertising_;
scoped_refptr<device::BluetoothAdvertisement> advertisement_;
base::Closure on_unregister_advertisement_success_callback_;
base::Callback<void(device::BluetoothAdvertisement::ErrorCode)>
on_unregister_advertisement_error_callback_;
std::unordered_set<std::string>* active_advertisement_device_ids_set_;
base::WeakPtrFactory<IndividualAdvertisement> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(IndividualAdvertisement);
};
BleAdvertiser( std::string device_id;
scoped_refptr<device::BluetoothAdapter> adapter, std::unique_ptr<cryptauth::DataWithTimestamp> service_data;
std::unique_ptr<cryptauth::ForegroundEidGenerator> eid_generator, };
const cryptauth::RemoteBeaconSeedFetcher* remote_beacon_seed_fetcher,
const cryptauth::LocalDeviceDataProvider* local_device_data_provider);
void OnUnregisterAdvertisementSuccess( void SetEidGeneratorForTest(
const std::string& associated_device_id); std::unique_ptr<cryptauth::ForegroundEidGenerator> test_eid_generator);
void OnUnregisterAdvertisementError( void UpdateAdvertisements();
const std::string& associated_device_id, void OnAdvertisementStopped(size_t index);
device::BluetoothAdvertisement::ErrorCode error_code);
void RemoveAdvertisingDeviceIdAndRetry(const std::string& device_id);
scoped_refptr<device::BluetoothAdapter> adapter_; scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_;
cryptauth::RemoteBeaconSeedFetcher* remote_beacon_seed_fetcher_;
cryptauth::LocalDeviceDataProvider* local_device_data_provider_;
std::unique_ptr<cryptauth::ForegroundEidGenerator> eid_generator_; std::unique_ptr<cryptauth::ForegroundEidGenerator> eid_generator_;
// Not owned by this instance and must outlive it.
const cryptauth::RemoteBeaconSeedFetcher* remote_beacon_seed_fetcher_;
const cryptauth::LocalDeviceDataProvider* local_device_data_provider_;
std::map<std::string, std::unique_ptr<IndividualAdvertisement>> // |registered_device_ids_| holds the device IDs that are currently
device_id_to_individual_advertisement_map_; // registered and is always up-to-date. |advertisements_| contains the active
std::unordered_set<std::string> active_advertisement_device_ids_set_; // advertisements, which may not correspond exactly to
// |registered_device_ids_| in the case that a previous advertisement failed
// to unregister.
std::array<std::unique_ptr<AdvertisementMetadata>,
kMaxConcurrentAdvertisements>
registered_device_metadata_;
std::array<std::unique_ptr<ErrorTolerantBleAdvertisement>,
kMaxConcurrentAdvertisements>
advertisements_;
base::WeakPtrFactory<BleAdvertiser> weak_ptr_factory_; base::WeakPtrFactory<BleAdvertiser> weak_ptr_factory_;
......
...@@ -385,8 +385,7 @@ void BleConnectionManager::UpdateConnectionAttempts() { ...@@ -385,8 +385,7 @@ void BleConnectionManager::UpdateConnectionAttempts() {
std::vector<cryptauth::RemoteDevice> should_advertise_to = std::vector<cryptauth::RemoteDevice> should_advertise_to =
ble_advertisement_device_queue_->GetDevicesToWhichToAdvertise(); ble_advertisement_device_queue_->GetDevicesToWhichToAdvertise();
DCHECK(should_advertise_to.size() <= DCHECK(should_advertise_to.size() <= kMaxConcurrentAdvertisements);
static_cast<size_t>(kMaxConcurrentAdvertisements));
for (const auto& remote_device : should_advertise_to) { for (const auto& remote_device : should_advertise_to) {
ConnectionMetadata* associated_data = GetConnectionMetadata(remote_device); ConnectionMetadata* associated_data = GetConnectionMetadata(remote_device);
......
...@@ -279,7 +279,7 @@ class BleConnectionManagerTest : public testing::Test { ...@@ -279,7 +279,7 @@ class BleConnectionManagerTest : public testing::Test {
BleConnectionManagerTest() : test_devices_(CreateTestDevices(4)) { BleConnectionManagerTest() : test_devices_(CreateTestDevices(4)) {
// These tests assume a maximum of two concurrent advertisers. Some of the // These tests assume a maximum of two concurrent advertisers. Some of the
// multi-device tests would need to be re-written if this constant changes. // multi-device tests would need to be re-written if this constant changes.
EXPECT_EQ(2, kMaxConcurrentAdvertisements); EXPECT_EQ(2u, kMaxConcurrentAdvertisements);
} }
void SetUp() override { void SetUp() override {
......
...@@ -18,13 +18,14 @@ namespace tether { ...@@ -18,13 +18,14 @@ namespace tether {
// Note that this upper limit on concurrent advertisements is imposed due to a // Note that this upper limit on concurrent advertisements is imposed due to a
// hardware limit of advertisements (many devices have <10 total advertisement // hardware limit of advertisements (many devices have <10 total advertisement
// slots). // slots).
extern const uint8_t kMaxConcurrentAdvertisements; constexpr const size_t kMaxConcurrentAdvertisements = 2;
// The service UUID used for BLE advertisements. // The service UUID used for BLE advertisements.
extern const char kAdvertisingServiceUuid[]; constexpr const char kAdvertisingServiceUuid[] =
"0000fe50-0000-1000-8000-00805f9b34fb";
// The GATT server UUID used for uWeave. // The GATT server UUID used for uWeave.
extern const char kGattServerUuid[]; constexpr const char kGattServerUuid[] = "b3b7e28e-a000-3e17-bd86-6e97b9e28c11";
} // namespace tether } // namespace tether
......
...@@ -503,7 +503,7 @@ TEST_F(BleScannerTest, TestRegistrationLimit) { ...@@ -503,7 +503,7 @@ TEST_F(BleScannerTest, TestRegistrationLimit) {
// Attempt to register another device. Registration should fail since the // Attempt to register another device. Registration should fail since the
// maximum number of devices have already been registered. // maximum number of devices have already been registered.
ASSERT_EQ(2, kMaxConcurrentAdvertisements); ASSERT_EQ(2u, kMaxConcurrentAdvertisements);
EXPECT_FALSE(ble_scanner_->RegisterScanFilterForDevice(test_devices_[2])); EXPECT_FALSE(ble_scanner_->RegisterScanFilterForDevice(test_devices_[2]));
EXPECT_FALSE(IsDeviceRegistered(test_devices_[2].GetDeviceId())); EXPECT_FALSE(IsDeviceRegistered(test_devices_[2].GetDeviceId()));
......
// Copyright 2016 The Chromium Authors. All rights reserved. // Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "chromeos/components/tether/ble_constants.h" #include "chromeos/components/tether/error_tolerant_ble_advertisement.h"
namespace chromeos { namespace chromeos {
namespace tether { namespace tether {
const uint8_t kMaxConcurrentAdvertisements = 2; ErrorTolerantBleAdvertisement::ErrorTolerantBleAdvertisement(
const char kAdvertisingServiceUuid[] = "0000fe50-0000-1000-8000-00805f9b34fb"; const std::string& device_id)
const char kGattServerUuid[] = "b3b7e28e-a000-3e17-bd86-6e97b9e28c11"; : device_id_(device_id) {}
ErrorTolerantBleAdvertisement::~ErrorTolerantBleAdvertisement() {}
} // namespace tether } // namespace tether
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_COMPONENTS_ERROR_TOLERANT_BLE_ADVERTISEMENT_H_
#define CHROMEOS_COMPONENTS_ERROR_TOLERANT_BLE_ADVERTISEMENT_H_
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
namespace chromeos {
namespace tether {
// Advertises to the device with the given ID. Due to issues in the Bluetooth
// stack, it is possible that registering or unregistering an advertisement can
// fail. If this class encounters an error, it retries until it succeeds. Once
// Stop() is called, the advertisement should not be considered unregistered
// until the stop callback is invoked.
class ErrorTolerantBleAdvertisement {
public:
ErrorTolerantBleAdvertisement(const std::string& device_id);
virtual ~ErrorTolerantBleAdvertisement();
// Stops advertising. Because BLE advertisements start and stop
// asynchronously, clients must use this function to stop advertising instead
// of simply deleting an ErrorTolerantBleAdvertisement object. Clients should
// not assume that advertising has actually stopped until |callback| has been
// invoked.
virtual void Stop(const base::Closure& callback) = 0;
// Returns whether Stop() has been called.
virtual bool HasBeenStopped() = 0;
const std::string& device_id() { return device_id_; }
private:
const std::string device_id_;
DISALLOW_COPY_AND_ASSIGN(ErrorTolerantBleAdvertisement);
};
} // namespace tether
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_ERROR_TOLERANT_BLE_ADVERTISEMENT_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/components/tether/error_tolerant_ble_advertisement_impl.h"
#include "base/bind.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "chromeos/components/tether/ble_constants.h"
#include "components/cryptauth/remote_device.h"
#include "components/proximity_auth/logging/logging.h"
#include "device/bluetooth/bluetooth_adapter.h"
namespace chromeos {
namespace tether {
namespace {
const uint8_t kInvertedConnectionFlag = 0x01;
const size_t kTimeBetweenAttemptsMs = 200u;
} // namespace
// static
ErrorTolerantBleAdvertisementImpl::Factory*
ErrorTolerantBleAdvertisementImpl::Factory::factory_instance_ = nullptr;
// static
std::unique_ptr<ErrorTolerantBleAdvertisement>
ErrorTolerantBleAdvertisementImpl::Factory::NewInstance(
const std::string& device_id,
scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
std::unique_ptr<cryptauth::DataWithTimestamp> advertisement_data) {
if (!factory_instance_)
factory_instance_ = new Factory();
return factory_instance_->BuildInstance(device_id, bluetooth_adapter,
std::move(advertisement_data));
}
// static
void ErrorTolerantBleAdvertisementImpl::Factory::SetInstanceForTesting(
Factory* factory) {
factory_instance_ = factory;
}
std::unique_ptr<ErrorTolerantBleAdvertisement>
ErrorTolerantBleAdvertisementImpl::Factory::BuildInstance(
const std::string& device_id,
scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
std::unique_ptr<cryptauth::DataWithTimestamp> advertisement_data) {
return base::MakeUnique<ErrorTolerantBleAdvertisementImpl>(
device_id, bluetooth_adapter, std::move(advertisement_data));
}
ErrorTolerantBleAdvertisementImpl::Factory::~Factory() {}
ErrorTolerantBleAdvertisementImpl::ErrorTolerantBleAdvertisementImpl(
const std::string& device_id,
scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
std::unique_ptr<cryptauth::DataWithTimestamp> advertisement_data)
: ErrorTolerantBleAdvertisement(device_id),
bluetooth_adapter_(bluetooth_adapter),
advertisement_data_(std::move(advertisement_data)),
timer_(base::MakeUnique<base::OneShotTimer>()),
weak_ptr_factory_(this) {
UpdateRegistrationStatus();
}
ErrorTolerantBleAdvertisementImpl::~ErrorTolerantBleAdvertisementImpl() {
if (advertisement_)
advertisement_->RemoveObserver(this);
}
void ErrorTolerantBleAdvertisementImpl::Stop(const base::Closure& callback) {
// Stop() should only be called once per instance.
DCHECK(stop_callback_.is_null());
stop_callback_ = callback;
UpdateRegistrationStatus();
}
bool ErrorTolerantBleAdvertisementImpl::HasBeenStopped() {
return !stop_callback_.is_null();
}
void ErrorTolerantBleAdvertisementImpl::AdvertisementReleased(
device::BluetoothAdvertisement* advertisement) {
DCHECK(advertisement_.get() == advertisement);
// If the advertisement was released, delete it and try again. Note that this
// situation is not expected to occur under normal circumstances.
advertisement_->RemoveObserver(this);
advertisement_ = nullptr;
PA_LOG(WARNING) << "Advertisement was released. Trying again. Device ID: \""
<< cryptauth::RemoteDevice::TruncateDeviceIdForLogs(
device_id())
<< "\", Service data: " << advertisement_data_->DataInHex();
UpdateRegistrationStatus();
}
void ErrorTolerantBleAdvertisementImpl::SetFakeTimerForTest(
std::unique_ptr<base::Timer> test_timer) {
timer_ = std::move(test_timer);
}
void ErrorTolerantBleAdvertisementImpl::UpdateRegistrationStatus() {
if (!advertisement_ && stop_callback_.is_null())
AttemptRegistration();
else if (advertisement_ && !stop_callback_.is_null())
AttemptUnregistration();
}
void ErrorTolerantBleAdvertisementImpl::RetryUpdateAfterTimer() {
timer_->Start(
FROM_HERE, base::TimeDelta::FromMilliseconds(kTimeBetweenAttemptsMs),
base::Bind(&ErrorTolerantBleAdvertisementImpl::UpdateRegistrationStatus,
weak_ptr_factory_.GetWeakPtr()));
}
void ErrorTolerantBleAdvertisementImpl::AttemptRegistration() {
// Should never attempt to register after Stop() has been called.
DCHECK(stop_callback_.is_null() && !unregistration_in_progress_);
if (registration_in_progress_)
return;
registration_in_progress_ = true;
std::unique_ptr<device::BluetoothAdvertisement::Data> advertisement_data =
base::MakeUnique<device::BluetoothAdvertisement::Data>(
device::BluetoothAdvertisement::AdvertisementType::
ADVERTISEMENT_TYPE_BROADCAST);
advertisement_data->set_service_uuids(CreateServiceUuids());
advertisement_data->set_service_data(CreateServiceData());
bluetooth_adapter_->RegisterAdvertisement(
std::move(advertisement_data),
base::Bind(&ErrorTolerantBleAdvertisementImpl::OnAdvertisementRegistered,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(
&ErrorTolerantBleAdvertisementImpl::OnErrorRegisteringAdvertisement,
weak_ptr_factory_.GetWeakPtr()));
}
void ErrorTolerantBleAdvertisementImpl::AttemptUnregistration() {
// Should never attempt to unregister before Stop() has been called.
DCHECK(!stop_callback_.is_null());
// If no advertisement has yet been registered, we must wait until it has been
// successfully registered before it is possible to unregister. Likewise, if
// unregistration is still in progress, there is nothing else to do.
if (registration_in_progress_ || unregistration_in_progress_)
return;
unregistration_in_progress_ = true;
advertisement_->Unregister(
base::Bind(
&ErrorTolerantBleAdvertisementImpl::OnAdvertisementUnregistered,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(
&ErrorTolerantBleAdvertisementImpl::OnErrorUnregisteringAdvertisement,
weak_ptr_factory_.GetWeakPtr()));
}
std::unique_ptr<device::BluetoothAdvertisement::UUIDList>
ErrorTolerantBleAdvertisementImpl::CreateServiceUuids() const {
std::unique_ptr<device::BluetoothAdvertisement::UUIDList> list =
base::MakeUnique<device::BluetoothAdvertisement::UUIDList>();
list->push_back(kAdvertisingServiceUuid);
return list;
}
std::unique_ptr<device::BluetoothAdvertisement::ServiceData>
ErrorTolerantBleAdvertisementImpl::CreateServiceData() const {
DCHECK(!advertisement_data_->data.empty());
std::vector<uint8_t> data_as_vector(advertisement_data_->data.size());
memcpy(data_as_vector.data(), advertisement_data_->data.data(),
advertisement_data_->data.size());
// Add a flag at the end of the service data to signify that the inverted
// connection flow should be used.
data_as_vector.push_back(kInvertedConnectionFlag);
std::unique_ptr<device::BluetoothAdvertisement::ServiceData> service_data =
base::MakeUnique<device::BluetoothAdvertisement::ServiceData>();
service_data->insert(std::pair<std::string, std::vector<uint8_t>>(
kAdvertisingServiceUuid, data_as_vector));
return service_data;
}
void ErrorTolerantBleAdvertisementImpl::OnAdvertisementRegistered(
scoped_refptr<device::BluetoothAdvertisement> advertisement) {
registration_in_progress_ = false;
advertisement_ = advertisement;
advertisement_->AddObserver(this);
PA_LOG(INFO) << "Advertisement registered. Device ID: \""
<< cryptauth::RemoteDevice::TruncateDeviceIdForLogs(device_id())
<< "\", Service data: " << advertisement_data_->DataInHex();
UpdateRegistrationStatus();
}
void ErrorTolerantBleAdvertisementImpl::OnErrorRegisteringAdvertisement(
device::BluetoothAdvertisement::ErrorCode error_code) {
registration_in_progress_ = false;
PA_LOG(ERROR) << "Error registering advertisement. Device ID: \""
<< cryptauth::RemoteDevice::TruncateDeviceIdForLogs(device_id())
<< "\", Service data: " << advertisement_data_->DataInHex()
<< ", Error code: " << error_code;
// Try again, but wait kTimeBetweenAttemptsMs to avoid spamming the Bluetooth
// controller.
RetryUpdateAfterTimer();
}
void ErrorTolerantBleAdvertisementImpl::OnAdvertisementUnregistered() {
unregistration_in_progress_ = false;
advertisement_->RemoveObserver(this);
advertisement_ = nullptr;
DCHECK(!stop_callback_.is_null());
stop_callback_.Run();
}
void ErrorTolerantBleAdvertisementImpl::OnErrorUnregisteringAdvertisement(
device::BluetoothAdvertisement::ErrorCode error_code) {
unregistration_in_progress_ = false;
PA_LOG(ERROR) << "Error unregistering advertisement. Device ID: \""
<< cryptauth::RemoteDevice::TruncateDeviceIdForLogs(device_id())
<< "\", Service data: " << advertisement_data_->DataInHex()
<< ", Error code: " << error_code;
// Try again, but wait kTimeBetweenAttemptsMs to avoid spamming the Bluetooth
// controller.
RetryUpdateAfterTimer();
}
} // namespace tether
} // namespace chromeos
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_COMPONENTS_ERROR_TOLERANT_BLE_ADVERTISEMENT_IMPL_H_
#define CHROMEOS_COMPONENTS_ERROR_TOLERANT_BLE_ADVERTISEMENT_IMPL_H_
#include <memory>
#include <string>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "chromeos/components/tether/error_tolerant_ble_advertisement.h"
#include "components/cryptauth/foreground_eid_generator.h"
#include "device/bluetooth/bluetooth_advertisement.h"
namespace device {
class BluetoothAdapter;
} // namespace device
namespace chromeos {
namespace tether {
// Concrete ErrorTolerantBleAdvertisement implementation.
class ErrorTolerantBleAdvertisementImpl
: public ErrorTolerantBleAdvertisement,
public device::BluetoothAdvertisement::Observer {
public:
class Factory {
public:
static std::unique_ptr<ErrorTolerantBleAdvertisement> NewInstance(
const std::string& device_id,
scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
std::unique_ptr<cryptauth::DataWithTimestamp> advertisement_data);
static void SetInstanceForTesting(Factory* factory);
protected:
virtual std::unique_ptr<ErrorTolerantBleAdvertisement> BuildInstance(
const std::string& device_id,
scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
std::unique_ptr<cryptauth::DataWithTimestamp> advertisement_data);
virtual ~Factory();
private:
static Factory* factory_instance_;
};
ErrorTolerantBleAdvertisementImpl(
const std::string& device_id,
scoped_refptr<device::BluetoothAdapter> bluetooth_adapter,
std::unique_ptr<cryptauth::DataWithTimestamp> advertisement_data);
~ErrorTolerantBleAdvertisementImpl() override;
// ErrorTolerantBleAdvertisement:
void Stop(const base::Closure& callback) override;
bool HasBeenStopped() override;
protected:
// device::BluetoothAdvertisement::Observer
void AdvertisementReleased(
device::BluetoothAdvertisement* advertisement) override;
private:
friend class ErrorTolerantBleAdvertisementImplTest;
const cryptauth::DataWithTimestamp& advertisement_data() const {
return *advertisement_data_;
}
void SetFakeTimerForTest(std::unique_ptr<base::Timer> test_timer);
void UpdateRegistrationStatus();
void RetryUpdateAfterTimer();
void AttemptRegistration();
void AttemptUnregistration();
std::unique_ptr<device::BluetoothAdvertisement::UUIDList> CreateServiceUuids()
const;
std::unique_ptr<device::BluetoothAdvertisement::ServiceData>
CreateServiceData() const;
void OnAdvertisementRegistered(
scoped_refptr<device::BluetoothAdvertisement> advertisement);
void OnErrorRegisteringAdvertisement(
device::BluetoothAdvertisement::ErrorCode error_code);
void OnAdvertisementUnregistered();
void OnErrorUnregisteringAdvertisement(
device::BluetoothAdvertisement::ErrorCode error_code);
std::string device_id_;
scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_;
std::unique_ptr<cryptauth::DataWithTimestamp> advertisement_data_;
std::unique_ptr<base::Timer> timer_;
bool registration_in_progress_ = false;
bool unregistration_in_progress_ = false;
scoped_refptr<device::BluetoothAdvertisement> advertisement_;
base::Closure stop_callback_;
base::WeakPtrFactory<ErrorTolerantBleAdvertisementImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ErrorTolerantBleAdvertisementImpl);
};
} // namespace tether
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_ERROR_TOLERANT_BLE_ADVERTISEMENT_IMPL_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/components/tether/fake_error_tolerant_ble_advertisement.h"
#include "base/bind.h"
namespace chromeos {
namespace tether {
FakeErrorTolerantBleAdvertisement::FakeErrorTolerantBleAdvertisement(
const std::string& device_id)
: ErrorTolerantBleAdvertisement(device_id) {}
FakeErrorTolerantBleAdvertisement::FakeErrorTolerantBleAdvertisement(
const std::string& device_id,
const base::Callback<void(FakeErrorTolerantBleAdvertisement*)>&
deletion_callback)
: ErrorTolerantBleAdvertisement(device_id),
deletion_callback_(deletion_callback) {}
FakeErrorTolerantBleAdvertisement::~FakeErrorTolerantBleAdvertisement() {
if (!deletion_callback_.is_null())
deletion_callback_.Run(this);
}
bool FakeErrorTolerantBleAdvertisement::HasBeenStopped() {
return !stop_callback_.is_null();
}
void FakeErrorTolerantBleAdvertisement::InvokeStopCallback() {
DCHECK(HasBeenStopped());
stop_callback_.Run();
}
void FakeErrorTolerantBleAdvertisement::Stop(const base::Closure& callback) {
DCHECK(!HasBeenStopped());
stop_callback_ = callback;
}
} // namespace tether
} // namespace chromeos
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_COMPONENTS_FAKE_ERROR_TOLERANT_BLE_ADVERTISEMENT_H_
#define CHROMEOS_COMPONENTS_FAKE_ERROR_TOLERANT_BLE_ADVERTISEMENT_H_
#include "base/callback.h"
#include "base/macros.h"
#include "chromeos/components/tether/error_tolerant_ble_advertisement.h"
namespace chromeos {
namespace tether {
// Test double for ErrorTolerantBleAdvertisement.
class FakeErrorTolerantBleAdvertisement : public ErrorTolerantBleAdvertisement {
public:
FakeErrorTolerantBleAdvertisement(const std::string& device_id);
FakeErrorTolerantBleAdvertisement(
const std::string& device_id,
const base::Callback<void(FakeErrorTolerantBleAdvertisement*)>&
deletion_callback);
~FakeErrorTolerantBleAdvertisement() override;
void InvokeStopCallback();
// ErrorTolerantBleAdvertisement:
void Stop(const base::Closure& callback) override;
bool HasBeenStopped() override;
private:
const base::Callback<void(FakeErrorTolerantBleAdvertisement*)>
deletion_callback_;
base::Closure stop_callback_;
DISALLOW_COPY_AND_ASSIGN(FakeErrorTolerantBleAdvertisement);
};
} // namespace tether
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_FAKE_ERROR_TOLERANT_BLE_ADVERTISEMENT_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment