Commit fe176681 authored by Jun Choi's avatar Jun Choi Committed by Commit Bot

Introduce BleAdapterPowerManager

Implement BleAdapterPowerManager that handles
1) Observing BluetoothAdapter for power state change and notifying
FidoRequestHandlerBase::TransportAvailabilityObserver.
2) If BluetoothAdapter has been powered on programmatically, turning off
bluetooth adapter power on destructor.
3) Exposing API to FidoRequestHandlerBase to power on bluetooth adapter.

TBR: jam@chromium.org
Bug: 877344
Change-Id: I3a99782186e232f1242937867c5091a4ee1ec338
Reviewed-on: https://chromium-review.googlesource.com/1195150
Commit-Queue: Jun Choi <hongjunchoi@chromium.org>
Reviewed-by: default avatarBalazs Engedy <engedy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#587475}
parent 4fb7704f
......@@ -125,7 +125,8 @@ content::BrowserContext* ChromeAuthenticatorRequestDelegate::browser_context()
void ChromeAuthenticatorRequestDelegate::RegisterActionCallbacks(
base::OnceClosure cancel_callback,
device::FidoRequestHandlerBase::RequestCallback request_callback) {
device::FidoRequestHandlerBase::RequestCallback request_callback,
base::RepeatingClosure bluetooth_adapter_power_on_callback) {
request_callback_ = request_callback;
cancel_callback_ = std::move(cancel_callback);
......
......@@ -64,9 +64,10 @@ class ChromeAuthenticatorRequestDelegate
content::BrowserContext* browser_context() const;
// content::AuthenticatorRequestClientDelegate:
void RegisterActionCallbacks(base::OnceClosure cancel_callback,
device::FidoRequestHandlerBase::RequestCallback
request_callback) override;
void RegisterActionCallbacks(
base::OnceClosure cancel_callback,
device::FidoRequestHandlerBase::RequestCallback request_callback,
base::RepeatingClosure bluetooth_adapter_power_on_callback) override;
bool ShouldPermitIndividualAttestation(
const std::string& relying_party_id) override;
void ShouldReturnAttestation(
......
......@@ -496,7 +496,10 @@ void AuthenticatorImpl::MakeCredential(
weak_factory_.GetWeakPtr()) /* cancel_callback */,
base::BindRepeating(
&device::FidoRequestHandlerBase::StartAuthenticatorRequest,
request_->GetWeakPtr()) /* request_callback */);
request_->GetWeakPtr()) /* request_callback */,
base::BindRepeating(
&device::FidoRequestHandlerBase::PowerOnBluetoothAdapter,
request_->GetWeakPtr()) /* bluetooth_adapter_power_on_callback */);
request_->set_observer(request_delegate_.get());
request_->SetPlatformAuthenticatorOrMarkUnavailable(
......@@ -583,7 +586,10 @@ void AuthenticatorImpl::GetAssertion(
weak_factory_.GetWeakPtr()) /* cancel_callback */,
base::BindRepeating(
&device::FidoRequestHandlerBase::StartAuthenticatorRequest,
request_->GetWeakPtr()) /* request_callback */);
request_->GetWeakPtr()) /* request_callback */,
base::BindRepeating(
&device::FidoRequestHandlerBase::PowerOnBluetoothAdapter,
request_->GetWeakPtr()) /* bluetooth_adapter_power_on_callback */);
request_->set_observer(request_delegate_.get());
request_->SetPlatformAuthenticatorOrMarkUnavailable(
......
......@@ -27,6 +27,8 @@
#include "content/public/test/test_service_manager_context.h"
#include "content/test/test_render_frame_host.h"
#include "device/base/features.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/fido/attested_credential_data.h"
#include "device/fido/authenticator_data.h"
#include "device/fido/fake_fido_discovery.h"
......@@ -897,6 +899,12 @@ TEST_F(AuthenticatorImplTest, TestGetAssertionU2fDeviceBackwardsCompatibility) {
}
TEST_F(AuthenticatorImplTest, GetAssertionWithEmptyAllowCredentials) {
auto mock_adapter =
base::MakeRefCounted<::testing::NiceMock<device::MockBluetoothAdapter>>();
EXPECT_CALL(*mock_adapter, IsPresent())
.WillRepeatedly(::testing::Return(true));
device::BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
SimulateNavigation(GURL(kTestOrigin1));
PublicKeyCredentialRequestOptionsPtr options =
GetTestPublicKeyCredentialRequestOptions();
......@@ -1103,9 +1111,10 @@ class TestAuthenticatorRequestDelegate
is_focused_(is_focused) {}
~TestAuthenticatorRequestDelegate() override {}
void RegisterActionCallbacks(base::OnceClosure cancel_callback,
device::FidoRequestHandlerBase::RequestCallback
request_callback) override {
void RegisterActionCallbacks(
base::OnceClosure cancel_callback,
device::FidoRequestHandlerBase::RequestCallback request_callback,
base::RepeatingClosure bluetooth_adapter_power_on_callback) override {
ASSERT_TRUE(action_callbacks_registered_callback_)
<< "RegisterActionCallbacks called twice.";
std::move(action_callbacks_registered_callback_).Run();
......@@ -1845,6 +1854,11 @@ class AuthenticatorImplRequestDelegateTest : public AuthenticatorImplTest {
TEST_F(AuthenticatorImplRequestDelegateTest,
TestRequestDelegateObservesFidoRequestHandler) {
EnableFeature(features::kWebAuthBle);
auto mock_adapter =
base::MakeRefCounted<::testing::NiceMock<device::MockBluetoothAdapter>>();
EXPECT_CALL(*mock_adapter, IsPresent())
.WillRepeatedly(::testing::Return(true));
device::BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
device::test::ScopedFakeFidoDiscoveryFactory discovery_factory;
auto* fake_ble_discovery = discovery_factory.ForgeNextBleDiscovery();
......@@ -1869,6 +1883,8 @@ TEST_F(AuthenticatorImplRequestDelegateTest,
const auto device_id = mock_ble_device->GetId();
EXPECT_CALL(*mock_delegate_ptr, OnTransportAvailabilityEnumerated(_));
EXPECT_CALL(*mock_delegate_ptr, EmbedderControlsAuthenticatorDispatch(_))
.WillOnce(testing::Return(true));
base::RunLoop ble_device_found_done;
EXPECT_CALL(*mock_delegate_ptr, FidoAuthenticatorAdded(_))
......@@ -1887,6 +1903,7 @@ TEST_F(AuthenticatorImplRequestDelegateTest,
fake_ble_discovery->RemoveDevice(device_id);
ble_device_lost_done.Run();
base::RunLoop().RunUntilIdle();
}
TEST_F(AuthenticatorImplRequestDelegateTest, FailureReasonForTimeout) {
......
......@@ -21,7 +21,8 @@ void AuthenticatorRequestClientDelegate::DidFailWithInterestingReason(
void AuthenticatorRequestClientDelegate::RegisterActionCallbacks(
base::OnceClosure cancel_callback,
device::FidoRequestHandlerBase::RequestCallback request_callback) {}
device::FidoRequestHandlerBase::RequestCallback request_callback,
base::RepeatingClosure bluetooth_adapter_power_on_callback) {}
bool AuthenticatorRequestClientDelegate::ShouldPermitIndividualAttestation(
const std::string& relying_party_id) {
......
......@@ -49,7 +49,8 @@ class CONTENT_EXPORT AuthenticatorRequestClientDelegate
// dispatch request to connected authenticators.
virtual void RegisterActionCallbacks(
base::OnceClosure cancel_callback,
device::FidoRequestHandlerBase::RequestCallback request_callback);
device::FidoRequestHandlerBase::RequestCallback request_callback,
base::RepeatingClosure bluetooth_adapter_power_on_callback);
// Returns true if the given relying party ID is permitted to receive
// individual attestation certificates. This:
......
......@@ -73,6 +73,7 @@ test("device_unittests") {
"fido/ble/fido_ble_connection_unittest.cc",
"fido/ble/fido_ble_device_unittest.cc",
"fido/ble/fido_ble_frames_unittest.cc",
"fido/ble_adapter_power_manager_unittest.cc",
"fido/cable/fido_cable_device_unittest.cc",
"fido/cable/fido_cable_discovery_unittest.cc",
"fido/cable/fido_cable_handshake_handler_unittest.cc",
......
......@@ -41,6 +41,8 @@ component("fido") {
"ble/fido_ble_transaction.h",
"ble/fido_ble_uuids.cc",
"ble/fido_ble_uuids.h",
"ble_adapter_power_manager.cc",
"ble_adapter_power_manager.h",
"cable/cable_discovery_data.h",
"cable/fido_cable_device.cc",
"cable/fido_cable_device.h",
......
......@@ -83,8 +83,6 @@ void FidoBleDiscovery::DeviceRemoved(BluetoothAdapter* adapter,
void FidoBleDiscovery::AdapterPoweredChanged(BluetoothAdapter* adapter,
bool powered) {
FidoBleDiscoveryBase::AdapterPoweredChanged(adapter, powered);
// If Bluetooth adapter is powered on, resume scanning for nearby FIDO
// devices. Previously inactive discovery sessions would be terminated upon
// invocation of OnSetPowered().
......
......@@ -34,12 +34,6 @@ void FidoBleDiscoveryBase::OnStartDiscoverySessionWithFilter(
NotifyDiscoveryStarted(true);
}
void FidoBleDiscoveryBase::AdapterPoweredChanged(BluetoothAdapter* adapter,
bool powered) {
if (observer_)
observer_->BluetoothAdapterPowerChanged(powered);
}
void FidoBleDiscoveryBase::OnSetPoweredError() {
DLOG(ERROR) << "Failed to power on the adapter.";
NotifyDiscoveryStarted(false);
......@@ -59,7 +53,6 @@ void FidoBleDiscoveryBase::OnGetAdapter(
scoped_refptr<BluetoothAdapter> adapter) {
if (!adapter->IsPresent()) {
DVLOG(2) << "bluetooth adapter is not available in current system.";
NotifyDiscoveryAvailable(false);
NotifyDiscoveryStarted(false);
return;
}
......@@ -71,8 +64,6 @@ void FidoBleDiscoveryBase::OnGetAdapter(
adapter_->AddObserver(this);
if (adapter_->IsPowered()) {
FidoBleDiscoveryBase::AdapterPoweredChanged(adapter.get(),
true /* is_powered */);
OnSetPowered();
} else {
adapter_->SetPowered(
......@@ -83,7 +74,6 @@ void FidoBleDiscoveryBase::OnGetAdapter(
base::BindOnce(&FidoBleDiscoveryBase::OnSetPoweredError,
weak_factory_.GetWeakPtr())));
}
NotifyDiscoveryAvailable(true);
}
void FidoBleDiscoveryBase::StartInternal() {
......
......@@ -30,9 +30,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoBleDiscoveryBase
virtual void OnStartDiscoverySessionWithFilter(
std::unique_ptr<BluetoothDiscoverySession>);
// BluetoothAdapter::Observer:
void AdapterPoweredChanged(BluetoothAdapter* adapter, bool powered) override;
void OnSetPoweredError();
void OnStartDiscoverySessionError();
void SetDiscoverySession(
......
......@@ -47,16 +47,8 @@ TEST_F(BluetoothTest, FidoBleDiscoveryNotifyObserverWhenAdapterNotPresent) {
base::MakeRefCounted<::testing::NiceMock<MockBluetoothAdapter>>();
EXPECT_CALL(*mock_adapter, IsPresent()).WillOnce(::testing::Return(false));
BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
{
base::RunLoop run_loop;
auto quit = run_loop.QuitClosure();
EXPECT_CALL(observer, DiscoveryAvailable(&discovery, false))
.WillOnce(ReturnFromAsyncCall(quit));
EXPECT_CALL(observer, DiscoveryStarted(&discovery, false));
discovery.Start();
run_loop.Run();
}
EXPECT_CALL(observer, DiscoveryStarted(&discovery, false));
discovery.Start();
}
TEST_F(BluetoothTest, FidoBleDiscoveryResumeScanningAfterPoweredOn) {
......@@ -69,22 +61,11 @@ TEST_F(BluetoothTest, FidoBleDiscoveryResumeScanningAfterPoweredOn) {
EXPECT_CALL(*mock_adapter, SetPowered)
.WillOnce(::testing::WithArg<2>(
[](const auto& error_callback) { error_callback.Run(); }));
BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
{
base::RunLoop run_loop;
auto quit = run_loop.QuitClosure();
EXPECT_CALL(observer, DiscoveryAvailable(&discovery, true))
.WillOnce(ReturnFromAsyncCall(quit));
discovery.Start();
run_loop.Run();
}
// After BluetoothAdapter is powered on, we expect that discovery session
// starts again.
EXPECT_CALL(*mock_adapter, StartDiscoverySessionWithFilterRaw);
BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
discovery.Start();
mock_adapter->NotifyAdapterPoweredChanged(true);
}
......@@ -97,7 +78,6 @@ TEST_F(BluetoothTest, FidoBleDiscoveryNoAdapter) {
// We don't expect any calls to the notification methods.
MockFidoDiscoveryObserver observer;
discovery.set_observer(&observer);
EXPECT_CALL(observer, DiscoveryAvailable(&discovery, _)).Times(0);
EXPECT_CALL(observer, DiscoveryStarted(&discovery, _)).Times(0);
EXPECT_CALL(observer, DeviceAdded(&discovery, _)).Times(0);
EXPECT_CALL(observer, DeviceRemoved(&discovery, _)).Times(0);
......
// Copyright 2018 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 "device/fido/ble_adapter_power_manager.h"
#include <utility>
#include "base/bind_helpers.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
namespace device {
BleAdapterPowerManager::BleAdapterPowerManager(
FidoRequestHandlerBase* request_handler)
: request_handler_(request_handler), weak_factory_(this) {
BluetoothAdapterFactory::Get().GetAdapter(base::BindRepeating(
&BleAdapterPowerManager::Start, weak_factory_.GetWeakPtr()));
}
BleAdapterPowerManager::~BleAdapterPowerManager() {
if (adapter_powered_on_programmatically_)
SetAdapterPower(false /* set_power_on */);
if (adapter_)
adapter_->RemoveObserver(this);
}
void BleAdapterPowerManager::SetAdapterPower(bool set_power_on) {
if (set_power_on)
adapter_powered_on_programmatically_ = true;
adapter_->SetPowered(set_power_on, base::DoNothing(), base::DoNothing());
}
void BleAdapterPowerManager::AdapterPoweredChanged(BluetoothAdapter* adapter,
bool powered) {
request_handler_->OnBluetoothAdapterPowerChanged(powered);
}
void BleAdapterPowerManager::Start(scoped_refptr<BluetoothAdapter> adapter) {
DCHECK(!adapter_);
adapter_ = std::move(adapter);
DCHECK(adapter_);
adapter_->AddObserver(this);
request_handler_->OnBluetoothAdapterEnumerated(adapter_->IsPresent(),
adapter_->IsPowered());
}
} // namespace device
// Copyright 2018 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 DEVICE_FIDO_BLE_ADAPTER_POWER_MANAGER_H_
#define DEVICE_FIDO_BLE_ADAPTER_POWER_MANAGER_H_
#include "base/component_export.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/fido/fido_request_handler_base.h"
namespace device {
class COMPONENT_EXPORT(DEVICE_FIDO) BleAdapterPowerManager
: public BluetoothAdapter::Observer {
public:
// Handles notifying |request_handler| when BluetoothAdapter is powered on and
// off. Exposes API for |request_handler| to power on BluetoothAdapter
// programmatically, and if BluetoothAdapter was powered on programmatically,
// powers off BluetoothAdapter when |this| goes out of scope.
// |request_handler| must outlive |this|.
BleAdapterPowerManager(FidoRequestHandlerBase* request_handler);
~BleAdapterPowerManager() override;
void SetAdapterPower(bool set_power_on);
private:
friend class FidoBleAdapterPowerManagerTest;
// BluetoothAdapter::Observer:
void AdapterPoweredChanged(BluetoothAdapter* adapter, bool powered) override;
void Start(scoped_refptr<BluetoothAdapter> adapter);
FidoRequestHandlerBase* const request_handler_;
scoped_refptr<BluetoothAdapter> adapter_;
bool adapter_powered_on_programmatically_ = false;
base::WeakPtrFactory<BleAdapterPowerManager> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(BleAdapterPowerManager);
};
} // namespace device
#endif // DEVICE_FIDO_BLE_ADAPTER_POWER_MANAGER_H_
// Copyright 2018 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 "device/fido/ble_adapter_power_manager.h"
#include <memory>
#include "base/test/scoped_task_environment.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/fido/fido_request_handler_base.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace device {
namespace {
using ::testing::_;
class MockTransportAvailabilityObserver
: public FidoRequestHandlerBase::TransportAvailabilityObserver {
public:
MockTransportAvailabilityObserver() = default;
~MockTransportAvailabilityObserver() override = default;
MOCK_METHOD1(OnTransportAvailabilityEnumerated,
void(FidoRequestHandlerBase::TransportAvailabilityInfo data));
MOCK_METHOD1(EmbedderControlsAuthenticatorDispatch,
bool(const FidoAuthenticator& authenticator));
MOCK_METHOD1(BluetoothAdapterPowerChanged, void(bool is_powered_on));
MOCK_METHOD1(FidoAuthenticatorAdded,
void(const FidoAuthenticator& authenticator));
MOCK_METHOD1(FidoAuthenticatorRemoved, void(base::StringPiece device_id));
private:
DISALLOW_COPY_AND_ASSIGN(MockTransportAvailabilityObserver);
};
class FakeFidoRequestHandlerBase : public FidoRequestHandlerBase {
public:
explicit FakeFidoRequestHandlerBase(
MockTransportAvailabilityObserver* observer)
: FidoRequestHandlerBase(nullptr, {}) {
set_observer(observer);
}
private:
void DispatchRequest(FidoAuthenticator*) override {}
DISALLOW_COPY_AND_ASSIGN(FakeFidoRequestHandlerBase);
};
} // namespace
class FidoBleAdapterPowerManagerTest : public ::testing::Test {
public:
FidoBleAdapterPowerManagerTest() {
BluetoothAdapterFactory::SetAdapterForTesting(adapter_);
}
std::unique_ptr<BleAdapterPowerManager> CreateTestBleAdapterPowerManager() {
return std::make_unique<BleAdapterPowerManager>(
fake_request_handler_.get());
}
MockBluetoothAdapter* adapter() { return adapter_.get(); }
MockTransportAvailabilityObserver* observer() { return mock_observer_.get(); }
bool adapter_powered_on_programmatically(
const BleAdapterPowerManager& adapter_power_manager) {
return adapter_power_manager.adapter_powered_on_programmatically_;
}
protected:
base::test::ScopedTaskEnvironment scoped_task_environment_;
scoped_refptr<MockBluetoothAdapter> adapter_ =
base::MakeRefCounted<::testing::NiceMock<MockBluetoothAdapter>>();
std::unique_ptr<MockTransportAvailabilityObserver> mock_observer_ =
std::make_unique<MockTransportAvailabilityObserver>();
std::unique_ptr<FakeFidoRequestHandlerBase> fake_request_handler_ =
std::make_unique<FakeFidoRequestHandlerBase>(mock_observer_.get());
};
TEST_F(FidoBleAdapterPowerManagerTest, CheckAdapterPresenceDuringConstruction) {
EXPECT_CALL(*adapter(), IsPowered()).WillOnce(::testing::Return(true));
CreateTestBleAdapterPowerManager();
}
TEST_F(FidoBleAdapterPowerManagerTest, TestSetBluetoothPowerOn) {
auto power_manager = CreateTestBleAdapterPowerManager();
::testing::InSequence s;
EXPECT_CALL(*adapter(), SetPowered(true, _, _));
EXPECT_CALL(*adapter(), SetPowered(false, _, _));
power_manager->SetAdapterPower(true /* set_power_on */);
EXPECT_TRUE(adapter_powered_on_programmatically(*power_manager));
power_manager.reset();
}
} // namespace device
......@@ -493,7 +493,6 @@ TEST_F(FidoCableDiscoveryTest, TestResumeDiscoveryAfterPoweredOn) {
auto mock_adapter =
base::MakeRefCounted<::testing::NiceMock<CableMockAdapter>>();
EXPECT_CALL(*mock_adapter, IsPresent()).WillOnce(::testing::Return(true));
EXPECT_CALL(mock_observer, DiscoveryAvailable(cable_discovery.get(), true));
// After BluetoothAdapter is powered on, we expect that Cable discovery starts
// again.
......
......@@ -27,11 +27,6 @@ void FakeFidoDiscovery::WaitForCallToStart() {
wait_for_start_loop_.Run();
}
void FakeFidoDiscovery::SimulateDiscoveryAvailable(bool is_available) {
ASSERT_FALSE(is_running());
NotifyDiscoveryAvailable(is_available);
}
void FakeFidoDiscovery::SimulateStarted(bool success) {
ASSERT_FALSE(is_running());
NotifyDiscoveryStarted(success);
......@@ -39,7 +34,6 @@ void FakeFidoDiscovery::SimulateStarted(bool success) {
void FakeFidoDiscovery::WaitForCallToStartAndSimulateSuccess() {
WaitForCallToStart();
SimulateDiscoveryAvailable(true /* is_available */);
SimulateStarted(true /* success */);
}
......
......@@ -72,9 +72,6 @@ class FakeFidoDiscovery : public FidoDiscovery,
// Blocks until start is requested.
void WaitForCallToStart();
// Simulates that the discovery availability has been confirmed.
void SimulateDiscoveryAvailable(bool is_available);
// Simulates the discovery actually starting.
void SimulateStarted(bool success);
......
......@@ -103,12 +103,6 @@ void FidoDiscovery::NotifyDiscoveryStarted(bool success) {
observer_->DiscoveryStarted(this, success);
}
void FidoDiscovery::NotifyDiscoveryAvailable(bool is_available) {
if (!observer_)
return;
observer_->DiscoveryAvailable(this, is_available);
}
void FidoDiscovery::NotifyDeviceAdded(FidoDevice* device) {
DCHECK_NE(state_, State::kIdle);
if (!observer_)
......
......@@ -44,8 +44,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscovery {
virtual ~Observer();
// It is guaranteed that this is never invoked synchronously from Start().
virtual void DiscoveryAvailable(FidoDiscovery* discovery,
bool is_available) = 0;
virtual void DiscoveryStarted(FidoDiscovery* discovery, bool success) {}
// It is guaranteed that DeviceAdded/DeviceRemoved() will not be invoked
......@@ -60,7 +58,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscovery {
virtual void DeviceAdded(FidoDiscovery* discovery, FidoDevice* device) = 0;
virtual void DeviceRemoved(FidoDiscovery* discovery,
FidoDevice* device) = 0;
virtual void BluetoothAdapterPowerChanged(bool is_powered_on) {}
};
// Factory functions to construct an instance that discovers authenticators on
......@@ -98,7 +95,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscovery {
protected:
FidoDiscovery(FidoTransportProtocol transport);
void NotifyDiscoveryAvailable(bool is_available);
void NotifyDiscoveryStarted(bool success);
void NotifyDeviceAdded(FidoDevice* device);
void NotifyDeviceRemoved(FidoDevice* device);
......
......@@ -35,7 +35,6 @@ class ConcreteFidoDiscovery : public FidoDiscovery {
using FidoDiscovery::AddDevice;
using FidoDiscovery::RemoveDevice;
using FidoDiscovery::NotifyDiscoveryAvailable;
using FidoDiscovery::NotifyDiscoveryStarted;
using FidoDiscovery::NotifyDeviceAdded;
using FidoDiscovery::NotifyDeviceRemoved;
......@@ -79,29 +78,6 @@ TEST(FidoDiscoveryTest, TestNotificationsOnSuccessfulStart) {
::testing::Mock::VerifyAndClearExpectations(&observer);
}
TEST(FidoDiscoveryTest, TestNotificationsOnDiscoveryAvailabilityDetermined) {
ConcreteFidoDiscovery discovery(FidoTransportProtocol::kBluetoothLowEnergy);
MockFidoDiscoveryObserver observer;
discovery.set_observer(&observer);
EXPECT_FALSE(discovery.is_start_requested());
EXPECT_FALSE(discovery.is_running());
EXPECT_CALL(discovery, StartInternal());
discovery.Start();
EXPECT_TRUE(discovery.is_start_requested());
EXPECT_FALSE(discovery.is_running());
::testing::Mock::VerifyAndClearExpectations(&discovery);
EXPECT_CALL(observer, DiscoveryAvailable(&discovery, true));
EXPECT_CALL(observer, DiscoveryStarted(&discovery, true));
discovery.NotifyDiscoveryAvailable(true);
discovery.NotifyDiscoveryStarted(true);
EXPECT_TRUE(discovery.is_start_requested());
EXPECT_TRUE(discovery.is_running());
::testing::Mock::VerifyAndClearExpectations(&observer);
}
TEST(FidoDiscoveryTest, TestNotificationsOnFailedStart) {
ConcreteFidoDiscovery discovery(FidoTransportProtocol::kBluetoothLowEnergy);
MockFidoDiscoveryObserver observer;
......
......@@ -13,6 +13,7 @@
#include "base/strings/string_piece.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "build/build_config.h"
#include "device/fido/ble_adapter_power_manager.h"
#include "device/fido/fido_device.h"
#include "device/fido/fido_task.h"
#include "services/service_manager/public/cpp/connector.h"
......@@ -66,22 +67,18 @@ FidoRequestHandlerBase::FidoRequestHandlerBase(
// once that part is ready, namely:
//
// 1) Once the platform authenticator related fields are filled out.
// 2) [Optionally, if BLE enabled] Once BLE related fields are filled out.
// 3) [Optionally, if caBLE enabled] Once caBLE related fields are filled
// out.
// 2) [Optionally, if BLE or caBLE enabled] if Bluetooth adapter is present.
//
// On top of that, we wait for (4) an invocation that happens when the
// On top of that, we wait for (3) an invocation that happens when the
// |observer_| is set, so that OnTransportAvailabilityEnumerated is never
// called before the observer is set.
size_t transport_info_callback_count = 1u + 0u + 0u + 1u;
size_t transport_info_callback_count = 1u + 0u + 1u;
for (const auto transport : available_transports) {
// Construction of CaBleDiscovery is handled by the implementing class as it
// requires an extension passed on from the relying party.
if (transport == FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy) {
++transport_info_callback_count;
if (transport == FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy)
continue;
}
if (transport == FidoTransportProtocol::kInternal) {
// Platform authenticator availability is always indicated by
......@@ -96,13 +93,22 @@ FidoRequestHandlerBase::FidoRequestHandlerBase(
continue;
}
if (transport == FidoTransportProtocol::kBluetoothLowEnergy)
++transport_info_callback_count;
discovery->set_observer(this);
discoveries_.push_back(std::move(discovery));
}
if (base::ContainsKey(
available_transports,
FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy) ||
base::ContainsKey(available_transports,
FidoTransportProtocol::kBluetoothLowEnergy)) {
++transport_info_callback_count;
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&FidoRequestHandlerBase::ConstructBleAdapterPowerManager,
weak_factory_.GetWeakPtr()));
}
transport_availability_info_.available_transports = available_transports;
notify_observer_callback_ = base::BarrierClosure(
transport_info_callback_count,
......@@ -137,6 +143,35 @@ void FidoRequestHandlerBase::CancelOngoingTasks(
}
}
void FidoRequestHandlerBase::OnBluetoothAdapterEnumerated(bool is_present,
bool is_powered_on) {
if (!is_present) {
transport_availability_info_.available_transports.erase(
FidoTransportProtocol::kBluetoothLowEnergy);
transport_availability_info_.available_transports.erase(
FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy);
}
transport_availability_info_.is_ble_powered = is_powered_on;
DCHECK(notify_observer_callback_);
notify_observer_callback_.Run();
}
void FidoRequestHandlerBase::OnBluetoothAdapterPowerChanged(
bool is_powered_on) {
transport_availability_info_.is_ble_powered = is_powered_on;
if (observer_)
observer_->BluetoothAdapterPowerChanged(is_powered_on);
}
void FidoRequestHandlerBase::PowerOnBluetoothAdapter() {
if (!bluetooth_power_manager_)
return;
bluetooth_power_manager_->SetAdapterPower(true /* set_power_on */);
}
base::WeakPtr<FidoRequestHandlerBase> FidoRequestHandlerBase::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
......@@ -171,30 +206,6 @@ void FidoRequestHandlerBase::DeviceRemoved(FidoDiscovery* discovery,
observer_->FidoAuthenticatorRemoved(device->GetId());
}
void FidoRequestHandlerBase::BluetoothAdapterPowerChanged(bool is_powered_on) {
transport_availability_info_.is_ble_powered = is_powered_on;
if (observer_)
observer_->BluetoothAdapterPowerChanged(is_powered_on);
}
void FidoRequestHandlerBase::DiscoveryAvailable(FidoDiscovery* discovery,
bool is_available) {
if (discovery->transport() == FidoTransportProtocol::kBluetoothLowEnergy ||
discovery->transport() ==
FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy) {
// For FidoBleDiscovery and FidoCableDiscovery, discovery is available when
// BluetoothAdapter is present in the system.
if (!is_available) {
transport_availability_info_.available_transports.erase(
discovery->transport());
}
DCHECK(notify_observer_callback_);
notify_observer_callback_.Run();
}
}
void FidoRequestHandlerBase::AddAuthenticator(
std::unique_ptr<FidoAuthenticator> authenticator) {
DCHECK(authenticator &&
......@@ -258,4 +269,8 @@ void FidoRequestHandlerBase::InitializeAuthenticatorAndDispatchRequest(
weak_factory_.GetWeakPtr(), authenticator));
}
void FidoRequestHandlerBase::ConstructBleAdapterPowerManager() {
bluetooth_power_manager_ = std::make_unique<BleAdapterPowerManager>(this);
}
} // namespace device
......@@ -29,6 +29,7 @@ class Connector;
namespace device {
class BleAdapterPowerManager;
class FidoAuthenticator;
class FidoDevice;
class FidoTask;
......@@ -135,6 +136,9 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
// per-device tasks are cancelled.
// https://w3c.github.io/webauthn/#iface-pkcredential
void CancelOngoingTasks(base::StringPiece exclude_device_id = nullptr);
void OnBluetoothAdapterEnumerated(bool is_present, bool is_powered_on);
void OnBluetoothAdapterPowerChanged(bool is_powered_on);
void PowerOnBluetoothAdapter();
base::WeakPtr<FidoRequestHandlerBase> GetWeakPtr();
......@@ -178,8 +182,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
// FidoDiscovery::Observer
void DeviceAdded(FidoDiscovery* discovery, FidoDevice* device) final;
void DeviceRemoved(FidoDiscovery* discovery, FidoDevice* device) final;
void BluetoothAdapterPowerChanged(bool is_powered_on) final;
void DiscoveryAvailable(FidoDiscovery* discovery, bool is_available) final;
void AddAuthenticator(std::unique_ptr<FidoAuthenticator> authenticator);
void NotifyObserverTransportAvailability();
......@@ -189,12 +191,14 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
// to FidoDeviceAuthenticator instances in order to determine their protocol
// versions before a request can be dispatched.
void InitializeAuthenticatorAndDispatchRequest(FidoAuthenticator*);
void ConstructBleAdapterPowerManager();
AuthenticatorMap active_authenticators_;
std::vector<std::unique_ptr<FidoDiscovery>> discoveries_;
TransportAvailabilityObserver* observer_ = nullptr;
TransportAvailabilityInfo transport_availability_info_;
base::RepeatingClosure notify_observer_callback_;
std::unique_ptr<BleAdapterPowerManager> bluetooth_power_manager_;
base::WeakPtrFactory<FidoRequestHandlerBase> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FidoRequestHandlerBase);
......
......@@ -9,6 +9,8 @@
#include "base/bind.h"
#include "base/numerics/safe_conversions.h"
#include "base/test/scoped_task_environment.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/fido/fake_fido_discovery.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_device.h"
......@@ -199,6 +201,12 @@ std::vector<uint8_t> CreateFakeOperationDeniedError() {
class FidoRequestHandlerTest : public ::testing::Test {
public:
FidoRequestHandlerTest() {
mock_adapter_ =
base::MakeRefCounted<::testing::NiceMock<MockBluetoothAdapter>>();
BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter_);
}
void ForgeNextHidDiscovery() {
discovery_ = scoped_fake_discovery_factory_.ForgeNextHidDiscovery();
ble_discovery_ = scoped_fake_discovery_factory_.ForgeNextBleDiscovery();
......@@ -217,12 +225,16 @@ class FidoRequestHandlerTest : public ::testing::Test {
test::FakeFidoDiscovery* discovery() const { return discovery_; }
test::FakeFidoDiscovery* ble_discovery() const { return ble_discovery_; }
scoped_refptr<::testing::NiceMock<MockBluetoothAdapter>> adapter() {
return mock_adapter_;
}
FakeHandlerCallbackReceiver& callback() { return cb_; }
protected:
base::test::ScopedTaskEnvironment scoped_task_environment_{
base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME};
test::ScopedFakeFidoDiscoveryFactory scoped_fake_discovery_factory_;
scoped_refptr<::testing::NiceMock<MockBluetoothAdapter>> mock_adapter_;
test::FakeFidoDiscovery* discovery_;
test::FakeFidoDiscovery* ble_discovery_;
FakeHandlerCallbackReceiver cb_;
......@@ -537,40 +549,36 @@ TEST_F(FidoRequestHandlerTest, InternalTransportDisallowedIfMarkedUnavailable) {
observer.WaitForAndExpectAvailableTransportsAre({});
}
TEST_F(FidoRequestHandlerTest,
BleTransportAllowedIfDiscoveryStartsSuccessfully) {
TEST_F(FidoRequestHandlerTest, BleTransportAllowedIfBluetoothAdapterPresent) {
EXPECT_CALL(*adapter(), IsPresent()).WillOnce(::testing::Return(true));
TestTransportAvailabilityObserver observer;
auto request_handler = CreateFakeHandler();
request_handler->set_observer(&observer);
discovery()->WaitForCallToStartAndSimulateSuccess();
ble_discovery()->WaitForCallToStartAndSimulateSuccess();
observer.WaitForAndExpectAvailableTransportsAre(
{FidoTransportProtocol::kUsbHumanInterfaceDevice,
FidoTransportProtocol::kBluetoothLowEnergy});
}
TEST_F(FidoRequestHandlerTest, BleTransportDisallowedIfDiscoveryFails) {
TEST_F(FidoRequestHandlerTest,
BleTransportDisallowedBluetoothAdapterNotPresent) {
EXPECT_CALL(*adapter(), IsPresent()).WillOnce(::testing::Return(false));
TestTransportAvailabilityObserver observer;
auto request_handler = CreateFakeHandler();
request_handler->set_observer(&observer);
discovery()->WaitForCallToStartAndSimulateSuccess();
ble_discovery()->WaitForCallToStart();
ble_discovery()->SimulateDiscoveryAvailable(false /* is_available */);
observer.WaitForAndExpectAvailableTransportsAre(
{FidoTransportProtocol::kUsbHumanInterfaceDevice});
}
TEST_F(FidoRequestHandlerTest,
TransportAvailabilityNotificationOnObserverSetLate) {
EXPECT_CALL(*adapter(), IsPresent()).WillOnce(::testing::Return(true));
TestTransportAvailabilityObserver observer;
auto request_handler = CreateFakeHandler();
discovery()->WaitForCallToStartAndSimulateSuccess();
ble_discovery()->WaitForCallToStartAndSimulateSuccess();
scoped_task_environment_.FastForwardUntilNoTasksRemain();
request_handler->set_observer(&observer);
......
......@@ -10,6 +10,8 @@
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h"
#include "device/base/features.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/fido/authenticator_get_assertion_response.h"
#include "device/fido/ctap_get_assertion_request.h"
#include "device/fido/device_response_converter.h"
......@@ -39,6 +41,12 @@ using TestGetAssertionRequestCallback = test::StatusAndValuesCallbackReceiver<
class FidoGetAssertionHandlerTest : public ::testing::Test {
public:
FidoGetAssertionHandlerTest() {
mock_adapter_ =
base::MakeRefCounted<::testing::NiceMock<MockBluetoothAdapter>>();
BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter_);
}
void ForgeDiscoveries() {
discovery_ = scoped_fake_discovery_factory_.ForgeNextHidDiscovery();
ble_discovery_ = scoped_fake_discovery_factory_.ForgeNextBleDiscovery();
......@@ -164,6 +172,7 @@ class FidoGetAssertionHandlerTest : public ::testing::Test {
test::FakeFidoDiscovery* ble_discovery_;
test::FakeFidoDiscovery* cable_discovery_;
test::FakeFidoDiscovery* nfc_discovery_;
scoped_refptr<::testing::NiceMock<MockBluetoothAdapter>> mock_adapter_;
std::unique_ptr<MockFidoDevice> mock_platform_device_;
TestGetAssertionRequestCallback get_assertion_cb_;
base::flat_set<FidoTransportProtocol> supported_transports_ =
......@@ -338,6 +347,7 @@ TEST_F(FidoGetAssertionHandlerTest, IncorrectUserEntity) {
TEST_F(FidoGetAssertionHandlerTest,
AllTransportsAllowedIfAllowCredentialsListUndefined) {
auto request = CreateTestRequestWithCableExtension();
EXPECT_CALL(*mock_adapter_, IsPresent()).WillOnce(::testing::Return(true));
auto request_handler =
CreateGetAssertionHandlerWithRequest(std::move(request));
ExpectAllTransportsAreAllowedForRequest(request_handler.get());
......@@ -347,7 +357,7 @@ TEST_F(FidoGetAssertionHandlerTest,
AllTransportsAllowedIfAllowCredentialsListIsEmpty) {
auto request = CreateTestRequestWithCableExtension();
request.SetAllowList({});
EXPECT_CALL(*mock_adapter_, IsPresent()).WillOnce(::testing::Return(true));
auto request_handler =
CreateGetAssertionHandlerWithRequest(std::move(request));
ExpectAllTransportsAreAllowedForRequest(request_handler.get());
......@@ -365,6 +375,7 @@ TEST_F(FidoGetAssertionHandlerTest,
fido_parsing_utils::Materialize(kBogusCredentialId)},
});
EXPECT_CALL(*mock_adapter_, IsPresent()).WillOnce(::testing::Return(true));
auto request_handler =
CreateGetAssertionHandlerWithRequest(std::move(request));
ExpectAllTransportsAreAllowedForRequest(request_handler.get());
......@@ -384,6 +395,7 @@ TEST_F(FidoGetAssertionHandlerTest,
FidoTransportProtocol::kNearFieldCommunication}},
});
EXPECT_CALL(*mock_adapter_, IsPresent()).WillOnce(::testing::Return(true));
auto request_handler =
CreateGetAssertionHandlerWithRequest(std::move(request));
ExpectAllowedTransportsForRequestAre(
......@@ -397,7 +409,7 @@ TEST_F(FidoGetAssertionHandlerTest,
CtapGetAssertionRequest request(test_data::kRelyingPartyId,
test_data::kClientDataHash);
ASSERT_FALSE(!!request.cable_extension());
EXPECT_CALL(*mock_adapter_, IsPresent()).WillOnce(::testing::Return(true));
auto request_handler =
CreateGetAssertionHandlerWithRequest(std::move(request));
ExpectAllowedTransportsForRequestAre(
......@@ -433,7 +445,7 @@ TEST_F(FidoGetAssertionHandlerTest, SupportedTransportsAreOnlyBleAndNfc) {
};
set_supported_transports(kBleAndNfc);
EXPECT_CALL(*mock_adapter_, IsPresent()).WillOnce(::testing::Return(true));
auto request_handler = CreateGetAssertionHandlerWithRequest(
CreateTestRequestWithCableExtension());
ExpectAllowedTransportsForRequestAre(request_handler.get(), kBleAndNfc);
......@@ -446,6 +458,7 @@ TEST_F(FidoGetAssertionHandlerTest,
FidoTransportProtocol::kInternal,
};
EXPECT_CALL(*mock_adapter_, IsPresent()).WillOnce(::testing::Return(true));
set_supported_transports(kCableAndInternal);
auto request_handler = CreateGetAssertionHandlerWithRequest(
CreateTestRequestWithCableExtension());
......@@ -495,7 +508,7 @@ TEST_F(FidoGetAssertionHandlerTest, SuccessWithOnlyBleTransportAllowed) {
});
set_supported_transports({FidoTransportProtocol::kBluetoothLowEnergy});
EXPECT_CALL(*mock_adapter_, IsPresent()).WillOnce(::testing::Return(true));
auto request_handler =
CreateGetAssertionHandlerWithRequest(std::move(request));
......
......@@ -55,7 +55,6 @@ void FidoHidDiscovery::DeviceRemoved(
void FidoHidDiscovery::OnGetDevices(
std::vector<device::mojom::HidDeviceInfoPtr> device_infos) {
NotifyDiscoveryAvailable(true);
for (auto& device_info : device_infos)
DeviceAdded(std::move(device_info));
......
......@@ -85,7 +85,6 @@ TEST_F(FidoHidDiscoveryTest, TestAddRemoveDevice) {
fake_hid_manager_->AddDevice(MakeFidoHidDevice("known"));
EXPECT_CALL(observer, DiscoveryAvailable(&discovery, true));
EXPECT_CALL(observer, DiscoveryStarted(&discovery, true));
discovery.set_observer(&observer);
discovery.Start();
......
......@@ -10,6 +10,8 @@
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h"
#include "device/base/features.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/fido/authenticator_make_credential_response.h"
#include "device/fido/authenticator_selection_criteria.h"
#include "device/fido/ctap_make_credential_request.h"
......@@ -43,6 +45,12 @@ using TestMakeCredentialRequestCallback = test::StatusAndValuesCallbackReceiver<
class FidoMakeCredentialHandlerTest : public ::testing::Test {
public:
FidoMakeCredentialHandlerTest() {
mock_adapter_ =
base::MakeRefCounted<::testing::NiceMock<MockBluetoothAdapter>>();
BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter_);
}
void ForgeDiscoveries() {
discovery_ = scoped_fake_discovery_factory_.ForgeNextHidDiscovery();
ble_discovery_ = scoped_fake_discovery_factory_.ForgeNextBleDiscovery();
......@@ -136,6 +144,7 @@ class FidoMakeCredentialHandlerTest : public ::testing::Test {
test::FakeFidoDiscovery* discovery_;
test::FakeFidoDiscovery* ble_discovery_;
test::FakeFidoDiscovery* nfc_discovery_;
scoped_refptr<::testing::NiceMock<MockBluetoothAdapter>> mock_adapter_;
std::unique_ptr<MockFidoDevice> mock_platform_device_;
TestMakeCredentialRequestCallback cb_;
base::flat_set<FidoTransportProtocol> supported_transports_ =
......@@ -257,7 +266,7 @@ TEST_F(FidoMakeCredentialHandlerTest, AnyAttachment) {
ReadCTAPGetInfoResponse(test_data::kTestGetInfoResponsePlatformDevice));
platform_device->SetDeviceTransport(FidoTransportProtocol::kInternal);
set_mock_platform_device(std::move(platform_device));
EXPECT_CALL(*mock_adapter_, IsPresent()).WillOnce(::testing::Return(true));
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
......@@ -280,6 +289,7 @@ TEST_F(FidoMakeCredentialHandlerTest, AnyAttachment) {
}
TEST_F(FidoMakeCredentialHandlerTest, CrossPlatformAttachment) {
EXPECT_CALL(*mock_adapter_, IsPresent()).WillOnce(::testing::Return(true));
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
......@@ -448,6 +458,7 @@ TEST_F(FidoMakeCredentialHandlerTest, SupportedTransportsAreOnlyBleAndNfc) {
};
set_supported_transports(kBleAndNfc);
EXPECT_CALL(*mock_adapter_, IsPresent()).WillOnce(::testing::Return(true));
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
......
......@@ -19,7 +19,6 @@ class MockFidoDiscoveryObserver : public FidoDiscovery::Observer {
MockFidoDiscoveryObserver();
~MockFidoDiscoveryObserver() override;
MOCK_METHOD2(DiscoveryAvailable, void(FidoDiscovery*, bool));
MOCK_METHOD2(DiscoveryStarted, void(FidoDiscovery*, bool));
MOCK_METHOD2(DiscoveryStopped, void(FidoDiscovery*, bool));
MOCK_METHOD2(DeviceAdded, void(FidoDiscovery*, FidoDevice*));
......
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