Commit 20bb4123 authored by Jun Choi's avatar Jun Choi Committed by Commit Bot

Start FidoDeviceDiscovery asynchronously

Callback for BluetoothAdapterFactory::GetAdapter() may be invoked
synchronously for ChromeOS devices. This results in discovery of
FidoBleDevices that were already known to BluetoothAdapter not being
notified to UI embedder, and WebAuthN UI would not show new Bluetooth
devices on device selection view --even when FidoBleDevices are
discovered. To avoid such hairpinning, invoke
FidoDeviceDiscovery::StartInternal asynchronously.

Bug: 823686
Change-Id: Idc6c4d1d12d76a15118f15366e734325ba1819c0
Reviewed-on: https://chromium-review.googlesource.com/c/1300798
Commit-Queue: Jun Choi <hongjunchoi@chromium.org>
Reviewed-by: default avatarJan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#603216}
parent 33db1ea9
...@@ -83,23 +83,9 @@ void FidoBleDiscoveryBase::OnGetAdapter( ...@@ -83,23 +83,9 @@ void FidoBleDiscoveryBase::OnGetAdapter(
} }
void FidoBleDiscoveryBase::StartInternal() { void FidoBleDiscoveryBase::StartInternal() {
auto& factory = BluetoothAdapterFactory::Get(); BluetoothAdapterFactory::Get().GetAdapter(
auto callback = base::BindOnce(&FidoBleDiscoveryBase::OnGetAdapter, base::AdaptCallbackForRepeating(base::BindOnce(
weak_factory_.GetWeakPtr()); &FidoBleDiscoveryBase::OnGetAdapter, weak_factory_.GetWeakPtr())));
#if defined(OS_MACOSX)
// BluetoothAdapter may invoke the callback synchronously on Mac, but
// StartInternal() never wants to invoke to NotifyDiscoveryStarted()
// immediately, so ensure there is at least post-task at this bottleneck.
// See: https://crbug.com/823686.
callback = base::BindOnce(
[](BluetoothAdapterFactory::AdapterCallback callback,
scoped_refptr<BluetoothAdapter> adapter) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), adapter));
},
base::AdaptCallbackForRepeating(std::move(callback)));
#endif // defined(OS_MACOSX)
factory.GetAdapter(base::AdaptCallbackForRepeating(std::move(callback)));
} }
} // namespace device } // namespace device
...@@ -120,6 +120,7 @@ TEST_F(FidoBleDiscoveryTest, ...@@ -120,6 +120,7 @@ TEST_F(FidoBleDiscoveryTest,
EXPECT_CALL(*adapter(), SetPowered).Times(0); EXPECT_CALL(*adapter(), SetPowered).Times(0);
EXPECT_CALL(*observer(), DiscoveryStarted(discovery(), false)); EXPECT_CALL(*observer(), DiscoveryStarted(discovery(), false));
discovery()->Start(); discovery()->Start();
scoped_task_environment_.FastForwardUntilNoTasksRemain();
} }
TEST_F(FidoBleDiscoveryTest, FidoBleDiscoveryResumeScanningAfterPoweredOn) { TEST_F(FidoBleDiscoveryTest, FidoBleDiscoveryResumeScanningAfterPoweredOn) {
...@@ -131,6 +132,7 @@ TEST_F(FidoBleDiscoveryTest, FidoBleDiscoveryResumeScanningAfterPoweredOn) { ...@@ -131,6 +132,7 @@ TEST_F(FidoBleDiscoveryTest, FidoBleDiscoveryResumeScanningAfterPoweredOn) {
// starts again. // starts again.
EXPECT_CALL(*adapter(), StartDiscoverySessionWithFilterRaw); EXPECT_CALL(*adapter(), StartDiscoverySessionWithFilterRaw);
discovery()->Start(); discovery()->Start();
scoped_task_environment_.FastForwardUntilNoTasksRemain();
adapter()->NotifyAdapterPoweredChanged(true); adapter()->NotifyAdapterPoweredChanged(true);
} }
...@@ -305,6 +307,7 @@ TEST_F(FidoBleDiscoveryTest, ...@@ -305,6 +307,7 @@ TEST_F(FidoBleDiscoveryTest,
EXPECT_CALL(*observer(), AuthenticatorIdChanged(discovery(), kAuthenticatorId, EXPECT_CALL(*observer(), AuthenticatorIdChanged(discovery(), kAuthenticatorId,
kAuthenticatorChangedId)); kAuthenticatorChangedId));
discovery()->Start(); discovery()->Start();
scoped_task_environment_.FastForwardUntilNoTasksRemain();
adapter()->NotifyDeviceChanged(mock_device.get()); adapter()->NotifyDeviceChanged(mock_device.get());
ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(mock_device.get())); ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(mock_device.get()));
...@@ -328,6 +331,7 @@ TEST_F(FidoBleDiscoveryTest, DiscoveryNotifiesObserverWhenDeviceInPairingMode) { ...@@ -328,6 +331,7 @@ TEST_F(FidoBleDiscoveryTest, DiscoveryNotifiesObserverWhenDeviceInPairingMode) {
const auto device_id = FidoBleDevice::GetId(kDeviceAddress); const auto device_id = FidoBleDevice::GetId(kDeviceAddress);
discovery()->Start(); discovery()->Start();
scoped_task_environment_.FastForwardUntilNoTasksRemain();
::testing::InSequence sequence; ::testing::InSequence sequence;
EXPECT_CALL(*observer(), EXPECT_CALL(*observer(),
...@@ -350,6 +354,7 @@ TEST_F(FidoBleDiscoveryTest, ...@@ -350,6 +354,7 @@ TEST_F(FidoBleDiscoveryTest,
const auto device_id = FidoBleDevice::GetId(kDeviceAddress); const auto device_id = FidoBleDevice::GetId(kDeviceAddress);
discovery()->Start(); discovery()->Start();
scoped_task_environment_.FastForwardUntilNoTasksRemain();
::testing::InSequence sequence; ::testing::InSequence sequence;
EXPECT_CALL(*observer(), EXPECT_CALL(*observer(),
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <utility> #include <utility>
#include "base/bind.h" #include "base/bind.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "device/fido/ble/fido_ble_discovery.h" #include "device/fido/ble/fido_ble_discovery.h"
#include "device/fido/cable/fido_cable_discovery.h" #include "device/fido/cable/fido_cable_discovery.h"
...@@ -90,10 +91,12 @@ FidoDeviceDiscovery::~FidoDeviceDiscovery() = default; ...@@ -90,10 +91,12 @@ FidoDeviceDiscovery::~FidoDeviceDiscovery() = default;
void FidoDeviceDiscovery::Start() { void FidoDeviceDiscovery::Start() {
DCHECK_EQ(state_, State::kIdle); DCHECK_EQ(state_, State::kIdle);
state_ = State::kStarting; state_ = State::kStarting;
// TODO(hongjunchoi): Fix so that NotifiyStarted() is never called
// synchronously after StartInternal(). // To ensure that that NotifiyStarted() is never invoked synchronously,
// See: https://crbug.com/823686 // post task asynchronously.
StartInternal(); base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&FidoDeviceDiscovery::StartInternal,
weak_factory_.GetWeakPtr()));
} }
void FidoDeviceDiscovery::NotifyDiscoveryStarted(bool success) { void FidoDeviceDiscovery::NotifyDiscoveryStarted(bool success) {
......
...@@ -59,6 +59,8 @@ TEST(FidoDiscoveryTest, TestAddAndRemoveObserver) { ...@@ -59,6 +59,8 @@ TEST(FidoDiscoveryTest, TestAddAndRemoveObserver) {
} }
TEST(FidoDiscoveryTest, TestNotificationsOnSuccessfulStart) { TEST(FidoDiscoveryTest, TestNotificationsOnSuccessfulStart) {
base::test::ScopedTaskEnvironment scoped_task_environment_;
ConcreteFidoDiscovery discovery(FidoTransportProtocol::kBluetoothLowEnergy); ConcreteFidoDiscovery discovery(FidoTransportProtocol::kBluetoothLowEnergy);
MockFidoDiscoveryObserver observer; MockFidoDiscoveryObserver observer;
discovery.set_observer(&observer); discovery.set_observer(&observer);
...@@ -68,6 +70,8 @@ TEST(FidoDiscoveryTest, TestNotificationsOnSuccessfulStart) { ...@@ -68,6 +70,8 @@ TEST(FidoDiscoveryTest, TestNotificationsOnSuccessfulStart) {
EXPECT_CALL(discovery, StartInternal()); EXPECT_CALL(discovery, StartInternal());
discovery.Start(); discovery.Start();
scoped_task_environment_.RunUntilIdle();
EXPECT_TRUE(discovery.is_start_requested()); EXPECT_TRUE(discovery.is_start_requested());
EXPECT_FALSE(discovery.is_running()); EXPECT_FALSE(discovery.is_running());
::testing::Mock::VerifyAndClearExpectations(&discovery); ::testing::Mock::VerifyAndClearExpectations(&discovery);
...@@ -80,11 +84,14 @@ TEST(FidoDiscoveryTest, TestNotificationsOnSuccessfulStart) { ...@@ -80,11 +84,14 @@ TEST(FidoDiscoveryTest, TestNotificationsOnSuccessfulStart) {
} }
TEST(FidoDiscoveryTest, TestNotificationsOnFailedStart) { TEST(FidoDiscoveryTest, TestNotificationsOnFailedStart) {
base::test::ScopedTaskEnvironment scoped_task_environment_;
ConcreteFidoDiscovery discovery(FidoTransportProtocol::kBluetoothLowEnergy); ConcreteFidoDiscovery discovery(FidoTransportProtocol::kBluetoothLowEnergy);
MockFidoDiscoveryObserver observer; MockFidoDiscoveryObserver observer;
discovery.set_observer(&observer); discovery.set_observer(&observer);
discovery.Start(); discovery.Start();
scoped_task_environment_.RunUntilIdle();
EXPECT_CALL(observer, DiscoveryStarted(&discovery, false)); EXPECT_CALL(observer, DiscoveryStarted(&discovery, false));
discovery.NotifyDiscoveryStarted(false); discovery.NotifyDiscoveryStarted(false);
......
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