Commit 3e7cdbb5 authored by Kyle Qian's avatar Kyle Qian Committed by Commit Bot

[CrOS MultiDevice] Handle removed/disabled BluetoothAdapter on request.

SecureChannel previously had no checks for when the BluetoothAdapter is
disabled or removed.

This CL adds an additional check within SecureChannelImpl that will
cancel a connection request early if the BluetoothAdapter is either
disabled or removed, as well as notify the client of the failure
reason.

Bug: 854366
Change-Id: I021435611c8a018da3e77a9eeb9c001311adada4
Reviewed-on: https://chromium-review.googlesource.com/1194675Reviewed-by: default avatarRyan Hansberry <hansberry@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Commit-Queue: Kyle Qian <kyleqian@google.com>
Cr-Commit-Position: refs/heads/master@{#589399}
parent dd1a0321
...@@ -34,7 +34,13 @@ enum ConnectionAttemptFailureReason { ...@@ -34,7 +34,13 @@ enum ConnectionAttemptFailureReason {
REMOTE_DEVICE_INVALID_PSK, REMOTE_DEVICE_INVALID_PSK,
// Timeouts occurred trying to contact the remote device. // Timeouts occurred trying to contact the remote device.
TIMEOUT_FINDING_DEVICE TIMEOUT_FINDING_DEVICE,
// The local Bluetooth adapter is disabled (turned off).
ADAPTER_DISABLED,
// The local Bluetooth adapter is not present.
ADAPTER_NOT_PRESENT
}; };
enum ConnectionCreationDetail { enum ConnectionCreationDetail {
......
...@@ -71,7 +71,8 @@ SecureChannelImpl::ConnectionRequestWaitingForDisconnection:: ...@@ -71,7 +71,8 @@ SecureChannelImpl::ConnectionRequestWaitingForDisconnection::
SecureChannelImpl::SecureChannelImpl( SecureChannelImpl::SecureChannelImpl(
scoped_refptr<device::BluetoothAdapter> bluetooth_adapter) scoped_refptr<device::BluetoothAdapter> bluetooth_adapter)
: timer_factory_(TimerFactoryImpl::Factory::Get()->BuildInstance()), : bluetooth_adapter_(std::move(bluetooth_adapter)),
timer_factory_(TimerFactoryImpl::Factory::Get()->BuildInstance()),
remote_device_cache_( remote_device_cache_(
cryptauth::RemoteDeviceCache::Factory::Get()->BuildInstance()), cryptauth::RemoteDeviceCache::Factory::Get()->BuildInstance()),
ble_service_data_helper_( ble_service_data_helper_(
...@@ -79,7 +80,7 @@ SecureChannelImpl::SecureChannelImpl( ...@@ -79,7 +80,7 @@ SecureChannelImpl::SecureChannelImpl(
remote_device_cache_.get())), remote_device_cache_.get())),
ble_connection_manager_( ble_connection_manager_(
BleConnectionManagerImpl::Factory::Get()->BuildInstance( BleConnectionManagerImpl::Factory::Get()->BuildInstance(
bluetooth_adapter, bluetooth_adapter_,
ble_service_data_helper_.get(), ble_service_data_helper_.get(),
timer_factory_.get())), timer_factory_.get())),
pending_connection_manager_( pending_connection_manager_(
...@@ -207,6 +208,17 @@ void SecureChannelImpl::ProcessConnectionRequest( ...@@ -207,6 +208,17 @@ void SecureChannelImpl::ProcessConnectionRequest(
return; return;
} }
// Check 4: Medium-specific verification.
switch (connection_medium) {
case ConnectionMedium::kBluetoothLowEnergy:
// Is the local Bluetooth adapter disabled or not present? If either,
// notify client and return early.
if (CheckIfBluetoothAdapterDisabledOrNotPresent(
api_fn_name, client_connection_parameters.get()))
return;
break;
}
// At this point, the request has been deemed valid. // At this point, the request has been deemed valid.
ConnectionAttemptDetails connection_attempt_details( ConnectionAttemptDetails connection_attempt_details(
device_to_connect.GetDeviceId(), local_device.GetDeviceId(), device_to_connect.GetDeviceId(), local_device.GetDeviceId(),
...@@ -320,6 +332,26 @@ bool SecureChannelImpl::CheckForInvalidInputDevice( ...@@ -320,6 +332,26 @@ bool SecureChannelImpl::CheckForInvalidInputDevice(
return true; return true;
} }
bool SecureChannelImpl::CheckIfBluetoothAdapterDisabledOrNotPresent(
ApiFunctionName api_fn_name,
ClientConnectionParameters* client_connection_parameters) {
if (!bluetooth_adapter_->IsPresent()) {
RejectRequestForReason(
api_fn_name, mojom::ConnectionAttemptFailureReason::ADAPTER_NOT_PRESENT,
client_connection_parameters);
return true;
}
if (!bluetooth_adapter_->IsPowered()) {
RejectRequestForReason(
api_fn_name, mojom::ConnectionAttemptFailureReason::ADAPTER_DISABLED,
client_connection_parameters);
return true;
}
return false;
}
base::Optional<SecureChannelImpl::InvalidRemoteDeviceReason> base::Optional<SecureChannelImpl::InvalidRemoteDeviceReason>
SecureChannelImpl::AddDeviceToCacheIfPossible( SecureChannelImpl::AddDeviceToCacheIfPossible(
ApiFunctionName api_fn_name, ApiFunctionName api_fn_name,
......
...@@ -56,7 +56,8 @@ class SecureChannelImpl : public mojom::SecureChannel, ...@@ -56,7 +56,8 @@ class SecureChannelImpl : public mojom::SecureChannel,
~SecureChannelImpl() override; ~SecureChannelImpl() override;
private: private:
SecureChannelImpl(scoped_refptr<device::BluetoothAdapter> bluetooth_adapter); explicit SecureChannelImpl(
scoped_refptr<device::BluetoothAdapter> bluetooth_adapter);
enum class InvalidRemoteDeviceReason { kInvalidPublicKey, kInvalidPsk }; enum class InvalidRemoteDeviceReason { kInvalidPublicKey, kInvalidPsk };
...@@ -136,6 +137,12 @@ class SecureChannelImpl : public mojom::SecureChannel, ...@@ -136,6 +137,12 @@ class SecureChannelImpl : public mojom::SecureChannel,
ClientConnectionParameters* client_connection_parameters, ClientConnectionParameters* client_connection_parameters,
bool is_local_device); bool is_local_device);
// Checks if |bluetooth_adapter_| is disabled or not present and rejects the
// connection request if so. Returns whether the request was rejected.
bool CheckIfBluetoothAdapterDisabledOrNotPresent(
ApiFunctionName api_fn_name,
ClientConnectionParameters* client_connection_parameters);
// Validates |device| and adds it to the |remote_device_cache_| if it is // Validates |device| and adds it to the |remote_device_cache_| if it is
// valid. If it is not valid, the reason is provided as a return type, and the // valid. If it is not valid, the reason is provided as a return type, and the
// device is not added to the cache. // device is not added to the cache.
...@@ -143,6 +150,7 @@ class SecureChannelImpl : public mojom::SecureChannel, ...@@ -143,6 +150,7 @@ class SecureChannelImpl : public mojom::SecureChannel,
ApiFunctionName api_fn_name, ApiFunctionName api_fn_name,
const cryptauth::RemoteDevice& device); const cryptauth::RemoteDevice& device);
scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_;
std::unique_ptr<TimerFactory> timer_factory_; std::unique_ptr<TimerFactory> timer_factory_;
std::unique_ptr<cryptauth::RemoteDeviceCache> remote_device_cache_; std::unique_ptr<cryptauth::RemoteDeviceCache> remote_device_cache_;
std::unique_ptr<BleServiceDataHelper> ble_service_data_helper_; std::unique_ptr<BleServiceDataHelper> ble_service_data_helper_;
......
...@@ -321,6 +321,14 @@ class SecureChannelServiceTest : public testing::Test { ...@@ -321,6 +321,14 @@ class SecureChannelServiceTest : public testing::Test {
void SetUp() override { void SetUp() override {
mock_adapter_ = mock_adapter_ =
base::MakeRefCounted<testing::NiceMock<device::MockBluetoothAdapter>>(); base::MakeRefCounted<testing::NiceMock<device::MockBluetoothAdapter>>();
is_adapter_powered_ = true;
is_adapter_present_ = true;
ON_CALL(*mock_adapter_, IsPresent())
.WillByDefault(
Invoke(this, &SecureChannelServiceTest::is_adapter_present));
ON_CALL(*mock_adapter_, IsPowered())
.WillByDefault(
Invoke(this, &SecureChannelServiceTest::is_adapter_powered));
device::BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter_); device::BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter_);
test_task_runner_ = base::MakeRefCounted<base::TestSimpleTaskRunner>(); test_task_runner_ = base::MakeRefCounted<base::TestSimpleTaskRunner>();
...@@ -584,6 +592,12 @@ class SecureChannelServiceTest : public testing::Test { ...@@ -584,6 +592,12 @@ class SecureChannelServiceTest : public testing::Test {
const cryptauth::RemoteDeviceList& test_devices() { return test_devices_; } const cryptauth::RemoteDeviceList& test_devices() { return test_devices_; }
bool is_adapter_present() { return is_adapter_present_; }
void set_is_adapter_present(bool present) { is_adapter_present_ = present; }
bool is_adapter_powered() { return is_adapter_powered_; }
void set_is_adapter_powered(bool powered) { is_adapter_powered_ = powered; }
private: private:
void AttemptConnectionAndVerifyPendingConnection( void AttemptConnectionAndVerifyPendingConnection(
const cryptauth::RemoteDevice& device_to_connect, const cryptauth::RemoteDevice& device_to_connect,
...@@ -853,6 +867,9 @@ class SecureChannelServiceTest : public testing::Test { ...@@ -853,6 +867,9 @@ class SecureChannelServiceTest : public testing::Test {
std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_; std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_;
std::unique_ptr<service_manager::Connector> connector_; std::unique_ptr<service_manager::Connector> connector_;
bool is_adapter_powered_;
bool is_adapter_present_;
mojom::SecureChannelPtr secure_channel_ptr_; mojom::SecureChannelPtr secure_channel_ptr_;
DISALLOW_COPY_AND_ASSIGN(SecureChannelServiceTest); DISALLOW_COPY_AND_ASSIGN(SecureChannelServiceTest);
...@@ -948,6 +965,48 @@ TEST_F(SecureChannelServiceTest, InitiateConnection_MissingLocalDevicePsk) { ...@@ -948,6 +965,48 @@ TEST_F(SecureChannelServiceTest, InitiateConnection_MissingLocalDevicePsk) {
mojom::ConnectionAttemptFailureReason::LOCAL_DEVICE_INVALID_PSK); mojom::ConnectionAttemptFailureReason::LOCAL_DEVICE_INVALID_PSK);
} }
TEST_F(SecureChannelServiceTest,
ListenForConnection_BluetoothAdapterNotPresent) {
FinishInitialization();
set_is_adapter_present(false);
CallListenForConnectionFromDeviceAndVerifyRejection(
test_devices()[0], test_devices()[1], "feature", ConnectionPriority::kLow,
mojom::ConnectionAttemptFailureReason::ADAPTER_NOT_PRESENT);
}
TEST_F(SecureChannelServiceTest,
InitiateConnection_BluetoothAdapterNotPresent) {
FinishInitialization();
set_is_adapter_present(false);
CallInitiateConnectionToDeviceAndVerifyRejection(
test_devices()[0], test_devices()[1], "feature", ConnectionPriority::kLow,
mojom::ConnectionAttemptFailureReason::ADAPTER_NOT_PRESENT);
}
TEST_F(SecureChannelServiceTest, ListenForConnection_BluetoothAdapterDisabled) {
FinishInitialization();
set_is_adapter_powered(false);
CallListenForConnectionFromDeviceAndVerifyRejection(
test_devices()[0], test_devices()[1], "feature", ConnectionPriority::kLow,
mojom::ConnectionAttemptFailureReason::ADAPTER_DISABLED);
}
TEST_F(SecureChannelServiceTest, InitiateConnection_BluetoothAdapterDisabled) {
FinishInitialization();
set_is_adapter_powered(false);
CallInitiateConnectionToDeviceAndVerifyRejection(
test_devices()[0], test_devices()[1], "feature", ConnectionPriority::kLow,
mojom::ConnectionAttemptFailureReason::ADAPTER_DISABLED);
}
TEST_F(SecureChannelServiceTest, CallsQueuedBeforeInitializationComplete) { TEST_F(SecureChannelServiceTest, CallsQueuedBeforeInitializationComplete) {
CallInitiateConnectionToDeviceAndVerifyInitializationNotComplete( CallInitiateConnectionToDeviceAndVerifyInitializationNotComplete(
test_devices()[4], test_devices()[5], "feature", test_devices()[4], test_devices()[5], "feature",
......
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