Commit 534600af authored by James Hawkins's avatar James Hawkins Committed by Commit Bot

Instant Tethering: Remove unused BleScannerImpl.

R=hansberry@chromium.org

Bug: 903991
Test: none
Change-Id: I51005dc78fc632371c1ad211fcafebfbdf730caf
Reviewed-on: https://chromium-review.googlesource.com/c/1343280
Commit-Queue: James Hawkins <jhawkins@chromium.org>
Reviewed-by: default avatarRyan Hansberry <hansberry@chromium.org>
Cr-Commit-Position: refs/heads/master@{#609590}
parent ec589a5c
......@@ -23,8 +23,6 @@ static_library("tether") {
"ble_connection_metrics_logger.h",
"ble_scanner.cc",
"ble_scanner.h",
"ble_scanner_impl.cc",
"ble_scanner_impl.h",
"connect_tethering_operation.cc",
"connect_tethering_operation.h",
"connection_preserver.cc",
......@@ -250,7 +248,6 @@ source_set("unit_tests") {
"ble_advertisement_device_queue_unittest.cc",
"ble_connection_manager_unittest.cc",
"ble_connection_metrics_logger_unittest.cc",
"ble_scanner_impl_unittest.cc",
"connect_tethering_operation_unittest.cc",
"connection_preserver_impl_unittest.cc",
"crash_recovery_manager_impl_unittest.cc",
......
......@@ -8,7 +8,6 @@
#include "chromeos/chromeos_features.h"
#include "chromeos/components/tether/ble_advertisement_device_queue.h"
#include "chromeos/components/tether/ble_connection_metrics_logger.h"
#include "chromeos/components/tether/ble_scanner_impl.h"
#include "chromeos/components/tether/disconnect_tethering_request_sender_impl.h"
#include "chromeos/components/tether/network_configuration_remover.h"
#include "chromeos/components/tether/wifi_hotspot_disconnector_impl.h"
......@@ -103,13 +102,6 @@ AsynchronousShutdownObjectContainerImpl::
? nullptr
: secure_channel::BleSynchronizer::Factory::Get()->BuildInstance(
adapter)),
ble_scanner_(
base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)
? nullptr
: BleScannerImpl::Factory::NewInstance(adapter,
nullptr,
ble_synchronizer_.get(),
tether_host_fetcher_)),
ble_connection_metrics_logger_(
base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)
? nullptr
......@@ -130,10 +122,6 @@ AsynchronousShutdownObjectContainerImpl::
AsynchronousShutdownObjectContainerImpl::
~AsynchronousShutdownObjectContainerImpl() {
disconnect_tethering_request_sender_->RemoveObserver(this);
if (!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) {
ble_scanner_->RemoveObserver(this);
}
}
void AsynchronousShutdownObjectContainerImpl::Shutdown(
......@@ -144,9 +132,6 @@ void AsynchronousShutdownObjectContainerImpl::Shutdown(
// The objects below require asynchronous shutdowns, so start observering
// these objects. Once they notify observers that they are finished shutting
// down, the asynchronous shutdown will complete.
if (!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) {
ble_scanner_->AddObserver(this);
}
disconnect_tethering_request_sender_->AddObserver(this);
ShutdownIfPossible();
......@@ -177,20 +162,12 @@ void AsynchronousShutdownObjectContainerImpl::
ShutdownIfPossible();
}
void AsynchronousShutdownObjectContainerImpl::OnDiscoverySessionStateChanged(
bool discovery_session_active) {
ShutdownIfPossible();
}
void AsynchronousShutdownObjectContainerImpl::ShutdownIfPossible() {
DCHECK(!shutdown_complete_callback_.is_null());
if (AreAsynchronousOperationsActive())
return;
if (!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) {
ble_scanner_->RemoveObserver(this);
}
disconnect_tethering_request_sender_->RemoveObserver(this);
shutdown_complete_callback_.Run();
......@@ -210,23 +187,12 @@ bool AsynchronousShutdownObjectContainerImpl::
return true;
}
// The BLE scanner must shut down completely before the component shuts down.
if (!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi) &&
ble_scanner_->ShouldDiscoverySessionBeActive() !=
ble_scanner_->IsDiscoverySessionActive()) {
return true;
}
return false;
}
void AsynchronousShutdownObjectContainerImpl::SetTestDoubles(
std::unique_ptr<BleScanner> ble_scanner,
std::unique_ptr<DisconnectTetheringRequestSender>
disconnect_tethering_request_sender) {
if (!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) {
ble_scanner_ = std::move(ble_scanner);
}
disconnect_tethering_request_sender_ =
std::move(disconnect_tethering_request_sender);
}
......
......@@ -55,7 +55,6 @@ class WifiHotspotDisconnector;
// Concrete AsynchronousShutdownObjectContainer implementation.
class AsynchronousShutdownObjectContainerImpl
: public AsynchronousShutdownObjectContainer,
public BleScanner::Observer,
public DisconnectTetheringRequestSender::Observer {
public:
class Factory {
......@@ -113,9 +112,6 @@ class AsynchronousShutdownObjectContainerImpl
NetworkConnectionHandler* network_connection_handler,
PrefService* pref_service);
// BleScanner::Observer:
void OnDiscoverySessionStateChanged(bool discovery_session_active) override;
// DisconnectTetheringRequestSender::Observer:
void OnPendingDisconnectRequestsComplete() override;
......@@ -125,8 +121,7 @@ class AsynchronousShutdownObjectContainerImpl
void ShutdownIfPossible();
bool AreAsynchronousOperationsActive();
void SetTestDoubles(std::unique_ptr<BleScanner> ble_scanner,
std::unique_ptr<DisconnectTetheringRequestSender>
void SetTestDoubles(std::unique_ptr<DisconnectTetheringRequestSender>
disconnect_tethering_request_sender);
scoped_refptr<device::BluetoothAdapter> adapter_;
......@@ -136,7 +131,6 @@ class AsynchronousShutdownObjectContainerImpl
local_device_data_provider_;
std::unique_ptr<BleAdvertisementDeviceQueue> ble_advertisement_device_queue_;
std::unique_ptr<secure_channel::BleSynchronizerBase> ble_synchronizer_;
std::unique_ptr<BleScanner> ble_scanner_;
std::unique_ptr<BleConnectionMetricsLogger> ble_connection_metrics_logger_;
std::unique_ptr<DisconnectTetheringRequestSender>
disconnect_tethering_request_sender_;
......
......@@ -11,7 +11,6 @@
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h"
#include "chromeos/chromeos_features.h"
#include "chromeos/components/tether/fake_ble_scanner.h"
#include "chromeos/components/tether/fake_disconnect_tethering_request_sender.h"
#include "chromeos/components/tether/fake_tether_host_fetcher.h"
#include "chromeos/components/tether/tether_component_impl.h"
......@@ -99,13 +98,10 @@ class AsynchronousShutdownObjectContainerImplTest : public testing::Test {
nullptr /* network_connection_handler */,
test_pref_service_.get() /* pref_service */));
fake_ble_scanner_ =
new FakeBleScanner(false /* automatically_update_discovery_session */);
fake_disconnect_tethering_request_sender_ =
new FakeDisconnectTetheringRequestSender();
container_->SetTestDoubles(
base::WrapUnique(fake_ble_scanner_),
base::WrapUnique(fake_disconnect_tethering_request_sender_));
}
......@@ -133,7 +129,6 @@ class AsynchronousShutdownObjectContainerImplTest : public testing::Test {
test_pref_service_;
std::unique_ptr<FakeRemoteDeviceProviderFactory>
fake_remote_device_provider_factory_;
FakeBleScanner* fake_ble_scanner_;
FakeDisconnectTetheringRequestSender*
fake_disconnect_tethering_request_sender_;
......@@ -152,25 +147,6 @@ TEST_F(AsynchronousShutdownObjectContainerImplTest,
EXPECT_TRUE(was_shutdown_callback_invoked_);
}
TEST_F(AsynchronousShutdownObjectContainerImplTest,
TestShutdown_AsyncBleScannerShutdown) {
fake_ble_scanner_->set_is_discovery_session_active(true);
EXPECT_FALSE(fake_ble_scanner_->ShouldDiscoverySessionBeActive());
EXPECT_TRUE(fake_ble_scanner_->IsDiscoverySessionActive());
// Start the shutdown; it should not yet succeed since there is an active
// discovery session.
CallShutdown();
EXPECT_FALSE(was_shutdown_callback_invoked_);
// Now, remove the discovery session; this should cause the shutdown to
// complete.
fake_ble_scanner_->set_is_discovery_session_active(false);
fake_ble_scanner_->NotifyDiscoverySessionStateChanged(
false /* discovery_session_active */);
EXPECT_TRUE(was_shutdown_callback_invoked_);
}
TEST_F(AsynchronousShutdownObjectContainerImplTest,
TestShutdown_AsyncDisconnectTetheringRequestSenderShutdown) {
fake_disconnect_tethering_request_sender_->set_has_pending_requests(true);
......@@ -191,10 +167,6 @@ TEST_F(AsynchronousShutdownObjectContainerImplTest,
TEST_F(AsynchronousShutdownObjectContainerImplTest,
TestShutdown_MultipleSimultaneousAsyncShutdowns) {
fake_ble_scanner_->set_is_discovery_session_active(true);
EXPECT_FALSE(fake_ble_scanner_->ShouldDiscoverySessionBeActive());
EXPECT_TRUE(fake_ble_scanner_->IsDiscoverySessionActive());
fake_disconnect_tethering_request_sender_->set_has_pending_requests(true);
EXPECT_TRUE(fake_disconnect_tethering_request_sender_->HasPendingRequests());
......@@ -203,13 +175,6 @@ TEST_F(AsynchronousShutdownObjectContainerImplTest,
CallShutdown();
EXPECT_FALSE(was_shutdown_callback_invoked_);
// Now, remove the discovery session; this should not cause the shutdown to
// complete since there are still pending requests.
fake_ble_scanner_->set_is_discovery_session_active(false);
fake_ble_scanner_->NotifyDiscoverySessionStateChanged(
false /* discovery_session_active */);
EXPECT_FALSE(was_shutdown_callback_invoked_);
// Now, finish the pending requests; this should cause the shutdown to
// complete.
fake_disconnect_tethering_request_sender_->set_has_pending_requests(false);
......@@ -220,10 +185,6 @@ TEST_F(AsynchronousShutdownObjectContainerImplTest,
TEST_F(AsynchronousShutdownObjectContainerImplTest,
TestShutdown_MultipleSimultaneousAsyncShutdowns_BluetoothDisabled) {
fake_ble_scanner_->set_is_discovery_session_active(true);
EXPECT_FALSE(fake_ble_scanner_->ShouldDiscoverySessionBeActive());
EXPECT_TRUE(fake_ble_scanner_->IsDiscoverySessionActive());
fake_disconnect_tethering_request_sender_->set_has_pending_requests(true);
EXPECT_TRUE(fake_disconnect_tethering_request_sender_->HasPendingRequests());
......
// 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/ble_scanner_impl.h"
#include <memory>
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chromeos/chromeos_switches.h"
#include "chromeos/components/proximity_auth/logging/logging.h"
#include "chromeos/components/tether/tether_host_fetcher.h"
#include "chromeos/services/secure_channel/ble_constants.h"
#include "chromeos/services/secure_channel/ble_service_data_helper.h"
#include "chromeos/services/secure_channel/ble_synchronizer.h"
#include "chromeos/services/secure_channel/device_id_pair.h"
#include "components/cryptauth/proto/cryptauth_api.pb.h"
#include "components/cryptauth/remote_device_ref.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_discovery_session.h"
#include "device/bluetooth/bluetooth_uuid.h"
namespace chromeos {
namespace tether {
namespace {
// Instant Tethering does not make use of the "local device ID" argument, since
// all connections are from the same device.
// TODO(hansberry): Remove when SecureChannelClient migration is complete.
const char kStubLocalDeviceId[] = "N/A";
// Valid advertisement service data must be at least 2 bytes.
// As of March 2018, valid background advertisement service data is exactly 2
// bytes, which identify the advertising device to the scanning device.
// Valid foreground advertisement service data must include at least 4 bytes:
// 2 bytes associated with the scanning device (used as a scan filter) and 2
// bytes which identify the advertising device to the scanning device.
const size_t kMinNumBytesInServiceData = 2;
} // namespace
// static
BleScannerImpl::Factory* BleScannerImpl::Factory::factory_instance_ = nullptr;
// static
std::unique_ptr<BleScanner> BleScannerImpl::Factory::NewInstance(
scoped_refptr<device::BluetoothAdapter> adapter,
secure_channel::BleServiceDataHelper* ble_service_data_helper,
secure_channel::BleSynchronizerBase* ble_synchronizer,
TetherHostFetcher* tether_host_fetcher) {
if (!factory_instance_)
factory_instance_ = new Factory();
return factory_instance_->BuildInstance(
adapter, ble_service_data_helper, ble_synchronizer, tether_host_fetcher);
}
// static
void BleScannerImpl::Factory::SetInstanceForTesting(Factory* factory) {
factory_instance_ = factory;
}
std::unique_ptr<BleScanner> BleScannerImpl::Factory::BuildInstance(
scoped_refptr<device::BluetoothAdapter> adapter,
secure_channel::BleServiceDataHelper* ble_service_data_helper,
secure_channel::BleSynchronizerBase* ble_synchronizer,
TetherHostFetcher* tether_host_fetcher) {
return base::WrapUnique(new BleScannerImpl(
adapter, ble_service_data_helper, ble_synchronizer, tether_host_fetcher));
}
BleScannerImpl::ServiceDataProviderImpl::ServiceDataProviderImpl() = default;
BleScannerImpl::ServiceDataProviderImpl::~ServiceDataProviderImpl() = default;
const std::vector<uint8_t>*
BleScannerImpl::ServiceDataProviderImpl::GetServiceDataForUUID(
device::BluetoothDevice* bluetooth_device) {
return bluetooth_device->GetServiceDataForUUID(
device::BluetoothUUID(secure_channel::kAdvertisingServiceUuid));
}
BleScannerImpl::BleScannerImpl(
scoped_refptr<device::BluetoothAdapter> adapter,
secure_channel::BleServiceDataHelper* ble_service_data_helper,
secure_channel::BleSynchronizerBase* ble_synchronizer,
TetherHostFetcher* tether_host_fetcher)
: adapter_(adapter),
ble_service_data_helper_(ble_service_data_helper),
ble_synchronizer_(ble_synchronizer),
tether_host_fetcher_(tether_host_fetcher),
service_data_provider_(std::make_unique<ServiceDataProviderImpl>()),
task_runner_(base::ThreadTaskRunnerHandle::Get()),
weak_ptr_factory_(this) {
adapter_->AddObserver(this);
}
BleScannerImpl::~BleScannerImpl() {
adapter_->RemoveObserver(this);
}
bool BleScannerImpl::RegisterScanFilterForDevice(const std::string& device_id) {
if (registered_remote_device_ids_.size() >=
secure_channel::kMaxConcurrentAdvertisements) {
// Each scan filter corresponds to an advertisement. Thus, the number of
// concurrent advertisements cannot exceed the maximum number of concurrent
// advertisements.
PA_LOG(WARNING) << "Attempted to start a scan for a new device when the "
<< "maximum number of devices have already been "
<< "registered.";
return false;
}
registered_remote_device_ids_.push_back(device_id);
UpdateDiscoveryStatus();
return true;
}
bool BleScannerImpl::UnregisterScanFilterForDevice(
const std::string& device_id) {
for (auto it = registered_remote_device_ids_.begin();
it != registered_remote_device_ids_.end(); ++it) {
if (*it == device_id) {
registered_remote_device_ids_.erase(it);
UpdateDiscoveryStatus();
return true;
}
}
return false;
}
bool BleScannerImpl::ShouldDiscoverySessionBeActive() {
return !registered_remote_device_ids_.empty();
}
bool BleScannerImpl::IsDiscoverySessionActive() {
ResetDiscoverySessionIfNotActive();
if (discovery_session_) {
// Once the session is stopped, the pointer is cleared.
DCHECK(discovery_session_->IsActive());
return true;
}
return false;
}
void BleScannerImpl::SetTestDoubles(
std::unique_ptr<ServiceDataProvider> service_data_provider,
scoped_refptr<base::TaskRunner> test_task_runner) {
service_data_provider_ = std::move(service_data_provider);
task_runner_ = test_task_runner;
}
bool BleScannerImpl::IsDeviceRegistered(const std::string& device_id) {
return base::ContainsValue(registered_remote_device_ids_, device_id);
}
void BleScannerImpl::DeviceAdded(device::BluetoothAdapter* adapter,
device::BluetoothDevice* bluetooth_device) {
DCHECK_EQ(adapter_.get(), adapter);
HandleDeviceUpdated(bluetooth_device);
}
void BleScannerImpl::DeviceChanged(device::BluetoothAdapter* adapter,
device::BluetoothDevice* bluetooth_device) {
DCHECK_EQ(adapter_.get(), adapter);
HandleDeviceUpdated(bluetooth_device);
}
void BleScannerImpl::ResetDiscoverySessionIfNotActive() {
if (!discovery_session_ || discovery_session_->IsActive())
return;
PA_LOG(ERROR) << "BluetoothDiscoverySession became out of sync. Session is "
<< "no longer active, but it was never stopped successfully. "
<< "Resetting session.";
// |discovery_session_| should be deleted whenever the session is no longer
// active. However, due to Bluetooth bugs, this does not always occur
// properly. When we detect that this situation has occurred, delete the
// pointer and reset discovery state.
discovery_session_.reset();
discovery_session_weak_ptr_factory_.reset();
is_initializing_discovery_session_ = false;
is_stopping_discovery_session_ = false;
weak_ptr_factory_.InvalidateWeakPtrs();
ScheduleStatusChangeNotification(false /* discovery_session_active */);
}
void BleScannerImpl::UpdateDiscoveryStatus() {
if (ShouldDiscoverySessionBeActive())
EnsureDiscoverySessionActive();
else
EnsureDiscoverySessionNotActive();
}
void BleScannerImpl::EnsureDiscoverySessionActive() {
// If the session is active or is in the process of becoming active, there is
// nothing to do.
if (IsDiscoverySessionActive() || is_initializing_discovery_session_)
return;
is_initializing_discovery_session_ = true;
ble_synchronizer_->StartDiscoverySession(
base::Bind(&BleScannerImpl::OnDiscoverySessionStarted,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&BleScannerImpl::OnStartDiscoverySessionError,
weak_ptr_factory_.GetWeakPtr()));
}
void BleScannerImpl::OnDiscoverySessionStarted(
std::unique_ptr<device::BluetoothDiscoverySession> discovery_session) {
is_initializing_discovery_session_ = false;
PA_LOG(VERBOSE) << "Started discovery session successfully.";
discovery_session_ = std::move(discovery_session);
discovery_session_weak_ptr_factory_ =
std::make_unique<base::WeakPtrFactory<device::BluetoothDiscoverySession>>(
discovery_session_.get());
ScheduleStatusChangeNotification(true /* discovery_session_active */);
UpdateDiscoveryStatus();
}
void BleScannerImpl::OnStartDiscoverySessionError() {
PA_LOG(ERROR) << "Error starting discovery session. Initialization failed.";
is_initializing_discovery_session_ = false;
UpdateDiscoveryStatus();
}
void BleScannerImpl::EnsureDiscoverySessionNotActive() {
// If there is no session, there is nothing to do.
if (!IsDiscoverySessionActive() || is_stopping_discovery_session_)
return;
is_stopping_discovery_session_ = true;
ble_synchronizer_->StopDiscoverySession(
discovery_session_weak_ptr_factory_->GetWeakPtr(),
base::Bind(&BleScannerImpl::OnDiscoverySessionStopped,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&BleScannerImpl::OnStopDiscoverySessionError,
weak_ptr_factory_.GetWeakPtr()));
}
void BleScannerImpl::OnDiscoverySessionStopped() {
is_stopping_discovery_session_ = false;
PA_LOG(VERBOSE) << "Stopped discovery session successfully.";
discovery_session_.reset();
discovery_session_weak_ptr_factory_.reset();
ScheduleStatusChangeNotification(false /* discovery_session_active */);
UpdateDiscoveryStatus();
}
void BleScannerImpl::OnStopDiscoverySessionError() {
PA_LOG(ERROR) << "Error stopping discovery session.";
is_stopping_discovery_session_ = false;
UpdateDiscoveryStatus();
}
void BleScannerImpl::HandleDeviceUpdated(
device::BluetoothDevice* bluetooth_device) {
DCHECK(bluetooth_device);
const std::vector<uint8_t>* service_data =
service_data_provider_->GetServiceDataForUUID(bluetooth_device);
if (!service_data || service_data->size() < kMinNumBytesInServiceData) {
// If there is no service data or the service data is of insufficient
// length, there is not enough information to create a connection.
return;
}
// Convert the service data from a std::vector<uint8_t> to a std::string.
std::string service_data_str;
char* string_contents_ptr =
base::WriteInto(&service_data_str, service_data->size() + 1);
memcpy(string_contents_ptr, service_data->data(), service_data->size());
CheckForMatchingScanFilters(bluetooth_device, service_data_str);
}
void BleScannerImpl::CheckForMatchingScanFilters(
device::BluetoothDevice* bluetooth_device,
const std::string& service_data) {
secure_channel::DeviceIdPairSet device_id_pair_set;
for (const auto& remote_device_id : registered_remote_device_ids_)
device_id_pair_set.emplace(remote_device_id, kStubLocalDeviceId);
base::Optional<secure_channel::BleServiceDataHelper::DeviceWithBackgroundBool>
device_with_background_bool =
ble_service_data_helper_->IdentifyRemoteDevice(service_data,
device_id_pair_set);
// If the service data does not correspond to an advertisement from a device
// on this account, ignore it.
if (!device_with_background_bool)
return;
NotifyReceivedAdvertisementFromDevice(
device_with_background_bool->first /* remote_device */, bluetooth_device,
device_with_background_bool->second /* is_background_advertisement */);
}
void BleScannerImpl::ScheduleStatusChangeNotification(
bool discovery_session_active) {
// Schedule the task to run after the current task has completed. This is
// necessary because the completion of a Bluetooth task may cause the Tether
// component to be shut down; if that occurs, then we cannot reference
// instance variables in this class after the object has been deleted.
// Completing the current command as part of the next task ensures that this
// cannot occur. See crbug.com/776241.
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&BleScannerImpl::NotifyDiscoverySessionStateChanged,
weak_ptr_factory_.GetWeakPtr(), discovery_session_active));
}
} // 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_TETHER_BLE_SCANNER_IMPL_H_
#define CHROMEOS_COMPONENTS_TETHER_BLE_SCANNER_IMPL_H_
#include <map>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "chromeos/components/tether/ble_scanner.h"
#include "components/cryptauth/remote_device_ref.h"
#include "device/bluetooth/bluetooth_adapter.h"
namespace base {
class TaskRunner;
} // namespace base
namespace device {
class BluetoothDevice;
class BluetoothDiscoverySession;
} // namespace device
namespace chromeos {
namespace secure_channel {
class BleServiceDataHelper;
class BleSynchronizerBase;
} // namespace secure_channel
namespace tether {
class TetherHostFetcher;
// Concrete BleScanner implementation.
class BleScannerImpl : public BleScanner,
public device::BluetoothAdapter::Observer {
public:
class Factory {
public:
static std::unique_ptr<BleScanner> NewInstance(
scoped_refptr<device::BluetoothAdapter> adapter,
secure_channel::BleServiceDataHelper* ble_service_data_helper,
secure_channel::BleSynchronizerBase* ble_synchronizer,
TetherHostFetcher* tether_host_fetcher);
static void SetInstanceForTesting(Factory* factory);
protected:
virtual std::unique_ptr<BleScanner> BuildInstance(
scoped_refptr<device::BluetoothAdapter> adapter,
secure_channel::BleServiceDataHelper* ble_service_data_helper,
secure_channel::BleSynchronizerBase* ble_synchronizer,
TetherHostFetcher* tether_host_fetcher);
private:
static Factory* factory_instance_;
};
~BleScannerImpl() override;
// BleScanner:
bool RegisterScanFilterForDevice(const std::string& device_id) override;
bool UnregisterScanFilterForDevice(const std::string& device_id) override;
bool ShouldDiscoverySessionBeActive() override;
bool IsDiscoverySessionActive() override;
protected:
BleScannerImpl(scoped_refptr<device::BluetoothAdapter> adapter,
secure_channel::BleServiceDataHelper* ble_service_data_helper,
secure_channel::BleSynchronizerBase* ble_synchronizer,
TetherHostFetcher* tether_host_fetcher);
// device::BluetoothAdapter::Observer:
void DeviceAdded(device::BluetoothAdapter* adapter,
device::BluetoothDevice* bluetooth_device) override;
void DeviceChanged(device::BluetoothAdapter* adapter,
device::BluetoothDevice* bluetooth_device) override;
private:
friend class BleScannerImplTest;
class ServiceDataProvider {
public:
virtual ~ServiceDataProvider() {}
virtual const std::vector<uint8_t>* GetServiceDataForUUID(
device::BluetoothDevice* bluetooth_device) = 0;
};
class ServiceDataProviderImpl : public ServiceDataProvider {
public:
ServiceDataProviderImpl();
~ServiceDataProviderImpl() override;
const std::vector<uint8_t>* GetServiceDataForUUID(
device::BluetoothDevice* bluetooth_device) override;
};
void SetTestDoubles(
std::unique_ptr<ServiceDataProvider> service_data_provider,
scoped_refptr<base::TaskRunner> test_task_runner);
bool IsDeviceRegistered(const std::string& device_id);
// A discovery session should stay active until it has been stopped. However,
// due to bugs in Bluetooth code, it is possible for a discovery status to
// transition to being off without a Stop() call ever succeeding. This
// function corrects the state of Bluetooth if such a bug occurs.
void ResetDiscoverySessionIfNotActive();
void UpdateDiscoveryStatus();
void EnsureDiscoverySessionActive();
void OnDiscoverySessionStarted(
std::unique_ptr<device::BluetoothDiscoverySession> discovery_session);
void OnStartDiscoverySessionError();
void EnsureDiscoverySessionNotActive();
void OnDiscoverySessionStopped();
void OnStopDiscoverySessionError();
void HandleDeviceUpdated(device::BluetoothDevice* bluetooth_device);
void CheckForMatchingScanFilters(device::BluetoothDevice* bluetooth_device,
const std::string& service_data);
void ScheduleStatusChangeNotification(bool discovery_session_active);
scoped_refptr<device::BluetoothAdapter> adapter_;
secure_channel::BleServiceDataHelper* ble_service_data_helper_;
secure_channel::BleSynchronizerBase* ble_synchronizer_;
TetherHostFetcher* tether_host_fetcher_;
std::unique_ptr<ServiceDataProvider> service_data_provider_;
std::vector<std::string> registered_remote_device_ids_;
bool is_initializing_discovery_session_ = false;
bool is_stopping_discovery_session_ = false;
scoped_refptr<base::TaskRunner> task_runner_;
std::unique_ptr<device::BluetoothDiscoverySession> discovery_session_;
std::unique_ptr<base::WeakPtrFactory<device::BluetoothDiscoverySession>>
discovery_session_weak_ptr_factory_;
base::WeakPtrFactory<BleScannerImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(BleScannerImpl);
};
} // namespace tether
} // namespace chromeos
#endif // CHROMEOS_COMPONENTS_TETHER_BLE_SCANNER_IMPL_H_
// Copyright 2016 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/ble_scanner_impl.h"
#include <memory>
#include "base/callback_forward.h"
#include "base/memory/ptr_util.h"
#include "base/test/scoped_task_environment.h"
#include "base/test/test_simple_task_runner.h"
#include "chromeos/components/tether/fake_tether_host_fetcher.h"
#include "chromeos/services/secure_channel/ble_constants.h"
#include "chromeos/services/secure_channel/fake_ble_service_data_helper.h"
#include "chromeos/services/secure_channel/fake_ble_synchronizer.h"
#include "components/cryptauth/proto/cryptauth_api.pb.h"
#include "components/cryptauth/remote_device_test_util.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/bluetooth/test/mock_bluetooth_device.h"
#include "device/bluetooth/test/mock_bluetooth_discovery_session.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using testing::Eq;
using testing::Invoke;
using testing::NiceMock;
using testing::Return;
namespace chromeos {
namespace tether {
namespace {
class TestBleScannerObserver final : public BleScanner::Observer {
public:
TestBleScannerObserver() = default;
const std::vector<std::string>& device_addresses() {
return device_addresses_;
}
const cryptauth::RemoteDeviceRefList& devices() { return devices_; }
std::vector<bool>& discovery_session_state_changes() {
return discovery_session_state_changes_;
}
// BleScanner::Observer:
void OnReceivedAdvertisementFromDevice(
cryptauth::RemoteDeviceRef remote_device,
device::BluetoothDevice* bluetooth_device,
bool is_background_advertisement) override {
device_addresses_.push_back(bluetooth_device->GetAddress());
devices_.push_back(remote_device);
}
void OnDiscoverySessionStateChanged(bool discovery_session_active) override {
discovery_session_state_changes_.push_back(discovery_session_active);
}
private:
std::vector<std::string> device_addresses_;
cryptauth::RemoteDeviceRefList devices_;
std::vector<bool> discovery_session_state_changes_;
};
// Deletes the BleScanner when notified.
class DeletingObserver final : public BleScanner::Observer {
public:
DeletingObserver(std::unique_ptr<BleScannerImpl>& ble_scanner)
: ble_scanner_(ble_scanner) {
ble_scanner_->AddObserver(this);
}
// BleScanner::Observer:
void OnDiscoverySessionStateChanged(bool discovery_session_active) override {
// Only delete if the discovery session is no longer active.
if (discovery_session_active)
return;
ble_scanner_->RemoveObserver(this);
ble_scanner_.reset();
}
void OnReceivedAdvertisementFromDevice(
cryptauth::RemoteDeviceRef remote_device,
device::BluetoothDevice* bluetooth_device,
bool is_background_advertisement) override {}
private:
std::unique_ptr<BleScannerImpl>& ble_scanner_;
};
class MockBluetoothDeviceWithServiceData : public device::MockBluetoothDevice {
public:
MockBluetoothDeviceWithServiceData(device::MockBluetoothAdapter* adapter,
const std::string& device_address,
const std::string& service_data)
: device::MockBluetoothDevice(adapter,
/* bluetooth_class */ 0,
"name",
device_address,
false,
false) {
for (size_t i = 0; i < service_data.size(); i++) {
service_data_.push_back(static_cast<uint8_t>(service_data[i]));
}
}
const std::vector<uint8_t>* service_data() { return &service_data_; }
private:
std::vector<uint8_t> service_data_;
};
const size_t kNumBytesInBackgroundAdvertisementServiceData = 2;
const size_t kMinNumBytesInForegroundAdvertisementServiceData = 4;
const char kDefaultBluetoothAddress[] = "11:22:33:44:55:66";
} // namespace
class BleScannerImplTest : public testing::Test {
protected:
class TestServiceDataProvider : public BleScannerImpl::ServiceDataProvider {
public:
TestServiceDataProvider() = default;
~TestServiceDataProvider() override = default;
// ServiceDataProvider:
const std::vector<uint8_t>* GetServiceDataForUUID(
device::BluetoothDevice* bluetooth_device) override {
return reinterpret_cast<MockBluetoothDeviceWithServiceData*>(
bluetooth_device)
->service_data();
}
};
BleScannerImplTest()
: test_devices_(cryptauth::CreateRemoteDeviceRefListForTest(3)) {}
void SetUp() override {
// Note: This value is only used after the discovery session has been
// created (i.e., after a StartDiscoverySession() call completes
// successfully).
should_discovery_session_be_active_ = true;
fake_ble_service_data_helper_ =
std::make_unique<secure_channel::FakeBleServiceDataHelper>();
fake_ble_synchronizer_ =
std::make_unique<secure_channel::FakeBleSynchronizer>();
fake_tether_host_fetcher_ =
std::make_unique<FakeTetherHostFetcher>(test_devices_);
mock_adapter_ =
base::MakeRefCounted<NiceMock<device::MockBluetoothAdapter>>();
ON_CALL(*mock_adapter_, IsPowered()).WillByDefault(Return(true));
mock_discovery_session_ = nullptr;
ble_scanner_ = base::WrapUnique(new BleScannerImpl(
mock_adapter_, fake_ble_service_data_helper_.get(),
fake_ble_synchronizer_.get(), fake_tether_host_fetcher_.get()));
test_service_data_provider_ = new TestServiceDataProvider();
test_task_runner_ = base::MakeRefCounted<base::TestSimpleTaskRunner>();
ble_scanner_->SetTestDoubles(base::WrapUnique(test_service_data_provider_),
test_task_runner_);
test_observer_ = std::make_unique<TestBleScannerObserver>();
ble_scanner_->AddObserver(test_observer_.get());
}
void TearDown() override {
EXPECT_EQ(discovery_state_changes_so_far_,
test_observer_->discovery_session_state_changes());
}
void DeviceAdded(MockBluetoothDeviceWithServiceData* device) {
ble_scanner_->DeviceAdded(mock_adapter_.get(), device);
}
void InvokeDiscoveryStartedCallback(bool success, size_t command_index) {
if (success) {
mock_discovery_session_ = new device::MockBluetoothDiscoverySession();
ON_CALL(*mock_discovery_session_, IsActive())
.WillByDefault(
Invoke(this, &BleScannerImplTest::MockDiscoveryIsActive));
fake_ble_synchronizer_->GetStartDiscoveryCallback(command_index)
.Run(base::WrapUnique(mock_discovery_session_));
test_task_runner_->RunUntilIdle();
VerifyDiscoveryStatusChange(true /* discovery_session_active */);
return;
}
fake_ble_synchronizer_->GetStartDiscoveryErrorCallback(command_index).Run();
}
bool IsDeviceRegistered(const std::string& device_id) {
return ble_scanner_->IsDeviceRegistered(device_id);
}
void VerifyDiscoveryStatusChange(bool discovery_session_active) {
discovery_state_changes_so_far_.push_back(discovery_session_active);
EXPECT_EQ(discovery_state_changes_so_far_,
test_observer_->discovery_session_state_changes());
}
bool MockDiscoveryIsActive() { return should_discovery_session_be_active_; }
void InvokeStopDiscoveryCallback(bool success, size_t command_index) {
if (success) {
fake_ble_synchronizer_->GetStopDiscoveryCallback(command_index).Run();
test_task_runner_->RunUntilIdle();
VerifyDiscoveryStatusChange(false /* discovery_session_active */);
return;
}
fake_ble_synchronizer_->GetStopDiscoveryErrorCallback(command_index).Run();
}
const base::test::ScopedTaskEnvironment scoped_task_environment_;
const cryptauth::RemoteDeviceRefList test_devices_;
std::unique_ptr<secure_channel::FakeBleServiceDataHelper>
fake_ble_service_data_helper_;
std::unique_ptr<secure_channel::FakeBleSynchronizer> fake_ble_synchronizer_;
std::unique_ptr<FakeTetherHostFetcher> fake_tether_host_fetcher_;
scoped_refptr<NiceMock<device::MockBluetoothAdapter>> mock_adapter_;
device::MockBluetoothDiscoverySession* mock_discovery_session_;
TestServiceDataProvider* test_service_data_provider_;
scoped_refptr<base::TestSimpleTaskRunner> test_task_runner_;
std::unique_ptr<TestBleScannerObserver> test_observer_;
bool should_discovery_session_be_active_;
std::vector<bool> discovery_state_changes_so_far_;
std::unique_ptr<BleScannerImpl> ble_scanner_;
private:
DISALLOW_COPY_AND_ASSIGN(BleScannerImplTest);
};
TEST_F(BleScannerImplTest, TestDiscoverySessionFailsToStart) {
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_TRUE(IsDeviceRegistered(test_devices_[0].GetDeviceId()));
InvokeDiscoveryStartedCallback(false /* success */, 0u /* command_index */);
EXPECT_TRUE(IsDeviceRegistered(test_devices_[0].GetDeviceId()));
EXPECT_TRUE(ble_scanner_->UnregisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_EQ(0u, test_observer_->device_addresses().size());
}
TEST_F(BleScannerImplTest, TestDiscoveryStartsButNoDevicesFound) {
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_TRUE(IsDeviceRegistered(test_devices_[0].GetDeviceId()));
InvokeDiscoveryStartedCallback(true /* success */, 0u /* command_index */);
// No devices found.
EXPECT_TRUE(IsDeviceRegistered(test_devices_[0].GetDeviceId()));
EXPECT_TRUE(ble_scanner_->UnregisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_EQ(0u, test_observer_->device_addresses().size());
InvokeStopDiscoveryCallback(true /* success */, 1u /* command_index */);
}
TEST_F(BleScannerImplTest, TestDiscovery_NoServiceData) {
std::string empty_service_data = "";
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_TRUE(IsDeviceRegistered(test_devices_[0].GetDeviceId()));
InvokeDiscoveryStartedCallback(true /* success */, 0u /* command_index */);
// Device with no service data connected. Service data is required to identify
// the advertising device.
MockBluetoothDeviceWithServiceData device(
mock_adapter_.get(), kDefaultBluetoothAddress, empty_service_data);
DeviceAdded(&device);
EXPECT_EQ(0u, test_observer_->device_addresses().size());
}
TEST_F(BleScannerImplTest, TestDiscovery_ServiceDataTooShort) {
std::string short_service_data = "abc";
ASSERT_TRUE(short_service_data.size() <
kMinNumBytesInForegroundAdvertisementServiceData);
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_TRUE(IsDeviceRegistered(test_devices_[0].GetDeviceId()));
InvokeDiscoveryStartedCallback(true /* success */, 0u /* command_index */);
// Device with short service data connected. Service data of at least 4 bytes
// is required to identify the advertising device.
MockBluetoothDeviceWithServiceData device(
mock_adapter_.get(), kDefaultBluetoothAddress, short_service_data);
DeviceAdded(&device);
EXPECT_EQ(0u, test_observer_->device_addresses().size());
}
TEST_F(BleScannerImplTest, TestDiscovery_LocalDeviceDataCannotBeFetched) {
std::string valid_service_data_for_other_device = "abcd";
ASSERT_TRUE(valid_service_data_for_other_device.size() >=
kMinNumBytesInForegroundAdvertisementServiceData);
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_TRUE(IsDeviceRegistered(test_devices_[0].GetDeviceId()));
InvokeDiscoveryStartedCallback(true /* success */, 0u /* command_index */);
// Device with valid service data connected, but the local device data
// cannot be fetched.
MockBluetoothDeviceWithServiceData device(
mock_adapter_.get(), kDefaultBluetoothAddress,
valid_service_data_for_other_device);
DeviceAdded(&device);
EXPECT_EQ(0u, test_observer_->device_addresses().size());
}
TEST_F(BleScannerImplTest, TestDiscovery_ScanSuccessfulButNoRegisteredDevice) {
std::string valid_service_data_for_other_device = "abcd";
ASSERT_TRUE(valid_service_data_for_other_device.size() >=
kMinNumBytesInForegroundAdvertisementServiceData);
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_TRUE(IsDeviceRegistered(test_devices_[0].GetDeviceId()));
InvokeDiscoveryStartedCallback(true /* success */, 0u /* command_index */);
// Device with valid service data connected, but there was no registered
// device corresponding to the one that just connected.
MockBluetoothDeviceWithServiceData device(
mock_adapter_.get(), kDefaultBluetoothAddress,
valid_service_data_for_other_device);
DeviceAdded(&device);
EXPECT_EQ(0u, test_observer_->device_addresses().size());
}
TEST_F(BleScannerImplTest, TestDiscovery_Success) {
std::string valid_service_data_for_registered_device = "abcde";
ASSERT_TRUE(valid_service_data_for_registered_device.size() >=
kMinNumBytesInForegroundAdvertisementServiceData);
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_TRUE(IsDeviceRegistered(test_devices_[0].GetDeviceId()));
InvokeDiscoveryStartedCallback(true /* success */, 0u /* command_index */);
// Registered device connects.
MockBluetoothDeviceWithServiceData device(
mock_adapter_.get(), kDefaultBluetoothAddress,
valid_service_data_for_registered_device);
fake_ble_service_data_helper_->SetIdentifiedDevice(
valid_service_data_for_registered_device, test_devices_[0],
false /* is_background_advertisement */);
DeviceAdded(&device);
EXPECT_EQ(1u, test_observer_->device_addresses().size());
EXPECT_EQ(device.GetAddress(), test_observer_->device_addresses()[0]);
EXPECT_EQ(1u, test_observer_->devices().size());
EXPECT_EQ(test_devices_[0], test_observer_->devices()[0]);
EXPECT_TRUE(IsDeviceRegistered(test_devices_[0].GetDeviceId()));
EXPECT_TRUE(ble_scanner_->UnregisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_EQ(1u, test_observer_->device_addresses().size());
InvokeStopDiscoveryCallback(true /* success */, 1u /* command_index */);
}
TEST_F(BleScannerImplTest, TestDiscovery_MultipleObservers) {
TestBleScannerObserver extra_observer;
ble_scanner_->AddObserver(&extra_observer);
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_TRUE(IsDeviceRegistered(test_devices_[0].GetDeviceId()));
InvokeDiscoveryStartedCallback(true /* success */, 0u /* command_index */);
MockBluetoothDeviceWithServiceData mock_bluetooth_device(
mock_adapter_.get(), kDefaultBluetoothAddress, "fakeServiceData");
fake_ble_service_data_helper_->SetIdentifiedDevice(
"fakeServiceData", test_devices_[0],
false /* is_background_advertisement */);
DeviceAdded(&mock_bluetooth_device);
EXPECT_EQ(1u, test_observer_->device_addresses().size());
EXPECT_EQ(mock_bluetooth_device.GetAddress(),
test_observer_->device_addresses()[0]);
EXPECT_EQ(1u, test_observer_->devices().size());
EXPECT_EQ(test_devices_[0], test_observer_->devices()[0]);
EXPECT_EQ(1u, extra_observer.device_addresses().size());
EXPECT_EQ(mock_bluetooth_device.GetAddress(),
extra_observer.device_addresses()[0]);
EXPECT_EQ(1u, extra_observer.devices().size());
EXPECT_EQ(test_devices_[0], extra_observer.devices()[0]);
// Now, unregister both observers.
ble_scanner_->RemoveObserver(test_observer_.get());
ble_scanner_->RemoveObserver(&extra_observer);
// Now, simulate another scan being received. The observers should not be
// notified since they are unregistered, so they should still have a call
// count of 1.
DeviceAdded(&mock_bluetooth_device);
EXPECT_EQ(1u, test_observer_->device_addresses().size());
EXPECT_EQ(1u, extra_observer.device_addresses().size());
EXPECT_TRUE(IsDeviceRegistered(test_devices_[0].GetDeviceId()));
EXPECT_TRUE(ble_scanner_->UnregisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
// Note: Cannot use InvokeStopDiscoveryCallback() since that function
// internally verifies observer callbacks, but the observers have been
// unregistered in this case.
fake_ble_synchronizer_->GetStopDiscoveryCallback(1u /* command_index */)
.Run();
}
TEST_F(BleScannerImplTest, TestRegistrationLimit) {
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_TRUE(IsDeviceRegistered(test_devices_[0].GetDeviceId()));
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[1].GetDeviceId()));
EXPECT_TRUE(IsDeviceRegistered(test_devices_[1].GetDeviceId()));
// Attempt to register another device. Registration should fail since the
// maximum number of devices have already been registered.
ASSERT_EQ(2u, secure_channel::kMaxConcurrentAdvertisements);
EXPECT_FALSE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[2].GetDeviceId()));
EXPECT_FALSE(IsDeviceRegistered(test_devices_[2].GetDeviceId()));
// Unregistering a device which is not registered should also return false.
EXPECT_FALSE(ble_scanner_->UnregisterScanFilterForDevice(
test_devices_[2].GetDeviceId()));
EXPECT_FALSE(IsDeviceRegistered(test_devices_[2].GetDeviceId()));
// Unregister device 0.
EXPECT_TRUE(IsDeviceRegistered(test_devices_[0].GetDeviceId()));
EXPECT_TRUE(ble_scanner_->UnregisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_FALSE(IsDeviceRegistered(test_devices_[0].GetDeviceId()));
// Now, device 2 can be registered.
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[2].GetDeviceId()));
EXPECT_TRUE(IsDeviceRegistered(test_devices_[2].GetDeviceId()));
// Now, unregister the devices.
EXPECT_TRUE(IsDeviceRegistered(test_devices_[1].GetDeviceId()));
EXPECT_TRUE(ble_scanner_->UnregisterScanFilterForDevice(
test_devices_[1].GetDeviceId()));
EXPECT_FALSE(IsDeviceRegistered(test_devices_[1].GetDeviceId()));
EXPECT_TRUE(IsDeviceRegistered(test_devices_[2].GetDeviceId()));
EXPECT_TRUE(ble_scanner_->UnregisterScanFilterForDevice(
test_devices_[2].GetDeviceId()));
EXPECT_FALSE(IsDeviceRegistered(test_devices_[2].GetDeviceId()));
}
TEST_F(BleScannerImplTest, TestStartAndStopCallbacks_Success) {
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_TRUE(ble_scanner_->ShouldDiscoverySessionBeActive());
EXPECT_FALSE(ble_scanner_->IsDiscoverySessionActive());
InvokeDiscoveryStartedCallback(true /* success */, 0u /* command_index */);
EXPECT_TRUE(ble_scanner_->IsDiscoverySessionActive());
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[1].GetDeviceId()));
// Registering device 1 should not have triggered a new discovery session from
// being created since one already existed.
EXPECT_EQ(1u, fake_ble_synchronizer_->GetNumCommands());
EXPECT_TRUE(ble_scanner_->ShouldDiscoverySessionBeActive());
EXPECT_TRUE(ble_scanner_->IsDiscoverySessionActive());
EXPECT_TRUE(ble_scanner_->UnregisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
// Unregistering device 0 should not have triggered a stopped session since
// a device is still registered.
EXPECT_EQ(1u, fake_ble_synchronizer_->GetNumCommands());
EXPECT_TRUE(ble_scanner_->ShouldDiscoverySessionBeActive());
EXPECT_TRUE(ble_scanner_->IsDiscoverySessionActive());
// Device 1 is the only device remaining, so unregistering it should trigger
// the session to stop.
EXPECT_TRUE(ble_scanner_->UnregisterScanFilterForDevice(
test_devices_[1].GetDeviceId()));
EXPECT_FALSE(ble_scanner_->ShouldDiscoverySessionBeActive());
EXPECT_TRUE(ble_scanner_->IsDiscoverySessionActive());
InvokeStopDiscoveryCallback(true /* success */, 1u /* command_index */);
EXPECT_FALSE(ble_scanner_->IsDiscoverySessionActive());
}
TEST_F(BleScannerImplTest, TestStartAndStopCallbacks_Errors) {
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_TRUE(ble_scanner_->ShouldDiscoverySessionBeActive());
EXPECT_FALSE(ble_scanner_->IsDiscoverySessionActive());
// Fail to start discovery session.
InvokeDiscoveryStartedCallback(false /* success */, 0u /* command_index */);
EXPECT_FALSE(ble_scanner_->IsDiscoverySessionActive());
// Since the previous try failed, a new one should have been attempted. Let
// that one fail as well.
InvokeDiscoveryStartedCallback(false /* success */, 1u /* command_index */);
EXPECT_FALSE(ble_scanner_->IsDiscoverySessionActive());
// Now, let it succeed.
InvokeDiscoveryStartedCallback(true /* success */, 2u /* command_index */);
EXPECT_TRUE(ble_scanner_->IsDiscoverySessionActive());
// Now, unregister it, but fail to stop the discovery session.
EXPECT_TRUE(ble_scanner_->UnregisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_FALSE(ble_scanner_->ShouldDiscoverySessionBeActive());
InvokeStopDiscoveryCallback(false /* success */, 3u /* command_index */);
EXPECT_TRUE(ble_scanner_->IsDiscoverySessionActive());
// Since the previous try failed, a new stop should have been attempted. Let
// that one fail as well.
InvokeStopDiscoveryCallback(false /* success */, 4u /* command_index */);
EXPECT_TRUE(ble_scanner_->IsDiscoverySessionActive());
// Now, let it succeed.
InvokeStopDiscoveryCallback(true /* success */, 5u /* command_index */);
EXPECT_FALSE(ble_scanner_->IsDiscoverySessionActive());
}
TEST_F(BleScannerImplTest, TestStartAndStopCallbacks_UnregisterBeforeStarted) {
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_TRUE(ble_scanner_->ShouldDiscoverySessionBeActive());
EXPECT_FALSE(ble_scanner_->IsDiscoverySessionActive());
// Before invoking the discovery callback, unregister the device.
EXPECT_TRUE(ble_scanner_->UnregisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_FALSE(ble_scanner_->ShouldDiscoverySessionBeActive());
// Complete the start discovery successfully.
InvokeDiscoveryStartedCallback(true /* success */, 0u /* command_index */);
EXPECT_TRUE(ble_scanner_->IsDiscoverySessionActive());
// Because the session should not be active (i.e., there are no registered
// devices), a stop should be triggered.
InvokeStopDiscoveryCallback(true /* success */, 1u /* command_index */);
EXPECT_FALSE(ble_scanner_->IsDiscoverySessionActive());
}
TEST_F(BleScannerImplTest,
TestStartAndStopCallbacks_UnregisterBeforeStartFails) {
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_TRUE(ble_scanner_->ShouldDiscoverySessionBeActive());
EXPECT_FALSE(ble_scanner_->IsDiscoverySessionActive());
// Before invoking the discovery callback, unregister the device.
EXPECT_TRUE(ble_scanner_->UnregisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_FALSE(ble_scanner_->ShouldDiscoverySessionBeActive());
// Fail to start discovery session.
InvokeDiscoveryStartedCallback(false /* success */, 0u /* command_index */);
EXPECT_FALSE(ble_scanner_->IsDiscoverySessionActive());
// Because the session should not be active (i.e., there are no registered
// devices), a new attempt should not have occurred.
EXPECT_EQ(1u, fake_ble_synchronizer_->GetNumCommands());
}
TEST_F(BleScannerImplTest, TestStartAndStopCallbacks_RegisterBeforeStopFails) {
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_TRUE(ble_scanner_->ShouldDiscoverySessionBeActive());
EXPECT_FALSE(ble_scanner_->IsDiscoverySessionActive());
// Start discovery session.
InvokeDiscoveryStartedCallback(true /* success */, 0u /* command_index */);
EXPECT_TRUE(ble_scanner_->IsDiscoverySessionActive());
// Unregister device to attempt a stop.
EXPECT_TRUE(ble_scanner_->UnregisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_FALSE(ble_scanner_->ShouldDiscoverySessionBeActive());
EXPECT_TRUE(ble_scanner_->IsDiscoverySessionActive());
// Before the stop completes, register the device again.
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_TRUE(ble_scanner_->ShouldDiscoverySessionBeActive());
EXPECT_TRUE(ble_scanner_->IsDiscoverySessionActive());
// Fail to stop.
InvokeStopDiscoveryCallback(false /* success */, 1u /* command_index */);
EXPECT_TRUE(ble_scanner_->IsDiscoverySessionActive());
// Since there is a device registered again, there should not be another
// attempt to stop.
EXPECT_EQ(2u, fake_ble_synchronizer_->GetNumCommands());
}
// Regression test for crbug.com/768521.
TEST_F(BleScannerImplTest,
TestStopCallback_DiscoverySessionInactiveButNotStopped) {
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_TRUE(ble_scanner_->ShouldDiscoverySessionBeActive());
EXPECT_FALSE(ble_scanner_->IsDiscoverySessionActive());
// Start discovery session.
InvokeDiscoveryStartedCallback(true /* success */, 0u /* command_index */);
test_task_runner_->RunUntilIdle();
EXPECT_TRUE(ble_scanner_->IsDiscoverySessionActive());
// Unregister device to attempt a stop.
EXPECT_TRUE(ble_scanner_->UnregisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_FALSE(ble_scanner_->ShouldDiscoverySessionBeActive());
EXPECT_TRUE(ble_scanner_->IsDiscoverySessionActive());
// For this test, simulate the discovery session transitioning to
// IsActive() == false without Stop() ever succeeding.
should_discovery_session_be_active_ = false;
// Fail to stop. Even though stopping failed, IsActive() will still return
// false. In this case, the discovery session should no longer be active.
InvokeStopDiscoveryCallback(false /* success */, 1u /* command_index */);
EXPECT_FALSE(ble_scanner_->IsDiscoverySessionActive());
test_task_runner_->RunUntilIdle();
VerifyDiscoveryStatusChange(false /* discovery_session_active */);
// Since the discovery session was not active, there should not have been an
// additional call to Stop().
EXPECT_EQ(2u, fake_ble_synchronizer_->GetNumCommands());
}
// Regression test for crbug.com/776241. This bug could cause a crash if, when
// BleScannerImpl notifies observers that all the discovery session has stopped,
// an observer deletes BleScannerImpl. The fix for this issue is simply
// notifying observers in a new task so that no further action will be taken if
// the object is deleted. Without the fix for crbug.com/776241, this test would
// crash.
TEST_F(BleScannerImplTest, ObserverDeletesObjectWhenNotified) {
DeletingObserver deleting_observer(ble_scanner_);
ble_scanner_->RegisterScanFilterForDevice(test_devices_[0].GetDeviceId());
InvokeDiscoveryStartedCallback(true /* success */, 0u /* command_index */);
test_task_runner_->RunUntilIdle();
ble_scanner_->UnregisterScanFilterForDevice(test_devices_[0].GetDeviceId());
InvokeStopDiscoveryCallback(true /* success */, 1u /* command_index */);
test_task_runner_->RunUntilIdle();
}
TEST_F(BleScannerImplTest, TestDiscovery_HostIsBackgroundAdvertising) {
std::string valid_service_data_for_registered_device = "ab";
ASSERT_TRUE(valid_service_data_for_registered_device.size() ==
kNumBytesInBackgroundAdvertisementServiceData);
EXPECT_TRUE(ble_scanner_->RegisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_TRUE(IsDeviceRegistered(test_devices_[0].GetDeviceId()));
InvokeDiscoveryStartedCallback(true /* success */, 0u /* command_index */);
// Registered device connects.
MockBluetoothDeviceWithServiceData device(
mock_adapter_.get(), kDefaultBluetoothAddress,
valid_service_data_for_registered_device);
fake_ble_service_data_helper_->SetIdentifiedDevice(
valid_service_data_for_registered_device, test_devices_[0],
true /* is_background_advertisement */);
DeviceAdded(&device);
EXPECT_EQ(1u, test_observer_->device_addresses().size());
EXPECT_EQ(device.GetAddress(), test_observer_->device_addresses()[0]);
EXPECT_EQ(1u, test_observer_->devices().size());
EXPECT_EQ(test_devices_[0], test_observer_->devices()[0]);
EXPECT_TRUE(IsDeviceRegistered(test_devices_[0].GetDeviceId()));
EXPECT_TRUE(ble_scanner_->UnregisterScanFilterForDevice(
test_devices_[0].GetDeviceId()));
EXPECT_EQ(1u, test_observer_->device_addresses().size());
InvokeStopDiscoveryCallback(true /* success */, 1u /* command_index */);
}
} // namespace tether
} // namespace chromeos
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