Commit af8d33b4 authored by Kyle Horimoto's avatar Kyle Horimoto Committed by Commit Bot

[CrOS MultiDevice] Fix BLE scan result handling.

Previously, we would attempt a BLE scan any time that we got a
DeviceChanged() or DeviceAdded() callback. However, the DeviceChanged()
callback was invoked when a device was in the process of disconnecting,
meaning that we would see a disconnecting device, then try to start a
connection immediately. This resulted in spurious connection requests
which could sometime cause a deadlock in underlying Bluetooth code.
Additionally, we would rely on the DeviceChanged() and DeviceRemoved()
callbacks to listen for Bluetooth disconnections, which also resulted in
error-prone disconnections.

This CL updates both call sites to use the updated
DeviceAdvertisementReceived() and DeviceConnectedStateChanged()
callbacks instead.

Bug: 898334
Change-Id: I743e51e6e47194649ab6852966b9d892c3ef334d
Reviewed-on: https://chromium-review.googlesource.com/c/1359478
Commit-Queue: Kyle Horimoto <khorimoto@chromium.org>
Reviewed-by: default avatarGiovanni Ortuño Urquidi <ortuno@chromium.org>
Cr-Commit-Position: refs/heads/master@{#613358}
parent e1e37728
...@@ -88,14 +88,11 @@ void BleScannerImpl::HandleScanFilterChange() { ...@@ -88,14 +88,11 @@ void BleScannerImpl::HandleScanFilterChange() {
UpdateDiscoveryStatus(); UpdateDiscoveryStatus();
} }
void BleScannerImpl::DeviceAdded(device::BluetoothAdapter* adapter, void BleScannerImpl::DeviceAdvertisementReceived(
device::BluetoothDevice* bluetooth_device) { device::BluetoothAdapter* adapter,
DCHECK_EQ(adapter_.get(), adapter); device::BluetoothDevice* bluetooth_device,
HandleDeviceUpdated(bluetooth_device); int16_t rssi,
} const std::vector<uint8_t>& eir) {
void BleScannerImpl::DeviceChanged(device::BluetoothAdapter* adapter,
device::BluetoothDevice* bluetooth_device) {
DCHECK_EQ(adapter_.get(), adapter); DCHECK_EQ(adapter_.get(), adapter);
HandleDeviceUpdated(bluetooth_device); HandleDeviceUpdated(bluetooth_device);
} }
......
...@@ -69,10 +69,10 @@ class BleScannerImpl : public BleScanner, ...@@ -69,10 +69,10 @@ class BleScannerImpl : public BleScanner,
void HandleScanFilterChange() override; void HandleScanFilterChange() override;
// device::BluetoothAdapter::Observer: // device::BluetoothAdapter::Observer:
void DeviceAdded(device::BluetoothAdapter* adapter, void DeviceAdvertisementReceived(device::BluetoothAdapter* adapter,
device::BluetoothDevice* bluetooth_device) override; device::BluetoothDevice* device,
void DeviceChanged(device::BluetoothAdapter* adapter, int16_t rssi,
device::BluetoothDevice* bluetooth_device) override; const std::vector<uint8_t>& eir) override;
void UpdateDiscoveryStatus(); void UpdateDiscoveryStatus();
bool IsDiscoverySessionActive(); bool IsDiscoverySessionActive();
......
...@@ -141,19 +141,17 @@ class SecureChannelBleScannerImplTest : public testing::Test { ...@@ -141,19 +141,17 @@ class SecureChannelBleScannerImplTest : public testing::Test {
} }
void ProcessScanResultAndVerifyNoDeviceIdentified( void ProcessScanResultAndVerifyNoDeviceIdentified(
const std::string& service_data, const std::string& service_data) {
bool is_new_device) {
const FakeBleScannerDelegate::ScannedResultList& results = const FakeBleScannerDelegate::ScannedResultList& results =
fake_delegate_->handled_scan_results(); fake_delegate_->handled_scan_results();
size_t num_results_before_call = results.size(); size_t num_results_before_call = results.size();
SimulateScanResult(service_data, is_new_device); SimulateScanResult(service_data);
EXPECT_EQ(num_results_before_call, results.size()); EXPECT_EQ(num_results_before_call, results.size());
} }
void ProcessScanResultAndVerifyDevice( void ProcessScanResultAndVerifyDevice(
const std::string& service_data, const std::string& service_data,
bool is_new_device,
multidevice::RemoteDeviceRef expected_remote_device, multidevice::RemoteDeviceRef expected_remote_device,
bool is_background_advertisement) { bool is_background_advertisement) {
const FakeBleScannerDelegate::ScannedResultList& results = const FakeBleScannerDelegate::ScannedResultList& results =
...@@ -164,7 +162,7 @@ class SecureChannelBleScannerImplTest : public testing::Test { ...@@ -164,7 +162,7 @@ class SecureChannelBleScannerImplTest : public testing::Test {
size_t num_results_before_call = results.size(); size_t num_results_before_call = results.size();
FakeBluetoothDevice* fake_bluetooth_device = FakeBluetoothDevice* fake_bluetooth_device =
SimulateScanResult(service_data, is_new_device); SimulateScanResult(service_data);
EXPECT_EQ(num_results_before_call + 1u, results.size()); EXPECT_EQ(num_results_before_call + 1u, results.size());
EXPECT_EQ(expected_remote_device, std::get<0>(results.back())); EXPECT_EQ(expected_remote_device, std::get<0>(results.back()));
...@@ -216,11 +214,10 @@ class SecureChannelBleScannerImplTest : public testing::Test { ...@@ -216,11 +214,10 @@ class SecureChannelBleScannerImplTest : public testing::Test {
} }
private: private:
// Scan results come in as the result of either a new device or a change on an FakeBluetoothDevice* SimulateScanResult(const std::string& service_data) {
// existing device. If |is_new_device| is true, a new device change will be static const int16_t kFakeRssi = -70;
// simulated; otherwise, an existing device change will be simulated. static const std::vector<uint8_t> kFakeEir;
FakeBluetoothDevice* SimulateScanResult(const std::string& service_data,
bool is_new_device) {
// Scan result should not be received if there is no active discovery // Scan result should not be received if there is no active discovery
// session. // session.
EXPECT_TRUE(fake_discovery_session_); EXPECT_TRUE(fake_discovery_session_);
...@@ -228,17 +225,12 @@ class SecureChannelBleScannerImplTest : public testing::Test { ...@@ -228,17 +225,12 @@ class SecureChannelBleScannerImplTest : public testing::Test {
auto fake_bluetooth_device = std::make_unique<FakeBluetoothDevice>( auto fake_bluetooth_device = std::make_unique<FakeBluetoothDevice>(
service_data, mock_adapter_.get()); service_data, mock_adapter_.get());
BleScannerImpl* ble_scanner_derived =
static_cast<BleScannerImpl*>(ble_scanner_.get());
// Note: MockBluetoothAdapter provides no way to notify observers, so the // Note: MockBluetoothAdapter provides no way to notify observers, so the
// observer callback must be invoked directly. // observer callback must be invoked directly.
if (is_new_device) { for (auto& observer : mock_adapter_->GetObservers()) {
ble_scanner_derived->DeviceAdded(mock_adapter_.get(), observer.DeviceAdvertisementReceived(mock_adapter_.get(),
fake_bluetooth_device.get()); fake_bluetooth_device.get(),
} else { kFakeRssi, kFakeEir);
ble_scanner_derived->DeviceChanged(mock_adapter_.get(),
fake_bluetooth_device.get());
} }
return fake_bluetooth_device.get(); return fake_bluetooth_device.get();
...@@ -271,10 +263,7 @@ TEST_F(SecureChannelBleScannerImplTest, UnrelatedScanResults) { ...@@ -271,10 +263,7 @@ TEST_F(SecureChannelBleScannerImplTest, UnrelatedScanResults) {
InvokeStartDiscoveryCallback(true /* success */, 0u /* command_index */); InvokeStartDiscoveryCallback(true /* success */, 0u /* command_index */);
EXPECT_TRUE(fake_discovery_session()); EXPECT_TRUE(fake_discovery_session());
ProcessScanResultAndVerifyNoDeviceIdentified("unrelatedServiceData", ProcessScanResultAndVerifyNoDeviceIdentified("unrelatedServiceData");
true /* is_new_device */);
ProcessScanResultAndVerifyNoDeviceIdentified("unrelatedServiceData",
false /* is_new_device */);
RemoveScanFilter(filter); RemoveScanFilter(filter);
InvokeStopDiscoveryCallback(true /* success */, 1u /* command_index */); InvokeStopDiscoveryCallback(true /* success */, 1u /* command_index */);
...@@ -296,17 +285,14 @@ TEST_F(SecureChannelBleScannerImplTest, IncorrectRole) { ...@@ -296,17 +285,14 @@ TEST_F(SecureChannelBleScannerImplTest, IncorrectRole) {
"wrongRoleServiceData", test_devices()[0], "wrongRoleServiceData", test_devices()[0],
false /* is_background_advertisement */); false /* is_background_advertisement */);
ProcessScanResultAndVerifyNoDeviceIdentified("wrongRoleServiceData", ProcessScanResultAndVerifyNoDeviceIdentified("wrongRoleServiceData");
true /* is_new_device */);
ProcessScanResultAndVerifyNoDeviceIdentified("wrongRoleServiceData",
false /* is_new_device */);
RemoveScanFilter(filter); RemoveScanFilter(filter);
InvokeStopDiscoveryCallback(true /* success */, 1u /* command_index */); InvokeStopDiscoveryCallback(true /* success */, 1u /* command_index */);
EXPECT_FALSE(fake_discovery_session()); EXPECT_FALSE(fake_discovery_session());
} }
TEST_F(SecureChannelBleScannerImplTest, IdentifyDevice_NewDevice_Background) { TEST_F(SecureChannelBleScannerImplTest, IdentifyDevice_Background) {
BleScanner::ScanFilter filter(DeviceIdPair(test_devices()[0].GetDeviceId(), BleScanner::ScanFilter filter(DeviceIdPair(test_devices()[0].GetDeviceId(),
test_devices()[1].GetDeviceId()), test_devices()[1].GetDeviceId()),
ConnectionRole::kListenerRole); ConnectionRole::kListenerRole);
...@@ -315,9 +301,7 @@ TEST_F(SecureChannelBleScannerImplTest, IdentifyDevice_NewDevice_Background) { ...@@ -315,9 +301,7 @@ TEST_F(SecureChannelBleScannerImplTest, IdentifyDevice_NewDevice_Background) {
InvokeStartDiscoveryCallback(true /* success */, 0u /* command_index */); InvokeStartDiscoveryCallback(true /* success */, 0u /* command_index */);
EXPECT_TRUE(fake_discovery_session()); EXPECT_TRUE(fake_discovery_session());
// is_new_device == true, is_background_advertisement == true ProcessScanResultAndVerifyDevice("device0ServiceData", test_devices()[0],
ProcessScanResultAndVerifyDevice("device0ServiceData",
true /* is_new_device */, test_devices()[0],
true /* is_background_advertisement */); true /* is_background_advertisement */);
RemoveScanFilter(filter); RemoveScanFilter(filter);
...@@ -325,8 +309,7 @@ TEST_F(SecureChannelBleScannerImplTest, IdentifyDevice_NewDevice_Background) { ...@@ -325,8 +309,7 @@ TEST_F(SecureChannelBleScannerImplTest, IdentifyDevice_NewDevice_Background) {
EXPECT_FALSE(fake_discovery_session()); EXPECT_FALSE(fake_discovery_session());
} }
TEST_F(SecureChannelBleScannerImplTest, TEST_F(SecureChannelBleScannerImplTest, IdentifyDevice_Foreground) {
IdentifyDevice_ExistingDevice_Foreground) {
BleScanner::ScanFilter filter(DeviceIdPair(test_devices()[0].GetDeviceId(), BleScanner::ScanFilter filter(DeviceIdPair(test_devices()[0].GetDeviceId(),
test_devices()[1].GetDeviceId()), test_devices()[1].GetDeviceId()),
ConnectionRole::kInitiatorRole); ConnectionRole::kInitiatorRole);
...@@ -335,9 +318,7 @@ TEST_F(SecureChannelBleScannerImplTest, ...@@ -335,9 +318,7 @@ TEST_F(SecureChannelBleScannerImplTest,
InvokeStartDiscoveryCallback(true /* success */, 0u /* command_index */); InvokeStartDiscoveryCallback(true /* success */, 0u /* command_index */);
EXPECT_TRUE(fake_discovery_session()); EXPECT_TRUE(fake_discovery_session());
// is_new_device == false, is_background_advertisement == false ProcessScanResultAndVerifyDevice("device0ServiceData", test_devices()[0],
ProcessScanResultAndVerifyDevice("device0ServiceData",
false /* is_new_device */, test_devices()[0],
false /* is_background_advertisement */); false /* is_background_advertisement */);
RemoveScanFilter(filter); RemoveScanFilter(filter);
...@@ -359,8 +340,7 @@ TEST_F(SecureChannelBleScannerImplTest, IdentifyDevice_MultipleScans) { ...@@ -359,8 +340,7 @@ TEST_F(SecureChannelBleScannerImplTest, IdentifyDevice_MultipleScans) {
EXPECT_TRUE(fake_discovery_session()); EXPECT_TRUE(fake_discovery_session());
// Identify device 0. // Identify device 0.
ProcessScanResultAndVerifyDevice("device0ServiceData", ProcessScanResultAndVerifyDevice("device0ServiceData", test_devices()[0],
false /* is_new_device */, test_devices()[0],
false /* is_background_advertisement */); false /* is_background_advertisement */);
// Remove the identified device from the list of scan filters. // Remove the identified device from the list of scan filters.
...@@ -383,8 +363,7 @@ TEST_F(SecureChannelBleScannerImplTest, IdentifyDevice_MultipleScans) { ...@@ -383,8 +363,7 @@ TEST_F(SecureChannelBleScannerImplTest, IdentifyDevice_MultipleScans) {
EXPECT_TRUE(fake_discovery_session()); EXPECT_TRUE(fake_discovery_session());
// Identify device 2. // Identify device 2.
ProcessScanResultAndVerifyDevice("device2ServiceData", ProcessScanResultAndVerifyDevice("device2ServiceData", test_devices()[2],
false /* is_new_device */, test_devices()[2],
false /* is_background_advertisement */); false /* is_background_advertisement */);
// Remove the scan filter, and verify that the scan stopped. // Remove the scan filter, and verify that the scan stopped.
......
...@@ -392,9 +392,10 @@ void BluetoothLowEnergyWeaveClientConnection::SendMessageImpl( ...@@ -392,9 +392,10 @@ void BluetoothLowEnergyWeaveClientConnection::SendMessageImpl(
ProcessNextWriteRequest(); ProcessNextWriteRequest();
} }
void BluetoothLowEnergyWeaveClientConnection::DeviceChanged( void BluetoothLowEnergyWeaveClientConnection::DeviceConnectedStateChanged(
device::BluetoothAdapter* adapter, device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) { device::BluetoothDevice* device,
bool is_now_connected) {
// Ignore updates about other devices. // Ignore updates about other devices.
if (device->GetAddress() != GetDeviceAddress()) if (device->GetAddress() != GetDeviceAddress())
return; return;
...@@ -408,7 +409,7 @@ void BluetoothLowEnergyWeaveClientConnection::DeviceChanged( ...@@ -408,7 +409,7 @@ void BluetoothLowEnergyWeaveClientConnection::DeviceChanged(
// If a connection has already occurred and |device| is still connected, there // If a connection has already occurred and |device| is still connected, there
// is nothing to do. // is nothing to do.
if (device->IsConnected()) if (is_now_connected)
return; return;
PA_LOG(WARNING) << "GATT connection to " << GetDeviceInfoLogString() PA_LOG(WARNING) << "GATT connection to " << GetDeviceInfoLogString()
...@@ -417,19 +418,6 @@ void BluetoothLowEnergyWeaveClientConnection::DeviceChanged( ...@@ -417,19 +418,6 @@ void BluetoothLowEnergyWeaveClientConnection::DeviceChanged(
BLE_WEAVE_CONNECTION_RESULT_ERROR_CONNECTION_DROPPED); BLE_WEAVE_CONNECTION_RESULT_ERROR_CONNECTION_DROPPED);
} }
void BluetoothLowEnergyWeaveClientConnection::DeviceRemoved(
device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) {
// Ignore updates about other devices.
if (device->GetAddress() != GetDeviceAddress())
return;
PA_LOG(WARNING) << "Device has been lost: " << GetDeviceInfoLogString()
<< ".";
DestroyConnection(
BleWeaveConnectionResult::BLE_WEAVE_CONNECTION_RESULT_ERROR_DEVICE_LOST);
}
void BluetoothLowEnergyWeaveClientConnection::GattCharacteristicValueChanged( void BluetoothLowEnergyWeaveClientConnection::GattCharacteristicValueChanged(
device::BluetoothAdapter* adapter, device::BluetoothAdapter* adapter,
device::BluetoothRemoteGattCharacteristic* characteristic, device::BluetoothRemoteGattCharacteristic* characteristic,
......
...@@ -152,10 +152,9 @@ class BluetoothLowEnergyWeaveClientConnection ...@@ -152,10 +152,9 @@ class BluetoothLowEnergyWeaveClientConnection
void OnDidSendMessage(const WireMessage& message, bool success) override; void OnDidSendMessage(const WireMessage& message, bool success) override;
// device::BluetoothAdapter::Observer: // device::BluetoothAdapter::Observer:
void DeviceChanged(device::BluetoothAdapter* adapter, void DeviceConnectedStateChanged(device::BluetoothAdapter* adapter,
device::BluetoothDevice* device) override; device::BluetoothDevice* device,
void DeviceRemoved(device::BluetoothAdapter* adapter, bool is_now_connected) override;
device::BluetoothDevice* device) override;
void GattCharacteristicValueChanged( void GattCharacteristicValueChanged(
device::BluetoothAdapter* adapter, device::BluetoothAdapter* adapter,
device::BluetoothRemoteGattCharacteristic* characteristic, device::BluetoothRemoteGattCharacteristic* characteristic,
...@@ -175,6 +174,8 @@ class BluetoothLowEnergyWeaveClientConnection ...@@ -175,6 +174,8 @@ class BluetoothLowEnergyWeaveClientConnection
ConnectSuccess); ConnectSuccess);
FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest, FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
ConnectSuccessDisconnect); ConnectSuccessDisconnect);
FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
ConnectThenBluetoothDisconnects);
FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest, FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
DisconnectCalledTwice); DisconnectCalledTwice);
FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest, FRIEND_TEST_ALL_PREFIXES(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
......
...@@ -759,6 +759,22 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest, ...@@ -759,6 +759,22 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY); BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
} }
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
ConnectThenBluetoothDisconnects) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
CreateConnection(true /* should_set_low_connection_latency */));
InitializeConnection(connection.get(), kDefaultMaxPacketSize);
EXPECT_EQ(connection->sub_status(), SubStatus::CONNECTED_AND_IDLE);
connection->DeviceConnectedStateChanged(adapter_.get(),
mock_bluetooth_device_.get(),
false /* is_now_connected */);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_ERROR_CONNECTION_DROPPED);
}
TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest, TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
DisconnectCalledTwice) { DisconnectCalledTwice) {
std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection( std::unique_ptr<TestBluetoothLowEnergyWeaveClientConnection> connection(
......
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