summaryrefslogtreecommitdiff
path: root/chromium/device
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-01-23 17:21:03 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-01-23 16:25:15 +0000
commitc551f43206405019121bd2b2c93714319a0a3300 (patch)
tree1f48c30631c421fd4bbb3c36da20183c8a2ed7d7 /chromium/device
parent7961cea6d1041e3e454dae6a1da660b453efd238 (diff)
downloadqtwebengine-chromium-c551f43206405019121bd2b2c93714319a0a3300.tar.gz
BASELINE: Update Chromium to 79.0.3945.139
Change-Id: I336b7182fab9bca80b709682489c07db112eaca5 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/device')
-rw-r--r--chromium/device/BUILD.gn5
-rw-r--r--chromium/device/base/features.cc3
-rw-r--r--chromium/device/bluetooth/BUILD.gn2
-rw-r--r--chromium/device/bluetooth/adapter.cc29
-rw-r--r--chromium/device/bluetooth/adapter.h6
-rw-r--r--chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothAdapter.java46
-rw-r--r--chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java36
-rw-r--r--chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java57
-rw-r--r--chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattDescriptor.java27
-rw-r--r--chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattService.java23
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter.cc28
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter.h6
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_android.cc4
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_android.h1
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_factory.h2
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_mac.h1
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_mac.mm4
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_mac_unittest.mm4
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_unittest.cc192
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_win.cc4
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_win.h1
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_winrt.cc4
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_winrt.h1
-rw-r--r--chromium/device/bluetooth/bluetooth_discovery_filter.cc67
-rw-r--r--chromium/device/bluetooth/bluetooth_discovery_filter.h51
-rw-r--r--chromium/device/bluetooth/bluetooth_discovery_filter_unittest.cc121
-rw-r--r--chromium/device/bluetooth/bluetooth_task_manager_win.cc6
-rw-r--r--chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc4
-rw-r--r--chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.h3
-rw-r--r--chromium/device/bluetooth/bluez/bluetooth_advertisement_bluez_unittest.cc5
-rw-r--r--chromium/device/bluetooth/bluez/bluetooth_bluez_unittest.cc125
-rw-r--r--chromium/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc29
-rw-r--r--chromium/device/bluetooth/cast/bluetooth_adapter_cast.cc10
-rw-r--r--chromium/device/bluetooth/cast/bluetooth_adapter_cast.h7
-rw-r--r--chromium/device/bluetooth/chromeos/bluetooth_utils.cc8
-rw-r--r--chromium/device/bluetooth/chromeos/bluetooth_utils_unittest.cc11
-rw-r--r--chromium/device/bluetooth/dbus/bluez_dbus_manager.cc11
-rw-r--r--chromium/device/bluetooth/device.cc12
-rw-r--r--chromium/device/bluetooth/device.h6
-rw-r--r--chromium/device/bluetooth/device_unittest.cc9
-rw-r--r--chromium/device/bluetooth/public/mojom/adapter.mojom7
-rw-r--r--chromium/device/bluetooth/public/mojom/test/fake_bluetooth.mojom3
-rw-r--r--chromium/device/fido/BUILD.gn9
-rw-r--r--chromium/device/fido/bio/enrollment_handler.cc254
-rw-r--r--chromium/device/fido/bio/enrollment_handler.h64
-rw-r--r--chromium/device/fido/bio/enrollment_handler_unittest.cc175
-rw-r--r--chromium/device/fido/ble/fido_ble_connection.cc2
-rw-r--r--chromium/device/fido/ble/fido_ble_discovery.cc8
-rw-r--r--chromium/device/fido/ble/fido_ble_discovery_base.cc23
-rw-r--r--chromium/device/fido/ble/fido_ble_discovery_unittest.cc61
-rw-r--r--chromium/device/fido/ble_adapter_manager_unittest.cc29
-rw-r--r--chromium/device/fido/cable/cable_discovery_data.h69
-rw-r--r--chromium/device/fido/cable/fido_cable_device.cc158
-rw-r--r--chromium/device/fido/cable/fido_cable_device.h24
-rw-r--r--chromium/device/fido/cable/fido_cable_device_unittest.cc2
-rw-r--r--chromium/device/fido/cable/fido_cable_discovery.cc473
-rw-r--r--chromium/device/fido/cable/fido_cable_discovery.h72
-rw-r--r--chromium/device/fido/cable/fido_cable_discovery_unittest.cc122
-rw-r--r--chromium/device/fido/cable/fido_cable_handshake_handler.cc168
-rw-r--r--chromium/device/fido/cable/fido_cable_handshake_handler.h17
-rw-r--r--chromium/device/fido/cable/fido_cable_handshake_handler_v2_fuzzer.cc31
-rw-r--r--chromium/device/fido/credential_management_handler_unittest.cc10
-rw-r--r--chromium/device/fido/fake_fido_discovery_unittest.cc20
-rw-r--r--chromium/device/fido/features.cc3
-rw-r--r--chromium/device/fido/features.h4
-rw-r--r--chromium/device/fido/fido_authenticator.cc7
-rw-r--r--chromium/device/fido/fido_authenticator.h9
-rw-r--r--chromium/device/fido/fido_constants.cc2
-rw-r--r--chromium/device/fido/fido_device_authenticator.cc66
-rw-r--r--chromium/device/fido/fido_device_authenticator.h9
-rw-r--r--chromium/device/fido/fido_device_discovery.cc11
-rw-r--r--chromium/device/fido/fido_device_discovery_unittest.cc20
-rw-r--r--chromium/device/fido/fido_discovery_base.h17
-rw-r--r--chromium/device/fido/fido_discovery_factory.cc55
-rw-r--r--chromium/device/fido/fido_discovery_factory.h50
-rw-r--r--chromium/device/fido/fido_request_handler_base.cc89
-rw-r--r--chromium/device/fido/fido_request_handler_base.h12
-rw-r--r--chromium/device/fido/fido_request_handler_unittest.cc27
-rw-r--r--chromium/device/fido/fido_test_data.h63
-rw-r--r--chromium/device/fido/get_assertion_handler_unittest.cc21
-rw-r--r--chromium/device/fido/get_assertion_request_handler.cc24
-rw-r--r--chromium/device/fido/get_assertion_request_handler.h6
-rw-r--r--chromium/device/fido/hid/fake_hid_impl_for_testing.cc31
-rw-r--r--chromium/device/fido/hid/fake_hid_impl_for_testing.h33
-rw-r--r--chromium/device/fido/hid/fido_hid_device.cc5
-rw-r--r--chromium/device/fido/hid/fido_hid_device.h6
-rw-r--r--chromium/device/fido/hid/fido_hid_device_unittest.cc31
-rw-r--r--chromium/device/fido/hid/fido_hid_discovery.cc15
-rw-r--r--chromium/device/fido/hid/fido_hid_discovery.h7
-rw-r--r--chromium/device/fido/hid/fido_hid_discovery_unittest.cc12
-rw-r--r--chromium/device/fido/mac/discovery.cc14
-rw-r--r--chromium/device/fido/make_credential_handler_unittest.cc17
-rw-r--r--chromium/device/fido/make_credential_request_handler.cc43
-rw-r--r--chromium/device/fido/make_credential_request_handler.h4
-rw-r--r--chromium/device/fido/mock_fido_discovery_observer.h4
-rw-r--r--chromium/device/fido/u2f_command_constructor.cc4
-rw-r--r--chromium/device/fido/u2f_command_constructor.h5
-rw-r--r--chromium/device/fido/u2f_register_operation.cc6
-rw-r--r--chromium/device/fido/u2f_register_operation_unittest.cc29
-rw-r--r--chromium/device/fido/virtual_ctap2_device.cc17
-rw-r--r--chromium/device/fido/virtual_ctap2_device.h4
-rw-r--r--chromium/device/fido/virtual_fido_device_factory.cc3
-rw-r--r--chromium/device/fido/virtual_fido_device_factory.h2
-rw-r--r--chromium/device/fido/win/authenticator.cc17
-rw-r--r--chromium/device/fido/win/authenticator.h9
-rw-r--r--chromium/device/fido/win/discovery.cc21
-rw-r--r--chromium/device/fido/win/discovery.h5
-rw-r--r--chromium/device/fido/win/fake_webauthn_api.cc98
-rw-r--r--chromium/device/fido/win/fake_webauthn_api.h30
-rw-r--r--chromium/device/fido/win/webauthn_api.cc18
-rw-r--r--chromium/device/fido/win/webauthn_api.h5
-rw-r--r--chromium/device/gamepad/BUILD.gn4
-rw-r--r--chromium/device/gamepad/android/java/src/org/chromium/device/gamepad/GamepadList.java20
-rw-r--r--chromium/device/gamepad/android/junit/src/org/chromium/device/gamepad/GamepadMappingsTest.java26
-rw-r--r--chromium/device/gamepad/gamepad_data_fetcher.cc11
-rw-r--r--chromium/device/gamepad/gamepad_data_fetcher.h33
-rw-r--r--chromium/device/gamepad/gamepad_haptics_manager.cc8
-rw-r--r--chromium/device/gamepad/gamepad_haptics_manager.h3
-rw-r--r--chromium/device/gamepad/gamepad_monitor.cc12
-rw-r--r--chromium/device/gamepad/gamepad_monitor.h10
-rw-r--r--chromium/device/gamepad/gamepad_pad_state_provider.cc21
-rw-r--r--chromium/device/gamepad/gamepad_pad_state_provider.h31
-rw-r--r--chromium/device/gamepad/gamepad_platform_data_fetcher_linux.cc18
-rw-r--r--chromium/device/gamepad/gamepad_platform_data_fetcher_linux.h2
-rw-r--r--chromium/device/gamepad/gamepad_platform_data_fetcher_mac.h20
-rw-r--r--chromium/device/gamepad/gamepad_platform_data_fetcher_mac.mm127
-rw-r--r--chromium/device/gamepad/gamepad_platform_data_fetcher_win.cc2
-rw-r--r--chromium/device/gamepad/gamepad_provider.cc43
-rw-r--r--chromium/device/gamepad/gamepad_provider.h37
-rw-r--r--chromium/device/gamepad/gamepad_provider_unittest.cc11
-rw-r--r--chromium/device/gamepad/gamepad_service.cc45
-rw-r--r--chromium/device/gamepad/gamepad_service.h36
-rw-r--r--chromium/device/gamepad/gamepad_service_unittest.cc19
-rw-r--r--chromium/device/gamepad/gamepad_test_helpers.h2
-rw-r--r--chromium/device/gamepad/nintendo_controller.cc15
-rw-r--r--chromium/device/gamepad/nintendo_controller.h6
-rw-r--r--chromium/device/gamepad/nintendo_data_fetcher.cc15
-rw-r--r--chromium/device/gamepad/nintendo_data_fetcher.h7
-rw-r--r--chromium/device/gamepad/nintendo_data_fetcher_unittest.cc18
-rw-r--r--chromium/device/gamepad/public/cpp/gamepad_mojom_traits_unittest.cc2
-rw-r--r--chromium/device/gamepad/raw_input_data_fetcher_win.cc17
-rw-r--r--chromium/device/gamepad/raw_input_data_fetcher_win.h2
-rw-r--r--chromium/device/gamepad/xinput_haptic_gamepad_win.cc2
-rw-r--r--chromium/device/vr/BUILD.gn6
-rw-r--r--chromium/device/vr/android/gvr/gvr_delegate.cc16
-rw-r--r--chromium/device/vr/android/gvr/gvr_device.cc33
-rw-r--r--chromium/device/vr/android/gvr/gvr_device.h4
-rw-r--r--chromium/device/vr/android/gvr/gvr_device_provider.cc5
-rw-r--r--chromium/device/vr/android/gvr/gvr_device_provider.h4
-rw-r--r--chromium/device/vr/android/java/src/org/chromium/device/vr/NonPresentingGvrContext.java11
-rw-r--r--chromium/device/vr/buildflags/buildflags.gni9
-rw-r--r--chromium/device/vr/isolated_gamepad_data_fetcher.cc20
-rw-r--r--chromium/device/vr/isolated_gamepad_data_fetcher.h18
-rw-r--r--chromium/device/vr/oculus/oculus_device.cc72
-rw-r--r--chromium/device/vr/oculus/oculus_device.h27
-rw-r--r--chromium/device/vr/oculus/oculus_render_loop.cc6
-rw-r--r--chromium/device/vr/openvr/openvr_device.cc71
-rw-r--r--chromium/device/vr/openvr/openvr_device.h27
-rw-r--r--chromium/device/vr/openvr/openvr_gamepad_helper.cc12
-rw-r--r--chromium/device/vr/openvr/openvr_render_loop.cc7
-rw-r--r--chromium/device/vr/openxr/openxr_api_wrapper.cc172
-rw-r--r--chromium/device/vr/openxr/openxr_api_wrapper.h15
-rw-r--r--chromium/device/vr/openxr/openxr_controller.cc258
-rw-r--r--chromium/device/vr/openxr/openxr_controller.h64
-rw-r--r--chromium/device/vr/openxr/openxr_device.cc73
-rw-r--r--chromium/device/vr/openxr/openxr_device.h26
-rw-r--r--chromium/device/vr/openxr/openxr_gamepad_helper.cc107
-rw-r--r--chromium/device/vr/openxr/openxr_gamepad_helper.h43
-rw-r--r--chromium/device/vr/openxr/openxr_input_helper.cc235
-rw-r--r--chromium/device/vr/openxr/openxr_input_helper.h58
-rw-r--r--chromium/device/vr/openxr/openxr_render_loop.cc69
-rw-r--r--chromium/device/vr/openxr/openxr_render_loop.h7
-rw-r--r--chromium/device/vr/orientation/orientation_device.cc42
-rw-r--r--chromium/device/vr/orientation/orientation_device.h9
-rw-r--r--chromium/device/vr/orientation/orientation_device_provider.cc13
-rw-r--r--chromium/device/vr/orientation/orientation_device_provider.h12
-rw-r--r--chromium/device/vr/orientation/orientation_device_provider_unittest.cc27
-rw-r--r--chromium/device/vr/orientation/orientation_device_unittest.cc37
-rw-r--r--chromium/device/vr/orientation/orientation_session.cc28
-rw-r--r--chromium/device/vr/orientation/orientation_session.h22
-rw-r--r--chromium/device/vr/public/mojom/browser_test_interfaces.mojom2
-rw-r--r--chromium/device/vr/public/mojom/isolated_xr_service.mojom28
-rw-r--r--chromium/device/vr/public/mojom/vr_service.mojom152
-rw-r--r--chromium/device/vr/vr_device_base.cc17
-rw-r--r--chromium/device/vr/vr_device_base.h14
-rw-r--r--chromium/device/vr/vr_device_base_unittest.cc31
-rw-r--r--chromium/device/vr/vr_device_provider.h4
-rw-r--r--chromium/device/vr/windows/compositor_base.cc100
-rw-r--r--chromium/device/vr/windows/compositor_base.h42
-rw-r--r--chromium/device/vr/windows_mixed_reality/mixed_reality_device.cc62
-rw-r--r--chromium/device/vr/windows_mixed_reality/mixed_reality_device.h27
-rw-r--r--chromium/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc18
-rw-r--r--chromium/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc79
-rw-r--r--chromium/device/vr/windows_mixed_reality/mixed_reality_renderloop.h6
-rw-r--r--chromium/device/vr/windows_mixed_reality/mixed_reality_statics.cc11
-rw-r--r--chromium/device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.cc65
-rw-r--r--chromium/device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.h23
-rw-r--r--chromium/device/vr/windows_mixed_reality/wrappers/wmr_input_location.cc11
-rw-r--r--chromium/device/vr/windows_mixed_reality/wrappers/wmr_input_location.h7
199 files changed, 4353 insertions, 2398 deletions
diff --git a/chromium/device/BUILD.gn b/chromium/device/BUILD.gn
index 8bf7a9d5186..3ddcd149be7 100644
--- a/chromium/device/BUILD.gn
+++ b/chromium/device/BUILD.gn
@@ -366,6 +366,7 @@ if (is_android) {
]
generate_jni("bluetooth_test_jni_headers") {
+ testonly = true
sources = bluetooth_java_sources_needing_jni
}
@@ -376,7 +377,7 @@ if (is_android) {
"//base:base_java",
"//components/location/android:location_java",
"//device/bluetooth:java",
- "//third_party/android_deps:com_android_support_support_annotations_java",
+ "//third_party/android_deps:androidx_annotation_annotation_java",
"//third_party/android_sdk:android_test_mock_java",
]
@@ -394,7 +395,7 @@ if (is_android) {
"//base:base_junit_test_support",
"//device/gamepad:java",
"//mojo/public/java:bindings_java",
- "//third_party/android_deps:com_android_support_support_annotations_java",
+ "//third_party/android_deps:androidx_annotation_annotation_java",
]
srcjar_deps = [ "//device/gamepad:java_enums_srcjar" ]
}
diff --git a/chromium/device/base/features.cc b/chromium/device/base/features.cc
index 1357a223a50..b50ee54a6ef 100644
--- a/chromium/device/base/features.cc
+++ b/chromium/device/base/features.cc
@@ -17,7 +17,8 @@ const base::Feature kNewBLEWinImplementation{"NewBLEWinImplementation",
#if defined(OS_CHROMEOS)
// Enables or disables the use of Bluetooth dispatcher daemon on Chrome OS.
-const base::Feature kNewblueDaemon{"Newblue", base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kNewblueDaemon{"Newblue",
+ base::FEATURE_DISABLED_BY_DEFAULT};
#endif // defined(OS_CHROMEOS)
#if BUILDFLAG(ENABLE_VR)
diff --git a/chromium/device/bluetooth/BUILD.gn b/chromium/device/bluetooth/BUILD.gn
index 5dfd6535122..7dcfcd0ab28 100644
--- a/chromium/device/bluetooth/BUILD.gn
+++ b/chromium/device/bluetooth/BUILD.gn
@@ -522,7 +522,9 @@ if (is_android) {
java_files = java_sources_needing_jni
deps = [
"//base:base_java",
+ "//base:jni_java",
"//components/location/android:location_java",
]
+ annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
}
}
diff --git a/chromium/device/bluetooth/adapter.cc b/chromium/device/bluetooth/adapter.cc
index dd2091cf5e3..5393ecc12e3 100644
--- a/chromium/device/bluetooth/adapter.cc
+++ b/chromium/device/bluetooth/adapter.cc
@@ -12,12 +12,13 @@
#include "device/bluetooth/device.h"
#include "device/bluetooth/discovery_session.h"
#include "device/bluetooth/public/mojom/connect_result_type_converter.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
namespace bluetooth {
Adapter::Adapter(scoped_refptr<device::BluetoothAdapter> adapter)
- : adapter_(std::move(adapter)), client_(nullptr) {
+ : adapter_(std::move(adapter)) {
adapter_->AddObserver(this);
}
@@ -32,7 +33,7 @@ void Adapter::ConnectToDevice(const std::string& address,
if (!device) {
std::move(callback).Run(mojom::ConnectResult::DEVICE_NO_LONGER_IN_RANGE,
- nullptr /* device */);
+ /* device */ mojo::NullRemote());
return;
}
@@ -68,8 +69,8 @@ void Adapter::GetInfo(GetInfoCallback callback) {
std::move(callback).Run(std::move(adapter_info));
}
-void Adapter::SetClient(mojom::AdapterClientPtr client) {
- client_ = std::move(client);
+void Adapter::SetClient(mojo::PendingRemote<mojom::AdapterClient> client) {
+ client_.Bind(std::move(client));
}
void Adapter::StartDiscoverySession(StartDiscoverySessionCallback callback) {
@@ -132,31 +133,31 @@ void Adapter::DeviceRemoved(device::BluetoothAdapter* adapter,
void Adapter::OnGattConnected(
ConnectToDeviceCallback callback,
std::unique_ptr<device::BluetoothGattConnection> connection) {
- mojom::DevicePtr device_ptr;
+ mojo::PendingRemote<mojom::Device> device;
Device::Create(adapter_, std::move(connection),
- mojo::MakeRequest(&device_ptr));
- std::move(callback).Run(mojom::ConnectResult::SUCCESS, std::move(device_ptr));
+ device.InitWithNewPipeAndPassReceiver());
+ std::move(callback).Run(mojom::ConnectResult::SUCCESS, std::move(device));
}
void Adapter::OnConnectError(
ConnectToDeviceCallback callback,
device::BluetoothDevice::ConnectErrorCode error_code) {
std::move(callback).Run(mojo::ConvertTo<mojom::ConnectResult>(error_code),
- nullptr /* Device */);
+ /* device */ mojo::NullRemote());
}
void Adapter::OnStartDiscoverySession(
StartDiscoverySessionCallback callback,
std::unique_ptr<device::BluetoothDiscoverySession> session) {
- mojom::DiscoverySessionPtr session_ptr;
- mojo::MakeStrongBinding(
+ mojo::PendingRemote<mojom::DiscoverySession> pending_session;
+ mojo::MakeSelfOwnedReceiver(
std::make_unique<DiscoverySession>(std::move(session)),
- mojo::MakeRequest(&session_ptr));
- std::move(callback).Run(std::move(session_ptr));
+ pending_session.InitWithNewPipeAndPassReceiver());
+ std::move(callback).Run(std::move(pending_session));
}
void Adapter::OnDiscoverySessionError(StartDiscoverySessionCallback callback) {
- std::move(callback).Run(nullptr /* session */);
+ std::move(callback).Run(mojo::NullRemote() /* session */);
}
} // namespace bluetooth
diff --git a/chromium/device/bluetooth/adapter.h b/chromium/device/bluetooth/adapter.h
index 743707ee591..d885cdae99b 100644
--- a/chromium/device/bluetooth/adapter.h
+++ b/chromium/device/bluetooth/adapter.h
@@ -14,6 +14,8 @@
#include "device/bluetooth/bluetooth_gatt_connection.h"
#include "device/bluetooth/public/mojom/adapter.mojom.h"
#include "device/bluetooth/public/mojom/device.mojom.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
namespace bluetooth {
@@ -32,7 +34,7 @@ class Adapter : public mojom::Adapter,
ConnectToDeviceCallback callback) override;
void GetDevices(GetDevicesCallback callback) override;
void GetInfo(GetInfoCallback callback) override;
- void SetClient(mojom::AdapterClientPtr client) override;
+ void SetClient(mojo::PendingRemote<mojom::AdapterClient> client) override;
void StartDiscoverySession(StartDiscoverySessionCallback callback) override;
// device::BluetoothAdapter::Observer overrides:
@@ -69,7 +71,7 @@ class Adapter : public mojom::Adapter,
scoped_refptr<device::BluetoothAdapter> adapter_;
// The adapter client that listens to this service.
- mojom::AdapterClientPtr client_;
+ mojo::Remote<mojom::AdapterClient> client_;
base::WeakPtrFactory<Adapter> weak_ptr_factory_{this};
diff --git a/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothAdapter.java b/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothAdapter.java
index b6067bfb59b..d1068444ed8 100644
--- a/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothAdapter.java
+++ b/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothAdapter.java
@@ -19,6 +19,7 @@ import org.chromium.base.Log;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNIAdditionalImport;
import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeMethods;
import org.chromium.components.location.LocationUtils;
import java.util.List;
@@ -288,7 +289,8 @@ final class ChromeBluetoothAdapter extends BroadcastReceiver {
// Object can be destroyed, but Android keeps calling onScanResult.
if (mNativeBluetoothAdapterAndroid != 0) {
- nativeCreateOrUpdateDeviceOnScan(mNativeBluetoothAdapterAndroid,
+ ChromeBluetoothAdapterJni.get().createOrUpdateDeviceOnScan(
+ mNativeBluetoothAdapterAndroid, ChromeBluetoothAdapter.this,
result.getDevice().getAddress(), result.getDevice(),
result.getScanRecord_getDeviceName(), result.getRssi(), uuid_strings,
result.getScanRecord_getTxPowerLevel(), serviceDataKeys, serviceDataValues,
@@ -299,7 +301,8 @@ final class ChromeBluetoothAdapter extends BroadcastReceiver {
@Override
public void onScanFailed(int errorCode) {
Log.w(TAG, "onScanFailed: %d", errorCode);
- nativeOnScanFailed(mNativeBluetoothAdapterAndroid);
+ ChromeBluetoothAdapterJni.get().onScanFailed(
+ mNativeBluetoothAdapterAndroid, ChromeBluetoothAdapter.this);
}
}
@@ -315,10 +318,12 @@ final class ChromeBluetoothAdapter extends BroadcastReceiver {
switch (state) {
case BluetoothAdapter.STATE_ON:
- nativeOnAdapterStateChanged(mNativeBluetoothAdapterAndroid, true);
+ ChromeBluetoothAdapterJni.get().onAdapterStateChanged(
+ mNativeBluetoothAdapterAndroid, ChromeBluetoothAdapter.this, true);
break;
case BluetoothAdapter.STATE_OFF:
- nativeOnAdapterStateChanged(mNativeBluetoothAdapterAndroid, false);
+ ChromeBluetoothAdapterJni.get().onAdapterStateChanged(
+ mNativeBluetoothAdapterAndroid, ChromeBluetoothAdapter.this, false);
break;
default:
// do nothing
@@ -342,20 +347,21 @@ final class ChromeBluetoothAdapter extends BroadcastReceiver {
}
}
- // ---------------------------------------------------------------------------------------------
- // BluetoothAdapterAndroid C++ methods declared for access from java:
-
- // Binds to BluetoothAdapterAndroid::OnScanFailed.
- private native void nativeOnScanFailed(long nativeBluetoothAdapterAndroid);
-
- // Binds to BluetoothAdapterAndroid::CreateOrUpdateDeviceOnScan.
- private native void nativeCreateOrUpdateDeviceOnScan(long nativeBluetoothAdapterAndroid,
- String address, Wrappers.BluetoothDeviceWrapper deviceWrapper, String localName,
- int rssi, String[] advertisedUuids, int txPower, String[] serviceDataKeys,
- Object[] serviceDataValues, int[] manufacturerDataKeys,
- Object[] manufacturerDataValues);
-
- // Binds to BluetoothAdapterAndroid::nativeOnAdapterStateChanged
- private native void nativeOnAdapterStateChanged(
- long nativeBluetoothAdapterAndroid, boolean powered);
+ @NativeMethods
+ interface Natives {
+ // Binds to BluetoothAdapterAndroid::OnScanFailed.
+ void onScanFailed(long nativeBluetoothAdapterAndroid, ChromeBluetoothAdapter caller);
+
+ // Binds to BluetoothAdapterAndroid::CreateOrUpdateDeviceOnScan.
+ void createOrUpdateDeviceOnScan(long nativeBluetoothAdapterAndroid,
+ ChromeBluetoothAdapter caller, String address,
+ Wrappers.BluetoothDeviceWrapper deviceWrapper, String localName, int rssi,
+ String[] advertisedUuids, int txPower, String[] serviceDataKeys,
+ Object[] serviceDataValues, int[] manufacturerDataKeys,
+ Object[] manufacturerDataValues);
+
+ // Binds to BluetoothAdapterAndroid::nativeOnAdapterStateChanged
+ void onAdapterStateChanged(
+ long nativeBluetoothAdapterAndroid, ChromeBluetoothAdapter caller, boolean powered);
+ }
}
diff --git a/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java b/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
index da726ec8d0e..e134b66cf13 100644
--- a/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
+++ b/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
@@ -13,6 +13,7 @@ import org.chromium.base.Log;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNIAdditionalImport;
import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeMethods;
import org.chromium.base.metrics.RecordHistogram;
import java.util.HashMap;
@@ -149,7 +150,8 @@ final class ChromeBluetoothDevice {
status);
}
if (mNativeBluetoothDeviceAndroid != 0) {
- nativeOnConnectionStateChange(mNativeBluetoothDeviceAndroid, status,
+ ChromeBluetoothDeviceJni.get().onConnectionStateChange(
+ mNativeBluetoothDeviceAndroid, ChromeBluetoothDevice.this, status,
newState == android.bluetooth.BluetoothProfile.STATE_CONNECTED);
}
}
@@ -185,10 +187,12 @@ final class ChromeBluetoothDevice {
// between service instances with the same UUID on this device.
String serviceInstanceId = getAddress() + "/"
+ service.getUuid().toString() + "," + service.getInstanceId();
- nativeCreateGattRemoteService(
- mNativeBluetoothDeviceAndroid, serviceInstanceId, service);
+ ChromeBluetoothDeviceJni.get().createGattRemoteService(
+ mNativeBluetoothDeviceAndroid, ChromeBluetoothDevice.this,
+ serviceInstanceId, service);
}
- nativeOnGattServicesDiscovered(mNativeBluetoothDeviceAndroid);
+ ChromeBluetoothDeviceJni.get().onGattServicesDiscovered(
+ mNativeBluetoothDeviceAndroid, ChromeBluetoothDevice.this);
}
}
});
@@ -304,17 +308,19 @@ final class ChromeBluetoothDevice {
}
}
- // ---------------------------------------------------------------------------------------------
- // BluetoothAdapterDevice C++ methods declared for access from java:
-
- // Binds to BluetoothDeviceAndroid::OnConnectionStateChange.
- private native void nativeOnConnectionStateChange(
- long nativeBluetoothDeviceAndroid, int status, boolean connected);
+ @NativeMethods
+ interface Natives {
+ // Binds to BluetoothDeviceAndroid::OnConnectionStateChange.
+ void onConnectionStateChange(long nativeBluetoothDeviceAndroid,
+ ChromeBluetoothDevice caller, int status, boolean connected);
- // Binds to BluetoothDeviceAndroid::CreateGattRemoteService.
- private native void nativeCreateGattRemoteService(long nativeBluetoothDeviceAndroid,
- String instanceId, Wrappers.BluetoothGattServiceWrapper serviceWrapper);
+ // Binds to BluetoothDeviceAndroid::CreateGattRemoteService.
+ void createGattRemoteService(long nativeBluetoothDeviceAndroid,
+ ChromeBluetoothDevice caller, String instanceId,
+ Wrappers.BluetoothGattServiceWrapper serviceWrapper);
- // Binds to BluetoothDeviceAndroid::GattServicesDiscovered.
- private native void nativeOnGattServicesDiscovered(long nativeBluetoothDeviceAndroid);
+ // Binds to BluetoothDeviceAndroid::GattServicesDiscovered.
+ void onGattServicesDiscovered(
+ long nativeBluetoothDeviceAndroid, ChromeBluetoothDevice caller);
+ }
}
diff --git a/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java b/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java
index 06b63aaac15..41344a1b708 100644
--- a/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java
+++ b/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattCharacteristic.java
@@ -11,6 +11,7 @@ import org.chromium.base.Log;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNIAdditionalImport;
import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeMethods;
import java.util.List;
@@ -63,7 +64,9 @@ final class ChromeBluetoothRemoteGattCharacteristic {
void onCharacteristicChanged(byte[] value) {
Log.i(TAG, "onCharacteristicChanged");
if (mNativeBluetoothRemoteGattCharacteristicAndroid != 0) {
- nativeOnChanged(mNativeBluetoothRemoteGattCharacteristicAndroid, value);
+ ChromeBluetoothRemoteGattCharacteristicJni.get().onChanged(
+ mNativeBluetoothRemoteGattCharacteristicAndroid,
+ ChromeBluetoothRemoteGattCharacteristic.this, value);
}
}
@@ -71,7 +74,9 @@ final class ChromeBluetoothRemoteGattCharacteristic {
Log.i(TAG, "onCharacteristicRead status:%d==%s", status,
status == android.bluetooth.BluetoothGatt.GATT_SUCCESS ? "OK" : "Error");
if (mNativeBluetoothRemoteGattCharacteristicAndroid != 0) {
- nativeOnRead(mNativeBluetoothRemoteGattCharacteristicAndroid, status,
+ ChromeBluetoothRemoteGattCharacteristicJni.get().onRead(
+ mNativeBluetoothRemoteGattCharacteristicAndroid,
+ ChromeBluetoothRemoteGattCharacteristic.this, status,
mCharacteristic.getValue());
}
}
@@ -80,7 +85,9 @@ final class ChromeBluetoothRemoteGattCharacteristic {
Log.i(TAG, "onCharacteristicWrite status:%d==%s", status,
status == android.bluetooth.BluetoothGatt.GATT_SUCCESS ? "OK" : "Error");
if (mNativeBluetoothRemoteGattCharacteristicAndroid != 0) {
- nativeOnWrite(mNativeBluetoothRemoteGattCharacteristicAndroid, status);
+ ChromeBluetoothRemoteGattCharacteristicJni.get().onWrite(
+ mNativeBluetoothRemoteGattCharacteristicAndroid,
+ ChromeBluetoothRemoteGattCharacteristic.this, status);
}
}
@@ -156,27 +163,31 @@ final class ChromeBluetoothRemoteGattCharacteristic {
for (Wrappers.BluetoothGattDescriptorWrapper descriptor : descriptors) {
String descriptorInstanceId =
mInstanceId + "/" + descriptor.getUuid().toString() + ";" + instanceIdCounter++;
- nativeCreateGattRemoteDescriptor(mNativeBluetoothRemoteGattCharacteristicAndroid,
- descriptorInstanceId, descriptor, mChromeDevice);
+ ChromeBluetoothRemoteGattCharacteristicJni.get().createGattRemoteDescriptor(
+ mNativeBluetoothRemoteGattCharacteristicAndroid,
+ ChromeBluetoothRemoteGattCharacteristic.this, descriptorInstanceId, descriptor,
+ mChromeDevice);
}
}
- // ---------------------------------------------------------------------------------------------
- // BluetoothAdapterDevice C++ methods declared for access from java:
-
- // Binds to BluetoothRemoteGattCharacteristicAndroid::OnChanged.
- native void nativeOnChanged(long nativeBluetoothRemoteGattCharacteristicAndroid, byte[] value);
-
- // Binds to BluetoothRemoteGattCharacteristicAndroid::OnRead.
- native void nativeOnRead(
- long nativeBluetoothRemoteGattCharacteristicAndroid, int status, byte[] value);
-
- // Binds to BluetoothRemoteGattCharacteristicAndroid::OnWrite.
- native void nativeOnWrite(long nativeBluetoothRemoteGattCharacteristicAndroid, int status);
-
- // Binds to BluetoothRemoteGattCharacteristicAndroid::CreateGattRemoteDescriptor.
- private native void nativeCreateGattRemoteDescriptor(
- long nativeBluetoothRemoteGattCharacteristicAndroid, String instanceId,
- Wrappers.BluetoothGattDescriptorWrapper descriptorWrapper,
- ChromeBluetoothDevice chromeBluetoothDevice);
+ @NativeMethods
+ interface Natives {
+ // Binds to BluetoothRemoteGattCharacteristicAndroid::OnChanged.
+ void onChanged(long nativeBluetoothRemoteGattCharacteristicAndroid,
+ ChromeBluetoothRemoteGattCharacteristic caller, byte[] value);
+
+ // Binds to BluetoothRemoteGattCharacteristicAndroid::OnRead.
+ void onRead(long nativeBluetoothRemoteGattCharacteristicAndroid,
+ ChromeBluetoothRemoteGattCharacteristic caller, int status, byte[] value);
+
+ // Binds to BluetoothRemoteGattCharacteristicAndroid::OnWrite.
+ void onWrite(long nativeBluetoothRemoteGattCharacteristicAndroid,
+ ChromeBluetoothRemoteGattCharacteristic caller, int status);
+
+ // Binds to BluetoothRemoteGattCharacteristicAndroid::CreateGattRemoteDescriptor.
+ void createGattRemoteDescriptor(long nativeBluetoothRemoteGattCharacteristicAndroid,
+ ChromeBluetoothRemoteGattCharacteristic caller, String instanceId,
+ Wrappers.BluetoothGattDescriptorWrapper descriptorWrapper,
+ ChromeBluetoothDevice chromeBluetoothDevice);
+ }
}
diff --git a/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattDescriptor.java b/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattDescriptor.java
index a90608bad1e..4214c4281be 100644
--- a/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattDescriptor.java
+++ b/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattDescriptor.java
@@ -8,6 +8,7 @@ import org.chromium.base.Log;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNIAdditionalImport;
import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeMethods;
/**
* Exposes android.bluetooth.BluetoothGattDescriptor as necessary
@@ -50,8 +51,9 @@ final class ChromeBluetoothRemoteGattDescriptor {
Log.i(TAG, "onDescriptorRead status:%d==%s", status,
status == android.bluetooth.BluetoothGatt.GATT_SUCCESS ? "OK" : "Error");
if (mNativeBluetoothRemoteGattDescriptorAndroid != 0) {
- nativeOnRead(
- mNativeBluetoothRemoteGattDescriptorAndroid, status, mDescriptor.getValue());
+ ChromeBluetoothRemoteGattDescriptorJni.get().onRead(
+ mNativeBluetoothRemoteGattDescriptorAndroid,
+ ChromeBluetoothRemoteGattDescriptor.this, status, mDescriptor.getValue());
}
}
@@ -59,7 +61,9 @@ final class ChromeBluetoothRemoteGattDescriptor {
Log.i(TAG, "onDescriptorWrite status:%d==%s", status,
status == android.bluetooth.BluetoothGatt.GATT_SUCCESS ? "OK" : "Error");
if (mNativeBluetoothRemoteGattDescriptorAndroid != 0) {
- nativeOnWrite(mNativeBluetoothRemoteGattDescriptorAndroid, status);
+ ChromeBluetoothRemoteGattDescriptorJni.get().onWrite(
+ mNativeBluetoothRemoteGattDescriptorAndroid,
+ ChromeBluetoothRemoteGattDescriptor.this, status);
}
}
@@ -106,13 +110,14 @@ final class ChromeBluetoothRemoteGattDescriptor {
return true;
}
- // ---------------------------------------------------------------------------------------------
- // BluetoothAdapterDevice C++ methods declared for access from java:
-
- // Binds to BluetoothRemoteGattDescriptorAndroid::OnRead.
- native void nativeOnRead(
- long nativeBluetoothRemoteGattDescriptorAndroid, int status, byte[] value);
+ @NativeMethods
+ interface Natives {
+ // Binds to BluetoothRemoteGattDescriptorAndroid::OnRead.
+ void onRead(long nativeBluetoothRemoteGattDescriptorAndroid,
+ ChromeBluetoothRemoteGattDescriptor caller, int status, byte[] value);
- // Binds to BluetoothRemoteGattDescriptorAndroid::OnWrite.
- native void nativeOnWrite(long nativeBluetoothRemoteGattDescriptorAndroid, int status);
+ // Binds to BluetoothRemoteGattDescriptorAndroid::OnWrite.
+ void onWrite(long nativeBluetoothRemoteGattDescriptorAndroid,
+ ChromeBluetoothRemoteGattDescriptor caller, int status);
+ }
}
diff --git a/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattService.java b/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattService.java
index 6f2989ebad2..fd6803e1ece 100644
--- a/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattService.java
+++ b/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothRemoteGattService.java
@@ -8,6 +8,7 @@ import org.chromium.base.Log;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNIAdditionalImport;
import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeMethods;
import java.util.List;
@@ -46,9 +47,6 @@ final class ChromeBluetoothRemoteGattService {
mNativeBluetoothRemoteGattServiceAndroid = 0;
}
- // ---------------------------------------------------------------------------------------------
- // BluetoothRemoteGattServiceAndroid methods implemented in java:
-
// Implements BluetoothRemoteGattServiceAndroid::Create.
@CalledByNative
private static ChromeBluetoothRemoteGattService create(
@@ -76,17 +74,18 @@ final class ChromeBluetoothRemoteGattService {
// characteristic instances with the same UUID on this service.
String characteristicInstanceId = mInstanceId + "/"
+ characteristic.getUuid().toString() + "," + characteristic.getInstanceId();
- nativeCreateGattRemoteCharacteristic(mNativeBluetoothRemoteGattServiceAndroid,
+ ChromeBluetoothRemoteGattServiceJni.get().createGattRemoteCharacteristic(
+ mNativeBluetoothRemoteGattServiceAndroid, ChromeBluetoothRemoteGattService.this,
characteristicInstanceId, characteristic, mChromeDevice);
}
}
- // ---------------------------------------------------------------------------------------------
- // BluetoothAdapterDevice C++ methods declared for access from java:
-
- // Binds to BluetoothRemoteGattServiceAndroid::CreateGattRemoteCharacteristic.
- private native void nativeCreateGattRemoteCharacteristic(
- long nativeBluetoothRemoteGattServiceAndroid, String instanceId,
- Wrappers.BluetoothGattCharacteristicWrapper characteristicWrapper,
- ChromeBluetoothDevice chromeBluetoothDevice);
+ @NativeMethods
+ interface Natives {
+ // Binds to BluetoothRemoteGattServiceAndroid::CreateGattRemoteCharacteristic.
+ void createGattRemoteCharacteristic(long nativeBluetoothRemoteGattServiceAndroid,
+ ChromeBluetoothRemoteGattService caller, String instanceId,
+ Wrappers.BluetoothGattCharacteristicWrapper characteristicWrapper,
+ ChromeBluetoothDevice chromeBluetoothDevice);
+ }
}
diff --git a/chromium/device/bluetooth/bluetooth_adapter.cc b/chromium/device/bluetooth/bluetooth_adapter.cc
index 564cf1a6843..eabda679333 100644
--- a/chromium/device/bluetooth/bluetooth_adapter.cc
+++ b/chromium/device/bluetooth/bluetooth_adapter.cc
@@ -37,7 +37,7 @@ base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
#endif // !defined(OS_CHROMEOS) && !defined(OS_WIN) && !defined(OS_MACOSX)
base::WeakPtr<BluetoothAdapter> BluetoothAdapter::GetWeakPtrForTesting() {
- return weak_ptr_factory_.GetWeakPtr();
+ return GetWeakPtr();
}
#if defined(OS_LINUX)
@@ -446,8 +446,15 @@ void BluetoothAdapter::OnDiscoveryChangeComplete(
UMABluetoothDiscoverySessionOutcome outcome) {
UpdateDiscoveryState(is_error);
+ // Take a weak reference to |this| in case a callback frees the adapter.
+ base::WeakPtr<BluetoothAdapter> self = GetWeakPtr();
+
if (is_error) {
NotifyDiscoveryError(std::move(callbacks_awaiting_response_));
+
+ if (!self)
+ return;
+
discovery_request_pending_ = false;
ProcessDiscoveryQueue();
return;
@@ -455,16 +462,20 @@ void BluetoothAdapter::OnDiscoveryChangeComplete(
current_discovery_filter_.CopyFrom(filter_being_set_);
- while (!callbacks_awaiting_response_.empty()) {
+ auto callbacks_awaiting_response = std::move(callbacks_awaiting_response_);
+ while (!callbacks_awaiting_response.empty()) {
std::unique_ptr<StartOrStopDiscoveryCallback> callbacks =
- std::move(callbacks_awaiting_response_.front());
- callbacks_awaiting_response_.pop();
+ std::move(callbacks_awaiting_response.front());
+ callbacks_awaiting_response.pop();
if (callbacks->start_callback)
std::move(callbacks->start_callback).Run();
-
if (callbacks->stop_callback)
std::move(callbacks->stop_callback).Run();
}
+
+ if (!self)
+ return;
+
discovery_request_pending_ = false;
ProcessDiscoveryQueue();
}
@@ -501,14 +512,13 @@ void BluetoothAdapter::ProcessDiscoveryQueue() {
internal_discovery_state_ = DiscoveryState::kStopping;
discovery_request_pending_ = true;
StopScan(base::BindOnce(&BluetoothAdapter::OnDiscoveryChangeComplete,
- weak_ptr_factory_.GetWeakPtr()));
+ GetWeakPtr()));
return;
}
- auto result_callback =
- base::BindOnce(&BluetoothAdapter::OnDiscoveryChangeComplete,
- weak_ptr_factory_.GetWeakPtr());
+ auto result_callback = base::BindOnce(
+ &BluetoothAdapter::OnDiscoveryChangeComplete, GetWeakPtr());
auto new_desired_filter = GetMergedDiscoveryFilter();
discovery_request_pending_ = true;
filter_being_set_.CopyFrom(*new_desired_filter.get());
diff --git a/chromium/device/bluetooth/bluetooth_adapter.h b/chromium/device/bluetooth/bluetooth_adapter.h
index 143d35b4eda..0cf207feb21 100644
--- a/chromium/device/bluetooth/bluetooth_adapter.h
+++ b/chromium/device/bluetooth/bluetooth_adapter.h
@@ -671,6 +671,8 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapter
BluetoothAdapter();
virtual ~BluetoothAdapter();
+ virtual base::WeakPtr<BluetoothAdapter> GetWeakPtr() = 0;
+
// This method calls into platform specific logic on macOS and Android where
// pending SetPowered() callbacks need to be stored explicitly.
virtual bool SetPoweredImpl(bool powered) = 0;
@@ -818,10 +820,6 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapter
// enum used to track our internal discovery state.
DiscoveryState internal_discovery_state_ = DiscoveryState::kIdle;
-
- // Note: This should remain the last member so it'll be destroyed and
- // invalidate its weak pointers before any other members are destroyed.
- base::WeakPtrFactory<BluetoothAdapter> weak_ptr_factory_{this};
};
} // namespace device
diff --git a/chromium/device/bluetooth/bluetooth_adapter_android.cc b/chromium/device/bluetooth/bluetooth_adapter_android.cc
index d521c57b316..9fa04809d08 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_android.cc
+++ b/chromium/device/bluetooth/bluetooth_adapter_android.cc
@@ -295,6 +295,10 @@ void BluetoothAdapterAndroid::PurgeTimedOutDevices() {
}
}
+base::WeakPtr<BluetoothAdapter> BluetoothAdapterAndroid::GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
bool BluetoothAdapterAndroid::SetPoweredImpl(bool powered) {
return Java_ChromeBluetoothAdapter_setPowered(AttachCurrentThread(),
j_adapter_, powered);
diff --git a/chromium/device/bluetooth/bluetooth_adapter_android.h b/chromium/device/bluetooth/bluetooth_adapter_android.h
index 3fbdba25ae5..dc866518978 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_android.h
+++ b/chromium/device/bluetooth/bluetooth_adapter_android.h
@@ -112,6 +112,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterAndroid final
~BluetoothAdapterAndroid() override;
// BluetoothAdapter:
+ base::WeakPtr<BluetoothAdapter> GetWeakPtr() override;
bool SetPoweredImpl(bool powered) override;
void StartScanWithFilter(
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
diff --git a/chromium/device/bluetooth/bluetooth_adapter_factory.h b/chromium/device/bluetooth/bluetooth_adapter_factory.h
index d33b22a6e20..e80a0d1205b 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_factory.h
+++ b/chromium/device/bluetooth/bluetooth_adapter_factory.h
@@ -86,7 +86,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterFactory {
static bool HasSharedInstanceForTesting();
#if defined(OS_CHROMEOS)
- // Sets the BleScanParserPtr callback used in Get*() below.
+ // Sets the mojo::Remote<BleScanParser> callback used in Get*() below.
static void SetBleScanParserCallback(BleScanParserCallback callback);
// Returns a reference to a parser for BLE advertisement packets.
// This will be an empty callback until something calls Set*() above.
diff --git a/chromium/device/bluetooth/bluetooth_adapter_mac.h b/chromium/device/bluetooth/bluetooth_adapter_mac.h
index 61414cc0503..544e868aef2 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_mac.h
+++ b/chromium/device/bluetooth/bluetooth_adapter_mac.h
@@ -124,6 +124,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterMac
base::RepeatingCallback<bool(const std::string& address)>;
// BluetoothAdapter override:
+ base::WeakPtr<BluetoothAdapter> GetWeakPtr() override;
bool SetPoweredImpl(bool powered) override;
void RemovePairingDelegateInternal(
device::BluetoothDevice::PairingDelegate* pairing_delegate) override;
diff --git a/chromium/device/bluetooth/bluetooth_adapter_mac.mm b/chromium/device/bluetooth/bluetooth_adapter_mac.mm
index 8e4a469b6f0..b2425416b19 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_mac.mm
+++ b/chromium/device/bluetooth/bluetooth_adapter_mac.mm
@@ -302,6 +302,10 @@ void BluetoothAdapterMac::DeviceConnected(IOBluetoothDevice* device) {
ClassicDeviceAdded(device);
}
+base::WeakPtr<BluetoothAdapter> BluetoothAdapterMac::GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
bool BluetoothAdapterMac::SetPoweredImpl(bool powered) {
power_state_function_.Run(base::strict_cast<int>(powered));
return true;
diff --git a/chromium/device/bluetooth/bluetooth_adapter_mac_unittest.mm b/chromium/device/bluetooth/bluetooth_adapter_mac_unittest.mm
index 1468c63e248..817338f5227 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_mac_unittest.mm
+++ b/chromium/device/bluetooth/bluetooth_adapter_mac_unittest.mm
@@ -306,7 +306,9 @@ TEST_F(BluetoothAdapterMacTest, AddSecondDiscoverySessionWithLowEnergyFilter) {
new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE));
// Adding uuid to first discovery session so that there is a change to be made
// when starting the second session.
- discovery_filter->AddUUID(device::BluetoothUUID("1000"));
+ BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(device::BluetoothUUID("1000"));
+ discovery_filter->AddDeviceFilter(device_filter);
adapter_mac_->StartDiscoverySessionWithFilter(
std::move(discovery_filter),
base::BindRepeating(
diff --git a/chromium/device/bluetooth/bluetooth_adapter_unittest.cc b/chromium/device/bluetooth/bluetooth_adapter_unittest.cc
index 2448a769e2a..04103ea933a 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_unittest.cc
+++ b/chromium/device/bluetooth/bluetooth_adapter_unittest.cc
@@ -69,9 +69,16 @@ using device::BluetoothDevice;
namespace device {
+void AddDeviceFilterWithUUID(BluetoothDiscoveryFilter* filter,
+ BluetoothUUID uuid) {
+ BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(uuid);
+ filter->AddDeviceFilter(device_filter);
+}
+
namespace {
-class TestBluetoothAdapter : public BluetoothAdapter {
+class TestBluetoothAdapter final : public BluetoothAdapter {
public:
TestBluetoothAdapter() = default;
@@ -162,6 +169,11 @@ class TestBluetoothAdapter : public BluetoothAdapter {
run_loop_quit.Run();
}
+ void set_discovery_session_outcome(
+ UMABluetoothDiscoverySessionOutcome outcome) {
+ discovery_session_outcome_ = outcome;
+ }
+
void StopDiscoverySession(base::Closure run_loop_quit) {
discovery_sessions_holder_.front()->Stop(
base::BindRepeating(&TestBluetoothAdapter::OnRemoveDiscoverySession,
@@ -250,12 +262,17 @@ class TestBluetoothAdapter : public BluetoothAdapter {
bool SetPoweredImpl(bool powered) override { return false; }
+ base::WeakPtr<BluetoothAdapter> GetWeakPtr() override {
+ return weak_ptr_factory_.GetWeakPtr();
+ }
+
void StartScanWithFilter(
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
DiscoverySessionResultCallback callback) override {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::BindOnce(&TestBluetoothAdapter::SetFilter, this,
+ base::BindOnce(&TestBluetoothAdapter::SetFilter,
+ weak_ptr_factory_.GetWeakPtr(),
std::move(discovery_filter), std::move(callback)));
}
@@ -263,22 +280,27 @@ class TestBluetoothAdapter : public BluetoothAdapter {
DiscoverySessionResultCallback callback) override {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::BindOnce(&TestBluetoothAdapter::SetFilter, this,
+ base::BindOnce(&TestBluetoothAdapter::SetFilter,
+ weak_ptr_factory_.GetWeakPtr(),
std::move(discovery_filter), std::move(callback)));
}
void SetFilter(std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
DiscoverySessionResultCallback callback) {
- is_discovering_ = true;
- current_filter->CopyFrom(*discovery_filter.get());
- std::move(callback).Run(/*is_error=*/false,
- UMABluetoothDiscoverySessionOutcome::SUCCESS);
+ bool is_error = discovery_session_outcome_ !=
+ UMABluetoothDiscoverySessionOutcome::SUCCESS;
+ if (!is_error) {
+ is_discovering_ = true;
+ current_filter->CopyFrom(*discovery_filter.get());
+ }
+ std::move(callback).Run(is_error, discovery_session_outcome_);
}
void StopScan(DiscoverySessionResultCallback callback) override {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&TestBluetoothAdapter::FakeOSStopScan, this,
- std::move(callback)));
+ FROM_HERE,
+ base::BindOnce(&TestBluetoothAdapter::FakeOSStopScan,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void FakeOSStopScan(DiscoverySessionResultCallback callback) {
@@ -297,6 +319,13 @@ class TestBluetoothAdapter : public BluetoothAdapter {
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
std::move(callback));
}
+
+ UMABluetoothDiscoverySessionOutcome discovery_session_outcome_ =
+ UMABluetoothDiscoverySessionOutcome::SUCCESS;
+
+ // This must be the last field in the class so that weak pointers are
+ // invalidated first.
+ base::WeakPtrFactory<TestBluetoothAdapter> weak_ptr_factory_{this};
};
class TestPairingDelegate : public BluetoothDevice::PairingDelegate {
@@ -399,15 +428,13 @@ TEST_F(BluetoothAdapterTest, MAYBE_GetMergedDiscoveryFilterRegular) {
}
TEST_F(BluetoothAdapterTest, TestQueueingLogic) {
- BluetoothDiscoveryFilter* df =
- new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE);
- df->AddUUID(device::BluetoothUUID("1001"));
- std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter(df);
+ auto discovery_filter =
+ std::make_unique<BluetoothDiscoveryFilter>(BLUETOOTH_TRANSPORT_LE);
+ AddDeviceFilterWithUUID(discovery_filter.get(), BluetoothUUID("1001"));
- BluetoothDiscoveryFilter* df2 =
- new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE);
- df->AddUUID(device::BluetoothUUID("1002"));
- std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter2(df2);
+ auto discovery_filter2 =
+ std::make_unique<BluetoothDiscoveryFilter>(BLUETOOTH_TRANSPORT_LE);
+ AddDeviceFilterWithUUID(discovery_filter2.get(), BluetoothUUID("1002"));
// Start a discovery session
base::RunLoop run_loop1;
@@ -460,10 +487,9 @@ TEST_F(BluetoothAdapterTest, TestQueueingLogic) {
TEST_F(BluetoothAdapterTest, ShortCircuitUpdateTest) {
auto discovery_filter_default1 = std::make_unique<BluetoothDiscoveryFilter>();
- BluetoothDiscoveryFilter* df =
- new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE);
- df->SetRSSI(-30);
- std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter(df);
+ auto discovery_filter =
+ std::make_unique<BluetoothDiscoveryFilter>(BLUETOOTH_TRANSPORT_LE);
+ discovery_filter->SetRSSI(-30);
base::RunLoop run_loop;
adapter_->StartSessionWithFilter(std::move(discovery_filter_default1),
@@ -535,15 +561,13 @@ TEST_F(BluetoothAdapterTest, MAYBE_GetMergedDiscoveryFilterRssi) {
uint16_t resulting_pathloss;
std::unique_ptr<BluetoothDiscoveryFilter> resulting_filter;
- BluetoothDiscoveryFilter* df =
- new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE);
- df->SetRSSI(-30);
- std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter(df);
+ auto discovery_filter =
+ std::make_unique<BluetoothDiscoveryFilter>(BLUETOOTH_TRANSPORT_LE);
+ discovery_filter->SetRSSI(-30);
- BluetoothDiscoveryFilter* df2 =
- new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE);
- df2->SetRSSI(-65);
- std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter2(df2);
+ auto discovery_filter2 =
+ std::make_unique<BluetoothDiscoveryFilter>(BLUETOOTH_TRANSPORT_LE);
+ discovery_filter2->SetRSSI(-65);
// Make sure adapter has one session without filtering.
adapter_->InjectFilteredSession(std::move(discovery_filter));
@@ -579,13 +603,11 @@ TEST_F(BluetoothAdapterTest, MAYBE_GetMergedDiscoveryFilterTransport) {
scoped_refptr<TestBluetoothAdapter> adapter = new TestBluetoothAdapter();
std::unique_ptr<BluetoothDiscoveryFilter> resulting_filter;
- BluetoothDiscoveryFilter* df =
- new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_CLASSIC);
- std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter(df);
+ auto discovery_filter =
+ std::make_unique<BluetoothDiscoveryFilter>(BLUETOOTH_TRANSPORT_CLASSIC);
- BluetoothDiscoveryFilter* df2 =
- new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE);
- std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter2(df2);
+ auto discovery_filter2 =
+ std::make_unique<BluetoothDiscoveryFilter>(BLUETOOTH_TRANSPORT_LE);
adapter_->InjectFilteredSession(std::move(discovery_filter));
@@ -599,10 +621,10 @@ TEST_F(BluetoothAdapterTest, MAYBE_GetMergedDiscoveryFilterTransport) {
resulting_filter = adapter_->GetMergedDiscoveryFilter();
EXPECT_EQ(BLUETOOTH_TRANSPORT_DUAL, resulting_filter->GetTransport());
- BluetoothDiscoveryFilter* df3 =
- new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE);
- df3->CopyFrom(BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_DUAL));
- std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter3(df3);
+ auto discovery_filter3 =
+ std::make_unique<BluetoothDiscoveryFilter>(BLUETOOTH_TRANSPORT_LE);
+ discovery_filter3->CopyFrom(
+ BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_DUAL));
// Merging empty filter in should result in empty filter
adapter_->InjectFilteredSession(std::move(discovery_filter3));
@@ -617,27 +639,23 @@ TEST_F(BluetoothAdapterTest, MAYBE_GetMergedDiscoveryFilterAllFields) {
int16_t resulting_rssi;
std::set<device::BluetoothUUID> resulting_uuids;
- BluetoothDiscoveryFilter* df =
- new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE);
- df->SetRSSI(-60);
- df->AddUUID(device::BluetoothUUID("1000"));
- std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter(df);
+ auto discovery_filter =
+ std::make_unique<BluetoothDiscoveryFilter>(BLUETOOTH_TRANSPORT_LE);
+ discovery_filter->SetRSSI(-60);
+ AddDeviceFilterWithUUID(discovery_filter.get(), BluetoothUUID("1000"));
- BluetoothDiscoveryFilter* df2 =
- new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE);
- df2->SetRSSI(-85);
- df2->SetTransport(BLUETOOTH_TRANSPORT_LE);
- df2->AddUUID(device::BluetoothUUID("1020"));
- df2->AddUUID(device::BluetoothUUID("1001"));
- std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter2(df2);
+ auto discovery_filter2 =
+ std::make_unique<BluetoothDiscoveryFilter>(BLUETOOTH_TRANSPORT_LE);
+ discovery_filter2->SetRSSI(-85);
+ AddDeviceFilterWithUUID(discovery_filter2.get(), BluetoothUUID("1020"));
+ AddDeviceFilterWithUUID(discovery_filter2.get(), BluetoothUUID("1001"));
- BluetoothDiscoveryFilter* df3 =
- new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE);
- df3->SetRSSI(-65);
- df3->SetTransport(BLUETOOTH_TRANSPORT_CLASSIC);
- df3->AddUUID(device::BluetoothUUID("1020"));
- df3->AddUUID(device::BluetoothUUID("1003"));
- std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter3(df3);
+ auto discovery_filter3 =
+ std::make_unique<BluetoothDiscoveryFilter>(BLUETOOTH_TRANSPORT_LE);
+ discovery_filter3->SetRSSI(-65);
+ discovery_filter3->SetTransport(BLUETOOTH_TRANSPORT_CLASSIC);
+ AddDeviceFilterWithUUID(discovery_filter3.get(), BluetoothUUID("1020"));
+ AddDeviceFilterWithUUID(discovery_filter3.get(), BluetoothUUID("1003"));
adapter_->InjectFilteredSession(std::move(discovery_filter));
adapter_->InjectFilteredSession(std::move(discovery_filter2));
@@ -662,6 +680,30 @@ TEST_F(BluetoothAdapterTest, MAYBE_GetMergedDiscoveryFilterAllFields) {
adapter_->CleanupSessions();
}
+TEST_F(BluetoothAdapterTest, StartDiscoverySession_Destroy) {
+ base::RunLoop loop;
+ adapter_->StartDiscoverySession(
+ base::BindLambdaForTesting(
+ [&](std::unique_ptr<BluetoothDiscoverySession> session) {
+ adapter_.reset();
+ loop.Quit();
+ }),
+ base::DoNothing());
+ loop.Run();
+}
+
+TEST_F(BluetoothAdapterTest, StartDiscoverySessionError_Destroy) {
+ base::RunLoop loop;
+ adapter_->set_discovery_session_outcome(
+ UMABluetoothDiscoverySessionOutcome::FAILED);
+ adapter_->StartDiscoverySession(base::DoNothing(),
+ base::BindLambdaForTesting([&]() {
+ adapter_.reset();
+ loop.Quit();
+ }));
+ loop.Run();
+}
+
// TODO(scheib): Enable BluetoothTest fixture tests on all platforms.
#if defined(OS_ANDROID) || defined(OS_MACOSX)
#define MAYBE_ConstructDefaultAdapter ConstructDefaultAdapter
@@ -1696,21 +1738,19 @@ TEST_F(BluetoothTest, MAYBE_RegisterLocalGattServices) {
base::WeakPtr<BluetoothLocalGattCharacteristic> characteristic1 =
BluetoothLocalGattCharacteristic::Create(
BluetoothUUID(kTestUUIDGenericAttribute),
- device::BluetoothLocalGattCharacteristic::Properties(),
- device::BluetoothLocalGattCharacteristic::Permissions(),
- service.get());
+ BluetoothLocalGattCharacteristic::Properties(),
+ BluetoothLocalGattCharacteristic::Permissions(), service.get());
base::WeakPtr<BluetoothLocalGattCharacteristic> characteristic2 =
BluetoothLocalGattCharacteristic::Create(
BluetoothUUID(kTestUUIDGenericAttribute),
- device::BluetoothLocalGattCharacteristic::Properties(),
- device::BluetoothLocalGattCharacteristic::Permissions(),
- service.get());
+ BluetoothLocalGattCharacteristic::Properties(),
+ BluetoothLocalGattCharacteristic::Permissions(), service.get());
base::WeakPtr<BluetoothLocalGattDescriptor> descriptor =
BluetoothLocalGattDescriptor::Create(
BluetoothUUID(kTestUUIDGenericAttribute),
- device::BluetoothLocalGattCharacteristic::Permissions(),
+ BluetoothLocalGattCharacteristic::Permissions(),
characteristic1.get());
service->Register(GetCallback(Call::EXPECTED),
@@ -1865,9 +1905,8 @@ TEST_F(BluetoothTest, DiscoverConnectedLowEnergyDeviceWithFilter) {
SimulateConnectedLowEnergyDevice(ConnectedDeviceType::GENERIC_DEVICE);
SimulateConnectedLowEnergyDevice(ConnectedDeviceType::HEART_RATE_DEVICE);
BluetoothDiscoveryFilter discovery_filter(BLUETOOTH_TRANSPORT_LE);
- device::BluetoothUUID heart_service_uuid =
- device::BluetoothUUID(kTestUUIDHeartRate);
- discovery_filter.AddUUID(heart_service_uuid);
+ BluetoothUUID heart_service_uuid = BluetoothUUID(kTestUUIDHeartRate);
+ AddDeviceFilterWithUUID(&discovery_filter, heart_service_uuid);
std::unordered_map<BluetoothDevice*, BluetoothDevice::UUIDSet> result =
adapter_->RetrieveGattConnectedDevicesWithDiscoveryFilter(
discovery_filter);
@@ -1900,7 +1939,7 @@ TEST_F(BluetoothTest, DiscoverConnectedLowEnergyDeviceWithWrongFilter) {
SimulateConnectedLowEnergyDevice(ConnectedDeviceType::GENERIC_DEVICE);
SimulateConnectedLowEnergyDevice(ConnectedDeviceType::HEART_RATE_DEVICE);
BluetoothDiscoveryFilter discovery_filter(BLUETOOTH_TRANSPORT_LE);
- discovery_filter.AddUUID(device::BluetoothUUID(kTestUUIDLinkLoss));
+ AddDeviceFilterWithUUID(&discovery_filter, BluetoothUUID(kTestUUIDLinkLoss));
std::unordered_map<BluetoothDevice*, BluetoothDevice::UUIDSet> result =
adapter_->RetrieveGattConnectedDevicesWithDiscoveryFilter(
discovery_filter);
@@ -1929,12 +1968,10 @@ TEST_F(BluetoothTest, DiscoverConnectedLowEnergyDeviceWithTwoFilters) {
SimulateConnectedLowEnergyDevice(ConnectedDeviceType::GENERIC_DEVICE);
SimulateConnectedLowEnergyDevice(ConnectedDeviceType::HEART_RATE_DEVICE);
BluetoothDiscoveryFilter discovery_filter(BLUETOOTH_TRANSPORT_LE);
- device::BluetoothUUID heart_service_uuid =
- device::BluetoothUUID(kTestUUIDHeartRate);
- discovery_filter.AddUUID(heart_service_uuid);
- device::BluetoothUUID generic_service_uuid =
- device::BluetoothUUID(kTestUUIDGenericAccess);
- discovery_filter.AddUUID(generic_service_uuid);
+ BluetoothUUID heart_service_uuid = BluetoothUUID(kTestUUIDHeartRate);
+ AddDeviceFilterWithUUID(&discovery_filter, heart_service_uuid);
+ BluetoothUUID generic_service_uuid = BluetoothUUID(kTestUUIDGenericAccess);
+ AddDeviceFilterWithUUID(&discovery_filter, generic_service_uuid);
std::unordered_map<BluetoothDevice*, BluetoothDevice::UUIDSet> result =
adapter_->RetrieveGattConnectedDevicesWithDiscoveryFilter(
discovery_filter);
@@ -1977,9 +2014,8 @@ TEST_F(BluetoothTest, DiscoverConnectedLowEnergyDeviceTwice) {
SimulateConnectedLowEnergyDevice(ConnectedDeviceType::GENERIC_DEVICE);
SimulateConnectedLowEnergyDevice(ConnectedDeviceType::HEART_RATE_DEVICE);
BluetoothDiscoveryFilter discovery_filter(BLUETOOTH_TRANSPORT_LE);
- device::BluetoothUUID heart_service_uuid =
- device::BluetoothUUID(kTestUUIDHeartRate);
- discovery_filter.AddUUID(heart_service_uuid);
+ BluetoothUUID heart_service_uuid = BluetoothUUID(kTestUUIDHeartRate);
+ AddDeviceFilterWithUUID(&discovery_filter, heart_service_uuid);
std::unordered_map<BluetoothDevice*, BluetoothDevice::UUIDSet> result =
adapter_->RetrieveGattConnectedDevicesWithDiscoveryFilter(
discovery_filter);
diff --git a/chromium/device/bluetooth/bluetooth_adapter_win.cc b/chromium/device/bluetooth/bluetooth_adapter_win.cc
index 85a34d42eeb..06eac5b7403 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_win.cc
+++ b/chromium/device/bluetooth/bluetooth_adapter_win.cc
@@ -279,6 +279,10 @@ void BluetoothAdapterWin::DevicesPolled(
}
}
+base::WeakPtr<BluetoothAdapter> BluetoothAdapterWin::GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
// BluetoothAdapterWin should override SetPowered() instead.
bool BluetoothAdapterWin::SetPoweredImpl(bool powered) {
NOTREACHED();
diff --git a/chromium/device/bluetooth/bluetooth_adapter_win.h b/chromium/device/bluetooth/bluetooth_adapter_win.h
index 8fb83752eb7..bd56d4b715a 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_win.h
+++ b/chromium/device/bluetooth/bluetooth_adapter_win.h
@@ -116,6 +116,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterWin
~BluetoothAdapterWin() override;
// BluetoothAdapter:
+ base::WeakPtr<BluetoothAdapter> GetWeakPtr() override;
bool SetPoweredImpl(bool powered) override;
void UpdateFilter(std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
DiscoverySessionResultCallback callback) override;
diff --git a/chromium/device/bluetooth/bluetooth_adapter_winrt.cc b/chromium/device/bluetooth/bluetooth_adapter_winrt.cc
index 79bf527656e..d2a7b9d7a97 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_winrt.cc
+++ b/chromium/device/bluetooth/bluetooth_adapter_winrt.cc
@@ -841,6 +841,10 @@ void BluetoothAdapterWinrt::CompleteInit(
}
}
+base::WeakPtr<BluetoothAdapter> BluetoothAdapterWinrt::GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
bool BluetoothAdapterWinrt::SetPoweredImpl(bool powered) {
// Due to an issue on WoW64 we might fail to obtain the radio in
// OnGetRadio(). This is why it can be null here.
diff --git a/chromium/device/bluetooth/bluetooth_adapter_winrt.h b/chromium/device/bluetooth/bluetooth_adapter_winrt.h
index 1c3019cea36..9474428376b 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_winrt.h
+++ b/chromium/device/bluetooth/bluetooth_adapter_winrt.h
@@ -92,6 +92,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterWinrt : public BluetoothAdapter {
radio_statics);
// BluetoothAdapter:
+ base::WeakPtr<BluetoothAdapter> GetWeakPtr() override;
bool SetPoweredImpl(bool powered) override;
void UpdateFilter(std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
DiscoverySessionResultCallback callback) override;
diff --git a/chromium/device/bluetooth/bluetooth_discovery_filter.cc b/chromium/device/bluetooth/bluetooth_discovery_filter.cc
index f591b63efa9..7a9910599e9 100644
--- a/chromium/device/bluetooth/bluetooth_discovery_filter.cc
+++ b/chromium/device/bluetooth/bluetooth_discovery_filter.cc
@@ -23,6 +23,23 @@ BluetoothDiscoveryFilter::BluetoothDiscoveryFilter(
BluetoothDiscoveryFilter::~BluetoothDiscoveryFilter() = default;
+BluetoothDiscoveryFilter::DeviceInfoFilter::DeviceInfoFilter() = default;
+BluetoothDiscoveryFilter::DeviceInfoFilter::DeviceInfoFilter(
+ const DeviceInfoFilter& other) = default;
+BluetoothDiscoveryFilter::DeviceInfoFilter::~DeviceInfoFilter() = default;
+bool BluetoothDiscoveryFilter::DeviceInfoFilter::operator==(
+ const BluetoothDiscoveryFilter::DeviceInfoFilter& other) const {
+ return uuids == other.uuids && name == other.name;
+}
+
+bool BluetoothDiscoveryFilter::DeviceInfoFilter::operator<(
+ const BluetoothDiscoveryFilter::DeviceInfoFilter& other) const {
+ if (name == other.name)
+ return uuids < other.uuids;
+
+ return name < other.name;
+}
+
bool BluetoothDiscoveryFilter::GetRSSI(int16_t* out_rssi) const {
DCHECK(out_rssi);
if (!rssi_)
@@ -61,30 +78,25 @@ void BluetoothDiscoveryFilter::SetTransport(BluetoothTransport transport) {
void BluetoothDiscoveryFilter::GetUUIDs(
std::set<device::BluetoothUUID>& out_uuids) const {
out_uuids.clear();
-
- for (const auto& uuid : uuids_)
- out_uuids.insert(*uuid);
-}
-
-void BluetoothDiscoveryFilter::AddUUID(const device::BluetoothUUID& uuid) {
- DCHECK(uuid.IsValid());
- for (const auto& uuid_it : uuids_) {
- if (*uuid_it == uuid)
- return;
+ for (const auto& device_filter : device_filters_) {
+ for (const auto& uuid : device_filter.uuids) {
+ out_uuids.insert(uuid);
+ }
}
+}
- uuids_.push_back(std::make_unique<device::BluetoothUUID>(uuid));
+void BluetoothDiscoveryFilter::AddDeviceFilter(
+ const BluetoothDiscoveryFilter::DeviceInfoFilter& device_filter) {
+ device_filters_.insert(device_filter);
}
void BluetoothDiscoveryFilter::CopyFrom(
const BluetoothDiscoveryFilter& filter) {
transport_ = filter.transport_;
- uuids_.clear();
- if (filter.uuids_.size()) {
- for (const auto& uuid : filter.uuids_)
- AddUUID(*uuid);
- }
+ device_filters_.clear();
+ for (const auto& device_filter : filter.device_filters_)
+ AddDeviceFilter(device_filter);
rssi_ = filter.rssi_;
pathloss_ = filter.pathloss_;
@@ -113,15 +125,13 @@ BluetoothDiscoveryFilter::Merge(
// if both filters have uuids, them merge them. Otherwise uuids filter should
// be left empty
- if (filter_a->uuids_.size() && filter_b->uuids_.size()) {
- std::set<device::BluetoothUUID> uuids;
- filter_a->GetUUIDs(uuids);
- for (auto& uuid : uuids)
- result->AddUUID(uuid);
-
- filter_b->GetUUIDs(uuids);
- for (auto& uuid : uuids)
- result->AddUUID(uuid);
+ if (!filter_a->device_filters_.empty() &&
+ !filter_b->device_filters_.empty()) {
+ for (const auto& device_filter : filter_a->device_filters_)
+ result->AddDeviceFilter(device_filter);
+
+ for (const auto& device_filter : filter_b->device_filters_)
+ result->AddDeviceFilter(device_filter);
}
if ((filter_a->rssi_ && filter_b->pathloss_) ||
@@ -155,17 +165,14 @@ bool BluetoothDiscoveryFilter::Equals(
if (transport_ != other.transport_)
return false;
- std::set<device::BluetoothUUID> uuids_a, uuids_b;
- GetUUIDs(uuids_a);
- other.GetUUIDs(uuids_b);
- if (uuids_a != uuids_b)
+ if (device_filters_ != other.device_filters_)
return false;
return true;
}
bool BluetoothDiscoveryFilter::IsDefault() const {
- return !(rssi_ || pathloss_ || uuids_.size() ||
+ return !(rssi_ || pathloss_ || !device_filters_.empty() ||
transport_ != BLUETOOTH_TRANSPORT_DUAL);
}
diff --git a/chromium/device/bluetooth/bluetooth_discovery_filter.h b/chromium/device/bluetooth/bluetooth_discovery_filter.h
index 77496359ec3..b76a37232d7 100644
--- a/chromium/device/bluetooth/bluetooth_discovery_filter.h
+++ b/chromium/device/bluetooth/bluetooth_discovery_filter.h
@@ -9,8 +9,10 @@
#include <memory>
#include <set>
+#include <string>
#include <vector>
+#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/optional.h"
#include "device/bluetooth/bluetooth_common.h"
@@ -19,13 +21,48 @@
namespace device {
-// Used to keep a discovery filter that can be used to limit reported devices.
+// *****************************************************************************
+// BluetoothDiscoveryFilter is a class which stores information used to filter
+// out Bluetooth devices at the operating system level while doing discovery.
+// If you want to filter by RSSI or path loss set them directly in the class
+// with the SetRSSI() and SetPathloss() functions. However, if you are looking
+// for a device with a particular name and/or set of services you must add a
+// DeviceInfoFilter.
+// Here is an example usage for DeviceInfoFilters:
+//
+// BluetoothDiscoveryFilter discovery_filter(BLUETOOTH_TRANSPORT_LE);
+// BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+// device_filter.uuids.insert(BluetoothUUID("1019"));
+// device_filter.uuids.insert(BluetoothUUID("1020"));
+// discovery_filter.AddDeviceFilter(device_filter);
+//
+// BluetoothDiscoveryFilter::DeviceInfoFilter device_filter2;
+// device_filter2.uuids.insert(BluetoothUUID("1021"));
+// device_filter2.name = "this device";
+// discovery_filter.AddDeviceFilter(device_filter2);
+//
+// When we add |device_filter| to |discovery_filter| our filter will only return
+// devices that have both the uuid 1019 AND 1020. When we add |device_filter2|
+// we will then allow devices though that have either (uuid 1019 AND 1020) OR
+// (uuid 1021 and a device name of "this device").
+// *****************************************************************************
+
class DEVICE_BLUETOOTH_EXPORT BluetoothDiscoveryFilter {
public:
BluetoothDiscoveryFilter();
BluetoothDiscoveryFilter(BluetoothTransport transport);
~BluetoothDiscoveryFilter();
+ struct DEVICE_BLUETOOTH_EXPORT DeviceInfoFilter {
+ DeviceInfoFilter();
+ DeviceInfoFilter(const DeviceInfoFilter& other);
+ ~DeviceInfoFilter();
+ bool operator==(const DeviceInfoFilter& other) const;
+ bool operator<(const DeviceInfoFilter& other) const;
+ base::flat_set<device::BluetoothUUID> uuids;
+ std::string name;
+ };
+
// These getters return true when given field is set in filter, and copy this
// value to |out_*| parameter. If value is not set, returns false.
// These setters assign given value to proper filter field.
@@ -38,12 +75,14 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothDiscoveryFilter {
BluetoothTransport GetTransport() const;
void SetTransport(BluetoothTransport transport);
- // Make |out_uuids| represent all uuids assigned to this filter.
+ // Make |out_uuids| represent all uuids in the |device_filters_| set.
void GetUUIDs(std::set<device::BluetoothUUID>& out_uuids) const;
- // Add UUID to internal UUIDs filter. If UUIDs filter doesn't exist, it will
- // be created.
- void AddUUID(const device::BluetoothUUID& uuid);
+ // Add new DeviceInfoFilter to our array of DeviceInfoFilters,
+ void AddDeviceFilter(const DeviceInfoFilter& device_filter);
+
+ // Returns a const pointer of our list of DeviceInfoFilters, device_filters_.
+ const base::flat_set<DeviceInfoFilter>* GetDeviceFilters();
// Copy content of |filter| and assigns it to this filter.
void CopyFrom(const BluetoothDiscoveryFilter& filter);
@@ -64,7 +103,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothDiscoveryFilter {
base::Optional<int16_t> rssi_;
base::Optional<uint16_t> pathloss_;
BluetoothTransport transport_;
- std::vector<std::unique_ptr<device::BluetoothUUID>> uuids_;
+ base::flat_set<DeviceInfoFilter> device_filters_;
DISALLOW_COPY_AND_ASSIGN(BluetoothDiscoveryFilter);
};
diff --git a/chromium/device/bluetooth/bluetooth_discovery_filter_unittest.cc b/chromium/device/bluetooth/bluetooth_discovery_filter_unittest.cc
index 53c19acebf9..1b24f0df217 100644
--- a/chromium/device/bluetooth/bluetooth_discovery_filter_unittest.cc
+++ b/chromium/device/bluetooth/bluetooth_discovery_filter_unittest.cc
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "device/bluetooth/bluetooth_common.h"
#include "device/bluetooth/bluetooth_discovery_session.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -16,6 +17,8 @@ namespace {
const device::BluetoothUUID uuid1003("1003");
const device::BluetoothUUID uuid1004("1004");
const device::BluetoothUUID uuid1020("1020");
+const device::BluetoothUUID uuid1057("1027");
+const device::BluetoothUUID uuid1019("1019");
} // namespace
@@ -24,20 +27,46 @@ namespace device {
TEST(BluetoothDiscoveryFilterTest, Equal) {
BluetoothDiscoveryFilter df1(BLUETOOTH_TRANSPORT_CLASSIC);
df1.SetRSSI(-65);
- df1.AddUUID(uuid1020);
- df1.AddUUID(uuid1003);
+ {
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(uuid1020);
+ device_filter.uuids.insert(uuid1057);
+ df1.AddDeviceFilter(device_filter);
+ }
+ {
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(uuid1003);
+ df1.AddDeviceFilter(device_filter);
+ }
BluetoothDiscoveryFilter df2(BLUETOOTH_TRANSPORT_CLASSIC);
df2.SetRSSI(-65);
- df2.AddUUID(uuid1020);
- df2.AddUUID(uuid1004);
+ {
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(uuid1020);
+ device_filter.uuids.insert(uuid1057);
+ df2.AddDeviceFilter(device_filter);
+ }
+ {
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(uuid1004);
+ df2.AddDeviceFilter(device_filter);
+ }
// uuids are not same, so should fail
ASSERT_FALSE(df1.Equals(df2));
// make filters equal
- df1.AddUUID(uuid1004);
- df2.AddUUID(uuid1003);
+ {
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(uuid1004);
+ df1.AddDeviceFilter(device_filter);
+ }
+ {
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(uuid1003);
+ df2.AddDeviceFilter(device_filter);
+ }
ASSERT_TRUE(df1.Equals(df2));
// now transport don't match
@@ -52,11 +81,41 @@ TEST(BluetoothDiscoveryFilterTest, Equal) {
df1.SetRSSI(-30);
ASSERT_FALSE(df1.Equals(df2));
+ // set RSSIs to be the same and confirm that
+ // the filters match to prepare for next test
+ df2.SetRSSI(-30);
+ ASSERT_TRUE(df1.Equals(df2));
+
+ // add filters with the same uuid but different names
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter_no_name;
+ device_filter_no_name.uuids.insert(uuid1019);
+ df1.AddDeviceFilter(device_filter_no_name);
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter_name;
+ device_filter_name.uuids.insert(uuid1019);
+ device_filter_name.name = "device 1019";
+ df2.AddDeviceFilter(device_filter_name);
+
+ // with different names the filters should not be the same
+ ASSERT_FALSE(df1.Equals(df2));
+
BluetoothDiscoveryFilter df3(BLUETOOTH_TRANSPORT_CLASSIC);
df3.SetPathloss(45);
- df3.AddUUID(uuid1020);
- df3.AddUUID(uuid1003);
- df3.AddUUID(uuid1004);
+ {
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(uuid1020);
+ device_filter.uuids.insert(uuid1057);
+ df3.AddDeviceFilter(device_filter);
+ }
+ {
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(uuid1003);
+ df3.AddDeviceFilter(device_filter);
+ }
+ {
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(uuid1004);
+ df3.AddDeviceFilter(device_filter);
+ }
// Having Pathloss and RSSI set in two different filter makes them unequal.
ASSERT_FALSE(df1.Equals(df3));
@@ -65,8 +124,17 @@ TEST(BluetoothDiscoveryFilterTest, Equal) {
TEST(BluetoothDiscoveryFilterTest, CopyFrom) {
BluetoothDiscoveryFilter df1(BLUETOOTH_TRANSPORT_CLASSIC);
df1.SetRSSI(-65);
- df1.AddUUID(uuid1020);
- df1.AddUUID(uuid1003);
+ {
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(uuid1020);
+ device_filter.uuids.insert(uuid1057);
+ df1.AddDeviceFilter(device_filter);
+ }
+ {
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(uuid1003);
+ df1.AddDeviceFilter(device_filter);
+ }
BluetoothDiscoveryFilter df2(BLUETOOTH_TRANSPORT_CLASSIC);
@@ -82,18 +150,37 @@ TEST(BluetoothDiscoveryFilterTest, CopyFrom) {
EXPECT_EQ(BLUETOOTH_TRANSPORT_CLASSIC, df2.GetTransport());
df2.GetUUIDs(out_uuids);
- EXPECT_TRUE(out_uuids.find(uuid1020) != out_uuids.end());
- EXPECT_TRUE(out_uuids.find(uuid1003) != out_uuids.end());
+ EXPECT_THAT(out_uuids, testing::Contains(uuid1020));
+ EXPECT_THAT(out_uuids, testing::Contains(uuid1057));
+ EXPECT_THAT(out_uuids, testing::Contains(uuid1003));
}
TEST(BluetoothDiscoveryFilterTest, MergeUUIDs) {
BluetoothDiscoveryFilter df1(BLUETOOTH_TRANSPORT_LE);
- df1.AddUUID(uuid1020);
- df1.AddUUID(uuid1003);
+ {
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(uuid1020);
+ device_filter.uuids.insert(uuid1057);
+ df1.AddDeviceFilter(device_filter);
+ }
+ {
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(uuid1003);
+ df1.AddDeviceFilter(device_filter);
+ }
BluetoothDiscoveryFilter df2(BLUETOOTH_TRANSPORT_LE);
- df2.AddUUID(uuid1020);
- df2.AddUUID(uuid1004);
+ {
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(uuid1020);
+ device_filter.uuids.insert(uuid1057);
+ df2.AddDeviceFilter(device_filter);
+ }
+ {
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(uuid1004);
+ df2.AddDeviceFilter(device_filter);
+ }
std::unique_ptr<BluetoothDiscoveryFilter> df3 =
BluetoothDiscoveryFilter::Merge(&df1, &df2);
diff --git a/chromium/device/bluetooth/bluetooth_task_manager_win.cc b/chromium/device/bluetooth/bluetooth_task_manager_win.cc
index 26599ed71dd..91b9f7229a2 100644
--- a/chromium/device/bluetooth/bluetooth_task_manager_win.cc
+++ b/chromium/device/bluetooth/bluetooth_task_manager_win.cc
@@ -455,12 +455,8 @@ void BluetoothTaskManagerWin::StopDiscovery() {
void BluetoothTaskManagerWin::DiscoverDevices(int timeout_multiplier) {
DCHECK(bluetooth_task_runner_->RunsTasksInCurrentSequence());
- if (!discovering_ || !classic_wrapper_->HasHandle()) {
- ui_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&BluetoothTaskManagerWin::OnDiscoveryStopped, this));
+ if (!discovering_ || !classic_wrapper_->HasHandle())
return;
- }
std::vector<std::unique_ptr<DeviceState>> device_list;
if (SearchDevices(timeout_multiplier, false, &device_list)) {
diff --git a/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc b/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
index 1b687557e72..e216180adc0 100644
--- a/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
+++ b/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
@@ -1476,6 +1476,10 @@ void BluetoothAdapterBlueZ::OnPropertyChangeCompleted(
}
}
+base::WeakPtr<BluetoothAdapter> BluetoothAdapterBlueZ::GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
// BluetoothAdapterBlueZ should override SetPowered() instead.
bool BluetoothAdapterBlueZ::SetPoweredImpl(bool powered) {
NOTREACHED();
diff --git a/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.h b/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.h
index 0734e5f0e27..8e8d5f24ea1 100644
--- a/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.h
+++ b/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.h
@@ -74,7 +74,7 @@ class BluetoothPairingBlueZ;
//
// When adding methods to this class verify shutdown behavior in
// BluetoothBlueZTest, Shutdown.
-class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterBlueZ
+class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterBlueZ final
: public device::BluetoothAdapter,
public bluez::BluetoothAdapterClient::Observer,
public bluez::BluetoothDeviceClient::Observer,
@@ -372,6 +372,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterBlueZ
bool success);
// BluetoothAdapter:
+ base::WeakPtr<BluetoothAdapter> GetWeakPtr() override;
bool SetPoweredImpl(bool powered) override;
void StartScanWithFilter(
std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter,
diff --git a/chromium/device/bluetooth/bluez/bluetooth_advertisement_bluez_unittest.cc b/chromium/device/bluetooth/bluez/bluetooth_advertisement_bluez_unittest.cc
index 292b9e2e527..d84b5afed1d 100644
--- a/chromium/device/bluetooth/bluez/bluetooth_advertisement_bluez_unittest.cc
+++ b/chromium/device/bluetooth/bluez/bluetooth_advertisement_bluez_unittest.cc
@@ -12,8 +12,8 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/test/task_environment.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_advertisement.h"
@@ -166,7 +166,8 @@ class BluetoothAdvertisementBlueZTest : public testing::Test {
BluetoothAdvertisement::ErrorCode last_error_code_;
- base::MessageLoopForIO message_loop_;
+ base::test::SingleThreadTaskEnvironment task_environment_{
+ base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
std::unique_ptr<TestBluetoothAdvertisementObserver> observer_;
scoped_refptr<BluetoothAdapter> adapter_;
diff --git a/chromium/device/bluetooth/bluez/bluetooth_bluez_unittest.cc b/chromium/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
index 19585df3874..e7f8620c018 100644
--- a/chromium/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
+++ b/chromium/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
@@ -313,7 +313,7 @@ class BluetoothBlueZTest : public testing::Test {
}
protected:
- base::test::TaskEnvironment task_environment_;
+ base::test::SingleThreadTaskEnvironment task_environment_;
bluez::FakeBluetoothAdapterClient* fake_bluetooth_adapter_client_;
bluez::FakeBluetoothDeviceClient* fake_bluetooth_device_client_;
scoped_refptr<BluetoothAdapter> adapter_;
@@ -1334,15 +1334,18 @@ TEST_F(BluetoothBlueZTest, SetDiscoveryFilterBeforeStartDiscovery) {
TestBluetoothAdapterObserver observer(adapter_);
- BluetoothDiscoveryFilter* df =
- new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_LE);
- df->SetRSSI(-60);
- df->AddUUID(BluetoothUUID("1000"));
- std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter(df);
+ auto discovery_filter = std::make_unique<BluetoothDiscoveryFilter>(
+ device::BLUETOOTH_TRANSPORT_LE);
+ discovery_filter->SetRSSI(-60);
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(BluetoothUUID("1000"));
+ discovery_filter->AddDeviceFilter(std::move(device_filter));
adapter_->SetPowered(
true, base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)),
base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this)));
+
+ auto* comparison_filter_holder = discovery_filter.get();
adapter_->StartDiscoverySessionWithFilter(
std::move(discovery_filter),
base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback,
@@ -1357,7 +1360,8 @@ TEST_F(BluetoothBlueZTest, SetDiscoveryFilterBeforeStartDiscovery) {
ASSERT_TRUE(adapter_->IsDiscovering());
ASSERT_EQ((size_t)1, discovery_sessions_.size());
ASSERT_TRUE(discovery_sessions_[0]->IsActive());
- ASSERT_TRUE(df->Equals(*discovery_sessions_[0]->GetDiscoveryFilter()));
+ ASSERT_TRUE(comparison_filter_holder->Equals(
+ *discovery_sessions_[0]->GetDiscoveryFilter()));
auto* filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter();
EXPECT_NE(nullptr, filter);
@@ -1394,11 +1398,12 @@ TEST_F(BluetoothBlueZTest, SetDiscoveryFilterBeforeStartDiscoveryFail) {
TestBluetoothAdapterObserver observer(adapter_);
- BluetoothDiscoveryFilter* df =
- new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_LE);
- df->SetRSSI(-60);
- df->AddUUID(BluetoothUUID("1000"));
- std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter(df);
+ auto discovery_filter = std::make_unique<BluetoothDiscoveryFilter>(
+ device::BLUETOOTH_TRANSPORT_LE);
+ discovery_filter->SetRSSI(-60);
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(BluetoothUUID("1000"));
+ discovery_filter->AddDeviceFilter(std::move(device_filter));
adapter_->SetPowered(
true, base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)),
@@ -1445,25 +1450,30 @@ TEST_F(BluetoothBlueZTest, SetDiscoveryFilterBeforeStartDiscoveryMultiple) {
for (int i = 0; i < 3; i++) {
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter;
if (i == 0) {
- BluetoothDiscoveryFilter* df =
- new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_LE);
- df->SetRSSI(-85);
- df->AddUUID(BluetoothUUID("1000"));
- discovery_filter.reset(df);
+ discovery_filter = std::make_unique<BluetoothDiscoveryFilter>(
+ device::BLUETOOTH_TRANSPORT_LE);
+ discovery_filter->SetRSSI(-85);
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(BluetoothUUID("1000"));
+ discovery_filter->AddDeviceFilter(std::move(device_filter));
} else if (i == 1) {
- BluetoothDiscoveryFilter* df =
- new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_LE);
- df->SetRSSI(-60);
- df->AddUUID(BluetoothUUID("1020"));
- df->AddUUID(BluetoothUUID("1001"));
- discovery_filter.reset(df);
+ discovery_filter = std::make_unique<BluetoothDiscoveryFilter>(
+ device::BLUETOOTH_TRANSPORT_LE);
+ discovery_filter->SetRSSI(-60);
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(BluetoothUUID("1020"));
+ device_filter.uuids.insert(BluetoothUUID("1001"));
+ discovery_filter->AddDeviceFilter(std::move(device_filter));
} else if (i == 2) {
- BluetoothDiscoveryFilter* df =
- new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_LE);
- df->SetRSSI(-65);
- df->AddUUID(BluetoothUUID("1020"));
- df->AddUUID(BluetoothUUID("1003"));
- discovery_filter.reset(df);
+ discovery_filter = std::make_unique<BluetoothDiscoveryFilter>(
+ device::BLUETOOTH_TRANSPORT_LE);
+ discovery_filter->SetRSSI(-65);
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(BluetoothUUID("1020"));
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter2;
+ device_filter2.uuids.insert(BluetoothUUID("1003"));
+ discovery_filter->AddDeviceFilter(std::move(device_filter));
+ discovery_filter->AddDeviceFilter(std::move(device_filter2));
}
adapter_->StartDiscoverySessionWithFilter(
@@ -1569,25 +1579,30 @@ TEST_F(BluetoothBlueZTest, SetDiscoveryFilterBeforeStartDiscoveryMultiple) {
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter;
if (i == 0) {
- BluetoothDiscoveryFilter* df =
- new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_LE);
- df->SetRSSI(-85);
- df->AddUUID(BluetoothUUID("1000"));
- discovery_filter.reset(df);
+ discovery_filter = std::make_unique<BluetoothDiscoveryFilter>(
+ device::BLUETOOTH_TRANSPORT_LE);
+ discovery_filter->SetRSSI(-85);
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(BluetoothUUID("1000"));
+ discovery_filter->AddDeviceFilter(std::move(device_filter));
} else if (i == 1) {
- BluetoothDiscoveryFilter* df =
- new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_LE);
- df->SetRSSI(-60);
- df->AddUUID(BluetoothUUID("1020"));
- df->AddUUID(BluetoothUUID("1001"));
- discovery_filter.reset(df);
+ discovery_filter = std::make_unique<BluetoothDiscoveryFilter>(
+ device::BLUETOOTH_TRANSPORT_LE);
+ discovery_filter->SetRSSI(-60);
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(BluetoothUUID("1020"));
+ device_filter.uuids.insert(BluetoothUUID("1001"));
+ discovery_filter->AddDeviceFilter(std::move(device_filter));
} else if (i == 2) {
- BluetoothDiscoveryFilter* df =
- new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_LE);
- df->SetRSSI(-65);
- df->AddUUID(BluetoothUUID("1020"));
- df->AddUUID(BluetoothUUID("1003"));
- discovery_filter.reset(df);
+ discovery_filter = std::make_unique<BluetoothDiscoveryFilter>(
+ device::BLUETOOTH_TRANSPORT_LE);
+ discovery_filter->SetRSSI(-65);
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(BluetoothUUID("1020"));
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter2;
+ device_filter2.uuids.insert(BluetoothUUID("1003"));
+ discovery_filter->AddDeviceFilter(std::move(device_filter));
+ discovery_filter->AddDeviceFilter(std::move(device_filter2));
}
adapter_->StartDiscoverySessionWithFilter(
@@ -1668,7 +1683,9 @@ TEST_F(BluetoothBlueZTest, SetDiscoveryFilterMergingTest) {
BluetoothDiscoveryFilter* df =
new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_LE);
df->SetRSSI(-15);
- df->AddUUID(BluetoothUUID("1000"));
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(BluetoothUUID("1000"));
+ df->AddDeviceFilter(std::move(device_filter));
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter(df);
adapter_->StartDiscoverySessionWithFilter(
@@ -1688,8 +1705,10 @@ TEST_F(BluetoothBlueZTest, SetDiscoveryFilterMergingTest) {
df = new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_LE);
df->SetRSSI(-60);
- df->AddUUID(BluetoothUUID("1020"));
- df->AddUUID(BluetoothUUID("1001"));
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter2;
+ device_filter2.uuids.insert(BluetoothUUID("1020"));
+ device_filter2.uuids.insert(BluetoothUUID("1001"));
+ df->AddDeviceFilter(device_filter2);
discovery_filter = std::unique_ptr<BluetoothDiscoveryFilter>(df);
adapter_->StartDiscoverySessionWithFilter(
@@ -1712,8 +1731,12 @@ TEST_F(BluetoothBlueZTest, SetDiscoveryFilterMergingTest) {
BluetoothDiscoveryFilter* df3 =
new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_CLASSIC);
df3->SetRSSI(-65);
- df3->AddUUID(BluetoothUUID("1020"));
- df3->AddUUID(BluetoothUUID("1003"));
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter3;
+ device_filter3.uuids.insert(BluetoothUUID("1020"));
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter4;
+ device_filter4.uuids.insert(BluetoothUUID("1003"));
+ df3->AddDeviceFilter(device_filter3);
+ df3->AddDeviceFilter(device_filter4);
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter3(df3);
adapter_->StartDiscoverySessionWithFilter(
diff --git a/chromium/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc b/chromium/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc
index 21ccaa1578e..fc0bc6b40a5 100644
--- a/chromium/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc
+++ b/chromium/device/bluetooth/bluez/bluetooth_gatt_bluez_unittest.cc
@@ -84,6 +84,13 @@ bool ValuesEqual(const std::vector<uint8_t>& value0,
return true;
}
+void AddDeviceFilterWithUUID(BluetoothDiscoveryFilter* filter,
+ BluetoothUUID uuid) {
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(uuid);
+ filter->AddDeviceFilter(device_filter);
+}
+
} // namespace
class BluetoothGattBlueZTest : public testing::Test {
@@ -287,7 +294,7 @@ class BluetoothGattBlueZTest : public testing::Test {
base::RunLoop::QuitCurrentWhenIdleDeprecated();
}
- base::test::TaskEnvironment task_environment_;
+ base::test::SingleThreadTaskEnvironment task_environment_;
bluez::FakeBluetoothDeviceClient* fake_bluetooth_device_client_;
bluez::FakeBluetoothGattServiceClient* fake_bluetooth_gatt_service_client_;
@@ -324,7 +331,7 @@ TEST_F(BluetoothGattBlueZTest,
AddDualDevice();
BluetoothDiscoveryFilter discovery_filter(device::BLUETOOTH_TRANSPORT_LE);
- discovery_filter.AddUUID(kBatteryServiceUUID);
+ AddDeviceFilterWithUUID(&discovery_filter, kBatteryServiceUUID);
DeviceToUUIDs result =
adapter_->RetrieveGattConnectedDevicesWithDiscoveryFilter(
@@ -340,7 +347,9 @@ TEST_F(
BluetoothDevice* dual = AddDualDevice();
BluetoothDiscoveryFilter discovery_filter(device::BLUETOOTH_TRANSPORT_LE);
- discovery_filter.AddUUID(kGenericAccessServiceUUID);
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(kGenericAccessServiceUUID);
+ discovery_filter.AddDeviceFilter(device_filter);
DeviceToUUIDs result =
adapter_->RetrieveGattConnectedDevicesWithDiscoveryFilter(
@@ -357,7 +366,7 @@ TEST_F(
BluetoothDevice* dual = AddDualDevice();
BluetoothDiscoveryFilter discovery_filter(device::BLUETOOTH_TRANSPORT_LE);
- discovery_filter.AddUUID(kHeartRateServiceUUID);
+ AddDeviceFilterWithUUID(&discovery_filter, kHeartRateServiceUUID);
DeviceToUUIDs result =
adapter_->RetrieveGattConnectedDevicesWithDiscoveryFilter(
@@ -374,8 +383,8 @@ TEST_F(BluetoothGattBlueZTest,
BluetoothDevice* dual = AddDualDevice();
BluetoothDiscoveryFilter discovery_filter(device::BLUETOOTH_TRANSPORT_LE);
- discovery_filter.AddUUID(kGenericAccessServiceUUID);
- discovery_filter.AddUUID(kHeartRateServiceUUID);
+ AddDeviceFilterWithUUID(&discovery_filter, kGenericAccessServiceUUID);
+ AddDeviceFilterWithUUID(&discovery_filter, kHeartRateServiceUUID);
DeviceToUUIDs result =
adapter_->RetrieveGattConnectedDevicesWithDiscoveryFilter(
@@ -393,8 +402,12 @@ TEST_F(
AddLeDevice();
BluetoothDevice* dual = AddDualDevice();
BluetoothDiscoveryFilter discovery_filter(device::BLUETOOTH_TRANSPORT_LE);
- discovery_filter.AddUUID(kGenericAccessServiceUUID);
- discovery_filter.AddUUID(kBatteryServiceUUID);
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(kGenericAccessServiceUUID);
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter2;
+ device_filter2.uuids.insert(kBatteryServiceUUID);
+ discovery_filter.AddDeviceFilter(device_filter);
+ discovery_filter.AddDeviceFilter(device_filter2);
DeviceToUUIDs result =
adapter_->RetrieveGattConnectedDevicesWithDiscoveryFilter(
diff --git a/chromium/device/bluetooth/cast/bluetooth_adapter_cast.cc b/chromium/device/bluetooth/cast/bluetooth_adapter_cast.cc
index 343ee9ff143..71028ce2b53 100644
--- a/chromium/device/bluetooth/cast/bluetooth_adapter_cast.cc
+++ b/chromium/device/bluetooth/cast/bluetooth_adapter_cast.cc
@@ -180,6 +180,11 @@ BluetoothLocalGattService* BluetoothAdapterCast::GetGattService(
return nullptr;
}
+base::WeakPtr<BluetoothAdapter> BluetoothAdapterCast::GetWeakPtr() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return weak_factory_.GetWeakPtr();
+}
+
bool BluetoothAdapterCast::SetPoweredImpl(bool powered) {
NOTREACHED() << "This method is not invoked when SetPowered() is overridden.";
return true;
@@ -247,11 +252,6 @@ void BluetoothAdapterCast::RemovePairingDelegateInternal(
NOTIMPLEMENTED();
}
-base::WeakPtr<BluetoothAdapterCast> BluetoothAdapterCast::GetWeakPtr() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return weak_factory_.GetWeakPtr();
-}
-
void BluetoothAdapterCast::OnConnectChanged(
scoped_refptr<chromecast::bluetooth::RemoteDevice> device,
bool connected) {
diff --git a/chromium/device/bluetooth/cast/bluetooth_adapter_cast.h b/chromium/device/bluetooth/cast/bluetooth_adapter_cast.h
index 7be88e9982c..5f3b9fd60ce 100644
--- a/chromium/device/bluetooth/cast/bluetooth_adapter_cast.h
+++ b/chromium/device/bluetooth/cast/bluetooth_adapter_cast.h
@@ -89,6 +89,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterCast
const AdvertisementErrorCallback& error_callback) override;
BluetoothLocalGattService* GetGattService(
const std::string& identifier) const override;
+ base::WeakPtr<BluetoothAdapter> GetWeakPtr() override;
bool SetPoweredImpl(bool powered) override;
void StartScanWithFilter(
std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter,
@@ -100,12 +101,6 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterCast
void RemovePairingDelegateInternal(
BluetoothDevice::PairingDelegate* pairing_delegate) override;
- // Return a WeakPtr for this class. Must be called on the sequence on which
- // this class was created.
- // TODO(slan): Remove this once this class talks to a dedicated Bluetooth
- // service (b/76155468)
- base::WeakPtr<BluetoothAdapterCast> GetWeakPtr();
-
// |factory_cb| is used to inject a factory method from ChromecastService into
// this class. It will be invoked when Create() is called.
// TODO(slan): Remove this once this class talks to a dedicated Bluetooth
diff --git a/chromium/device/bluetooth/chromeos/bluetooth_utils.cc b/chromium/device/bluetooth/chromeos/bluetooth_utils.cc
index 3a5a84df481..dd5075c721e 100644
--- a/chromium/device/bluetooth/chromeos/bluetooth_utils.cc
+++ b/chromium/device/bluetooth/chromeos/bluetooth_utils.cc
@@ -84,6 +84,14 @@ BluetoothAdapter::DeviceList FilterUnknownDevices(
continue;
}
+ // Always filter out phones. There is no intended use case or Bluetooth
+ // profile in this context.
+ if (base::FeatureList::IsEnabled(
+ chromeos::features::kBluetoothPhoneFilter) &&
+ device->GetDeviceType() == BluetoothDeviceType::PHONE) {
+ continue;
+ }
+
switch (device->GetType()) {
// Device with invalid bluetooth transport is filtered out.
case BLUETOOTH_TRANSPORT_INVALID:
diff --git a/chromium/device/bluetooth/chromeos/bluetooth_utils_unittest.cc b/chromium/device/bluetooth/chromeos/bluetooth_utils_unittest.cc
index 468193532f2..b9c3d3dfd36 100644
--- a/chromium/device/bluetooth/chromeos/bluetooth_utils_unittest.cc
+++ b/chromium/device/bluetooth/chromeos/bluetooth_utils_unittest.cc
@@ -245,6 +245,17 @@ TEST_F(
0u /* num_expected_remaining_devices */);
}
+TEST_F(BluetoothUtilsTest,
+ TestFilterBluetoothDeviceList_FilterKnown_RemoveAppearancePhone) {
+ auto* mock_bluetooth_device =
+ AddMockBluetoothDeviceToAdapter(BLUETOOTH_TRANSPORT_DUAL);
+ ON_CALL(*mock_bluetooth_device, GetDeviceType)
+ .WillByDefault(testing::Return(BluetoothDeviceType::PHONE));
+
+ VerifyFilterBluetoothDeviceList(BluetoothFilterType::KNOWN,
+ 0u /* num_expected_remaining_devices */);
+}
+
TEST_F(BluetoothUtilsTest, TestGetBlockedLongTermKeys_ListIncludesBadLtks) {
// One nibble too long, one nibble too short, and one nibble just right.
std::string hex_key_1 = "000000000000000000000000000012345";
diff --git a/chromium/device/bluetooth/dbus/bluez_dbus_manager.cc b/chromium/device/bluetooth/dbus/bluez_dbus_manager.cc
index 853fe8a5106..4c3b949ebac 100644
--- a/chromium/device/bluetooth/dbus/bluez_dbus_manager.cc
+++ b/chromium/device/bluetooth/dbus/bluez_dbus_manager.cc
@@ -235,14 +235,9 @@ void BluezDBusManager::InitializeClients() {
}
std::string BluezDBusManager::GetBluetoothServiceName() {
- bool use_newblue = false;
-#if defined(OS_CHROMEOS)
- use_newblue = base::FeatureList::IsEnabled(device::kNewblueDaemon);
-#endif // defined(OS_CHROMEOS)
-
- return use_newblue
- ? bluetooth_object_manager::kBluetoothObjectManagerServiceName
- : bluez_object_manager::kBluezObjectManagerServiceName;
+ // TODO(b/145163508): Remove the NewBlue feature flag as Bluetooth service is
+ // now always BlueZ.
+ return bluez_object_manager::kBluezObjectManagerServiceName;
}
// static
diff --git a/chromium/device/bluetooth/device.cc b/chromium/device/bluetooth/device.cc
index 75c276ee759..41ef648d677 100644
--- a/chromium/device/bluetooth/device.cc
+++ b/chromium/device/bluetooth/device.cc
@@ -10,7 +10,7 @@
#include "base/strings/utf_string_conversions.h"
#include "device/bluetooth/device.h"
#include "device/bluetooth/public/mojom/gatt_result_type_converter.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
namespace bluetooth {
Device::~Device() {
@@ -20,12 +20,12 @@ Device::~Device() {
// static
void Device::Create(scoped_refptr<device::BluetoothAdapter> adapter,
std::unique_ptr<device::BluetoothGattConnection> connection,
- mojom::DeviceRequest request) {
+ mojo::PendingReceiver<mojom::Device> receiver) {
auto device_impl =
base::WrapUnique(new Device(adapter, std::move(connection)));
auto* device_ptr = device_impl.get();
- device_ptr->binding_ =
- mojo::MakeStrongBinding(std::move(device_impl), std::move(request));
+ device_ptr->receiver_ =
+ mojo::MakeSelfOwnedReceiver(std::move(device_impl), std::move(receiver));
}
// static
@@ -54,7 +54,7 @@ void Device::DeviceChanged(device::BluetoothAdapter* adapter,
}
if (!device->IsGattConnected()) {
- binding_->Close();
+ receiver_->Close();
}
}
@@ -72,7 +72,7 @@ void Device::GattServicesDiscovered(device::BluetoothAdapter* adapter,
}
void Device::Disconnect() {
- binding_->Close();
+ receiver_->Close();
}
void Device::GetInfo(GetInfoCallback callback) {
diff --git a/chromium/device/bluetooth/device.h b/chromium/device/bluetooth/device.h
index b74276b5644..953fb9bf097 100644
--- a/chromium/device/bluetooth/device.h
+++ b/chromium/device/bluetooth/device.h
@@ -19,7 +19,7 @@
#include "device/bluetooth/bluetooth_remote_gatt_descriptor.h"
#include "device/bluetooth/bluetooth_remote_gatt_service.h"
#include "device/bluetooth/public/mojom/device.mojom.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
namespace bluetooth {
@@ -37,7 +37,7 @@ class Device : public mojom::Device, public device::BluetoothAdapter::Observer {
static void Create(
scoped_refptr<device::BluetoothAdapter> adapter,
std::unique_ptr<device::BluetoothGattConnection> connection,
- mojom::DeviceRequest request);
+ mojo::PendingReceiver<mojom::Device> receiver);
// Creates a mojom::DeviceInfo using info from the given |device|.
static mojom::DeviceInfoPtr ConstructDeviceInfoStruct(
@@ -122,7 +122,7 @@ class Device : public mojom::Device, public device::BluetoothAdapter::Observer {
// The GATT connection to this device.
std::unique_ptr<device::BluetoothGattConnection> connection_;
- mojo::StrongBindingPtr<mojom::Device> binding_;
+ mojo::SelfOwnedReceiverRef<mojom::Device> receiver_;
// The services request queue which holds callbacks that are waiting for
// services to be discovered for this device.
diff --git a/chromium/device/bluetooth/device_unittest.cc b/chromium/device/bluetooth/device_unittest.cc
index b87b5df49b3..18336a406ee 100644
--- a/chromium/device/bluetooth/device_unittest.cc
+++ b/chromium/device/bluetooth/device_unittest.cc
@@ -19,6 +19,7 @@
#include "device/bluetooth/test/mock_bluetooth_gatt_characteristic.h"
#include "device/bluetooth/test/mock_bluetooth_gatt_connection.h"
#include "device/bluetooth/test/mock_bluetooth_gatt_service.h"
+#include "mojo/public/cpp/bindings/remote.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::Return;
@@ -121,9 +122,10 @@ class BluetoothInterfaceDeviceTest : public testing::Test {
auto connection = std::make_unique<NiceMockBluetoothGattConnection>(
adapter_, device_.GetAddress());
- Device::Create(adapter_, std::move(connection), mojo::MakeRequest(&proxy_));
+ Device::Create(adapter_, std::move(connection),
+ proxy_.BindNewPipeAndPassReceiver());
- proxy_.set_connection_error_handler(
+ proxy_.set_disconnect_handler(
base::BindOnce(&BluetoothInterfaceDeviceTest::OnConnectionError,
weak_factory_.GetWeakPtr()));
}
@@ -174,8 +176,7 @@ class BluetoothInterfaceDeviceTest : public testing::Test {
scoped_refptr<NiceMockBluetoothAdapter> adapter_;
NiceMockBluetoothDevice device_;
base::test::SingleThreadTaskEnvironment task_environment_;
- mojom::DevicePtr proxy_;
- mojo::StrongBindingPtr<mojom::Device> binding_ptr_;
+ mojo::Remote<mojom::Device> proxy_;
bool message_pipe_closed_ = false;
bool expect_device_service_deleted_ = false;
diff --git a/chromium/device/bluetooth/public/mojom/adapter.mojom b/chromium/device/bluetooth/public/mojom/adapter.mojom
index 2225cf58e97..cd79f593b48 100644
--- a/chromium/device/bluetooth/public/mojom/adapter.mojom
+++ b/chromium/device/bluetooth/public/mojom/adapter.mojom
@@ -55,7 +55,8 @@ interface Adapter {
// Creates a GATT connection to the device with |address| and returns a
// Device if the connection was succesful. The GATT connection is tied to the
// the lifetime of the Device message pipe.
- ConnectToDevice(string address) => (ConnectResult result, Device? device);
+ ConnectToDevice(string address) =>
+ (ConnectResult result, pending_remote<Device>? device);
// Retrieves the list of the devices known by the adapter including Connected
// Devices, GATT Connected Devices, Paired Devices and Devices discovered
@@ -66,11 +67,11 @@ interface Adapter {
GetInfo() => (AdapterInfo info);
// Sets the client that listens for the adapter's events.
- SetClient(AdapterClient client);
+ SetClient(pending_remote<AdapterClient> client);
// Requests the adapter to start a new discovery session. Returns null if
// session not created successfully.
- StartDiscoverySession() => (DiscoverySession? session);
+ StartDiscoverySession() => (pending_remote<DiscoverySession>? session);
};
interface AdapterClient {
diff --git a/chromium/device/bluetooth/public/mojom/test/fake_bluetooth.mojom b/chromium/device/bluetooth/public/mojom/test/fake_bluetooth.mojom
index 687425164c6..710be64b77d 100644
--- a/chromium/device/bluetooth/public/mojom/test/fake_bluetooth.mojom
+++ b/chromium/device/bluetooth/public/mojom/test/fake_bluetooth.mojom
@@ -81,7 +81,8 @@ interface FakeBluetooth {
SetLESupported(bool available) => ();
// Initializes a fake Central with |state| as the initial state.
- SimulateCentral(CentralState state) => (FakeCentral fake_central);
+ SimulateCentral(CentralState state) =>
+ (pending_remote<FakeCentral> fake_central);
// Evaluates whether all responses set by this API have been consumed by this
// central or otherwise. This includes responses set by:
diff --git a/chromium/device/fido/BUILD.gn b/chromium/device/fido/BUILD.gn
index d71340bd9f4..798345eb8ca 100644
--- a/chromium/device/fido/BUILD.gn
+++ b/chromium/device/fido/BUILD.gn
@@ -224,6 +224,8 @@ component("fido") {
"win/authenticator.h",
"win/discovery.cc",
"win/discovery.h",
+ "win/fake_webauthn_api.cc",
+ "win/fake_webauthn_api.h",
"win/logging.cc",
"win/logging.h",
"win/type_conversions.cc",
@@ -362,11 +364,4 @@ source_set("test_support") {
"mac/scoped_touch_id_test_environment.mm",
]
}
-
- if (is_win) {
- sources += [
- "win/fake_webauthn_api.cc",
- "win/fake_webauthn_api.h",
- ]
- }
}
diff --git a/chromium/device/fido/bio/enrollment_handler.cc b/chromium/device/fido/bio/enrollment_handler.cc
index a15d97b1e70..9ce4850b9d8 100644
--- a/chromium/device/fido/bio/enrollment_handler.cc
+++ b/chromium/device/fido/bio/enrollment_handler.cc
@@ -30,42 +30,32 @@ BioEnrollmentHandler::~BioEnrollmentHandler() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
-void BioEnrollmentHandler::GetModality(ResponseCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(authenticator_);
- authenticator_->GetModality(std::move(callback));
-}
-
-void BioEnrollmentHandler::GetSensorInfo(ResponseCallback callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(authenticator_);
- authenticator_->GetSensorInfo(std::move(callback));
-}
-
-void BioEnrollmentHandler::EnrollTemplate(SampleCallback sample_callback,
- StatusCallback completion_callback) {
+void BioEnrollmentHandler::EnrollTemplate(
+ SampleCallback sample_callback,
+ CompletionCallback completion_callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_EQ(state_, State::kReady);
+ state_ = State::kEnrolling;
authenticator_->BioEnrollFingerprint(
- *pin_token_response_, std::move(sample_callback),
- base::BindOnce(&BioEnrollmentHandler::OnEnrollTemplateFinished,
- weak_factory_.GetWeakPtr(),
- std::move(completion_callback)));
+ *pin_token_response_, /*template_id=*/base::nullopt,
+ base::BindOnce(&BioEnrollmentHandler::OnEnrollResponse,
+ weak_factory_.GetWeakPtr(), std::move(sample_callback),
+ std::move(completion_callback),
+ /*current_template_id=*/base::nullopt));
}
-void BioEnrollmentHandler::Cancel(StatusCallback callback) {
+void BioEnrollmentHandler::CancelEnrollment() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- // Must CTAPHID_CANCEL before cancelCurrentEnrollment so the
- // authenticator doesn't queue the enrollment cancel behind
- // an ongoing enrollment.
+ DCHECK_EQ(state_, State::kEnrolling);
+ state_ = State::kEnrollingPendingCancel;
authenticator_->Cancel();
- authenticator_->BioEnrollCancel(
- base::BindOnce(&BioEnrollmentHandler::OnCancel,
- weak_factory_.GetWeakPtr(), std::move(callback)));
}
void BioEnrollmentHandler::EnumerateTemplates(EnumerationCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(pin_token_response_);
+ DCHECK_EQ(state_, State::kReady);
+ state_ = State::kEnumerating;
authenticator_->BioEnrollEnumerate(
*pin_token_response_,
base::BindOnce(&BioEnrollmentHandler::OnEnumerateTemplates,
@@ -76,23 +66,30 @@ void BioEnrollmentHandler::RenameTemplate(std::vector<uint8_t> template_id,
std::string name,
StatusCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_EQ(state_, State::kReady);
+ state_ = State::kRenaming;
authenticator_->BioEnrollRename(
*pin_token_response_, std::move(template_id), std::move(name),
- base::BindOnce(&BioEnrollmentHandler::OnStatusCallback,
+ base::BindOnce(&BioEnrollmentHandler::OnRenameTemplate,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
void BioEnrollmentHandler::DeleteTemplate(std::vector<uint8_t> template_id,
StatusCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_EQ(state_, State::kReady);
+ state_ = State::kDeleting;
authenticator_->BioEnrollDelete(
*pin_token_response_, std::move(template_id),
- base::BindOnce(&BioEnrollmentHandler::OnStatusCallback,
+ base::BindOnce(&BioEnrollmentHandler::OnDeleteTemplate,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
void BioEnrollmentHandler::DispatchRequest(FidoAuthenticator* authenticator) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (state_ != State::kWaitingForTouch) {
+ return;
+ }
authenticator->GetTouch(base::BindOnce(&BioEnrollmentHandler::OnTouch,
weak_factory_.GetWeakPtr(),
authenticator));
@@ -103,15 +100,20 @@ void BioEnrollmentHandler::AuthenticatorRemoved(
FidoAuthenticator* authenticator) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
FidoRequestHandlerBase::AuthenticatorRemoved(discovery, authenticator);
- if (authenticator_ != authenticator) {
+ if (authenticator_ != authenticator || state_ == State::kFinished) {
return;
}
authenticator_ = nullptr;
- std::move(error_callback_).Run(BioEnrollmentStatus::kSuccess);
+ Finish(BioEnrollmentStatus::kSuccess);
}
void BioEnrollmentHandler::OnTouch(FidoAuthenticator* authenticator) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (state_ != State::kWaitingForTouch) {
+ return;
+ }
+
CancelActiveAuthenticators(authenticator->GetId());
if (!authenticator->Options() ||
@@ -121,40 +123,39 @@ void BioEnrollmentHandler::OnTouch(FidoAuthenticator* authenticator) {
authenticator->Options()->bio_enrollment_availability_preview ==
AuthenticatorSupportedOptions::BioEnrollmentAvailability::
kNotSupported)) {
- std::move(error_callback_)
- .Run(BioEnrollmentStatus::kAuthenticatorMissingBioEnrollment);
+ Finish(BioEnrollmentStatus::kAuthenticatorMissingBioEnrollment);
return;
}
if (authenticator->Options()->client_pin_availability !=
AuthenticatorSupportedOptions::ClientPinAvailability::
kSupportedAndPinSet) {
- std::move(error_callback_).Run(BioEnrollmentStatus::kNoPINSet);
+ Finish(BioEnrollmentStatus::kNoPINSet);
return;
}
authenticator_ = authenticator;
+ state_ = State::kGettingRetries;
authenticator_->GetRetries(base::BindOnce(
&BioEnrollmentHandler::OnRetriesResponse, weak_factory_.GetWeakPtr()));
}
void BioEnrollmentHandler::OnRetriesResponse(
- CtapDeviceResponseCode code,
+ CtapDeviceResponseCode status,
base::Optional<pin::RetriesResponse> response) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (!response || code != CtapDeviceResponseCode::kSuccess) {
- FIDO_LOG(DEBUG) << "OnRetriesResponse failed with response code "
- << static_cast<int>(code);
- std::move(error_callback_)
- .Run(BioEnrollmentStatus::kAuthenticatorResponseInvalid);
+ DCHECK_EQ(state_, State::kGettingRetries);
+ if (!response || status != CtapDeviceResponseCode::kSuccess) {
+ Finish(BioEnrollmentStatus::kAuthenticatorResponseInvalid);
return;
}
if (response->retries == 0) {
- std::move(error_callback_).Run(BioEnrollmentStatus::kHardPINBlock);
+ Finish(BioEnrollmentStatus::kHardPINBlock);
return;
}
+ state_ = State::kWaitingForPIN;
get_pin_callback_.Run(response->retries,
base::BindOnce(&BioEnrollmentHandler::OnHavePIN,
weak_factory_.GetWeakPtr()));
@@ -162,6 +163,8 @@ void BioEnrollmentHandler::OnRetriesResponse(
void BioEnrollmentHandler::OnHavePIN(std::string pin) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_EQ(state_, State::kWaitingForPIN);
+ state_ = State::kGettingEphemeralKey;
authenticator_->GetEphemeralKey(
base::BindOnce(&BioEnrollmentHandler::OnHaveEphemeralKey,
weak_factory_.GetWeakPtr(), std::move(pin)));
@@ -169,16 +172,17 @@ void BioEnrollmentHandler::OnHavePIN(std::string pin) {
void BioEnrollmentHandler::OnHaveEphemeralKey(
std::string pin,
- CtapDeviceResponseCode code,
+ CtapDeviceResponseCode status,
base::Optional<pin::KeyAgreementResponse> response) {
- if (code != CtapDeviceResponseCode::kSuccess) {
- FIDO_LOG(DEBUG) << "OnHaveEphemeralKey failed with response code "
- << static_cast<int>(code);
- std::move(error_callback_)
- .Run(BioEnrollmentStatus::kAuthenticatorResponseInvalid);
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_EQ(State::kGettingEphemeralKey, state_);
+
+ if (status != CtapDeviceResponseCode::kSuccess) {
+ Finish(BioEnrollmentStatus::kAuthenticatorResponseInvalid);
return;
}
+ state_ = State::kGettingPINToken;
authenticator_->GetPINToken(
std::move(pin), *response,
base::BindOnce(&BioEnrollmentHandler::OnHavePINToken,
@@ -186,78 +190,148 @@ void BioEnrollmentHandler::OnHaveEphemeralKey(
}
void BioEnrollmentHandler::OnHavePINToken(
- CtapDeviceResponseCode code,
+ CtapDeviceResponseCode status,
base::Optional<pin::TokenResponse> response) {
- switch (code) {
- case CtapDeviceResponseCode::kCtap2ErrPinInvalid:
- authenticator_->GetRetries(
- base::BindOnce(&BioEnrollmentHandler::OnRetriesResponse,
- weak_factory_.GetWeakPtr()));
- return;
- case CtapDeviceResponseCode::kCtap2ErrPinAuthBlocked:
- std::move(error_callback_).Run(BioEnrollmentStatus::kSoftPINBlock);
- return;
- case CtapDeviceResponseCode::kCtap2ErrPinBlocked:
- std::move(error_callback_).Run(BioEnrollmentStatus::kHardPINBlock);
- return;
- default:
- std::move(error_callback_)
- .Run(BioEnrollmentStatus::kAuthenticatorResponseInvalid);
- return;
- case CtapDeviceResponseCode::kSuccess:
- // fall through on success
- break;
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_EQ(state_, State::kGettingPINToken);
+
+ if (status != CtapDeviceResponseCode::kSuccess) {
+ switch (status) {
+ case CtapDeviceResponseCode::kCtap2ErrPinInvalid:
+ state_ = State::kGettingRetries;
+ authenticator_->GetRetries(
+ base::BindOnce(&BioEnrollmentHandler::OnRetriesResponse,
+ weak_factory_.GetWeakPtr()));
+ return;
+ case CtapDeviceResponseCode::kCtap2ErrPinAuthBlocked:
+ Finish(BioEnrollmentStatus::kSoftPINBlock);
+ return;
+ case CtapDeviceResponseCode::kCtap2ErrPinBlocked:
+ Finish(BioEnrollmentStatus::kHardPINBlock);
+ return;
+ default:
+ Finish(BioEnrollmentStatus::kAuthenticatorResponseInvalid);
+ return;
+ }
}
+ state_ = State::kReady;
pin_token_response_ = std::move(response);
std::move(ready_callback_).Run();
}
-void BioEnrollmentHandler::OnEnrollTemplateFinished(
- StatusCallback callback,
- CtapDeviceResponseCode code,
+void BioEnrollmentHandler::OnEnrollResponse(
+ SampleCallback sample_callback,
+ CompletionCallback completion_callback,
+ base::Optional<std::vector<uint8_t>> current_template_id,
+ CtapDeviceResponseCode status,
base::Optional<BioEnrollmentResponse> response) {
- if (code == CtapDeviceResponseCode::kSuccess &&
- (!response || !response->last_status || !response->remaining_samples)) {
- // Response is incomplete or invalid.
- std::move(callback).Run(CtapDeviceResponseCode::kCtap2ErrOther);
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(state_ == State::kEnrolling ||
+ state_ == State::kEnrollingPendingCancel);
+
+ if (state_ == State::kEnrollingPendingCancel) {
+ state_ = State::kCancellingEnrollment;
+ authenticator_->BioEnrollCancel(base::BindOnce(
+ &BioEnrollmentHandler::OnCancel, weak_factory_.GetWeakPtr(),
+ std::move(completion_callback)));
+ return;
+ }
+
+ if (status != CtapDeviceResponseCode::kSuccess) {
+ state_ = State::kReady;
+ std::move(completion_callback).Run(status, {});
return;
}
- FIDO_LOG(DEBUG) << "Finished bio enrollment with response code "
- << static_cast<int>(code);
- std::move(callback).Run(code);
+
+ if (!response || !response->last_status || !response->remaining_samples) {
+ Finish(BioEnrollmentStatus::kAuthenticatorResponseInvalid);
+ return;
+ }
+
+ if (!current_template_id) {
+ if (!response->template_id) {
+ // The templateId response field is required in the first response of each
+ // enrollment.
+ Finish(BioEnrollmentStatus::kAuthenticatorResponseInvalid);
+ return;
+ }
+ current_template_id = *response->template_id;
+ }
+
+ if (*response->remaining_samples > 0) {
+ // FidoAuthenticator automatically requests the next sample and
+ // will invoke this method again on response.
+ sample_callback.Run(*response->last_status, *response->remaining_samples);
+ authenticator_->BioEnrollFingerprint(
+ *pin_token_response_, current_template_id,
+ base::BindOnce(&BioEnrollmentHandler::OnEnrollResponse,
+ weak_factory_.GetWeakPtr(), std::move(sample_callback),
+ std::move(completion_callback), current_template_id));
+ return;
+ }
+
+ state_ = State::kReady;
+ std::move(completion_callback)
+ .Run(CtapDeviceResponseCode::kSuccess, std::move(*current_template_id));
}
-void BioEnrollmentHandler::OnCancel(StatusCallback callback,
- CtapDeviceResponseCode code,
+void BioEnrollmentHandler::OnCancel(CompletionCallback callback,
+ CtapDeviceResponseCode status,
base::Optional<BioEnrollmentResponse>) {
- std::move(callback).Run(code);
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_EQ(state_, State::kCancellingEnrollment);
+ state_ = State::kReady;
+ std::move(callback).Run(CtapDeviceResponseCode::kCtap2ErrKeepAliveCancel, {});
}
void BioEnrollmentHandler::OnEnumerateTemplates(
EnumerationCallback callback,
- CtapDeviceResponseCode code,
+ CtapDeviceResponseCode status,
base::Optional<BioEnrollmentResponse> response) {
- if (code != CtapDeviceResponseCode::kSuccess) {
- // Response is not valid if operation was not successful.
- // Note that an empty enumeration returns kCtap2ErrInvalidOption.
- std::move(callback).Run(code, base::nullopt);
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_EQ(state_, State::kEnumerating);
+
+ state_ = State::kReady;
+
+ if (status != CtapDeviceResponseCode::kSuccess) {
+ std::move(callback).Run(status, base::nullopt);
return;
}
+
if (!response || !response->template_infos) {
- // Response must have template_infos.
- std::move(callback).Run(CtapDeviceResponseCode::kCtap2ErrOther,
- base::nullopt);
+ Finish(BioEnrollmentStatus::kAuthenticatorResponseInvalid);
return;
}
- std::move(callback).Run(code, std::move(*response->template_infos));
+
+ std::move(callback).Run(status, std::move(*response->template_infos));
+}
+
+void BioEnrollmentHandler::OnRenameTemplate(
+ StatusCallback callback,
+ CtapDeviceResponseCode status,
+ base::Optional<BioEnrollmentResponse> response) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_EQ(state_, State::kRenaming);
+ state_ = State::kReady;
+ std::move(callback).Run(status);
}
-void BioEnrollmentHandler::OnStatusCallback(
+void BioEnrollmentHandler::OnDeleteTemplate(
StatusCallback callback,
- CtapDeviceResponseCode code,
+ CtapDeviceResponseCode status,
base::Optional<BioEnrollmentResponse> response) {
- std::move(callback).Run(code);
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_EQ(state_, State::kDeleting);
+ state_ = State::kReady;
+ std::move(callback).Run(status);
+}
+
+void BioEnrollmentHandler::Finish(BioEnrollmentStatus status) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK_NE(state_, State::kFinished);
+ state_ = State::kFinished;
+ std::move(error_callback_).Run(status);
}
} // namespace device
diff --git a/chromium/device/fido/bio/enrollment_handler.h b/chromium/device/fido/bio/enrollment_handler.h
index 00024a6241d..6118710b78d 100644
--- a/chromium/device/fido/bio/enrollment_handler.h
+++ b/chromium/device/fido/bio/enrollment_handler.h
@@ -28,22 +28,26 @@ enum class BioEnrollmentStatus {
kAuthenticatorMissingBioEnrollment,
};
+// BioEnrollmentHandler exercises the CTAP2.1 authenticatorBioEnrollment
+// sub-protocol for enrolling biometric templates on external authenticators
+// supporting internal UV.
class COMPONENT_EXPORT(DEVICE_FIDO) BioEnrollmentHandler
: public FidoRequestHandlerBase {
public:
+ using TemplateId = std::vector<uint8_t>;
+
using ErrorCallback = base::OnceCallback<void(BioEnrollmentStatus)>;
using GetPINCallback =
base::RepeatingCallback<void(int64_t retries,
base::OnceCallback<void(std::string)>)>;
- using ResponseCallback =
- base::OnceCallback<void(CtapDeviceResponseCode,
- base::Optional<BioEnrollmentResponse>)>;
using StatusCallback = base::OnceCallback<void(CtapDeviceResponseCode)>;
using EnumerationCallback = base::OnceCallback<void(
CtapDeviceResponseCode,
- base::Optional<std::map<std::vector<uint8_t>, std::string>>)>;
+ base::Optional<std::map<TemplateId, std::string>>)>;
using SampleCallback =
base::RepeatingCallback<void(BioEnrollmentSampleStatus, uint8_t)>;
+ using CompletionCallback =
+ base::OnceCallback<void(CtapDeviceResponseCode, TemplateId)>;
BioEnrollmentHandler(
service_manager::Connector* connector,
@@ -54,14 +58,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) BioEnrollmentHandler
FidoDiscoveryFactory* factory);
~BioEnrollmentHandler() override;
- // Returns the modality of the authenticator's user verification.
- // Currently, the only valid modality is fingerprint.
- void GetModality(ResponseCallback);
-
- // Returns fingerprint sensor info for the authenticator.
- // This includes number of required samples to enroll and sensor type.
- void GetSensorInfo(ResponseCallback);
-
// Enrolls a new fingerprint template. The user must provide the required
// number of samples by touching the authenticator's sensor repeatedly.
// After each sample, or a timeout, |sample_callback| is invoked with the
@@ -69,11 +65,12 @@ class COMPONENT_EXPORT(DEVICE_FIDO) BioEnrollmentHandler
// the operation has been cancelled, |completion_callback| is invoked
// with the operation status.
void EnrollTemplate(SampleCallback sample_callback,
- StatusCallback completion_callback);
+ CompletionCallback completion_callback);
- // Cancels an ongoing enrollment, if any, and invokes the callback with
- // |CtapDeviceResponseCode::kSuccess|.
- void Cancel(StatusCallback);
+ // Cancels an ongoing enrollment, if any, and invokes the
+ // |completion_callback| passed to EnrollTemplate() with
+ // |CtapDeviceResponseCode::kCtap2ErrKeepAliveCancel|.
+ void CancelEnrollment();
// Requests a map of current enrollments from the authenticator. On success,
// the callback is invoked with a map from template IDs to human-readable
@@ -89,6 +86,22 @@ class COMPONENT_EXPORT(DEVICE_FIDO) BioEnrollmentHandler
void DeleteTemplate(std::vector<uint8_t> template_id, StatusCallback);
private:
+ enum class State {
+ kWaitingForTouch,
+ kGettingRetries,
+ kWaitingForPIN,
+ kGettingEphemeralKey,
+ kGettingPINToken,
+ kReady,
+ kEnrolling,
+ kEnrollingPendingCancel,
+ kCancellingEnrollment,
+ kEnumerating,
+ kRenaming,
+ kDeleting,
+ kFinished,
+ };
+
// FidoRequestHandlerBase:
void DispatchRequest(FidoAuthenticator*) override;
void AuthenticatorRemoved(FidoDiscoveryBase*, FidoAuthenticator*) override;
@@ -102,21 +115,30 @@ class COMPONENT_EXPORT(DEVICE_FIDO) BioEnrollmentHandler
base::Optional<pin::KeyAgreementResponse>);
void OnHavePINToken(CtapDeviceResponseCode,
base::Optional<pin::TokenResponse>);
- void OnEnrollTemplateFinished(StatusCallback,
- CtapDeviceResponseCode,
- base::Optional<BioEnrollmentResponse>);
- void OnCancel(StatusCallback,
+ void OnEnrollResponse(SampleCallback,
+ CompletionCallback,
+ base::Optional<TemplateId> current_template_id,
+ CtapDeviceResponseCode,
+ base::Optional<BioEnrollmentResponse>);
+ void OnCancel(CompletionCallback,
CtapDeviceResponseCode,
base::Optional<BioEnrollmentResponse>);
void OnEnumerateTemplates(EnumerationCallback,
CtapDeviceResponseCode,
base::Optional<BioEnrollmentResponse>);
- void OnStatusCallback(StatusCallback,
+ void OnRenameTemplate(StatusCallback,
+ CtapDeviceResponseCode,
+ base::Optional<BioEnrollmentResponse>);
+ void OnDeleteTemplate(StatusCallback,
CtapDeviceResponseCode,
base::Optional<BioEnrollmentResponse>);
+ void Finish(BioEnrollmentStatus status);
+
SEQUENCE_CHECKER(sequence_checker_);
+ State state_ = State::kWaitingForTouch;
+
FidoAuthenticator* authenticator_ = nullptr;
base::OnceClosure ready_callback_;
ErrorCallback error_callback_;
diff --git a/chromium/device/fido/bio/enrollment_handler_unittest.cc b/chromium/device/fido/bio/enrollment_handler_unittest.cc
index c1837b4f7f2..8d76e0e288c 100644
--- a/chromium/device/fido/bio/enrollment_handler_unittest.cc
+++ b/chromium/device/fido/bio/enrollment_handler_unittest.cc
@@ -10,16 +10,11 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/test/task_environment.h"
-#include "build/build_config.h"
#include "device/fido/bio/enrollment_handler.h"
#include "device/fido/fido_transport_protocol.h"
#include "device/fido/test_callback_receiver.h"
#include "device/fido/virtual_fido_device_factory.h"
-#if defined(OS_WIN)
-#include "device/fido/win/fake_webauthn_api.h"
-#endif // defined(OS_WIN)
-
namespace device {
namespace {
@@ -55,12 +50,23 @@ class BioEnrollmentHandlerTest : public ::testing::Test {
&virtual_device_factory_);
}
+ std::pair<CtapDeviceResponseCode, BioEnrollmentHandler::TemplateId>
+ EnrollTemplate(BioEnrollmentHandler* handler) {
+ test::StatusAndValueCallbackReceiver<CtapDeviceResponseCode,
+ BioEnrollmentHandler::TemplateId>
+ cb;
+ handler->EnrollTemplate(MakeSampleCallback(), cb.callback());
+
+ cb.WaitForCallback();
+ return {cb.status(), cb.value()};
+ }
+
void GetPIN(int64_t attempts,
base::OnceCallback<void(std::string)> provide_pin) {
std::move(provide_pin).Run(kPIN);
}
- auto MakeStatusCallback() {
+ BioEnrollmentHandler::SampleCallback MakeSampleCallback() {
remaining_samples_ = 0;
sampling_ = false;
return base::BindRepeating(&BioEnrollmentHandlerTest::OnEnroll,
@@ -73,11 +79,6 @@ class BioEnrollmentHandlerTest : public ::testing::Test {
test::TestCallbackReceiver<> ready_callback_;
test::ValueCallbackReceiver<BioEnrollmentStatus> error_callback_;
test::VirtualFidoDeviceFactory virtual_device_factory_;
-
-#if defined(OS_WIN)
- device::ScopedFakeWinWebAuthnApi win_webauthn_api_ =
- device::ScopedFakeWinWebAuthnApi::MakeUnavailable();
-#endif // defined(OS_WIN)
};
// Tests bio enrollment handler against device without PIN support.
@@ -94,58 +95,6 @@ TEST_F(BioEnrollmentHandlerTest, NoPINSupport) {
EXPECT_EQ(error_callback_.value(), BioEnrollmentStatus::kNoPINSet);
}
-// Tests getting authenticator modality without pin auth.
-TEST_F(BioEnrollmentHandlerTest, Modality) {
- VirtualCtap2Device::Config config;
- config.pin_support = true;
- config.bio_enrollment_preview_support = true;
-
- virtual_device_factory_.SetCtap2Config(config);
-
- auto handler = MakeHandler();
- ready_callback_.WaitForCallback();
-
- test::StatusAndValueCallbackReceiver<CtapDeviceResponseCode,
- base::Optional<BioEnrollmentResponse>>
- cb;
- handler->GetModality(cb.callback());
- cb.WaitForCallback();
-
- // Operation was successful.
- EXPECT_EQ(cb.status(), CtapDeviceResponseCode::kSuccess);
-
- // Result is correct.
- BioEnrollmentResponse expected;
- expected.modality = BioEnrollmentModality::kFingerprint;
- EXPECT_EQ(cb.value(), expected);
-}
-
-// Tests getting authenticator modality without pin auth.
-TEST_F(BioEnrollmentHandlerTest, FingerprintSensorInfo) {
- VirtualCtap2Device::Config config;
- config.pin_support = true;
- config.bio_enrollment_preview_support = true;
-
- virtual_device_factory_.SetCtap2Config(config);
-
- auto handler = MakeHandler();
- ready_callback_.WaitForCallback();
-
- test::StatusAndValueCallbackReceiver<CtapDeviceResponseCode,
- base::Optional<BioEnrollmentResponse>>
- cb;
- handler->GetSensorInfo(cb.callback());
- cb.WaitForCallback();
-
- EXPECT_EQ(cb.status(), CtapDeviceResponseCode::kSuccess);
-
- BioEnrollmentResponse expected;
- expected.modality = BioEnrollmentModality::kFingerprint;
- expected.fingerprint_kind = BioEnrollmentFingerprintKind::kTouch;
- expected.max_samples_for_enroll = 4;
- EXPECT_EQ(cb.value(), expected);
-}
-
// Tests enrollment handler PIN soft block.
TEST_F(BioEnrollmentHandlerTest, SoftPINBlock) {
VirtualCtap2Device::Config config;
@@ -185,11 +134,11 @@ TEST_F(BioEnrollmentHandlerTest, Enroll) {
auto handler = MakeHandler();
ready_callback_.WaitForCallback();
- test::ValueCallbackReceiver<CtapDeviceResponseCode> cb;
- handler->EnrollTemplate(MakeStatusCallback(), cb.callback());
-
- cb.WaitForCallback();
- EXPECT_EQ(cb.value(), CtapDeviceResponseCode::kSuccess);
+ CtapDeviceResponseCode status;
+ BioEnrollmentHandler::TemplateId template_id;
+ std::tie(status, template_id) = EnrollTemplate(handler.get());
+ EXPECT_EQ(status, CtapDeviceResponseCode::kSuccess);
+ EXPECT_FALSE(template_id.empty());
}
// Tests enrolling multiple fingerprints.
@@ -205,10 +154,11 @@ TEST_F(BioEnrollmentHandlerTest, EnrollMultiple) {
// Multiple enrollments
for (auto i = 0; i < 4; i++) {
- test::ValueCallbackReceiver<CtapDeviceResponseCode> cb;
- handler->EnrollTemplate(MakeStatusCallback(), cb.callback());
- cb.WaitForCallback();
- EXPECT_EQ(cb.value(), CtapDeviceResponseCode::kSuccess);
+ CtapDeviceResponseCode status;
+ BioEnrollmentHandler::TemplateId template_id;
+ std::tie(status, template_id) = EnrollTemplate(handler.get());
+ EXPECT_EQ(status, CtapDeviceResponseCode::kSuccess);
+ EXPECT_FALSE(template_id.empty());
}
// Enumerate to check enrollments.
@@ -238,33 +188,16 @@ TEST_F(BioEnrollmentHandlerTest, EnrollMax) {
ready_callback_.WaitForCallback();
// Enroll until full.
- auto status = CtapDeviceResponseCode::kSuccess;
- while (status == CtapDeviceResponseCode::kSuccess) {
- test::ValueCallbackReceiver<CtapDeviceResponseCode> cb;
- handler->EnrollTemplate(MakeStatusCallback(), cb.callback());
- cb.WaitForCallback();
- status = cb.value();
+ CtapDeviceResponseCode status;
+ BioEnrollmentHandler::TemplateId template_id;
+ for (;;) {
+ std::tie(status, template_id) = EnrollTemplate(handler.get());
+ if (status != CtapDeviceResponseCode::kSuccess)
+ break;
}
EXPECT_EQ(status, CtapDeviceResponseCode::kCtap2ErrKeyStoreFull);
-}
-
-// Tests cancelling fingerprint without an ongoing enrollment.
-TEST_F(BioEnrollmentHandlerTest, CancelNoEnroll) {
- VirtualCtap2Device::Config config;
- config.pin_support = true;
- config.bio_enrollment_preview_support = true;
-
- virtual_device_factory_.SetCtap2Config(config);
-
- auto handler = MakeHandler();
- ready_callback_.WaitForCallback();
-
- test::ValueCallbackReceiver<CtapDeviceResponseCode> cb;
- handler->Cancel(cb.callback());
- cb.WaitForCallback();
-
- EXPECT_EQ(cb.value(), CtapDeviceResponseCode::kSuccess);
+ EXPECT_TRUE(template_id.empty());
}
// Tests enumerating with no enrollments.
@@ -300,10 +233,11 @@ TEST_F(BioEnrollmentHandlerTest, EnumerateOne) {
ready_callback_.WaitForCallback();
// Enroll - skip response validation
- test::ValueCallbackReceiver<CtapDeviceResponseCode> cb0;
- handler->EnrollTemplate(MakeStatusCallback(), cb0.callback());
- cb0.WaitForCallback();
- EXPECT_EQ(cb0.value(), CtapDeviceResponseCode::kSuccess);
+ CtapDeviceResponseCode status;
+ BioEnrollmentHandler::TemplateId template_id;
+ std::tie(status, template_id) = EnrollTemplate(handler.get());
+ EXPECT_EQ(status, CtapDeviceResponseCode::kSuccess);
+ EXPECT_FALSE(template_id.empty());
// Enumerate
test::StatusAndValueCallbackReceiver<
@@ -335,14 +269,15 @@ TEST_F(BioEnrollmentHandlerTest, Rename) {
EXPECT_EQ(cb0.value(), CtapDeviceResponseCode::kCtap2ErrInvalidOption);
// Enroll - skip response validation.
- test::ValueCallbackReceiver<CtapDeviceResponseCode> cb1;
- handler->EnrollTemplate(MakeStatusCallback(), cb1.callback());
- cb1.WaitForCallback();
- EXPECT_EQ(cb1.value(), CtapDeviceResponseCode::kSuccess);
+ CtapDeviceResponseCode status;
+ BioEnrollmentHandler::TemplateId template_id;
+ std::tie(status, template_id) = EnrollTemplate(handler.get());
+ EXPECT_EQ(status, CtapDeviceResponseCode::kSuccess);
+ EXPECT_FALSE(template_id.empty());
// Rename non-existent enrollment.
test::ValueCallbackReceiver<CtapDeviceResponseCode> cb2;
- handler->RenameTemplate({1}, "OtherFingerprint1", cb2.callback());
+ handler->RenameTemplate(template_id, "OtherFingerprint1", cb2.callback());
cb2.WaitForCallback();
EXPECT_EQ(cb2.value(), CtapDeviceResponseCode::kSuccess);
@@ -355,7 +290,7 @@ TEST_F(BioEnrollmentHandlerTest, Rename) {
cb3.WaitForCallback();
EXPECT_EQ(cb3.status(), CtapDeviceResponseCode::kSuccess);
EXPECT_EQ(cb3.value(), (std::map<std::vector<uint8_t>, std::string>{
- {{1}, "OtherFingerprint1"}}));
+ {template_id, "OtherFingerprint1"}}));
}
// Tests deleting an enrollment (success and failure).
@@ -376,10 +311,11 @@ TEST_F(BioEnrollmentHandlerTest, Delete) {
EXPECT_EQ(cb0.value(), CtapDeviceResponseCode::kCtap2ErrInvalidOption);
// Enroll - skip response validation.
- test::ValueCallbackReceiver<CtapDeviceResponseCode> cb1;
- handler->EnrollTemplate(MakeStatusCallback(), cb1.callback());
- cb1.WaitForCallback();
- EXPECT_EQ(cb1.value(), CtapDeviceResponseCode::kSuccess);
+ CtapDeviceResponseCode status;
+ BioEnrollmentHandler::TemplateId template_id;
+ std::tie(status, template_id) = EnrollTemplate(handler.get());
+ EXPECT_EQ(status, CtapDeviceResponseCode::kSuccess);
+ EXPECT_FALSE(template_id.empty());
// Delete existing enrollment.
test::ValueCallbackReceiver<CtapDeviceResponseCode> cb2;
@@ -394,24 +330,5 @@ TEST_F(BioEnrollmentHandlerTest, Delete) {
EXPECT_EQ(cb3.value(), CtapDeviceResponseCode::kCtap2ErrInvalidOption);
}
-// Test cancelling using the non-preview command.
-TEST_F(BioEnrollmentHandlerTest, NonPreviewCancel) {
- VirtualCtap2Device::Config config;
- config.pin_support = true;
- config.bio_enrollment_support = true;
-
- virtual_device_factory_.SetCtap2Config(config);
-
- auto handler = MakeHandler();
- ready_callback_.WaitForCallback();
-
- // Cancel enrollment.
- test::ValueCallbackReceiver<CtapDeviceResponseCode> cb;
- handler->Cancel(cb.callback());
-
- cb.WaitForCallback();
- EXPECT_EQ(cb.value(), CtapDeviceResponseCode::kSuccess);
-}
-
} // namespace
} // namespace device
diff --git a/chromium/device/fido/ble/fido_ble_connection.cc b/chromium/device/fido/ble/fido_ble_connection.cc
index 235d8985c2d..95dadff5d75 100644
--- a/chromium/device/fido/ble/fido_ble_connection.cc
+++ b/chromium/device/fido/ble/fido_ble_connection.cc
@@ -501,8 +501,6 @@ const BluetoothRemoteGattService* FidoBleConnection::GetFidoService() {
// and a caBLE device.
if (service->GetUUID() == BluetoothUUID(kFidoServiceUUID) ||
service->GetUUID() == BluetoothUUID(kCableAdvertisementUUID128)) {
- FIDO_LOG(EVENT) << "Found caBLE service UUID: "
- << service->GetUUID().value();
return service;
}
}
diff --git a/chromium/device/fido/ble/fido_ble_discovery.cc b/chromium/device/fido/ble/fido_ble_discovery.cc
index 6a2e73d6287..f42980ed6f4 100644
--- a/chromium/device/fido/ble/fido_ble_discovery.cc
+++ b/chromium/device/fido/ble/fido_ble_discovery.cc
@@ -48,12 +48,14 @@ void FidoBleDiscovery::OnSetPowered() {
}
}
- auto filter = std::make_unique<BluetoothDiscoveryFilter>(
+ auto discovery_filter = std::make_unique<BluetoothDiscoveryFilter>(
BluetoothTransport::BLUETOOTH_TRANSPORT_LE);
- filter->AddUUID(FidoServiceUUID());
+ device::BluetoothDiscoveryFilter::DeviceInfoFilter device_filter;
+ device_filter.uuids.insert(FidoServiceUUID());
+ discovery_filter->AddDeviceFilter(device_filter);
adapter()->StartDiscoverySessionWithFilter(
- std::move(filter),
+ std::move(discovery_filter),
base::AdaptCallbackForRepeating(
base::BindOnce(&FidoBleDiscovery::OnStartDiscoverySessionWithFilter,
weak_factory_.GetWeakPtr())),
diff --git a/chromium/device/fido/ble/fido_ble_discovery_base.cc b/chromium/device/fido/ble/fido_ble_discovery_base.cc
index 5b0945316cc..22c41154304 100644
--- a/chromium/device/fido/ble/fido_ble_discovery_base.cc
+++ b/chromium/device/fido/ble/fido_ble_discovery_base.cc
@@ -39,18 +39,15 @@ const BluetoothUUID& FidoBleDiscoveryBase::CableAdvertisementUUID() {
void FidoBleDiscoveryBase::OnStartDiscoverySessionWithFilter(
std::unique_ptr<BluetoothDiscoverySession> session) {
SetDiscoverySession(std::move(session));
- FIDO_LOG(DEBUG) << "Discovery session started.";
- NotifyDiscoveryStarted(true);
+ FIDO_LOG(DEBUG) << "BLE discovery session started";
}
void FidoBleDiscoveryBase::OnSetPoweredError() {
- FIDO_LOG(ERROR) << "Failed to power on the adapter.";
- NotifyDiscoveryStarted(false);
+ FIDO_LOG(ERROR) << "Failed to power on BLE adapter";
}
void FidoBleDiscoveryBase::OnStartDiscoverySessionError() {
- FIDO_LOG(ERROR) << "Discovery session not started.";
- NotifyDiscoveryStarted(false);
+ FIDO_LOG(ERROR) << "Failed to start BLE discovery";
}
void FidoBleDiscoveryBase::SetDiscoverySession(
@@ -67,7 +64,7 @@ bool FidoBleDiscoveryBase::IsCableDevice(const BluetoothDevice* device) const {
void FidoBleDiscoveryBase::OnGetAdapter(
scoped_refptr<BluetoothAdapter> adapter) {
if (!adapter->IsPresent()) {
- FIDO_LOG(DEBUG) << "bluetooth adapter is not available in current system.";
+ FIDO_LOG(DEBUG) << "No BLE adapter present";
NotifyDiscoveryStarted(false);
return;
}
@@ -75,11 +72,19 @@ void FidoBleDiscoveryBase::OnGetAdapter(
DCHECK(!adapter_);
adapter_ = std::move(adapter);
DCHECK(adapter_);
- FIDO_LOG(DEBUG) << "Got adapter " << adapter_->GetAddress();
+ FIDO_LOG(DEBUG) << "BLE adapter address " << adapter_->GetAddress();
adapter_->AddObserver(this);
- if (adapter_->IsPowered())
+ if (adapter_->IsPowered()) {
OnSetPowered();
+ }
+
+ // FidoRequestHandlerBase blocks its transport availability callback on the
+ // DiscoveryStarted() calls of all instantiated discoveries. Hence, this call
+ // must not be put behind the BLE adapter getting powered on (which is
+ // dependent on the UI), or else the UI and this discovery will wait on each
+ // other indefinitely (see crbug.com/1018416).
+ NotifyDiscoveryStarted(true);
}
void FidoBleDiscoveryBase::StartInternal() {
diff --git a/chromium/device/fido/ble/fido_ble_discovery_unittest.cc b/chromium/device/fido/ble/fido_ble_discovery_unittest.cc
index 977ede1eb84..b9f69ccbecb 100644
--- a/chromium/device/fido/ble/fido_ble_discovery_unittest.cc
+++ b/chromium/device/fido/ble/fido_ble_discovery_unittest.cc
@@ -114,6 +114,18 @@ class FidoBleDiscoveryTest : public ::testing::Test {
BluetoothAdapterFactory::SetAdapterForTesting(adapter_);
}
+ void ExpectSuccessfulStartScan() {
+ EXPECT_CALL(*adapter(), StartScanWithFilter_)
+ .WillOnce(testing::Invoke(
+ [](const device::BluetoothDiscoveryFilter* discovery_filter,
+ device::BluetoothAdapter::DiscoverySessionResultCallback&
+ callback) {
+ std::move(callback).Run(
+ /*is_error=*/false,
+ device::UMABluetoothDiscoverySessionOutcome::SUCCESS);
+ }));
+ }
+
FidoBleDiscovery* discovery() { return &discovery_; }
MockFidoDiscoveryObserver* observer() { return &observer_; }
MockBluetoothAdapter* adapter() {
@@ -136,7 +148,8 @@ TEST_F(FidoBleDiscoveryTest,
SetMockBluetoothAdapter();
EXPECT_CALL(*adapter(), IsPresent()).WillOnce(Return(false));
EXPECT_CALL(*adapter(), SetPowered).Times(0);
- EXPECT_CALL(*observer(), DiscoveryStarted(discovery(), false));
+ EXPECT_CALL(*observer(), DiscoveryStarted(discovery(), false,
+ std::vector<FidoAuthenticator*>()));
discovery()->Start();
task_environment_.FastForwardUntilNoTasksRemain();
}
@@ -149,15 +162,9 @@ TEST_F(FidoBleDiscoveryTest, FidoBleDiscoveryResumeScanningAfterPoweredOn) {
// After BluetoothAdapter is powered on, we expect that discovery session
// starts again. Immediately calling the callback so that it does not hold a
// reference to the adapter.
- EXPECT_CALL(*adapter(), StartScanWithFilter_)
- .WillOnce(testing::Invoke(
- [](const device::BluetoothDiscoveryFilter* discovery_filter,
- device::BluetoothAdapter::DiscoverySessionResultCallback&
- callback) {
- std::move(callback).Run(
- /*is_error=*/false,
- device::UMABluetoothDiscoverySessionOutcome::SUCCESS);
- }));
+ ExpectSuccessfulStartScan();
+ EXPECT_CALL(*observer(), DiscoveryStarted(discovery(), true,
+ std::vector<FidoAuthenticator*>()));
discovery()->Start();
task_environment_.FastForwardUntilNoTasksRemain();
adapter()->NotifyAdapterPoweredChanged(true);
@@ -168,7 +175,7 @@ TEST_F(FidoBleDiscoveryTest, FidoBleDiscoveryNoAdapter) {
// simulating cases where the discovery is destroyed before obtaining a handle
// to an adapter. This should be handled gracefully and not result in a crash.
// We don't expect any calls to the notification methods.
- EXPECT_CALL(*observer(), DiscoveryStarted(discovery(), _)).Times(0);
+ EXPECT_CALL(*observer(), DiscoveryStarted(discovery(), _, _)).Times(0);
EXPECT_CALL(*observer(), AuthenticatorAdded(discovery(), _)).Times(0);
EXPECT_CALL(*observer(), AuthenticatorRemoved(discovery(), _)).Times(0);
}
@@ -191,11 +198,10 @@ TEST_F(BluetoothTest, FidoBleDiscoveryFindsKnownDevice) {
{
base::RunLoop run_loop;
auto quit = run_loop.QuitClosure();
- EXPECT_CALL(
- observer,
- AuthenticatorAdded(&discovery,
- IdMatches(BluetoothTestBase::kTestDeviceAddress1)));
- EXPECT_CALL(observer, DiscoveryStarted(&discovery, true))
+ EXPECT_CALL(observer,
+ DiscoveryStarted(&discovery, true,
+ testing::ElementsAre(IdMatches(
+ BluetoothTestBase::kTestDeviceAddress1))))
.WillOnce(ReturnFromAsyncCall(quit));
discovery.Start();
@@ -217,7 +223,8 @@ TEST_F(BluetoothTest, FidoBleDiscoveryFindsNewDevice) {
{
base::RunLoop run_loop;
auto quit = run_loop.QuitClosure();
- EXPECT_CALL(observer, DiscoveryStarted(&discovery, true))
+ EXPECT_CALL(observer, DiscoveryStarted(&discovery, true,
+ std::vector<FidoAuthenticator*>()))
.WillOnce(ReturnFromAsyncCall(quit));
discovery.Start();
@@ -261,7 +268,8 @@ TEST_F(BluetoothTest, FidoBleDiscoveryFindsUpdatedDevice) {
{
base::RunLoop run_loop;
auto quit = run_loop.QuitClosure();
- EXPECT_CALL(observer, DiscoveryStarted(&discovery, true))
+ EXPECT_CALL(observer, DiscoveryStarted(&discovery, true,
+ std::vector<FidoAuthenticator*>()))
.WillOnce(ReturnFromAsyncCall(quit));
discovery.Start();
@@ -306,7 +314,8 @@ TEST_F(BluetoothTest, FidoBleDiscoveryRejectsCableDevice) {
{
base::RunLoop run_loop;
auto quit = run_loop.QuitClosure();
- EXPECT_CALL(observer, DiscoveryStarted(&discovery, true))
+ EXPECT_CALL(observer, DiscoveryStarted(&discovery, true,
+ std::vector<FidoAuthenticator*>()))
.WillOnce(ReturnFromAsyncCall(quit));
discovery.Start();
@@ -355,13 +364,16 @@ TEST_F(FidoBleDiscoveryTest,
TEST_F(FidoBleDiscoveryTest, DiscoveryNotifiesObserverWhenDeviceInPairingMode) {
SetMockBluetoothAdapter();
EXPECT_CALL(*adapter(), IsPresent()).WillOnce(Return(true));
+ EXPECT_CALL(*adapter(), IsPowered()).WillOnce(Return(true));
auto mock_device = CreateMockFidoDevice();
+ ::testing::InSequence sequence;
+ ExpectSuccessfulStartScan();
+ EXPECT_CALL(*observer(), DiscoveryStarted(discovery(), true, _));
const auto device_id = FidoBleDevice::GetIdForAddress(kDeviceAddress);
discovery()->Start();
task_environment_.FastForwardUntilNoTasksRemain();
- ::testing::InSequence sequence;
EXPECT_CALL(*observer(),
AuthenticatorAdded(discovery(), IdMatches(kDeviceAddress)));
adapter()->NotifyDeviceChanged(mock_device.get());
@@ -378,13 +390,16 @@ TEST_F(FidoBleDiscoveryTest,
DiscoveryNotifiesObserverWhenDeviceInNonPairingMode) {
SetMockBluetoothAdapter();
EXPECT_CALL(*adapter(), IsPresent()).WillOnce(Return(true));
+ EXPECT_CALL(*adapter(), IsPowered()).WillOnce(Return(true));
auto mock_device = CreateMockFidoDevice();
+ ::testing::InSequence sequence;
+ ExpectSuccessfulStartScan();
+ EXPECT_CALL(*observer(), DiscoveryStarted(discovery(), true, _));
const auto device_id = FidoBleDevice::GetIdForAddress(kDeviceAddress);
discovery()->Start();
task_environment_.FastForwardUntilNoTasksRemain();
- ::testing::InSequence sequence;
EXPECT_CALL(*observer(),
AuthenticatorAdded(discovery(), IdMatches(kDeviceAddress)));
adapter()->NotifyDeviceChanged(mock_device.get());
@@ -429,9 +444,13 @@ TEST_F(FidoBleDiscoveryTest,
TEST_F(FidoBleDiscoveryTest, DiscoveryDoesNotDeleteDeviceOnAddressCollision) {
SetMockBluetoothAdapter();
EXPECT_CALL(*adapter(), IsPresent()).WillOnce(Return(true));
+ EXPECT_CALL(*adapter(), IsPowered()).WillOnce(Return(true));
auto mock_device = CreateMockFidoDevice();
auto changed_mock_device = CreateChangedMockFidoDevice();
+ ExpectSuccessfulStartScan();
+ EXPECT_CALL(*observer(), DiscoveryStarted(discovery(), true, _));
+
EXPECT_CALL(*observer(),
AuthenticatorAdded(discovery(), IdMatches(kDeviceAddress)));
diff --git a/chromium/device/fido/ble_adapter_manager_unittest.cc b/chromium/device/fido/ble_adapter_manager_unittest.cc
index db0f0fff598..1617f86c0a4 100644
--- a/chromium/device/fido/ble_adapter_manager_unittest.cc
+++ b/chromium/device/fido/ble_adapter_manager_unittest.cc
@@ -11,22 +11,17 @@
#include "base/bind_helpers.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
-#include "build/build_config.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/bluetooth/test/mock_bluetooth_device.h"
+#include "device/fido/fake_fido_discovery.h"
#include "device/fido/fido_authenticator.h"
-#include "device/fido/fido_discovery_factory.h"
#include "device/fido/fido_request_handler_base.h"
#include "device/fido/fido_transport_protocol.h"
#include "device/fido/test_callback_receiver.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_WIN)
-#include "device/fido/win/fake_webauthn_api.h"
-#endif // defined(OS_WIN)
-
namespace device {
namespace {
@@ -75,6 +70,7 @@ class FakeFidoRequestHandlerBase : public FidoRequestHandlerBase {
fido_discovery_factory,
{FidoTransportProtocol::kBluetoothLowEnergy}) {
set_observer(observer);
+ Start();
}
void SimulateFidoRequestHandlerHasAuthenticator(bool simulate_authenticator) {
@@ -100,6 +96,11 @@ class FidoBleAdapterManagerTest : public ::testing::Test {
public:
FidoBleAdapterManagerTest() {
BluetoothAdapterFactory::SetAdapterForTesting(adapter_);
+ fido_discovery_factory_->ForgeNextBleDiscovery(
+ test::FakeFidoDiscovery::StartMode::kAutomatic);
+
+ fake_request_handler_ = std::make_unique<FakeFidoRequestHandlerBase>(
+ mock_observer_.get(), fido_discovery_factory_.get());
}
MockBluetoothDevice* AddMockBluetoothDeviceToAdapter() {
@@ -139,18 +140,10 @@ class FidoBleAdapterManagerTest : public ::testing::Test {
base::MakeRefCounted<::testing::NiceMock<MockBluetoothAdapter>>();
std::unique_ptr<MockObserver> mock_observer_ =
std::make_unique<MockObserver>();
- std::unique_ptr<FidoDiscoveryFactory> fido_discovery_factory_ =
- std::make_unique<FidoDiscoveryFactory>();
-
-#if defined(OS_WIN)
- device::ScopedFakeWinWebAuthnApi win_webauthn_api_ =
- device::ScopedFakeWinWebAuthnApi::MakeUnavailable();
-#endif // defined(OS_WIN)
-
- std::unique_ptr<FakeFidoRequestHandlerBase> fake_request_handler_ =
- std::make_unique<FakeFidoRequestHandlerBase>(
- mock_observer_.get(),
- fido_discovery_factory_.get());
+ std::unique_ptr<test::FakeFidoDiscoveryFactory> fido_discovery_factory_ =
+ std::make_unique<test::FakeFidoDiscoveryFactory>();
+
+ std::unique_ptr<FakeFidoRequestHandlerBase> fake_request_handler_;
};
TEST_F(FidoBleAdapterManagerTest, AdapterNotPresent) {
diff --git a/chromium/device/fido/cable/cable_discovery_data.h b/chromium/device/fido/cable/cable_discovery_data.h
index 0ba7dc4f0e2..81a90674135 100644
--- a/chromium/device/fido/cable/cable_discovery_data.h
+++ b/chromium/device/fido/cable/cable_discovery_data.h
@@ -23,6 +23,17 @@ using CableSessionPreKeyArray = std::array<uint8_t, kCableSessionPreKeySize>;
// |CableDiscoveryData::DeriveQRKeyMaterial| to encrypt a coarse timestamp and
// generate QR secrets, EIDs, etc.
using QRGeneratorKey = std::array<uint8_t, 32>;
+// CableNonce is a nonce used in BLE handshaking.
+using CableNonce = std::array<uint8_t, 8>;
+// CableEidGeneratorKey is an AES-256 key that is used to encrypt a 64-bit nonce
+// and 64-bits of zeros, resulting in a BLE-advertised EID.
+using CableEidGeneratorKey = std::array<uint8_t, 32>;
+// CablePskGeneratorKey is HKDF input keying material that is used to
+// generate a Noise PSK given the nonce decrypted from an EID.
+using CablePskGeneratorKey = std::array<uint8_t, 32>;
+// CableAuthenticatorIdentityKey is a P-256 public value used to authenticate a
+// paired phone.
+using CableAuthenticatorIdentityKey = std::array<uint8_t, 65>;
// Encapsulates information required to discover Cable device per single
// credential. When multiple credentials are enrolled to a single account
@@ -32,10 +43,20 @@ using QRGeneratorKey = std::array<uint8_t, 32>;
// TODO(hongjunchoi): Add discovery data required for MakeCredential request.
// See: https://crbug.com/837088
struct COMPONENT_EXPORT(DEVICE_FIDO) CableDiscoveryData {
- CableDiscoveryData(uint8_t version,
+ enum class Version {
+ INVALID,
+ V1,
+ V2,
+ };
+
+ CableDiscoveryData(Version version,
const CableEidArray& client_eid,
const CableEidArray& authenticator_eid,
const CableSessionPreKeyArray& session_pre_key);
+ // Creates discovery data given a specific QR secret. See |DeriveQRSecret| for
+ // how to generate such secrets.
+ explicit CableDiscoveryData(
+ base::span<const uint8_t, kCableQRSecretSize> qr_secret);
CableDiscoveryData();
CableDiscoveryData(const CableDiscoveryData& data);
~CableDiscoveryData();
@@ -43,6 +64,10 @@ struct COMPONENT_EXPORT(DEVICE_FIDO) CableDiscoveryData {
CableDiscoveryData& operator=(const CableDiscoveryData& other);
bool operator==(const CableDiscoveryData& other) const;
+ // Match attempts to recognise the given EID. If it matches this discovery
+ // data, the nonce is returned.
+ base::Optional<CableNonce> Match(const CableEidArray& candidate_eid) const;
+
// NewQRKey returns a random key for QR generation.
static QRGeneratorKey NewQRKey();
@@ -50,21 +75,39 @@ struct COMPONENT_EXPORT(DEVICE_FIDO) CableDiscoveryData {
// of these ticks is a purely local matter for Chromium.
static int64_t CurrentTimeTick();
- // DeriveQRKeyMaterial writes |kCableQRSecretSize| bytes to |out_qr_secret|,
- // |kCableEphemeralIdSize| bytes to |out_authenticator_eid| and
- // |kCableSessionPreKeySize| bytes of |out_session_key|, based on the given
- // generator key and current time.
- static void DeriveQRKeyMaterial(
- base::span<uint8_t, kCableQRSecretSize> out_qr_secret,
- base::span<uint8_t, kCableEphemeralIdSize> out_authenticator_eid,
- base::span<uint8_t, kCableSessionPreKeySize> out_session_key,
+ // DeriveQRKeyMaterial returns a QR-secret given a generating key and a
+ // timestamp.
+ static std::array<uint8_t, kCableQRSecretSize> DeriveQRSecret(
base::span<const uint8_t, 32> qr_generator_key,
const int64_t tick);
- uint8_t version;
- CableEidArray client_eid;
- CableEidArray authenticator_eid;
- CableSessionPreKeyArray session_pre_key;
+ // version indicates whether v1 or v2 data is contained in this object.
+ // |INVALID| is not a valid version but is set as the default to catch any
+ // cases where the version hasn't been set explicitly.
+ Version version = Version::INVALID;
+
+ struct V1Data {
+ CableEidArray client_eid;
+ CableEidArray authenticator_eid;
+ CableSessionPreKeyArray session_pre_key;
+ };
+ base::Optional<V1Data> v1;
+
+ struct COMPONENT_EXPORT(DEVICE_FIDO) V2Data {
+ V2Data();
+ V2Data(const V2Data&);
+ ~V2Data();
+
+ CableEidGeneratorKey eid_gen_key;
+ CablePskGeneratorKey psk_gen_key;
+ base::Optional<CableAuthenticatorIdentityKey> peer_identity;
+ // peer_name is an authenticator-controlled, UTF8-valid string containing
+ // the self-reported, human-friendly name of a v2 authenticator. This need
+ // not be filled in when handshaking but an authenticator may provide it
+ // when offering long-term pairing data.
+ base::Optional<std::string> peer_name;
+ };
+ base::Optional<V2Data> v2;
};
} // namespace device
diff --git a/chromium/device/fido/cable/fido_cable_device.cc b/chromium/device/fido/cable/fido_cable_device.cc
index df77590463e..2c3767ccd01 100644
--- a/chromium/device/fido/cable/fido_cable_device.cc
+++ b/chromium/device/fido/cable/fido_cable_device.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/numerics/safe_math.h"
#include "base/strings/string_piece.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/device_event_log/device_event_log.h"
@@ -22,9 +23,9 @@ namespace {
// Maximum size of EncryptionData::read_sequence_num or
// EncryptionData::write_sequence_num allowed. If we encounter
// counter larger than |kMaxCounter| FidoCableDevice should error out.
-constexpr size_t kMaxCounter = (1 << 24) - 1;
+constexpr uint32_t kMaxCounter = (1 << 24) - 1;
-base::Optional<std::vector<uint8_t>> ConstructEncryptionNonce(
+base::Optional<std::vector<uint8_t>> ConstructV1Nonce(
base::span<const uint8_t> nonce,
bool is_sender_client,
uint32_t counter) {
@@ -39,6 +40,20 @@ base::Optional<std::vector<uint8_t>> ConstructEncryptionNonce(
return constructed_nonce;
}
+bool ConstructV2Nonce(base::span<uint8_t, 12> out_nonce, uint32_t counter) {
+ if (counter > kMaxCounter) {
+ return false;
+ }
+
+ // Nonce is just a little-endian counter.
+ std::array<uint8_t, sizeof(counter)> counter_bytes;
+ memcpy(counter_bytes.data(), &counter, sizeof(counter));
+ auto remaining =
+ std::copy(counter_bytes.begin(), counter_bytes.end(), out_nonce.begin());
+ std::fill(remaining, out_nonce.end(), 0);
+ return true;
+}
+
} // namespace
FidoCableDevice::EncryptionData::EncryptionData() = default;
@@ -105,16 +120,28 @@ void FidoCableDevice::SendHandshakeMessage(
std::move(handshake_message), std::move(callback));
}
-void FidoCableDevice::SetEncryptionData(
+void FidoCableDevice::SetV1EncryptionData(
base::span<const uint8_t, 32> session_key,
base::span<const uint8_t, 8> nonce) {
// Encryption data must be set at most once during Cable handshake protocol.
DCHECK(!encryption_data_);
encryption_data_.emplace();
- encryption_data_->session_key = fido_parsing_utils::Materialize(session_key);
+ encryption_data_->read_key = fido_parsing_utils::Materialize(session_key);
+ encryption_data_->write_key = fido_parsing_utils::Materialize(session_key);
encryption_data_->nonce = fido_parsing_utils::Materialize(nonce);
}
+void FidoCableDevice::SetV2EncryptionData(
+ base::span<const uint8_t, 32> read_key,
+ base::span<const uint8_t, 32> write_key) {
+ DCHECK(!encryption_data_);
+ encryption_data_.emplace();
+ encryption_data_->read_key = fido_parsing_utils::Materialize(read_key);
+ encryption_data_->write_key = fido_parsing_utils::Materialize(write_key);
+ memset(encryption_data_->nonce.data(), 0, encryption_data_->nonce.size());
+ encryption_data_->is_version_two = true;
+}
+
FidoTransportProtocol FidoCableDevice::DeviceTransport() const {
return FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy;
}
@@ -129,14 +156,32 @@ void FidoCableDevice::SetSequenceNumbersForTesting(uint32_t read_seq,
bool FidoCableDevice::EncryptOutgoingMessage(
const EncryptionData& encryption_data,
std::vector<uint8_t>* message_to_encrypt) {
- const auto nonce = ConstructEncryptionNonce(
- encryption_data.nonce, true /* is_sender_client */,
- encryption_data.write_sequence_num);
+ return encryption_data.is_version_two
+ ? EncryptV2OutgoingMessage(encryption_data, message_to_encrypt)
+ : EncryptV1OutgoingMessage(encryption_data, message_to_encrypt);
+}
+
+// static
+bool FidoCableDevice::DecryptIncomingMessage(
+ const EncryptionData& encryption_data,
+ FidoBleFrame* incoming_frame) {
+ return encryption_data.is_version_two
+ ? DecryptV2IncomingMessage(encryption_data, incoming_frame)
+ : DecryptV1IncomingMessage(encryption_data, incoming_frame);
+}
+
+// static
+bool FidoCableDevice::EncryptV1OutgoingMessage(
+ const EncryptionData& encryption_data,
+ std::vector<uint8_t>* message_to_encrypt) {
+ const auto nonce =
+ ConstructV1Nonce(encryption_data.nonce, /*is_sender_client=*/true,
+ encryption_data.write_sequence_num);
if (!nonce)
return false;
crypto::Aead aes_key(crypto::Aead::AES_256_GCM);
- aes_key.Init(encryption_data.session_key);
+ aes_key.Init(encryption_data.write_key);
DCHECK_EQ(nonce->size(), aes_key.NonceLength());
const uint8_t additional_data[1] = {
@@ -148,17 +193,17 @@ bool FidoCableDevice::EncryptOutgoingMessage(
}
// static
-bool FidoCableDevice::DecryptIncomingMessage(
+bool FidoCableDevice::DecryptV1IncomingMessage(
const EncryptionData& encryption_data,
FidoBleFrame* incoming_frame) {
- const auto nonce = ConstructEncryptionNonce(
- encryption_data.nonce, false /* is_sender_client */,
- encryption_data.read_sequence_num);
+ const auto nonce =
+ ConstructV1Nonce(encryption_data.nonce, /*is_sender_client=*/false,
+ encryption_data.read_sequence_num);
if (!nonce)
return false;
crypto::Aead aes_key(crypto::Aead::AES_256_GCM);
- aes_key.Init(encryption_data.session_key);
+ aes_key.Init(encryption_data.read_key);
DCHECK_EQ(nonce->size(), aes_key.NonceLength());
const uint8_t additional_data[1] = {
@@ -174,4 +219,91 @@ bool FidoCableDevice::DecryptIncomingMessage(
return true;
}
+// static
+bool FidoCableDevice::EncryptV2OutgoingMessage(
+ const EncryptionData& encryption_data,
+ std::vector<uint8_t>* message_to_encrypt) {
+ // Messages will be padded in order to round their length up to a multiple of
+ // kPaddingGranularity.
+ constexpr size_t kPaddingGranularity = 32;
+ static_assert(kPaddingGranularity > 0, "padding too small");
+ static_assert(kPaddingGranularity < 256, "padding too large");
+ static_assert((kPaddingGranularity & (kPaddingGranularity - 1)) == 0,
+ "padding must be a power of two");
+
+ // Padding consists of a some number of zero bytes appended to the message and
+ // the final byte in the message is the number of zeros.
+ base::CheckedNumeric<size_t> padded_size_checked = message_to_encrypt->size();
+ padded_size_checked += 1; // padding-length byte.
+ padded_size_checked = (padded_size_checked + kPaddingGranularity - 1) &
+ ~(kPaddingGranularity - 1);
+ if (!padded_size_checked.IsValid()) {
+ return false;
+ }
+
+ const size_t padded_size = padded_size_checked.ValueOrDie();
+ DCHECK_GT(padded_size, message_to_encrypt->size());
+ const size_t num_zeros = padded_size - message_to_encrypt->size() - 1;
+
+ std::vector<uint8_t> padded_message(padded_size, 0);
+ memcpy(padded_message.data(), message_to_encrypt->data(),
+ message_to_encrypt->size());
+ // The number of added zeros has to fit in a single byte so it has to be less
+ // than 256.
+ DCHECK_LT(num_zeros, 256u);
+ padded_message[padded_message.size() - 1] = static_cast<uint8_t>(num_zeros);
+
+ std::array<uint8_t, 12> nonce;
+ if (!ConstructV2Nonce(nonce, encryption_data.write_sequence_num)) {
+ return false;
+ }
+
+ crypto::Aead aes_key(crypto::Aead::AES_256_GCM);
+ aes_key.Init(encryption_data.write_key);
+ DCHECK_EQ(nonce.size(), aes_key.NonceLength());
+
+ const uint8_t additional_data[2] = {
+ base::strict_cast<uint8_t>(FidoBleDeviceCommand::kMsg), /*version=*/2};
+ std::vector<uint8_t> ciphertext =
+ aes_key.Seal(padded_message, nonce, additional_data);
+ message_to_encrypt->swap(ciphertext);
+ return true;
+}
+
+// static
+bool FidoCableDevice::DecryptV2IncomingMessage(
+ const EncryptionData& encryption_data,
+ FidoBleFrame* incoming_frame) {
+ std::array<uint8_t, 12> nonce;
+ if (!ConstructV2Nonce(nonce, encryption_data.read_sequence_num)) {
+ return false;
+ }
+
+ crypto::Aead aes_key(crypto::Aead::AES_256_GCM);
+ aes_key.Init(encryption_data.read_key);
+ DCHECK_EQ(nonce.size(), aes_key.NonceLength());
+
+ const uint8_t additional_data[2] = {
+ base::strict_cast<uint8_t>(incoming_frame->command()), /*version=*/2};
+ base::Optional<std::vector<uint8_t>> plaintext =
+ aes_key.Open(incoming_frame->data(), nonce, additional_data);
+ if (!plaintext) {
+ FIDO_LOG(ERROR) << "Failed to decrypt caBLE message.";
+ return false;
+ }
+
+ if (plaintext->empty()) {
+ return false;
+ }
+
+ const size_t padding_length = (*plaintext)[plaintext->size() - 1];
+ if (padding_length + 1 > plaintext->size()) {
+ return false;
+ }
+ plaintext->resize(plaintext->size() - padding_length - 1);
+
+ incoming_frame->data().swap(*plaintext);
+ return true;
+}
+
} // namespace device
diff --git a/chromium/device/fido/cable/fido_cable_device.h b/chromium/device/fido/cable/fido_cable_device.h
index 504a7c0ad64..4e6d3620990 100644
--- a/chromium/device/fido/cable/fido_cable_device.h
+++ b/chromium/device/fido/cable/fido_cable_device.h
@@ -43,8 +43,12 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDevice : public FidoBleDevice {
void SendHandshakeMessage(std::vector<uint8_t> handshake_message,
DeviceCallback callback);
- void SetEncryptionData(base::span<const uint8_t, 32> session_key,
- base::span<const uint8_t, 8> nonce);
+ // Configure caBLE v1 keys.
+ void SetV1EncryptionData(base::span<const uint8_t, 32> session_key,
+ base::span<const uint8_t, 8> nonce);
+ // Configure caBLE v2 keys.
+ void SetV2EncryptionData(base::span<const uint8_t, 32> read_key,
+ base::span<const uint8_t, 32> write_key);
FidoTransportProtocol DeviceTransport() const override;
// SetCountersForTesting allows tests to set the message counters. Non-test
@@ -58,10 +62,12 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDevice : public FidoBleDevice {
struct EncryptionData {
EncryptionData();
- std::array<uint8_t, 32> session_key;
+ std::array<uint8_t, 32> read_key;
+ std::array<uint8_t, 32> write_key;
std::array<uint8_t, 8> nonce;
uint32_t write_sequence_num = 0;
uint32_t read_sequence_num = 0;
+ bool is_version_two = false;
};
static bool EncryptOutgoingMessage(const EncryptionData& encryption_data,
@@ -69,6 +75,18 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDevice : public FidoBleDevice {
static bool DecryptIncomingMessage(const EncryptionData& encryption_data,
FidoBleFrame* incoming_frame);
+ static bool EncryptV1OutgoingMessage(
+ const EncryptionData& encryption_data,
+ std::vector<uint8_t>* message_to_encrypt);
+ static bool DecryptV1IncomingMessage(const EncryptionData& encryption_data,
+ FidoBleFrame* incoming_frame);
+
+ static bool EncryptV2OutgoingMessage(
+ const EncryptionData& encryption_data,
+ std::vector<uint8_t>* message_to_encrypt);
+ static bool DecryptV2IncomingMessage(const EncryptionData& encryption_data,
+ FidoBleFrame* incoming_frame);
+
base::Optional<EncryptionData> encryption_data_;
base::WeakPtrFactory<FidoCableDevice> weak_factory_{this};
diff --git a/chromium/device/fido/cable/fido_cable_device_unittest.cc b/chromium/device/fido/cable/fido_cable_device_unittest.cc
index 2c0a3887581..9f37dfb9001 100644
--- a/chromium/device/fido/cable/fido_cable_device_unittest.cc
+++ b/chromium/device/fido/cable/fido_cable_device_unittest.cc
@@ -140,7 +140,7 @@ class FidoCableDeviceTest : public Test {
adapter_.get(), BluetoothTestBase::kTestDeviceAddress1);
connection_ = connection.get();
device_ = std::make_unique<FidoCableDevice>(std::move(connection));
- device_->SetEncryptionData(kTestSessionKey, kTestEncryptionNonce);
+ device_->SetV1EncryptionData(kTestSessionKey, kTestEncryptionNonce);
connection_->read_callback() = device_->GetReadCallbackForTesting();
}
diff --git a/chromium/device/fido/cable/fido_cable_discovery.cc b/chromium/device/fido/cable/fido_cable_discovery.cc
index 3d6611588a9..dbfc006053c 100644
--- a/chromium/device/fido/cable/fido_cable_discovery.cc
+++ b/chromium/device/fido/cable/fido_cable_discovery.cc
@@ -27,8 +27,10 @@
#include "device/fido/cable/fido_cable_handshake_handler.h"
#include "device/fido/features.h"
#include "device/fido/fido_parsing_utils.h"
+#include "third_party/boringssl/src/include/openssl/aes.h"
#include "third_party/boringssl/src/include/openssl/digest.h"
#include "third_party/boringssl/src/include/openssl/hkdf.h"
+#include "third_party/boringssl/src/include/openssl/mem.h"
namespace device {
@@ -40,7 +42,6 @@ namespace {
// instead, and on Mac our only option is to advertise an additional service
// with the EID as its UUID.
std::unique_ptr<BluetoothAdvertisement::Data> ConstructAdvertisementData(
- uint8_t version_number,
base::span<const uint8_t, kCableEphemeralIdSize> client_eid) {
auto advertisement_data = std::make_unique<BluetoothAdvertisement::Data>(
BluetoothAdvertisement::AdvertisementType::ADVERTISEMENT_TYPE_BROADCAST);
@@ -66,7 +67,7 @@ std::unique_ptr<BluetoothAdvertisement::Data> ConstructAdvertisementData(
3u + kCableEphemeralIdSize;
std::array<uint8_t, 4> kCableGoogleManufacturerDataHeader = {
kCableGoogleManufacturerDataLength, kCableGoogleManufacturerDataType,
- kCableFlags, version_number};
+ kCableFlags, /*version=*/1};
auto manufacturer_data =
std::make_unique<BluetoothAdvertisement::ManufacturerData>();
@@ -91,7 +92,7 @@ std::unique_ptr<BluetoothAdvertisement::Data> ConstructAdvertisementData(
// Since the remainder of this service data field is a Cable EID, set the 5th
// bit of the flag byte.
service_data_value[0] = kCableFlags;
- service_data_value[1] = version_number;
+ service_data_value[1] = 1 /* version */;
std::copy(client_eid.begin(), client_eid.end(),
service_data_value.begin() + 2);
service_data->emplace(kCableAdvertisementUUID128,
@@ -109,14 +110,36 @@ std::unique_ptr<BluetoothAdvertisement::Data> ConstructAdvertisementData(
CableDiscoveryData::CableDiscoveryData() = default;
CableDiscoveryData::CableDiscoveryData(
- uint8_t version,
+ CableDiscoveryData::Version version,
const CableEidArray& client_eid,
const CableEidArray& authenticator_eid,
const CableSessionPreKeyArray& session_pre_key)
- : version(version),
- client_eid(client_eid),
- authenticator_eid(authenticator_eid),
- session_pre_key(session_pre_key) {}
+ : version(version) {
+ CHECK_EQ(Version::V1, version);
+ v1.emplace();
+ v1->client_eid = client_eid;
+ v1->authenticator_eid = authenticator_eid;
+ v1->session_pre_key = session_pre_key;
+}
+
+CableDiscoveryData::CableDiscoveryData(
+ base::span<const uint8_t, kCableQRSecretSize> qr_secret) {
+ version = Version::V2;
+ v2.emplace();
+
+ static const char kEIDGen[] = "caBLE QR to EID generator key";
+ bool ok =
+ HKDF(v2->eid_gen_key.data(), v2->eid_gen_key.size(), EVP_sha256(),
+ qr_secret.data(), qr_secret.size(), /*salt=*/nullptr, 0,
+ reinterpret_cast<const uint8_t*>(kEIDGen), sizeof(kEIDGen) - 1);
+ DCHECK(ok);
+
+ static const char kPSKGen[] = "caBLE QR to PSK generator key";
+ ok = HKDF(v2->psk_gen_key.data(), v2->psk_gen_key.size(), EVP_sha256(),
+ qr_secret.data(), qr_secret.size(), /*salt=*/nullptr, 0,
+ reinterpret_cast<const uint8_t*>(kPSKGen), sizeof(kPSKGen) - 1);
+ DCHECK(ok);
+}
CableDiscoveryData::CableDiscoveryData(const CableDiscoveryData& data) =
default;
@@ -127,9 +150,76 @@ CableDiscoveryData& CableDiscoveryData::operator=(
CableDiscoveryData::~CableDiscoveryData() = default;
bool CableDiscoveryData::operator==(const CableDiscoveryData& other) const {
- return version == other.version && client_eid == other.client_eid &&
- authenticator_eid == other.authenticator_eid &&
- session_pre_key == other.session_pre_key;
+ if (version != other.version) {
+ return false;
+ }
+
+ switch (version) {
+ case CableDiscoveryData::Version::V1:
+ return v1->client_eid == other.v1->client_eid &&
+ v1->authenticator_eid == other.v1->authenticator_eid &&
+ v1->session_pre_key == other.v1->session_pre_key;
+
+ case CableDiscoveryData::Version::V2:
+ return v2->eid_gen_key == other.v2->eid_gen_key &&
+ v2->psk_gen_key == other.v2->psk_gen_key &&
+ v2->peer_identity == other.v2->peer_identity &&
+ v2->peer_name == other.v2->peer_name;
+
+ case CableDiscoveryData::Version::INVALID:
+ CHECK(false);
+ return false;
+ }
+}
+
+base::Optional<CableNonce> CableDiscoveryData::Match(
+ const CableEidArray& eid) const {
+ switch (version) {
+ case Version::V1: {
+ if (eid != v1->authenticator_eid) {
+ return base::nullopt;
+ }
+
+ // The nonce is the first eight bytes of the EID.
+ CableNonce nonce;
+ const bool ok =
+ fido_parsing_utils::ExtractArray(v1->client_eid, 0, &nonce);
+ DCHECK(ok);
+ return nonce;
+ }
+
+ case Version::V2: {
+ // Attempt to decrypt the EID with the EID generator key and check whether
+ // it has a valid structure.
+ AES_KEY key;
+ CHECK(AES_set_decrypt_key(v2->eid_gen_key.data(),
+ /*bits=*/8 * v2->eid_gen_key.size(),
+ &key) == 0);
+ static_assert(kCableEphemeralIdSize == AES_BLOCK_SIZE,
+ "EIDs are not AES blocks");
+ CableEidArray decrypted;
+ AES_decrypt(/*in=*/eid.data(), /*out=*/decrypted.data(), &key);
+ const uint8_t kZeroTrailer[8] = {0};
+ static_assert(8 + sizeof(kZeroTrailer) ==
+ std::tuple_size<decltype(decrypted)>::value,
+ "Trailer is wrong size");
+ if (CRYPTO_memcmp(kZeroTrailer, decrypted.data() + 8,
+ sizeof(kZeroTrailer)) != 0) {
+ return base::nullopt;
+ }
+
+ CableNonce nonce;
+ static_assert(
+ sizeof(nonce) <= std::tuple_size<decltype(decrypted)>::value,
+ "nonce too large");
+ memcpy(nonce.data(), decrypted.data(), sizeof(nonce));
+ return nonce;
+ }
+
+ case Version::INVALID:
+ DCHECK(false);
+ return base::nullopt;
+ }
}
// static
@@ -146,10 +236,7 @@ int64_t CableDiscoveryData::CurrentTimeTick() {
}
// static
-void CableDiscoveryData::DeriveQRKeyMaterial(
- base::span<uint8_t, kCableQRSecretSize> out_qr_secret,
- base::span<uint8_t, kCableEphemeralIdSize> out_authenticator_eid,
- base::span<uint8_t, kCableSessionPreKeySize> out_session_key,
+std::array<uint8_t, kCableQRSecretSize> CableDiscoveryData::DeriveQRSecret(
base::span<const uint8_t, 32> qr_generator_key,
const int64_t tick) {
union {
@@ -158,34 +245,53 @@ void CableDiscoveryData::DeriveQRKeyMaterial(
} current_tick;
current_tick.i = tick;
- bool ok = HKDF(out_qr_secret.data(), out_qr_secret.size(), EVP_sha256(),
- qr_generator_key.data(), qr_generator_key.size(),
+ std::array<uint8_t, kCableQRSecretSize> ret;
+ bool ok = HKDF(ret.data(), ret.size(), EVP_sha256(), qr_generator_key.data(),
+ qr_generator_key.size(),
/*salt=*/nullptr, 0, current_tick.bytes, sizeof(current_tick));
DCHECK(ok);
- static const char kAuthenticatorEIDInfo[] = "caBLE QR to EID";
- ok = HKDF(out_authenticator_eid.data(), out_authenticator_eid.size(),
- EVP_sha256(), out_qr_secret.data(), out_qr_secret.size(),
- /*salt=*/nullptr, 0,
- reinterpret_cast<const uint8_t*>(kAuthenticatorEIDInfo),
- sizeof(kAuthenticatorEIDInfo) - 1);
- DCHECK(ok);
- static const char kSessionKeyInfo[] = "caBLE QR to session pre-key";
- ok = HKDF(out_session_key.data(), out_session_key.size(), EVP_sha256(),
- out_qr_secret.data(), out_qr_secret.size(), /*salt=*/nullptr, 0,
- reinterpret_cast<const uint8_t*>(kSessionKeyInfo),
- sizeof(kSessionKeyInfo) - 1);
- DCHECK(ok);
+ return ret;
}
+CableDiscoveryData::V2Data::V2Data() = default;
+CableDiscoveryData::V2Data::V2Data(const V2Data&) = default;
+CableDiscoveryData::V2Data::~V2Data() = default;
+
+// FidoCableDiscovery::Result -------------------------------------------------
+
+FidoCableDiscovery::Result::Result() = default;
+
+FidoCableDiscovery::Result::Result(const CableDiscoveryData& in_discovery_data,
+ const CableNonce& in_nonce,
+ const CableEidArray& in_eid,
+ base::Optional<int> in_ticks_back)
+ : discovery_data(in_discovery_data),
+ nonce(in_nonce),
+ eid(in_eid),
+ ticks_back(in_ticks_back) {}
+
+FidoCableDiscovery::Result::Result(const Result& other) = default;
+
+FidoCableDiscovery::Result::~Result() = default;
+
+// FidoCableDiscovery::ObservedDeviceData -------------------------------------
+
+FidoCableDiscovery::ObservedDeviceData::ObservedDeviceData() = default;
+FidoCableDiscovery::ObservedDeviceData::~ObservedDeviceData() = default;
+
// FidoCableDiscovery ---------------------------------------------------------
FidoCableDiscovery::FidoCableDiscovery(
std::vector<CableDiscoveryData> discovery_data,
- base::Optional<QRGeneratorKey> qr_generator_key)
+ base::Optional<QRGeneratorKey> qr_generator_key,
+ base::Optional<
+ base::RepeatingCallback<void(std::unique_ptr<CableDiscoveryData>)>>
+ pairing_callback)
: FidoBleDiscoveryBase(
FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy),
discovery_data_(std::move(discovery_data)),
- qr_generator_key_(std::move(qr_generator_key)) {
+ qr_generator_key_(std::move(qr_generator_key)),
+ pairing_callback_(std::move(pairing_callback)) {
// Windows currently does not support multiple EIDs, thus we ignore any extra
// discovery data.
// TODO(https://crbug.com/837088): Add support for multiple EIDs on Windows.
@@ -204,32 +310,41 @@ FidoCableDiscovery::~FidoCableDiscovery() {
base::Optional<std::unique_ptr<FidoCableHandshakeHandler>>
FidoCableDiscovery::CreateHandshakeHandler(
FidoCableDevice* device,
- const CableDiscoveryData* discovery_data) {
+ const CableDiscoveryData& discovery_data,
+ const CableNonce& nonce,
+ const CableEidArray& eid) {
std::unique_ptr<FidoCableHandshakeHandler> handler;
- switch (discovery_data->version) {
- case 1: {
+ switch (discovery_data.version) {
+ case CableDiscoveryData::Version::V1: {
// Nonce is embedded as first 8 bytes of client EID.
std::array<uint8_t, 8> nonce;
const bool ok = fido_parsing_utils::ExtractArray(
- discovery_data->client_eid, 0, &nonce);
+ discovery_data.v1->client_eid, 0, &nonce);
DCHECK(ok);
handler.reset(new FidoCableV1HandshakeHandler(
- device, nonce, discovery_data->session_pre_key));
+ device, nonce, discovery_data.v1->session_pre_key));
break;
}
- case 2:
+ case CableDiscoveryData::Version::V2: {
if (!base::FeatureList::IsEnabled(device::kWebAuthPhoneSupport)) {
return base::nullopt;
}
+ if (!pairing_callback_) {
+ FIDO_LOG(DEBUG) << "Discarding caBLE v2 handshake because of missing "
+ "pairing callback";
+ return base::nullopt;
+ }
+
handler.reset(new FidoCableV2HandshakeHandler(
- device, discovery_data->session_pre_key));
+ device, discovery_data.v2->psk_gen_key, nonce, eid,
+ discovery_data.v2->peer_identity, *pairing_callback_));
break;
+ }
- default:
- FIDO_LOG(DEBUG) << "Dropping caBLE handshake request for unknown version "
- << discovery_data->version;
+ case CableDiscoveryData::Version::INVALID:
+ CHECK(false);
return base::nullopt;
}
@@ -241,7 +356,6 @@ void FidoCableDiscovery::DeviceAdded(BluetoothAdapter* adapter,
if (!IsCableDevice(device))
return;
- FIDO_LOG(DEBUG) << "Discovered caBLE device: " << device->GetAddress();
CableDeviceFound(adapter, device);
}
@@ -250,8 +364,6 @@ void FidoCableDiscovery::DeviceChanged(BluetoothAdapter* adapter,
if (!IsCableDevice(device))
return;
- FIDO_LOG(DEBUG) << "Device changed for caBLE device: "
- << device->GetAddress();
CableDeviceFound(adapter, device);
}
@@ -304,26 +416,33 @@ void FidoCableDiscovery::OnStartDiscoverySessionWithFilter(
std::unique_ptr<BluetoothDiscoverySession> session) {
SetDiscoverySession(std::move(session));
FIDO_LOG(DEBUG) << "Discovery session started.";
- StartAdvertisement();
+ // Advertising is delayed by 500ms to ensure that any UI has a chance to
+ // appear as we don't want to start broadcasting without the user being
+ // aware.
+ base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&FidoCableDiscovery::StartAdvertisement,
+ weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(500));
}
void FidoCableDiscovery::StartAdvertisement() {
DCHECK(adapter());
- if (discovery_data_.empty() && qr_generator_key_.has_value()) {
- // If no caBLE extension was provided then there are no BLE advertisements
- // and discovery starts immediately on the assumption that the user will
- // scan a QR-code with their phone.
- NotifyDiscoveryStarted(true);
- return;
- }
-
- FIDO_LOG(DEBUG) << "Starting to advertise clientEID.";
+ bool advertisements_pending = false;
for (const auto& data : discovery_data_) {
+ if (data.version != CableDiscoveryData::Version::V1) {
+ continue;
+ }
+
+ if (!advertisements_pending) {
+ FIDO_LOG(DEBUG) << "Starting to advertise clientEIDs.";
+ advertisements_pending = true;
+ }
adapter()->RegisterAdvertisement(
- ConstructAdvertisementData(data.version, data.client_eid),
+ ConstructAdvertisementData(data.v1->client_eid),
base::AdaptCallbackForRepeating(
base::BindOnce(&FidoCableDiscovery::OnAdvertisementRegistered,
- weak_factory_.GetWeakPtr(), data.client_eid)),
+ weak_factory_.GetWeakPtr(), data.v1->client_eid)),
base::AdaptCallbackForRepeating(
base::BindOnce(&FidoCableDiscovery::OnAdvertisementRegisterError,
weak_factory_.GetWeakPtr())));
@@ -363,45 +482,43 @@ void FidoCableDiscovery::OnAdvertisementRegisterError(
void FidoCableDiscovery::RecordAdvertisementResult(bool is_success) {
// If at least one advertisement succeeds, then notify discovery start.
if (is_success) {
- if (!advertisement_success_counter_++)
- NotifyDiscoveryStarted(true);
- return;
+ advertisement_success_counter_++;
+ } else {
+ advertisement_failure_counter_++;
}
-
- // No advertisements succeeded, no point in continuing with Cable discovery.
- if (++advertisement_failure_counter_ == discovery_data_.size())
- NotifyDiscoveryStarted(false);
}
void FidoCableDiscovery::CableDeviceFound(BluetoothAdapter* adapter,
BluetoothDevice* device) {
- base::Optional<CableDiscoveryData> found_cable_device_data =
- GetCableDiscoveryData(device);
const std::string device_address = device->GetAddress();
- if (!found_cable_device_data ||
- base::Contains(active_authenticator_eids_,
- found_cable_device_data->authenticator_eid) ||
- base::Contains(active_devices_, device_address)) {
+ if (base::Contains(active_devices_, device_address)) {
+ return;
+ }
+
+ base::Optional<Result> maybe_result = GetCableDiscoveryData(device);
+ if (!maybe_result ||
+ base::Contains(active_authenticator_eids_, maybe_result->eid)) {
return;
}
FIDO_LOG(EVENT) << "Found new caBLE device.";
- active_authenticator_eids_.insert(found_cable_device_data->authenticator_eid);
active_devices_.insert(device_address);
+ active_authenticator_eids_.insert(maybe_result->eid);
auto cable_device =
std::make_unique<FidoCableDevice>(adapter, device->GetAddress());
StopAdvertisements(
base::BindOnce(&FidoCableDiscovery::ConductEncryptionHandshake,
weak_factory_.GetWeakPtr(), std::move(cable_device),
- std::move(*found_cable_device_data)));
+ std::move(*maybe_result)));
}
void FidoCableDiscovery::ConductEncryptionHandshake(
std::unique_ptr<FidoCableDevice> cable_device,
- CableDiscoveryData discovery_data) {
+ FidoCableDiscovery::Result result) {
base::Optional<std::unique_ptr<FidoCableHandshakeHandler>> handshake_handler =
- CreateHandshakeHandler(cable_device.get(), &discovery_data);
+ CreateHandshakeHandler(cable_device.get(), result.discovery_data,
+ result.nonce, result.eid);
if (!handshake_handler) {
return;
}
@@ -430,24 +547,65 @@ void FidoCableDiscovery::ValidateAuthenticatorHandshakeMessage(
}
}
-base::Optional<CableDiscoveryData> FidoCableDiscovery::GetCableDiscoveryData(
- const BluetoothDevice* device) const {
- auto maybe_discovery_data = GetCableDiscoveryDataFromServiceData(device);
- if (maybe_discovery_data) {
- FIDO_LOG(DEBUG) << "Found caBLE service data.";
- return maybe_discovery_data;
+base::Optional<FidoCableDiscovery::Result>
+FidoCableDiscovery::GetCableDiscoveryData(const BluetoothDevice* device) const {
+ base::Optional<CableEidArray> maybe_eid_from_service_data =
+ MaybeGetEidFromServiceData(device);
+ std::vector<CableEidArray> uuids = GetUUIDs(device);
+
+ const std::string address = device->GetAddress();
+ const auto it = observed_devices_.find(address);
+ const bool known = it != observed_devices_.end();
+ if (known) {
+ std::unique_ptr<ObservedDeviceData>& data = it->second;
+ if (maybe_eid_from_service_data == data->service_data &&
+ uuids == data->uuids) {
+ // Duplicate data. Ignore.
+ return base::nullopt;
+ }
+ }
+
+ auto data = std::make_unique<ObservedDeviceData>();
+ data->service_data = maybe_eid_from_service_data;
+ data->uuids = uuids;
+ observed_devices_.insert_or_assign(address, std::move(data));
+
+ // New or updated device information.
+ if (known) {
+ FIDO_LOG(DEBUG) << "Updated information for caBLE device " << address
+ << ":";
+ } else {
+ FIDO_LOG(DEBUG) << "New caBLE device " << address << ":";
}
- FIDO_LOG(DEBUG)
- << "caBLE service data not found. Searching for caBLE UUIDs instead.";
- // iOS devices cannot advertise service data. These devices instead put the
- // authenticator EID as a second UUID in addition to the caBLE UUID.
- return GetCableDiscoveryDataFromServiceUUIDs(device);
+ base::Optional<FidoCableDiscovery::Result> ret;
+ if (maybe_eid_from_service_data.has_value()) {
+ ret =
+ GetCableDiscoveryDataFromAuthenticatorEid(*maybe_eid_from_service_data);
+ FIDO_LOG(DEBUG) << " Service data: "
+ << ResultDebugString(*maybe_eid_from_service_data, ret);
+
+ } else {
+ FIDO_LOG(DEBUG) << " Service data: <none>";
+ }
+
+ if (!uuids.empty()) {
+ FIDO_LOG(DEBUG) << " UUIDs:";
+ for (const auto& uuid : uuids) {
+ auto result = GetCableDiscoveryDataFromAuthenticatorEid(uuid);
+ FIDO_LOG(DEBUG) << " " << ResultDebugString(uuid, result);
+ if (!ret.has_value() && result.has_value()) {
+ ret = result;
+ }
+ }
+ }
+
+ return ret;
}
-base::Optional<CableDiscoveryData>
-FidoCableDiscovery::GetCableDiscoveryDataFromServiceData(
- const BluetoothDevice* device) const {
+// static
+base::Optional<CableEidArray> FidoCableDiscovery::MaybeGetEidFromServiceData(
+ const BluetoothDevice* device) {
const auto* service_data =
device->GetServiceDataForUUID(CableAdvertisementUUID());
if (!service_data) {
@@ -464,19 +622,16 @@ FidoCableDiscovery::GetCableDiscoveryDataFromServiceData(
*service_data, 2, &received_authenticator_eid);
if (!extract_success)
return base::nullopt;
-
- return GetCableDiscoveryDataFromAuthenticatorEid(
- std::move(received_authenticator_eid));
+ return received_authenticator_eid;
}
-base::Optional<CableDiscoveryData>
-FidoCableDiscovery::GetCableDiscoveryDataFromServiceUUIDs(
- const BluetoothDevice* device) const {
+// static
+std::vector<CableEidArray> FidoCableDiscovery::GetUUIDs(
+ const BluetoothDevice* device) {
+ std::vector<CableEidArray> ret;
+
const auto service_uuids = device->GetUUIDs();
for (const auto& uuid : service_uuids) {
- if (uuid == CableAdvertisementUUID())
- continue;
-
// |uuid_hex| is a hex string with the format:
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
const std::string& uuid_hex = uuid.canonical_value();
@@ -501,47 +656,52 @@ FidoCableDiscovery::GetCableDiscoveryDataFromServiceUUIDs(
memcpy(authenticator_eid.data(), uuid_binary.data(),
authenticator_eid.size());
- auto match = GetCableDiscoveryDataFromAuthenticatorEid(authenticator_eid);
- if (match.has_value()) {
- return match;
- }
+ ret.emplace_back(std::move(authenticator_eid));
}
- return base::nullopt;
+ return ret;
}
-base::Optional<CableDiscoveryData>
+base::Optional<FidoCableDiscovery::Result>
FidoCableDiscovery::GetCableDiscoveryDataFromAuthenticatorEid(
CableEidArray authenticator_eid) const {
- auto discovery_data_iterator =
- std::find_if(discovery_data_.begin(), discovery_data_.end(),
- [&authenticator_eid](const auto& data) {
- return authenticator_eid == data.authenticator_eid;
- });
-
- if (discovery_data_iterator != discovery_data_.end()) {
- return *discovery_data_iterator;
+ for (const auto& candidate : discovery_data_) {
+ auto maybe_nonce = candidate.Match(authenticator_eid);
+ if (maybe_nonce) {
+ return Result(candidate, *maybe_nonce, authenticator_eid, base::nullopt);
+ }
}
if (qr_generator_key_) {
// Attempt to match |authenticator_eid| as the result of scanning a QR code.
const int64_t current_tick = CableDiscoveryData::CurrentTimeTick();
// kNumPreviousTicks is the number of previous ticks that will be accepted
- // as valid. Ticks are currently 256ms so the value of eight translates to a
- // couple of seconds.
- constexpr int kNumPreviousTicks = 8;
+ // as valid. Ticks are currently 256ms so the value of sixteen translates to
+ // about four seconds.
+ constexpr int kNumPreviousTicks = 16;
for (int i = 0; i < kNumPreviousTicks; i++) {
- uint8_t qr_secret[device::kCableQRSecretSize];
- CableEidArray expected_authenticator_eid;
- CableSessionPreKeyArray session_pre_key;
- CableDiscoveryData::DeriveQRKeyMaterial(
- qr_secret, expected_authenticator_eid, session_pre_key,
- *qr_generator_key_, current_tick - i);
- if (expected_authenticator_eid == authenticator_eid) {
- CableEidArray zero_eid{};
- return CableDiscoveryData(/*version=*/2, zero_eid, authenticator_eid,
- session_pre_key);
+ auto qr_secret = CableDiscoveryData::DeriveQRSecret(*qr_generator_key_,
+ current_tick - i);
+ CableDiscoveryData candidate(qr_secret);
+ auto maybe_nonce = candidate.Match(authenticator_eid);
+ if (maybe_nonce) {
+ return Result(candidate, *maybe_nonce, authenticator_eid, i);
+ }
+ }
+
+ if (base::Contains(noted_obsolete_eids_, authenticator_eid)) {
+ for (int i = kNumPreviousTicks; i < 2 * kNumPreviousTicks; i++) {
+ auto qr_secret = CableDiscoveryData::DeriveQRSecret(*qr_generator_key_,
+ current_tick - i);
+ CableDiscoveryData candidate(qr_secret);
+ if (candidate.Match(authenticator_eid)) {
+ noted_obsolete_eids_.insert(authenticator_eid);
+ FIDO_LOG(DEBUG)
+ << "(EID " << base::HexEncode(authenticator_eid) << " is " << i
+ << " ticks old and would be valid but for the cutoff)";
+ break;
+ }
}
}
}
@@ -549,4 +709,69 @@ FidoCableDiscovery::GetCableDiscoveryDataFromAuthenticatorEid(
return base::nullopt;
}
+// static
+std::string FidoCableDiscovery::ResultDebugString(
+ const CableEidArray& eid,
+ const base::Optional<FidoCableDiscovery::Result>& result) {
+ static const uint8_t kAppleContinuity[16] = {
+ 0xd0, 0x61, 0x1e, 0x78, 0xbb, 0xb4, 0x45, 0x91,
+ 0xa5, 0xf8, 0x48, 0x79, 0x10, 0xae, 0x43, 0x66,
+ };
+ static const uint8_t kAppleUnknown[16] = {
+ 0x9f, 0xa4, 0x80, 0xe0, 0x49, 0x67, 0x45, 0x42,
+ 0x93, 0x90, 0xd3, 0x43, 0xdc, 0x5d, 0x04, 0xae,
+ };
+ static const uint8_t kAppleMedia[16] = {
+ 0x89, 0xd3, 0x50, 0x2b, 0x0f, 0x36, 0x43, 0x3a,
+ 0x8e, 0xf4, 0xc5, 0x02, 0xad, 0x55, 0xf8, 0xdc,
+ };
+ static const uint8_t kAppleNotificationCenter[16] = {
+ 0x79, 0x05, 0xf4, 0x31, 0xb5, 0xce, 0x4e, 0x99,
+ 0xa4, 0x0f, 0x4b, 0x1e, 0x12, 0x2d, 0x00, 0xd0,
+ };
+ static const uint8_t kCable[16] = {
+ 0x00, 0x00, 0xfd, 0xe2, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+ };
+
+ std::string ret = base::HexEncode(eid) + "";
+
+ if (!result) {
+ // Try to identify some common UUIDs that are random and thus otherwise look
+ // like potential EIDs.
+ if (memcmp(eid.data(), kAppleContinuity, eid.size()) == 0) {
+ ret += " (Apple Continuity service)";
+ } else if (memcmp(eid.data(), kAppleUnknown, eid.size()) == 0) {
+ ret += " (Apple service)";
+ } else if (memcmp(eid.data(), kAppleMedia, eid.size()) == 0) {
+ ret += " (Apple Media service)";
+ } else if (memcmp(eid.data(), kAppleNotificationCenter, eid.size()) == 0) {
+ ret += " (Apple Notification service)";
+ } else if (memcmp(eid.data(), kCable, eid.size()) == 0) {
+ ret += " (caBLE indicator)";
+ }
+ return ret;
+ }
+
+ switch (result->discovery_data.version) {
+ case CableDiscoveryData::Version::V1:
+ ret += " (version one match";
+ break;
+ case CableDiscoveryData::Version::V2:
+ ret += " (version two match";
+ break;
+ case CableDiscoveryData::Version::INVALID:
+ NOTREACHED();
+ }
+
+ if (!result->ticks_back) {
+ ret += " against pairing data)";
+ } else {
+ ret += " from QR, " + base::NumberToString(*result->ticks_back) +
+ " tick(s) ago)";
+ }
+
+ return ret;
+}
+
} // namespace device
diff --git a/chromium/device/fido/cable/fido_cable_discovery.h b/chromium/device/fido/cable/fido_cable_discovery.h
index 55dd744be5d..96878e1e7da 100644
--- a/chromium/device/fido/cable/fido_cable_discovery.h
+++ b/chromium/device/fido/cable/fido_cable_discovery.h
@@ -31,16 +31,53 @@ class FidoCableHandshakeHandler;
class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDiscovery
: public FidoBleDiscoveryBase {
public:
- FidoCableDiscovery(std::vector<CableDiscoveryData> discovery_data,
- base::Optional<QRGeneratorKey> qr_generator_key);
+ FidoCableDiscovery(
+ std::vector<CableDiscoveryData> discovery_data,
+ base::Optional<QRGeneratorKey> qr_generator_key,
+ base::Optional<
+ base::RepeatingCallback<void(std::unique_ptr<CableDiscoveryData>)>>
+ pairing_callback);
~FidoCableDiscovery() override;
protected:
virtual base::Optional<std::unique_ptr<FidoCableHandshakeHandler>>
CreateHandshakeHandler(FidoCableDevice* device,
- const CableDiscoveryData* discovery_data);
+ const CableDiscoveryData& discovery_data,
+ const CableNonce& nonce,
+ const CableEidArray& eid);
private:
+ // Result represents a successful match of a received EID against a specific
+ // |FidoDiscoveryData|.
+ struct Result {
+ Result();
+ Result(const CableDiscoveryData& in_discovery_data,
+ const CableNonce& in_nonce,
+ const CableEidArray& in_eid,
+ base::Optional<int> ticks_back);
+ Result(const Result&);
+ ~Result();
+
+ CableDiscoveryData discovery_data;
+ CableNonce nonce;
+ CableEidArray eid;
+ // ticks_back is either |base::nullopt|, if the Result is from established
+ // discovery pairings, or else contains the number of QR ticks back in time
+ // against which the match was found.
+ base::Optional<int> ticks_back;
+ };
+
+ // ObservedDeviceData contains potential EIDs observed from a BLE device. This
+ // information is kept in order to de-duplicate device-log entries and make
+ // debugging easier.
+ struct ObservedDeviceData {
+ ObservedDeviceData();
+ ~ObservedDeviceData();
+
+ base::Optional<CableEidArray> service_data;
+ std::vector<CableEidArray> uuids;
+ };
+
FRIEND_TEST_ALL_PREFIXES(FidoCableDiscoveryTest,
TestDiscoveryWithAdvertisementFailures);
FRIEND_TEST_ALL_PREFIXES(FidoCableDiscoveryTest,
@@ -77,20 +114,23 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDiscovery
void StopAdvertisements(base::OnceClosure callback);
void CableDeviceFound(BluetoothAdapter* adapter, BluetoothDevice* device);
void ConductEncryptionHandshake(std::unique_ptr<FidoCableDevice> cable_device,
- CableDiscoveryData discovery_data);
+ Result discovery_data);
void ValidateAuthenticatorHandshakeMessage(
std::unique_ptr<FidoCableDevice> cable_device,
FidoCableHandshakeHandler* handshake_handler,
base::Optional<std::vector<uint8_t>> handshake_response);
- base::Optional<CableDiscoveryData> GetCableDiscoveryData(
- const BluetoothDevice* device) const;
- base::Optional<CableDiscoveryData> GetCableDiscoveryDataFromServiceData(
+ base::Optional<Result> GetCableDiscoveryData(
const BluetoothDevice* device) const;
- base::Optional<CableDiscoveryData> GetCableDiscoveryDataFromServiceUUIDs(
- const BluetoothDevice* device) const;
- base::Optional<CableDiscoveryData> GetCableDiscoveryDataFromAuthenticatorEid(
+ static base::Optional<CableEidArray> MaybeGetEidFromServiceData(
+ const BluetoothDevice* device);
+ static std::vector<CableEidArray> GetUUIDs(const BluetoothDevice* device);
+ base::Optional<Result> GetCableDiscoveryDataFromAuthenticatorEid(
CableEidArray authenticator_eid) const;
+ // ResultDebugString returns a containing a hex dump of |eid| and a
+ // description of |result|, if present.
+ static std::string ResultDebugString(const CableEidArray& eid,
+ const base::Optional<Result>& result);
std::vector<CableDiscoveryData> discovery_data_;
// active_authenticator_eids_ contains authenticator EIDs for which a
@@ -109,6 +149,18 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDiscovery
advertisements_;
std::vector<std::unique_ptr<FidoCableHandshakeHandler>>
cable_handshake_handlers_;
+ base::Optional<
+ base::RepeatingCallback<void(std::unique_ptr<CableDiscoveryData>)>>
+ pairing_callback_;
+
+ // observed_devices_ caches the information from observed caBLE devices so
+ // that the device-log isn't spammed.
+ mutable base::flat_map<std::string, std::unique_ptr<ObservedDeviceData>>
+ observed_devices_;
+ // noted_obsolete_eids_ remembers QR-code EIDs that have been logged as
+ // valid-but-expired in order to avoid spamming the device-log.
+ mutable base::flat_set<CableEidArray> noted_obsolete_eids_;
+
base::WeakPtrFactory<FidoCableDiscovery> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(FidoCableDiscovery);
diff --git a/chromium/device/fido/cable/fido_cable_discovery_unittest.cc b/chromium/device/fido/cable/fido_cable_discovery_unittest.cc
index c7cac3ae0cb..24364aade0e 100644
--- a/chromium/device/fido/cable/fido_cable_discovery_unittest.cc
+++ b/chromium/device/fido/cable/fido_cable_discovery_unittest.cc
@@ -25,14 +25,17 @@
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
-using ::testing::Sequence;
using ::testing::NiceMock;
+using ::testing::Sequence;
namespace device {
namespace {
-constexpr uint8_t kTestCableVersionNumber = 0x01;
+constexpr auto kTestCableVersion = CableDiscoveryData::Version::V1;
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+constexpr auto kTestCableVersionNumber = 1;
+#endif
// Constants required for discovering and constructing a Cable device that
// are given by the relying party via an extension.
@@ -291,20 +294,19 @@ class FakeFidoCableDiscovery : public FidoCableDiscovery {
public:
explicit FakeFidoCableDiscovery(
std::vector<CableDiscoveryData> discovery_data)
- : FidoCableDiscovery(std::move(discovery_data), BogusQRGeneratorKey()) {}
+ : FidoCableDiscovery(std::move(discovery_data),
+ BogusQRGeneratorKey(),
+ /*pairing_callback=*/base::nullopt) {}
~FakeFidoCableDiscovery() override = default;
private:
base::Optional<std::unique_ptr<FidoCableHandshakeHandler>>
CreateHandshakeHandler(FidoCableDevice* device,
- const CableDiscoveryData* discovery_data) override {
- // Nonce is embedded as first 8 bytes of client EID.
- std::array<uint8_t, 8> nonce;
- const bool ok =
- fido_parsing_utils::ExtractArray(discovery_data->client_eid, 0, &nonce);
- DCHECK(ok);
+ const CableDiscoveryData& discovery_data,
+ const CableNonce& nonce,
+ const CableEidArray& eid) override {
return std::make_unique<FakeHandshakeHandler>(
- device, nonce, discovery_data->session_pre_key);
+ device, nonce, discovery_data.v1->session_pre_key);
}
static std::array<uint8_t, 32> BogusQRGeneratorKey() {
@@ -320,18 +322,63 @@ class FidoCableDiscoveryTest : public ::testing::Test {
public:
std::unique_ptr<FidoCableDiscovery> CreateDiscovery() {
std::vector<CableDiscoveryData> discovery_data;
- discovery_data.emplace_back(kTestCableVersionNumber, kClientEid,
+ discovery_data.emplace_back(kTestCableVersion, kClientEid,
kAuthenticatorEid, kTestSessionPreKey);
return std::make_unique<FakeFidoCableDiscovery>(std::move(discovery_data));
}
- base::test::TaskEnvironment task_environment_;
+ base::test::TaskEnvironment task_environment_{
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME};
};
+// Tests discovery without a BLE adapter.
+TEST_F(FidoCableDiscoveryTest, TestDiscoveryFails) {
+ auto cable_discovery = CreateDiscovery();
+ NiceMock<MockFidoDiscoveryObserver> mock_observer;
+ EXPECT_CALL(mock_observer,
+ DiscoveryStarted(cable_discovery.get(), false,
+ std::vector<FidoAuthenticator*>()));
+ EXPECT_CALL(mock_observer, AuthenticatorAdded(_, _)).Times(0);
+ cable_discovery->set_observer(&mock_observer);
+
+ auto mock_adapter =
+ base::MakeRefCounted<::testing::NiceMock<CableMockAdapter>>();
+ EXPECT_CALL(*mock_adapter, IsPresent()).WillOnce(::testing::Return(false));
+
+ BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
+ cable_discovery->Start();
+ task_environment_.FastForwardUntilNoTasksRemain();
+}
+
+// Tests discovery with a powered-off BLE adapter. Not calling
+// DiscoveryStarted() in the case of a present-but-unpowered adapter leads to a
+// deadlock between the discovery and the UI (see crbug.com/1018416).
+TEST_F(FidoCableDiscoveryTest, TestDiscoveryStartedWithUnpoweredAdapter) {
+ auto cable_discovery = CreateDiscovery();
+ NiceMock<MockFidoDiscoveryObserver> mock_observer;
+ EXPECT_CALL(mock_observer,
+ DiscoveryStarted(cable_discovery.get(), true,
+ std::vector<FidoAuthenticator*>()));
+ EXPECT_CALL(mock_observer, AuthenticatorAdded(_, _)).Times(0);
+ cable_discovery->set_observer(&mock_observer);
+
+ auto mock_adapter =
+ base::MakeRefCounted<::testing::NiceMock<CableMockAdapter>>();
+ EXPECT_CALL(*mock_adapter, IsPresent()).WillOnce(::testing::Return(true));
+ EXPECT_CALL(*mock_adapter, IsPowered()).WillOnce(::testing::Return(false));
+
+ BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
+ cable_discovery->Start();
+ task_environment_.FastForwardUntilNoTasksRemain();
+}
+
// Tests regular successful discovery flow for Cable device.
TEST_F(FidoCableDiscoveryTest, TestDiscoveryFindsNewDevice) {
auto cable_discovery = CreateDiscovery();
NiceMock<MockFidoDiscoveryObserver> mock_observer;
+ EXPECT_CALL(mock_observer,
+ DiscoveryStarted(cable_discovery.get(), true,
+ std::vector<FidoAuthenticator*>()));
EXPECT_CALL(mock_observer, AuthenticatorAdded(_, _));
cable_discovery->set_observer(&mock_observer);
@@ -344,13 +391,16 @@ TEST_F(FidoCableDiscoveryTest, TestDiscoveryFindsNewDevice) {
BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
cable_discovery->Start();
- task_environment_.RunUntilIdle();
+ task_environment_.FastForwardUntilNoTasksRemain();
}
// Tests successful discovery flow for Apple Cable device.
TEST_F(FidoCableDiscoveryTest, TestDiscoveryFindsNewAppleDevice) {
auto cable_discovery = CreateDiscovery();
NiceMock<MockFidoDiscoveryObserver> mock_observer;
+ EXPECT_CALL(mock_observer,
+ DiscoveryStarted(cable_discovery.get(), true,
+ std::vector<FidoAuthenticator*>()));
EXPECT_CALL(mock_observer, AuthenticatorAdded(_, _));
cable_discovery->set_observer(&mock_observer);
@@ -363,7 +413,7 @@ TEST_F(FidoCableDiscoveryTest, TestDiscoveryFindsNewAppleDevice) {
BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
cable_discovery->Start();
- task_environment_.RunUntilIdle();
+ task_environment_.FastForwardUntilNoTasksRemain();
}
// Tests a scenario where upon broadcasting advertisement and scanning, client
@@ -373,6 +423,8 @@ TEST_F(FidoCableDiscoveryTest, TestDiscoveryFindsIncorrectDevice) {
auto cable_discovery = CreateDiscovery();
NiceMock<MockFidoDiscoveryObserver> mock_observer;
EXPECT_CALL(mock_observer, AuthenticatorAdded(_, _)).Times(0);
+ EXPECT_CALL(mock_observer, DiscoveryStarted(cable_discovery.get(), true,
+ testing::IsEmpty()));
cable_discovery->set_observer(&mock_observer);
auto mock_adapter =
@@ -384,7 +436,7 @@ TEST_F(FidoCableDiscoveryTest, TestDiscoveryFindsIncorrectDevice) {
BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
cable_discovery->Start();
- task_environment_.RunUntilIdle();
+ task_environment_.FastForwardUntilNoTasksRemain();
}
// Windows currently does not support multiple EIDs, so the following tests are
@@ -397,9 +449,9 @@ TEST_F(FidoCableDiscoveryTest, TestDiscoveryFindsIncorrectDevice) {
// BluetoothAdapter::RegisterAdvertisement().
TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithMultipleEids) {
std::vector<CableDiscoveryData> discovery_data;
- discovery_data.emplace_back(kTestCableVersionNumber, kClientEid,
- kAuthenticatorEid, kTestSessionPreKey);
- discovery_data.emplace_back(kTestCableVersionNumber, kSecondaryClientEid,
+ discovery_data.emplace_back(kTestCableVersion, kClientEid, kAuthenticatorEid,
+ kTestSessionPreKey);
+ discovery_data.emplace_back(kTestCableVersion, kSecondaryClientEid,
kSecondaryAuthenticatorEid,
kSecondarySessionPreKey);
auto cable_discovery =
@@ -410,6 +462,9 @@ TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithMultipleEids) {
mock_adapter->ExpectDiscoveryWithScanCallback(kAuthenticatorEid);
NiceMock<MockFidoDiscoveryObserver> mock_observer;
+ EXPECT_CALL(mock_observer,
+ DiscoveryStarted(cable_discovery.get(), true,
+ std::vector<FidoAuthenticator*>()));
EXPECT_CALL(mock_observer, AuthenticatorAdded(_, _));
cable_discovery->set_observer(&mock_observer);
@@ -423,7 +478,7 @@ TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithMultipleEids) {
BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
cable_discovery->Start();
- task_environment_.RunUntilIdle();
+ task_environment_.FastForwardUntilNoTasksRemain();
}
// Tests a scenario where only one of the two client EID's are advertised
@@ -431,14 +486,17 @@ TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithMultipleEids) {
// scanning process should be invoked.
TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithPartialAdvertisementSuccess) {
std::vector<CableDiscoveryData> discovery_data;
- discovery_data.emplace_back(kTestCableVersionNumber, kClientEid,
- kAuthenticatorEid, kTestSessionPreKey);
- discovery_data.emplace_back(kTestCableVersionNumber, kSecondaryClientEid,
+ discovery_data.emplace_back(kTestCableVersion, kClientEid, kAuthenticatorEid,
+ kTestSessionPreKey);
+ discovery_data.emplace_back(kTestCableVersion, kSecondaryClientEid,
kSecondaryAuthenticatorEid,
kSecondarySessionPreKey);
auto cable_discovery =
std::make_unique<FakeFidoCableDiscovery>(std::move(discovery_data));
NiceMock<MockFidoDiscoveryObserver> mock_observer;
+ EXPECT_CALL(mock_observer,
+ DiscoveryStarted(cable_discovery.get(), true,
+ std::vector<FidoAuthenticator*>()));
EXPECT_CALL(mock_observer, AuthenticatorAdded(_, _));
cable_discovery->set_observer(&mock_observer);
@@ -456,15 +514,15 @@ TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithPartialAdvertisementSuccess) {
BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
cable_discovery->Start();
- task_environment_.RunUntilIdle();
+ task_environment_.FastForwardUntilNoTasksRemain();
}
// Test the scenario when all advertisement for client EID's fails.
TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithAdvertisementFailures) {
std::vector<CableDiscoveryData> discovery_data;
- discovery_data.emplace_back(kTestCableVersionNumber, kClientEid,
- kAuthenticatorEid, kTestSessionPreKey);
- discovery_data.emplace_back(kTestCableVersionNumber, kSecondaryClientEid,
+ discovery_data.emplace_back(kTestCableVersion, kClientEid, kAuthenticatorEid,
+ kTestSessionPreKey);
+ discovery_data.emplace_back(kTestCableVersion, kSecondaryClientEid,
kSecondaryAuthenticatorEid,
kSecondarySessionPreKey);
auto cable_discovery =
@@ -472,6 +530,8 @@ TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithAdvertisementFailures) {
NiceMock<MockFidoDiscoveryObserver> mock_observer;
EXPECT_CALL(mock_observer, AuthenticatorAdded(_, _)).Times(0);
+ EXPECT_CALL(mock_observer, DiscoveryStarted(cable_discovery.get(), true,
+ testing::IsEmpty()));
cable_discovery->set_observer(&mock_observer);
auto mock_adapter =
@@ -488,7 +548,7 @@ TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithAdvertisementFailures) {
BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
cable_discovery->Start();
- task_environment_.RunUntilIdle();
+ task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_TRUE(cable_discovery->advertisements_.empty());
}
#endif // !defined(OS_WIN)
@@ -509,7 +569,7 @@ TEST_F(FidoCableDiscoveryTest, TestUnregisterAdvertisementUponDestruction) {
BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
cable_discovery->Start();
- task_environment_.RunUntilIdle();
+ task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(1u, cable_discovery->advertisements_.size());
cable_discovery.reset();
@@ -519,7 +579,10 @@ TEST_F(FidoCableDiscoveryTest, TestUnregisterAdvertisementUponDestruction) {
TEST_F(FidoCableDiscoveryTest, TestResumeDiscoveryAfterPoweredOn) {
auto cable_discovery = CreateDiscovery();
NiceMock<MockFidoDiscoveryObserver> mock_observer;
- EXPECT_CALL(mock_observer, AuthenticatorAdded);
+ EXPECT_CALL(mock_observer,
+ DiscoveryStarted(cable_discovery.get(), true,
+ std::vector<FidoAuthenticator*>()));
+ EXPECT_CALL(mock_observer, AuthenticatorAdded(_, _));
cable_discovery->set_observer(&mock_observer);
auto mock_adapter =
@@ -548,6 +611,7 @@ TEST_F(FidoCableDiscoveryTest, TestResumeDiscoveryAfterPoweredOn) {
}
mock_adapter->NotifyAdapterPoweredChanged(true);
+ task_environment_.FastForwardUntilNoTasksRemain();
}
} // namespace device
diff --git a/chromium/device/fido/cable/fido_cable_handshake_handler.cc b/chromium/device/fido/cable/fido_cable_handshake_handler.cc
index 76d7f5bdb7c..c7c26ea52b9 100644
--- a/chromium/device/fido/cable/fido_cable_handshake_handler.cc
+++ b/chromium/device/fido/cable/fido_cable_handshake_handler.cc
@@ -155,7 +155,7 @@ bool FidoCableV1HandshakeHandler::ValidateAuthenticatorHandshakeMessage(
return false;
}
- cable_device_->SetEncryptionData(
+ cable_device_->SetV1EncryptionData(
base::make_span<32>(
GetEncryptionKeyAfterSuccessfulHandshake(base::make_span<16>(
authenticator_random_nonce->second.GetBytestring()))),
@@ -176,19 +176,32 @@ FidoCableV1HandshakeHandler::GetEncryptionKeyAfterSuccessfulHandshake(
/*derived_key_length=*/32);
}
+// kP256PointSize is the number of bytes in an X9.62 encoding of a P-256 point.
+static constexpr size_t kP256PointSize = 65;
+
FidoCableV2HandshakeHandler::FidoCableV2HandshakeHandler(
FidoCableDevice* cable_device,
- base::span<const uint8_t, 32> session_pre_key)
+ base::span<const uint8_t, 32> psk_gen_key,
+ base::span<const uint8_t, 8> nonce,
+ base::span<const uint8_t, kCableEphemeralIdSize> eid,
+ base::Optional<base::span<const uint8_t, kP256PointSize>> peer_identity,
+ base::RepeatingCallback<void(std::unique_ptr<CableDiscoveryData>)>
+ pairing_callback)
: cable_device_(cable_device),
- session_pre_key_(fido_parsing_utils::Materialize(session_pre_key)) {}
+ eid_(fido_parsing_utils::Materialize(eid)),
+ pairing_callback_(std::move(pairing_callback)) {
+ HKDF(psk_.data(), psk_.size(), EVP_sha256(), psk_gen_key.data(),
+ psk_gen_key.size(), /*salt=*/nonce.data(), nonce.size(),
+ /*info=*/nullptr, 0);
+ if (peer_identity) {
+ peer_identity_ = fido_parsing_utils::Materialize(*peer_identity);
+ }
+}
FidoCableV2HandshakeHandler::~FidoCableV2HandshakeHandler() {}
namespace {
-// P256PointSize is the number of bytes in an X9.62 encoding of a P-256 point.
-constexpr size_t P256PointSize = 65;
-
// HKDF2 implements the functions with the same name from Noise[1], specialized
// to the case where |num_outputs| is two.
//
@@ -198,7 +211,7 @@ std::tuple<std::array<uint8_t, 32>, std::array<uint8_t, 32>> HKDF2(
base::span<const uint8_t> ikm) {
uint8_t output[32 * 2];
HKDF(output, sizeof(output), EVP_sha256(), ikm.data(), ikm.size(), ck.data(),
- ck.size(), /*salt=*/nullptr, 0);
+ ck.size(), /*info=*/nullptr, 0);
std::array<uint8_t, 32> a, b;
memcpy(a.data(), &output[0], 32);
@@ -217,7 +230,7 @@ std::tuple<std::array<uint8_t, 32>,
HKDF3(base::span<const uint8_t, 32> ck, base::span<const uint8_t> ikm) {
uint8_t output[32 * 3];
HKDF(output, sizeof(output), EVP_sha256(), ikm.data(), ikm.size(), ck.data(),
- ck.size(), /*salt=*/nullptr, 0);
+ ck.size(), /*info=*/nullptr, 0);
std::array<uint8_t, 32> a, b, c;
memcpy(a.data(), &output[0], 32);
@@ -227,44 +240,86 @@ HKDF3(base::span<const uint8_t, 32> ck, base::span<const uint8_t> ikm) {
return std::make_tuple(a, b, c);
}
+template <size_t N>
+bool CopyBytestring(std::array<uint8_t, N>* out,
+ const cbor::Value::MapValue& map,
+ int key) {
+ const auto it = map.find(cbor::Value(key));
+ if (it == map.end() || !it->second.is_bytestring()) {
+ return false;
+ }
+ const std::vector<uint8_t> bytestring = it->second.GetBytestring();
+ return fido_parsing_utils::ExtractArray(bytestring, /*pos=*/0, out);
+}
+
} // namespace
void FidoCableV2HandshakeHandler::InitiateCableHandshake(
FidoDevice::DeviceCallback callback) {
// See https://www.noiseprotocol.org/noise.html#the-handshakestate-object
- static const char kProtocolName[] = "Noise_NNpsk0_P256_AESGCM_SHA256";
- static_assert(sizeof(kProtocolName) == crypto::kSHA256Length,
+ static const char kNNProtocolName[] = "Noise_NNpsk0_P256_AESGCM_SHA256";
+ static const char kNKProtocolName[] = "Noise_NKpsk0_P256_AESGCM_SHA256";
+ static_assert(sizeof(kNKProtocolName) == sizeof(kNNProtocolName),
+ "protocol names are different lengths");
+ static_assert(sizeof(kNNProtocolName) == crypto::kSHA256Length,
"name may need padding if not HASHLEN bytes long");
static_assert(
std::tuple_size<decltype(chaining_key_)>::value == crypto::kSHA256Length,
"chaining_key_ is wrong size");
static_assert(std::tuple_size<decltype(h_)>::value == crypto::kSHA256Length,
"h_ is wrong size");
- memcpy(chaining_key_.data(), kProtocolName, sizeof(kProtocolName));
+ if (peer_identity_) {
+ memcpy(chaining_key_.data(), kNKProtocolName, sizeof(kNKProtocolName));
+ } else {
+ memcpy(chaining_key_.data(), kNNProtocolName, sizeof(kNNProtocolName));
+ }
h_ = chaining_key_;
- static const uint8_t kPrologue[] = "caBLE QR code handshake";
- MixHash(kPrologue);
+ if (peer_identity_) {
+ static const uint8_t kPrologue[] = "caBLE handshake";
+ MixHash(kPrologue);
+ } else {
+ static const uint8_t kPrologue[] = "caBLE QR code handshake";
+ MixHash(kPrologue);
+ }
- MixKeyAndHash(session_pre_key_);
+ MixKeyAndHash(psk_);
ephemeral_key_.reset(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
+ const EC_GROUP* group = EC_KEY_get0_group(ephemeral_key_.get());
CHECK(EC_KEY_generate_key(ephemeral_key_.get()));
- uint8_t ephemeral_key_public_bytes[P256PointSize];
+ uint8_t ephemeral_key_public_bytes[kP256PointSize];
CHECK_EQ(sizeof(ephemeral_key_public_bytes),
EC_POINT_point2oct(
- EC_KEY_get0_group(ephemeral_key_.get()),
- EC_KEY_get0_public_key(ephemeral_key_.get()),
+ group, EC_KEY_get0_public_key(ephemeral_key_.get()),
POINT_CONVERSION_UNCOMPRESSED, ephemeral_key_public_bytes,
sizeof(ephemeral_key_public_bytes), /*ctx=*/nullptr));
MixHash(ephemeral_key_public_bytes);
MixKey(ephemeral_key_public_bytes);
+ if (peer_identity_) {
+ // If we know the identity of the peer from a previous interaction, NKpsk0
+ // is performed to ensure that other browsers, which may also know the PSK,
+ // cannot impersonate the authenticator.
+ bssl::UniquePtr<EC_POINT> peer_identity_point(EC_POINT_new(group));
+ uint8_t es_key[32];
+ if (!EC_POINT_oct2point(group, peer_identity_point.get(),
+ peer_identity_->data(), peer_identity_->size(),
+ /*ctx=*/nullptr) ||
+ !ECDH_compute_key(es_key, sizeof(es_key), peer_identity_point.get(),
+ ephemeral_key_.get(), /*kdf=*/nullptr)) {
+ FIDO_LOG(DEBUG) << "Dropping handshake because peer identity is invalid";
+ return;
+ }
+ MixKey(es_key);
+ }
+
std::vector<uint8_t> ciphertext = Encrypt(base::span<const uint8_t>());
MixHash(ciphertext);
std::vector<uint8_t> handshake_message;
- handshake_message.reserve(sizeof(ephemeral_key_public_bytes) +
+ handshake_message.reserve(eid_.size() + sizeof(ephemeral_key_public_bytes) +
ciphertext.size());
+ handshake_message.insert(handshake_message.end(), eid_.begin(), eid_.end());
handshake_message.insert(
handshake_message.end(), ephemeral_key_public_bytes,
ephemeral_key_public_bytes + sizeof(ephemeral_key_public_bytes));
@@ -277,17 +332,17 @@ void FidoCableV2HandshakeHandler::InitiateCableHandshake(
bool FidoCableV2HandshakeHandler::ValidateAuthenticatorHandshakeMessage(
base::span<const uint8_t> response) {
- if (response.size() < P256PointSize) {
+ if (response.size() < kP256PointSize) {
return false;
}
- auto peer_point_bytes = response.subspan(0, P256PointSize);
- auto ciphertext = response.subspan(P256PointSize);
+ auto peer_point_bytes = response.subspan(0, kP256PointSize);
+ auto ciphertext = response.subspan(kP256PointSize);
bssl::UniquePtr<EC_POINT> peer_point(
EC_POINT_new(EC_KEY_get0_group(ephemeral_key_.get())));
uint8_t shared_key[32];
- if (!EC_POINT_oct2point(EC_KEY_get0_group(ephemeral_key_.get()),
- peer_point.get(), peer_point_bytes.data(),
+ const EC_GROUP* group = EC_KEY_get0_group(ephemeral_key_.get());
+ if (!EC_POINT_oct2point(group, peer_point.get(), peer_point_bytes.data(),
peer_point_bytes.size(), /*ctx=*/nullptr) ||
!ECDH_compute_key(shared_key, sizeof(shared_key), peer_point.get(),
ephemeral_key_.get(), /*kdf=*/nullptr)) {
@@ -298,20 +353,63 @@ bool FidoCableV2HandshakeHandler::ValidateAuthenticatorHandshakeMessage(
MixKey(peer_point_bytes);
MixKey(shared_key);
- auto maybe_plaintext = Decrypt(ciphertext);
- if (!maybe_plaintext || !maybe_plaintext->empty()) {
+ auto plaintext = Decrypt(ciphertext);
+ if (!plaintext || plaintext->empty() != peer_identity_.has_value()) {
+ FIDO_LOG(DEBUG) << "Invalid caBLE handshake message";
return false;
}
+
+ if (!peer_identity_) {
+ // Handshakes without a peer identity (i.e. NNpsk0 handshakes setup from a
+ // QR code) send a padded message in the reply. This message can,
+ // optionally, contain CBOR-encoded, long-term pairing information.
+ const size_t padding_length = (*plaintext)[plaintext->size() - 1];
+ if (padding_length + 1 > plaintext->size()) {
+ FIDO_LOG(DEBUG) << "Invalid padding in caBLE handshake message";
+ return false;
+ }
+ plaintext->resize(plaintext->size() - padding_length - 1);
+
+ if (!plaintext->empty()) {
+ base::Optional<cbor::Value> pairing = cbor::Reader::Read(*plaintext);
+ if (!pairing || !pairing->is_map()) {
+ FIDO_LOG(DEBUG) << "CBOR parse failure in caBLE handshake message";
+ return false;
+ }
+
+ auto future_discovery = std::make_unique<CableDiscoveryData>();
+ future_discovery->version = CableDiscoveryData::Version::V2;
+ future_discovery->v2.emplace();
+ future_discovery->v2->peer_identity.emplace();
+
+ const cbor::Value::MapValue& pairing_map(pairing->GetMap());
+ const auto name_it = pairing_map.find(cbor::Value(4));
+ if (!CopyBytestring(&future_discovery->v2->eid_gen_key, pairing_map, 1) ||
+ !CopyBytestring(&future_discovery->v2->psk_gen_key, pairing_map, 2) ||
+ !CopyBytestring(&future_discovery->v2->peer_identity.value(),
+ pairing_map, 3) ||
+ name_it == pairing_map.end() || !name_it->second.is_string() ||
+ !EC_POINT_oct2point(group, peer_point.get(),
+ future_discovery->v2->peer_identity->data(),
+ future_discovery->v2->peer_identity->size(),
+ /*ctx=*/nullptr)) {
+ FIDO_LOG(DEBUG) << "CBOR structure error in caBLE handshake message";
+ return false;
+ }
+
+ future_discovery->v2->peer_name = name_it->second.GetString();
+ pairing_callback_.Run(std::move(future_discovery));
+ }
+ }
+
// Here the spec says to do MixHash(ciphertext), but there are no more
// handshake messages so that's moot.
// MixHash(ciphertext);
- std::array<uint8_t, 32> key1, unused_key2;
- std::tie(key1, unused_key2) =
+ std::array<uint8_t, 32> read_key, write_key;
+ std::tie(write_key, read_key) =
HKDF2(chaining_key_, base::span<const uint8_t>());
-
- uint8_t zero_nonce[8] = {0};
- cable_device_->SetEncryptionData(key1, zero_nonce);
+ cable_device_->SetV2EncryptionData(read_key, write_key);
return true;
}
@@ -351,10 +449,7 @@ void FidoCableV2HandshakeHandler::InitializeKey(
std::vector<uint8_t> FidoCableV2HandshakeHandler::Encrypt(
base::span<const uint8_t> plaintext) {
uint8_t nonce[12] = {0};
- nonce[8] = symmetric_nonce_ >> 24;
- nonce[9] = symmetric_nonce_ >> 16;
- nonce[10] = symmetric_nonce_ >> 8;
- nonce[11] = symmetric_nonce_;
+ memcpy(nonce, &symmetric_nonce_, sizeof(symmetric_nonce_));
symmetric_nonce_++;
crypto::Aead aead(crypto::Aead::AES_256_GCM);
@@ -365,10 +460,7 @@ std::vector<uint8_t> FidoCableV2HandshakeHandler::Encrypt(
base::Optional<std::vector<uint8_t>> FidoCableV2HandshakeHandler::Decrypt(
base::span<const uint8_t> ciphertext) {
uint8_t nonce[12] = {0};
- nonce[8] = symmetric_nonce_ >> 24;
- nonce[9] = symmetric_nonce_ >> 16;
- nonce[10] = symmetric_nonce_ >> 8;
- nonce[11] = symmetric_nonce_;
+ memcpy(nonce, &symmetric_nonce_, sizeof(symmetric_nonce_));
symmetric_nonce_++;
crypto::Aead aead(crypto::Aead::AES_256_GCM);
diff --git a/chromium/device/fido/cable/fido_cable_handshake_handler.h b/chromium/device/fido/cable/fido_cable_handshake_handler.h
index 06c4bef4f05..e05a982f9dc 100644
--- a/chromium/device/fido/cable/fido_cable_handshake_handler.h
+++ b/chromium/device/fido/cable/fido_cable_handshake_handler.h
@@ -17,6 +17,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
+#include "device/fido/cable/cable_discovery_data.h"
#include "device/fido/fido_device.h"
#include "third_party/boringssl/src/include/openssl/base.h"
@@ -78,8 +79,14 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableV1HandshakeHandler
class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableV2HandshakeHandler
: public FidoCableHandshakeHandler {
public:
- FidoCableV2HandshakeHandler(FidoCableDevice* device,
- base::span<const uint8_t, 32> session_pre_key);
+ FidoCableV2HandshakeHandler(
+ FidoCableDevice* device,
+ base::span<const uint8_t, 32> psk_gen_key,
+ base::span<const uint8_t, 8> nonce,
+ base::span<const uint8_t, kCableEphemeralIdSize> eid,
+ base::Optional<base::span<const uint8_t, 65>> peer_identity,
+ base::RepeatingCallback<void(std::unique_ptr<CableDiscoveryData>)>
+ pairing_callback);
~FidoCableV2HandshakeHandler() override;
// FidoCableHandshakeHandler:
@@ -97,12 +104,16 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableV2HandshakeHandler
base::span<const uint8_t> ciphertext);
FidoCableDevice* const cable_device_;
- std::array<uint8_t, 32> session_pre_key_;
+ std::array<uint8_t, 16> eid_;
+ std::array<uint8_t, 32> psk_;
std::array<uint8_t, 32> chaining_key_;
std::array<uint8_t, 32> h_;
std::array<uint8_t, 32> symmetric_key_;
uint32_t symmetric_nonce_;
+ base::Optional<std::array<uint8_t, 65>> peer_identity_;
bssl::UniquePtr<EC_KEY> ephemeral_key_;
+ base::RepeatingCallback<void(std::unique_ptr<CableDiscoveryData>)>
+ pairing_callback_;
};
} // namespace device
diff --git a/chromium/device/fido/cable/fido_cable_handshake_handler_v2_fuzzer.cc b/chromium/device/fido/cable/fido_cable_handshake_handler_v2_fuzzer.cc
index 279fd85ba19..286ce789db7 100644
--- a/chromium/device/fido/cable/fido_cable_handshake_handler_v2_fuzzer.cc
+++ b/chromium/device/fido/cable/fido_cable_handshake_handler_v2_fuzzer.cc
@@ -18,27 +18,44 @@
namespace {
-constexpr std::array<uint8_t, 32> kTestSessionPreKey = {{
+constexpr std::array<uint8_t, 32> kTestPSKGeneratorKey = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-}};
-
+};
+constexpr std::array<uint8_t, 8> kTestNonce = {1, 2, 3, 4, 5, 6, 7, 8};
+constexpr std::array<uint8_t, 16> kTestEphemeralID = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+constexpr std::array<uint8_t, 65> kTestPeerIdentity = {
+ 0x04, 0x67, 0x80, 0xc5, 0xfc, 0x70, 0x27, 0x5e, 0x2c, 0x70, 0x61,
+ 0xa0, 0xe7, 0x87, 0x7b, 0xb1, 0x74, 0xde, 0xad, 0xeb, 0x98, 0x87,
+ 0x02, 0x7f, 0x3f, 0xa8, 0x36, 0x54, 0x15, 0x8b, 0xa7, 0xf5, 0x0c,
+ 0x3c, 0xba, 0x8c, 0x34, 0xbc, 0x35, 0xd2, 0x0e, 0x81, 0xf7, 0x30,
+ 0xac, 0x1c, 0x7b, 0xd6, 0xd6, 0x61, 0xa9, 0x42, 0xf9, 0x0c, 0x6a,
+ 0x9c, 0xa5, 0x5c, 0x51, 0x2f, 0x9e, 0x4a, 0x00, 0x12, 0x66,
+};
constexpr char kTestDeviceAddress[] = "Fake_Address";
} // namespace
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* raw_data, size_t size) {
- auto data_span = base::make_span(raw_data, size);
+ auto input = base::make_span(raw_data, size);
auto adapter =
base::MakeRefCounted<::testing::NiceMock<device::MockBluetoothAdapter>>();
device::FidoCableDevice test_cable_device(adapter.get(), kTestDeviceAddress);
test_cable_device.SetStateForTesting(
device::FidoCableDevice::State::kDeviceError);
- device::FidoCableV2HandshakeHandler handshake_handler_v2(&test_cable_device,
- kTestSessionPreKey);
+ base::Optional<base::span<const uint8_t, 65>> peer_identity;
+ if (!input.empty() && (input[0] & 1)) {
+ peer_identity = kTestPeerIdentity;
+ input = input.subspan(1);
+ }
+
+ device::FidoCableV2HandshakeHandler handshake_handler_v2(
+ &test_cable_device, kTestPSKGeneratorKey, kTestNonce, kTestEphemeralID,
+ peer_identity, base::DoNothing());
handshake_handler_v2.InitiateCableHandshake(base::DoNothing());
- handshake_handler_v2.ValidateAuthenticatorHandshakeMessage(data_span);
+ handshake_handler_v2.ValidateAuthenticatorHandshakeMessage(input);
return 0;
}
diff --git a/chromium/device/fido/credential_management_handler_unittest.cc b/chromium/device/fido/credential_management_handler_unittest.cc
index b3701e718df..067e27c6541 100644
--- a/chromium/device/fido/credential_management_handler_unittest.cc
+++ b/chromium/device/fido/credential_management_handler_unittest.cc
@@ -9,7 +9,6 @@
#include "base/bind.h"
#include "base/strings/strcat.h"
#include "base/test/task_environment.h"
-#include "build/build_config.h"
#include "device/fido/credential_management.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_request_handler_base.h"
@@ -19,10 +18,6 @@
#include "device/fido/virtual_fido_device_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_WIN)
-#include "device/fido/win/fake_webauthn_api.h"
-#endif // defined(OS_WIN)
-
namespace device {
namespace {
@@ -66,11 +61,6 @@ class CredentialManagementHandlerTest : public ::testing::Test {
test::ValueCallbackReceiver<CtapDeviceResponseCode> delete_callback_;
test::ValueCallbackReceiver<CredentialManagementStatus> finished_callback_;
test::VirtualFidoDeviceFactory virtual_device_factory_;
-
-#if defined(OS_WIN)
- device::ScopedFakeWinWebAuthnApi win_webauthn_api_ =
- device::ScopedFakeWinWebAuthnApi::MakeUnavailable();
-#endif // defined(OS_WIN)
};
TEST_F(CredentialManagementHandlerTest, Test) {
diff --git a/chromium/device/fido/fake_fido_discovery_unittest.cc b/chromium/device/fido/fake_fido_discovery_unittest.cc
index 81c85a684cc..1a89940aaeb 100644
--- a/chromium/device/fido/fake_fido_discovery_unittest.cc
+++ b/chromium/device/fido/fake_fido_discovery_unittest.cc
@@ -67,7 +67,8 @@ TEST_F(FakeFidoDiscoveryTest, StartDiscovery) {
ASSERT_TRUE(discovery.is_start_requested());
ASSERT_FALSE(discovery.is_running());
- EXPECT_CALL(observer, DiscoveryStarted(&discovery, true));
+ EXPECT_CALL(observer, DiscoveryStarted(&discovery, true,
+ std::vector<FidoAuthenticator*>()));
discovery.WaitForCallToStartAndSimulateSuccess();
ASSERT_TRUE(discovery.is_running());
ASSERT_TRUE(discovery.is_start_requested());
@@ -87,7 +88,8 @@ TEST_F(FakeFidoDiscoveryTest, WaitThenStartStopDiscovery) {
ASSERT_FALSE(discovery.is_running());
ASSERT_TRUE(discovery.is_start_requested());
- EXPECT_CALL(observer, DiscoveryStarted(&discovery, true));
+ EXPECT_CALL(observer, DiscoveryStarted(&discovery, true,
+ std::vector<FidoAuthenticator*>()));
discovery.SimulateStarted(true);
ASSERT_TRUE(discovery.is_running());
ASSERT_TRUE(discovery.is_start_requested());
@@ -105,7 +107,8 @@ TEST_F(FakeFidoDiscoveryTest, StartFail) {
ASSERT_FALSE(discovery.is_running());
ASSERT_TRUE(discovery.is_start_requested());
- EXPECT_CALL(observer, DiscoveryStarted(&discovery, false));
+ EXPECT_CALL(observer, DiscoveryStarted(&discovery, false,
+ std::vector<FidoAuthenticator*>()));
discovery.SimulateStarted(false);
ASSERT_FALSE(discovery.is_running());
ASSERT_TRUE(discovery.is_start_requested());
@@ -119,19 +122,16 @@ TEST_F(FakeFidoDiscoveryTest, AddDevice) {
discovery.set_observer(&observer);
discovery.Start();
-
auto device0 = std::make_unique<MockFidoDevice>();
EXPECT_CALL(*device0, GetId()).WillOnce(::testing::Return("device0"));
base::RunLoop device0_done;
- EXPECT_CALL(observer, AuthenticatorAdded(&discovery, _))
- .WillOnce(testing::InvokeWithoutArgs(
- [&device0_done]() { device0_done.Quit(); }));
discovery.AddDevice(std::move(device0));
- device0_done.Run();
- ::testing::Mock::VerifyAndClearExpectations(&observer);
- EXPECT_CALL(observer, DiscoveryStarted(&discovery, true));
+ EXPECT_CALL(observer, DiscoveryStarted(&discovery, true, testing::SizeIs(1)))
+ .WillOnce(testing::InvokeWithoutArgs(
+ [&device0_done]() { device0_done.Quit(); }));
discovery.SimulateStarted(true);
+ device0_done.Run();
::testing::Mock::VerifyAndClearExpectations(&observer);
auto device1 = std::make_unique<MockFidoDevice>();
diff --git a/chromium/device/fido/features.cc b/chromium/device/fido/features.cc
index d80f894e60d..f0a0b1e37ac 100644
--- a/chromium/device/fido/features.cc
+++ b/chromium/device/fido/features.cc
@@ -16,9 +16,6 @@ const base::Feature kWebAuthUseNativeWinApi{"WebAuthenticationUseNativeWinApi",
base::FEATURE_ENABLED_BY_DEFAULT};
#endif // defined(OS_WIN)
-extern const base::Feature kWebAuthResidentKeys{
- "WebAuthenticationResidentKeys", base::FEATURE_ENABLED_BY_DEFAULT};
-
extern const base::Feature kWebAuthBiometricEnrollment{
"WebAuthenticationBiometricEnrollment", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chromium/device/fido/features.h b/chromium/device/fido/features.h
index 24f04e102ef..78c83eda3aa 100644
--- a/chromium/device/fido/features.h
+++ b/chromium/device/fido/features.h
@@ -16,10 +16,6 @@ COMPONENT_EXPORT(DEVICE_FIDO)
extern const base::Feature kWebAuthUseNativeWinApi;
#endif // defined(OS_WIN)
-// Enable support for resident keys.
-COMPONENT_EXPORT(DEVICE_FIDO)
-extern const base::Feature kWebAuthResidentKeys;
-
// Enable biometric enrollment in the security keys settings UI.
COMPONENT_EXPORT(DEVICE_FIDO)
extern const base::Feature kWebAuthBiometricEnrollment;
diff --git a/chromium/device/fido/fido_authenticator.cc b/chromium/device/fido/fido_authenticator.cc
index 9574e871e20..11f8d3b8794 100644
--- a/chromium/device/fido/fido_authenticator.cc
+++ b/chromium/device/fido/fido_authenticator.cc
@@ -91,9 +91,10 @@ void FidoAuthenticator::GetSensorInfo(BioEnrollmentCallback) {
NOTREACHED();
}
-void FidoAuthenticator::BioEnrollFingerprint(const pin::TokenResponse&,
- BioEnrollmentSampleCallback,
- BioEnrollmentCallback) {
+void FidoAuthenticator::BioEnrollFingerprint(
+ const pin::TokenResponse&,
+ base::Optional<std::vector<uint8_t>> template_id,
+ BioEnrollmentCallback) {
NOTREACHED();
}
diff --git a/chromium/device/fido/fido_authenticator.h b/chromium/device/fido/fido_authenticator.h
index 71747c25dae..82168747d52 100644
--- a/chromium/device/fido/fido_authenticator.h
+++ b/chromium/device/fido/fido_authenticator.h
@@ -73,8 +73,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoAuthenticator {
using BioEnrollmentCallback =
base::OnceCallback<void(CtapDeviceResponseCode,
base::Optional<BioEnrollmentResponse>)>;
- using BioEnrollmentSampleCallback =
- base::RepeatingCallback<void(BioEnrollmentSampleStatus, uint8_t)>;
FidoAuthenticator() = default;
virtual ~FidoAuthenticator() = default;
@@ -174,9 +172,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoAuthenticator {
// Biometric enrollment commands.
virtual void GetModality(BioEnrollmentCallback callback);
virtual void GetSensorInfo(BioEnrollmentCallback callback);
- virtual void BioEnrollFingerprint(const pin::TokenResponse&,
- BioEnrollmentSampleCallback,
- BioEnrollmentCallback);
+ virtual void BioEnrollFingerprint(
+ const pin::TokenResponse&,
+ base::Optional<std::vector<uint8_t>> template_id,
+ BioEnrollmentCallback);
virtual void BioEnrollCancel(BioEnrollmentCallback);
virtual void BioEnrollEnumerate(const pin::TokenResponse&,
BioEnrollmentCallback);
diff --git a/chromium/device/fido/fido_constants.cc b/chromium/device/fido/fido_constants.cc
index c07c373b1ab..3a2ae6730e9 100644
--- a/chromium/device/fido/fido_constants.cc
+++ b/chromium/device/fido/fido_constants.cc
@@ -32,7 +32,7 @@ const char kCredentialManagementPreviewMapKey[] = "credentialMgmtPreview";
const char kBioEnrollmentMapKey[] = "bioEnroll";
const char kBioEnrollmentPreviewMapKey[] = "userVerificationMgmtPreview";
-const base::TimeDelta kDeviceTimeout = base::TimeDelta::FromSeconds(10);
+const base::TimeDelta kDeviceTimeout = base::TimeDelta::FromSeconds(20);
const base::TimeDelta kU2fRetryDelay = base::TimeDelta::FromMilliseconds(200);
const char kFormatKey[] = "fmt";
diff --git a/chromium/device/fido/fido_device_authenticator.cc b/chromium/device/fido/fido_device_authenticator.cc
index 3f741483732..3ca8dd6c109 100644
--- a/chromium/device/fido/fido_device_authenticator.cc
+++ b/chromium/device/fido/fido_device_authenticator.cc
@@ -513,80 +513,42 @@ void FidoDeviceAuthenticator::GetSensorInfo(BioEnrollmentCallback callback) {
}
void FidoDeviceAuthenticator::BioEnrollFingerprint(
- const pin::TokenResponse& response,
- BioEnrollmentSampleCallback sample_callback,
- BioEnrollmentCallback completion_callback) {
+ const pin::TokenResponse& pin_token,
+ base::Optional<std::vector<uint8_t>> template_id,
+ BioEnrollmentCallback callback) {
RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
- BioEnrollmentRequest::ForEnrollBegin(
- GetBioEnrollmentRequestVersion(*Options()), response),
- base::BindOnce(&FidoDeviceAuthenticator::OnBioEnroll,
- weak_factory_.GetWeakPtr(), std::move(response),
- std::move(sample_callback), std::move(completion_callback),
- /*current_template_id=*/base::nullopt),
- base::BindOnce(&BioEnrollmentResponse::Parse));
+ template_id ? BioEnrollmentRequest::ForEnrollNextSample(
+ GetBioEnrollmentRequestVersion(*Options()),
+ std::move(pin_token), std::move(*template_id))
+ : BioEnrollmentRequest::ForEnrollBegin(
+ GetBioEnrollmentRequestVersion(*Options()),
+ std::move(pin_token)),
+ std::move(callback), base::BindOnce(&BioEnrollmentResponse::Parse));
}
void FidoDeviceAuthenticator::BioEnrollRename(
- const pin::TokenResponse& response,
+ const pin::TokenResponse& pin_token,
std::vector<uint8_t> id,
std::string name,
BioEnrollmentCallback callback) {
RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
BioEnrollmentRequest::ForRename(
- GetBioEnrollmentRequestVersion(*Options()), response, std::move(id),
+ GetBioEnrollmentRequestVersion(*Options()), pin_token, std::move(id),
std::move(name)),
std::move(callback), base::BindOnce(&BioEnrollmentResponse::Parse));
}
void FidoDeviceAuthenticator::BioEnrollDelete(
- const pin::TokenResponse& response,
+ const pin::TokenResponse& pin_token,
std::vector<uint8_t> template_id,
BioEnrollmentCallback callback) {
RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
BioEnrollmentRequest::ForDelete(
- GetBioEnrollmentRequestVersion(*Options()), response,
+ GetBioEnrollmentRequestVersion(*Options()), pin_token,
std::move(template_id)),
std::move(callback), base::BindOnce(&BioEnrollmentResponse::Parse));
}
-void FidoDeviceAuthenticator::OnBioEnroll(
- pin::TokenResponse response,
- BioEnrollmentSampleCallback sample_callback,
- BioEnrollmentCallback completion_callback,
- base::Optional<std::vector<uint8_t>> current_template_id,
- CtapDeviceResponseCode code,
- base::Optional<BioEnrollmentResponse> bio) {
- if (code != CtapDeviceResponseCode::kSuccess || !bio->last_status ||
- !bio->remaining_samples || bio->remaining_samples == 0) {
- std::move(completion_callback).Run(code, std::move(bio));
- return;
- }
- if (!current_template_id) {
- if (!bio->template_id) {
- // The templateId response field is required in the first response of each
- // enrollment.
- std::move(completion_callback)
- .Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt);
- return;
- }
- current_template_id = *bio->template_id;
- }
-
- sample_callback.Run(*bio->last_status, *bio->remaining_samples);
-
- auto request = BioEnrollmentRequest::ForEnrollNextSample(
- GetBioEnrollmentRequestVersion(*Options()), response,
- *current_template_id);
-
- RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
- std::move(request),
- base::BindOnce(&FidoDeviceAuthenticator::OnBioEnroll,
- weak_factory_.GetWeakPtr(), std::move(response),
- std::move(sample_callback), std::move(completion_callback),
- std::move(current_template_id)),
- base::BindOnce(&BioEnrollmentResponse::Parse));
-}
-
void FidoDeviceAuthenticator::BioEnrollCancel(BioEnrollmentCallback callback) {
RunOperation<BioEnrollmentRequest, BioEnrollmentResponse>(
BioEnrollmentRequest::ForCancel(
diff --git a/chromium/device/fido/fido_device_authenticator.h b/chromium/device/fido/fido_device_authenticator.h
index 6ca4a1ae662..0f0c2b7ca3b 100644
--- a/chromium/device/fido/fido_device_authenticator.h
+++ b/chromium/device/fido/fido_device_authenticator.h
@@ -82,7 +82,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDeviceAuthenticator
void GetModality(BioEnrollmentCallback callback) override;
void GetSensorInfo(BioEnrollmentCallback callback) override;
void BioEnrollFingerprint(const pin::TokenResponse&,
- BioEnrollmentSampleCallback,
+ base::Optional<std::vector<uint8_t>> template_id,
BioEnrollmentCallback) override;
void BioEnrollCancel(BioEnrollmentCallback) override;
void BioEnrollEnumerate(const pin::TokenResponse&,
@@ -154,13 +154,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDeviceAuthenticator
CtapDeviceResponseCode status,
base::Optional<EnumerateCredentialsResponse> response);
- void OnBioEnroll(pin::TokenResponse,
- BioEnrollmentSampleCallback sample_callback,
- BioEnrollmentCallback completion_callback,
- base::Optional<std::vector<uint8_t>> current_template_id,
- CtapDeviceResponseCode,
- base::Optional<BioEnrollmentResponse>);
-
const std::unique_ptr<FidoDevice> device_;
base::Optional<AuthenticatorSupportedOptions> options_;
std::unique_ptr<FidoTask> task_;
diff --git a/chromium/device/fido/fido_device_discovery.cc b/chromium/device/fido/fido_device_discovery.cc
index ae9ab155fa5..41c25063a3d 100644
--- a/chromium/device/fido/fido_device_discovery.cc
+++ b/chromium/device/fido/fido_device_discovery.cc
@@ -38,13 +38,18 @@ void FidoDeviceDiscovery::NotifyDiscoveryStarted(bool success) {
state_ = State::kRunning;
if (!observer())
return;
- observer()->DiscoveryStarted(this, success);
+
+ std::vector<FidoAuthenticator*> authenticators;
+ authenticators.reserve(authenticators_.size());
+ for (const auto& authenticator : authenticators_)
+ authenticators.push_back(authenticator.second.get());
+ observer()->DiscoveryStarted(this, success, std::move(authenticators));
}
void FidoDeviceDiscovery::NotifyAuthenticatorAdded(
FidoAuthenticator* authenticator) {
DCHECK_NE(state_, State::kIdle);
- if (!observer())
+ if (!observer() || state_ != State::kRunning)
return;
observer()->AuthenticatorAdded(this, authenticator);
}
@@ -52,7 +57,7 @@ void FidoDeviceDiscovery::NotifyAuthenticatorAdded(
void FidoDeviceDiscovery::NotifyAuthenticatorRemoved(
FidoAuthenticator* authenticator) {
DCHECK_NE(state_, State::kIdle);
- if (!observer())
+ if (!observer() || state_ != State::kRunning)
return;
observer()->AuthenticatorRemoved(this, authenticator);
}
diff --git a/chromium/device/fido/fido_device_discovery_unittest.cc b/chromium/device/fido/fido_device_discovery_unittest.cc
index 9e8a1aa8d9f..6b1dd0eb19f 100644
--- a/chromium/device/fido/fido_device_discovery_unittest.cc
+++ b/chromium/device/fido/fido_device_discovery_unittest.cc
@@ -76,7 +76,8 @@ TEST(FidoDiscoveryTest, TestNotificationsOnSuccessfulStart) {
EXPECT_FALSE(discovery.is_running());
::testing::Mock::VerifyAndClearExpectations(&discovery);
- EXPECT_CALL(observer, DiscoveryStarted(&discovery, true));
+ EXPECT_CALL(observer, DiscoveryStarted(&discovery, true,
+ std::vector<FidoAuthenticator*>()));
discovery.NotifyDiscoveryStarted(true);
EXPECT_TRUE(discovery.is_start_requested());
EXPECT_TRUE(discovery.is_running());
@@ -93,7 +94,8 @@ TEST(FidoDiscoveryTest, TestNotificationsOnFailedStart) {
discovery.Start();
task_environment_.RunUntilIdle();
- EXPECT_CALL(observer, DiscoveryStarted(&discovery, false));
+ EXPECT_CALL(observer, DiscoveryStarted(&discovery, false,
+ std::vector<FidoAuthenticator*>()));
discovery.NotifyDiscoveryStarted(false);
EXPECT_TRUE(discovery.is_start_requested());
EXPECT_FALSE(discovery.is_running());
@@ -112,19 +114,23 @@ TEST(FidoDiscoveryTest, TestAddRemoveDevices) {
auto* device0_raw = device0.get();
FidoAuthenticator* authenticator0 = nullptr;
base::RunLoop device0_done;
- EXPECT_CALL(observer, AuthenticatorAdded(&discovery, _))
- .WillOnce(DoAll(SaveArg<1>(&authenticator0),
- testing::InvokeWithoutArgs(
- [&device0_done]() { device0_done.Quit(); })));
+ EXPECT_CALL(observer, DiscoveryStarted(&discovery, true, _))
+ .WillOnce(testing::Invoke(
+ [&](auto* discovery, bool success, auto authenticators) {
+ EXPECT_EQ(1u, authenticators.size());
+ authenticator0 = authenticators[0];
+ device0_done.Quit();
+ }));
EXPECT_CALL(*device0, GetId()).WillRepeatedly(Return("device0"));
EXPECT_TRUE(discovery.AddDevice(std::move(device0)));
+ discovery.NotifyDiscoveryStarted(true);
EXPECT_EQ("device0", authenticator0->GetId());
EXPECT_EQ(device0_raw,
static_cast<FidoDeviceAuthenticator*>(authenticator0)->device());
device0_done.Run();
::testing::Mock::VerifyAndClearExpectations(&observer);
- // Expect successful insertion.
+ // Expect successful insertion after starting.
base::RunLoop device1_done;
auto device1 = std::make_unique<MockFidoDevice>();
auto* device1_raw = device1.get();
diff --git a/chromium/device/fido/fido_discovery_base.h b/chromium/device/fido/fido_discovery_base.h
index 6fd43084880..4df9ef73b58 100644
--- a/chromium/device/fido/fido_discovery_base.h
+++ b/chromium/device/fido/fido_discovery_base.h
@@ -5,6 +5,8 @@
#ifndef DEVICE_FIDO_FIDO_DISCOVERY_BASE_H_
#define DEVICE_FIDO_FIDO_DISCOVERY_BASE_H_
+#include <vector>
+
#include "base/component_export.h"
#include "base/logging.h"
#include "base/macros.h"
@@ -23,13 +25,14 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscoveryBase {
virtual ~Observer();
// It is guaranteed that this is never invoked synchronously from Start().
- virtual void DiscoveryStarted(FidoDiscoveryBase* discovery, bool success) {}
-
- // It is guaranteed that AuthenticatorAdded/AuthenticatorRemoved() will not
- // be invoked before the client of FidoDiscoveryBase calls
- // FidoDiscoveryBase::Start(). However, for authenticators already known to
- // the system at that point, AuthenticatorAdded() might already be called to
- // reported already known devices.
+ // |authenticators| is the list of authenticators discovered upon start.
+ virtual void DiscoveryStarted(
+ FidoDiscoveryBase* discovery,
+ bool success,
+ std::vector<FidoAuthenticator*> authenticators = {}) {}
+
+ // Called after DiscoveryStarted for any devices discovered after
+ // initialization.
virtual void AuthenticatorAdded(FidoDiscoveryBase* discovery,
FidoAuthenticator* authenticator) = 0;
virtual void AuthenticatorRemoved(FidoDiscoveryBase* discovery,
diff --git a/chromium/device/fido/fido_discovery_factory.cc b/chromium/device/fido/fido_discovery_factory.cc
index 73a58b857d5..05d5f211b17 100644
--- a/chromium/device/fido/fido_discovery_factory.cc
+++ b/chromium/device/fido/fido_discovery_factory.cc
@@ -46,6 +46,10 @@ std::unique_ptr<FidoDiscoveryBase> CreateUsbFidoDiscovery(
FidoDiscoveryFactory::FidoDiscoveryFactory() = default;
FidoDiscoveryFactory::~FidoDiscoveryFactory() = default;
+void FidoDiscoveryFactory::ResetRequestState() {
+ request_state_ = {};
+}
+
std::unique_ptr<FidoDiscoveryBase> FidoDiscoveryFactory::Create(
FidoTransportProtocol transport,
service_manager::Connector* connector) {
@@ -55,10 +59,13 @@ std::unique_ptr<FidoDiscoveryBase> FidoDiscoveryFactory::Create(
case FidoTransportProtocol::kBluetoothLowEnergy:
return std::make_unique<FidoBleDiscovery>();
case FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy:
- if (cable_data_.has_value() || qr_generator_key_.has_value()) {
+ if (request_state_.cable_data_.has_value() ||
+ request_state_.qr_generator_key_.has_value()) {
return std::make_unique<FidoCableDiscovery>(
- cable_data_.value_or(std::vector<CableDiscoveryData>()),
- qr_generator_key_);
+ request_state_.cable_data_.value_or(
+ std::vector<CableDiscoveryData>()),
+ request_state_.qr_generator_key_,
+ request_state_.cable_pairing_callback_);
}
return nullptr;
case FidoTransportProtocol::kNearFieldCommunication:
@@ -81,26 +88,40 @@ std::unique_ptr<FidoDiscoveryBase> FidoDiscoveryFactory::Create(
void FidoDiscoveryFactory::set_cable_data(
std::vector<CableDiscoveryData> cable_data,
base::Optional<QRGeneratorKey> qr_generator_key) {
- cable_data_ = std::move(cable_data);
- qr_generator_key_ = std::move(qr_generator_key);
+ request_state_.cable_data_ = std::move(cable_data);
+ request_state_.qr_generator_key_ = std::move(qr_generator_key);
+}
+
+void FidoDiscoveryFactory::set_cable_pairing_callback(
+ base::RepeatingCallback<void(std::unique_ptr<CableDiscoveryData>)>
+ pairing_callback) {
+ request_state_.cable_pairing_callback_.emplace(std::move(pairing_callback));
}
#if defined(OS_WIN)
+void FidoDiscoveryFactory::set_win_webauthn_api(WinWebAuthnApi* api) {
+ win_webauthn_api_ = api;
+}
+
+WinWebAuthnApi* FidoDiscoveryFactory::win_webauthn_api() const {
+ return win_webauthn_api_;
+}
+
std::unique_ptr<FidoDiscoveryBase>
FidoDiscoveryFactory::MaybeCreateWinWebAuthnApiDiscovery() {
- if (!base::FeatureList::IsEnabled(device::kWebAuthUseNativeWinApi) ||
- !WinWebAuthnApi::GetDefault()->IsAvailable()) {
- return nullptr;
- }
- return std::make_unique<WinWebAuthnApiAuthenticatorDiscovery>(
- // TODO(martinkr): Inject the window from which the request
- // originated. Windows uses this parameter to center the
- // dialog over the parent. The dialog should be centered
- // over the originating Chrome Window; the foreground window
- // may have changed to something else since the request was
- // issued.
- GetForegroundWindow());
+ // TODO(martinkr): Inject the window from which the request originated.
+ // Windows uses this parameter to center the dialog over the parent. The
+ // dialog should be centered over the originating Chrome Window; the
+ // foreground window may have changed to something else since the request
+ // was issued.
+ return win_webauthn_api_ && win_webauthn_api_->IsAvailable()
+ ? std::make_unique<WinWebAuthnApiAuthenticatorDiscovery>(
+ GetForegroundWindow(), win_webauthn_api_)
+ : nullptr;
}
#endif // defined(OS_WIN)
+FidoDiscoveryFactory::RequestState::RequestState() = default;
+FidoDiscoveryFactory::RequestState::~RequestState() = default;
+
} // namespace device
diff --git a/chromium/device/fido/fido_discovery_factory.h b/chromium/device/fido/fido_discovery_factory.h
index 0b04b7cff04..63133e7dc2b 100644
--- a/chromium/device/fido/fido_discovery_factory.h
+++ b/chromium/device/fido/fido_discovery_factory.h
@@ -27,6 +27,10 @@ class Connector;
namespace device {
+#if defined(OS_WIN)
+class WinWebAuthnApi;
+#endif // defined(OS_WIN)
+
// FidoDiscoveryFactory offers methods to construct instances of
// FidoDiscoveryBase for a given |transport| protocol.
class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscoveryFactory {
@@ -34,6 +38,18 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscoveryFactory {
FidoDiscoveryFactory();
virtual ~FidoDiscoveryFactory();
+ // Resets all fields that are only meaningful for the duration of a single
+ // request to a safe default.
+ //
+ // The "regular" FidoDiscoveryFactory is owned by the
+ // AuthenticatorClientRequestDelegate and lives only for a single request.
+ // Instances returned from
+ // AuthenticatorEnvironmentImpl::GetDiscoveryFactoryOverride(), which are
+ // used in unit tests or by the WebDriver virtual authenticators, are
+ // long-lived and may handle multiple WebAuthn requests. Hence, they will be
+ // reset at the beginning of each new request.
+ void ResetRequestState();
+
// Instantiates a FidoDiscoveryBase for the given transport.
//
// FidoTransportProtocol::kUsbHumanInterfaceDevice requires specifying a
@@ -46,6 +62,12 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscoveryFactory {
void set_cable_data(std::vector<CableDiscoveryData> cable_data,
base::Optional<QRGeneratorKey> qr_generator_key);
+ // set_cable_pairing_callback installs a repeating callback that will be
+ // called when a QR handshake results in a phone wishing to pair with this
+ // browser.
+ void set_cable_pairing_callback(
+ base::RepeatingCallback<void(std::unique_ptr<CableDiscoveryData>)>);
+
#if defined(OS_MACOSX)
// Configures the Touch ID authenticator. Set to base::nullopt to disable it.
void set_mac_touch_id_info(
@@ -55,17 +77,37 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscoveryFactory {
#endif // defined(OS_MACOSX)
#if defined(OS_WIN)
- // Instantiates a FidoDiscovery for the native Windows WebAuthn
- // API where available. Returns nullptr otherwise.
+ // Instantiates a FidoDiscovery for the native Windows WebAuthn API where
+ // available. Returns nullptr otherwise.
std::unique_ptr<FidoDiscoveryBase> MaybeCreateWinWebAuthnApiDiscovery();
+
+ // Sets the WinWebAuthnApi instance to be used for creating the discovery for
+ // the Windows authenticator. If none is set,
+ // MaybeCreateWinWebAuthnApiDiscovery() returns nullptr.
+ void set_win_webauthn_api(WinWebAuthnApi* api);
+ WinWebAuthnApi* win_webauthn_api() const;
#endif // defined(OS_WIN)
private:
+ // RequestState holds configuration data that is only meaningful for a
+ // single WebAuthn request.
+ struct RequestState {
+ RequestState();
+ ~RequestState();
+ base::Optional<std::vector<CableDiscoveryData>> cable_data_;
+ base::Optional<QRGeneratorKey> qr_generator_key_;
+ base::Optional<
+ base::RepeatingCallback<void(std::unique_ptr<CableDiscoveryData>)>>
+ cable_pairing_callback_;
+ };
+
+ RequestState request_state_;
#if defined(OS_MACOSX)
base::Optional<fido::mac::AuthenticatorConfig> mac_touch_id_config_;
#endif // defined(OS_MACOSX)
- base::Optional<std::vector<CableDiscoveryData>> cable_data_;
- base::Optional<QRGeneratorKey> qr_generator_key_;
+#if defined(OS_WIN)
+ WinWebAuthnApi* win_webauthn_api_ = nullptr;
+#endif // defined(OS_WIN)
};
} // namespace device
diff --git a/chromium/device/fido/fido_request_handler_base.cc b/chromium/device/fido/fido_request_handler_base.cc
index b3322aca79f..e6216746eb9 100644
--- a/chromium/device/fido/fido_request_handler_base.cc
+++ b/chromium/device/fido/fido_request_handler_base.cc
@@ -48,41 +48,22 @@ FidoRequestHandlerBase::Observer::~Observer() = default;
FidoRequestHandlerBase::FidoRequestHandlerBase(
service_manager::Connector* connector,
FidoDiscoveryFactory* fido_discovery_factory,
- const base::flat_set<FidoTransportProtocol>& available_transports)
- : fido_discovery_factory_(fido_discovery_factory), connector_(connector) {
+ const base::flat_set<FidoTransportProtocol>& available_transports) {
#if defined(OS_WIN)
- InitDiscoveriesWin(available_transports);
+ InitDiscoveriesWin(fido_discovery_factory, connector, available_transports);
#else
- InitDiscoveries(available_transports);
+ InitDiscoveries(fido_discovery_factory, connector, available_transports);
#endif // !defined(OS_WIN)
}
void FidoRequestHandlerBase::InitDiscoveries(
+ FidoDiscoveryFactory* fido_discovery_factory,
+ service_manager::Connector* connector,
const base::flat_set<FidoTransportProtocol>& available_transports) {
- // The number of times |notify_observer_callback_| needs to be invoked before
- // Observer::OnTransportAvailabilityEnumerated is dispatched. Essentially this
- // is used to wait until the parts |transport_availability_info_| are
- // filled out; the |notify_observer_callback_| is invoked once for each part
- // once that part is ready, namely:
- //
- // 1) [If the platform authenticator is enabled] once the platform
- // authenticator is ready.
- // 2) [If BLE or caBLE are enabled] if Bluetooth adapter is present.
- //
- // 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;
-
-#if defined(OS_WIN)
- if (transport_availability_info_.has_win_native_api_authenticator)
- ++transport_info_callback_count;
-#endif // defined(OS_WIN)
-
transport_availability_info_.available_transports = available_transports;
for (const auto transport : available_transports) {
std::unique_ptr<FidoDiscoveryBase> discovery =
- fido_discovery_factory_->Create(transport, connector_);
+ fido_discovery_factory->Create(transport, connector);
if (discovery == nullptr) {
// This can occur in tests when a ScopedVirtualU2fDevice is in effect and
// HID transports are not configured or when caBLE discovery data isn't
@@ -91,27 +72,35 @@ void FidoRequestHandlerBase::InitDiscoveries(
continue;
}
- if (transport == FidoTransportProtocol::kInternal) {
- ++transport_info_callback_count;
- }
-
discovery->set_observer(this);
discoveries_.push_back(std::move(discovery));
}
+ bool has_ble = false;
if (base::Contains(transport_availability_info_.available_transports,
FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy) ||
base::Contains(transport_availability_info_.available_transports,
FidoTransportProtocol::kBluetoothLowEnergy)) {
- ++transport_info_callback_count;
+ has_ble = true;
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&FidoRequestHandlerBase::ConstructBleAdapterPowerManager,
weak_factory_.GetWeakPtr()));
}
+ // Initialize |notify_observer_callback_| with the number of times it has to
+ // be invoked before Observer::OnTransportAvailabilityEnumerated is
+ // dispatched.
+ // Essentially this is used to wait until the parts
+ // |transport_availability_info_| are filled out; the
+ // |notify_observer_callback_| is invoked once for each discovery once it is
+ // ready, and additionally:
+ //
+ // 1) [If BLE or caBLE are enabled] once BLE adapters have been enumerated
+ // 2) When |observer_| is set, so that OnTransportAvailabilityEnumerated is
+ // never called before it is set.
notify_observer_callback_ = base::BarrierClosure(
- transport_info_callback_count,
+ discoveries_.size() + has_ble + 1,
base::BindOnce(
&FidoRequestHandlerBase::NotifyObserverTransportAvailability,
weak_factory_.GetWeakPtr()));
@@ -119,14 +108,15 @@ void FidoRequestHandlerBase::InitDiscoveries(
#if defined(OS_WIN)
void FidoRequestHandlerBase::InitDiscoveriesWin(
+ FidoDiscoveryFactory* fido_discovery_factory,
+ service_manager::Connector* connector,
const base::flat_set<FidoTransportProtocol>& available_transports) {
// Try to instantiate the discovery for proxying requests to the native
// Windows WebAuthn API; or fall back to using the regular device transport
// discoveries if the API is unavailable.
- auto discovery =
- fido_discovery_factory_->MaybeCreateWinWebAuthnApiDiscovery();
+ auto discovery = fido_discovery_factory->MaybeCreateWinWebAuthnApiDiscovery();
if (!discovery) {
- InitDiscoveries(available_transports);
+ InitDiscoveries(fido_discovery_factory, connector, available_transports);
return;
}
@@ -154,7 +144,7 @@ void FidoRequestHandlerBase::InitDiscoveriesWin(
FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy};
}
- InitDiscoveries(other_transports);
+ InitDiscoveries(fido_discovery_factory, connector, other_transports);
}
#endif // defined(OS_WIN)
@@ -243,13 +233,6 @@ void FidoRequestHandlerBase::Start() {
discovery->Start();
}
-void FidoRequestHandlerBase::AuthenticatorAdded(
- FidoDiscoveryBase* discovery,
- FidoAuthenticator* authenticator) {
- DCHECK(!base::Contains(active_authenticators(), authenticator->GetId()));
- AddAuthenticator(authenticator);
-}
-
void FidoRequestHandlerBase::AuthenticatorRemoved(
FidoDiscoveryBase* discovery,
FidoAuthenticator* authenticator) {
@@ -296,7 +279,19 @@ void FidoRequestHandlerBase::AuthenticatorPairingModeChanged(
}
}
-void FidoRequestHandlerBase::AddAuthenticator(
+void FidoRequestHandlerBase::DiscoveryStarted(
+ FidoDiscoveryBase* discovery,
+ bool success,
+ std::vector<FidoAuthenticator*> authenticators) {
+ for (auto* authenticator : authenticators) {
+ AuthenticatorAdded(discovery, authenticator);
+ }
+ DCHECK(notify_observer_callback_);
+ notify_observer_callback_.Run();
+}
+
+void FidoRequestHandlerBase::AuthenticatorAdded(
+ FidoDiscoveryBase* discovery,
FidoAuthenticator* authenticator) {
DCHECK(authenticator &&
!base::Contains(active_authenticators(), authenticator->GetId()));
@@ -336,16 +331,8 @@ void FidoRequestHandlerBase::AddAuthenticator(
.win_native_ui_shows_resident_credential_notice =
static_cast<WinWebAuthnApiAuthenticator*>(authenticator)
->ShowsPrivacyNotice();
- DCHECK(notify_observer_callback_);
- notify_observer_callback_.Run();
}
#endif // defined(OS_WIN)
-
- if (authenticator->AuthenticatorTransport() ==
- FidoTransportProtocol::kInternal) {
- DCHECK(notify_observer_callback_);
- notify_observer_callback_.Run();
- }
}
bool FidoRequestHandlerBase::HasAuthenticator(
diff --git a/chromium/device/fido/fido_request_handler_base.h b/chromium/device/fido/fido_request_handler_base.h
index bfaddf9ef33..936ece7c9d6 100644
--- a/chromium/device/fido/fido_request_handler_base.h
+++ b/chromium/device/fido/fido_request_handler_base.h
@@ -235,6 +235,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
Observer* observer() const { return observer_; }
// FidoDiscoveryBase::Observer
+ void DiscoveryStarted(
+ FidoDiscoveryBase* discovery,
+ bool success,
+ std::vector<FidoAuthenticator*> authenticators) override;
void AuthenticatorAdded(FidoDiscoveryBase* discovery,
FidoAuthenticator* authenticator) override;
void AuthenticatorRemoved(FidoDiscoveryBase* discovery,
@@ -246,19 +250,20 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
const std::string& device_id,
bool is_in_pairing_mode) override;
- FidoDiscoveryFactory* fido_discovery_factory_;
-
private:
friend class FidoRequestHandlerTest;
void InitDiscoveries(
+ FidoDiscoveryFactory* fido_discovery_factory,
+ service_manager::Connector* connector,
const base::flat_set<FidoTransportProtocol>& available_transports);
#if defined(OS_WIN)
void InitDiscoveriesWin(
+ FidoDiscoveryFactory* fido_discovery_factory,
+ service_manager::Connector* connector,
const base::flat_set<FidoTransportProtocol>& available_transports);
#endif
- void AddAuthenticator(FidoAuthenticator* authenticator);
void NotifyObserverTransportAvailability();
// Invokes FidoAuthenticator::InitializeAuthenticator(), followed by
@@ -274,7 +279,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
TransportAvailabilityInfo transport_availability_info_;
base::RepeatingClosure notify_observer_callback_;
std::unique_ptr<BleAdapterManager> bluetooth_adapter_manager_;
- service_manager::Connector* const connector_;
base::WeakPtrFactory<FidoRequestHandlerBase> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(FidoRequestHandlerBase);
diff --git a/chromium/device/fido/fido_request_handler_unittest.cc b/chromium/device/fido/fido_request_handler_unittest.cc
index 96f50f0f9e1..66711141096 100644
--- a/chromium/device/fido/fido_request_handler_unittest.cc
+++ b/chromium/device/fido/fido_request_handler_unittest.cc
@@ -367,11 +367,6 @@ class FidoRequestHandlerTest : public ::testing::Test {
test::FakeFidoDiscovery* discovery_;
test::FakeFidoDiscovery* ble_discovery_;
FakeHandlerCallbackReceiver cb_;
-
-#if defined(OS_WIN)
- device::ScopedFakeWinWebAuthnApi win_webauthn_api_ =
- device::ScopedFakeWinWebAuthnApi::MakeUnavailable();
-#endif // defined(OS_WIN)
};
TEST_F(FidoRequestHandlerTest, TestSingleDeviceSuccess) {
@@ -581,6 +576,8 @@ TEST_F(FidoRequestHandlerTest,
discovery()->AddDevice(std::move(device0));
platform_discovery->AddDevice(std::move(device1));
+ discovery()->WaitForCallToStartAndSimulateSuccess();
+ platform_discovery->WaitForCallToStartAndSimulateSuccess();
task_environment_.FastForwardUntilNoTasksRemain();
callback().WaitForCallback();
@@ -626,7 +623,8 @@ TEST_F(FidoRequestHandlerTest, TestWithPlatformAuthenticator) {
device->ExpectRequestAndRespondWith(std::vector<uint8_t>(),
CreateFakeSuccessDeviceResponse());
device->SetDeviceTransport(FidoTransportProtocol::kInternal);
- auto* fake_discovery = fake_discovery_factory_.ForgeNextPlatformDiscovery();
+ auto* fake_discovery = fake_discovery_factory_.ForgeNextPlatformDiscovery(
+ test::FakeFidoDiscovery::StartMode::kAutomatic);
TestObserver observer;
auto request_handler = std::make_unique<FakeFidoRequestHandler>(
@@ -660,6 +658,8 @@ TEST_F(FidoRequestHandlerTest, BleTransportAllowedIfBluetoothAdapterPresent) {
TestObserver observer;
auto request_handler = CreateFakeHandler();
+ ble_discovery()->WaitForCallToStartAndSimulateSuccess();
+ discovery()->WaitForCallToStartAndSimulateSuccess();
request_handler->set_observer(&observer);
observer.WaitForAndExpectAvailableTransportsAre(
@@ -673,6 +673,8 @@ TEST_F(FidoRequestHandlerTest,
TestObserver observer;
auto request_handler = CreateFakeHandler();
+ ble_discovery()->WaitForCallToStartAndSimulateSuccess();
+ discovery()->WaitForCallToStartAndSimulateSuccess();
request_handler->set_observer(&observer);
observer.WaitForAndExpectAvailableTransportsAre(
@@ -685,6 +687,8 @@ TEST_F(FidoRequestHandlerTest,
TestObserver observer;
auto request_handler = CreateFakeHandler();
+ ble_discovery()->WaitForCallToStartAndSimulateSuccess();
+ discovery()->WaitForCallToStartAndSimulateSuccess();
task_environment_.FastForwardUntilNoTasksRemain();
request_handler->set_observer(&observer);
@@ -698,6 +702,7 @@ TEST_F(FidoRequestHandlerTest, EmbedderNotifiedWhenAuthenticatorIdChanges) {
TestObserver observer;
auto request_handler = CreateFakeHandler();
request_handler->set_observer(&observer);
+ discovery()->WaitForCallToStartAndSimulateSuccess();
ble_discovery()->WaitForCallToStartAndSimulateSuccess();
auto device = std::make_unique<MockFidoDevice>();
@@ -711,9 +716,11 @@ TEST_F(FidoRequestHandlerTest, EmbedderNotifiedWhenAuthenticatorIdChanges) {
#if defined(OS_WIN)
TEST_F(FidoRequestHandlerTest, TransportAvailabilityOfWindowsAuthenticator) {
+ FakeWinWebAuthnApi api;
+ fake_discovery_factory_.set_win_webauthn_api(&api);
for (const bool api_available : {false, true}) {
SCOPED_TRACE(::testing::Message() << "api_available=" << api_available);
- win_webauthn_api_.set_available(api_available);
+ api.set_available(api_available);
TestObserver observer;
ForgeNextHidDiscovery();
@@ -721,6 +728,12 @@ TEST_F(FidoRequestHandlerTest, TransportAvailabilityOfWindowsAuthenticator) {
{FidoTransportProtocol::kUsbHumanInterfaceDevice},
&fake_discovery_factory_);
request_handler.set_observer(&observer);
+
+ // If the windows API is not enabled, the request is dispatched to the USB
+ // discovery. Simulate a success to fill the transport availability info.
+ if (!api_available)
+ discovery()->WaitForCallToStartAndSimulateSuccess();
+
task_environment_.FastForwardUntilNoTasksRemain();
auto transport_availability_info =
diff --git a/chromium/device/fido/fido_test_data.h b/chromium/device/fido/fido_test_data.h
index de691a551a6..1651004e490 100644
--- a/chromium/device/fido/fido_test_data.h
+++ b/chromium/device/fido/fido_test_data.h
@@ -163,6 +163,27 @@ constexpr uint8_t kU2fSignCommandApduWithKeyAlpha[] = {
0x00, 0x00,
};
+constexpr uint8_t kU2fSignCommandApduWithKeyAlphaAndBogusChallenge[] = {
+ // CLA, INS, P1, P2 APDU instruction parameters
+ 0x00, 0x02, 0x03, 0x00,
+ // Data Length (3 bytes in big endian order)
+ 0x00, 0x00, 0x42,
+ // Bogus challenge parameter
+ 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
+ 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
+ 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
+ // Application parameter
+ 0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7,
+ 0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF,
+ 0x01, 0x3D, 0xE9, 0x6D, 0x4E, 0xFB, 0x17, 0xDE,
+ // Dummy key handle length
+ 0x01,
+ // Key handle
+ 0xEA,
+ // Max response length
+ 0x00, 0x00,
+};
+
constexpr uint8_t kU2fSignCommandApduWithKeyBeta[] = {
// CLA, INS, P1, P2 APDU instruction parameters
0x00, 0x02, 0x03, 0x00,
@@ -184,6 +205,27 @@ constexpr uint8_t kU2fSignCommandApduWithKeyBeta[] = {
0x00, 0x00,
};
+constexpr uint8_t kU2fSignCommandApduWithKeyBetaAndBogusChallenge[] = {
+ // CLA, INS, P1, P2 APDU instruction parameters
+ 0x00, 0x02, 0x03, 0x00,
+ // Data Length (3 bytes in big endian order)
+ 0x00, 0x00, 0x42,
+ // Bogus challenge parameter
+ 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
+ 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
+ 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
+ // Application parameter
+ 0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7,
+ 0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF,
+ 0x01, 0x3D, 0xE9, 0x6D, 0x4E, 0xFB, 0x17, 0xDE,
+ // Dummy key handle length
+ 0x01,
+ // Key handle
+ 0xEB,
+ // Max response length
+ 0x00, 0x00,
+};
+
constexpr uint8_t kU2fSignCommandApduWithKeyGamma[] = {
// CLA, INS, P1, P2 APDU instruction parameters
0x00, 0x02, 0x03, 0x00,
@@ -205,6 +247,27 @@ constexpr uint8_t kU2fSignCommandApduWithKeyGamma[] = {
0x00, 0x00,
};
+constexpr uint8_t kU2fSignCommandApduWithKeyGammaAndBogusChallenge[] = {
+ // CLA, INS, P1, P2 APDU instruction parameters
+ 0x00, 0x02, 0x03, 0x00,
+ // Data Length (3 bytes in big endian order)
+ 0x00, 0x00, 0x42,
+ // Bogus challenge parameter
+ 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
+ 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
+ 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
+ // Application parameter
+ 0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7,
+ 0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF,
+ 0x01, 0x3D, 0xE9, 0x6D, 0x4E, 0xFB, 0x17, 0xDE,
+ // Dummy key handle length
+ 0x01,
+ // Key handle
+ 0xEC,
+ // Max response length
+ 0x00, 0x00,
+};
+
constexpr uint8_t kU2fSignCommandApdu[] = {
// CLA, INS, P1, P2 APDU instruction parameters
0x00, 0x02, 0x03, 0x00,
diff --git a/chromium/device/fido/get_assertion_handler_unittest.cc b/chromium/device/fido/get_assertion_handler_unittest.cc
index 9b2236c8690..95af34ed342 100644
--- a/chromium/device/fido/get_assertion_handler_unittest.cc
+++ b/chromium/device/fido/get_assertion_handler_unittest.cc
@@ -32,7 +32,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_WIN)
-#include "device/fido/win/authenticator.h"
#include "device/fido/win/fake_webauthn_api.h"
#endif // defined(OS_WIN)
@@ -102,7 +101,7 @@ class FidoGetAssertionHandlerTest : public ::testing::Test {
auto handler = std::make_unique<GetAssertionRequestHandler>(
nullptr /* connector */, fake_discovery_factory_.get(),
supported_transports_, std::move(request),
- get_assertion_cb_.callback());
+ /*allow_skipping_pin_touch=*/true, get_assertion_cb_.callback());
return handler;
}
@@ -177,11 +176,6 @@ class FidoGetAssertionHandlerTest : public ::testing::Test {
TestGetAssertionRequestCallback get_assertion_cb_;
base::flat_set<FidoTransportProtocol> supported_transports_ =
GetAllTransportProtocols();
-
-#if defined(OS_WIN)
- device::ScopedFakeWinWebAuthnApi win_webauthn_api_ =
- device::ScopedFakeWinWebAuthnApi::MakeUnavailable();
-#endif // defined(OS_WIN)
};
TEST_F(FidoGetAssertionHandlerTest, TransportAvailabilityInfo) {
@@ -742,10 +736,6 @@ TEST_F(FidoGetAssertionHandlerTest, DeviceFailsImmediately) {
TEST(GetAssertionRequestHandlerTest, IncorrectTransportType) {
base::test::TaskEnvironment task_environment{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
-#if defined(OS_WIN)
- device::ScopedFakeWinWebAuthnApi win_webauthn_api_ =
- device::ScopedFakeWinWebAuthnApi::MakeUnavailable();
-#endif // defined(OS_WIN)
device::test::VirtualFidoDeviceFactory virtual_device_factory;
virtual_device_factory.SetSupportedProtocol(device::ProtocolVersion::kCtap2);
@@ -769,7 +759,7 @@ TEST(GetAssertionRequestHandlerTest, IncorrectTransportType) {
nullptr /* connector */, &virtual_device_factory,
base::flat_set<FidoTransportProtocol>(
{FidoTransportProtocol::kUsbHumanInterfaceDevice}),
- std::move(request), cb.callback());
+ std::move(request), /*allow_skipping_pin_touch=*/true, cb.callback());
task_environment.FastForwardUntilNoTasksRemain();
EXPECT_FALSE(cb.was_called());
@@ -821,10 +811,10 @@ class TestObserver : public FidoRequestHandlerBase::Observer {
// on API availability.
TEST(GetAssertionRequestHandlerWinTest, TestWinUsbDiscovery) {
base::test::TaskEnvironment task_environment;
- ScopedFakeWinWebAuthnApi scoped_fake_win_webauthn_api;
for (const bool enable_api : {false, true}) {
SCOPED_TRACE(::testing::Message() << "enable_api=" << enable_api);
- scoped_fake_win_webauthn_api.set_available(enable_api);
+ FakeWinWebAuthnApi api;
+ api.set_available(enable_api);
// Simulate a connected HID device.
ScopedFakeFidoHidManager fake_hid_manager;
@@ -832,13 +822,14 @@ TEST(GetAssertionRequestHandlerWinTest, TestWinUsbDiscovery) {
TestGetAssertionRequestCallback cb;
FidoDiscoveryFactory fido_discovery_factory;
+ fido_discovery_factory.set_win_webauthn_api(&api);
auto handler = std::make_unique<GetAssertionRequestHandler>(
fake_hid_manager.service_manager_connector(), &fido_discovery_factory,
base::flat_set<FidoTransportProtocol>(
{FidoTransportProtocol::kUsbHumanInterfaceDevice}),
CtapGetAssertionRequest(test_data::kRelyingPartyId,
test_data::kClientDataJson),
- cb.callback());
+ /*allow_skipping_pin_touch=*/true, cb.callback());
// Register an observer that disables automatic dispatch. Dispatch to the
// (unimplemented) fake Windows API would immediately result in an invalid
// response.
diff --git a/chromium/device/fido/get_assertion_request_handler.cc b/chromium/device/fido/get_assertion_request_handler.cc
index df16a9457f6..ba547443d48 100644
--- a/chromium/device/fido/get_assertion_request_handler.cc
+++ b/chromium/device/fido/get_assertion_request_handler.cc
@@ -14,6 +14,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/stl_util.h"
#include "build/build_config.h"
+#include "components/cbor/diagnostic_writer.h"
#include "components/device_event_log/device_event_log.h"
#include "device/fido/cable/fido_cable_discovery.h"
#include "device/fido/fido_authenticator.h"
@@ -151,6 +152,16 @@ bool ResponseValid(const FidoAuthenticator& authenticator,
return false;
}
+ // No extensions are supported when getting assertions therefore no extensions
+ // are permitted in the response.
+ const base::Optional<cbor::Value>& extensions =
+ response.auth_data().extensions();
+ if (extensions) {
+ FIDO_LOG(ERROR) << "assertion response invalid due to extensions block: "
+ << cbor::DiagnosticWriter::Write(*extensions);
+ return false;
+ }
+
return true;
}
@@ -213,6 +224,7 @@ GetAssertionRequestHandler::GetAssertionRequestHandler(
FidoDiscoveryFactory* fido_discovery_factory,
const base::flat_set<FidoTransportProtocol>& supported_transports,
CtapGetAssertionRequest request,
+ bool allow_skipping_pin_touch,
CompletionCallback completion_callback)
: FidoRequestHandlerBase(
connector,
@@ -221,7 +233,8 @@ GetAssertionRequestHandler::GetAssertionRequestHandler(
supported_transports,
GetTransportsAllowedByRP(request))),
completion_callback_(std::move(completion_callback)),
- request_(std::move(request)) {
+ request_(std::move(request)),
+ allow_skipping_pin_touch_(allow_skipping_pin_touch) {
transport_availability_info().request_type =
FidoRequestHandlerBase::RequestType::kGetAssertion;
transport_availability_info().has_empty_allow_list =
@@ -251,6 +264,11 @@ void GetAssertionRequestHandler::DispatchRequest(
switch (authenticator->WillNeedPINToGetAssertion(request_, observer())) {
case FidoAuthenticator::GetAssertionPINDisposition::kUsePIN:
+ // Skip asking for touch if this is the only available authenticator.
+ if (active_authenticators().size() == 1 && allow_skipping_pin_touch_) {
+ HandleTouch(authenticator);
+ return;
+ }
// A PIN will be needed. Just request a touch to let the user select
// this authenticator if they wish.
FIDO_LOG(DEBUG) << "Asking for touch from "
@@ -303,6 +321,9 @@ void GetAssertionRequestHandler::AuthenticatorAdded(
DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
#if defined(OS_MACOSX)
+ // Indicate to the UI whether a GetAssertion call to Touch ID would succeed
+ // or not. This needs to happen before the base AuthenticatorAdded()
+ // implementation runs |notify_observer_callback_| for this callback.
if (authenticator->IsTouchIdAuthenticator()) {
transport_availability_info().has_recognized_mac_touch_id_credential =
static_cast<fido::mac::TouchIdAuthenticator*>(authenticator)
@@ -537,7 +558,6 @@ void GetAssertionRequestHandler::OnHavePIN(std::string pin) {
if (authenticator_ == nullptr) {
// Authenticator was detached. The request will already have been canceled
// but this callback may have been waiting in a queue.
- DCHECK(!completion_callback_);
return;
}
diff --git a/chromium/device/fido/get_assertion_request_handler.h b/chromium/device/fido/get_assertion_request_handler.h
index f112431f624..d1aa1f7da20 100644
--- a/chromium/device/fido/get_assertion_request_handler.h
+++ b/chromium/device/fido/get_assertion_request_handler.h
@@ -64,6 +64,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) GetAssertionRequestHandler
FidoDiscoveryFactory* fido_discovery_factory,
const base::flat_set<FidoTransportProtocol>& supported_transports,
CtapGetAssertionRequest request_parameter,
+ bool allow_skipping_pin_touch,
CompletionCallback completion_callback);
~GetAssertionRequestHandler() override;
@@ -108,6 +109,11 @@ class COMPONENT_EXPORT(DEVICE_FIDO) GetAssertionRequestHandler
CompletionCallback completion_callback_;
State state_ = State::kWaitingForTouch;
CtapGetAssertionRequest request_;
+ // If true, and if at the time the request is dispatched to the first
+ // authenticator no other authenticators are available, the request handler
+ // will skip the initial touch that is usually required to select a PIN
+ // protected authenticator.
+ bool allow_skipping_pin_touch_;
// authenticator_ points to the authenticator that will be used for this
// operation. It's only set after the user touches an authenticator to select
// it, after which point that authenticator will be used exclusively through
diff --git a/chromium/device/fido/hid/fake_hid_impl_for_testing.cc b/chromium/device/fido/hid/fake_hid_impl_for_testing.cc
index c51c9c2f853..a81999c5620 100644
--- a/chromium/device/fido/hid/fake_hid_impl_for_testing.cc
+++ b/chromium/device/fido/hid/fake_hid_impl_for_testing.cc
@@ -25,9 +25,9 @@ MATCHER_P(IsCtapHidCommand, expected_command, "") {
MockFidoHidConnection::MockFidoHidConnection(
device::mojom::HidDeviceInfoPtr device,
- device::mojom::HidConnectionRequest request,
+ mojo::PendingReceiver<device::mojom::HidConnection> receiver,
std::array<uint8_t, 4> connection_channel_id)
- : binding_(this, std::move(request)),
+ : receiver_(this, std::move(receiver)),
device_(std::move(device)),
connection_channel_id_(connection_channel_id) {}
@@ -127,13 +127,14 @@ FakeFidoHidManager::FakeFidoHidManager() = default;
FakeFidoHidManager::~FakeFidoHidManager() = default;
-void FakeFidoHidManager::AddBinding(mojo::ScopedMessagePipeHandle handle) {
- bindings_.AddBinding(this,
- device::mojom::HidManagerRequest(std::move(handle)));
+void FakeFidoHidManager::AddReceiver(mojo::ScopedMessagePipeHandle handle) {
+ receivers_.Add(this, mojo::PendingReceiver<device::mojom::HidManager>(
+ std::move(handle)));
}
-void FakeFidoHidManager::AddBinding2(device::mojom::HidManagerRequest request) {
- bindings_.AddBinding(this, std::move(request));
+void FakeFidoHidManager::AddReceiver2(
+ mojo::PendingReceiver<device::mojom::HidManager> receiver) {
+ receivers_.Add(this, std::move(receiver));
}
void FakeFidoHidManager::AddFidoHidDevice(std::string guid) {
@@ -155,9 +156,7 @@ void FakeFidoHidManager::GetDevicesAndSetClient(
GetDevicesCallback callback) {
GetDevices(std::move(callback));
- device::mojom::HidManagerClientAssociatedPtr client_ptr;
- client_ptr.Bind(std::move(client));
- clients_.AddPtr(std::move(client_ptr));
+ clients_.Add(std::move(client));
}
void FakeFidoHidManager::GetDevices(GetDevicesCallback callback) {
@@ -175,7 +174,7 @@ void FakeFidoHidManager::Connect(
auto device_it = devices_.find(device_guid);
auto connection_it = connections_.find(device_guid);
if (device_it == devices_.end() || connection_it == connections_.end()) {
- std::move(callback).Run(nullptr);
+ std::move(callback).Run(mojo::NullRemote());
return;
}
@@ -184,16 +183,15 @@ void FakeFidoHidManager::Connect(
void FakeFidoHidManager::AddDevice(device::mojom::HidDeviceInfoPtr device) {
device::mojom::HidDeviceInfo* device_info = device.get();
- clients_.ForAllPtrs([device_info](device::mojom::HidManagerClient* client) {
+ for (auto& client : clients_)
client->DeviceAdded(device_info->Clone());
- });
devices_[device->guid] = std::move(device);
}
void FakeFidoHidManager::AddDeviceAndSetConnection(
device::mojom::HidDeviceInfoPtr device,
- device::mojom::HidConnectionPtr connection) {
+ mojo::PendingRemote<device::mojom::HidConnection> connection) {
connections_[device->guid] = std::move(connection);
AddDevice(std::move(device));
}
@@ -204,9 +202,8 @@ void FakeFidoHidManager::RemoveDevice(const std::string device_guid) {
return;
device::mojom::HidDeviceInfo* device_info = it->second.get();
- clients_.ForAllPtrs([device_info](device::mojom::HidManagerClient* client) {
+ for (auto& client : clients_)
client->DeviceRemoved(device_info->Clone());
- });
devices_.erase(it);
}
@@ -216,7 +213,7 @@ ScopedFakeFidoHidManager::ScopedFakeFidoHidManager() {
connector_->OverrideBinderForTesting(
service_manager::ServiceFilter::ByName(device::mojom::kServiceName),
device::mojom::HidManager::Name_,
- base::BindRepeating(&FakeFidoHidManager::AddBinding,
+ base::BindRepeating(&FakeFidoHidManager::AddReceiver,
base::Unretained(this)));
}
diff --git a/chromium/device/fido/hid/fake_hid_impl_for_testing.h b/chromium/device/fido/hid/fake_hid_impl_for_testing.h
index 597cd5d357e..d72f4c3e200 100644
--- a/chromium/device/fido/hid/fake_hid_impl_for_testing.h
+++ b/chromium/device/fido/hid/fake_hid_impl_for_testing.h
@@ -14,9 +14,11 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "device/fido/fido_constants.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/bindings/interface_ptr_set.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote_set.h"
#include "services/device/public/mojom/hid.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -28,9 +30,10 @@ namespace device {
class MockFidoHidConnection : public device::mojom::HidConnection {
public:
- explicit MockFidoHidConnection(device::mojom::HidDeviceInfoPtr device,
- device::mojom::HidConnectionRequest request,
- std::array<uint8_t, 4> connection_channel_id);
+ explicit MockFidoHidConnection(
+ device::mojom::HidDeviceInfoPtr device,
+ mojo::PendingReceiver<device::mojom::HidConnection> receiver,
+ std::array<uint8_t, 4> connection_channel_id);
~MockFidoHidConnection() override;
MOCK_METHOD1(ReadPtr, void(ReadCallback* callback));
@@ -61,7 +64,7 @@ class MockFidoHidConnection : public device::mojom::HidConnection {
const std::vector<uint8_t>& nonce() const { return nonce_; }
private:
- mojo::Binding<device::mojom::HidConnection> binding_;
+ mojo::Receiver<device::mojom::HidConnection> receiver_;
device::mojom::HidDeviceInfoPtr device_;
std::vector<uint8_t> nonce_;
std::array<uint8_t, 4> connection_channel_id_;
@@ -111,18 +114,20 @@ class FakeFidoHidManager : public device::mojom::HidManager {
const std::string& device_guid,
mojo::PendingRemote<mojom::HidConnectionClient> connection_client,
ConnectCallback callback) override;
- void AddBinding(mojo::ScopedMessagePipeHandle handle);
- void AddBinding2(device::mojom::HidManagerRequest request);
+ void AddReceiver(mojo::ScopedMessagePipeHandle handle);
+ void AddReceiver2(mojo::PendingReceiver<device::mojom::HidManager> receiver);
void AddDevice(device::mojom::HidDeviceInfoPtr device);
- void AddDeviceAndSetConnection(device::mojom::HidDeviceInfoPtr device,
- device::mojom::HidConnectionPtr connection);
+ void AddDeviceAndSetConnection(
+ device::mojom::HidDeviceInfoPtr device,
+ mojo::PendingRemote<device::mojom::HidConnection> connection);
void RemoveDevice(const std::string device_guid);
private:
std::map<std::string, device::mojom::HidDeviceInfoPtr> devices_;
- std::map<std::string, device::mojom::HidConnectionPtr> connections_;
- mojo::AssociatedInterfacePtrSet<device::mojom::HidManagerClient> clients_;
- mojo::BindingSet<device::mojom::HidManager> bindings_;
+ std::map<std::string, mojo::PendingRemote<device::mojom::HidConnection>>
+ connections_;
+ mojo::AssociatedRemoteSet<device::mojom::HidManagerClient> clients_;
+ mojo::ReceiverSet<device::mojom::HidManager> receivers_;
DISALLOW_COPY_AND_ASSIGN(FakeFidoHidManager);
};
diff --git a/chromium/device/fido/hid/fido_hid_device.cc b/chromium/device/fido/hid/fido_hid_device.cc
index a90c2a79a84..d581712ef01 100644
--- a/chromium/device/fido/hid/fido_hid_device.cc
+++ b/chromium/device/fido/hid/fido_hid_device.cc
@@ -181,7 +181,8 @@ void FidoHidDevice::Connect(
std::move(callback));
}
-void FidoHidDevice::OnConnect(device::mojom::HidConnectionPtr connection) {
+void FidoHidDevice::OnConnect(
+ mojo::PendingRemote<device::mojom::HidConnection> connection) {
timeout_callback_.Cancel();
if (!connection) {
@@ -189,7 +190,7 @@ void FidoHidDevice::OnConnect(device::mojom::HidConnectionPtr connection) {
return;
}
- connection_ = std::move(connection);
+ connection_.Bind(std::move(connection));
// Send random nonce to device to verify received message.
std::vector<uint8_t> nonce(8);
crypto::RandBytes(nonce.data(), nonce.size());
diff --git a/chromium/device/fido/hid/fido_hid_device.h b/chromium/device/fido/hid/fido_hid_device.h
index 8c4bc8c5b7f..c36efd70e28 100644
--- a/chromium/device/fido/hid/fido_hid_device.h
+++ b/chromium/device/fido/hid/fido_hid_device.h
@@ -19,6 +19,8 @@
#include "components/apdu/apdu_command.h"
#include "components/apdu/apdu_response.h"
#include "device/fido/fido_device.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/hid.mojom.h"
namespace device {
@@ -92,7 +94,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoHidDevice : public FidoDevice {
// Open a connection to this device.
void Connect(device::mojom::HidManager::ConnectCallback callback);
- void OnConnect(device::mojom::HidConnectionPtr connection);
+ void OnConnect(mojo::PendingRemote<device::mojom::HidConnection> connection);
void OnInitWriteComplete(std::vector<uint8_t> nonce, bool success);
// Ask device to allocate a unique channel id for this connection.
void OnAllocateChannel(std::vector<uint8_t> nonce,
@@ -145,7 +147,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoHidDevice : public FidoDevice {
// U2fRequest.
device::mojom::HidManager* hid_manager_;
device::mojom::HidDeviceInfoPtr device_info_;
- device::mojom::HidConnectionPtr connection_;
+ mojo::Remote<device::mojom::HidConnection> connection_;
base::WeakPtrFactory<FidoHidDevice> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(FidoHidDevice);
diff --git a/chromium/device/fido/hid/fido_hid_device_unittest.cc b/chromium/device/fido/hid/fido_hid_device_unittest.cc
index b6597970bb2..c229fc1841e 100644
--- a/chromium/device/fido/hid/fido_hid_device_unittest.cc
+++ b/chromium/device/fido/hid/fido_hid_device_unittest.cc
@@ -21,8 +21,8 @@
#include "device/fido/hid/fake_hid_impl_for_testing.h"
#include "device/fido/hid/fido_hid_message.h"
#include "device/fido/test_callback_receiver.h"
-#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/cpp/hid/hid_device_filter.h"
#include "services/device/public/mojom/hid.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -136,12 +136,13 @@ CreateHidConnectionWithHidInitExpectations(
FakeFidoHidManager* fake_hid_manager,
::testing::Sequence sequence) {
auto hid_device = TestHidDevice();
- device::mojom::HidConnectionPtr connection_client;
+ mojo::PendingRemote<device::mojom::HidConnection> connection_client;
// Replace device HID connection with custom client connection bound to mock
// server-side mojo connection.
auto mock_connection = std::make_unique<MockFidoHidConnection>(
- hid_device.Clone(), mojo::MakeRequest(&connection_client), channel_id);
+ hid_device.Clone(), connection_client.InitWithNewPipeAndPassReceiver(),
+ channel_id);
// Initial write for establishing channel ID.
mock_connection->ExpectWriteHidInit();
@@ -223,13 +224,13 @@ class FidoHidDeviceTest : public ::testing::Test {
public:
void SetUp() override {
fake_hid_manager_ = std::make_unique<FakeFidoHidManager>();
- fake_hid_manager_->AddBinding2(mojo::MakeRequest(&hid_manager_));
+ fake_hid_manager_->AddReceiver2(hid_manager_.BindNewPipeAndPassReceiver());
}
protected:
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
- device::mojom::HidManagerPtr hid_manager_;
+ mojo::Remote<device::mojom::HidManager> hid_manager_;
std::unique_ptr<FakeFidoHidManager> fake_hid_manager_;
};
@@ -283,9 +284,10 @@ TEST_F(FidoHidDeviceTest, TestRetryChannelAllocation) {
// Replace device HID connection with custom client connection bound to mock
// server-side mojo connection.
- device::mojom::HidConnectionPtr connection_client;
+ mojo::PendingRemote<device::mojom::HidConnection> connection_client;
MockFidoHidConnection mock_connection(
- hid_device.Clone(), mojo::MakeRequest(&connection_client), kChannelId);
+ hid_device.Clone(), connection_client.InitWithNewPipeAndPassReceiver(),
+ kChannelId);
// Initial write for establishing a channel ID.
mock_connection.ExpectWriteHidInit();
@@ -883,9 +885,10 @@ TEST_F(FidoHidDeviceTest, TestWinkNotSupported) {
// Replace device HID connection with custom client connection bound to mock
// server-side mojo connection.
- device::mojom::HidConnectionPtr connection_client;
+ mojo::PendingRemote<device::mojom::HidConnection> connection_client;
MockFidoHidConnection mock_connection(
- hid_device.Clone(), mojo::MakeRequest(&connection_client), kChannelId);
+ hid_device.Clone(), connection_client.InitWithNewPipeAndPassReceiver(),
+ kChannelId);
// Initial write for establishing a channel ID.
mock_connection.ExpectWriteHidInit();
@@ -943,9 +946,10 @@ TEST_F(FidoHidDeviceTest, TestCtap2DeviceShouldNotBlink) {
// Replace device HID connection with custom client connection bound to mock
// server-side mojo connection.
- device::mojom::HidConnectionPtr connection_client;
+ mojo::PendingRemote<device::mojom::HidConnection> connection_client;
MockFidoHidConnection mock_connection(
- hid_device.Clone(), mojo::MakeRequest(&connection_client), kChannelId);
+ hid_device.Clone(), connection_client.InitWithNewPipeAndPassReceiver(),
+ kChannelId);
// Initial write for establishing a channel ID.
mock_connection.ExpectWriteHidInit();
@@ -998,9 +1002,10 @@ TEST_F(FidoHidDeviceTest, TestSuccessfulWink) {
// Replace device HID connection with custom client connection bound to mock
// server-side mojo connection.
- device::mojom::HidConnectionPtr connection_client;
+ mojo::PendingRemote<device::mojom::HidConnection> connection_client;
MockFidoHidConnection mock_connection(
- hid_device.Clone(), mojo::MakeRequest(&connection_client), kChannelId);
+ hid_device.Clone(), connection_client.InitWithNewPipeAndPassReceiver(),
+ kChannelId);
// Initial write for establishing a channel ID.
mock_connection.ExpectWriteHidInit();
diff --git a/chromium/device/fido/hid/fido_hid_discovery.cc b/chromium/device/fido/hid/fido_hid_discovery.cc
index c471cd02df8..cd80cf0fca7 100644
--- a/chromium/device/fido/hid/fido_hid_discovery.cc
+++ b/chromium/device/fido/hid/fido_hid_discovery.cc
@@ -8,7 +8,6 @@
#include "base/bind.h"
#include "device/fido/hid/fido_hid_device.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
#include "services/device/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
@@ -16,8 +15,7 @@ namespace device {
FidoHidDiscovery::FidoHidDiscovery(::service_manager::Connector* connector)
: FidoDeviceDiscovery(FidoTransportProtocol::kUsbHumanInterfaceDevice),
- connector_(connector),
- binding_(this) {
+ connector_(connector) {
// TODO(piperc@): Give this constant a name.
filter_.SetUsagePage(0xf1d0);
}
@@ -26,14 +24,13 @@ FidoHidDiscovery::~FidoHidDiscovery() = default;
void FidoHidDiscovery::StartInternal() {
DCHECK(connector_);
- connector_->BindInterface(device::mojom::kServiceName,
- mojo::MakeRequest(&hid_manager_));
- device::mojom::HidManagerClientAssociatedPtrInfo client;
- binding_.Bind(mojo::MakeRequest(&client));
+ connector_->Connect(device::mojom::kServiceName,
+ hid_manager_.BindNewPipeAndPassReceiver());
hid_manager_->GetDevicesAndSetClient(
- std::move(client), base::BindOnce(&FidoHidDiscovery::OnGetDevices,
- weak_factory_.GetWeakPtr()));
+ receiver_.BindNewEndpointAndPassRemote(),
+ base::BindOnce(&FidoHidDiscovery::OnGetDevices,
+ weak_factory_.GetWeakPtr()));
}
void FidoHidDiscovery::DeviceAdded(
diff --git a/chromium/device/fido/hid/fido_hid_discovery.h b/chromium/device/fido/hid/fido_hid_discovery.h
index 204bb256122..25772ae2dbd 100644
--- a/chromium/device/fido/hid/fido_hid_discovery.h
+++ b/chromium/device/fido/hid/fido_hid_discovery.h
@@ -12,7 +12,8 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "device/fido/fido_device_discovery.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/cpp/hid/hid_device_filter.h"
#include "services/device/public/mojom/hid.mojom.h"
@@ -43,8 +44,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoHidDiscovery
void OnGetDevices(std::vector<device::mojom::HidDeviceInfoPtr> devices);
service_manager::Connector* connector_;
- device::mojom::HidManagerPtr hid_manager_;
- mojo::AssociatedBinding<device::mojom::HidManagerClient> binding_;
+ mojo::Remote<device::mojom::HidManager> hid_manager_;
+ mojo::AssociatedReceiver<device::mojom::HidManagerClient> receiver_{this};
HidDeviceFilter filter_;
base::WeakPtrFactory<FidoHidDiscovery> weak_factory_{this};
diff --git a/chromium/device/fido/hid/fido_hid_discovery_unittest.cc b/chromium/device/fido/hid/fido_hid_discovery_unittest.cc
index 40d8d61845c..407af4a4bc5 100644
--- a/chromium/device/fido/hid/fido_hid_discovery_unittest.cc
+++ b/chromium/device/fido/hid/fido_hid_discovery_unittest.cc
@@ -4,8 +4,10 @@
#include "device/fido/hid/fido_hid_discovery.h"
+#include <algorithm>
#include <string>
#include <utility>
+#include <vector>
#include "base/test/task_environment.h"
#include "device/fido/fido_authenticator.h"
@@ -52,13 +54,13 @@ TEST_F(FidoHidDiscoveryTest, TestAddRemoveDevice) {
fake_hid_manager_.AddFidoHidDevice("known");
- EXPECT_CALL(observer, DiscoveryStarted(&discovery, true));
- discovery.set_observer(&observer);
- discovery.Start();
-
// Devices initially known to the service before discovery started should be
// reported as KNOWN.
- EXPECT_CALL(observer, AuthenticatorAdded(&discovery, IdMatches("known")));
+ EXPECT_CALL(observer,
+ DiscoveryStarted(&discovery, true,
+ testing::ElementsAre(IdMatches("known"))));
+ discovery.set_observer(&observer);
+ discovery.Start();
task_environment_.RunUntilIdle();
// Devices added during the discovery should be reported as ADDED.
diff --git a/chromium/device/fido/mac/discovery.cc b/chromium/device/fido/mac/discovery.cc
index d7f79396bf6..80e4fce5012 100644
--- a/chromium/device/fido/mac/discovery.cc
+++ b/chromium/device/fido/mac/discovery.cc
@@ -26,13 +26,6 @@ void FidoTouchIdDiscovery::Start() {
return;
}
- if (!TouchIdAuthenticator::IsAvailable(authenticator_config_)) {
- observer()->DiscoveryStarted(this, /*success=*/false);
- return;
- }
-
- observer()->DiscoveryStarted(this, /*success=*/true);
-
// Start() is currently invoked synchronously in the
// FidoRequestHandler ctor. Invoke AddAuthenticator() asynchronously
// to avoid hairpinning FidoRequestHandler::AuthenticatorAdded()
@@ -43,9 +36,12 @@ void FidoTouchIdDiscovery::Start() {
}
void FidoTouchIdDiscovery::AddAuthenticator() {
- DCHECK(TouchIdAuthenticator::IsAvailable(authenticator_config_));
+ if (!TouchIdAuthenticator::IsAvailable(authenticator_config_)) {
+ observer()->DiscoveryStarted(this, /*success=*/false);
+ return;
+ }
authenticator_ = TouchIdAuthenticator::Create(authenticator_config_);
- observer()->AuthenticatorAdded(this, authenticator_.get());
+ observer()->DiscoveryStarted(this, /*success=*/true, {authenticator_.get()});
}
} // namespace mac
diff --git a/chromium/device/fido/make_credential_handler_unittest.cc b/chromium/device/fido/make_credential_handler_unittest.cc
index b9f8adcd042..fd62b38b075 100644
--- a/chromium/device/fido/make_credential_handler_unittest.cc
+++ b/chromium/device/fido/make_credential_handler_unittest.cc
@@ -9,7 +9,6 @@
#include "base/bind_helpers.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
#include "components/cbor/reader.h"
#include "components/cbor/values.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
@@ -33,10 +32,6 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#if defined(OS_WIN)
-#include "device/fido/win/fake_webauthn_api.h"
-#endif // defined(OS_WIN)
-
using ::testing::_;
using ::testing::DoAll;
using ::testing::Invoke;
@@ -91,9 +86,12 @@ class FidoMakeCredentialHandlerTest : public ::testing::Test {
auto handler = std::make_unique<MakeCredentialRequestHandler>(
nullptr, fake_discovery_factory_.get(), supported_transports_,
std::move(request_parameter),
- std::move(authenticator_selection_criteria), cb_.callback());
- if (pending_mock_platform_device_)
+ std::move(authenticator_selection_criteria),
+ /*allow_skipping_pin_touch=*/true, cb_.callback());
+ if (pending_mock_platform_device_) {
platform_discovery_->AddDevice(std::move(pending_mock_platform_device_));
+ platform_discovery_->WaitForCallToStartAndSimulateSuccess();
+ }
return handler;
}
@@ -151,11 +149,6 @@ class FidoMakeCredentialHandlerTest : public ::testing::Test {
TestMakeCredentialRequestCallback cb_;
base::flat_set<FidoTransportProtocol> supported_transports_ =
GetAllTransportProtocols();
-
-#if defined(OS_WIN)
- device::ScopedFakeWinWebAuthnApi win_webauthn_api_ =
- device::ScopedFakeWinWebAuthnApi::MakeUnavailable();
-#endif // defined(OS_WIN)
};
TEST_F(FidoMakeCredentialHandlerTest, TransportAvailabilityInfo) {
diff --git a/chromium/device/fido/make_credential_request_handler.cc b/chromium/device/fido/make_credential_request_handler.cc
index a76d0486414..4cca45d7e15 100644
--- a/chromium/device/fido/make_credential_request_handler.cc
+++ b/chromium/device/fido/make_credential_request_handler.cc
@@ -12,6 +12,7 @@
#include "base/metrics/histogram_functions.h"
#include "base/stl_util.h"
#include "build/build_config.h"
+#include "components/cbor/diagnostic_writer.h"
#include "components/device_event_log/device_event_log.h"
#include "device/fido/fido_authenticator.h"
#include "device/fido/fido_parsing_utils.h"
@@ -177,6 +178,7 @@ MakeCredentialRequestHandler::MakeCredentialRequestHandler(
const base::flat_set<FidoTransportProtocol>& supported_transports,
CtapMakeCredentialRequest request,
AuthenticatorSelectionCriteria authenticator_selection_criteria,
+ bool allow_skipping_pin_touch,
CompletionCallback completion_callback)
: FidoRequestHandlerBase(
connector,
@@ -187,7 +189,8 @@ MakeCredentialRequestHandler::MakeCredentialRequestHandler(
completion_callback_(std::move(completion_callback)),
request_(std::move(request)),
authenticator_selection_criteria_(
- std::move(authenticator_selection_criteria)) {
+ std::move(authenticator_selection_criteria)),
+ allow_skipping_pin_touch_(allow_skipping_pin_touch) {
transport_availability_info().request_type =
FidoRequestHandlerBase::RequestType::kMakeCredential;
@@ -252,6 +255,11 @@ void MakeCredentialRequestHandler::DispatchRequest(
switch (authenticator->WillNeedPINToMakeCredential(request_, observer())) {
case MakeCredentialPINDisposition::kUsePIN:
case MakeCredentialPINDisposition::kSetPIN:
+ // Skip asking for touch if this is the only available authenticator.
+ if (active_authenticators().size() == 1 && allow_skipping_pin_touch_) {
+ HandleTouch(authenticator);
+ return;
+ }
// A PIN will be needed. Just request a touch to let the user select
// this authenticator if they wish.
authenticator->GetTouch(
@@ -373,14 +381,43 @@ void MakeCredentialRequestHandler::HandleResponse(
const auto rp_id_hash = fido_parsing_utils::CreateSHA256Hash(request_.rp.id);
if (!response || response->GetRpIdHash() != rp_id_hash) {
- FIDO_LOG(ERROR) << "Failing assertion request due to bad response from "
- << authenticator->GetDisplayName();
+ FIDO_LOG(ERROR)
+ << "Failing make credential request due to bad response from "
+ << authenticator->GetDisplayName();
std::move(completion_callback_)
.Run(MakeCredentialStatus::kAuthenticatorResponseInvalid, base::nullopt,
authenticator);
return;
}
+ const base::Optional<cbor::Value>& extensions =
+ response->attestation_object().authenticator_data().extensions();
+ if (extensions) {
+ // The fact that |extensions| is a map is checked in
+ // |AuthenticatorData::DecodeAuthenticatorData|.
+ for (const auto& it : extensions->GetMap()) {
+ if (request_.cred_protect &&
+ authenticator->Options()->supports_cred_protect &&
+ it.first.is_string() &&
+ it.first.GetString() == kExtensionCredProtect &&
+ it.second.is_integer()) {
+ continue;
+ }
+ if (request_.hmac_secret && it.first.is_string() &&
+ it.first.GetString() == kExtensionHmacSecret && it.second.is_bool()) {
+ continue;
+ }
+
+ FIDO_LOG(ERROR)
+ << "Failing make credential request due to extensions block: "
+ << cbor::DiagnosticWriter::Write(*extensions);
+ std::move(completion_callback_)
+ .Run(MakeCredentialStatus::kAuthenticatorResponseInvalid,
+ base::nullopt, authenticator);
+ return;
+ }
+ }
+
if (authenticator->AuthenticatorTransport()) {
base::UmaHistogramEnumeration(
"WebAuthentication.MakeCredentialResponseTransport",
diff --git a/chromium/device/fido/make_credential_request_handler.h b/chromium/device/fido/make_credential_request_handler.h
index e4dcce2b1a3..a0128b67200 100644
--- a/chromium/device/fido/make_credential_request_handler.h
+++ b/chromium/device/fido/make_credential_request_handler.h
@@ -70,6 +70,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) MakeCredentialRequestHandler
const base::flat_set<FidoTransportProtocol>& supported_transports,
CtapMakeCredentialRequest request_parameter,
AuthenticatorSelectionCriteria authenticator_criteria,
+ bool allow_skipping_pin_touch,
CompletionCallback completion_callback);
~MakeCredentialRequestHandler() override;
@@ -115,6 +116,9 @@ class COMPONENT_EXPORT(DEVICE_FIDO) MakeCredentialRequestHandler
State state_ = State::kWaitingForTouch;
CtapMakeCredentialRequest request_;
AuthenticatorSelectionCriteria authenticator_selection_criteria_;
+ // If true, the request handler may skip the first touch to select a device
+ // that will require a PIN.
+ bool allow_skipping_pin_touch_;
// authenticator_ points to the authenticator that will be used for this
// operation. It's only set after the user touches an authenticator to select
// it, after which point that authenticator will be used exclusively through
diff --git a/chromium/device/fido/mock_fido_discovery_observer.h b/chromium/device/fido/mock_fido_discovery_observer.h
index ce022186b6c..6be19886a72 100644
--- a/chromium/device/fido/mock_fido_discovery_observer.h
+++ b/chromium/device/fido/mock_fido_discovery_observer.h
@@ -6,6 +6,7 @@
#define DEVICE_FIDO_MOCK_FIDO_DISCOVERY_OBSERVER_H_
#include <string>
+#include <vector>
#include "base/component_export.h"
#include "base/macros.h"
@@ -21,7 +22,8 @@ class MockFidoDiscoveryObserver : public FidoDiscoveryBase::Observer {
MockFidoDiscoveryObserver();
~MockFidoDiscoveryObserver() override;
- MOCK_METHOD2(DiscoveryStarted, void(FidoDiscoveryBase*, bool));
+ MOCK_METHOD3(DiscoveryStarted,
+ void(FidoDiscoveryBase*, bool, std::vector<FidoAuthenticator*>));
MOCK_METHOD2(DiscoveryStopped, void(FidoDiscoveryBase*, bool));
MOCK_METHOD2(AuthenticatorAdded,
void(FidoDiscoveryBase*, FidoAuthenticator*));
diff --git a/chromium/device/fido/u2f_command_constructor.cc b/chromium/device/fido/u2f_command_constructor.cc
index ce2839e662c..e54cf880ff0 100644
--- a/chromium/device/fido/u2f_command_constructor.cc
+++ b/chromium/device/fido/u2f_command_constructor.cc
@@ -53,12 +53,12 @@ base::Optional<std::vector<uint8_t>> ConvertToU2fRegisterCommand(
request.client_data_hash, is_invidual_attestation);
}
-base::Optional<std::vector<uint8_t>> ConvertToU2fSignCommand(
+base::Optional<std::vector<uint8_t>> ConvertToU2fSignCommandWithBogusChallenge(
const CtapMakeCredentialRequest& request,
base::span<const uint8_t> key_handle) {
return ConstructU2fSignCommand(
fido_parsing_utils::CreateSHA256Hash(request.rp.id),
- request.client_data_hash, key_handle);
+ kBogusChallenge, key_handle);
}
base::Optional<std::vector<uint8_t>> ConvertToU2fSignCommand(
diff --git a/chromium/device/fido/u2f_command_constructor.h b/chromium/device/fido/u2f_command_constructor.h
index fd3225d4901..e36fecc7112 100644
--- a/chromium/device/fido/u2f_command_constructor.h
+++ b/chromium/device/fido/u2f_command_constructor.h
@@ -37,9 +37,10 @@ COMPONENT_EXPORT(DEVICE_FIDO)
base::Optional<std::vector<uint8_t>> ConvertToU2fRegisterCommand(
const CtapMakeCredentialRequest& request);
-// Extracts APDU encoded U2F sign command from CtapMakeCredentialRequest.
+// Turns a CtapMakeCredentialRequest into an APDU encoded U2F sign command
+// for the same RP and key handle, but a bogus challenge.
COMPONENT_EXPORT(DEVICE_FIDO)
-base::Optional<std::vector<uint8_t>> ConvertToU2fSignCommand(
+base::Optional<std::vector<uint8_t>> ConvertToU2fSignCommandWithBogusChallenge(
const CtapMakeCredentialRequest& request,
base::span<const uint8_t> key_handle);
diff --git a/chromium/device/fido/u2f_register_operation.cc b/chromium/device/fido/u2f_register_operation.cc
index 3a85342a84e..1a7d3954b97 100644
--- a/chromium/device/fido/u2f_register_operation.cc
+++ b/chromium/device/fido/u2f_register_operation.cc
@@ -57,9 +57,11 @@ void U2fRegisterOperation::TrySign() {
if (probing_alternative_rp_id_) {
CtapMakeCredentialRequest sign_request(request());
sign_request.rp.id = *request().app_id;
- sign_command = ConvertToU2fSignCommand(sign_request, excluded_key_handle());
+ sign_command = ConvertToU2fSignCommandWithBogusChallenge(
+ sign_request, excluded_key_handle());
} else {
- sign_command = ConvertToU2fSignCommand(request(), excluded_key_handle());
+ sign_command = ConvertToU2fSignCommandWithBogusChallenge(
+ request(), excluded_key_handle());
}
DispatchDeviceRequest(
diff --git a/chromium/device/fido/u2f_register_operation_unittest.cc b/chromium/device/fido/u2f_register_operation_unittest.cc
index 7f4eaf0ac70..bd55c89ebb4 100644
--- a/chromium/device/fido/u2f_register_operation_unittest.cc
+++ b/chromium/device/fido/u2f_register_operation_unittest.cc
@@ -155,17 +155,19 @@ TEST_F(U2fRegisterOperationTest, TestRegistrationWithExclusionList) {
auto device = std::make_unique<MockFidoDevice>();
EXPECT_CALL(*device, GetId()).WillRepeatedly(::testing::Return("device"));
device->ExpectWinkedAtLeastOnce();
- // DeviceTransact() will be called three times including two check only sign-
- // in calls and one registration call. For the first two calls, device will
- // invoke MockFidoDevice::WrongData/WrongLength as the authenticator did not
- // create the two key handles provided in the exclude list. At the third call,
- // MockFidoDevice::NoErrorRegister will be invoked after registration.
+ // DeviceTransact() will be called three times including two sign-in calls
+ // with bogus challenges and one registration call. For the first two calls,
+ // device will invoke MockFidoDevice::WrongData/WrongLength as the
+ // authenticator did not create the two key handles provided in the exclude
+ // list. At the third call, MockFidoDevice::NoErrorRegister will be invoked
+ // after registration.
::testing::InSequence s;
device->ExpectRequestAndRespondWith(
- test_data::kU2fSignCommandApduWithKeyAlpha,
+ test_data::kU2fSignCommandApduWithKeyAlphaAndBogusChallenge,
test_data::kU2fWrongDataApduResponse);
- device->ExpectRequestAndRespondWith(test_data::kU2fSignCommandApduWithKeyBeta,
- test_data::kU2fWrongLengthApduResponse);
+ device->ExpectRequestAndRespondWith(
+ test_data::kU2fSignCommandApduWithKeyBetaAndBogusChallenge,
+ test_data::kU2fWrongLengthApduResponse);
device->ExpectRequestAndRespondWith(
test_data::kU2fRegisterCommandApdu,
test_data::kApduEncodedNoErrorRegisterResponse);
@@ -210,12 +212,15 @@ TEST_F(U2fRegisterOperationTest, TestRegistrationWithDuplicateHandle) {
// request is concluded with Ctap2ErrCredentialExcluded.
::testing::InSequence s;
device->ExpectRequestAndRespondWith(
- test_data::kU2fSignCommandApduWithKeyAlpha,
+ test_data::kU2fSignCommandApduWithKeyAlphaAndBogusChallenge,
+ test_data::kU2fWrongDataApduResponse);
+ device->ExpectRequestAndRespondWith(
+ test_data::kU2fSignCommandApduWithKeyBetaAndBogusChallenge,
test_data::kU2fWrongDataApduResponse);
- device->ExpectRequestAndRespondWith(test_data::kU2fSignCommandApduWithKeyBeta,
- test_data::kU2fWrongDataApduResponse);
+ // The signature in the response is intentionally incorrect since nothing
+ // should depend on it being correct.
device->ExpectRequestAndRespondWith(
- test_data::kU2fSignCommandApduWithKeyGamma,
+ test_data::kU2fSignCommandApduWithKeyGammaAndBogusChallenge,
test_data::kApduEncodedNoErrorSignResponse);
auto u2f_register = std::make_unique<U2fRegisterOperation>(
diff --git a/chromium/device/fido/virtual_ctap2_device.cc b/chromium/device/fido/virtual_ctap2_device.cc
index b3450febf46..d3f9971cf4f 100644
--- a/chromium/device/fido/virtual_ctap2_device.cc
+++ b/chromium/device/fido/virtual_ctap2_device.cc
@@ -791,6 +791,11 @@ base::Optional<CtapDeviceResponseCode> VirtualCtap2Device::OnMakeCredential(
cbor::Value(
request.cred_protect->first == CredProtect::kUVRequired ? 3 : 2));
}
+
+ if (config_.add_extra_extension) {
+ extensions_map.emplace(cbor::Value("unsolicited"), cbor::Value(42));
+ }
+
if (!extensions_map.empty()) {
extensions = cbor::Value(std::move(extensions_map));
}
@@ -983,6 +988,15 @@ base::Optional<CtapDeviceResponseCode> VirtualCtap2Device::OnGetAssertion(
return CtapDeviceResponseCode::kCtap2ErrNoCredentials;
}
+ base::Optional<cbor::Value> extensions;
+ cbor::Value::MapValue extensions_map;
+ if (config_.add_extra_extension) {
+ extensions_map.emplace(cbor::Value("unsolicited"), cbor::Value(42));
+ }
+ if (!extensions_map.empty()) {
+ extensions = cbor::Value(std::move(extensions_map));
+ }
+
// This implementation does not sort credentials by creation time as the spec
// requires.
@@ -1005,7 +1019,8 @@ base::Optional<CtapDeviceResponseCode> VirtualCtap2Device::OnGetAssertion(
auto authenticator_data = ConstructAuthenticatorData(
rp_id_hash, user_verified, registration.second->counter,
- std::move(opt_attested_cred_data), base::nullopt);
+ std::move(opt_attested_cred_data),
+ extensions ? base::make_optional(extensions->Clone()) : base::nullopt);
auto signature_buffer =
ConstructSignatureBuffer(authenticator_data, client_data_hash);
diff --git a/chromium/device/fido/virtual_ctap2_device.h b/chromium/device/fido/virtual_ctap2_device.h
index 62114aae5e1..a598c78b2e1 100644
--- a/chromium/device/fido/virtual_ctap2_device.h
+++ b/chromium/device/fido/virtual_ctap2_device.h
@@ -85,6 +85,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualCtap2Device
// at a pre-defined byte length without concern for UTF-8 validity of the
// result.
bool allow_invalid_utf8_in_credential_entities = false;
+
+ // add_extra_extension causes an unsolicited extension to be added in the
+ // authenticator extensions output.
+ bool add_extra_extension = false;
};
VirtualCtap2Device();
diff --git a/chromium/device/fido/virtual_fido_device_factory.cc b/chromium/device/fido/virtual_fido_device_factory.cc
index 69c3aef6dc7..fd2e2aaa3bf 100644
--- a/chromium/device/fido/virtual_fido_device_factory.cc
+++ b/chromium/device/fido/virtual_fido_device_factory.cc
@@ -57,8 +57,7 @@ class VirtualFidoDeviceDiscovery
DISALLOW_COPY_AND_ASSIGN(VirtualFidoDeviceDiscovery);
};
-VirtualFidoDeviceFactory::VirtualFidoDeviceFactory()
- : state_(new VirtualFidoDevice::State) {}
+VirtualFidoDeviceFactory::VirtualFidoDeviceFactory() = default;
VirtualFidoDeviceFactory::~VirtualFidoDeviceFactory() = default;
void VirtualFidoDeviceFactory::SetSupportedProtocol(
diff --git a/chromium/device/fido/virtual_fido_device_factory.h b/chromium/device/fido/virtual_fido_device_factory.h
index daf500bb345..44747edcc69 100644
--- a/chromium/device/fido/virtual_fido_device_factory.h
+++ b/chromium/device/fido/virtual_fido_device_factory.h
@@ -48,7 +48,7 @@ class VirtualFidoDeviceFactory : public device::FidoDiscoveryFactory {
FidoTransportProtocol transport_ =
FidoTransportProtocol::kUsbHumanInterfaceDevice;
VirtualCtap2Device::Config ctap2_config_;
- scoped_refptr<VirtualFidoDevice::State> state_;
+ scoped_refptr<VirtualFidoDevice::State> state_ = new VirtualFidoDevice::State;
DISALLOW_COPY_AND_ASSIGN(VirtualFidoDeviceFactory);
};
diff --git a/chromium/device/fido/win/authenticator.cc b/chromium/device/fido/win/authenticator.cc
index afcd487d398..88f88042340 100644
--- a/chromium/device/fido/win/authenticator.cc
+++ b/chromium/device/fido/win/authenticator.cc
@@ -4,7 +4,6 @@
#include "device/fido/win/authenticator.h"
-#include <Combaseapi.h>
#include <windows.h>
#include <utility>
#include <vector>
@@ -24,24 +23,24 @@
#include "device/fido/fido_constants.h"
#include "device/fido/fido_transport_protocol.h"
#include "device/fido/win/type_conversions.h"
+#include "device/fido/win/webauthn_api.h"
#include "third_party/microsoft_webauthn/webauthn.h"
namespace device {
// static
-bool WinWebAuthnApiAuthenticator::
- IsUserVerifyingPlatformAuthenticatorAvailable() {
+bool WinWebAuthnApiAuthenticator::IsUserVerifyingPlatformAuthenticatorAvailable(
+ WinWebAuthnApi* api) {
BOOL result;
- WinWebAuthnApi* api = WinWebAuthnApi::GetDefault();
- return api->IsAvailable() &&
+ return api && api->IsAvailable() &&
api->IsUserVerifyingPlatformAuthenticatorAvailable(&result) == S_OK &&
result == TRUE;
}
-WinWebAuthnApiAuthenticator::WinWebAuthnApiAuthenticator(HWND current_window)
- : FidoAuthenticator(),
- current_window_(current_window),
- win_api_(WinWebAuthnApi::GetDefault()) {
+WinWebAuthnApiAuthenticator::WinWebAuthnApiAuthenticator(
+ HWND current_window,
+ WinWebAuthnApi* win_api)
+ : current_window_(current_window), win_api_(win_api) {
CHECK(win_api_->IsAvailable());
CoCreateGuid(&cancellation_id_);
}
diff --git a/chromium/device/fido/win/authenticator.h b/chromium/device/fido/win/authenticator.h
index 36adb1a8814..3eccf8ce791 100644
--- a/chromium/device/fido/win/authenticator.h
+++ b/chromium/device/fido/win/authenticator.h
@@ -5,6 +5,7 @@
#ifndef DEVICE_FIDO_WIN_AUTHENTICATOR_H_
#define DEVICE_FIDO_WIN_AUTHENTICATOR_H_
+#include <Combaseapi.h>
#include <memory>
#include <string>
@@ -14,10 +15,11 @@
#include "base/optional.h"
#include "base/sequence_checker.h"
#include "device/fido/fido_authenticator.h"
-#include "device/fido/win/webauthn_api.h"
namespace device {
+class WinWebAuthnApi;
+
// WinWebAuthnApiAuthenticator forwards WebAuthn requests to external
// authenticators via the native Windows WebAuthentication API
// (webauthn.dll).
@@ -29,13 +31,14 @@ class COMPONENT_EXPORT(DEVICE_FIDO) WinWebAuthnApiAuthenticator
public:
// This method is safe to call without checking
// WinWebAuthnApi::IsAvailable().
- static bool IsUserVerifyingPlatformAuthenticatorAvailable();
+ static bool IsUserVerifyingPlatformAuthenticatorAvailable(
+ WinWebAuthnApi* api);
// Instantiates an authenticator that uses the default WinWebAuthnApi.
//
// Callers must ensure that WinWebAuthnApi::IsAvailable() returns true
// before creating instances of this class.
- WinWebAuthnApiAuthenticator(HWND current_window);
+ WinWebAuthnApiAuthenticator(HWND current_window, WinWebAuthnApi* win_api_);
~WinWebAuthnApiAuthenticator() override;
// SupportsCredProtectExtension returns whether the native API supports the
diff --git a/chromium/device/fido/win/discovery.cc b/chromium/device/fido/win/discovery.cc
index fa41083bec2..f5e4abf4b68 100644
--- a/chromium/device/fido/win/discovery.cc
+++ b/chromium/device/fido/win/discovery.cc
@@ -12,9 +12,11 @@
namespace device {
WinWebAuthnApiAuthenticatorDiscovery::WinWebAuthnApiAuthenticatorDiscovery(
- HWND parent_window)
+ HWND parent_window,
+ WinWebAuthnApi* api)
: FidoDiscoveryBase(FidoTransportProtocol::kUsbHumanInterfaceDevice),
- parent_window_(parent_window) {}
+ parent_window_(parent_window),
+ api_(api) {}
WinWebAuthnApiAuthenticatorDiscovery::~WinWebAuthnApiAuthenticatorDiscovery() =
default;
@@ -25,13 +27,6 @@ void WinWebAuthnApiAuthenticatorDiscovery::Start() {
return;
}
- if (!WinWebAuthnApi::GetDefault()->IsAvailable()) {
- observer()->DiscoveryStarted(this, false /* discovery failed */);
- return;
- }
-
- observer()->DiscoveryStarted(this, true /* success */);
-
// Start() is currently invoked synchronously in the
// FidoRequestHandler ctor. Invoke AddAuthenticator() asynchronously
// to avoid hairpinning FidoRequestHandler::AuthenticatorAdded()
@@ -43,13 +38,13 @@ void WinWebAuthnApiAuthenticatorDiscovery::Start() {
}
void WinWebAuthnApiAuthenticatorDiscovery::AddAuthenticator() {
- if (!WinWebAuthnApi::GetDefault()->IsAvailable()) {
- NOTREACHED();
+ if (!api_->IsAvailable()) {
+ observer()->DiscoveryStarted(this, /*success=*/false);
return;
}
authenticator_ =
- std::make_unique<WinWebAuthnApiAuthenticator>(parent_window_);
- observer()->AuthenticatorAdded(this, authenticator_.get());
+ std::make_unique<WinWebAuthnApiAuthenticator>(parent_window_, api_);
+ observer()->DiscoveryStarted(this, /*success=*/true, {authenticator_.get()});
}
} // namespace device
diff --git a/chromium/device/fido/win/discovery.h b/chromium/device/fido/win/discovery.h
index 10f2b008706..201e6017d9e 100644
--- a/chromium/device/fido/win/discovery.h
+++ b/chromium/device/fido/win/discovery.h
@@ -14,12 +14,14 @@
namespace device {
+class WinWebAuthnApi;
+
// Instantiates the authenticator subclass for forwarding requests to external
// authenticators via the Windows WebAuthn API.
class COMPONENT_EXPORT(DEVICE_FIDO) WinWebAuthnApiAuthenticatorDiscovery
: public FidoDiscoveryBase {
public:
- WinWebAuthnApiAuthenticatorDiscovery(HWND parent_window);
+ WinWebAuthnApiAuthenticatorDiscovery(HWND parent_window, WinWebAuthnApi* api);
~WinWebAuthnApiAuthenticatorDiscovery() override;
// FidoDiscoveryBase:
@@ -30,6 +32,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) WinWebAuthnApiAuthenticatorDiscovery
std::unique_ptr<WinWebAuthnApiAuthenticator> authenticator_;
const HWND parent_window_;
+ WinWebAuthnApi* api_;
base::WeakPtrFactory<WinWebAuthnApiAuthenticatorDiscovery> weak_factory_{
this};
diff --git a/chromium/device/fido/win/fake_webauthn_api.cc b/chromium/device/fido/win/fake_webauthn_api.cc
index 837a1bb7713..6c77584d668 100644
--- a/chromium/device/fido/win/fake_webauthn_api.cc
+++ b/chromium/device/fido/win/fake_webauthn_api.cc
@@ -12,54 +12,7 @@
namespace device {
-namespace {
-
-WEBAUTHN_CREDENTIAL_ATTESTATION FakeAttestation() {
- WEBAUTHN_CREDENTIAL_ATTESTATION attestation = {};
- attestation.dwVersion = WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_1;
- attestation.cbAuthenticatorData =
- sizeof(test_data::kCtap2MakeCredentialAuthData);
- attestation.pbAuthenticatorData = reinterpret_cast<PBYTE>(
- const_cast<uint8_t*>(device::test_data::kCtap2MakeCredentialAuthData));
- attestation.cbAttestation =
- sizeof(test_data::kPackedAttestationStatementCBOR);
- attestation.pbAttestation = reinterpret_cast<PBYTE>(
- const_cast<uint8_t*>(device::test_data::kPackedAttestationStatementCBOR));
- attestation.cbAttestationObject = 0;
- attestation.cbCredentialId = 0;
- attestation.pwszFormatType = L"packed";
- attestation.dwAttestationDecodeType = 0;
- return attestation;
-}
-
-WEBAUTHN_ASSERTION FakeAssertion() {
- WEBAUTHN_CREDENTIAL credential = {};
- // No constant macro available because 1 is the current version
- credential.dwVersion = 1;
- credential.cbId = sizeof(test_data::kCredentialId);
- credential.pbId =
- reinterpret_cast<PBYTE>(const_cast<uint8_t*>(test_data::kCredentialId));
- credential.pwszCredentialType = L"public-key";
-
- WEBAUTHN_ASSERTION assertion = {};
- // No constant macro available because 1 is the current version
- assertion.dwVersion = 1;
- assertion.cbAuthenticatorData = sizeof(test_data::kTestSignAuthenticatorData);
- assertion.pbAuthenticatorData = reinterpret_cast<PBYTE>(
- const_cast<uint8_t*>(test_data::kTestSignAuthenticatorData));
- assertion.cbSignature = sizeof(test_data::kCtap2GetAssertionSignature);
- assertion.pbSignature = reinterpret_cast<PBYTE>(
- const_cast<uint8_t*>(test_data::kCtap2GetAssertionSignature));
- assertion.Credential = credential;
- assertion.pbUserId = NULL;
- assertion.cbUserId = 0;
- return assertion;
-}
-
-} // namespace
-
-FakeWinWebAuthnApi::FakeWinWebAuthnApi()
- : attestation_(FakeAttestation()), assertion_(FakeAssertion()) {}
+FakeWinWebAuthnApi::FakeWinWebAuthnApi() = default;
FakeWinWebAuthnApi::~FakeWinWebAuthnApi() = default;
bool FakeWinWebAuthnApi::IsAvailable() const {
@@ -137,19 +90,48 @@ int FakeWinWebAuthnApi::Version() {
return version_;
}
-ScopedFakeWinWebAuthnApi::ScopedFakeWinWebAuthnApi() : FakeWinWebAuthnApi() {
- WinWebAuthnApi::SetDefaultForTesting(this);
-}
-
-ScopedFakeWinWebAuthnApi::~ScopedFakeWinWebAuthnApi() {
- WinWebAuthnApi::ClearDefaultForTesting();
+// static
+WEBAUTHN_CREDENTIAL_ATTESTATION FakeWinWebAuthnApi::FakeAttestation() {
+ WEBAUTHN_CREDENTIAL_ATTESTATION attestation = {};
+ attestation.dwVersion = WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_1;
+ attestation.cbAuthenticatorData =
+ sizeof(test_data::kCtap2MakeCredentialAuthData);
+ attestation.pbAuthenticatorData = reinterpret_cast<PBYTE>(
+ const_cast<uint8_t*>(device::test_data::kCtap2MakeCredentialAuthData));
+ attestation.cbAttestation =
+ sizeof(test_data::kPackedAttestationStatementCBOR);
+ attestation.pbAttestation = reinterpret_cast<PBYTE>(
+ const_cast<uint8_t*>(device::test_data::kPackedAttestationStatementCBOR));
+ attestation.cbAttestationObject = 0;
+ attestation.cbCredentialId = 0;
+ attestation.pwszFormatType = L"packed";
+ attestation.dwAttestationDecodeType = 0;
+ return attestation;
}
// static
-ScopedFakeWinWebAuthnApi ScopedFakeWinWebAuthnApi::MakeUnavailable() {
- ScopedFakeWinWebAuthnApi api;
- api.set_available(false);
- return api;
+WEBAUTHN_ASSERTION FakeWinWebAuthnApi::FakeAssertion() {
+ WEBAUTHN_CREDENTIAL credential = {};
+ // No constant macro available because 1 is the current version
+ credential.dwVersion = 1;
+ credential.cbId = sizeof(test_data::kCredentialId);
+ credential.pbId =
+ reinterpret_cast<PBYTE>(const_cast<uint8_t*>(test_data::kCredentialId));
+ credential.pwszCredentialType = L"public-key";
+
+ WEBAUTHN_ASSERTION assertion = {};
+ // No constant macro available because 1 is the current version
+ assertion.dwVersion = 1;
+ assertion.cbAuthenticatorData = sizeof(test_data::kTestSignAuthenticatorData);
+ assertion.pbAuthenticatorData = reinterpret_cast<PBYTE>(
+ const_cast<uint8_t*>(test_data::kTestSignAuthenticatorData));
+ assertion.cbSignature = sizeof(test_data::kCtap2GetAssertionSignature);
+ assertion.pbSignature = reinterpret_cast<PBYTE>(
+ const_cast<uint8_t*>(test_data::kCtap2GetAssertionSignature));
+ assertion.Credential = credential;
+ assertion.pbUserId = nullptr;
+ assertion.cbUserId = 0;
+ return assertion;
}
} // namespace device
diff --git a/chromium/device/fido/win/fake_webauthn_api.h b/chromium/device/fido/win/fake_webauthn_api.h
index cc4d3c9433a..88a901df9f8 100644
--- a/chromium/device/fido/win/fake_webauthn_api.h
+++ b/chromium/device/fido/win/fake_webauthn_api.h
@@ -5,6 +5,7 @@
#ifndef DEVICE_FIDO_WIN_FAKE_WEBAUTHN_API_H_
#define DEVICE_FIDO_WIN_FAKE_WEBAUTHN_API_H_
+#include "base/component_export.h"
#include "device/fido/public_key_credential_descriptor.h"
#include "device/fido/public_key_credential_rp_entity.h"
#include "device/fido/public_key_credential_user_entity.h"
@@ -12,7 +13,7 @@
namespace device {
-class FakeWinWebAuthnApi : public WinWebAuthnApi {
+class COMPONENT_EXPORT(DEVICE_FIDO) FakeWinWebAuthnApi : public WinWebAuthnApi {
public:
FakeWinWebAuthnApi();
~FakeWinWebAuthnApi() override;
@@ -53,34 +54,17 @@ class FakeWinWebAuthnApi : public WinWebAuthnApi {
int Version() override;
private:
+ static WEBAUTHN_CREDENTIAL_ATTESTATION FakeAttestation();
+ static WEBAUTHN_ASSERTION FakeAssertion();
+
bool is_available_ = true;
bool is_uvpaa_ = false;
int version_ = WEBAUTHN_API_VERSION_2;
- WEBAUTHN_CREDENTIAL_ATTESTATION attestation_;
- WEBAUTHN_ASSERTION assertion_;
+ WEBAUTHN_CREDENTIAL_ATTESTATION attestation_ = FakeAttestation();
+ WEBAUTHN_ASSERTION assertion_ = FakeAssertion();
HRESULT result_ = S_OK;
};
-// ScopedFakeWinWebAuthnApi overrides the value returned
-// by WinWebAuthnApi::GetDefault() with itself for the duration of its
-// lifetime.
-class ScopedFakeWinWebAuthnApi : public FakeWinWebAuthnApi {
- public:
- // MakeUnavailable() returns a ScopedFakeWinWebAuthnApi that simulates a
- // system where the native WebAuthn API is unavailable.
- //
- // Tests that instantiate a FidoDiscoveryFactory and FidoRequestHandler
- // should instantiate a ScopedFakeWinWebAuthnApi with this method to avoid
- // invoking the real Windows WebAuthn API on systems where it is available.
- // Note that individual tests can call set_available(true) prior to
- // instantiating the FidoRequestHandler in order to make the fake simulate an
- // available API.
- static ScopedFakeWinWebAuthnApi MakeUnavailable();
-
- ScopedFakeWinWebAuthnApi();
- ~ScopedFakeWinWebAuthnApi() override;
-};
-
} // namespace device
#endif // DEVICE_FIDO_WIN_FAKE_WEBAUTHN_API_H_
diff --git a/chromium/device/fido/win/webauthn_api.cc b/chromium/device/fido/win/webauthn_api.cc
index 05936a30aa3..11b81adf9e5 100644
--- a/chromium/device/fido/win/webauthn_api.cc
+++ b/chromium/device/fido/win/webauthn_api.cc
@@ -162,30 +162,12 @@ class WinWebAuthnApiImpl : public WinWebAuthnApi {
decltype(&WebAuthNGetApiVersionNumber) get_api_version_number_ = nullptr;
};
-static WinWebAuthnApi* kDefaultForTesting = nullptr;
-
// static
WinWebAuthnApi* WinWebAuthnApi::GetDefault() {
- if (kDefaultForTesting) {
- return kDefaultForTesting;
- }
-
static base::NoDestructor<WinWebAuthnApiImpl> api;
return api.get();
}
-// static
-void WinWebAuthnApi::SetDefaultForTesting(WinWebAuthnApi* api) {
- DCHECK(!kDefaultForTesting);
- kDefaultForTesting = api;
-}
-
-// static
-void WinWebAuthnApi::ClearDefaultForTesting() {
- DCHECK(kDefaultForTesting);
- kDefaultForTesting = nullptr;
-}
-
WinWebAuthnApi::WinWebAuthnApi() = default;
WinWebAuthnApi::~WinWebAuthnApi() = default;
diff --git a/chromium/device/fido/win/webauthn_api.h b/chromium/device/fido/win/webauthn_api.h
index 92951364f69..85a1f60a5d6 100644
--- a/chromium/device/fido/win/webauthn_api.h
+++ b/chromium/device/fido/win/webauthn_api.h
@@ -70,11 +70,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) WinWebAuthnApi {
protected:
WinWebAuthnApi();
-
- private:
- friend class ScopedFakeWinWebAuthnApi;
- static void SetDefaultForTesting(WinWebAuthnApi* api);
- static void ClearDefaultForTesting();
};
std::pair<CtapDeviceResponseCode,
diff --git a/chromium/device/gamepad/BUILD.gn b/chromium/device/gamepad/BUILD.gn
index ec7c1aea0a4..8442e95c2b7 100644
--- a/chromium/device/gamepad/BUILD.gn
+++ b/chromium/device/gamepad/BUILD.gn
@@ -184,8 +184,10 @@ if (is_android) {
]
deps = [
"//base:base_java",
- "//third_party/android_deps:com_android_support_support_annotations_java",
+ "//base:jni_java",
+ "//third_party/android_deps:androidx_annotation_annotation_java",
]
+ annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
srcjar_deps = [ ":java_enums_srcjar" ]
}
diff --git a/chromium/device/gamepad/android/java/src/org/chromium/device/gamepad/GamepadList.java b/chromium/device/gamepad/android/java/src/org/chromium/device/gamepad/GamepadList.java
index 0991f38be92..eb1b9862179 100644
--- a/chromium/device/gamepad/android/java/src/org/chromium/device/gamepad/GamepadList.java
+++ b/chromium/device/gamepad/android/java/src/org/chromium/device/gamepad/GamepadList.java
@@ -16,6 +16,7 @@ import android.view.MotionEvent;
import org.chromium.base.ThreadUtils;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeMethods;
/**
* Class to manage connected gamepad devices list.
@@ -288,11 +289,12 @@ public class GamepadList {
final GamepadDevice device = getDevice(i);
if (device != null) {
device.updateButtonsAndAxesMapping();
- nativeSetGamepadData(webGamepadsPtr, i, device.isStandardGamepad(), true,
- device.getName(), device.getTimestamp(), device.getAxes(),
- device.getButtons());
+ GamepadListJni.get().setGamepadData(GamepadList.this, webGamepadsPtr, i,
+ device.isStandardGamepad(), true, device.getName(),
+ device.getTimestamp(), device.getAxes(), device.getButtons());
} else {
- nativeSetGamepadData(webGamepadsPtr, i, false, false, null, 0, null, null);
+ GamepadListJni.get().setGamepadData(
+ GamepadList.this, webGamepadsPtr, i, false, false, null, 0, null, null);
}
}
}
@@ -316,10 +318,14 @@ public class GamepadList {
}
}
- private native void nativeSetGamepadData(long webGamepadsPtr, int index, boolean mapping,
- boolean connected, String devicename, long timestamp, float[] axes, float[] buttons);
-
private static class LazyHolder {
private static final GamepadList INSTANCE = new GamepadList();
}
+
+ @NativeMethods
+ interface Natives {
+ void setGamepadData(GamepadList caller, long webGamepadsPtr, int index, boolean mapping,
+ boolean connected, String devicename, long timestamp, float[] axes,
+ float[] buttons);
+ }
}
diff --git a/chromium/device/gamepad/android/junit/src/org/chromium/device/gamepad/GamepadMappingsTest.java b/chromium/device/gamepad/android/junit/src/org/chromium/device/gamepad/GamepadMappingsTest.java
index bb5a8284c3a..599f9d24afa 100644
--- a/chromium/device/gamepad/android/junit/src/org/chromium/device/gamepad/GamepadMappingsTest.java
+++ b/chromium/device/gamepad/android/junit/src/org/chromium/device/gamepad/GamepadMappingsTest.java
@@ -52,7 +52,7 @@ public class GamepadMappingsTest {
private float[] mRawAxes = new float[GamepadDevice.MAX_RAW_AXIS_VALUES];
@Before
- public void setUp() throws Exception {
+ public void setUp() {
// By default, we expect every button and axis to be mapped.
mUnmappedButtons.clear();
mUnmappedAxes.clear();
@@ -72,7 +72,7 @@ public class GamepadMappingsTest {
@Test
@Feature({"Gamepad"})
- public void testShieldGamepadMappings() throws Exception {
+ public void testShieldGamepadMappings() {
GamepadMappings mappings =
GamepadMappings.getMappings(GamepadMappings.NVIDIA_SHIELD_DEVICE_NAME_PREFIX);
mappings.mapToStandardGamepad(mMappedAxes, mMappedButtons, mRawAxes, mRawButtons);
@@ -82,7 +82,7 @@ public class GamepadMappingsTest {
@Test
@Feature({"Gamepad"})
- public void testXBox360GamepadMappings() throws Exception {
+ public void testXBox360GamepadMappings() {
GamepadMappings mappings =
GamepadMappings.getMappings(GamepadMappings.MICROSOFT_XBOX_PAD_DEVICE_NAME);
mappings.mapToStandardGamepad(mMappedAxes, mMappedButtons, mRawAxes, mRawButtons);
@@ -92,7 +92,7 @@ public class GamepadMappingsTest {
@Test
@Feature({"Gamepad"})
- public void testPS3SixAxisGamepadMappings() throws Exception {
+ public void testPS3SixAxisGamepadMappings() {
GamepadMappings mappings =
GamepadMappings.getMappings(GamepadMappings.PS3_SIXAXIS_DEVICE_NAME);
mappings.mapToStandardGamepad(mMappedAxes, mMappedButtons, mRawAxes, mRawButtons);
@@ -119,7 +119,7 @@ public class GamepadMappingsTest {
@Test
@Feature({"Gamepad"})
- public void testSamsungEIGP20GamepadMappings() throws Exception {
+ public void testSamsungEIGP20GamepadMappings() {
GamepadMappings mappings =
GamepadMappings.getMappings(GamepadMappings.SAMSUNG_EI_GP20_DEVICE_NAME);
mappings.mapToStandardGamepad(mMappedAxes, mMappedButtons, mRawAxes, mRawButtons);
@@ -138,7 +138,7 @@ public class GamepadMappingsTest {
@Test
@Feature({"Gamepad"})
- public void testAmazonFireGamepadMappings() throws Exception {
+ public void testAmazonFireGamepadMappings() {
GamepadMappings mappings =
GamepadMappings.getMappings(GamepadMappings.AMAZON_FIRE_DEVICE_NAME);
mappings.mapToStandardGamepad(mMappedAxes, mMappedButtons, mRawAxes, mRawButtons);
@@ -157,7 +157,7 @@ public class GamepadMappingsTest {
@Test
@Feature({"Gamepad"})
- public void testUnknownXBox360GamepadMappings() throws Exception {
+ public void testUnknownXBox360GamepadMappings() {
int[] axes = new int[] {
MotionEvent.AXIS_X,
MotionEvent.AXIS_Y,
@@ -186,7 +186,7 @@ public class GamepadMappingsTest {
@Test
@Feature({"Gamepad"})
- public void testUnknownMogaProGamepadMappings() throws Exception {
+ public void testUnknownMogaProGamepadMappings() {
int[] axes = new int[] {
MotionEvent.AXIS_X,
MotionEvent.AXIS_Y,
@@ -215,7 +215,7 @@ public class GamepadMappingsTest {
@Test
@Feature({"Gamepad"})
- public void testUnknownXiaomiGamepadMappings() throws Exception {
+ public void testUnknownXiaomiGamepadMappings() {
int[] axes = new int[] {
MotionEvent.AXIS_X,
MotionEvent.AXIS_Y,
@@ -244,7 +244,7 @@ public class GamepadMappingsTest {
@Test
@Feature({"Gamepad"})
- public void testUnknownGpdXdGamepadMappings() throws Exception {
+ public void testUnknownGpdXdGamepadMappings() {
int[] axes = new int[] {
MotionEvent.AXIS_X,
MotionEvent.AXIS_Y,
@@ -270,7 +270,7 @@ public class GamepadMappingsTest {
@Test
@Ignore("https://crbug.com/719765")
@Feature({"Gamepad"})
- public void testPS4GamepadMappings() throws Exception {
+ public void testPS4GamepadMappings() {
GamepadMappings mappings =
GamepadMappings.getMappings(GamepadMappings.PS_DUALSHOCK_4_PRODUCT_ID,
GamepadMappings.PS_DUALSHOCK_4_VENDOR_ID);
@@ -306,7 +306,7 @@ public class GamepadMappingsTest {
@Test
@Feature({"Gamepad"})
- public void testXboxOneSBluetooth2016FirmwareMappings() throws Exception {
+ public void testXboxOneSBluetooth2016FirmwareMappings() {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
GamepadMappings mappings =
GamepadMappings.getMappings(GamepadMappings.XBOX_ONE_S_2016_FIRMWARE_PRODUCT_ID,
@@ -356,7 +356,7 @@ public class GamepadMappingsTest {
@Test
@Feature({"Gamepad"})
- public void testXboxOneSBluetoothUsesDefaultMappings() throws Exception {
+ public void testXboxOneSBluetoothUsesDefaultMappings() {
// Test that Xbox One S gamepads with updated firmware connected over Bluetooth use the
// default mapping.
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
diff --git a/chromium/device/gamepad/gamepad_data_fetcher.cc b/chromium/device/gamepad/gamepad_data_fetcher.cc
index a33216dfad0..8c64640164e 100644
--- a/chromium/device/gamepad/gamepad_data_fetcher.cc
+++ b/chromium/device/gamepad/gamepad_data_fetcher.cc
@@ -19,14 +19,17 @@ void RunCallbackOnCallbackThread(
}
} // namespace
-GamepadDataFetcher::GamepadDataFetcher() : provider_(nullptr) {}
+GamepadDataFetcher::GamepadDataFetcher() = default;
GamepadDataFetcher::~GamepadDataFetcher() = default;
-void GamepadDataFetcher::InitializeProvider(GamepadPadStateProvider* provider) {
+void GamepadDataFetcher::InitializeProvider(
+ GamepadPadStateProvider* provider,
+ service_manager::Connector* service_manager_connector) {
DCHECK(provider);
provider_ = provider;
+ service_manager_connector_ = service_manager_connector;
OnAddedToProvider();
}
@@ -48,6 +51,10 @@ void GamepadDataFetcher::ResetVibration(
mojom::GamepadHapticsResult::GamepadHapticsResultError);
}
+bool GamepadDataFetcher::DisconnectUnrecognizedGamepad(int source_id) {
+ return false;
+}
+
// static
int64_t GamepadDataFetcher::TimeInMicroseconds(base::TimeTicks update_time) {
return update_time.since_origin().InMicroseconds();
diff --git a/chromium/device/gamepad/gamepad_data_fetcher.h b/chromium/device/gamepad/gamepad_data_fetcher.h
index 500e9cdd3b8..bb062002349 100644
--- a/chromium/device/gamepad/gamepad_data_fetcher.h
+++ b/chromium/device/gamepad/gamepad_data_fetcher.h
@@ -12,9 +12,13 @@
#include "device/gamepad/public/cpp/gamepad.h"
#include "device/gamepad/public/mojom/gamepad.mojom.h"
+namespace service_manager {
+class Connector;
+} // namespace service_manager
+
namespace device {
-// Abstract interface for imlementing platform- (and test-) specific behavior
+// Abstract interface for implementing platform- (and test-) specific behavior
// for getting the gamepad data.
class DEVICE_GAMEPAD_EXPORT GamepadDataFetcher {
public:
@@ -34,13 +38,24 @@ class DEVICE_GAMEPAD_EXPORT GamepadDataFetcher {
scoped_refptr<base::SequencedTaskRunner>);
virtual GamepadSource source() = 0;
+
+ // Shuts down the gamepad with given |source_id| and removes it from the data
+ // fetchers list of devices. Default implementation used on data fetchers for
+ // recognized gamepads because it should never be called on those gamepads.
+ // Returns a boolean that is true if the gamepad was successfully
+ // disconnected.
+ virtual bool DisconnectUnrecognizedGamepad(int source_id);
+
GamepadPadStateProvider* provider() { return provider_; }
+ service_manager::Connector* connector() const {
+ return service_manager_connector_;
+ }
- PadState* GetPadState(int source_id) {
+ PadState* GetPadState(int source_id, bool new_pad_recognized = true) {
if (!provider_)
return nullptr;
- return provider_->GetPadState(source(), source_id);
+ return provider_->GetPadState(source(), source_id, new_pad_recognized);
}
// Returns the current time value in microseconds. Data fetchers should use
@@ -69,7 +84,9 @@ class DEVICE_GAMEPAD_EXPORT GamepadDataFetcher {
friend GamepadPadStateProvider;
// To be called by the GamepadPadStateProvider on the polling thread;
- void InitializeProvider(GamepadPadStateProvider* provider);
+ void InitializeProvider(
+ GamepadPadStateProvider* provider,
+ service_manager::Connector* service_manager_connector);
// This call will happen on the gamepad polling thread. Any initialization
// that needs to happen on that thread should be done here, not in the
@@ -77,7 +94,13 @@ class DEVICE_GAMEPAD_EXPORT GamepadDataFetcher {
virtual void OnAddedToProvider() {}
private:
- GamepadPadStateProvider* provider_;
+ // GamepadPadStateProvider is the base class of GamepadProvider, which owns
+ // this data fetcher.
+ GamepadPadStateProvider* provider_ = nullptr;
+
+ // The service manager connector is owned by the provider, which destroys the
+ // data fetcher prior to destroying the connector.
+ service_manager::Connector* service_manager_connector_ = nullptr;
};
// Factory class for creating a GamepadDataFetcher. Used by the
diff --git a/chromium/device/gamepad/gamepad_haptics_manager.cc b/chromium/device/gamepad/gamepad_haptics_manager.cc
index 8171275c221..abdbc4e8108 100644
--- a/chromium/device/gamepad/gamepad_haptics_manager.cc
+++ b/chromium/device/gamepad/gamepad_haptics_manager.cc
@@ -8,7 +8,7 @@
#include "base/memory/ptr_util.h"
#include "device/gamepad/gamepad_service.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
namespace device {
@@ -18,9 +18,9 @@ GamepadHapticsManager::~GamepadHapticsManager() = default;
// static
void GamepadHapticsManager::Create(
- mojom::GamepadHapticsManagerRequest request) {
- mojo::MakeStrongBinding(std::make_unique<GamepadHapticsManager>(),
- std::move(request));
+ mojo::PendingReceiver<mojom::GamepadHapticsManager> receiver) {
+ mojo::MakeSelfOwnedReceiver(std::make_unique<GamepadHapticsManager>(),
+ std::move(receiver));
}
void GamepadHapticsManager::PlayVibrationEffectOnce(
diff --git a/chromium/device/gamepad/gamepad_haptics_manager.h b/chromium/device/gamepad/gamepad_haptics_manager.h
index a95d65691d2..7e7d8e30735 100644
--- a/chromium/device/gamepad/gamepad_haptics_manager.h
+++ b/chromium/device/gamepad/gamepad_haptics_manager.h
@@ -17,7 +17,8 @@ class DEVICE_GAMEPAD_EXPORT GamepadHapticsManager
GamepadHapticsManager();
~GamepadHapticsManager() override;
- static void Create(mojom::GamepadHapticsManagerRequest request);
+ static void Create(
+ mojo::PendingReceiver<mojom::GamepadHapticsManager> receiver);
// mojom::GamepadHapticsManager implementation.
void PlayVibrationEffectOnce(uint32_t pad_index,
diff --git a/chromium/device/gamepad/gamepad_monitor.cc b/chromium/device/gamepad/gamepad_monitor.cc
index 00222ec0d41..a4e24a81fdf 100644
--- a/chromium/device/gamepad/gamepad_monitor.cc
+++ b/chromium/device/gamepad/gamepad_monitor.cc
@@ -15,17 +15,18 @@
namespace device {
-GamepadMonitor::GamepadMonitor() : is_started_(false) {}
+GamepadMonitor::GamepadMonitor() = default;
GamepadMonitor::~GamepadMonitor() {
- if (is_started_)
+ if (is_registered_consumer_)
GamepadService::GetInstance()->RemoveConsumer(this);
}
// static
-void GamepadMonitor::Create(mojom::GamepadMonitorRequest request) {
- mojo::MakeStrongBinding(std::make_unique<GamepadMonitor>(),
- std::move(request));
+void GamepadMonitor::Create(
+ mojo::PendingReceiver<mojom::GamepadMonitor> receiver) {
+ mojo::MakeSelfOwnedReceiver(std::make_unique<GamepadMonitor>(),
+ std::move(receiver));
}
void GamepadMonitor::OnGamepadConnected(uint32_t index,
@@ -49,6 +50,7 @@ void GamepadMonitor::OnGamepadButtonOrAxisChanged(uint32_t index,
void GamepadMonitor::GamepadStartPolling(GamepadStartPollingCallback callback) {
DCHECK(!is_started_);
is_started_ = true;
+ is_registered_consumer_ = true;
GamepadService* service = GamepadService::GetInstance();
if (!service->ConsumerBecameActive(this)) {
diff --git a/chromium/device/gamepad/gamepad_monitor.h b/chromium/device/gamepad/gamepad_monitor.h
index ce597e25872..9092f8c258c 100644
--- a/chromium/device/gamepad/gamepad_monitor.h
+++ b/chromium/device/gamepad/gamepad_monitor.h
@@ -10,6 +10,7 @@
#include "device/gamepad/gamepad_consumer.h"
#include "device/gamepad/gamepad_export.h"
#include "device/gamepad/public/mojom/gamepad.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace device {
@@ -20,7 +21,7 @@ class DEVICE_GAMEPAD_EXPORT GamepadMonitor : public GamepadConsumer,
GamepadMonitor();
~GamepadMonitor() override;
- static void Create(mojom::GamepadMonitorRequest request);
+ static void Create(mojo::PendingReceiver<mojom::GamepadMonitor> receiver);
// GamepadConsumer implementation.
void OnGamepadConnected(uint32_t index, const Gamepad& gamepad) override;
@@ -36,7 +37,12 @@ class DEVICE_GAMEPAD_EXPORT GamepadMonitor : public GamepadConsumer,
private:
mojo::Remote<mojom::GamepadObserver> gamepad_observer_remote_;
- bool is_started_;
+
+ // True if this monitor is an active gamepad consumer.
+ bool is_started_ = false;
+
+ // True if this monitor has been registered with the gamepad service.
+ bool is_registered_consumer_ = false;
DISALLOW_COPY_AND_ASSIGN(GamepadMonitor);
};
diff --git a/chromium/device/gamepad/gamepad_pad_state_provider.cc b/chromium/device/gamepad/gamepad_pad_state_provider.cc
index 11f1f37e4bd..fcebacae728 100644
--- a/chromium/device/gamepad/gamepad_pad_state_provider.cc
+++ b/chromium/device/gamepad/gamepad_pad_state_provider.cc
@@ -17,6 +17,9 @@ const float kMinAxisResetValue = 0.1f;
} // namespace
+PadState::PadState() = default;
+PadState::~PadState() = default;
+
GamepadPadStateProvider::GamepadPadStateProvider() {
pad_states_.reset(new PadState[Gamepads::kItemsLengthCap]);
@@ -27,9 +30,11 @@ GamepadPadStateProvider::GamepadPadStateProvider() {
GamepadPadStateProvider::~GamepadPadStateProvider() = default;
PadState* GamepadPadStateProvider::GetPadState(GamepadSource source,
- int source_id) {
+ int source_id,
+ bool new_gamepad_recognized) {
// Check to see if the device already has a reserved slot
PadState* empty_slot = nullptr;
+ PadState* unrecognized_slot = nullptr;
for (size_t i = 0; i < Gamepads::kItemsLengthCap; ++i) {
PadState& state = pad_states_.get()[i];
if (state.source == source && state.source_id == source_id) {
@@ -39,6 +44,14 @@ PadState* GamepadPadStateProvider::GetPadState(GamepadSource source,
}
if (!empty_slot && state.source == GAMEPAD_SOURCE_NONE)
empty_slot = &state;
+ if (!state.is_recognized)
+ unrecognized_slot = &state;
+ }
+
+ if (!empty_slot && unrecognized_slot && new_gamepad_recognized) {
+ DisconnectUnrecognizedGamepad(unrecognized_slot->source,
+ unrecognized_slot->source_id);
+ empty_slot = unrecognized_slot;
}
if (empty_slot) {
empty_slot->source = source;
@@ -46,6 +59,7 @@ PadState* GamepadPadStateProvider::GetPadState(GamepadSource source,
empty_slot->is_active = true;
empty_slot->is_newly_active = true;
empty_slot->is_initialized = false;
+ empty_slot->is_recognized = new_gamepad_recognized;
}
return empty_slot;
}
@@ -66,8 +80,9 @@ void GamepadPadStateProvider::ClearPadState(PadState& state) {
}
void GamepadPadStateProvider::InitializeDataFetcher(
- GamepadDataFetcher* fetcher) {
- fetcher->InitializeProvider(this);
+ GamepadDataFetcher* fetcher,
+ service_manager::Connector* service_manager_connector) {
+ fetcher->InitializeProvider(this, service_manager_connector);
}
void GamepadPadStateProvider::MapAndSanitizeGamepadData(PadState* pad_state,
diff --git a/chromium/device/gamepad/gamepad_pad_state_provider.h b/chromium/device/gamepad/gamepad_pad_state_provider.h
index 621072cbda0..2ab4848b423 100644
--- a/chromium/device/gamepad/gamepad_pad_state_provider.h
+++ b/chromium/device/gamepad/gamepad_pad_state_provider.h
@@ -14,6 +14,10 @@
#include "device/gamepad/gamepad_standard_mappings.h"
#include "device/gamepad/public/cpp/gamepad.h"
+namespace service_manager {
+class Connector;
+} // namespace service_manager
+
namespace device {
class GamepadDataFetcher;
@@ -42,6 +46,9 @@ enum GamepadSource {
};
struct PadState {
+ PadState();
+ ~PadState();
+
// Which data fetcher provided this gamepad's data.
GamepadSource source;
// Data fetcher-specific identifier for this gamepad.
@@ -60,6 +67,11 @@ struct PadState {
// gamepad has been completed.
bool is_initialized;
+ // Set by the data fetcher to indicate whether this gamepad's ids are
+ // recognized as a specific gamepad. It is then used to prioritize recognized
+ // gamepads when finding an empty slot for any new gamepads when activated.
+ bool is_recognized;
+
// Gamepad data, unmapped.
Gamepad data;
@@ -92,8 +104,12 @@ class DEVICE_GAMEPAD_EXPORT GamepadPadStateProvider {
// Gets a PadState object for the given source and id. If the device hasn't
// been encountered before one of the remaining slots will be reserved for it.
- // If no slots are available will return NULL.
- PadState* GetPadState(GamepadSource source, int source_id);
+ // If no slots are available this returns nullptr. However, if one of those
+ // slots contains an unrecognized gamepad and |new_gamepad_recognized| is true
+ // that slot will be reset and returned.
+ PadState* GetPadState(GamepadSource source,
+ int source_id,
+ bool new_gamepad_recognized);
// Gets a PadState object for a connected gamepad by specifying its index in
// the pad_states_ array. Returns NULL if there is no connected gamepad at
@@ -103,7 +119,9 @@ class DEVICE_GAMEPAD_EXPORT GamepadPadStateProvider {
protected:
void ClearPadState(PadState& state);
- void InitializeDataFetcher(GamepadDataFetcher* fetcher);
+ void InitializeDataFetcher(
+ GamepadDataFetcher* fetcher,
+ service_manager::Connector* service_manager_connector);
void MapAndSanitizeGamepadData(PadState* pad_state,
Gamepad* pad,
@@ -111,6 +129,13 @@ class DEVICE_GAMEPAD_EXPORT GamepadPadStateProvider {
// Tracks the state of each gamepad slot.
std::unique_ptr<PadState[]> pad_states_;
+
+ private:
+ // Calls the DisconnectUnrecognizedGamepad method on the data fetcher
+ // associated with the given |source|. The actual implementation is always
+ // in the |gamepad_provider|.
+ virtual void DisconnectUnrecognizedGamepad(GamepadSource source,
+ int source_id) = 0;
};
} // namespace device
diff --git a/chromium/device/gamepad/gamepad_platform_data_fetcher_linux.cc b/chromium/device/gamepad/gamepad_platform_data_fetcher_linux.cc
index 64239e65e93..f0246cf5814 100644
--- a/chromium/device/gamepad/gamepad_platform_data_fetcher_linux.cc
+++ b/chromium/device/gamepad/gamepad_platform_data_fetcher_linux.cc
@@ -106,7 +106,7 @@ void GamepadPlatformDataFetcherLinux::RefreshDevice(udev_device* dev) {
if (pad_info.type == UdevGamepadLinux::Type::JOYDEV) {
// If |syspath_prefix| is empty, the device was already disconnected.
if (pad_info.syspath_prefix.empty())
- RemoveDeviceAtIndex(pad_info.index);
+ DisconnectUnrecognizedGamepad(pad_info.index);
else
RefreshJoydevDevice(dev, pad_info);
} else if (pad_info.type == UdevGamepadLinux::Type::EVDEV) {
@@ -138,15 +138,16 @@ void GamepadPlatformDataFetcherLinux::RemoveDevice(GamepadDeviceLinux* device) {
}
}
-void GamepadPlatformDataFetcherLinux::RemoveDeviceAtIndex(int index) {
+bool GamepadPlatformDataFetcherLinux::DisconnectUnrecognizedGamepad(int index) {
for (auto it = devices_.begin(); it != devices_.end(); ++it) {
const auto& device = *it;
if (device->GetJoydevIndex() == index) {
device->Shutdown();
devices_.erase(it);
- return;
+ return true;
}
}
+ return false;
}
GamepadDeviceLinux* GamepadPlatformDataFetcherLinux::GetOrCreateMatchingDevice(
@@ -195,7 +196,10 @@ void GamepadPlatformDataFetcherLinux::RefreshJoydevDevice(
return;
}
- PadState* state = GetPadState(joydev_index);
+ bool is_recognized = GamepadIdList::Get().GetGamepadId(
+ vendor_id, product_id) != GamepadId::kUnknownGamepad;
+
+ PadState* state = GetPadState(joydev_index, is_recognized);
if (!state) {
// No slot available for device, don't use.
device->CloseJoydevNode();
@@ -217,12 +221,10 @@ void GamepadPlatformDataFetcherLinux::RefreshJoydevDevice(
return;
}
- // Joydev uses its own internal list of device IDs to identify known gamepads.
// If the device is on our list, record it by ID. If the device is unknown,
// record that an unknown gamepad was enumerated.
- GamepadId gamepad_id =
- GamepadIdList::Get().GetGamepadId(vendor_id, product_id);
- if (gamepad_id == GamepadId::kUnknownGamepad)
+
+ if (is_recognized)
RecordUnknownGamepad(source());
else
RecordConnectedGamepad(vendor_id, product_id);
diff --git a/chromium/device/gamepad/gamepad_platform_data_fetcher_linux.h b/chromium/device/gamepad/gamepad_platform_data_fetcher_linux.h
index 8d88425ca81..78df7a12c63 100644
--- a/chromium/device/gamepad/gamepad_platform_data_fetcher_linux.h
+++ b/chromium/device/gamepad/gamepad_platform_data_fetcher_linux.h
@@ -48,6 +48,7 @@ class DEVICE_GAMEPAD_EXPORT GamepadPlatformDataFetcherLinux
// GamepadDataFetcher implementation.
void GetGamepadData(bool devices_changed_hint) override;
+ bool DisconnectUnrecognizedGamepad(int source_id) override;
void PlayEffect(int pad_index,
mojom::GamepadHapticEffectType,
@@ -75,7 +76,6 @@ class DEVICE_GAMEPAD_EXPORT GamepadPlatformDataFetcherLinux
GamepadDeviceLinux* GetOrCreateMatchingDevice(
const UdevGamepadLinux& pad_info);
void RemoveDevice(GamepadDeviceLinux* device);
- void RemoveDeviceAtIndex(int index);
// UdevWatcher::Observer overrides
void OnDeviceAdded(ScopedUdevDevicePtr device) override;
diff --git a/chromium/device/gamepad/gamepad_platform_data_fetcher_mac.h b/chromium/device/gamepad/gamepad_platform_data_fetcher_mac.h
index df9df56c105..67b6c12ea24 100644
--- a/chromium/device/gamepad/gamepad_platform_data_fetcher_mac.h
+++ b/chromium/device/gamepad/gamepad_platform_data_fetcher_mac.h
@@ -66,18 +66,9 @@ class GamepadPlatformDataFetcherMac : public GamepadDataFetcher {
// GamepadDataFetcher private implementation.
void OnAddedToProvider() override;
- // Returns the index of the first empty slot, or Gamepads::kItemsLengthCap if
- // there are no empty slots.
- size_t GetEmptySlot();
-
- // Returns the index of the slot allocated for this device, or the first empty
- // slot if none is yet allocated. If there is no allocated or empty slots,
- // returns Gamepads::kItemsLengthCap.
- size_t GetSlotForDevice(IOHIDDeviceRef device);
-
- // Returns the index of the slot allocated for the device with the specified
- // |location_id|, or Gamepads::kItemsLengthCap if none is yet allocated.
- size_t GetSlotForLocation(int location_id);
+ // Returns the GamepadDeviceMac from |devices_| that has the given device
+ // reference. Returns nullptr if the device is not in |devices_|.
+ GamepadDeviceMac* GetGamepadFromHidDevice(IOHIDDeviceRef device);
// Query device info for |device| and add it to |devices_| if it is a
// gamepad.
@@ -96,11 +87,14 @@ class GamepadPlatformDataFetcherMac : public GamepadDataFetcher {
// Unregister from connection events and value change notifications.
void UnregisterFromNotifications();
+ bool DisconnectUnrecognizedGamepad(int source_id) override;
+
bool enabled_ = false;
bool paused_ = false;
base::ScopedCFTypeRef<IOHIDManagerRef> hid_manager_ref_;
- std::unique_ptr<GamepadDeviceMac> devices_[Gamepads::kItemsLengthCap];
+ // A map of all devices using this data fetcher with the source_id as the key.
+ std::unordered_map<int, std::unique_ptr<GamepadDeviceMac>> devices_;
DISALLOW_COPY_AND_ASSIGN(GamepadPlatformDataFetcherMac);
};
diff --git a/chromium/device/gamepad/gamepad_platform_data_fetcher_mac.mm b/chromium/device/gamepad/gamepad_platform_data_fetcher_mac.mm
index 391419fc9c0..4475b7e21ca 100644
--- a/chromium/device/gamepad/gamepad_platform_data_fetcher_mac.mm
+++ b/chromium/device/gamepad/gamepad_platform_data_fetcher_mac.mm
@@ -102,9 +102,8 @@ void GamepadPlatformDataFetcherMac::PauseHint(bool pause) {
GamepadPlatformDataFetcherMac::~GamepadPlatformDataFetcherMac() {
UnregisterFromNotifications();
- for (size_t slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) {
- if (devices_[slot] != nullptr)
- devices_[slot]->Shutdown();
+ for (auto& iter : devices_) {
+ iter.second->Shutdown();
}
}
@@ -134,31 +133,15 @@ void GamepadPlatformDataFetcherMac::ValueChangedCallback(void* context,
InstanceFromContext(context)->ValueChanged(ref);
}
-size_t GamepadPlatformDataFetcherMac::GetEmptySlot() {
- // Find a free slot for this device.
- for (size_t slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) {
- if (devices_[slot] == nullptr)
- return slot;
+GamepadDeviceMac* GamepadPlatformDataFetcherMac::GetGamepadFromHidDevice(
+ IOHIDDeviceRef device) {
+ for (auto& iter : devices_) {
+ if (iter.second->IsSameDevice(device)) {
+ return iter.second.get();
+ }
}
- return Gamepads::kItemsLengthCap;
-}
-size_t GamepadPlatformDataFetcherMac::GetSlotForDevice(IOHIDDeviceRef device) {
- for (size_t slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) {
- // If we already have this device, and it's already connected, don't do
- // anything now.
- if (devices_[slot] != nullptr && devices_[slot]->IsSameDevice(device))
- return Gamepads::kItemsLengthCap;
- }
- return GetEmptySlot();
-}
-
-size_t GamepadPlatformDataFetcherMac::GetSlotForLocation(int location_id) {
- for (size_t slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) {
- if (devices_[slot] && devices_[slot]->GetLocationId() == location_id)
- return slot;
- }
- return Gamepads::kItemsLengthCap;
+ return nullptr;
}
void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) {
@@ -172,9 +155,6 @@ void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) {
IOHIDDeviceGetProperty(device, CFSTR(kIOHIDLocationIDKey))));
int location_int = [location_id intValue];
- // Find an index for this device.
- size_t slot = GetSlotForDevice(device);
-
NSNumber* vendor_id = CFToNSCast(CFCastStrict<CFNumberRef>(
IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey))));
NSNumber* product_id = CFToNSCast(CFCastStrict<CFNumberRef>(
@@ -201,21 +181,23 @@ void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) {
const auto& gamepad_id_list = GamepadIdList::Get();
DCHECK_EQ(kXInputTypeNone,
gamepad_id_list.GetXInputType(vendor_int, product_int));
- RecordConnectedGamepad(vendor_int, product_int);
- // We can't handle this many connected devices.
- if (slot == Gamepads::kItemsLengthCap)
+ if (devices_.find(location_int) != devices_.end())
return;
+ RecordConnectedGamepad(vendor_int, product_int);
+
// The SteelSeries Nimbus and other Made for iOS gamepads should be handled
- // through the GameController interface. Blacklist it here so it doesn't
- // take up an additional gamepad slot.
+ // through the GameController interface.
if (gamepad_id_list.GetGamepadId(vendor_int, product_int) ==
GamepadId::kSteelSeriesProduct1420) {
return;
}
- PadState* state = GetPadState(location_int);
+ bool is_recognized = gamepad_id_list.GetGamepadId(vendor_int, product_int) !=
+ GamepadId::kUnknownGamepad;
+
+ PadState* state = GetPadState(location_int, is_recognized);
if (!state)
return; // No available slot for this device
@@ -232,34 +214,42 @@ void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) {
state->data.mapping =
state->mapper ? GamepadMapping::kStandard : GamepadMapping::kNone;
- devices_[slot] = std::make_unique<GamepadDeviceMac>(location_int, device,
- vendor_int, product_int);
- if (!devices_[slot]->AddButtonsAndAxes(&state->data)) {
- devices_[slot]->Shutdown();
- devices_[slot] = nullptr;
+ auto new_device = std::make_unique<GamepadDeviceMac>(location_int, device,
+ vendor_int, product_int);
+ if (!new_device->AddButtonsAndAxes(&state->data)) {
+ new_device->Shutdown();
return;
}
state->data.vibration_actuator.type = GamepadHapticActuatorType::kDualRumble;
- state->data.vibration_actuator.not_null = devices_[slot]->SupportsVibration();
+ state->data.vibration_actuator.not_null = new_device->SupportsVibration();
state->data.connected = true;
+
+ devices_.emplace(location_int, std::move(new_device));
+}
+
+bool GamepadPlatformDataFetcherMac::DisconnectUnrecognizedGamepad(
+ int source_id) {
+ auto gamepad_iter = devices_.find(source_id);
+ if (gamepad_iter == devices_.end())
+ return false;
+ gamepad_iter->second->Shutdown();
+ devices_.erase(gamepad_iter);
+ return true;
}
void GamepadPlatformDataFetcherMac::DeviceRemove(IOHIDDeviceRef device) {
if (!enabled_)
return;
- // Find the index for this device.
- size_t slot;
- for (slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) {
- if (devices_[slot] != nullptr && devices_[slot]->IsSameDevice(device))
- break;
- }
- if (slot < Gamepads::kItemsLengthCap) {
- devices_[slot]->Shutdown();
- devices_[slot] = nullptr;
- }
+ GamepadDeviceMac* gamepad_device = GetGamepadFromHidDevice(device);
+
+ if (!gamepad_device)
+ return;
+
+ gamepad_device->Shutdown();
+ devices_.erase(gamepad_device->GetLocationId());
}
void GamepadPlatformDataFetcherMac::ValueChanged(IOHIDValueRef value) {
@@ -269,20 +259,16 @@ void GamepadPlatformDataFetcherMac::ValueChanged(IOHIDValueRef value) {
IOHIDElementRef element = IOHIDValueGetElement(value);
IOHIDDeviceRef device = IOHIDElementGetDevice(element);
- // Find device slot.
- size_t slot;
- for (slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) {
- if (devices_[slot] != nullptr && devices_[slot]->IsSameDevice(device))
- break;
- }
- if (slot == Gamepads::kItemsLengthCap)
+ GamepadDeviceMac* gamepad_device = GetGamepadFromHidDevice(device);
+
+ if (!gamepad_device)
return;
- PadState* state = GetPadState(devices_[slot]->GetLocationId());
+ PadState* state = GetPadState(gamepad_device->GetLocationId());
if (!state)
return;
- devices_[slot]->UpdateGamepadForValue(value, &state->data);
+ gamepad_device->UpdateGamepadForValue(value, &state->data);
}
void GamepadPlatformDataFetcherMac::GetGamepadData(bool) {
@@ -290,9 +276,8 @@ void GamepadPlatformDataFetcherMac::GetGamepadData(bool) {
return;
// Loop through and GetPadState to indicate the devices are still connected.
- for (size_t slot = 0; slot < Gamepads::kItemsLengthCap; ++slot) {
- if (devices_[slot])
- GetPadState(devices_[slot]->GetLocationId());
+ for (const auto& iter : devices_) {
+ GetPadState(iter.first);
}
}
@@ -302,8 +287,8 @@ void GamepadPlatformDataFetcherMac::PlayEffect(
mojom::GamepadEffectParametersPtr params,
mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback callback,
scoped_refptr<base::SequencedTaskRunner> callback_runner) {
- size_t slot = GetSlotForLocation(source_id);
- if (slot == Gamepads::kItemsLengthCap) {
+ auto device_iter = devices_.find(source_id);
+ if (device_iter == devices_.end()) {
// No connected gamepad with this location. Probably the effect was issued
// while the gamepad was still connected, so handle this as if it were
// preempted by a disconnect.
@@ -312,16 +297,16 @@ void GamepadPlatformDataFetcherMac::PlayEffect(
mojom::GamepadHapticsResult::GamepadHapticsResultPreempted);
return;
}
- devices_[slot]->PlayEffect(type, std::move(params), std::move(callback),
- std::move(callback_runner));
+ device_iter->second->PlayEffect(type, std::move(params), std::move(callback),
+ std::move(callback_runner));
}
void GamepadPlatformDataFetcherMac::ResetVibration(
int source_id,
mojom::GamepadHapticsManager::ResetVibrationActuatorCallback callback,
scoped_refptr<base::SequencedTaskRunner> callback_runner) {
- size_t slot = GetSlotForLocation(source_id);
- if (slot == Gamepads::kItemsLengthCap) {
+ auto device_iter = devices_.find(source_id);
+ if (device_iter == devices_.end()) {
// No connected gamepad with this location. Since the gamepad is already
// disconnected, allow the reset to report success.
RunVibrationCallback(
@@ -329,8 +314,8 @@ void GamepadPlatformDataFetcherMac::ResetVibration(
mojom::GamepadHapticsResult::GamepadHapticsResultComplete);
return;
}
- devices_[slot]->ResetVibration(std::move(callback),
- std::move(callback_runner));
+ device_iter->second->ResetVibration(std::move(callback),
+ std::move(callback_runner));
}
} // namespace device
diff --git a/chromium/device/gamepad/gamepad_platform_data_fetcher_win.cc b/chromium/device/gamepad/gamepad_platform_data_fetcher_win.cc
index e475eb14003..1367ea1f3da 100644
--- a/chromium/device/gamepad/gamepad_platform_data_fetcher_win.cc
+++ b/chromium/device/gamepad/gamepad_platform_data_fetcher_win.cc
@@ -171,7 +171,7 @@ void GamepadPlatformDataFetcherWin::GetGamepadData(bool devices_changed_hint) {
}
void GamepadPlatformDataFetcherWin::GetXInputPadData(int i) {
- PadState* pad_state = provider()->GetPadState(GAMEPAD_SOURCE_WIN_XINPUT, i);
+ PadState* pad_state = GetPadState(i);
if (!pad_state)
return;
diff --git a/chromium/device/gamepad/gamepad_provider.cc b/chromium/device/gamepad/gamepad_provider.cc
index 2e082543b17..ea301b8a91a 100644
--- a/chromium/device/gamepad/gamepad_provider.cc
+++ b/chromium/device/gamepad/gamepad_provider.cc
@@ -26,6 +26,7 @@
#include "device/gamepad/gamepad_user_gesture.h"
#include "device/gamepad/public/cpp/gamepad_features.h"
#include "mojo/public/cpp/system/platform_handle.h"
+#include "services/service_manager/public/cpp/connector.h"
namespace device {
@@ -40,29 +41,23 @@ GamepadProvider::ClosureAndThread::ClosureAndThread(
GamepadProvider::ClosureAndThread::~ClosureAndThread() = default;
GamepadProvider::GamepadProvider(
- GamepadConnectionChangeClient* connection_change_client)
- : is_paused_(true),
- have_scheduled_do_poll_(false),
- devices_changed_(true),
- ever_had_user_gesture_(false),
- sanitize_(true),
- gamepad_shared_buffer_(std::make_unique<GamepadSharedBuffer>()),
- connection_change_client_(connection_change_client) {
+ GamepadConnectionChangeClient* connection_change_client,
+ std::unique_ptr<service_manager::Connector> service_manager_connector)
+ : gamepad_shared_buffer_(std::make_unique<GamepadSharedBuffer>()),
+ connection_change_client_(connection_change_client),
+ service_manager_connector_(std::move(service_manager_connector)) {
Initialize(std::unique_ptr<GamepadDataFetcher>());
}
GamepadProvider::GamepadProvider(
GamepadConnectionChangeClient* connection_change_client,
+ std::unique_ptr<service_manager::Connector> service_manager_connector,
std::unique_ptr<GamepadDataFetcher> fetcher,
std::unique_ptr<base::Thread> polling_thread)
- : is_paused_(true),
- have_scheduled_do_poll_(false),
- devices_changed_(true),
- ever_had_user_gesture_(false),
- sanitize_(true),
- gamepad_shared_buffer_(std::make_unique<GamepadSharedBuffer>()),
+ : gamepad_shared_buffer_(std::make_unique<GamepadSharedBuffer>()),
polling_thread_(std::move(polling_thread)),
- connection_change_client_(connection_change_client) {
+ connection_change_client_(connection_change_client),
+ service_manager_connector_(std::move(service_manager_connector)) {
Initialize(std::move(fetcher));
}
@@ -80,6 +75,11 @@ GamepadProvider::~GamepadProvider() {
FROM_HERE, base::BindOnce(&GamepadFetcherVector::clear,
base::Unretained(&data_fetchers_)));
+ // The service manager connector is bound to the polling thread and must be
+ // destroyed on that thread.
+ polling_thread_->task_runner()->DeleteSoon(
+ FROM_HERE, std::move(service_manager_connector_));
+
// Use Stop() to join the polling thread, as there may be pending callbacks
// which dereference |polling_thread_|.
polling_thread_->Stop();
@@ -274,7 +274,7 @@ void GamepadProvider::DoAddGamepadDataFetcher(
if (!fetcher)
return;
- InitializeDataFetcher(fetcher.get());
+ InitializeDataFetcher(fetcher.get(), service_manager_connector_.get());
data_fetchers_.push_back(std::move(fetcher));
}
@@ -385,6 +385,17 @@ void GamepadProvider::DoPoll() {
ScheduleDoPoll();
}
+void GamepadProvider::DisconnectUnrecognizedGamepad(GamepadSource source,
+ int source_id) {
+ for (auto& fetcher : data_fetchers_) {
+ if (fetcher->source() == source) {
+ bool disconnected = fetcher->DisconnectUnrecognizedGamepad(source_id);
+ DCHECK(disconnected);
+ return;
+ }
+ }
+}
+
void GamepadProvider::ScheduleDoPoll() {
DCHECK(polling_thread_->task_runner()->BelongsToCurrentThread());
if (have_scheduled_do_poll_)
diff --git a/chromium/device/gamepad/gamepad_provider.h b/chromium/device/gamepad/gamepad_provider.h
index 2319efb1a52..c1c555bf9b3 100644
--- a/chromium/device/gamepad/gamepad_provider.h
+++ b/chromium/device/gamepad/gamepad_provider.h
@@ -26,7 +26,11 @@
namespace base {
class SingleThreadTaskRunner;
class Thread;
-}
+} // namespace base
+
+namespace service_manager {
+class Connector;
+} // namespace service_manager
namespace device {
@@ -43,14 +47,17 @@ class DEVICE_GAMEPAD_EXPORT GamepadProvider
: public GamepadPadStateProvider,
public base::SystemMonitor::DevicesChangedObserver {
public:
- explicit GamepadProvider(
- GamepadConnectionChangeClient* connection_change_client);
+ GamepadProvider(
+ GamepadConnectionChangeClient* connection_change_client,
+ std::unique_ptr<service_manager::Connector> service_manager_connector);
// Manually specifies the data fetcher and polling thread. The polling thread
// will be created normally if |polling_thread| is nullptr. Used for testing.
- GamepadProvider(GamepadConnectionChangeClient* connection_change_client,
- std::unique_ptr<GamepadDataFetcher> fetcher,
- std::unique_ptr<base::Thread> polling_thread);
+ GamepadProvider(
+ GamepadConnectionChangeClient* connection_change_client,
+ std::unique_ptr<service_manager::Connector> service_manager_connector,
+ std::unique_ptr<GamepadDataFetcher> fetcher,
+ std::unique_ptr<base::Thread> polling_thread);
~GamepadProvider() override;
@@ -115,6 +122,10 @@ class DEVICE_GAMEPAD_EXPORT GamepadProvider
// true if any user gesture observers were notified.
bool CheckForUserGesture();
+ // GamepadPadStateProvider implementation.
+ void DisconnectUnrecognizedGamepad(GamepadSource source,
+ int source_id) override;
+
void PlayEffectOnPollingThread(
uint32_t pad_index,
mojom::GamepadHapticEffectType,
@@ -133,12 +144,12 @@ class DEVICE_GAMEPAD_EXPORT GamepadProvider
// Keeps track of when the background thread is paused. Access to is_paused_
// must be guarded by is_paused_lock_.
base::Lock is_paused_lock_;
- bool is_paused_;
+ bool is_paused_ = true;
// Keep track of when a polling task is schedlued, so as to prevent us from
// accidentally scheduling more than one at any time, when rapidly toggling
// |is_paused_|.
- bool have_scheduled_do_poll_;
+ bool have_scheduled_do_poll_ = false;
// Lists all observers registered for user gestures, and the thread which
// to issue the callbacks on. Since we always issue the callback on the
@@ -164,10 +175,10 @@ class DEVICE_GAMEPAD_EXPORT GamepadProvider
// tests. Access to devices_changed_ must be guarded by
// devices_changed_lock_.
base::Lock devices_changed_lock_;
- bool devices_changed_;
+ bool devices_changed_ = true;
- bool ever_had_user_gesture_;
- bool sanitize_;
+ bool ever_had_user_gesture_ = false;
+ bool sanitize_ = true;
// Only used on the polling thread.
using GamepadFetcherVector = std::vector<std::unique_ptr<GamepadDataFetcher>>;
@@ -181,6 +192,10 @@ class DEVICE_GAMEPAD_EXPORT GamepadProvider
GamepadConnectionChangeClient* connection_change_client_;
+ // Service manager connector, to allow data fetchers to access the device
+ // service from the polling thread.
+ std::unique_ptr<service_manager::Connector> service_manager_connector_;
+
DISALLOW_COPY_AND_ASSIGN(GamepadProvider);
};
diff --git a/chromium/device/gamepad/gamepad_provider_unittest.cc b/chromium/device/gamepad/gamepad_provider_unittest.cc
index 2829c0e0cc7..2571b60a3e1 100644
--- a/chromium/device/gamepad/gamepad_provider_unittest.cc
+++ b/chromium/device/gamepad/gamepad_provider_unittest.cc
@@ -15,6 +15,7 @@
#include "build/build_config.h"
#include "device/gamepad/gamepad_data_fetcher.h"
#include "device/gamepad/gamepad_test_helpers.h"
+#include "services/service_manager/public/cpp/connector.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace device {
@@ -44,10 +45,12 @@ class UserGestureListener {
class GamepadProviderTest : public testing::Test, public GamepadTestHelper {
public:
GamepadProvider* CreateProvider(const Gamepads& test_data) {
- mock_data_fetcher_ = new MockGamepadDataFetcher(test_data);
- provider_.reset(new GamepadProvider(
- nullptr, std::unique_ptr<GamepadDataFetcher>(mock_data_fetcher_),
- std::unique_ptr<base::Thread>()));
+ auto fetcher = std::make_unique<MockGamepadDataFetcher>(test_data);
+ mock_data_fetcher_ = fetcher.get();
+ provider_ = std::make_unique<GamepadProvider>(
+ /*connection_change_client=*/nullptr,
+ /*service_manager_connector=*/nullptr, std::move(fetcher),
+ /*polling_thread=*/nullptr);
return provider_.get();
}
diff --git a/chromium/device/gamepad/gamepad_service.cc b/chromium/device/gamepad/gamepad_service.cc
index 320a082bef8..d3998dc5b4f 100644
--- a/chromium/device/gamepad/gamepad_service.cc
+++ b/chromium/device/gamepad/gamepad_service.cc
@@ -22,36 +22,33 @@
namespace device {
namespace {
-GamepadService* g_gamepad_service = 0;
-}
+GamepadService* g_gamepad_service = nullptr;
+} // namespace
GamepadService::GamepadService()
- : main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
- num_active_consumers_(0),
- gesture_callback_pending_(false) {
+ : main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
SetInstance(this);
}
-GamepadService::GamepadService(
- std::unique_ptr<device::GamepadDataFetcher> fetcher)
- : provider_(new device::GamepadProvider(this,
- std::move(fetcher),
- std::unique_ptr<base::Thread>())),
- main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
- num_active_consumers_(0),
- gesture_callback_pending_(false) {
+GamepadService::GamepadService(std::unique_ptr<GamepadDataFetcher> fetcher)
+ : provider_(std::make_unique<GamepadProvider>(
+ /*connection_change_client=*/this,
+ /*service_manager_connector=*/nullptr,
+ std::move(fetcher),
+ /*polling_thread=*/nullptr)),
+ main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
SetInstance(this);
}
-GamepadService::~GamepadService() {
- SetInstance(NULL);
-}
+GamepadService::~GamepadService() = default;
void GamepadService::SetInstance(GamepadService* instance) {
// Unit tests can create multiple instances but only one should exist at any
- // given time so g_gamepad_service should only go from NULL to non-NULL and
- // vica versa.
+ // given time so |g_gamepad_service| should only go from nullptr to
+ // non-nullptr and vice versa.
CHECK(!!instance != !!g_gamepad_service);
+ if (g_gamepad_service)
+ delete g_gamepad_service;
g_gamepad_service = instance;
}
@@ -72,15 +69,13 @@ void GamepadService::StartUp(
GamepadDataFetcherManager::GetInstance();
}
-service_manager::Connector* GamepadService::GetConnector() {
- return service_manager_connector_.get();
-}
-
bool GamepadService::ConsumerBecameActive(GamepadConsumer* consumer) {
DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
- if (!provider_)
- provider_.reset(new device::GamepadProvider(this));
+ if (!provider_) {
+ provider_ = std::make_unique<GamepadProvider>(
+ /*connection_change_client=*/this, service_manager_connector_->Clone());
+ }
std::pair<ConsumerSet::iterator, bool> insert_result =
consumers_.insert(consumer);
@@ -147,9 +142,9 @@ bool GamepadService::RemoveConsumer(GamepadConsumer* consumer) {
auto it = consumers_.find(consumer);
if (it == consumers_.end())
return false;
- DCHECK_GT(num_active_consumers_, 0);
if (it->is_active && --num_active_consumers_ == 0)
provider_->Pause();
+ DCHECK_GE(num_active_consumers_, 0);
consumers_.erase(it);
inactive_consumer_state_.erase(consumer);
return true;
diff --git a/chromium/device/gamepad/gamepad_service.h b/chromium/device/gamepad/gamepad_service.h
index fff121234cf..cbfe58184f3 100644
--- a/chromium/device/gamepad/gamepad_service.h
+++ b/chromium/device/gamepad/gamepad_service.h
@@ -19,17 +19,13 @@
#include "device/gamepad/gamepad_provider.h"
#include "device/gamepad/public/mojom/gamepad.mojom.h"
-namespace {
+namespace base {
class SingleThreadTaskRunner;
-}
-
-namespace content {
-class GamepadServiceTestConstructor;
-}
+} // namespace base
namespace service_manager {
class Connector;
-}
+} // namespace service_manager
namespace device {
class GamepadConsumer;
@@ -48,11 +44,12 @@ class DEVICE_GAMEPAD_EXPORT GamepadService
// Sets the GamepadService instance. Exposed for tests.
static void SetInstance(GamepadService*);
+ // Initializes the GamepadService. |service_manager_connector| will be
+ // passed to the GamepadProvider once it is created, to allow data fetchers
+ // to access the device service from the polling thread.
void StartUp(
std::unique_ptr<service_manager::Connector> service_manager_connector);
- service_manager::Connector* GetConnector();
-
// Increments the number of users of the provider. The Provider is running
// when there's > 0 users, and is paused when the count drops to 0.
// |consumer| is registered to listen for gamepad connections. If this is the
@@ -120,19 +117,18 @@ class DEVICE_GAMEPAD_EXPORT GamepadService
uint32_t pad_index,
mojom::GamepadHapticsManager::ResetVibrationActuatorCallback);
+ // Constructor for testing. This specifies the data fetcher to use for a
+ // provider, bypassing the default platform one.
+ GamepadService(std::unique_ptr<GamepadDataFetcher> fetcher);
+
+ virtual ~GamepadService();
+
private:
friend struct base::DefaultSingletonTraits<GamepadService>;
- friend class GamepadServiceTestConstructor;
friend class GamepadServiceTest;
GamepadService();
- // Constructor for testing. This specifies the data fetcher to use for a
- // provider, bypassing the default platform one.
- GamepadService(std::unique_ptr<device::GamepadDataFetcher> fetcher);
-
- virtual ~GamepadService();
-
void OnUserGesture();
void OnGamepadConnectionChange(bool connected,
@@ -153,7 +149,7 @@ class DEVICE_GAMEPAD_EXPORT GamepadService
mutable bool did_observe_user_gesture = false;
};
- std::unique_ptr<device::GamepadProvider> provider_;
+ std::unique_ptr<GamepadProvider> provider_;
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
@@ -165,10 +161,12 @@ class DEVICE_GAMEPAD_EXPORT GamepadService
ConsumerConnectedStateMap inactive_consumer_state_;
- int num_active_consumers_;
+ // The number of active consumers in |consumers_|.
+ int num_active_consumers_ = 0;
- bool gesture_callback_pending_;
+ bool gesture_callback_pending_ = false;
+ // Service manager connector. Must be used only on the main thread.
std::unique_ptr<service_manager::Connector> service_manager_connector_;
DISALLOW_COPY_AND_ASSIGN(GamepadService);
diff --git a/chromium/device/gamepad/gamepad_service_unittest.cc b/chromium/device/gamepad/gamepad_service_unittest.cc
index 9c0245d3d87..81602220d4a 100644
--- a/chromium/device/gamepad/gamepad_service_unittest.cc
+++ b/chromium/device/gamepad/gamepad_service_unittest.cc
@@ -21,7 +21,7 @@ namespace {
constexpr int kNumberOfGamepads = Gamepads::kItemsLengthCap;
} // namespace
-class ConnectionListener : public device::GamepadConsumer {
+class ConnectionListener : public GamepadConsumer {
public:
ConnectionListener() = default;
@@ -214,10 +214,11 @@ TEST_F(GamepadServiceTest, ReloadTest) {
EXPECT_EQ(0, consumer->disconnected_counter());
}
-// Flaky, see https://crbug.com/795170
-TEST_F(GamepadServiceTest, DISABLED_SecondConsumerGestureTest) {
+TEST_F(GamepadServiceTest, SecondConsumerGestureTest) {
auto* consumer1 = CreateConsumer();
auto* consumer2 = CreateConsumer();
+ EXPECT_TRUE(service()->ConsumerBecameActive(consumer1));
+
WaitForData();
EXPECT_EQ(0, consumer1->connected_counter());
EXPECT_EQ(0, consumer1->disconnected_counter());
@@ -477,8 +478,7 @@ TEST_F(GamepadServiceTest, DisconnectAndConnectWhileInactiveTest) {
EXPECT_EQ(0, consumer2->disconnected_counter());
}
-// Flaky, see https://crbug.com/795170
-TEST_F(GamepadServiceTest, DISABLED_ActiveConsumerBecameActive) {
+TEST_F(GamepadServiceTest, ActiveConsumerBecameActive) {
// Mark |consumer| active.
auto* consumer = CreateConsumer();
EXPECT_TRUE(service()->ConsumerBecameActive(consumer));
@@ -487,8 +487,7 @@ TEST_F(GamepadServiceTest, DISABLED_ActiveConsumerBecameActive) {
EXPECT_FALSE(service()->ConsumerBecameActive(consumer));
}
-// Flaky, see https://crbug.com/795170
-TEST_F(GamepadServiceTest, DISABLED_InactiveConsumerBecameInactive) {
+TEST_F(GamepadServiceTest, InactiveConsumerBecameInactive) {
// Mark |consumer| active.
auto* consumer = CreateConsumer();
EXPECT_TRUE(service()->ConsumerBecameActive(consumer));
@@ -500,8 +499,7 @@ TEST_F(GamepadServiceTest, DISABLED_InactiveConsumerBecameInactive) {
EXPECT_FALSE(service()->ConsumerBecameInactive(consumer));
}
-// Flaky, see https://crbug.com/795170
-TEST_F(GamepadServiceTest, DISABLED_UnregisteredConsumerBecameInactive) {
+TEST_F(GamepadServiceTest, UnregisteredConsumerBecameInactive) {
auto* consumer = CreateConsumer();
// |consumer| has not yet been added to the gamepad service through a call to
@@ -509,8 +507,7 @@ TEST_F(GamepadServiceTest, DISABLED_UnregisteredConsumerBecameInactive) {
EXPECT_FALSE(service()->ConsumerBecameInactive(consumer));
}
-// Flaky, see https://crbug.com/795170
-TEST_F(GamepadServiceTest, DISABLED_RemoveUnregisteredConsumer) {
+TEST_F(GamepadServiceTest, RemoveUnregisteredConsumer) {
auto* consumer = CreateConsumer();
// |consumer| has not yet been added to the gamepad service through a call to
diff --git a/chromium/device/gamepad/gamepad_test_helpers.h b/chromium/device/gamepad/gamepad_test_helpers.h
index 1ea3643d12a..c41ecab25e2 100644
--- a/chromium/device/gamepad/gamepad_test_helpers.h
+++ b/chromium/device/gamepad/gamepad_test_helpers.h
@@ -60,7 +60,7 @@ class GamepadTestHelper {
private:
// This must be constructed before the system monitor.
- base::test::TaskEnvironment task_environment_;
+ base::test::SingleThreadTaskEnvironment task_environment_;
DISALLOW_COPY_AND_ASSIGN(GamepadTestHelper);
};
diff --git a/chromium/device/gamepad/nintendo_controller.cc b/chromium/device/gamepad/nintendo_controller.cc
index d47cd32af5a..375c8df30c1 100644
--- a/chromium/device/gamepad/nintendo_controller.cc
+++ b/chromium/device/gamepad/nintendo_controller.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/numerics/ranges.h"
#include "base/strings/stringprintf.h"
#include "device/gamepad/gamepad_data_fetcher.h"
#include "device/gamepad/gamepad_id_list.h"
@@ -720,9 +721,9 @@ void FrequencyToHex(float frequency,
int freq = static_cast<int>(frequency);
int amp = static_cast<int>(amplitude * kVibrationAmplitudeMax);
// Clamp the target frequency and amplitude to a safe range.
- freq = std::min(std::max(freq, kVibrationFrequencyHzMin),
- kVibrationFrequencyHzMax);
- amp = std::min(std::max(amp, 0), kVibrationAmplitudeMax);
+ freq = base::ClampToRange(freq, kVibrationFrequencyHzMin,
+ kVibrationFrequencyHzMax);
+ amp = base::ClampToRange(amp, 0, kVibrationAmplitudeMax);
const auto* best_vf = &kVibrationFrequency[0];
for (size_t i = 1; i < kVibrationFrequencySize; ++i) {
const auto* vf = &kVibrationFrequency[i];
@@ -1146,9 +1147,10 @@ void NintendoController::Connect(mojom::HidManager::ConnectCallback callback) {
std::move(callback));
}
-void NintendoController::OnConnect(mojom::HidConnectionPtr connection) {
+void NintendoController::OnConnect(
+ mojo::PendingRemote<mojom::HidConnection> connection) {
if (connection) {
- connection_ = std::move(connection);
+ connection_.Bind(std::move(connection));
ReadInputReport();
StartInitSequence();
}
@@ -1608,8 +1610,7 @@ void NintendoController::RequestSetHomeLight(
}
void NintendoController::RequestSetHomeLightIntensity(double intensity) {
- // Clamp |intensity| to [0,1].
- intensity = std::max(0.0, std::min(1.0, intensity));
+ intensity = base::ClampToRange(intensity, 0.0, 1.0);
uint8_t led_intensity = std::round(intensity * 0x0f);
// Each pair of bytes in the minicycle data describes two minicyles.
// The first byte holds two 4-bit values encoding minicycle intensities.
diff --git a/chromium/device/gamepad/nintendo_controller.h b/chromium/device/gamepad/nintendo_controller.h
index 0a2cb9c1559..4fcda6b12e0 100644
--- a/chromium/device/gamepad/nintendo_controller.h
+++ b/chromium/device/gamepad/nintendo_controller.h
@@ -15,6 +15,8 @@
#include "device/gamepad/gamepad_id_list.h"
#include "device/gamepad/gamepad_standard_mappings.h"
#include "device/gamepad/public/cpp/gamepad.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/hid.mojom.h"
namespace device {
@@ -238,7 +240,7 @@ class NintendoController final : public AbstractHapticGamepad {
void Connect(mojom::HidManager::ConnectCallback callback);
// Completion callback for the HID connection request.
- void OnConnect(mojom::HidConnectionPtr connection);
+ void OnConnect(mojo::PendingRemote<mojom::HidConnection> connection);
// Initiate the sequence of exchanges to prepare the device to provide
// controller data.
@@ -398,7 +400,7 @@ class NintendoController final : public AbstractHapticGamepad {
mojom::HidManager* const hid_manager_;
// The open connection to the underlying HID device.
- mojom::HidConnectionPtr connection_;
+ mojo::Remote<mojom::HidConnection> connection_;
// A closure, provided in the call to Open, to be called once the device
// becomes ready.
diff --git a/chromium/device/gamepad/nintendo_data_fetcher.cc b/chromium/device/gamepad/nintendo_data_fetcher.cc
index 6711187fbd1..ee356fcfe22 100644
--- a/chromium/device/gamepad/nintendo_data_fetcher.cc
+++ b/chromium/device/gamepad/nintendo_data_fetcher.cc
@@ -14,7 +14,7 @@
namespace device {
-NintendoDataFetcher::NintendoDataFetcher() : binding_(this) {}
+NintendoDataFetcher::NintendoDataFetcher() = default;
NintendoDataFetcher::~NintendoDataFetcher() {
for (auto& entry : controllers_) {
@@ -30,15 +30,12 @@ GamepadSource NintendoDataFetcher::source() {
void NintendoDataFetcher::OnAddedToProvider() {
// Open a connection to the HID service. On a successful connection,
// OnGetDevices will be called with a list of connected HID devices.
- auto* connector = GamepadService::GetInstance()->GetConnector();
- DCHECK(connector);
- connector->BindInterface(mojom::kServiceName,
- mojo::MakeRequest(&hid_manager_));
- mojom::HidManagerClientAssociatedPtrInfo client;
- binding_.Bind(mojo::MakeRequest(&client));
+ connector()->Connect(mojom::kServiceName,
+ hid_manager_.BindNewPipeAndPassReceiver());
hid_manager_->GetDevicesAndSetClient(
- std::move(client), base::BindOnce(&NintendoDataFetcher::OnGetDevices,
- weak_factory_.GetWeakPtr()));
+ receiver_.BindNewEndpointAndPassRemote(),
+ base::BindOnce(&NintendoDataFetcher::OnGetDevices,
+ weak_factory_.GetWeakPtr()));
}
void NintendoDataFetcher::OnGetDevices(
diff --git a/chromium/device/gamepad/nintendo_data_fetcher.h b/chromium/device/gamepad/nintendo_data_fetcher.h
index c0964a2e875..776544ed703 100644
--- a/chromium/device/gamepad/nintendo_data_fetcher.h
+++ b/chromium/device/gamepad/nintendo_data_fetcher.h
@@ -14,7 +14,8 @@
#include "device/gamepad/gamepad_data_fetcher.h"
#include "device/gamepad/nintendo_controller.h"
#include "device/gamepad/public/cpp/gamepads.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/hid.mojom.h"
namespace device {
@@ -110,8 +111,8 @@ class DEVICE_GAMEPAD_EXPORT NintendoDataFetcher : public GamepadDataFetcher,
// A mapping from source ID to connected Nintendo Switch devices.
ControllerMap controllers_;
- mojom::HidManagerPtr hid_manager_;
- mojo::AssociatedBinding<mojom::HidManagerClient> binding_;
+ mojo::Remote<mojom::HidManager> hid_manager_;
+ mojo::AssociatedReceiver<mojom::HidManagerClient> receiver_{this};
base::WeakPtrFactory<NintendoDataFetcher> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(NintendoDataFetcher);
diff --git a/chromium/device/gamepad/nintendo_data_fetcher_unittest.cc b/chromium/device/gamepad/nintendo_data_fetcher_unittest.cc
index 32d390ce6aa..977fd193f5a 100644
--- a/chromium/device/gamepad/nintendo_data_fetcher_unittest.cc
+++ b/chromium/device/gamepad/nintendo_data_fetcher_unittest.cc
@@ -19,15 +19,6 @@
#include "services/service_manager/public/cpp/connector.h"
#include "testing/gtest/include/gtest/gtest.h"
-// TODO(crbug.com/961039): Fix memory leaks in tests and re-enable on LSAN.
-#ifdef LEAK_SANITIZER
-#define MAYBE_AddAndRemoveSwitchPro DISABLED_AddAndRemoveSwitchPro
-#define MAYBE_UnsupportedDeviceIsIgnored DISABLED_UnsupportedDeviceIsIgnored
-#else
-#define MAYBE_AddAndRemoveSwitchPro AddAndRemoveSwitchPro
-#define MAYBE_UnsupportedDeviceIsIgnored UnsupportedDeviceIsIgnored
-#endif
-
namespace device {
namespace {
@@ -65,8 +56,9 @@ class NintendoDataFetcherTest : public DeviceServiceTestBase {
fetcher_ = fetcher.get();
auto polling_thread = std::make_unique<base::Thread>("polling thread");
polling_thread_ = polling_thread.get();
- provider_.reset(new GamepadProvider(nullptr, std::move(fetcher),
- std::move(polling_thread)));
+ provider_ = std::make_unique<GamepadProvider>(
+ /*connection_change_client=*/nullptr, connector()->Clone(),
+ std::move(fetcher), std::move(polling_thread));
RunUntilIdle();
}
@@ -89,7 +81,7 @@ class NintendoDataFetcherTest : public DeviceServiceTestBase {
DISALLOW_COPY_AND_ASSIGN(NintendoDataFetcherTest);
};
-TEST_F(NintendoDataFetcherTest, MAYBE_UnsupportedDeviceIsIgnored) {
+TEST_F(NintendoDataFetcherTest, UnsupportedDeviceIsIgnored) {
// Simulate an unsupported, non-Nintendo HID device.
auto collection = mojom::HidCollectionInfo::New();
collection->usage = mojom::HidUsageAndPage::New(0, 0);
@@ -110,7 +102,7 @@ TEST_F(NintendoDataFetcherTest, MAYBE_UnsupportedDeviceIsIgnored) {
RunUntilIdle();
}
-TEST_F(NintendoDataFetcherTest, MAYBE_AddAndRemoveSwitchPro) {
+TEST_F(NintendoDataFetcherTest, AddAndRemoveSwitchPro) {
// Simulate a Switch Pro over USB.
auto collection = mojom::HidCollectionInfo::New();
collection->usage = mojom::HidUsageAndPage::New(0, 0);
diff --git a/chromium/device/gamepad/public/cpp/gamepad_mojom_traits_unittest.cc b/chromium/device/gamepad/public/cpp/gamepad_mojom_traits_unittest.cc
index 13ab0e9a490..daf77d44026 100644
--- a/chromium/device/gamepad/public/cpp/gamepad_mojom_traits_unittest.cc
+++ b/chromium/device/gamepad/public/cpp/gamepad_mojom_traits_unittest.cc
@@ -164,7 +164,7 @@ class GamepadStructTraitsTest : public testing::Test {
GamepadStructTraitsTest() {}
private:
- base::test::TaskEnvironment task_environment_;
+ base::test::SingleThreadTaskEnvironment task_environment_;
DISALLOW_COPY_AND_ASSIGN(GamepadStructTraitsTest);
};
diff --git a/chromium/device/gamepad/raw_input_data_fetcher_win.cc b/chromium/device/gamepad/raw_input_data_fetcher_win.cc
index 2132d33dbfc..6a7f9be19e7 100644
--- a/chromium/device/gamepad/raw_input_data_fetcher_win.cc
+++ b/chromium/device/gamepad/raw_input_data_fetcher_win.cc
@@ -107,6 +107,17 @@ void RawInputDataFetcher::StopMonitor() {
window_.reset();
}
+bool RawInputDataFetcher::DisconnectUnrecognizedGamepad(int source_id) {
+ for (auto it = controllers_.begin(); it != controllers_.end(); ++it) {
+ if (it->second->GetSourceId() == source_id) {
+ it->second->Shutdown();
+ controllers_.erase(it);
+ return true;
+ }
+ }
+ return false;
+}
+
void RawInputDataFetcher::ClearControllers() {
for (const auto& entry : controllers_)
entry.second->Shutdown();
@@ -179,6 +190,10 @@ void RawInputDataFetcher::EnumerateDevices() {
continue;
}
+ bool is_recognized =
+ GamepadId::kUnknownGamepad !=
+ GamepadIdList::Get().GetGamepadId(vendor_int, product_int);
+
// Record gamepad metrics before excluding XInput devices. This allows
// us to recognize XInput devices even though the XInput API masks
// the vendor and product IDs.
@@ -194,7 +209,7 @@ void RawInputDataFetcher::EnumerateDevices() {
continue;
}
- PadState* state = GetPadState(source_id);
+ PadState* state = GetPadState(source_id, is_recognized);
if (!state) {
new_device->Shutdown();
continue; // No slot available for this gamepad.
diff --git a/chromium/device/gamepad/raw_input_data_fetcher_win.h b/chromium/device/gamepad/raw_input_data_fetcher_win.h
index 3d51f7463f6..6d76268ec49 100644
--- a/chromium/device/gamepad/raw_input_data_fetcher_win.h
+++ b/chromium/device/gamepad/raw_input_data_fetcher_win.h
@@ -49,6 +49,8 @@ class RawInputDataFetcher : public GamepadDataFetcher,
mojom::GamepadHapticsManager::ResetVibrationActuatorCallback,
scoped_refptr<base::SequencedTaskRunner>) override;
+ bool DisconnectUnrecognizedGamepad(int source_id) override;
+
private:
void OnAddedToProvider() override;
diff --git a/chromium/device/gamepad/xinput_haptic_gamepad_win.cc b/chromium/device/gamepad/xinput_haptic_gamepad_win.cc
index b0e03dcd63f..8666c31824a 100644
--- a/chromium/device/gamepad/xinput_haptic_gamepad_win.cc
+++ b/chromium/device/gamepad/xinput_haptic_gamepad_win.cc
@@ -4,6 +4,8 @@
#include "device/gamepad/xinput_haptic_gamepad_win.h"
+#include "base/trace_event/trace_event.h"
+
namespace {
const long kRumbleMagnitudeMax = 0xffff;
} // namespace
diff --git a/chromium/device/vr/BUILD.gn b/chromium/device/vr/BUILD.gn
index cf711256acc..089939493f8 100644
--- a/chromium/device/vr/BUILD.gn
+++ b/chromium/device/vr/BUILD.gn
@@ -241,8 +241,8 @@ if (enable_vr) {
"openxr/openxr_controller.h",
"openxr/openxr_device.cc",
"openxr/openxr_device.h",
- "openxr/openxr_gamepad_helper.cc",
- "openxr/openxr_gamepad_helper.h",
+ "openxr/openxr_input_helper.cc",
+ "openxr/openxr_input_helper.h",
"openxr/openxr_render_loop.cc",
"openxr/openxr_render_loop.h",
"openxr/openxr_util.cc",
@@ -401,8 +401,10 @@ if (enable_gvr_services) {
java_files = java_sources_needing_jni
deps = [
"//base:base_java",
+ "//base:jni_java",
"//third_party/gvr-android-sdk:gvr_common_java",
"//ui/android:ui_java",
]
+ annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
}
}
diff --git a/chromium/device/vr/android/gvr/gvr_delegate.cc b/chromium/device/vr/android/gvr/gvr_delegate.cc
index 9b596dae2f8..a09b8378dbc 100644
--- a/chromium/device/vr/android/gvr/gvr_delegate.cc
+++ b/chromium/device/vr/android/gvr/gvr_delegate.cc
@@ -151,6 +151,22 @@ mojom::VRPosePtr GvrDelegate::GetVRPosePtrWithNeckModel(
pose->angular_velocity =
GetAngularVelocityFromPoses(*head_mat_ptr, head_mat_2, epsilon_seconds);
+ // The position is emulated unless the current tracking status is 6DoF and is
+ // not still initializing or invalid.
+ pose->emulated_position = true;
+ gvr::Properties props = gvr_api->GetCurrentProperties();
+ gvr::Value head_tracking_status;
+ if (props.Get(GVR_PROPERTY_TRACKING_STATUS, &head_tracking_status)) {
+ bool has_6dof =
+ !!(head_tracking_status.fl & GVR_TRACKING_STATUS_FLAG_HAS_6DOF);
+ bool initialized =
+ !(head_tracking_status.fl & GVR_TRACKING_STATUS_FLAG_INITIALIZING);
+ bool valid = !(head_tracking_status.fl & GVR_TRACKING_STATUS_FLAG_INVALID);
+ if (has_6dof && initialized && valid) {
+ pose->emulated_position = false;
+ }
+ }
+
return pose;
}
diff --git a/chromium/device/vr/android/gvr/gvr_device.cc b/chromium/device/vr/android/gvr/gvr_device.cc
index 084f1869c0f..116982b1d17 100644
--- a/chromium/device/vr/android/gvr/gvr_device.cc
+++ b/chromium/device/vr/android/gvr/gvr_device.cc
@@ -20,6 +20,7 @@
#include "device/vr/android/gvr/gvr_device_provider.h"
#include "device/vr/android/gvr/gvr_utils.h"
#include "device/vr/jni_headers/NonPresentingGvrContext_jni.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/transform.h"
@@ -141,9 +142,7 @@ mojom::VRDisplayInfoPtr CreateVRDisplayInfo(gvr::GvrApi* gvr_api,
} // namespace
-GvrDevice::GvrDevice()
- : VRDeviceBase(mojom::XRDeviceId::GVR_DEVICE_ID),
- exclusive_controller_binding_(this) {
+GvrDevice::GvrDevice() : VRDeviceBase(mojom::XRDeviceId::GVR_DEVICE_ID) {
GvrDelegateProviderFactory::SetDevice(this);
}
@@ -156,7 +155,8 @@ GvrDevice::~GvrDevice() {
}
if (pending_request_session_callback_) {
- std::move(pending_request_session_callback_).Run(nullptr, nullptr);
+ std::move(pending_request_session_callback_)
+ .Run(nullptr, mojo::NullRemote());
}
GvrDelegateProviderFactory::SetDevice(nullptr);
@@ -171,7 +171,7 @@ void GvrDevice::RequestSession(
mojom::XRRuntime::RequestSessionCallback callback) {
// We can only process one request at a time.
if (pending_request_session_callback_) {
- std::move(callback).Run(nullptr, nullptr);
+ std::move(callback).Run(nullptr, mojo::NullRemote());
return;
}
pending_request_session_callback_ = std::move(callback);
@@ -189,25 +189,26 @@ void GvrDevice::OnStartPresentResult(
DCHECK(pending_request_session_callback_);
if (!session) {
- std::move(pending_request_session_callback_).Run(nullptr, nullptr);
+ std::move(pending_request_session_callback_)
+ .Run(nullptr, mojo::NullRemote());
return;
}
OnStartPresenting();
- mojom::XRSessionControllerPtr session_controller;
// Close the binding to ensure any previous sessions were closed.
// TODO(billorr): Only do this in OnPresentingControllerMojoConnectionError.
- exclusive_controller_binding_.Close();
- exclusive_controller_binding_.Bind(mojo::MakeRequest(&session_controller));
+ exclusive_controller_receiver_.reset();
+
+ std::move(pending_request_session_callback_)
+ .Run(std::move(session),
+ exclusive_controller_receiver_.BindNewPipeAndPassRemote());
// Unretained is safe because the error handler won't be called after the
// binding has been destroyed.
- exclusive_controller_binding_.set_connection_error_handler(
+ exclusive_controller_receiver_.set_disconnect_handler(
base::BindOnce(&GvrDevice::OnPresentingControllerMojoConnectionError,
base::Unretained(this)));
- std::move(pending_request_session_callback_)
- .Run(std::move(session), std::move(session_controller));
}
// XRSessionController
@@ -225,7 +226,7 @@ void GvrDevice::StopPresenting() {
if (delegate_provider)
delegate_provider->ExitWebVRPresent();
OnExitPresent();
- exclusive_controller_binding_.Close();
+ exclusive_controller_receiver_.reset();
}
void GvrDevice::OnListeningForActivate(bool listening) {
@@ -312,13 +313,15 @@ void GvrDevice::OnInitRequestSessionFinished(
DCHECK(pending_request_session_callback_);
if (!success) {
- std::move(pending_request_session_callback_).Run(nullptr, nullptr);
+ std::move(pending_request_session_callback_)
+ .Run(nullptr, mojo::NullRemote());
return;
}
GvrDelegateProvider* delegate_provider = GetGvrDelegateProvider();
if (!delegate_provider) {
- std::move(pending_request_session_callback_).Run(nullptr, nullptr);
+ std::move(pending_request_session_callback_)
+ .Run(nullptr, mojo::NullRemote());
return;
}
diff --git a/chromium/device/vr/android/gvr/gvr_device.h b/chromium/device/vr/android/gvr/gvr_device.h
index 4c91a525be3..bf4c03fa04c 100644
--- a/chromium/device/vr/android/gvr/gvr_device.h
+++ b/chromium/device/vr/android/gvr/gvr_device.h
@@ -12,6 +12,7 @@
#include "base/android/scoped_java_ref.h"
#include "base/macros.h"
#include "device/vr/vr_device_base.h"
+#include "mojo/public/cpp/bindings/receiver.h"
#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
namespace device {
@@ -63,7 +64,8 @@ class DEVICE_VR_EXPORT GvrDevice : public VRDeviceBase,
bool paused_ = true;
- mojo::Binding<mojom::XRSessionController> exclusive_controller_binding_;
+ mojo::Receiver<mojom::XRSessionController> exclusive_controller_receiver_{
+ this};
mojom::XRRuntime::RequestSessionCallback pending_request_session_callback_;
diff --git a/chromium/device/vr/android/gvr/gvr_device_provider.cc b/chromium/device/vr/android/gvr/gvr_device_provider.cc
index 33856d1f842..9b007593a09 100644
--- a/chromium/device/vr/android/gvr/gvr_device_provider.cc
+++ b/chromium/device/vr/android/gvr/gvr_device_provider.cc
@@ -16,7 +16,8 @@ GvrDeviceProvider::~GvrDeviceProvider() = default;
void GvrDeviceProvider::Initialize(
base::RepeatingCallback<void(mojom::XRDeviceId,
mojom::VRDisplayInfoPtr,
- mojom::XRRuntimePtr)> add_device_callback,
+ mojo::PendingRemote<mojom::XRRuntime>)>
+ add_device_callback,
base::RepeatingCallback<void(mojom::XRDeviceId)> remove_device_callback,
base::OnceClosure initialization_complete) {
// Version check should match MIN_SDK_VERSION in VrCoreVersionChecker.java.
@@ -30,7 +31,7 @@ void GvrDeviceProvider::Initialize(
}
if (vr_device_) {
add_device_callback.Run(vr_device_->GetId(), vr_device_->GetVRDisplayInfo(),
- vr_device_->BindXRRuntimePtr());
+ vr_device_->BindXRRuntime());
}
initialized_ = true;
std::move(initialization_complete).Run();
diff --git a/chromium/device/vr/android/gvr/gvr_device_provider.h b/chromium/device/vr/android/gvr/gvr_device_provider.h
index 527b84715cb..52209459da5 100644
--- a/chromium/device/vr/android/gvr/gvr_device_provider.h
+++ b/chromium/device/vr/android/gvr/gvr_device_provider.h
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "device/vr/vr_device_provider.h"
#include "device/vr/vr_export.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
namespace device {
@@ -23,7 +24,8 @@ class DEVICE_VR_EXPORT GvrDeviceProvider : public VRDeviceProvider {
void Initialize(
base::RepeatingCallback<void(mojom::XRDeviceId,
mojom::VRDisplayInfoPtr,
- mojom::XRRuntimePtr)> add_device_callback,
+ mojo::PendingRemote<mojom::XRRuntime>)>
+ add_device_callback,
base::RepeatingCallback<void(mojom::XRDeviceId)> remove_device_callback,
base::OnceClosure initialization_complete) override;
diff --git a/chromium/device/vr/android/java/src/org/chromium/device/vr/NonPresentingGvrContext.java b/chromium/device/vr/android/java/src/org/chromium/device/vr/NonPresentingGvrContext.java
index d7ba07e62b0..20acaecf050 100644
--- a/chromium/device/vr/android/java/src/org/chromium/device/vr/NonPresentingGvrContext.java
+++ b/chromium/device/vr/android/java/src/org/chromium/device/vr/NonPresentingGvrContext.java
@@ -15,6 +15,7 @@ import com.google.vr.ndk.base.GvrApi;
import org.chromium.base.ContextUtils;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeMethods;
/**
* Creates an active GvrContext from a GvrApi created from the Application Context. This GvrContext
@@ -90,8 +91,14 @@ public class NonPresentingGvrContext {
public void onDisplayConfigurationChanged() {
mGvrApi.refreshDisplayMetrics();
- if (mNativeGvrDevice != 0) nativeOnDisplayConfigurationChanged(mNativeGvrDevice);
+ if (mNativeGvrDevice != 0) {
+ NonPresentingGvrContextJni.get().onDisplayConfigurationChanged(
+ mNativeGvrDevice, NonPresentingGvrContext.this);
+ }
}
- private native void nativeOnDisplayConfigurationChanged(long nativeGvrDevice);
+ @NativeMethods
+ interface Natives {
+ void onDisplayConfigurationChanged(long nativeGvrDevice, NonPresentingGvrContext caller);
+ }
}
diff --git a/chromium/device/vr/buildflags/buildflags.gni b/chromium/device/vr/buildflags/buildflags.gni
index dfe975ea1ee..b95861404df 100644
--- a/chromium/device/vr/buildflags/buildflags.gni
+++ b/chromium/device/vr/buildflags/buildflags.gni
@@ -47,13 +47,4 @@ declare_args() {
# TODO(crbug.com/843374): AR should not depend on |enable_vr|.
enable_arcore = enable_vr && is_android && !is_chromecast &&
(current_cpu == "arm" || current_cpu == "arm64")
-
- # When true, portions of VR's native code are included in the VR DFM.
- modularize_vr_native = true
-
- # Whether to create AR module as an asynchronous DFM.
- async_ar = false
-
- # Whether to create VR module as an asynchronous DFM.
- async_vr = false
}
diff --git a/chromium/device/vr/isolated_gamepad_data_fetcher.cc b/chromium/device/vr/isolated_gamepad_data_fetcher.cc
index bd27e4299c1..d58d3189f7f 100644
--- a/chromium/device/vr/isolated_gamepad_data_fetcher.cc
+++ b/chromium/device/vr/isolated_gamepad_data_fetcher.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/trace_event/trace_event.h"
#include "build/buildflag.h"
#include "device/vr/buildflags/buildflags.h"
#include "device/vr/vr_device.h"
@@ -69,15 +70,17 @@ GamepadSource GamepadSourceFromDeviceId(device::mojom::XRDeviceId id) {
IsolatedGamepadDataFetcher::Factory::Factory(
device::mojom::XRDeviceId display_id,
- device::mojom::IsolatedXRGamepadProviderFactoryPtr factory)
+ mojo::PendingRemote<device::mojom::IsolatedXRGamepadProviderFactory>
+ factory)
: display_id_(display_id), factory_(std::move(factory)) {}
IsolatedGamepadDataFetcher::Factory::~Factory() {}
std::unique_ptr<GamepadDataFetcher>
IsolatedGamepadDataFetcher::Factory::CreateDataFetcher() {
- device::mojom::IsolatedXRGamepadProviderPtr provider;
- factory_->GetIsolatedXRGamepadProvider(mojo::MakeRequest(&provider));
+ mojo::PendingRemote<device::mojom::IsolatedXRGamepadProvider> provider;
+ factory_->GetIsolatedXRGamepadProvider(
+ provider.InitWithNewPipeAndPassReceiver());
return std::make_unique<IsolatedGamepadDataFetcher>(display_id_,
std::move(provider));
}
@@ -88,11 +91,11 @@ GamepadSource IsolatedGamepadDataFetcher::Factory::source() {
IsolatedGamepadDataFetcher::IsolatedGamepadDataFetcher(
device::mojom::XRDeviceId display_id,
- device::mojom::IsolatedXRGamepadProviderPtr provider)
+ mojo::PendingRemote<device::mojom::IsolatedXRGamepadProvider> provider)
: display_id_(display_id) {
// We bind provider_ on the poling thread, but we're created on the main UI
// thread.
- provider_info_ = provider.PassInterface();
+ pending_provider_ = std::move(provider);
}
IsolatedGamepadDataFetcher::~IsolatedGamepadDataFetcher() = default;
@@ -161,8 +164,8 @@ GamepadPose GamepadPoseFromXRPose(device::mojom::VRPose* pose) {
}
void IsolatedGamepadDataFetcher::GetGamepadData(bool devices_changed_hint) {
- if (!provider_ && provider_info_) {
- provider_.Bind(std::move(provider_info_));
+ if (!provider_ && pending_provider_) {
+ provider_.Bind(std::move(pending_provider_));
}
// If we don't have a provider, we can't give out data.
@@ -289,7 +292,8 @@ void IsolatedGamepadDataFetcher::Factory::RemoveGamepad(
void IsolatedGamepadDataFetcher::Factory::AddGamepad(
device::mojom::XRDeviceId device_id,
- device::mojom::IsolatedXRGamepadProviderFactoryPtr gamepad_factory) {
+ mojo::PendingRemote<device::mojom::IsolatedXRGamepadProviderFactory>
+ gamepad_factory) {
if (!IsValidDeviceId(device_id))
return;
diff --git a/chromium/device/vr/isolated_gamepad_data_fetcher.h b/chromium/device/vr/isolated_gamepad_data_fetcher.h
index 39511405498..cf5e1af92e6 100644
--- a/chromium/device/vr/isolated_gamepad_data_fetcher.h
+++ b/chromium/device/vr/isolated_gamepad_data_fetcher.h
@@ -8,6 +8,8 @@
#include "device/gamepad/gamepad_data_fetcher.h"
#include "device/vr/public/mojom/isolated_xr_service.mojom.h"
#include "device/vr/vr_device.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
namespace device {
@@ -16,24 +18,26 @@ class IsolatedGamepadDataFetcher : public GamepadDataFetcher {
class DEVICE_VR_EXPORT Factory : public GamepadDataFetcherFactory {
public:
Factory(device::mojom::XRDeviceId display_id,
- device::mojom::IsolatedXRGamepadProviderFactoryPtr factory);
+ mojo::PendingRemote<device::mojom::IsolatedXRGamepadProviderFactory>
+ factory);
~Factory() override;
std::unique_ptr<GamepadDataFetcher> CreateDataFetcher() override;
GamepadSource source() override;
static void AddGamepad(
device::mojom::XRDeviceId device_id,
- device::mojom::IsolatedXRGamepadProviderFactoryPtr gamepad_factory);
+ mojo::PendingRemote<device::mojom::IsolatedXRGamepadProviderFactory>
+ gamepad_factory);
static void RemoveGamepad(device::mojom::XRDeviceId device_id);
private:
device::mojom::XRDeviceId display_id_;
- device::mojom::IsolatedXRGamepadProviderFactoryPtr factory_;
+ mojo::Remote<device::mojom::IsolatedXRGamepadProviderFactory> factory_;
};
IsolatedGamepadDataFetcher(
device::mojom::XRDeviceId display_id,
- device::mojom::IsolatedXRGamepadProviderPtr provider);
+ mojo::PendingRemote<device::mojom::IsolatedXRGamepadProvider> provider);
~IsolatedGamepadDataFetcher() override;
GamepadSource source() override;
@@ -49,10 +53,10 @@ class IsolatedGamepadDataFetcher : public GamepadDataFetcher {
bool have_outstanding_request_ = false;
std::set<unsigned int> active_gamepads_;
device::mojom::XRGamepadDataPtr data_;
- device::mojom::IsolatedXRGamepadProviderPtr
+ mojo::Remote<device::mojom::IsolatedXRGamepadProvider>
provider_; // Bound on the polling thread.
- device::mojom::IsolatedXRGamepadProviderPtrInfo
- provider_info_; // Received on the UI thread, bound when polled.
+ mojo::PendingRemote<device::mojom::IsolatedXRGamepadProvider>
+ pending_provider_; // Received on the UI thread, bound when polled.
DISALLOW_COPY_AND_ASSIGN(IsolatedGamepadDataFetcher);
};
diff --git a/chromium/device/vr/oculus/oculus_device.cc b/chromium/device/vr/oculus/oculus_device.cc
index 9f15d2e9356..cc3f0a5cd51 100644
--- a/chromium/device/vr/oculus/oculus_device.cc
+++ b/chromium/device/vr/oculus/oculus_device.cc
@@ -16,6 +16,7 @@
#include "device/vr/oculus/oculus_render_loop.h"
#include "device/vr/oculus/oculus_type_converters.h"
#include "device/vr/util/transform_utils.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
#include "third_party/libovr/src/Include/OVR_CAPI.h"
#include "third_party/libovr/src/Include/OVR_CAPI_D3D.h"
#include "ui/gfx/geometry/angle_conversions.h"
@@ -95,9 +96,6 @@ mojom::VRDisplayInfoPtr CreateVRDisplayInfo(mojom::XRDeviceId id,
OculusDevice::OculusDevice()
: VRDeviceBase(mojom::XRDeviceId::OCULUS_DEVICE_ID),
main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
- exclusive_controller_binding_(this),
- gamepad_provider_factory_binding_(this),
- compositor_host_binding_(this),
weak_ptr_factory_(this) {
render_loop_ = std::make_unique<OculusRenderLoop>();
}
@@ -112,16 +110,14 @@ bool OculusDevice::IsApiAvailable() {
return result.IsOculusServiceRunning;
}
-mojom::IsolatedXRGamepadProviderFactoryPtr OculusDevice::BindGamepadFactory() {
- mojom::IsolatedXRGamepadProviderFactoryPtr ret;
- gamepad_provider_factory_binding_.Bind(mojo::MakeRequest(&ret));
- return ret;
+mojo::PendingRemote<mojom::IsolatedXRGamepadProviderFactory>
+OculusDevice::BindGamepadFactory() {
+ return gamepad_provider_factory_receiver_.BindNewPipeAndPassRemote();
}
-mojom::XRCompositorHostPtr OculusDevice::BindCompositorHost() {
- mojom::XRCompositorHostPtr ret;
- compositor_host_binding_.Bind(mojo::MakeRequest(&ret));
- return ret;
+mojo::PendingRemote<mojom::XRCompositorHost>
+OculusDevice::BindCompositorHost() {
+ return compositor_host_receiver_.BindNewPipeAndPassRemote();
}
OculusDevice::~OculusDevice() {
@@ -137,7 +133,7 @@ void OculusDevice::RequestSession(
mojom::XRRuntimeSessionOptionsPtr options,
mojom::XRRuntime::RequestSessionCallback callback) {
if (!EnsureValidDisplayInfo()) {
- std::move(callback).Run(nullptr, nullptr);
+ std::move(callback).Run(nullptr, mojo::NullRemote());
return;
}
@@ -149,25 +145,25 @@ void OculusDevice::RequestSession(
render_loop_->Start();
if (!render_loop_->IsRunning()) {
- std::move(callback).Run(nullptr, nullptr);
+ std::move(callback).Run(nullptr, mojo::NullRemote());
StartOvrSession();
return;
}
- // If we have a pending gamepad provider request when starting the render
- // loop, post the request over to the render loop to be bound.
- if (provider_request_) {
+ // If we have a pending gamepad provider receiver when starting the render
+ // loop, post the receiver over to the render loop to be bound.
+ if (provider_receiver_) {
render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestGamepadProvider,
base::Unretained(render_loop_.get()),
- std::move(provider_request_)));
+ std::move(provider_receiver_)));
}
- if (overlay_request_) {
+ if (overlay_receiver_) {
render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
base::Unretained(render_loop_.get()),
- std::move(overlay_request_)));
+ std::move(overlay_receiver_)));
}
}
@@ -182,8 +178,9 @@ void OculusDevice::RequestSession(
FROM_HERE,
base::BindOnce(&XRCompositorCommon::RequestSession,
base::Unretained(render_loop_.get()),
- std::move(on_presentation_ended), std::move(options),
- std::move(on_request_present_result)));
+ std::move(on_presentation_ended),
+ base::DoNothing::Repeatedly<mojom::XRVisibilityState>(),
+ std::move(options), std::move(on_request_present_result)));
outstanding_session_requests_count_++;
}
@@ -213,7 +210,7 @@ void OculusDevice::OnRequestSessionResult(
mojom::XRSessionPtr session) {
outstanding_session_requests_count_--;
if (!result) {
- std::move(callback).Run(nullptr, nullptr);
+ std::move(callback).Run(nullptr, mojo::NullRemote());
// Start magic window again.
if (outstanding_session_requests_count_ == 0)
@@ -223,18 +220,17 @@ void OculusDevice::OnRequestSessionResult(
OnStartPresenting();
- mojom::XRSessionControllerPtr session_controller;
- exclusive_controller_binding_.Bind(mojo::MakeRequest(&session_controller));
+ session->display_info = display_info_.Clone();
+
+ std::move(callback).Run(
+ std::move(session),
+ exclusive_controller_receiver_.BindNewPipeAndPassRemote());
// Unretained is safe because the error handler won't be called after the
// binding has been destroyed.
- exclusive_controller_binding_.set_connection_error_handler(
+ exclusive_controller_receiver_.set_disconnect_handler(
base::BindOnce(&OculusDevice::OnPresentingControllerMojoConnectionError,
base::Unretained(this)));
-
- session->display_info = display_info_.Clone();
-
- std::move(callback).Run(std::move(session), std::move(session_controller));
}
bool OculusDevice::IsAvailable() {
@@ -253,7 +249,7 @@ void OculusDevice::OnPresentingControllerMojoConnectionError() {
FROM_HERE, base::BindOnce(&XRCompositorCommon::ExitPresent,
base::Unretained(render_loop_.get())));
OnExitPresent();
- exclusive_controller_binding_.Close();
+ exclusive_controller_receiver_.reset();
}
void OculusDevice::OnPresentationEnded() {
@@ -289,30 +285,30 @@ void OculusDevice::StopOvrSession() {
}
void OculusDevice::GetIsolatedXRGamepadProvider(
- mojom::IsolatedXRGamepadProviderRequest provider_request) {
- // We bind the provider_request on the render loop thread, so gamepad data is
+ mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver) {
+ // We bind the provider_receiver on the render loop thread, so gamepad data is
// updated at the rendering rate.
- // If we haven't started the render loop yet, postpone binding the request
+ // If we haven't started the render loop yet, postpone binding the receiver
// until we do.
if (render_loop_->IsRunning()) {
render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestGamepadProvider,
base::Unretained(render_loop_.get()),
- std::move(provider_request)));
+ std::move(provider_receiver)));
} else {
- provider_request_ = std::move(provider_request);
+ provider_receiver_ = std::move(provider_receiver);
}
}
void OculusDevice::CreateImmersiveOverlay(
- mojom::ImmersiveOverlayRequest overlay_request) {
+ mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver) {
if (render_loop_->IsRunning()) {
render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
base::Unretained(render_loop_.get()),
- std::move(overlay_request)));
+ std::move(overlay_receiver)));
} else {
- overlay_request_ = std::move(overlay_request);
+ overlay_receiver_ = std::move(overlay_receiver);
}
}
diff --git a/chromium/device/vr/oculus/oculus_device.h b/chromium/device/vr/oculus/oculus_device.h
index a44754a177c..63670cf4dcd 100644
--- a/chromium/device/vr/oculus/oculus_device.h
+++ b/chromium/device/vr/oculus/oculus_device.h
@@ -11,7 +11,9 @@
#include "base/single_thread_task_runner.h"
#include "device/vr/public/mojom/vr_service.mojom.h"
#include "device/vr/vr_device_base.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
#include "third_party/libovr/src/Include/OVR_CAPI.h"
namespace device {
@@ -41,8 +43,9 @@ class DEVICE_VR_EXPORT OculusDevice
bool IsAvailable();
- mojom::IsolatedXRGamepadProviderFactoryPtr BindGamepadFactory();
- mojom::XRCompositorHostPtr BindCompositorHost();
+ mojo::PendingRemote<mojom::IsolatedXRGamepadProviderFactory>
+ BindGamepadFactory();
+ mojo::PendingRemote<mojom::XRCompositorHost> BindCompositorHost();
private:
// XRSessionController
@@ -52,11 +55,12 @@ class DEVICE_VR_EXPORT OculusDevice
// mojom::IsolatedXRGamepadProviderFactory
void GetIsolatedXRGamepadProvider(
- mojom::IsolatedXRGamepadProviderRequest provider_request) override;
+ mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver)
+ override;
// XRCompositorHost
void CreateImmersiveOverlay(
- mojom::ImmersiveOverlayRequest overlay_request) override;
+ mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver) override;
void OnPresentationEnded();
bool EnsureValidDisplayInfo();
@@ -69,13 +73,14 @@ class DEVICE_VR_EXPORT OculusDevice
ovrSession session_ = nullptr;
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
- mojo::Binding<mojom::XRSessionController> exclusive_controller_binding_;
- mojo::Binding<mojom::IsolatedXRGamepadProviderFactory>
- gamepad_provider_factory_binding_;
- mojom::IsolatedXRGamepadProviderRequest provider_request_;
+ mojo::Receiver<mojom::XRSessionController> exclusive_controller_receiver_{
+ this};
+ mojo::Receiver<mojom::IsolatedXRGamepadProviderFactory>
+ gamepad_provider_factory_receiver_{this};
+ mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver_;
- mojo::Binding<mojom::XRCompositorHost> compositor_host_binding_;
- mojom::ImmersiveOverlayRequest overlay_request_;
+ mojo::Receiver<mojom::XRCompositorHost> compositor_host_receiver_{this};
+ mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver_;
base::WeakPtrFactory<OculusDevice> weak_ptr_factory_;
diff --git a/chromium/device/vr/oculus/oculus_render_loop.cc b/chromium/device/vr/oculus/oculus_render_loop.cc
index 12449248b41..dda325d132b 100644
--- a/chromium/device/vr/oculus/oculus_render_loop.cc
+++ b/chromium/device/vr/oculus/oculus_render_loop.cc
@@ -347,8 +347,8 @@ device::mojom::XRInputSourceStatePtr OculusRenderLoop::GetTouchData(
break;
}
- // Touch controller are fully 6DoF.
- desc->emulated_position = false;
+ // Touch controllers are fully 6DoF.
+ state->emulated_position = false;
// The grip pose will be rotated and translated back a bit from the pointer
// pose, which is what the Oculus API returns.
@@ -368,7 +368,7 @@ device::mojom::XRInputSourceStatePtr OculusRenderLoop::GetTouchData(
// The absence of "touchpad" in this string indicates that the slots in the
// button and axes arrays are placeholders required by the xr-standard mapping
// but not actually updated with any input.
- desc->profiles.push_back("grip-thumbstick-controller");
+ desc->profiles.push_back("generic-trigger-squeeze-thumbstick");
state->description = std::move(desc);
diff --git a/chromium/device/vr/openvr/openvr_device.cc b/chromium/device/vr/openvr/openvr_device.cc
index 8110ff38df0..98e630c7b62 100644
--- a/chromium/device/vr/openvr/openvr_device.cc
+++ b/chromium/device/vr/openvr/openvr_device.cc
@@ -16,6 +16,7 @@
#include "build/build_config.h"
#include "device/vr/openvr/openvr_render_loop.h"
#include "device/vr/openvr/openvr_type_converters.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
#include "third_party/openvr/src/headers/openvr.h"
#include "ui/gfx/geometry/angle_conversions.h"
@@ -122,10 +123,7 @@ mojom::VRDisplayInfoPtr CreateVRDisplayInfo(vr::IVRSystem* vr_system,
OpenVRDevice::OpenVRDevice()
: VRDeviceBase(device::mojom::XRDeviceId::OPENVR_DEVICE_ID),
- main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
- exclusive_controller_binding_(this),
- gamepad_provider_factory_binding_(this),
- compositor_host_binding_(this) {
+ main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
render_loop_ = std::make_unique<OpenVRRenderLoop>();
OnPollingEvents();
@@ -139,16 +137,14 @@ bool OpenVRDevice::IsApiAvailable() {
return vr::VR_IsRuntimeInstalled();
}
-mojom::IsolatedXRGamepadProviderFactoryPtr OpenVRDevice::BindGamepadFactory() {
- mojom::IsolatedXRGamepadProviderFactoryPtr ret;
- gamepad_provider_factory_binding_.Bind(mojo::MakeRequest(&ret));
- return ret;
+mojo::PendingRemote<mojom::IsolatedXRGamepadProviderFactory>
+OpenVRDevice::BindGamepadFactory() {
+ return gamepad_provider_factory_receiver_.BindNewPipeAndPassRemote();
}
-mojom::XRCompositorHostPtr OpenVRDevice::BindCompositorHost() {
- mojom::XRCompositorHostPtr ret;
- compositor_host_binding_.Bind(mojo::MakeRequest(&ret));
- return ret;
+mojo::PendingRemote<mojom::XRCompositorHost>
+OpenVRDevice::BindCompositorHost() {
+ return compositor_host_receiver_.BindNewPipeAndPassRemote();
}
OpenVRDevice::~OpenVRDevice() {
@@ -167,7 +163,7 @@ void OpenVRDevice::RequestSession(
mojom::XRRuntimeSessionOptionsPtr options,
mojom::XRRuntime::RequestSessionCallback callback) {
if (!EnsureValidDisplayInfo()) {
- std::move(callback).Run(nullptr, nullptr);
+ std::move(callback).Run(nullptr, mojo::NullRemote());
return;
}
@@ -177,22 +173,22 @@ void OpenVRDevice::RequestSession(
render_loop_->Start();
if (!render_loop_->IsRunning()) {
- std::move(callback).Run(nullptr, nullptr);
+ std::move(callback).Run(nullptr, mojo::NullRemote());
return;
}
- if (provider_request_) {
+ if (provider_receiver_) {
render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestGamepadProvider,
base::Unretained(render_loop_.get()),
- std::move(provider_request_)));
+ std::move(provider_receiver_)));
}
- if (overlay_request_) {
+ if (overlay_receiver_) {
render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
base::Unretained(render_loop_.get()),
- std::move(overlay_request_)));
+ std::move(overlay_receiver_)));
}
}
@@ -207,10 +203,12 @@ void OpenVRDevice::RequestSession(
&OpenVRDevice::OnPresentationEnded, weak_ptr_factory_.GetWeakPtr());
render_loop_->task_runner()->PostTask(
- FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestSession,
- base::Unretained(render_loop_.get()),
- std::move(on_presentation_ended),
- std::move(options), std::move(my_callback)));
+ FROM_HERE,
+ base::BindOnce(&XRCompositorCommon::RequestSession,
+ base::Unretained(render_loop_.get()),
+ std::move(on_presentation_ended),
+ base::DoNothing::Repeatedly<mojom::XRVisibilityState>(),
+ std::move(options), std::move(my_callback)));
outstanding_session_requests_count_++;
}
@@ -253,24 +251,23 @@ void OpenVRDevice::OnRequestSessionResult(
outstanding_session_requests_count_--;
if (!result) {
OnPresentationEnded();
- std::move(callback).Run(nullptr, nullptr);
+ std::move(callback).Run(nullptr, mojo::NullRemote());
return;
}
OnStartPresenting();
- mojom::XRSessionControllerPtr session_controller;
- exclusive_controller_binding_.Bind(mojo::MakeRequest(&session_controller));
+ session->display_info = display_info_.Clone();
+
+ std::move(callback).Run(
+ std::move(session),
+ exclusive_controller_receiver_.BindNewPipeAndPassRemote());
// Use of Unretained is safe because the callback will only occur if the
// binding is not destroyed.
- exclusive_controller_binding_.set_connection_error_handler(
+ exclusive_controller_receiver_.set_disconnect_handler(
base::BindOnce(&OpenVRDevice::OnPresentingControllerMojoConnectionError,
base::Unretained(this)));
-
- session->display_info = display_info_.Clone();
-
- std::move(callback).Run(std::move(session), std::move(session_controller));
}
bool OpenVRDevice::IsAvailable() {
@@ -278,26 +275,26 @@ bool OpenVRDevice::IsAvailable() {
}
void OpenVRDevice::GetIsolatedXRGamepadProvider(
- mojom::IsolatedXRGamepadProviderRequest provider_request) {
+ mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver) {
if (render_loop_->IsRunning()) {
render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestGamepadProvider,
base::Unretained(render_loop_.get()),
- std::move(provider_request)));
+ std::move(provider_receiver)));
} else {
- provider_request_ = std::move(provider_request);
+ provider_receiver_ = std::move(provider_receiver);
}
}
void OpenVRDevice::CreateImmersiveOverlay(
- mojom::ImmersiveOverlayRequest overlay_request) {
+ mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver) {
if (render_loop_->IsRunning()) {
render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
base::Unretained(render_loop_.get()),
- std::move(overlay_request)));
+ std::move(overlay_receiver)));
} else {
- overlay_request_ = std::move(overlay_request);
+ overlay_receiver_ = std::move(overlay_receiver);
}
}
@@ -316,7 +313,7 @@ void OpenVRDevice::OnPresentingControllerMojoConnectionError() {
// TODO(https://crbug.com/875187): Alternatively, we could recreate the
// provider on the next session, or look into why the callback gets lost.
OnExitPresent();
- exclusive_controller_binding_.Close();
+ exclusive_controller_receiver_.reset();
}
// Only deal with events that will cause displayInfo changes for now.
diff --git a/chromium/device/vr/openvr/openvr_device.h b/chromium/device/vr/openvr/openvr_device.h
index d852eea191a..3d02da8e939 100644
--- a/chromium/device/vr/openvr/openvr_device.h
+++ b/chromium/device/vr/openvr/openvr_device.h
@@ -12,7 +12,9 @@
#include "device/vr/openvr/openvr_api_wrapper.h"
#include "device/vr/public/mojom/vr_service.mojom.h"
#include "device/vr/vr_device_base.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
namespace device {
@@ -47,8 +49,9 @@ class DEVICE_VR_EXPORT OpenVRDevice
bool IsAvailable();
- mojom::IsolatedXRGamepadProviderFactoryPtr BindGamepadFactory();
- mojom::XRCompositorHostPtr BindCompositorHost();
+ mojo::PendingRemote<mojom::IsolatedXRGamepadProviderFactory>
+ BindGamepadFactory();
+ mojo::PendingRemote<mojom::XRCompositorHost> BindCompositorHost();
private:
// XRSessionController
@@ -56,11 +59,12 @@ class DEVICE_VR_EXPORT OpenVRDevice
// mojom::IsolatedXRGamepadProviderFactory
void GetIsolatedXRGamepadProvider(
- mojom::IsolatedXRGamepadProviderRequest provider_request) override;
+ mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver)
+ override;
// XRCompositorHost
void CreateImmersiveOverlay(
- mojom::ImmersiveOverlayRequest overlay_request) override;
+ mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver) override;
void OnPresentingControllerMojoConnectionError();
void OnPresentationEnded();
@@ -72,14 +76,15 @@ class DEVICE_VR_EXPORT OpenVRDevice
std::unique_ptr<OpenVRWrapper> openvr_;
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
- mojo::Binding<mojom::XRSessionController> exclusive_controller_binding_;
+ mojo::Receiver<mojom::XRSessionController> exclusive_controller_receiver_{
+ this};
- mojo::Binding<mojom::IsolatedXRGamepadProviderFactory>
- gamepad_provider_factory_binding_;
- mojom::IsolatedXRGamepadProviderRequest provider_request_;
+ mojo::Receiver<mojom::IsolatedXRGamepadProviderFactory>
+ gamepad_provider_factory_receiver_{this};
+ mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver_;
- mojo::Binding<mojom::XRCompositorHost> compositor_host_binding_;
- mojom::ImmersiveOverlayRequest overlay_request_;
+ mojo::Receiver<mojom::XRCompositorHost> compositor_host_receiver_{this};
+ mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver_;
base::WeakPtrFactory<OpenVRDevice> weak_ptr_factory_{this};
diff --git a/chromium/device/vr/openvr/openvr_gamepad_helper.cc b/chromium/device/vr/openvr/openvr_gamepad_helper.cc
index 7f7c6682802..313c0706a9d 100644
--- a/chromium/device/vr/openvr/openvr_gamepad_helper.cc
+++ b/chromium/device/vr/openvr/openvr_gamepad_helper.cc
@@ -351,18 +351,18 @@ class OpenVRGamepadBuilder : public XRStandardGamepadBuilder {
profiles_.push_back(name);
// Also record information about what this controller actually does in a
- // more general sense.
- std::string capabilities = "";
+ // more general sense. The controller is guaranteed to at least have a
+ // trigger if we get here.
+ std::string capabilities = "generic-trigger";
if (HasSecondaryButton()) {
- capabilities += "grip-";
+ capabilities += "-squeeze";
}
if (HasTouchpad()) {
- capabilities += "touchpad-";
+ capabilities += "-touchpad";
}
if (HasThumbstick()) {
- capabilities += "thumbstick-";
+ capabilities += "-thumbstick";
}
- capabilities += "controller";
profiles_.push_back(capabilities);
}
diff --git a/chromium/device/vr/openvr/openvr_render_loop.cc b/chromium/device/vr/openvr/openvr_render_loop.cc
index e3df40e994b..8b13108c747 100644
--- a/chromium/device/vr/openvr/openvr_render_loop.cc
+++ b/chromium/device/vr/openvr/openvr_render_loop.cc
@@ -4,6 +4,7 @@
#include "device/vr/openvr/openvr_render_loop.h"
+#include "base/trace_event/trace_event.h"
#include "device/vr/openvr/openvr_api_wrapper.h"
#include "device/vr/openvr/openvr_gamepad_helper.h"
#include "device/vr/openvr/openvr_type_converters.h"
@@ -290,6 +291,9 @@ std::vector<mojom::XRInputSourceStatePtr> OpenVRRenderLoop::GetInputState(
controller_state, handedness);
state->gamepad = input_source_data.gamepad;
+ // OpenVR controller are fully 6DoF.
+ state->emulated_position = false;
+
// Re-send the controller's description if it's newly active or if the
// handedness or profile strings have changed.
if (newly_active ||
@@ -304,9 +308,6 @@ std::vector<mojom::XRInputSourceStatePtr> OpenVRRenderLoop::GetInputState(
desc->handedness = handedness;
input_active_state.controller_role = controller_role;
- // OpenVR controller are fully 6DoF.
- desc->emulated_position = false;
-
// Tweak the pointer transform so that it's angled down from the
// grip. This should be a bit more ergonomic.
desc->pointer_offset = gfx::Transform();
diff --git a/chromium/device/vr/openxr/openxr_api_wrapper.cc b/chromium/device/vr/openxr/openxr_api_wrapper.cc
index 68e8af15e2c..c3ad215b4d9 100644
--- a/chromium/device/vr/openxr/openxr_api_wrapper.cc
+++ b/chromium/device/vr/openxr/openxr_api_wrapper.cc
@@ -4,13 +4,12 @@
#include "device/vr/openxr/openxr_api_wrapper.h"
-#include <directxmath.h>
#include <stdint.h>
#include <algorithm>
#include <array>
#include "base/logging.h"
-#include "device/vr/openxr/openxr_gamepad_helper.h"
+#include "device/vr/openxr/openxr_input_helper.h"
#include "device/vr/openxr/openxr_util.h"
#include "device/vr/test/test_hook.h"
#include "ui/gfx/geometry/point3_f.h"
@@ -33,6 +32,7 @@ constexpr uint32_t kNumViews = 2;
XrResult CreateInstance(XrInstance* instance) {
XrInstanceCreateInfo instance_create_info = {XR_TYPE_INSTANCE_CREATE_INFO};
strcpy_s(instance_create_info.applicationInfo.applicationName, "Chromium");
+ instance_create_info.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;
// xrCreateInstance validates the list of extensions and returns
// XR_ERROR_EXTENSION_NOT_PRESENT if an extension is not supported,
@@ -116,7 +116,8 @@ void OpenXrApiWrapper::Reset() {
view_configs_.clear();
color_swapchain_images_.clear();
frame_state_ = {};
- views_.clear();
+ origin_from_eye_views_.clear();
+ head_from_eye_views_.clear();
layer_projection_views_.clear();
}
@@ -278,7 +279,7 @@ XrResult OpenXrApiWrapper::PickEnvironmentBlendMode(XrSystemId system) {
// objects that may have been created before the failure.
XrResult OpenXrApiWrapper::InitSession(
const Microsoft::WRL::ComPtr<ID3D11Device>& d3d_device,
- std::unique_ptr<OpenXrGamepadHelper>* gamepad_helper) {
+ std::unique_ptr<OpenXRInputHelper>* input_helper) {
DCHECK(d3d_device.Get());
DCHECK(IsInitialized());
@@ -289,7 +290,7 @@ XrResult OpenXrApiWrapper::InitSession(
RETURN_IF_XR_FAILED(
CreateSpace(XR_REFERENCE_SPACE_TYPE_LOCAL, &local_space_));
RETURN_IF_XR_FAILED(CreateSpace(XR_REFERENCE_SPACE_TYPE_VIEW, &view_space_));
- RETURN_IF_XR_FAILED(CreateGamepadHelper(gamepad_helper));
+ RETURN_IF_XR_FAILED(CreateGamepadHelper(input_helper));
// It's ok if stage_space_ fails since not all OpenXR devices are required to
// support this reference space.
@@ -298,15 +299,16 @@ XrResult OpenXrApiWrapper::InitSession(
// Since the objects in these arrays are used on every frame,
// we don't want to create and destroy these objects every frame,
// so create the number of objects we need and reuse them.
- views_.resize(view_configs_.size());
- layer_projection_views_.resize(view_configs_.size());
+ origin_from_eye_views_.resize(kNumViews);
+ head_from_eye_views_.resize(kNumViews);
+ layer_projection_views_.resize(kNumViews);
// Make sure all of the objects we initialized are there.
DCHECK(HasSession());
DCHECK(HasColorSwapChain());
DCHECK(HasSpace(XR_REFERENCE_SPACE_TYPE_LOCAL));
DCHECK(HasSpace(XR_REFERENCE_SPACE_TYPE_VIEW));
- DCHECK(gamepad_helper);
+ DCHECK(input_helper);
return xr_result;
}
@@ -387,12 +389,12 @@ XrResult OpenXrApiWrapper::CreateSpace(XrReferenceSpaceType type,
}
XrResult OpenXrApiWrapper::CreateGamepadHelper(
- std::unique_ptr<OpenXrGamepadHelper>* gamepad_helper) {
+ std::unique_ptr<OpenXRInputHelper>* input_helper) {
DCHECK(HasSession());
DCHECK(HasSpace(XR_REFERENCE_SPACE_TYPE_LOCAL));
- return OpenXrGamepadHelper::CreateOpenXrGamepadHelper(
- instance_, session_, local_space_, gamepad_helper);
+ return OpenXRInputHelper::CreateOpenXRInputHelper(instance_, session_,
+ local_space_, input_helper);
}
XrResult OpenXrApiWrapper::BeginSession() {
@@ -456,7 +458,7 @@ XrResult OpenXrApiWrapper::EndFrame() {
XrCompositionLayerProjection* multi_projection_layer_ptr =
&multi_projection_layer;
multi_projection_layer.space = local_space_;
- multi_projection_layer.viewCount = views_.size();
+ multi_projection_layer.viewCount = origin_from_eye_views_.size();
multi_projection_layer.views = layer_projection_views_.data();
XrFrameEndInfo end_frame_info = {XR_TYPE_FRAME_END_INFO};
@@ -475,25 +477,15 @@ XrResult OpenXrApiWrapper::EndFrame() {
XrResult OpenXrApiWrapper::UpdateProjectionLayers() {
XrResult xr_result;
- XrViewState view_state = {XR_TYPE_VIEW_STATE};
-
- XrViewLocateInfo view_locate_info = {XR_TYPE_VIEW_LOCATE_INFO};
-
- view_locate_info.viewConfigurationType = kSupportedViewConfiguration;
- view_locate_info.displayTime = frame_state_.predictedDisplayTime;
- view_locate_info.space = local_space_;
-
- uint32_t view_count = 0;
- RETURN_IF_XR_FAILED(xrLocateViews(session_, &view_locate_info, &view_state,
- views_.size(), &view_count, views_.data()));
+ RETURN_IF_XR_FAILED(
+ LocateViews(XR_REFERENCE_SPACE_TYPE_LOCAL, &origin_from_eye_views_));
+ RETURN_IF_XR_FAILED(
+ LocateViews(XR_REFERENCE_SPACE_TYPE_VIEW, &head_from_eye_views_));
gfx::Size view_size = GetViewSize();
-
- DCHECK(view_count <= views_.size());
- DCHECK(view_count <= layer_projection_views_.size());
-
- for (uint32_t view_index = 0; view_index < view_count; view_index++) {
- const XrView& view = views_[view_index];
+ for (uint32_t view_index = 0; view_index < origin_from_eye_views_.size();
+ view_index++) {
+ const XrView& view = origin_from_eye_views_[view_index];
XrCompositionLayerProjectionView& layer_projection_view =
layer_projection_views_[view_index];
@@ -516,6 +508,47 @@ XrResult OpenXrApiWrapper::UpdateProjectionLayers() {
return xr_result;
}
+XrResult OpenXrApiWrapper::LocateViews(XrReferenceSpaceType type,
+ std::vector<XrView>* views) const {
+ DCHECK(HasSession());
+
+ XrResult xr_result;
+
+ XrViewState view_state = {XR_TYPE_VIEW_STATE};
+ XrViewLocateInfo view_locate_info = {XR_TYPE_VIEW_LOCATE_INFO};
+ view_locate_info.viewConfigurationType = kSupportedViewConfiguration;
+ view_locate_info.displayTime = frame_state_.predictedDisplayTime;
+
+ switch (type) {
+ case XR_REFERENCE_SPACE_TYPE_LOCAL:
+ view_locate_info.space = local_space_;
+ break;
+ case XR_REFERENCE_SPACE_TYPE_VIEW:
+ view_locate_info.space = view_space_;
+ break;
+ case XR_REFERENCE_SPACE_TYPE_STAGE:
+ case XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT:
+ case XR_REFERENCE_SPACE_TYPE_MAX_ENUM:
+ NOTREACHED();
+ }
+
+ std::vector<XrView> new_views(kNumViews);
+ uint32_t view_count;
+ RETURN_IF_XR_FAILED(xrLocateViews(session_, &view_locate_info, &view_state,
+ new_views.size(), &view_count,
+ new_views.data()));
+ DCHECK(view_count == kNumViews);
+
+ // If the position or orientation is not valid, don't update the views so that
+ // the previous valid views are used instead.
+ if ((view_state.viewStateFlags & XR_VIEW_STATE_POSITION_VALID_BIT) &&
+ (view_state.viewStateFlags & XR_VIEW_STATE_ORIENTATION_VALID_BIT)) {
+ *views = std::move(new_views);
+ }
+
+ return xr_result;
+}
+
bool OpenXrApiWrapper::HasPosition() const {
DCHECK(IsInitialized());
@@ -544,21 +577,23 @@ XrResult OpenXrApiWrapper::GetHeadPose(
XrResult xr_result;
- XrSpaceLocation location = {XR_TYPE_SPACE_LOCATION};
- RETURN_IF_XR_FAILED(xrLocateSpace(
- view_space_, local_space_, frame_state_.predictedDisplayTime, &location));
+ XrSpaceLocation view_from_local = {XR_TYPE_SPACE_LOCATION};
+ RETURN_IF_XR_FAILED(xrLocateSpace(view_space_, local_space_,
+ frame_state_.predictedDisplayTime,
+ &view_from_local));
- if (location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) {
+ if (view_from_local.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) {
*orientation = gfx::Quaternion(
- location.pose.orientation.x, location.pose.orientation.y,
- location.pose.orientation.z, location.pose.orientation.w);
+ view_from_local.pose.orientation.x, view_from_local.pose.orientation.y,
+ view_from_local.pose.orientation.z, view_from_local.pose.orientation.w);
} else {
*orientation = base::nullopt;
}
- if (location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) {
- *position = gfx::Point3F(location.pose.position.x, location.pose.position.y,
- location.pose.position.z);
+ if (view_from_local.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) {
+ *position = gfx::Point3F(view_from_local.pose.position.x,
+ view_from_local.pose.position.y,
+ view_from_local.pose.position.z);
} else {
*position = base::nullopt;
}
@@ -566,6 +601,13 @@ XrResult OpenXrApiWrapper::GetHeadPose(
return xr_result;
}
+void OpenXrApiWrapper::GetHeadFromEyes(XrView* left, XrView* right) const {
+ DCHECK(HasSession());
+
+ *left = head_from_eye_views_[0];
+ *right = head_from_eye_views_[1];
+}
+
XrResult OpenXrApiWrapper::GetLuid(LUID* luid) const {
DCHECK(IsInitialized());
@@ -648,17 +690,6 @@ std::string OpenXrApiWrapper::GetRuntimeName() const {
}
}
-const XrView& OpenXrApiWrapper::GetView(uint32_t index) const {
- DCHECK(HasSession());
-
- // XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO so the OpenXR runtime must have
- // returned two view configurations.
- DCHECK(views_.size() == kNumViews);
- DCHECK(index < kNumViews);
-
- return views_[index];
-}
-
XrResult OpenXrApiWrapper::GetStageBounds(XrExtent2Df* stage_bounds) const {
DCHECK(stage_bounds);
DCHECK(HasSession());
@@ -667,10 +698,11 @@ XrResult OpenXrApiWrapper::GetStageBounds(XrExtent2Df* stage_bounds) const {
stage_bounds);
}
-bool OpenXrApiWrapper::GetStageParameters(XrExtent2Df* stage_bounds,
- gfx::Transform* transform) const {
+bool OpenXrApiWrapper::GetStageParameters(
+ XrExtent2Df* stage_bounds,
+ gfx::Transform* local_from_stage) const {
DCHECK(stage_bounds);
- DCHECK(transform);
+ DCHECK(local_from_stage);
DCHECK(HasSession());
if (!HasSpace(XR_REFERENCE_SPACE_TYPE_LOCAL))
@@ -682,25 +714,33 @@ bool OpenXrApiWrapper::GetStageParameters(XrExtent2Df* stage_bounds,
if (XR_FAILED(GetStageBounds(stage_bounds)))
return false;
- XrSpaceLocation location = {XR_TYPE_SPACE_LOCATION};
- if (FAILED(xrLocateSpace(stage_space_, local_space_,
- frame_state_.predictedDisplayTime, &location)) ||
- !(location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) ||
- !(location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT)) {
+ XrSpaceLocation local_from_stage_location = {XR_TYPE_SPACE_LOCATION};
+ if (FAILED(xrLocateSpace(local_space_, stage_space_,
+ frame_state_.predictedDisplayTime,
+ &local_from_stage_location)) ||
+ !(local_from_stage_location.locationFlags &
+ XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) ||
+ !(local_from_stage_location.locationFlags &
+ XR_SPACE_LOCATION_POSITION_VALID_BIT)) {
return false;
}
// Convert the orientation and translation given by runtime into a
// transformation matrix.
- gfx::DecomposedTransform seat_to_standing_decomp;
- seat_to_standing_decomp.quaternion =
- gfx::Quaternion(location.pose.orientation.x, location.pose.orientation.y,
- location.pose.orientation.z, location.pose.orientation.w);
- seat_to_standing_decomp.translate[0] = location.pose.position.x;
- seat_to_standing_decomp.translate[1] = location.pose.position.y;
- seat_to_standing_decomp.translate[2] = location.pose.position.z;
-
- *transform = gfx::ComposeTransform(seat_to_standing_decomp);
+ gfx::DecomposedTransform local_from_stage_decomp;
+ local_from_stage_decomp.quaternion =
+ gfx::Quaternion(local_from_stage_location.pose.orientation.x,
+ local_from_stage_location.pose.orientation.y,
+ local_from_stage_location.pose.orientation.z,
+ local_from_stage_location.pose.orientation.w);
+ local_from_stage_decomp.translate[0] =
+ local_from_stage_location.pose.position.x;
+ local_from_stage_decomp.translate[1] =
+ local_from_stage_location.pose.position.y;
+ local_from_stage_decomp.translate[2] =
+ local_from_stage_location.pose.position.z;
+
+ *local_from_stage = gfx::ComposeTransform(local_from_stage_decomp);
return true;
}
diff --git a/chromium/device/vr/openxr/openxr_api_wrapper.h b/chromium/device/vr/openxr/openxr_api_wrapper.h
index 3c64f5bbcab..24ed4616b3a 100644
--- a/chromium/device/vr/openxr/openxr_api_wrapper.h
+++ b/chromium/device/vr/openxr/openxr_api_wrapper.h
@@ -26,7 +26,7 @@ class Transform;
namespace device {
-class OpenXrGamepadHelper;
+class OpenXRInputHelper;
class VRTestHook;
class ServiceTestHook;
@@ -46,22 +46,22 @@ class OpenXrApiWrapper {
bool session_ended() const { return session_ended_; }
XrResult InitSession(const Microsoft::WRL::ComPtr<ID3D11Device>& d3d_device,
- std::unique_ptr<OpenXrGamepadHelper>* gamepad_helper);
+ std::unique_ptr<OpenXRInputHelper>* input_helper);
XrResult BeginFrame(Microsoft::WRL::ComPtr<ID3D11Texture2D>* texture);
XrResult EndFrame();
XrResult GetHeadPose(base::Optional<gfx::Quaternion>* orientation,
base::Optional<gfx::Point3F>* position) const;
+ void GetHeadFromEyes(XrView* left, XrView* right) const;
bool HasPosition() const;
gfx::Size GetViewSize() const;
- const XrView& GetView(uint32_t index) const;
XrTime GetPredictedDisplayTime() const;
XrResult GetLuid(LUID* luid) const;
std::string GetRuntimeName() const;
bool GetStageParameters(XrExtent2Df* stage_bounds,
- gfx::Transform* standing_transform) const;
+ gfx::Transform* local_from_stage) const;
static void DEVICE_VR_EXPORT SetTestHook(VRTestHook* hook);
@@ -79,10 +79,12 @@ class OpenXrApiWrapper {
XrResult CreateSwapchain();
XrResult CreateSpace(XrReferenceSpaceType type, XrSpace* space);
XrResult CreateGamepadHelper(
- std::unique_ptr<OpenXrGamepadHelper>* gamepad_helper);
+ std::unique_ptr<OpenXRInputHelper>* input_helper);
XrResult BeginSession();
XrResult UpdateProjectionLayers();
+ XrResult LocateViews(XrReferenceSpaceType type,
+ std::vector<XrView>* views) const;
bool HasInstance() const;
bool HasSystem() const;
@@ -121,7 +123,8 @@ class OpenXrApiWrapper {
// These objects store information about the current frame. They're
// valid only while a session is active, and they are updated each frame.
XrFrameState frame_state_;
- std::vector<XrView> views_;
+ std::vector<XrView> origin_from_eye_views_;
+ std::vector<XrView> head_from_eye_views_;
std::vector<XrCompositionLayerProjectionView> layer_projection_views_;
DISALLOW_COPY_AND_ASSIGN(OpenXrApiWrapper);
diff --git a/chromium/device/vr/openxr/openxr_controller.cc b/chromium/device/vr/openxr/openxr_controller.cc
index 4fae1658b5c..f8e64e1c0f2 100644
--- a/chromium/device/vr/openxr/openxr_controller.cc
+++ b/chromium/device/vr/openxr/openxr_controller.cc
@@ -7,8 +7,12 @@
#include <stdint.h>
#include "base/logging.h"
+#include "device/gamepad/public/cpp/gamepads.h"
#include "device/vr/openxr/openxr_util.h"
#include "device/vr/public/mojom/vr_service.mojom.h"
+#include "device/vr/util/xr_standard_gamepad_builder.h"
+#include "ui/gfx/geometry/quaternion.h"
+#include "ui/gfx/transform_util.h"
namespace device {
@@ -17,22 +21,32 @@ namespace {
constexpr char kMicrosoftInteractionProfileName[] =
"/interaction_profiles/microsoft/motion_controller";
-const char* GetStringFromType(OpenXrControllerType type) {
+const char* GetStringFromType(OpenXrHandednessType type) {
switch (type) {
- case OpenXrControllerType::kLeft:
+ case OpenXrHandednessType::kLeft:
return "left";
- case OpenXrControllerType::kRight:
+ case OpenXrHandednessType::kRight:
return "right";
- default:
+ case OpenXrHandednessType::kCount:
NOTREACHED();
return "";
}
}
+mojom::XRGamepadButtonPtr GetXRGamepadButtonPtr(
+ base::Optional<GamepadButton> button) {
+ mojom::XRGamepadButtonPtr ret = mojom::XRGamepadButton::New();
+ ret->pressed = button->pressed;
+ ret->touched = button->touched;
+ ret->value = button->value;
+ return ret;
+}
+
} // namespace
OpenXrController::OpenXrController()
- : type_(OpenXrControllerType::kCount), // COUNT refers to invalid.
+ : description_(nullptr),
+ type_(OpenXrHandednessType::kCount), // COUNT refers to invalid.
session_(XR_NULL_HANDLE),
action_set_(XR_NULL_HANDLE),
grip_pose_action_{XR_NULL_HANDLE},
@@ -51,15 +65,15 @@ OpenXrController::~OpenXrController() {
}
XrResult OpenXrController::Initialize(
- OpenXrControllerType type,
+ OpenXrHandednessType type,
XrInstance instance,
XrSession session,
std::map<XrPath, std::vector<XrActionSuggestedBinding>>* bindings) {
type_ = type;
session_ = session;
- std::string type_string = GetStringFromType(type_);
+ std::string handedness_string = GetStringFromType(type_);
- std::string action_set_name = type_string + "_action_set";
+ std::string action_set_name = handedness_string + "_action_set";
XrActionSetCreateInfo action_set_create_info = {
XR_TYPE_ACTION_SET_CREATE_INFO};
@@ -75,20 +89,15 @@ XrResult OpenXrController::Initialize(
RETURN_IF_XR_FAILED(
xrCreateActionSet(instance, &action_set_create_info, &action_set_));
- RETURN_IF_XR_FAILED(
- InitializeMicrosoftMotionControllers(instance, type_string, bindings));
+ RETURN_IF_XR_FAILED(InitializeMicrosoftMotionControllerActions(
+ instance, handedness_string, bindings));
+
+ RETURN_IF_XR_FAILED(InitializeMicrosoftMotionControllerSpaces());
- XrActionSpaceCreateInfo action_space_create_info = {};
- action_space_create_info.type = XR_TYPE_ACTION_SPACE_CREATE_INFO;
- action_space_create_info.action = grip_pose_action_;
- action_space_create_info.subactionPath = XR_NULL_PATH;
- action_space_create_info.poseInActionSpace = PoseIdentity();
- RETURN_IF_XR_FAILED(xrCreateActionSpace(session_, &action_space_create_info,
- &grip_pose_space_));
return xr_result;
}
-XrResult OpenXrController::InitializeMicrosoftMotionControllers(
+XrResult OpenXrController::InitializeMicrosoftMotionControllerActions(
XrInstance instance,
const std::string& type_string,
std::map<XrPath, std::vector<XrActionSuggestedBinding>>* bindings) {
@@ -99,28 +108,40 @@ XrResult OpenXrController::InitializeMicrosoftMotionControllers(
RETURN_IF_XR_FAILED(CreateAction(
instance, XR_ACTION_TYPE_BOOLEAN_INPUT, kMicrosoftInteractionProfileName,
- binding_prefix + "trackpad/click", name_prefix + "trackpad_button_press",
- &(button_action_map_[OpenXrButtonType::kTrackpad].press_action),
+ binding_prefix + "trigger/value", name_prefix + "trigger_button_press",
+ &(button_action_map_[OpenXrButtonType::kTrigger].press_action),
+ bindings));
+
+ RETURN_IF_XR_FAILED(CreateAction(
+ instance, XR_ACTION_TYPE_FLOAT_INPUT, kMicrosoftInteractionProfileName,
+ binding_prefix + "trigger/value", name_prefix + "trigger_button_value",
+ &(button_action_map_[OpenXrButtonType::kTrigger].value_action),
bindings));
RETURN_IF_XR_FAILED(CreateAction(
instance, XR_ACTION_TYPE_BOOLEAN_INPUT, kMicrosoftInteractionProfileName,
- binding_prefix + "trigger/value", name_prefix + "trigger_button_press",
- &(button_action_map_[OpenXrButtonType::kTrigger].press_action),
+ binding_prefix + "thumbstick/click",
+ name_prefix + "thumbstick_button_press",
+ &(button_action_map_[OpenXrButtonType::kThumbstick].press_action),
bindings));
- // In OpenXR, this input is called 'squeeze'. However, the rest of Chromium
- // uses the term 'grip' for this button, so the OpenXrButtonType is named
- // kGrip for consistency.
RETURN_IF_XR_FAILED(CreateAction(
instance, XR_ACTION_TYPE_BOOLEAN_INPUT, kMicrosoftInteractionProfileName,
binding_prefix + "squeeze/click", name_prefix + "squeeze_button_press",
- &(button_action_map_[OpenXrButtonType::kGrip].press_action), bindings));
+ &(button_action_map_[OpenXrButtonType::kSqueeze].press_action),
+ bindings));
+
+ RETURN_IF_XR_FAILED(CreateAction(
+ instance, XR_ACTION_TYPE_BOOLEAN_INPUT, kMicrosoftInteractionProfileName,
+ binding_prefix + "trackpad/click", name_prefix + "trackpad_button_press",
+ &(button_action_map_[OpenXrButtonType::kTrackpad].press_action),
+ bindings));
RETURN_IF_XR_FAILED(CreateAction(
instance, XR_ACTION_TYPE_BOOLEAN_INPUT, kMicrosoftInteractionProfileName,
- binding_prefix + "menu/click", name_prefix + "menu_button_press",
- &(button_action_map_[OpenXrButtonType::kMenu].press_action), bindings));
+ binding_prefix + "trackpad/touch", name_prefix + "trackpad_button_touch",
+ &(button_action_map_[OpenXrButtonType::kTrackpad].touch_action),
+ bindings));
RETURN_IF_XR_FAILED(CreateAction(
instance, XR_ACTION_TYPE_VECTOR2F_INPUT, kMicrosoftInteractionProfileName,
@@ -137,20 +158,36 @@ XrResult OpenXrController::InitializeMicrosoftMotionControllers(
kMicrosoftInteractionProfileName, binding_prefix + "grip",
name_prefix + "grip_pose", &grip_pose_action_, bindings));
+ RETURN_IF_XR_FAILED(
+ CreateAction(instance, XR_ACTION_TYPE_POSE_INPUT,
+ kMicrosoftInteractionProfileName, binding_prefix + "aim",
+ name_prefix + "aim_pose", &pointer_pose_action_, bindings));
+
+ return xr_result;
+}
+
+XrResult OpenXrController::InitializeMicrosoftMotionControllerSpaces() {
+ XrResult xr_result;
+
+ RETURN_IF_XR_FAILED(CreateActionSpace(grip_pose_action_, &grip_pose_space_));
+
+ RETURN_IF_XR_FAILED(
+ CreateActionSpace(pointer_pose_action_, &pointer_pose_space_));
+
return xr_result;
}
-uint32_t OpenXrController::GetID() const {
+uint32_t OpenXrController::GetId() const {
return static_cast<uint32_t>(type_);
}
device::mojom::XRHandedness OpenXrController::GetHandness() const {
switch (type_) {
- case OpenXrControllerType::kLeft:
+ case OpenXrHandednessType::kLeft:
return device::mojom::XRHandedness::LEFT;
- case OpenXrControllerType::kRight:
+ case OpenXrHandednessType::kRight:
return device::mojom::XRHandedness::RIGHT;
- default:
+ case OpenXrHandednessType::kCount:
// LEFT controller and RIGHT controller are currently the only supported
// controllers. In the future, other controllers such as sound (which
// does not have a handedness) will be added here.
@@ -159,6 +196,32 @@ device::mojom::XRHandedness OpenXrController::GetHandness() const {
}
}
+device::mojom::XRInputSourceDescriptionPtr OpenXrController::GetDescription(
+ XrTime predicted_display_time) {
+ if (!description_) {
+ description_ = device::mojom::XRInputSourceDescription::New();
+ description_->handedness = GetHandness();
+ description_->target_ray_mode = device::mojom::XRTargetRayMode::POINTING;
+ // TODO(crbug.com/1006072):
+ // Query USB vendor and product ID From OpenXR.
+ description_->profiles.push_back("windows-mixed-reality");
+ // This makes it clear that the controller actually has a squeeze button,
+ // trigger button, a touchpad and a thumbstick. Otherwise, it's ambiguous
+ // whether slots like the touchpad buttons + axes are hooked up vs just
+ // placeholders.
+ description_->profiles.push_back(
+ "generic-trigger-squeeze-touchpad-thumbstick");
+ }
+ // pointer_offset only need to be set once unless something changed about
+ // controller.
+ if (!description_->pointer_offset) {
+ description_->pointer_offset =
+ GetPointerFromGripTransform(predicted_display_time);
+ }
+
+ return description_.Clone();
+}
+
std::vector<mojom::XRGamepadButtonPtr> OpenXrController::GetWebVrButtons()
const {
std::vector<mojom::XRGamepadButtonPtr> buttons;
@@ -166,37 +229,51 @@ std::vector<mojom::XRGamepadButtonPtr> OpenXrController::GetWebVrButtons()
constexpr uint32_t kNumButtons =
static_cast<uint32_t>(OpenXrButtonType::kMaxValue) + 1;
for (uint32_t i = 0; i < kNumButtons; i++) {
- mojom::XRGamepadButtonPtr mojo_button_ptr =
+ base::Optional<GamepadButton> button =
GetButton(static_cast<OpenXrButtonType>(i));
- if (!mojo_button_ptr) {
+ if (button) {
+ buttons.push_back(GetXRGamepadButtonPtr(button.value()));
+ } else {
return {};
}
-
- buttons.push_back(std::move(mojo_button_ptr));
}
return buttons;
}
-mojom::XRGamepadButtonPtr OpenXrController::GetButton(
+base::Optional<GamepadButton> OpenXrController::GetButton(
OpenXrButtonType type) const {
+ GamepadButton ret;
+
+ DCHECK(button_action_map_.count(type) == 1);
+
XrActionStateBoolean press_state_bool = {XR_TYPE_ACTION_STATE_BOOLEAN};
if (XR_FAILED(QueryState(button_action_map_.at(type).press_action,
&press_state_bool)) ||
!press_state_bool.isActive) {
- return nullptr;
+ return base::nullopt;
+ }
+ ret.pressed = press_state_bool.currentState;
+
+ XrActionStateBoolean touch_state_bool = {XR_TYPE_ACTION_STATE_BOOLEAN};
+ if (button_action_map_.at(type).touch_action != XR_NULL_HANDLE &&
+ XR_SUCCEEDED(QueryState(button_action_map_.at(type).touch_action,
+ &touch_state_bool)) &&
+ touch_state_bool.isActive) {
+ ret.touched = touch_state_bool.currentState;
+ } else {
+ ret.touched = ret.pressed;
}
- return GetGamepadButton(press_state_bool);
-}
-
-mojom::XRGamepadButtonPtr OpenXrController::GetGamepadButton(
- const XrActionStateBoolean& action_state) const {
- mojom::XRGamepadButtonPtr ret = mojom::XRGamepadButton::New();
- bool button_pressed = action_state.currentState;
- ret->touched = button_pressed;
- ret->pressed = button_pressed;
- ret->value = button_pressed ? 1.0 : 0.0;
+ XrActionStateFloat value_state_float = {XR_TYPE_ACTION_STATE_FLOAT};
+ if (button_action_map_.at(type).value_action != XR_NULL_HANDLE &&
+ XR_SUCCEEDED(QueryState(button_action_map_.at(type).value_action,
+ &value_state_float)) &&
+ value_state_float.isActive) {
+ ret.value = value_state_float.currentState;
+ } else {
+ ret.value = ret.pressed ? 1.0 : 0.0;
+ }
return ret;
}
@@ -237,43 +314,85 @@ mojom::VRPosePtr OpenXrController::GetPose(XrTime predicted_display_time,
return nullptr;
}
- XrSpaceVelocity velocity = {XR_TYPE_SPACE_VELOCITY};
- XrSpaceLocation space_location = {XR_TYPE_SPACE_LOCATION};
- space_location.next = &velocity;
+ XrSpaceVelocity local_from_grip_speed = {XR_TYPE_SPACE_VELOCITY};
+ XrSpaceLocation local_from_grip = {XR_TYPE_SPACE_LOCATION};
+ local_from_grip.next = &local_from_grip_speed;
if (XR_FAILED(xrLocateSpace(grip_pose_space_, local_space,
- predicted_display_time, &space_location))) {
+ predicted_display_time, &local_from_grip))) {
return nullptr;
}
mojom::VRPosePtr pose = mojom::VRPose::New();
- if (space_location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) {
- pose->position = gfx::Point3F(space_location.pose.position.x,
- space_location.pose.position.y,
- space_location.pose.position.z);
+ if (local_from_grip.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT) {
+ pose->position = gfx::Point3F(local_from_grip.pose.position.x,
+ local_from_grip.pose.position.y,
+ local_from_grip.pose.position.z);
}
- if (space_location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) {
+ if (local_from_grip.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) {
pose->orientation = gfx::Quaternion(
- space_location.pose.orientation.x, space_location.pose.orientation.y,
- space_location.pose.orientation.z, space_location.pose.orientation.w);
+ local_from_grip.pose.orientation.x, local_from_grip.pose.orientation.y,
+ local_from_grip.pose.orientation.z, local_from_grip.pose.orientation.w);
}
- if (velocity.velocityFlags & XR_SPACE_VELOCITY_LINEAR_VALID_BIT) {
+ if (local_from_grip_speed.velocityFlags &
+ XR_SPACE_VELOCITY_LINEAR_VALID_BIT) {
pose->linear_velocity =
- gfx::Vector3dF(velocity.linearVelocity.x, velocity.linearVelocity.y,
- velocity.linearVelocity.z);
+ gfx::Vector3dF(local_from_grip_speed.linearVelocity.x,
+ local_from_grip_speed.linearVelocity.y,
+ local_from_grip_speed.linearVelocity.z);
}
- if (velocity.velocityFlags & XR_SPACE_VELOCITY_ANGULAR_VALID_BIT) {
+ if (local_from_grip_speed.velocityFlags &
+ XR_SPACE_VELOCITY_ANGULAR_VALID_BIT) {
pose->angular_velocity =
- gfx::Vector3dF(velocity.angularVelocity.x, velocity.angularVelocity.y,
- velocity.angularVelocity.z);
+ gfx::Vector3dF(local_from_grip_speed.angularVelocity.x,
+ local_from_grip_speed.angularVelocity.y,
+ local_from_grip_speed.angularVelocity.z);
}
return pose;
}
+base::Optional<gfx::Transform> OpenXrController::GetMojoFromGripTransform(
+ XrTime predicted_display_time,
+ XrSpace local_space) const {
+ return GetTransformFromSpaces(predicted_display_time, grip_pose_space_,
+ local_space);
+}
+
+base::Optional<gfx::Transform> OpenXrController::GetPointerFromGripTransform(
+ XrTime predicted_display_time) const {
+ return GetTransformFromSpaces(predicted_display_time, pointer_pose_space_,
+ grip_pose_space_);
+}
+
+base::Optional<gfx::Transform> OpenXrController::GetTransformFromSpaces(
+ XrTime predicted_display_time,
+ XrSpace target,
+ XrSpace origin) const {
+ XrSpaceLocation location = {XR_TYPE_SPACE_LOCATION};
+ if (FAILED(
+ xrLocateSpace(target, origin, predicted_display_time, &location)) ||
+ !(location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT) ||
+ !(location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT)) {
+ return base::nullopt;
+ }
+
+ // Convert the orientation and translation given by runtime into a
+ // transformation matrix.
+ gfx::DecomposedTransform decomp;
+ decomp.quaternion =
+ gfx::Quaternion(location.pose.orientation.x, location.pose.orientation.y,
+ location.pose.orientation.z, location.pose.orientation.w);
+ decomp.translate[0] = location.pose.position.x;
+ decomp.translate[1] = location.pose.position.y;
+ decomp.translate[2] = location.pose.position.z;
+
+ return gfx::ComposeTransform(decomp);
+}
+
XrActionSet OpenXrController::GetActionSet() const {
return action_set_;
}
@@ -308,4 +427,13 @@ XrResult OpenXrController::CreateAction(
return xr_result;
}
+XrResult OpenXrController::CreateActionSpace(XrAction action, XrSpace* space) {
+ XrActionSpaceCreateInfo action_space_create_info = {};
+ action_space_create_info.type = XR_TYPE_ACTION_SPACE_CREATE_INFO;
+ action_space_create_info.action = action;
+ action_space_create_info.subactionPath = XR_NULL_PATH;
+ action_space_create_info.poseInActionSpace = PoseIdentity();
+ return xrCreateActionSpace(session_, &action_space_create_info, space);
+}
+
} // namespace device
diff --git a/chromium/device/vr/openxr/openxr_controller.h b/chromium/device/vr/openxr/openxr_controller.h
index 7b430173111..8d836b41ce4 100644
--- a/chromium/device/vr/openxr/openxr_controller.h
+++ b/chromium/device/vr/openxr/openxr_controller.h
@@ -8,15 +8,16 @@
#include <stdint.h>
#include <unordered_map>
+#include "base/optional.h"
#include "device/vr/public/mojom/isolated_xr_service.mojom.h"
-#include "device/vr/util/gamepad_builder.h"
#include "third_party/openxr/src/include/openxr/openxr.h"
+#include "ui/gfx/transform.h"
namespace device {
constexpr uint32_t kAxisDimensions = 2;
-enum class OpenXrControllerType {
+enum class OpenXrHandednessType {
kLeft = 0,
kRight = 1,
kCount = 2,
@@ -24,9 +25,9 @@ enum class OpenXrControllerType {
enum class OpenXrButtonType {
kTrigger = 0,
- kTrackpad = 1,
- kGrip = 2,
- kMenu = 3,
+ kSqueeze = 1,
+ kTrackpad = 2,
+ kThumbstick = 3,
kMaxValue = 3,
};
@@ -42,34 +43,50 @@ class OpenXrController {
~OpenXrController();
XrResult Initialize(
- OpenXrControllerType type,
+ OpenXrHandednessType type,
XrInstance instance,
XrSession session,
std::map<XrPath, std::vector<XrActionSuggestedBinding>>* bindings);
XrActionSet GetActionSet() const;
- uint32_t GetID() const;
+ uint32_t GetId() const;
device::mojom::XRHandedness GetHandness() const;
+ device::mojom::XRInputSourceDescriptionPtr GetDescription(
+ XrTime predicted_display_time);
+
+ base::Optional<GamepadButton> GetButton(OpenXrButtonType type) const;
std::vector<mojom::XRGamepadButtonPtr> GetWebVrButtons() const;
+ std::vector<double> GetAxis(OpenXrAxisType type) const;
std::vector<double> GetWebVrAxes() const;
mojom::VRPosePtr GetPose(XrTime predicted_display_time,
XrSpace local_space) const;
+ base::Optional<gfx::Transform> GetMojoFromGripTransform(
+ XrTime predicted_display_time,
+ XrSpace local_space) const;
+
private:
// ActionButton struct is used to store all XrAction that is related to the
// button. For example, we may need to query the analog value for button press
// which require a seperate XrAction than the current boolean XrAction.
struct ActionButton {
XrAction press_action;
- ActionButton() : press_action(XR_NULL_HANDLE) {}
+ XrAction touch_action;
+ XrAction value_action;
+ ActionButton()
+ : press_action(XR_NULL_HANDLE),
+ touch_action(XR_NULL_HANDLE),
+ value_action(XR_NULL_HANDLE) {}
};
- XrResult InitializeMicrosoftMotionControllers(
+ XrResult InitializeMicrosoftMotionControllerActions(
XrInstance instance,
const std::string& type_string,
std::map<XrPath, std::vector<XrActionSuggestedBinding>>* bindings);
+ XrResult InitializeMicrosoftMotionControllerSpaces();
+
XrResult CreateAction(
XrInstance instance,
XrActionType type,
@@ -79,6 +96,16 @@ class OpenXrController {
XrAction* action,
std::map<XrPath, std::vector<XrActionSuggestedBinding>>* bindings);
+ XrResult CreateActionSpace(XrAction action, XrSpace* space);
+
+ base::Optional<gfx::Transform> GetPointerFromGripTransform(
+ XrTime predicted_display_time) const;
+
+ base::Optional<gfx::Transform> GetTransformFromSpaces(
+ XrTime predicted_display_time,
+ XrSpace target,
+ XrSpace origin) const;
+
template <typename T>
XrResult QueryState(XrAction action, T* action_state) const {
// this function should never be called because each valid XrActionState
@@ -88,6 +115,16 @@ class OpenXrController {
}
template <>
+ XrResult QueryState<XrActionStateFloat>(
+ XrAction action,
+ XrActionStateFloat* action_state) const {
+ action_state->type = XR_TYPE_ACTION_STATE_FLOAT;
+ XrActionStateGetInfo get_info = {XR_TYPE_ACTION_STATE_GET_INFO};
+ get_info.action = action;
+ return xrGetActionStateFloat(session_, &get_info, action_state);
+ }
+
+ template <>
XrResult QueryState<XrActionStateBoolean>(
XrAction action,
XrActionStateBoolean* action_state) const {
@@ -117,16 +154,15 @@ class OpenXrController {
return xrGetActionStatePose(session_, &get_info, action_state);
}
- std::vector<double> GetAxis(OpenXrAxisType type) const;
- mojom::XRGamepadButtonPtr GetButton(OpenXrButtonType type) const;
- mojom::XRGamepadButtonPtr GetGamepadButton(
- const XrActionStateBoolean& action_state) const;
+ device::mojom::XRInputSourceDescriptionPtr description_;
- OpenXrControllerType type_;
+ OpenXrHandednessType type_;
XrSession session_;
XrActionSet action_set_;
XrAction grip_pose_action_;
XrSpace grip_pose_space_;
+ XrAction pointer_pose_action_;
+ XrSpace pointer_pose_space_;
std::unordered_map<OpenXrButtonType, ActionButton> button_action_map_;
std::unordered_map<OpenXrAxisType, XrAction> axis_action_map_;
diff --git a/chromium/device/vr/openxr/openxr_device.cc b/chromium/device/vr/openxr/openxr_device.cc
index 2983f9ce7ca..edfa4dc9097 100644
--- a/chromium/device/vr/openxr/openxr_device.cc
+++ b/chromium/device/vr/openxr/openxr_device.cc
@@ -10,6 +10,7 @@
#include "device/vr/openxr/openxr_api_wrapper.h"
#include "device/vr/openxr/openxr_render_loop.h"
#include "device/vr/util/transform_utils.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
namespace device {
@@ -85,9 +86,6 @@ bool OpenXrDevice::IsApiAvailable() {
OpenXrDevice::OpenXrDevice()
: VRDeviceBase(device::mojom::XRDeviceId::OPENXR_DEVICE_ID),
- exclusive_controller_binding_(this),
- gamepad_provider_factory_binding_(this),
- compositor_host_binding_(this),
weak_ptr_factory_(this) {
SetVRDisplayInfo(CreateFakeVRDisplayInfo(GetId()));
}
@@ -101,16 +99,14 @@ OpenXrDevice::~OpenXrDevice() {
}
}
-mojom::IsolatedXRGamepadProviderFactoryPtr OpenXrDevice::BindGamepadFactory() {
- mojom::IsolatedXRGamepadProviderFactoryPtr ret;
- gamepad_provider_factory_binding_.Bind(mojo::MakeRequest(&ret));
- return ret;
+mojo::PendingRemote<mojom::IsolatedXRGamepadProviderFactory>
+OpenXrDevice::BindGamepadFactory() {
+ return gamepad_provider_factory_receiver_.BindNewPipeAndPassRemote();
}
-mojom::XRCompositorHostPtr OpenXrDevice::BindCompositorHost() {
- mojom::XRCompositorHostPtr ret;
- compositor_host_binding_.Bind(mojo::MakeRequest(&ret));
- return ret;
+mojo::PendingRemote<mojom::XRCompositorHost>
+OpenXrDevice::BindCompositorHost() {
+ return compositor_host_receiver_.BindNewPipeAndPassRemote();
}
void OpenXrDevice::EnsureRenderLoop() {
@@ -132,22 +128,22 @@ void OpenXrDevice::RequestSession(
render_loop_->Start();
if (!render_loop_->IsRunning()) {
- std::move(callback).Run(nullptr, nullptr);
+ std::move(callback).Run(nullptr, mojo::NullRemote());
return;
}
- if (provider_request_) {
+ if (provider_receiver_) {
render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestGamepadProvider,
base::Unretained(render_loop_.get()),
- std::move(provider_request_)));
+ std::move(provider_receiver_)));
}
- if (overlay_request_) {
+ if (overlay_receiver_) {
render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
base::Unretained(render_loop_.get()),
- std::move(overlay_request_)));
+ std::move(overlay_receiver_)));
}
}
@@ -160,10 +156,12 @@ void OpenXrDevice::RequestSession(
// a method and cannot take nullptr, so passing in base::DoNothing::Once()
// for on_presentation_ended
render_loop_->task_runner()->PostTask(
- FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestSession,
- base::Unretained(render_loop_.get()),
- base::DoNothing::Once(), std::move(options),
- std::move(my_callback)));
+ FROM_HERE,
+ base::BindOnce(&XRCompositorCommon::RequestSession,
+ base::Unretained(render_loop_.get()),
+ base::DoNothing::Once(),
+ base::DoNothing::Repeatedly<mojom::XRVisibilityState>(),
+ std::move(options), std::move(my_callback)));
}
void OpenXrDevice::OnRequestSessionResult(
@@ -171,21 +169,12 @@ void OpenXrDevice::OnRequestSessionResult(
bool result,
mojom::XRSessionPtr session) {
if (!result) {
- std::move(callback).Run(nullptr, nullptr);
+ std::move(callback).Run(nullptr, mojo::NullRemote());
return;
}
OnStartPresenting();
- mojom::XRSessionControllerPtr session_controller;
- exclusive_controller_binding_.Bind(mojo::MakeRequest(&session_controller));
-
- // Use of Unretained is safe because the callback will only occur if the
- // binding is not destroyed.
- exclusive_controller_binding_.set_connection_error_handler(
- base::BindOnce(&OpenXrDevice::OnPresentingControllerMojoConnectionError,
- base::Unretained(this)));
-
EnsureRenderLoop();
gfx::Size view_size = render_loop_->GetViewSize();
display_info_->left_eye->render_width = view_size.width();
@@ -194,7 +183,15 @@ void OpenXrDevice::OnRequestSessionResult(
display_info_->right_eye->render_height = view_size.height();
session->display_info = display_info_.Clone();
- std::move(callback).Run(std::move(session), std::move(session_controller));
+ std::move(callback).Run(
+ std::move(session),
+ exclusive_controller_receiver_.BindNewPipeAndPassRemote());
+
+ // Use of Unretained is safe because the callback will only occur if the
+ // binding is not destroyed.
+ exclusive_controller_receiver_.set_disconnect_handler(
+ base::BindOnce(&OpenXrDevice::OnPresentingControllerMojoConnectionError,
+ base::Unretained(this)));
}
void OpenXrDevice::OnPresentingControllerMojoConnectionError() {
@@ -206,7 +203,7 @@ void OpenXrDevice::OnPresentingControllerMojoConnectionError() {
base::Unretained(render_loop_.get())));
}
OnExitPresent();
- exclusive_controller_binding_.Close();
+ exclusive_controller_receiver_.reset();
}
void OpenXrDevice::SetFrameDataRestricted(bool restricted) {
@@ -215,28 +212,28 @@ void OpenXrDevice::SetFrameDataRestricted(bool restricted) {
}
void OpenXrDevice::GetIsolatedXRGamepadProvider(
- mojom::IsolatedXRGamepadProviderRequest provider_request) {
+ mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver) {
EnsureRenderLoop();
if (render_loop_->IsRunning()) {
render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestGamepadProvider,
base::Unretained(render_loop_.get()),
- std::move(provider_request)));
+ std::move(provider_receiver)));
} else {
- provider_request_ = std::move(provider_request);
+ provider_receiver_ = std::move(provider_receiver);
}
}
void OpenXrDevice::CreateImmersiveOverlay(
- mojom::ImmersiveOverlayRequest overlay_request) {
+ mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver) {
EnsureRenderLoop();
if (render_loop_->IsRunning()) {
render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
base::Unretained(render_loop_.get()),
- std::move(overlay_request)));
+ std::move(overlay_receiver)));
} else {
- overlay_request_ = std::move(overlay_request);
+ overlay_receiver_ = std::move(overlay_receiver);
}
}
diff --git a/chromium/device/vr/openxr/openxr_device.h b/chromium/device/vr/openxr/openxr_device.h
index 3f4706c19a3..c9fa1dd4174 100644
--- a/chromium/device/vr/openxr/openxr_device.h
+++ b/chromium/device/vr/openxr/openxr_device.h
@@ -10,6 +10,9 @@
#include "base/macros.h"
#include "device/vr/public/mojom/vr_service.mojom.h"
#include "device/vr/vr_device_base.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
namespace device {
@@ -32,8 +35,9 @@ class DEVICE_VR_EXPORT OpenXrDevice
mojom::XRRuntimeSessionOptionsPtr options,
mojom::XRRuntime::RequestSessionCallback callback) override;
- mojom::IsolatedXRGamepadProviderFactoryPtr BindGamepadFactory();
- mojom::XRCompositorHostPtr BindCompositorHost();
+ mojo::PendingRemote<mojom::IsolatedXRGamepadProviderFactory>
+ BindGamepadFactory();
+ mojo::PendingRemote<mojom::XRCompositorHost> BindCompositorHost();
private:
// XRSessionController
@@ -41,11 +45,12 @@ class DEVICE_VR_EXPORT OpenXrDevice
// mojom::IsolatedXRGamepadProviderFactory
void GetIsolatedXRGamepadProvider(
- mojom::IsolatedXRGamepadProviderRequest provider_request) override;
+ mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver)
+ override;
// XRCompositorHost
void CreateImmersiveOverlay(
- mojom::ImmersiveOverlayRequest overlay_request) override;
+ mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver) override;
void EnsureRenderLoop();
@@ -56,14 +61,15 @@ class DEVICE_VR_EXPORT OpenXrDevice
std::unique_ptr<OpenXrRenderLoop> render_loop_;
- mojo::Binding<mojom::XRSessionController> exclusive_controller_binding_;
+ mojo::Receiver<mojom::XRSessionController> exclusive_controller_receiver_{
+ this};
- mojo::Binding<mojom::IsolatedXRGamepadProviderFactory>
- gamepad_provider_factory_binding_;
- mojom::IsolatedXRGamepadProviderRequest provider_request_;
+ mojo::Receiver<mojom::IsolatedXRGamepadProviderFactory>
+ gamepad_provider_factory_receiver_{this};
+ mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver_;
- mojo::Binding<mojom::XRCompositorHost> compositor_host_binding_;
- mojom::ImmersiveOverlayRequest overlay_request_;
+ mojo::Receiver<mojom::XRCompositorHost> compositor_host_receiver_{this};
+ mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver_;
base::WeakPtrFactory<OpenXrDevice> weak_ptr_factory_;
diff --git a/chromium/device/vr/openxr/openxr_gamepad_helper.cc b/chromium/device/vr/openxr/openxr_gamepad_helper.cc
deleted file mode 100644
index 418d9f779d1..00000000000
--- a/chromium/device/vr/openxr/openxr_gamepad_helper.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2019 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/vr/openxr/openxr_gamepad_helper.h"
-
-#include "device/vr/openxr/openxr_util.h"
-
-namespace device {
-
-XrResult OpenXrGamepadHelper::CreateOpenXrGamepadHelper(
- XrInstance instance,
- XrSession session,
- XrSpace local_space,
- std::unique_ptr<OpenXrGamepadHelper>* helper) {
- XrResult xr_result;
-
- std::unique_ptr<OpenXrGamepadHelper> new_helper =
- std::make_unique<OpenXrGamepadHelper>(session, local_space);
-
- // This map is used to store bindings for different kinds of interaction
- // profiles. This allows the runtime to choose a different input sources based
- // on availability.
- std::map<XrPath, std::vector<XrActionSuggestedBinding>> bindings;
- DCHECK(new_helper->controllers_.size() ==
- new_helper->active_action_sets_.size());
- for (size_t i = 0; i < new_helper->controllers_.size(); i++) {
- RETURN_IF_XR_FAILED(new_helper->controllers_[i].Initialize(
- static_cast<OpenXrControllerType>(i), instance, session, &bindings));
-
- new_helper->active_action_sets_[i].actionSet =
- new_helper->controllers_[i].GetActionSet();
- new_helper->active_action_sets_[i].subactionPath = XR_NULL_PATH;
- }
-
- for (auto it = bindings.begin(); it != bindings.end(); it++) {
- XrInteractionProfileSuggestedBinding profile_suggested_bindings = {
- XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING};
- profile_suggested_bindings.interactionProfile = it->first;
- profile_suggested_bindings.suggestedBindings = it->second.data();
- profile_suggested_bindings.countSuggestedBindings = it->second.size();
-
- RETURN_IF_XR_FAILED(xrSuggestInteractionProfileBindings(
- instance, &profile_suggested_bindings));
- }
-
- std::vector<XrActionSet> action_sets(new_helper->controllers_.size());
- for (size_t i = 0; i < new_helper->controllers_.size(); i++) {
- action_sets[i] = new_helper->controllers_[i].GetActionSet();
- }
-
- XrSessionActionSetsAttachInfo attach_info = {
- XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO};
- attach_info.countActionSets = action_sets.size();
- attach_info.actionSets = action_sets.data();
- RETURN_IF_XR_FAILED(xrAttachSessionActionSets(session, &attach_info));
-
- *helper = std::move(new_helper);
- return xr_result;
-}
-
-OpenXrGamepadHelper::OpenXrGamepadHelper(XrSession session, XrSpace local_space)
- : session_(session), local_space_(local_space) {}
-
-OpenXrGamepadHelper::~OpenXrGamepadHelper() = default;
-
-mojom::XRGamepadDataPtr OpenXrGamepadHelper::GetGamepadData(
- XrTime predicted_display_time) {
- XrActionsSyncInfo sync_info = {XR_TYPE_ACTIONS_SYNC_INFO};
- sync_info.countActiveActionSets = active_action_sets_.size();
- sync_info.activeActionSets = active_action_sets_.data();
- if (XR_FAILED(xrSyncActions(session_, &sync_info)))
- return nullptr;
-
- mojom::XRGamepadDataPtr gamepad_data_ptr = mojom::XRGamepadData::New();
- for (const OpenXrController& controller : controllers_) {
- mojom::XRGamepadPtr gamepad_ptr = mojom::XRGamepad::New();
- gamepad_ptr->controller_id = controller.GetID();
- gamepad_ptr->timestamp = base::TimeTicks::Now();
- gamepad_ptr->hand = controller.GetHandness();
-
- std::vector<mojom::XRGamepadButtonPtr> buttons =
- controller.GetWebVrButtons();
- if (buttons.empty())
- continue;
- gamepad_ptr->buttons = std::move(buttons);
-
- std::vector<double> axes = controller.GetWebVrAxes();
- if (axes.empty())
- continue;
- gamepad_ptr->axes = std::move(axes);
-
- gamepad_ptr->pose =
- controller.GetPose(predicted_display_time, local_space_);
- if (!gamepad_ptr->pose)
- continue;
- gamepad_ptr->can_provide_position = gamepad_ptr->pose->position.has_value();
- gamepad_ptr->can_provide_orientation =
- gamepad_ptr->pose->orientation.has_value();
-
- gamepad_data_ptr->gamepads.push_back(std::move(gamepad_ptr));
- }
-
- return gamepad_data_ptr;
-}
-
-} // namespace device
diff --git a/chromium/device/vr/openxr/openxr_gamepad_helper.h b/chromium/device/vr/openxr/openxr_gamepad_helper.h
deleted file mode 100644
index f5e6763d57b..00000000000
--- a/chromium/device/vr/openxr/openxr_gamepad_helper.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2019 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_VR_OPENXR_OPENXR_GAMEPAD_HELPER_H_
-#define DEVICE_VR_OPENXR_OPENXR_GAMEPAD_HELPER_H_
-
-#include "device/vr/openxr/openxr_controller.h"
-#include "device/vr/public/mojom/isolated_xr_service.mojom.h"
-
-namespace device {
-
-class OpenXrGamepadHelper {
- public:
- static XrResult CreateOpenXrGamepadHelper(
- XrInstance instance,
- XrSession session,
- XrSpace local_space,
- std::unique_ptr<OpenXrGamepadHelper>* helper);
-
- OpenXrGamepadHelper(XrSession session, XrSpace local_space);
-
- ~OpenXrGamepadHelper();
-
- mojom::XRGamepadDataPtr GetGamepadData(XrTime predicted_display_time);
-
- private:
- XrSession session_;
- XrSpace local_space_;
-
- std::array<OpenXrController,
- static_cast<size_t>(OpenXrControllerType::kCount)>
- controllers_;
- std::array<XrActiveActionSet,
- static_cast<size_t>(OpenXrControllerType::kCount)>
- active_action_sets_;
-
- DISALLOW_COPY_AND_ASSIGN(OpenXrGamepadHelper);
-};
-
-} // namespace device
-
-#endif // DEVICE_VR_OPENXR_OPENXR_GAMEPAD_HELPER_H_
diff --git a/chromium/device/vr/openxr/openxr_input_helper.cc b/chromium/device/vr/openxr/openxr_input_helper.cc
new file mode 100644
index 00000000000..6a8cfa26ab6
--- /dev/null
+++ b/chromium/device/vr/openxr/openxr_input_helper.cc
@@ -0,0 +1,235 @@
+// Copyright 2019 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/vr/openxr/openxr_input_helper.h"
+
+#include "device/vr/openxr/openxr_util.h"
+#include "device/vr/util/xr_standard_gamepad_builder.h"
+
+namespace device {
+
+namespace {
+base::Optional<GamepadBuilder::ButtonData> GetAxisButtonData(
+ OpenXrAxisType openxr_button_type,
+ base::Optional<GamepadButton> button_data,
+ std::vector<double> axis) {
+ GamepadBuilder::ButtonData data;
+ if (!button_data || axis.size() != 2) {
+ return base::nullopt;
+ }
+
+ switch (openxr_button_type) {
+ case OpenXrAxisType::kThumbstick:
+ data.type = GamepadBuilder::ButtonData::Type::kThumbstick;
+ break;
+ case OpenXrAxisType::kTrackpad:
+ data.type = GamepadBuilder::ButtonData::Type::kTouchpad;
+ break;
+ }
+ data.touched = button_data->touched;
+ data.pressed = button_data->pressed;
+ data.value = button_data->value;
+ // Invert the y axis because -1 is up in the Gamepad API, but down in
+ // OpenXR.
+ data.x_axis = axis.at(0);
+ data.y_axis = -axis.at(1);
+ return data;
+}
+} // namespace
+
+XrResult OpenXRInputHelper::CreateOpenXRInputHelper(
+ XrInstance instance,
+ XrSession session,
+ XrSpace local_space,
+ std::unique_ptr<OpenXRInputHelper>* helper) {
+ XrResult xr_result;
+
+ std::unique_ptr<OpenXRInputHelper> new_helper =
+ std::make_unique<OpenXRInputHelper>(session, local_space);
+
+ // This map is used to store bindings for different kinds of interaction
+ // profiles. This allows the runtime to choose a different input sources based
+ // on availability.
+ std::map<XrPath, std::vector<XrActionSuggestedBinding>> bindings;
+
+ for (size_t i = 0; i < new_helper->controller_states_.size(); i++) {
+ RETURN_IF_XR_FAILED(new_helper->controller_states_[i].controller.Initialize(
+ static_cast<OpenXrHandednessType>(i), instance, session, &bindings));
+ new_helper->controller_states_[i].primary_button_pressed = false;
+ }
+
+ for (auto it = bindings.begin(); it != bindings.end(); it++) {
+ XrInteractionProfileSuggestedBinding profile_suggested_bindings = {
+ XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING};
+ profile_suggested_bindings.interactionProfile = it->first;
+ profile_suggested_bindings.suggestedBindings = it->second.data();
+ profile_suggested_bindings.countSuggestedBindings = it->second.size();
+
+ RETURN_IF_XR_FAILED(xrSuggestInteractionProfileBindings(
+ instance, &profile_suggested_bindings));
+ }
+
+ std::vector<XrActionSet> action_sets(new_helper->controller_states_.size());
+ for (size_t i = 0; i < new_helper->controller_states_.size(); i++) {
+ action_sets[i] =
+ new_helper->controller_states_[i].controller.GetActionSet();
+ }
+
+ XrSessionActionSetsAttachInfo attach_info = {
+ XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO};
+ attach_info.countActionSets = action_sets.size();
+ attach_info.actionSets = action_sets.data();
+ RETURN_IF_XR_FAILED(xrAttachSessionActionSets(session, &attach_info));
+
+ *helper = std::move(new_helper);
+ return xr_result;
+}
+
+OpenXRInputHelper::OpenXRInputHelper(XrSession session, XrSpace local_space)
+ : session_(session), local_space_(local_space) {}
+
+OpenXRInputHelper::~OpenXRInputHelper() = default;
+
+mojom::XRGamepadDataPtr OpenXRInputHelper::GetGamepadData(
+ XrTime predicted_display_time) {
+ if (XR_FAILED(SyncActions(predicted_display_time)))
+ return nullptr;
+
+ mojom::XRGamepadDataPtr gamepad_data_ptr = mojom::XRGamepadData::New();
+ for (const OpenXrControllerState& controller_state : controller_states_) {
+ const OpenXrController& controller = controller_state.controller;
+ mojom::XRGamepadPtr gamepad_ptr = mojom::XRGamepad::New();
+ gamepad_ptr->controller_id = controller.GetId();
+ gamepad_ptr->timestamp = base::TimeTicks::Now();
+ gamepad_ptr->hand = controller.GetHandness();
+
+ std::vector<mojom::XRGamepadButtonPtr> buttons =
+ controller.GetWebVrButtons();
+ if (buttons.empty())
+ continue;
+ gamepad_ptr->buttons = std::move(buttons);
+
+ std::vector<double> axes = controller.GetWebVrAxes();
+ if (axes.empty())
+ continue;
+ gamepad_ptr->axes = std::move(axes);
+
+ gamepad_ptr->pose =
+ controller.GetPose(predicted_display_time, local_space_);
+ if (!gamepad_ptr->pose)
+ continue;
+ gamepad_ptr->can_provide_position = gamepad_ptr->pose->position.has_value();
+ gamepad_ptr->can_provide_orientation =
+ gamepad_ptr->pose->orientation.has_value();
+
+ gamepad_data_ptr->gamepads.push_back(std::move(gamepad_ptr));
+ }
+
+ return gamepad_data_ptr;
+}
+
+std::vector<mojom::XRInputSourceStatePtr> OpenXRInputHelper::GetInputState(
+ XrTime predicted_display_time) {
+ std::vector<mojom::XRInputSourceStatePtr> input_states;
+ if (XR_FAILED(SyncActions(predicted_display_time))) {
+ for (OpenXrControllerState& state : controller_states_) {
+ state.primary_button_pressed = false;
+ }
+ return input_states;
+ }
+
+ for (uint32_t i = 0; i < controller_states_.size(); i++) {
+ device::OpenXrController* controller = &controller_states_[i].controller;
+
+ base::Optional<GamepadButton> trigger_button =
+ controller->GetButton(OpenXrButtonType::kTrigger);
+
+ // Having a trigger button is the minimum for an webxr input.
+ // No trigger button indicates input is not connected.
+ if (!trigger_button) {
+ continue;
+ }
+
+ device::mojom::XRInputSourceStatePtr state =
+ device::mojom::XRInputSourceState::New();
+
+ // ID 0 will cause a DCHECK in the hash table used on the blink side.
+ // To ensure that we don't have any collisions with other ids, increment
+ // all of the ids by one.
+ state->source_id = i + 1;
+
+ state->description = controller->GetDescription(predicted_display_time);
+
+ state->grip = controller->GetMojoFromGripTransform(predicted_display_time,
+ local_space_);
+ state->emulated_position = false;
+ state->primary_input_pressed = trigger_button.value().pressed;
+ state->primary_input_clicked =
+ controller_states_[i].primary_button_pressed &&
+ !state->primary_input_pressed;
+ controller_states_[i].primary_button_pressed = state->primary_input_pressed;
+ state->gamepad = GetWebXRGamepad(*controller);
+ input_states.push_back(std::move(state));
+ }
+
+ return input_states;
+}
+
+base::Optional<Gamepad> OpenXRInputHelper::GetWebXRGamepad(
+ const OpenXrController& controller) const {
+ XRStandardGamepadBuilder builder(controller.GetHandness());
+
+ base::Optional<GamepadButton> trigger_button =
+ controller.GetButton(OpenXrButtonType::kTrigger);
+ if (!trigger_button)
+ return base::nullopt;
+
+ builder.SetPrimaryButton(trigger_button.value());
+
+ base::Optional<GamepadButton> squeeze_button =
+ controller.GetButton(OpenXrButtonType::kSqueeze);
+ if (squeeze_button)
+ builder.SetSecondaryButton(squeeze_button.value());
+
+ base::Optional<GamepadButton> trackpad_button =
+ controller.GetButton(OpenXrButtonType::kTrackpad);
+ std::vector<double> trackpad_axis =
+ controller.GetAxis(OpenXrAxisType::kTrackpad);
+ base::Optional<GamepadBuilder::ButtonData> trackpad_button_data =
+ GetAxisButtonData(OpenXrAxisType::kTrackpad, trackpad_button,
+ trackpad_axis);
+
+ if (trackpad_button_data)
+ builder.SetTouchpadData(trackpad_button_data.value());
+
+ base::Optional<GamepadButton> thumbstick_button =
+ controller.GetButton(OpenXrButtonType::kThumbstick);
+ std::vector<double> thumbstick_axis =
+ controller.GetAxis(OpenXrAxisType::kThumbstick);
+ base::Optional<GamepadBuilder::ButtonData> thumbstick_button_data =
+ GetAxisButtonData(OpenXrAxisType::kThumbstick, thumbstick_button,
+ thumbstick_axis);
+
+ if (thumbstick_button_data)
+ builder.SetThumbstickData(thumbstick_button_data.value());
+
+ return builder.GetGamepad();
+}
+
+XrResult OpenXRInputHelper::SyncActions(XrTime predicted_display_time) {
+ std::vector<XrActiveActionSet> active_action_sets(controller_states_.size());
+
+ for (size_t i = 0; i < controller_states_.size(); i++) {
+ active_action_sets[i].actionSet =
+ controller_states_[i].controller.GetActionSet();
+ active_action_sets[i].subactionPath = XR_NULL_PATH;
+ }
+
+ XrActionsSyncInfo sync_info = {XR_TYPE_ACTIONS_SYNC_INFO};
+ sync_info.countActiveActionSets = active_action_sets.size();
+ sync_info.activeActionSets = active_action_sets.data();
+ return xrSyncActions(session_, &sync_info);
+}
+
+} // namespace device
diff --git a/chromium/device/vr/openxr/openxr_input_helper.h b/chromium/device/vr/openxr/openxr_input_helper.h
new file mode 100644
index 00000000000..4e3909e271e
--- /dev/null
+++ b/chromium/device/vr/openxr/openxr_input_helper.h
@@ -0,0 +1,58 @@
+// Copyright 2019 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_VR_OPENXR_OPENXR_INPUT_HELPER_H_
+#define DEVICE_VR_OPENXR_OPENXR_INPUT_HELPER_H_
+
+#include <array>
+#include <memory>
+#include <vector>
+
+#include "base/optional.h"
+
+#include "device/vr/openxr/openxr_controller.h"
+#include "device/vr/public/mojom/isolated_xr_service.mojom.h"
+
+namespace device {
+
+class OpenXRInputHelper {
+ public:
+ static XrResult CreateOpenXRInputHelper(
+ XrInstance instance,
+ XrSession session,
+ XrSpace local_space,
+ std::unique_ptr<OpenXRInputHelper>* helper);
+
+ OpenXRInputHelper(XrSession session, XrSpace local_space);
+
+ ~OpenXRInputHelper();
+
+ mojom::XRGamepadDataPtr GetGamepadData(XrTime predicted_display_time);
+
+ std::vector<mojom::XRInputSourceStatePtr> GetInputState(
+ XrTime predicted_display_time);
+
+ private:
+ base::Optional<Gamepad> GetWebXRGamepad(
+ const OpenXrController& controller) const;
+
+ XrResult SyncActions(XrTime predicted_display_time);
+
+ XrSession session_;
+ XrSpace local_space_;
+
+ struct OpenXrControllerState {
+ OpenXrController controller;
+ bool primary_button_pressed;
+ };
+ std::array<OpenXrControllerState,
+ static_cast<size_t>(OpenXrHandednessType::kCount)>
+ controller_states_;
+
+ DISALLOW_COPY_AND_ASSIGN(OpenXRInputHelper);
+};
+
+} // namespace device
+
+#endif // DEVICE_VR_OPENXR_OPENXR_INPUT_HELPER_H_
diff --git a/chromium/device/vr/openxr/openxr_render_loop.cc b/chromium/device/vr/openxr/openxr_render_loop.cc
index 442e5cb825c..4e01032274c 100644
--- a/chromium/device/vr/openxr/openxr_render_loop.cc
+++ b/chromium/device/vr/openxr/openxr_render_loop.cc
@@ -4,11 +4,12 @@
#include "device/vr/openxr/openxr_render_loop.h"
-#include <directxmath.h>
-
#include "device/vr/openxr/openxr_api_wrapper.h"
-#include "device/vr/openxr/openxr_gamepad_helper.h"
+#include "device/vr/openxr/openxr_input_helper.h"
#include "device/vr/util/transform_utils.h"
+#include "ui/gfx/geometry/angle_conversions.h"
+#include "ui/gfx/transform.h"
+#include "ui/gfx/transform_util.h"
namespace device {
@@ -40,10 +41,13 @@ mojom::XRFrameDataPtr OpenXrRenderLoop::GetNextFrameData() {
frame_data->time_delta =
base::TimeDelta::FromNanoseconds(openxr_->GetPredictedDisplayTime());
+ frame_data->pose = mojom::VRPose::New();
+ frame_data->pose->input_state =
+ input_helper_->GetInputState(openxr_->GetPredictedDisplayTime());
+
base::Optional<gfx::Quaternion> orientation;
base::Optional<gfx::Point3F> position;
if (XR_SUCCEEDED(openxr_->GetHeadPose(&orientation, &position))) {
- frame_data->pose = mojom::VRPose::New();
if (orientation.has_value())
frame_data->pose->orientation = orientation;
@@ -78,12 +82,12 @@ mojom::XRFrameDataPtr OpenXrRenderLoop::GetNextFrameData() {
}
mojom::XRGamepadDataPtr OpenXrRenderLoop::GetNextGamepadData() {
- return gamepad_helper_->GetGamepadData(openxr_->GetPredictedDisplayTime());
+ return input_helper_->GetGamepadData(openxr_->GetPredictedDisplayTime());
}
bool OpenXrRenderLoop::StartRuntime() {
DCHECK(!openxr_);
- DCHECK(!gamepad_helper_);
+ DCHECK(!input_helper_);
DCHECK(!current_display_info_);
// The new wrapper object is stored in a temporary variable instead of
@@ -100,7 +104,7 @@ bool OpenXrRenderLoop::StartRuntime() {
!texture_helper_.SetAdapterLUID(luid) ||
!texture_helper_.EnsureInitialized() ||
XR_FAILED(
- openxr->InitSession(texture_helper_.GetDevice(), &gamepad_helper_))) {
+ openxr->InitSession(texture_helper_.GetDevice(), &input_helper_))) {
texture_helper_.Reset();
return false;
}
@@ -111,16 +115,16 @@ bool OpenXrRenderLoop::StartRuntime() {
texture_helper_.SetDefaultSize(GetViewSize());
DCHECK(openxr_);
- DCHECK(gamepad_helper_);
+ DCHECK(input_helper_);
return true;
}
void OpenXrRenderLoop::StopRuntime() {
- // Has to reset gamepad_helper_ before reset openxr_. If we destroy openxr_
- // first, gamepad_helper_destructor will try to call the actual openxr runtime
+ // Has to reset input_helper_ before reset openxr_. If we destroy openxr_
+ // first, input_helper_destructor will try to call the actual openxr runtime
// rather than the mock in tests.
- gamepad_helper_.reset();
+ input_helper_.reset();
openxr_ = nullptr;
current_display_info_ = nullptr;
texture_helper_.Reset();
@@ -202,27 +206,19 @@ bool OpenXrRenderLoop::UpdateEyeParameters() {
changed = true;
}
- const XrView left = openxr_->GetView(0);
- const XrView right = openxr_->GetView(1);
-
- gfx::Point3F center =
- gfx::Point3F((left.pose.position.x + right.pose.position.x) / 2,
- (left.pose.position.y + right.pose.position.y) / 2,
- (left.pose.position.z + right.pose.position.z) / 2);
-
+ XrView left;
+ XrView right;
+ openxr_->GetHeadFromEyes(&left, &right);
gfx::Size view_size = GetViewSize();
- changed |=
- UpdateEye(left, center, view_size, &current_display_info_->left_eye);
+ changed |= UpdateEye(left, view_size, &current_display_info_->left_eye);
- changed |=
- UpdateEye(right, center, view_size, &current_display_info_->right_eye);
+ changed |= UpdateEye(right, view_size, &current_display_info_->right_eye);
return changed;
}
-bool OpenXrRenderLoop::UpdateEye(const XrView& view,
- const gfx::Point3F& center,
+bool OpenXrRenderLoop::UpdateEye(const XrView& view_head,
const gfx::Size& view_size,
mojom::VREyeParametersPtr* eye) const {
bool changed = false;
@@ -231,8 +227,8 @@ bool OpenXrRenderLoop::UpdateEye(const XrView& view,
// that instead of just building a transformation matrix from the translation
// component.
gfx::Transform head_from_eye = vr_utils::MakeTranslationTransform(
- view.pose.position.x - center.x(), view.pose.position.y - center.y(),
- view.pose.position.z - center.z());
+ view_head.pose.position.x, view_head.pose.position.y,
+ view_head.pose.position.z);
if ((*eye)->head_from_eye != head_from_eye) {
(*eye)->head_from_eye = head_from_eye;
@@ -249,11 +245,11 @@ bool OpenXrRenderLoop::UpdateEye(const XrView& view,
changed = true;
}
- mojom::VRFieldOfViewPtr fov = mojom::VRFieldOfView::New(
- DirectX::XMConvertToDegrees(view.fov.angleUp),
- -DirectX::XMConvertToDegrees(view.fov.angleDown),
- -DirectX::XMConvertToDegrees(view.fov.angleLeft),
- DirectX::XMConvertToDegrees(view.fov.angleRight));
+ mojom::VRFieldOfViewPtr fov =
+ mojom::VRFieldOfView::New(gfx::RadToDeg(view_head.fov.angleUp),
+ gfx::RadToDeg(-view_head.fov.angleDown),
+ gfx::RadToDeg(-view_head.fov.angleLeft),
+ gfx::RadToDeg(view_head.fov.angleRight));
if (!(*eye)->field_of_view || !fov->Equals(*(*eye)->field_of_view)) {
(*eye)->field_of_view = std::move(fov);
changed = true;
@@ -265,8 +261,8 @@ bool OpenXrRenderLoop::UpdateEye(const XrView& view,
bool OpenXrRenderLoop::UpdateStageParameters() {
bool changed = false;
XrExtent2Df stage_bounds;
- gfx::Transform transform;
- if (openxr_->GetStageParameters(&stage_bounds, &transform)) {
+ gfx::Transform local_from_stage;
+ if (openxr_->GetStageParameters(&stage_bounds, &local_from_stage)) {
if (!current_display_info_->stage_parameters) {
current_display_info_->stage_parameters = mojom::VRStageParameters::New();
changed = true;
@@ -281,8 +277,9 @@ bool OpenXrRenderLoop::UpdateStageParameters() {
}
if (current_display_info_->stage_parameters->standing_transform !=
- transform) {
- current_display_info_->stage_parameters->standing_transform = transform;
+ local_from_stage) {
+ current_display_info_->stage_parameters->standing_transform =
+ local_from_stage;
changed = true;
}
} else if (current_display_info_->stage_parameters) {
diff --git a/chromium/device/vr/openxr/openxr_render_loop.h b/chromium/device/vr/openxr/openxr_render_loop.h
index 6c1cb17e1b6..4a79f69bba6 100644
--- a/chromium/device/vr/openxr/openxr_render_loop.h
+++ b/chromium/device/vr/openxr/openxr_render_loop.h
@@ -16,7 +16,7 @@ struct XrView;
namespace device {
class OpenXrApiWrapper;
-class OpenXrGamepadHelper;
+class OpenXRInputHelper;
class OpenXrRenderLoop : public XRCompositorCommon {
public:
@@ -39,14 +39,13 @@ class OpenXrRenderLoop : public XRCompositorCommon {
bool UpdateDisplayInfo();
bool UpdateEyeParameters();
- bool UpdateEye(const XrView& view,
- const gfx::Point3F& center,
+ bool UpdateEye(const XrView& view_head,
const gfx::Size& view_size,
mojom::VREyeParametersPtr* eye) const;
bool UpdateStageParameters();
std::unique_ptr<OpenXrApiWrapper> openxr_;
- std::unique_ptr<OpenXrGamepadHelper> gamepad_helper_;
+ std::unique_ptr<OpenXRInputHelper> input_helper_;
base::RepeatingCallback<void(mojom::VRDisplayInfoPtr)>
on_display_info_changed_;
diff --git a/chromium/device/vr/orientation/orientation_device.cc b/chromium/device/vr/orientation/orientation_device.cc
index fe7b0a9346a..d6e1a98601f 100644
--- a/chromium/device/vr/orientation/orientation_device.cc
+++ b/chromium/device/vr/orientation/orientation_device.cc
@@ -10,6 +10,7 @@
#include "base/time/time.h"
#include "device/vr/orientation/orientation_device.h"
#include "device/vr/orientation/orientation_session.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/device/public/cpp/generic_sensor/sensor_reading.h"
#include "services/device/public/cpp/generic_sensor/sensor_reading_shared_buffer_reader.h"
#include "services/device/public/mojom/sensor_provider.mojom.h"
@@ -52,16 +53,13 @@ display::Display::Rotation GetRotation() {
} // namespace
-VROrientationDevice::VROrientationDevice(
- mojom::SensorProviderPtr* sensor_provider,
- base::OnceClosure ready_callback)
+VROrientationDevice::VROrientationDevice(mojom::SensorProvider* sensor_provider,
+ base::OnceClosure ready_callback)
: VRDeviceBase(mojom::XRDeviceId::ORIENTATION_DEVICE_ID),
- ready_callback_(std::move(ready_callback)),
- binding_(this) {
- (*sensor_provider)
- ->GetSensor(kOrientationSensorType,
- base::BindOnce(&VROrientationDevice::SensorReady,
- base::Unretained(this)));
+ ready_callback_(std::move(ready_callback)) {
+ sensor_provider->GetSensor(kOrientationSensorType,
+ base::BindOnce(&VROrientationDevice::SensorReady,
+ base::Unretained(this)));
SetVRDisplayInfo(CreateVRDisplayInfo(GetId()));
}
@@ -87,7 +85,7 @@ void VROrientationDevice::SensorReady(
sensor_.Bind(std::move(params->sensor));
- binding_.Bind(std::move(params->client_request));
+ receiver_.Bind(std::move(params->client_receiver));
shared_buffer_reader_ = device::SensorReadingSharedBufferReader::Create(
std::move(params->memory), params->buffer_offset);
@@ -99,7 +97,7 @@ void VROrientationDevice::SensorReady(
}
default_config.set_frequency(kDefaultPumpFrequencyHz);
- sensor_.set_connection_error_handler(base::BindOnce(
+ sensor_.set_disconnect_handler(base::BindOnce(
&VROrientationDevice::HandleSensorError, base::Unretained(this)));
sensor_->ConfigureReadingChangeNotifications(false /* disabled */);
sensor_->AddConfiguration(
@@ -128,7 +126,7 @@ void VROrientationDevice::RaiseError() {
void VROrientationDevice::HandleSensorError() {
sensor_.reset();
shared_buffer_reader_.reset();
- binding_.Close();
+ receiver_.reset();
}
void VROrientationDevice::RequestSession(
@@ -139,18 +137,22 @@ void VROrientationDevice::RequestSession(
// TODO(http://crbug.com/695937): Perform a check to see if sensors are
// available when RequestSession is called for non-immersive sessions.
- mojom::XRFrameDataProviderPtr data_provider;
- mojom::XRSessionControllerPtr controller;
+ mojo::PendingRemote<mojom::XRFrameDataProvider> data_provider;
+ mojo::PendingRemote<mojom::XRSessionController> controller;
magic_window_sessions_.push_back(std::make_unique<VROrientationSession>(
- this, mojo::MakeRequest(&data_provider), mojo::MakeRequest(&controller)));
+ this, data_provider.InitWithNewPipeAndPassReceiver(),
+ controller.InitWithNewPipeAndPassReceiver()));
auto session = mojom::XRSession::New();
- session->data_provider = data_provider.PassInterface();
+ session->data_provider = std::move(data_provider);
if (display_info_) {
session->display_info = display_info_.Clone();
}
std::move(callback).Run(std::move(session), std::move(controller));
+
+ // The sensor may have been suspended, so resume it now.
+ sensor_->Resume();
}
void VROrientationDevice::EndMagicWindowSession(VROrientationSession* session) {
@@ -158,10 +160,18 @@ void VROrientationDevice::EndMagicWindowSession(VROrientationSession* session) {
[session](const std::unique_ptr<VROrientationSession>& item) {
return item.get() == session;
});
+
+ // If there are no more magic window sessions, suspend the sensor until we get
+ // a new one.
+ if (magic_window_sessions_.empty()) {
+ sensor_->Suspend();
+ }
}
void VROrientationDevice::GetInlineFrameData(
mojom::XRFrameDataProvider::GetFrameDataCallback callback) {
+ // Orientation sessions should never be exclusive or presenting.
+ DCHECK(!HasExclusiveSession());
if (!inline_poses_enabled_) {
std::move(callback).Run(nullptr);
return;
diff --git a/chromium/device/vr/orientation/orientation_device.h b/chromium/device/vr/orientation/orientation_device.h
index eff93f7a041..420ead8ca8f 100644
--- a/chromium/device/vr/orientation/orientation_device.h
+++ b/chromium/device/vr/orientation/orientation_device.h
@@ -13,7 +13,8 @@
#include "build/build_config.h"
#include "device/vr/public/mojom/vr_service.mojom.h"
#include "device/vr/vr_device_base.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/sensor_provider.mojom.h"
#include "ui/gfx/geometry/quaternion.h"
@@ -39,7 +40,7 @@ static constexpr mojom::SensorType kOrientationSensorType =
class DEVICE_VR_EXPORT VROrientationDevice : public VRDeviceBase,
public mojom::SensorClient {
public:
- VROrientationDevice(mojom::SensorProviderPtr* sensor_provider,
+ VROrientationDevice(mojom::SensorProvider* sensor_provider,
base::OnceClosure ready_callback);
~VROrientationDevice() override;
@@ -76,9 +77,9 @@ class DEVICE_VR_EXPORT VROrientationDevice : public VRDeviceBase,
base::Optional<gfx::Quaternion> base_pose_;
gfx::Quaternion latest_pose_;
- mojom::SensorPtr sensor_;
+ mojo::Remote<mojom::Sensor> sensor_;
std::unique_ptr<SensorReadingSharedBufferReader> shared_buffer_reader_;
- mojo::Binding<mojom::SensorClient> binding_;
+ mojo::Receiver<mojom::SensorClient> receiver_{this};
std::vector<std::unique_ptr<VROrientationSession>> magic_window_sessions_;
};
diff --git a/chromium/device/vr/orientation/orientation_device_provider.cc b/chromium/device/vr/orientation/orientation_device_provider.cc
index 505ae2c496a..4fd6fffd15f 100644
--- a/chromium/device/vr/orientation/orientation_device_provider.cc
+++ b/chromium/device/vr/orientation/orientation_device_provider.cc
@@ -17,8 +17,8 @@ namespace device {
VROrientationDeviceProvider::VROrientationDeviceProvider(
service_manager::Connector* connector) {
- connector->BindInterface(device::mojom::kServiceName,
- mojo::MakeRequest(&sensor_provider_));
+ connector->Connect(device::mojom::kServiceName,
+ sensor_provider_.BindNewPipeAndPassReceiver());
}
VROrientationDeviceProvider::~VROrientationDeviceProvider() = default;
@@ -26,7 +26,8 @@ VROrientationDeviceProvider::~VROrientationDeviceProvider() = default;
void VROrientationDeviceProvider::Initialize(
base::RepeatingCallback<void(mojom::XRDeviceId,
mojom::VRDisplayInfoPtr,
- mojom::XRRuntimePtr)> add_device_callback,
+ mojo::PendingRemote<mojom::XRRuntime>)>
+ add_device_callback,
base::RepeatingCallback<void(mojom::XRDeviceId)> remove_device_callback,
base::OnceClosure initialization_complete) {
if (!base::FeatureList::IsEnabled(device::kWebXrOrientationSensorDevice)) {
@@ -39,13 +40,13 @@ void VROrientationDeviceProvider::Initialize(
if (device_ && device_->IsAvailable()) {
add_device_callback.Run(device_->GetId(), device_->GetVRDisplayInfo(),
- device_->BindXRRuntimePtr());
+ device_->BindXRRuntime());
return;
}
if (!device_) {
device_ = std::make_unique<VROrientationDevice>(
- &sensor_provider_,
+ sensor_provider_.get(),
base::BindOnce(&VROrientationDeviceProvider::DeviceInitialized,
base::Unretained(this)));
add_device_callback_ = add_device_callback;
@@ -66,7 +67,7 @@ void VROrientationDeviceProvider::DeviceInitialized() {
// If the device successfully connected to the orientation APIs, provide it.
if (device_->IsAvailable()) {
add_device_callback_.Run(device_->GetId(), device_->GetVRDisplayInfo(),
- device_->BindXRRuntimePtr());
+ device_->BindXRRuntime());
}
initialized_ = true;
diff --git a/chromium/device/vr/orientation/orientation_device_provider.h b/chromium/device/vr/orientation/orientation_device_provider.h
index a260c5ba38c..72e8a0e8656 100644
--- a/chromium/device/vr/orientation/orientation_device_provider.h
+++ b/chromium/device/vr/orientation/orientation_device_provider.h
@@ -12,6 +12,8 @@
#include "device/vr/orientation/orientation_device.h"
#include "device/vr/vr_device_provider.h"
#include "device/vr/vr_export.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/constants.mojom.h"
#include "services/device/public/mojom/sensor_provider.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
@@ -26,7 +28,8 @@ class DEVICE_VR_EXPORT VROrientationDeviceProvider : public VRDeviceProvider {
void Initialize(
base::RepeatingCallback<void(mojom::XRDeviceId,
mojom::VRDisplayInfoPtr,
- mojom::XRRuntimePtr)> add_device_callback,
+ mojo::PendingRemote<mojom::XRRuntime>)>
+ add_device_callback,
base::RepeatingCallback<void(mojom::XRDeviceId)> remove_device_callback,
base::OnceClosure initialization_complete) override;
@@ -37,12 +40,13 @@ class DEVICE_VR_EXPORT VROrientationDeviceProvider : public VRDeviceProvider {
bool initialized_ = false;
- device::mojom::SensorProviderPtr sensor_provider_;
+ mojo::Remote<device::mojom::SensorProvider> sensor_provider_;
std::unique_ptr<VROrientationDevice> device_;
- base::RepeatingCallback<
- void(mojom::XRDeviceId, mojom::VRDisplayInfoPtr, mojom::XRRuntimePtr)>
+ base::RepeatingCallback<void(mojom::XRDeviceId,
+ mojom::VRDisplayInfoPtr,
+ mojo::PendingRemote<mojom::XRRuntime>)>
add_device_callback_;
base::OnceClosure initialized_callback_;
diff --git a/chromium/device/vr/orientation/orientation_device_provider_unittest.cc b/chromium/device/vr/orientation/orientation_device_provider_unittest.cc
index 1e2a294940e..3874089d4e4 100644
--- a/chromium/device/vr/orientation/orientation_device_provider_unittest.cc
+++ b/chromium/device/vr/orientation/orientation_device_provider_unittest.cc
@@ -18,6 +18,8 @@
#include "device/vr/orientation/orientation_device_provider.h"
#include "device/vr/test/fake_orientation_provider.h"
#include "device/vr/test/fake_sensor_provider.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/cpp/generic_sensor/sensor_reading.h"
#include "services/device/public/cpp/generic_sensor/sensor_reading_shared_buffer_reader.h"
#include "services/device/public/cpp/generic_sensor/sensor_traits.h"
@@ -38,7 +40,7 @@ class VROrientationDeviceProviderTest : public testing::Test {
fake_sensor_provider_ = std::make_unique<FakeSensorProvider>();
fake_sensor_ = std::make_unique<FakeOrientationSensor>(
- mojo::MakeRequest(&sensor_ptr_));
+ sensor_.InitWithNewPipeAndPassReceiver());
shared_buffer_handle_ = mojo::SharedBufferHandle::Create(
sizeof(SensorReadingSharedBuffer) *
(static_cast<uint64_t>(mojom::SensorType::kMaxValue) + 1));
@@ -70,11 +72,11 @@ class VROrientationDeviceProviderTest : public testing::Test {
mojom::SensorInitParamsPtr FakeInitParams() {
auto init_params = mojom::SensorInitParams::New();
- init_params->sensor = std::move(sensor_ptr_);
+ init_params->sensor = std::move(sensor_);
init_params->default_configuration = PlatformSensorConfiguration(
SensorTraits<kOrientationSensorType>::kDefaultFrequency);
- init_params->client_request = mojo::MakeRequest(&sensor_client_ptr_);
+ init_params->client_receiver = sensor_client_.BindNewPipeAndPassReceiver();
init_params->memory = shared_buffer_handle_->Clone(
mojo::SharedBufferHandle::AccessMode::READ_ONLY);
@@ -87,11 +89,11 @@ class VROrientationDeviceProviderTest : public testing::Test {
base::RepeatingCallback<void(device::mojom::XRDeviceId,
mojom::VRDisplayInfoPtr,
- mojom::XRRuntimePtr device)>
+ mojo::PendingRemote<mojom::XRRuntime> device)>
DeviceAndIdCallbackFailIfCalled() {
- return base::BindRepeating([](device::mojom::XRDeviceId id,
- mojom::VRDisplayInfoPtr,
- mojom::XRRuntimePtr device) { FAIL(); });
+ return base::BindRepeating(
+ [](device::mojom::XRDeviceId id, mojom::VRDisplayInfoPtr,
+ mojo::PendingRemote<mojom::XRRuntime> device) { FAIL(); });
}
base::RepeatingCallback<void(device::mojom::XRDeviceId)>
@@ -101,11 +103,12 @@ class VROrientationDeviceProviderTest : public testing::Test {
base::RepeatingCallback<void(device::mojom::XRDeviceId,
mojom::VRDisplayInfoPtr,
- mojom::XRRuntimePtr device)>
+ mojo::PendingRemote<mojom::XRRuntime> device)>
DeviceAndIdCallbackMustBeCalled(base::RunLoop* loop) {
return base::BindRepeating(
[](base::OnceClosure quit_closure, device::mojom::XRDeviceId id,
- mojom::VRDisplayInfoPtr info, mojom::XRRuntimePtr device) {
+ mojom::VRDisplayInfoPtr info,
+ mojo::PendingRemote<mojom::XRRuntime> device) {
ASSERT_TRUE(device);
ASSERT_TRUE(info);
std::move(quit_closure).Run();
@@ -138,13 +141,13 @@ class VROrientationDeviceProviderTest : public testing::Test {
std::unique_ptr<VROrientationDeviceProvider> provider_;
std::unique_ptr<FakeSensorProvider> fake_sensor_provider_;
- mojom::SensorProviderPtr sensor_provider_ptr_;
+ mojo::Remote<mojom::SensorProvider> sensor_provider_;
// Fake Sensor Init params objects
std::unique_ptr<FakeOrientationSensor> fake_sensor_;
- mojom::SensorPtrInfo sensor_ptr_;
+ mojo::PendingRemote<mojom::Sensor> sensor_;
mojo::ScopedSharedBufferHandle shared_buffer_handle_;
- mojom::SensorClientPtr sensor_client_ptr_;
+ mojo::Remote<mojom::SensorClient> sensor_client_;
std::unique_ptr<service_manager::Connector> connector_;
diff --git a/chromium/device/vr/orientation/orientation_device_unittest.cc b/chromium/device/vr/orientation/orientation_device_unittest.cc
index be550164ee6..9f8ce7aa889 100644
--- a/chromium/device/vr/orientation/orientation_device_unittest.cc
+++ b/chromium/device/vr/orientation/orientation_device_unittest.cc
@@ -16,6 +16,8 @@
#include "device/vr/orientation/orientation_session.h"
#include "device/vr/test/fake_orientation_provider.h"
#include "device/vr/test/fake_sensor_provider.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/cpp/generic_sensor/sensor_reading.h"
#include "services/device/public/cpp/generic_sensor/sensor_reading_shared_buffer_reader.h"
#include "services/device/public/cpp/generic_sensor/sensor_traits.h"
@@ -79,10 +81,10 @@ class VROrientationDeviceTest : public testing::Test {
~VROrientationDeviceTest() override = default;
void SetUp() override {
fake_sensor_provider_ = std::make_unique<FakeSensorProvider>(
- mojo::MakeRequest(&sensor_provider_ptr_));
+ sensor_provider_.BindNewPipeAndPassReceiver());
fake_sensor_ = std::make_unique<FakeOrientationSensor>(
- mojo::MakeRequest(&sensor_ptr_));
+ sensor_.InitWithNewPipeAndPassReceiver());
shared_buffer_handle_ = mojo::SharedBufferHandle::Create(
sizeof(SensorReadingSharedBuffer) *
@@ -108,13 +110,8 @@ class VROrientationDeviceTest : public testing::Test {
void InitializeDevice(mojom::SensorInitParamsPtr params) {
base::RunLoop loop;
- device_ = std::make_unique<VROrientationDevice>(
- &sensor_provider_ptr_, base::BindOnce(
- [](base::OnceClosure quit_closure) {
- // The callback was called.
- std::move(quit_closure).Run();
- },
- loop.QuitClosure()));
+ device_ = std::make_unique<VROrientationDevice>(sensor_provider_.get(),
+ loop.QuitClosure());
// Complete the creation of device_ by letting the GetSensor function go
// through.
@@ -166,11 +163,11 @@ class VROrientationDeviceTest : public testing::Test {
}
std::unique_ptr<VROrientationSession> MakeDisplay() {
- mojom::XRFrameDataProviderPtr data_provider;
- mojom::XRSessionControllerPtr controller;
+ mojo::PendingRemote<mojom::XRFrameDataProvider> data_provider;
+ mojo::PendingRemote<mojom::XRSessionController> controller;
return std::make_unique<VROrientationSession>(
- device_.get(), mojo::MakeRequest(&data_provider),
- mojo::MakeRequest(&controller));
+ device_.get(), data_provider.InitWithNewPipeAndPassReceiver(),
+ controller.InitWithNewPipeAndPassReceiver());
}
void TryGetFrameData(VROrientationSession* display, bool expect_null) {
@@ -190,11 +187,11 @@ class VROrientationDeviceTest : public testing::Test {
mojom::SensorInitParamsPtr FakeInitParams() {
auto init_params = mojom::SensorInitParams::New();
- init_params->sensor = std::move(sensor_ptr_);
+ init_params->sensor = std::move(sensor_);
init_params->default_configuration = PlatformSensorConfiguration(
SensorTraits<kOrientationSensorType>::kDefaultFrequency);
- init_params->client_request = mojo::MakeRequest(&sensor_client_ptr_);
+ init_params->client_receiver = sensor_client_.BindNewPipeAndPassReceiver();
init_params->memory = shared_buffer_handle_->Clone(
mojo::SharedBufferHandle::AccessMode::READ_ONLY);
@@ -229,14 +226,14 @@ class VROrientationDeviceTest : public testing::Test {
std::unique_ptr<VROrientationDevice> device_;
std::unique_ptr<FakeSensorProvider> fake_sensor_provider_;
- mojom::SensorProviderPtr sensor_provider_ptr_;
+ mojo::Remote<mojom::SensorProvider> sensor_provider_;
// Fake Sensor Init params objects
std::unique_ptr<FakeOrientationSensor> fake_sensor_;
- mojom::SensorPtrInfo sensor_ptr_;
+ mojo::PendingRemote<mojom::Sensor> sensor_;
mojo::ScopedSharedBufferHandle shared_buffer_handle_;
mojo::ScopedSharedBufferMapping shared_buffer_mapping_;
- mojom::SensorClientPtr sensor_client_ptr_;
+ mojo::Remote<mojom::SensorClient> sensor_client_;
std::unique_ptr<FakeScreen> fake_screen_;
std::unique_ptr<ScopedScreenOverride> scoped_screen_override_;
@@ -248,8 +245,8 @@ TEST_F(VROrientationDeviceTest, InitializationTest) {
// Check that without running anything, the device will return not available,
// without crashing.
- device_ = std::make_unique<VROrientationDevice>(&sensor_provider_ptr_,
- base::BindOnce([]() {}));
+ device_ = std::make_unique<VROrientationDevice>(sensor_provider_.get(),
+ base::DoNothing());
task_environment_.RunUntilIdle();
EXPECT_FALSE(device_->IsAvailable());
diff --git a/chromium/device/vr/orientation/orientation_session.cc b/chromium/device/vr/orientation/orientation_session.cc
index 3a937ed332e..35207e4eaa5 100644
--- a/chromium/device/vr/orientation/orientation_session.cc
+++ b/chromium/device/vr/orientation/orientation_session.cc
@@ -13,15 +13,17 @@ namespace device {
VROrientationSession::VROrientationSession(
VROrientationDevice* device,
- mojom::XRFrameDataProviderRequest magic_window_request,
- mojom::XRSessionControllerRequest session_request)
- : magic_window_binding_(this, std::move(magic_window_request)),
- session_controller_binding_(this, std::move(session_request)),
+ mojo::PendingReceiver<mojom::XRFrameDataProvider> magic_window_receiver,
+ mojo::PendingReceiver<mojom::XRSessionController> session_receiver)
+ : magic_window_receiver_(this, std::move(magic_window_receiver)),
+ session_controller_receiver_(this, std::move(session_receiver)),
device_(device) {
- // Unretained is safe because the binding will close when we are destroyed,
- // so we won't receive any more callbacks after that.
- session_controller_binding_.set_connection_error_handler(base::BindOnce(
- &VROrientationSession::OnMojoConnectionError, base::Unretained(this)));
+ magic_window_receiver_.set_disconnect_handler(
+ base::BindOnce(&VROrientationSession::OnMojoConnectionError,
+ weak_ptr_factory_.GetWeakPtr()));
+ session_controller_receiver_.set_disconnect_handler(
+ base::BindOnce(&VROrientationSession::OnMojoConnectionError,
+ weak_ptr_factory_.GetWeakPtr()));
}
VROrientationSession::~VROrientationSession() = default;
@@ -42,15 +44,15 @@ void VROrientationSession::GetFrameData(
}
void VROrientationSession::GetEnvironmentIntegrationProvider(
- mojom::XREnvironmentIntegrationProviderAssociatedRequest
- environment_request) {
+ mojo::PendingAssociatedReceiver<mojom::XREnvironmentIntegrationProvider>
+ environment_provider) {
// Environment integration is not supported. This call should not
// be made on this device.
mojo::ReportBadMessage("Environment integration is not supported.");
}
void VROrientationSession::SetInputSourceButtonListener(
- device::mojom::XRInputSourceButtonListenerAssociatedPtrInfo) {
+ mojo::PendingAssociatedRemote<device::mojom::XRInputSourceButtonListener>) {
// Input eventing is not supported. This call should not
// be made on this device.
mojo::ReportBadMessage("Input eventing is not supported.");
@@ -62,8 +64,8 @@ void VROrientationSession::SetFrameDataRestricted(bool frame_data_restricted) {
}
void VROrientationSession::OnMojoConnectionError() {
- magic_window_binding_.Close();
- session_controller_binding_.Close();
+ magic_window_receiver_.reset();
+ session_controller_receiver_.reset();
device_->EndMagicWindowSession(this); // This call will destroy us.
}
diff --git a/chromium/device/vr/orientation/orientation_session.h b/chromium/device/vr/orientation/orientation_session.h
index 50c28288591..ab8a7af6a44 100644
--- a/chromium/device/vr/orientation/orientation_session.h
+++ b/chromium/device/vr/orientation/orientation_session.h
@@ -13,8 +13,10 @@
#include "device/vr/public/mojom/vr_service.mojom.h"
#include "device/vr/vr_device.h"
#include "device/vr/vr_export.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
+#include "mojo/public/cpp/bindings/pending_associated_remote.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
#include "ui/display/display.h"
namespace device {
@@ -30,15 +32,16 @@ class DEVICE_VR_EXPORT VROrientationSession
public mojom::XRSessionController {
public:
VROrientationSession(VROrientationDevice* device,
- mojom::XRFrameDataProviderRequest,
- mojom::XRSessionControllerRequest);
+ mojo::PendingReceiver<mojom::XRFrameDataProvider>,
+ mojo::PendingReceiver<mojom::XRSessionController>);
~VROrientationSession() override;
void GetEnvironmentIntegrationProvider(
- mojom::XREnvironmentIntegrationProviderAssociatedRequest
+ mojo::PendingAssociatedReceiver<mojom::XREnvironmentIntegrationProvider>
environment_provider) override;
void SetInputSourceButtonListener(
- device::mojom::XRInputSourceButtonListenerAssociatedPtrInfo) override;
+ mojo::PendingAssociatedRemote<device::mojom::XRInputSourceButtonListener>)
+ override;
// Accessible to tests.
protected:
@@ -51,10 +54,13 @@ class DEVICE_VR_EXPORT VROrientationSession
void OnMojoConnectionError();
- mojo::Binding<mojom::XRFrameDataProvider> magic_window_binding_;
- mojo::Binding<mojom::XRSessionController> session_controller_binding_;
+ mojo::Receiver<mojom::XRFrameDataProvider> magic_window_receiver_;
+ mojo::Receiver<mojom::XRSessionController> session_controller_receiver_;
device::VROrientationDevice* device_;
bool restrict_frame_data_ = true;
+
+ // This must be the last member
+ base::WeakPtrFactory<VROrientationSession> weak_ptr_factory_{this};
};
} // namespace device
diff --git a/chromium/device/vr/public/mojom/browser_test_interfaces.mojom b/chromium/device/vr/public/mojom/browser_test_interfaces.mojom
index bbf864023c1..a9e321fc0fd 100644
--- a/chromium/device/vr/public/mojom/browser_test_interfaces.mojom
+++ b/chromium/device/vr/public/mojom/browser_test_interfaces.mojom
@@ -128,7 +128,7 @@ interface XRTestHook {
// It is always hosted in the XRDevice process, but only has effects while
// running in browser tests with mock implementations of runtimes.
interface XRServiceTestHook {
- [Sync] SetTestHook(XRTestHook? hook) => ();
+ [Sync] SetTestHook(pending_remote<XRTestHook>? hook) => ();
// Called by tests to trigger a termination of the Device Service Process
// To test that the product can properly handle the service either crashing
diff --git a/chromium/device/vr/public/mojom/isolated_xr_service.mojom b/chromium/device/vr/public/mojom/isolated_xr_service.mojom
index e16e645b86d..5bb301d542c 100644
--- a/chromium/device/vr/public/mojom/isolated_xr_service.mojom
+++ b/chromium/device/vr/public/mojom/isolated_xr_service.mojom
@@ -34,6 +34,10 @@ interface XRRuntimeEventListener {
// A device has indicated that it is idle.
OnDeviceIdle(device.mojom.VRDisplayEventReason reason);
+ // A device has indicated that the visibility of the content it's displaying
+ // has changed.
+ OnVisibilityStateChanged(device.mojom.XRVisibilityState visibility_state);
+
// Called when the device exits presentation.
OnExitPresent();
};
@@ -42,6 +46,10 @@ struct XRRuntimeSessionOptions {
bool immersive;
bool environment_integration;
+ // The enabled features combine the active required and optional features as
+ // resolved by BrowserXRRuntime and VRServiceImpl.
+ array<XRSessionFeature> enabled_features;
+
// The following options are used for permission requests and showing module
// install UI.
// TODO(crbug.com/854655): Remove these fields, and do permission checks, show
@@ -65,12 +73,13 @@ interface XRRuntime {
// the browser process.
RequestSession(XRRuntimeSessionOptions options) => (
XRSession? session,
- XRSessionController? controller);
+ pending_remote<XRSessionController>? controller);
// The browser may register for changes to a device. Initial VRDisplayInfo
// will immediately be returned to the listener to prevent races.
- ListenToDeviceChanges(associated XRRuntimeEventListener listener) =>
- (VRDisplayInfo? display_info);
+ ListenToDeviceChanges(
+ pending_associated_remote<XRRuntimeEventListener> listener) =>
+ (VRDisplayInfo? display_info);
// Ensure that the runtime has installed most prerequisites, and is ready to
// start. May result in updated display info being sent to registered
@@ -144,7 +153,8 @@ interface IsolatedXRGamepadProviderFactory {
// Get the IsolatedXRGamepadProvider for a specific XR runtime API (Oculus, or
// OpenVR, which are currently the only two that are hosted outside of the
// browser process).
- GetIsolatedXRGamepadProvider(IsolatedXRGamepadProvider& provider);
+ GetIsolatedXRGamepadProvider(
+ pending_receiver<IsolatedXRGamepadProvider> provider);
};
// Represents an overlay that the browser may show on top of or instead of WebXR
@@ -178,7 +188,7 @@ interface ImmersiveOverlay {
// obtain an ImmersiveOverlay to show overlay UI. The obtained overlay will
// disconnect when presentation ends.
interface XRCompositorHost {
- CreateImmersiveOverlay(ImmersiveOverlay& overlay);
+ CreateImmersiveOverlay(pending_receiver<ImmersiveOverlay> overlay);
};
// Notify the browser process about a set of runtimes. The browser process
@@ -187,9 +197,9 @@ interface XRCompositorHost {
interface IsolatedXRRuntimeProviderClient {
// Called when runtimes are initially enumerated, or when devices are later
// attached and become available.
- OnDeviceAdded(XRRuntime runtime,
- IsolatedXRGamepadProviderFactory gamepad_factory,
- XRCompositorHost compositor_host,
+ OnDeviceAdded(pending_remote<XRRuntime> runtime,
+ pending_remote<IsolatedXRGamepadProviderFactory> gamepad_factory,
+ pending_remote<XRCompositorHost> compositor_host,
device.mojom.XRDeviceId device_id);
// Called when runtimes become unavailable - for example if the hardware is
@@ -210,7 +220,7 @@ interface IsolatedXRRuntimeProvider {
// Register a client, and triggers OnDeviceAdded for all available runtimes,
// followed by OnDevicesEnumerated.
// Should only be called once.
- RequestDevices(IsolatedXRRuntimeProviderClient client);
+ RequestDevices(pending_remote<IsolatedXRRuntimeProviderClient> client);
};
// The main interface for the XR Device Service.
diff --git a/chromium/device/vr/public/mojom/vr_service.mojom b/chromium/device/vr/public/mojom/vr_service.mojom
index fb00428808c..5e53c01301f 100644
--- a/chromium/device/vr/public/mojom/vr_service.mojom
+++ b/chromium/device/vr/public/mojom/vr_service.mojom
@@ -52,6 +52,9 @@ enum XRSessionFeature {
REF_SPACE_LOCAL_FLOOR = 3,
REF_SPACE_BOUNDED_FLOOR = 4,
REF_SPACE_UNBOUNDED = 5,
+
+ // Experimental or not-yet-standardized feature names.
+ DOM_OVERLAY_FOR_HANDHELD_AR = 6,
};
struct XRSessionOptions {
@@ -80,15 +83,15 @@ struct XRSessionOptions {
// apropriate based on the session creation options. (for example, an immersive
// session ought to have a XRPresentationConnection to submit the frames to the
// immersive environment).
-// The XRSessionClient request must be fulfilled for the session to get
+// The XRSessionClient receiver must be fulfilled for the session to get
// information about the device it is connected to, such as focus and blur
// events, changes to view or stage parameters, or exit present calls initiated
// by the device.
struct XRSession {
- XRFrameDataProvider data_provider;
- // TODO(http://crbug.com/842025) Move where the client_request gets set to the
+ pending_remote<XRFrameDataProvider> data_provider;
+ // TODO(http://crbug.com/842025) Move where the client_receiver gets set to the
// device process then mark this as non-optional.
- XRSessionClient&? client_request;
+ pending_receiver<XRSessionClient>? client_receiver;
// TODO(http://crbug.com/842025) Move the information that is sent in display
// info to more sensible places so that this doesn't need to be sent here.
VRDisplayInfo display_info;
@@ -107,15 +110,14 @@ struct XRSession {
// way connection between the renderer and a device to synchronize and submit
// frames to a sink outside of Chrome.
struct XRPresentationConnection {
- XRPresentationProvider provider;
- XRPresentationClient& client_request;
+ pending_remote<XRPresentationProvider> provider;
+ pending_receiver<XRPresentationClient> client_receiver;
XRPresentationTransportOptions transport_options;
};
struct XRInputSourceDescription {
XRTargetRayMode target_ray_mode;
XRHandedness handedness;
- bool emulated_position;
// Transform from the grip matrix to the pointer's origin and orientation.
gfx.mojom.Transform? pointer_offset;
@@ -137,6 +139,10 @@ struct XRInputSourceState {
// Transform to the controllers grip (users palm) from start space origin.
gfx.mojom.Transform? grip;
+ // True when position is estimated by something like a neck or arm model.
+ // False when position is based on sensors tracking a 6DoF pose.
+ bool emulated_position;
+
// Describes the current state of the primary input.
bool primary_input_pressed;
@@ -174,6 +180,10 @@ struct VRPose {
gfx.mojom.Quaternion? orientation;
gfx.mojom.Point3F? position;
+ // True when position is estimated by something like a neck or arm model.
+ // False when position is based on sensors tracking a 6DoF pose.
+ bool emulated_position;
+
// Velocity/Acceleration is in global coordinates, as rad/s.
gfx.mojom.Vector3dF? angular_velocity;
gfx.mojom.Vector3dF? linear_velocity;
@@ -279,6 +289,31 @@ struct XRPresentationTransportOptions {
bool wait_for_gpu_fence;
};
+// Native origins that are reference spaces are identified by their category.
+// Currently, the device needs to know about 3 reference space categories.
+enum XRReferenceSpaceCategory {
+ LOCAL,
+ LOCAL_FLOOR,
+ VIEWER,
+ BOUNDED_FLOOR,
+ UNBOUNDED
+};
+
+// Native origin represents a reference space that is known to the device and
+// whose position can be tracked over time. There are multiple different types
+// of native origins (planes, anchors, reference spaces, input sources), each of
+// them roughly corresponds to something that either is an XRSpace (for example
+// XRReferenceSpaceType, XRBoundedReferenceSpace) or returns an XRSpace (for
+// example XRAnchor, XRPlane, XRInputSource). Native origin can be identified,
+// depending on its type, by the id of the entity (this is the case for planes,
+// anchors and input sources), or by reference space category.
+union XRNativeOriginInformation {
+ uint32 input_source_id;
+ uint32 plane_id;
+ uint32 anchor_id;
+ XRReferenceSpaceCategory reference_space_category;
+};
+
enum XRPlaneOrientation {
UNKNOWN = 0,
HORIZONTAL = 1,
@@ -294,7 +329,7 @@ struct XRPlanePointData {
// detected in the real world by the underlying system.
struct XRPlaneData {
// Unique (per session) identifier of the plane.
- int32 id;
+ uint32 id;
// Plane orientation relative to gravity.
XRPlaneOrientation orientation;
@@ -314,7 +349,7 @@ struct XRPlaneData {
// present in updated_planes_data.
struct XRPlaneDetectionData {
// Array with ids of all tracked planes.
- array<int32> all_planes_ids;
+ array<uint32> all_planes_ids;
// Array with plane data for all updated planes. Plane is considered updated
// if its position or polygon has changed. Updated planes are always a subset
@@ -329,7 +364,7 @@ struct XRPlaneDetectionData {
// evolves.
struct XRAnchorData {
// Unique (per session) identifier of the anchor.
- int32 id;
+ uint32 id;
// Pose of the anchor.
VRPose pose;
@@ -341,7 +376,7 @@ struct XRAnchorData {
// will not be present in updated_anchors_data.
struct XRAnchorsData {
// Array with ids of all tracked anchors.
- array<int32> all_anchors_ids;
+ array<uint32> all_anchors_ids;
// Array with anchor data for all updated anchors. Updated anchors are always
// a subset of all anchors (i.e. for each anchor found in
@@ -349,6 +384,18 @@ struct XRAnchorsData {
array<XRAnchorData> updated_anchors_data;
};
+// Information about results for a single subscription for the current frame.
+struct XRHitTestSubscriptionResultData {
+ uint32 subscription_id;
+ array<XRHitResult> hit_test_results;
+};
+
+// Struct containing data about results of all hit test subscriptions for the
+// current frame.
+struct XRHitTestSubscriptionResultsData {
+ array<XRHitTestSubscriptionResultData> results;
+};
+
// The data needed for each animation frame of an XRSession.
struct XRFrameData {
// General XRSession value
@@ -398,6 +445,10 @@ struct XRFrameData {
// Tracked anchors information.
XRAnchorsData? anchors_data;
+
+ // Hit test subscription results. Only present if the session supports
+ // environment integration.
+ XRHitTestSubscriptionResultsData? hit_test_subscription_results;
};
enum VRDisplayEventReason {
@@ -445,6 +496,15 @@ interface VRService {
GetImmersiveVRDisplayInfo() => (VRDisplayInfo? info);
ExitPresent();
+
+ // Used for the renderer process to indicate that it is throttling frame
+ // requests from the page, and thus it (not the page) is responsible for any
+ // drop in frame rate or delay in posting frames. This is mainly meant to be
+ // informational for the browser process, so that it can decide if or what UI
+ // to show if it seems like the frame rate is too low or has stalled. The
+ // renderer can (and may) still decide to submit frames and that should not be
+ // treated as illegal or clear the throttled state.
+ SetFramesThrottled(bool throttled);
};
// The interface for the renderer to listen to top level XR events, events that
@@ -454,9 +514,22 @@ interface VRServiceClient {
OnDeviceChanged();
};
+enum CreateAnchorResult {
+ SUCCESS = 0,
+ FAILURE = 1,
+};
+
+enum SubscribeToHitTestResult {
+ SUCCESS = 0,
+ FAILURE_GENERIC = 1,
+};
+
// Provides functionality for integrating environment information into an
// XRSession. For example, some AR sessions would implement hit test to allow
// developers to get the information about the world that its sensors supply.
+// On XRSession end, the message pipe will be destroyed - we need to clean up
+// all outstanding JavaScript promises at that time. The XRsession might end for
+// example due to a call to XRSession::end() method (exposed to JavaScript).
interface XREnvironmentIntegrationProvider {
// Performs a raycast into the scene and returns a list of XRHitResults sorted
// from closest to furthest hit from the ray. Each hit result contains a
@@ -465,6 +538,45 @@ interface XREnvironmentIntegrationProvider {
// An empty result list means there were no hits. If a nullopt is returned,
// there was an error.
RequestHitTest(XRRay ray) => (array<XRHitResult>? results);
+
+ // Establishes a hit test subscription on the device. The subscription results
+ // will be computed taking into account latest state of the native origin
+ // identified by passed in |native_origin_information|. I.e., in each frame,
+ // the ray used to subscribe to hit test will be transformed to device
+ // coordinate system using the device's current knowledge of the state of the
+ // native origin. The returned |subscription_id| uniquely identifies the
+ // subscription within an immersive session. Lifetime of the subscription is
+ // tied to the lifetime of the immersive session.
+ SubscribeToHitTest(
+ XRNativeOriginInformation native_origin_information, XRRay ray) =>
+ (SubscribeToHitTestResult result, uint32 subscription_id);
+
+ // Notifies the device that subscription with the passed in |subscription_id|
+ // is no longer needed and should be removed. The |subscription_id| must be a
+ // valid id of a subscription returned by one of the SubscribeToHitTest calls,
+ // otherwise the call will be ignored.
+ UnsubscribeFromHitTest(uint32 subscription_id);
+
+ // Issues a request to create an anchor attached to a session.
+ // |result| will contain status code of the request. |anchor_id| will be valid
+ // only if the |result| is SUCCESS.
+ CreateAnchor(VRPose anchor_pose) => (CreateAnchorResult result,
+ uint32 anchor_id);
+ // TODO(https://crbug.com/657632): Switch anchor_id to nullable integer once
+ // that's available. This will allow us to remove CreateAnchorResult if we're
+ // not interested in obtaining detailed error information from the device.
+
+ // Issues a request to create an anchor attached to a plane.
+ // |result| will contain status code of the request. |anchor_id| will be valid
+ // only if the |result| is SUCCESS.
+ CreatePlaneAnchor(VRPose anchor_pose, uint32 plane_id) =>
+ (CreateAnchorResult result, uint32 anchor_id);
+ // TODO(https://crbug.com/657632): Ditto - make anchor_id a nullable integer..
+
+ // Detaches an existing anchor. The |anchor_id| must be a valid id of an
+ // anchor created by one of the CreateAnchor calls, otherwise the call will be
+ // ignored.
+ DetachAnchor(uint32 anchor_id);
};
// Provides a mechanism for a channel to plumb up any button click events
@@ -490,9 +602,10 @@ interface XRFrameDataProvider {
// for some reason, such as device disconnection.
GetFrameData(XRFrameDataRequestOptions? options) => (XRFrameData? frame_data);
GetEnvironmentIntegrationProvider(
- associated XREnvironmentIntegrationProvider& environment_provider);
+ pending_associated_receiver<XREnvironmentIntegrationProvider>
+ environment_provider);
SetInputSourceButtonListener(
- associated XRInputSourceButtonListener? event_listener);
+ pending_associated_remote<XRInputSourceButtonListener>? event_listener);
};
// Provides the necessary functionality for sending frames to a headset.
@@ -561,12 +674,21 @@ interface XRPresentationClient {
OnSubmitFrameGpuFence(gfx.mojom.GpuFenceHandle gpu_fence_handle);
};
+enum XRVisibilityState {
+ // Indicates the WebXR content is visible to the user and receiving input.
+ VISIBLE = 1,
+ // Indicates the WebXR content is visible but not receiving input.
+ VISIBLE_BLURRED = 2,
+ // Indicates the WebXR content is not visible.
+ HIDDEN = 3
+};
+
// Functions for pushing device information to the sessions.
interface XRSessionClient {
OnChanged(VRDisplayInfo display);
OnExitPresent();
- OnBlur();
- OnFocus();
+ // Indicates a change in the visibility of the WebXR content.
+ OnVisibilityStateChanged(XRVisibilityState visibility_state);
};
// Backwards compatibility events for WebVR 1.1. These are expected to not be
diff --git a/chromium/device/vr/vr_device_base.cc b/chromium/device/vr/vr_device_base.cc
index 878dee57066..306b0aced64 100644
--- a/chromium/device/vr/vr_device_base.cc
+++ b/chromium/device/vr/vr_device_base.cc
@@ -11,8 +11,7 @@
namespace device {
-VRDeviceBase::VRDeviceBase(mojom::XRDeviceId id)
- : id_(id), runtime_binding_(this) {}
+VRDeviceBase::VRDeviceBase(mojom::XRDeviceId id) : id_(id) {}
VRDeviceBase::~VRDeviceBase() = default;
@@ -43,7 +42,7 @@ bool VRDeviceBase::HasExclusiveSession() {
}
void VRDeviceBase::ListenToDeviceChanges(
- mojom::XRRuntimeEventListenerAssociatedPtrInfo listener_info,
+ mojo::PendingAssociatedRemote<mojom::XRRuntimeEventListener> listener_info,
mojom::XRRuntime::ListenToDeviceChangesCallback callback) {
listener_.Bind(std::move(listener_info));
std::move(callback).Run(display_info_.Clone());
@@ -64,10 +63,14 @@ void VRDeviceBase::OnActivate(mojom::VRDisplayEventReason reason,
listener_->OnDeviceActivated(reason, std::move(on_handled));
}
-mojom::XRRuntimePtr VRDeviceBase::BindXRRuntimePtr() {
- mojom::XRRuntimePtr runtime;
- runtime_binding_.Bind(mojo::MakeRequest(&runtime));
- return runtime;
+void VRDeviceBase::OnVisibilityStateChanged(
+ mojom::XRVisibilityState visibility_state) {
+ if (listener_)
+ listener_->OnVisibilityStateChanged(visibility_state);
+}
+
+mojo::PendingRemote<mojom::XRRuntime> VRDeviceBase::BindXRRuntime() {
+ return runtime_receiver_.BindNewPipeAndPassRemote();
}
void VRDeviceBase::OnListeningForActivate(bool listening) {}
diff --git a/chromium/device/vr/vr_device_base.h b/chromium/device/vr/vr_device_base.h
index 42efcad5d6c..75218d81554 100644
--- a/chromium/device/vr/vr_device_base.h
+++ b/chromium/device/vr/vr_device_base.h
@@ -13,7 +13,10 @@
#include "device/vr/public/mojom/vr_service.mojom.h"
#include "device/vr/vr_device.h"
#include "device/vr/vr_export.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
+#include "mojo/public/cpp/bindings/pending_associated_remote.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
#include "ui/display/display.h"
namespace device {
@@ -28,7 +31,7 @@ class DEVICE_VR_EXPORT VRDeviceBase : public mojom::XRRuntime {
// VRDevice Implementation
void ListenToDeviceChanges(
- mojom::XRRuntimeEventListenerAssociatedPtrInfo listener,
+ mojo::PendingAssociatedRemote<mojom::XRRuntimeEventListener> listener,
mojom::XRRuntime::ListenToDeviceChangesCallback callback) final;
void SetListeningForActivate(bool is_listening) override;
void EnsureInitialized(EnsureInitializedCallback callback) override;
@@ -48,7 +51,7 @@ class DEVICE_VR_EXPORT VRDeviceBase : public mojom::XRRuntime {
mojom::VRDisplayInfoPtr GetVRDisplayInfo();
// Used by providers to bind devices.
- mojom::XRRuntimePtr BindXRRuntimePtr();
+ mojo::PendingRemote<mojom::XRRuntime> BindXRRuntime();
// TODO(mthiesse): The browser should handle browser-side exiting of
// presentation before device/ is even aware presentation is being exited.
@@ -65,6 +68,7 @@ class DEVICE_VR_EXPORT VRDeviceBase : public mojom::XRRuntime {
void SetVRDisplayInfo(mojom::VRDisplayInfoPtr display_info);
void OnActivate(mojom::VRDisplayEventReason reason,
base::Callback<void(bool)> on_handled);
+ void OnVisibilityStateChanged(mojom::XRVisibilityState visibility_state);
mojom::VRDisplayInfoPtr display_info_;
@@ -74,13 +78,13 @@ class DEVICE_VR_EXPORT VRDeviceBase : public mojom::XRRuntime {
// TODO(https://crbug.com/842227): Rename methods to HandleOnXXX
virtual void OnListeningForActivate(bool listening);
- mojom::XRRuntimeEventListenerAssociatedPtr listener_;
+ mojo::AssociatedRemote<mojom::XRRuntimeEventListener> listener_;
bool presenting_ = false;
device::mojom::XRDeviceId id_;
- mojo::Binding<mojom::XRRuntime> runtime_binding_;
+ mojo::Receiver<mojom::XRRuntime> runtime_receiver_{this};
DISALLOW_COPY_AND_ASSIGN(VRDeviceBase);
};
diff --git a/chromium/device/vr/vr_device_base_unittest.cc b/chromium/device/vr/vr_device_base_unittest.cc
index 9c489a010e6..e3cc39788c5 100644
--- a/chromium/device/vr/vr_device_base_unittest.cc
+++ b/chromium/device/vr/vr_device_base_unittest.cc
@@ -13,7 +13,8 @@
#include "device/vr/public/mojom/vr_service.mojom.h"
#include "device/vr/test/fake_vr_device.h"
#include "device/vr/vr_device_base.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -52,8 +53,8 @@ class VRDeviceBaseForTesting : public VRDeviceBase {
class StubVRDeviceEventListener : public mojom::XRRuntimeEventListener {
public:
- StubVRDeviceEventListener() : binding_(this) {}
- ~StubVRDeviceEventListener() override {}
+ StubVRDeviceEventListener() = default;
+ ~StubVRDeviceEventListener() override = default;
MOCK_METHOD1(DoOnChanged, void(mojom::VRDisplayInfo* vr_device_info));
void OnDisplayInfoChanged(mojom::VRDisplayInfoPtr vr_device_info) override {
@@ -71,18 +72,16 @@ class StubVRDeviceEventListener : public mojom::XRRuntimeEventListener {
}
MOCK_METHOD0(OnExitPresent, void());
- MOCK_METHOD0(OnBlur, void());
- MOCK_METHOD0(OnFocus, void());
+ MOCK_METHOD1(OnVisibilityStateChanged, void(mojom::XRVisibilityState));
MOCK_METHOD1(OnDeviceIdle, void(mojom::VRDisplayEventReason));
MOCK_METHOD0(OnInitialized, void());
- mojom::XRRuntimeEventListenerAssociatedPtrInfo BindPtrInfo() {
- mojom::XRRuntimeEventListenerAssociatedPtrInfo ret;
- binding_.Bind(mojo::MakeRequest(&ret));
- return ret;
+ mojo::PendingAssociatedRemote<mojom::XRRuntimeEventListener>
+ BindPendingRemote() {
+ return receiver_.BindNewEndpointAndPassRemote();
}
- mojo::AssociatedBinding<mojom::XRRuntimeEventListener> binding_;
+ mojo::AssociatedReceiver<mojom::XRRuntimeEventListener> receiver_{this};
};
} // namespace
@@ -117,10 +116,10 @@ class VRDeviceTest : public testing::Test {
// will receive the "vrdevicechanged" event.
TEST_F(VRDeviceTest, DeviceChangedDispatched) {
auto device = MakeVRDevice();
- auto device_ptr = device->BindXRRuntimePtr();
+ mojo::Remote<mojom::XRRuntime> device_remote(device->BindXRRuntime());
StubVRDeviceEventListener listener;
- device_ptr->ListenToDeviceChanges(
- listener.BindPtrInfo(),
+ device_remote->ListenToDeviceChanges(
+ listener.BindPendingRemote(),
base::DoNothing()); // TODO: consider getting initial info
base::RunLoop().RunUntilIdle();
EXPECT_CALL(listener, DoOnChanged(testing::_)).Times(1);
@@ -132,10 +131,10 @@ TEST_F(VRDeviceTest, DisplayActivateRegsitered) {
device::mojom::VRDisplayEventReason mounted =
device::mojom::VRDisplayEventReason::MOUNTED;
auto device = MakeVRDevice();
- auto device_ptr = device->BindXRRuntimePtr();
+ mojo::Remote<mojom::XRRuntime> device_remote(device->BindXRRuntime());
StubVRDeviceEventListener listener;
- device_ptr->ListenToDeviceChanges(
- listener.BindPtrInfo(),
+ device_remote->ListenToDeviceChanges(
+ listener.BindPendingRemote(),
base::DoNothing()); // TODO: consider getting initial data
base::RunLoop().RunUntilIdle();
diff --git a/chromium/device/vr/vr_device_provider.h b/chromium/device/vr/vr_device_provider.h
index 27616caa4f4..b40470766c7 100644
--- a/chromium/device/vr/vr_device_provider.h
+++ b/chromium/device/vr/vr_device_provider.h
@@ -9,6 +9,7 @@
#include "base/callback.h"
#include "device/vr/public/mojom/isolated_xr_service.mojom.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
namespace device {
@@ -21,7 +22,8 @@ class VRDeviceProvider {
virtual void Initialize(
base::RepeatingCallback<void(mojom::XRDeviceId id,
mojom::VRDisplayInfoPtr,
- mojom::XRRuntimePtr)> add_device_callback,
+ mojo::PendingRemote<mojom::XRRuntime>)>
+ add_device_callback,
base::RepeatingCallback<void(mojom::XRDeviceId id)>
remove_device_callback,
base::OnceClosure initialization_complete) = 0;
diff --git a/chromium/device/vr/windows/compositor_base.cc b/chromium/device/vr/windows/compositor_base.cc
index 0c8d6d1a4d8..9ec0f3359a7 100644
--- a/chromium/device/vr/windows/compositor_base.cc
+++ b/chromium/device/vr/windows/compositor_base.cc
@@ -5,7 +5,7 @@
#include "device/vr/windows/compositor_base.h"
#include "base/bind.h"
-#include "base/trace_event/common/trace_event_common.h"
+#include "base/trace_event/trace_event.h"
#include "ui/gfx/geometry/angle_conversions.h"
#include "ui/gfx/transform.h"
@@ -44,11 +44,7 @@ XRCompositorCommon::XRCompositorCommon()
: base::Thread("WindowsXRCompositor"),
main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
webxr_js_time_(kSlidingAverageSize),
- webxr_gpu_time_(kSlidingAverageSize),
- presentation_binding_(this),
- frame_data_binding_(this),
- gamepad_provider_(this),
- overlay_binding_(this) {
+ webxr_gpu_time_(kSlidingAverageSize) {
DCHECK(main_thread_task_runner_);
}
@@ -136,26 +132,26 @@ void XRCompositorCommon::SubmitFrameWithTextureHandle(
}
void XRCompositorCommon::CleanUp() {
- submit_client_ = nullptr;
+ submit_client_.reset();
webxr_has_pose_ = false;
- presentation_binding_.Close();
- frame_data_binding_.Close();
- gamepad_provider_.Close();
- overlay_binding_.Close();
- input_event_listener_ = nullptr;
+ presentation_receiver_.reset();
+ frame_data_receiver_.reset();
+ gamepad_provider_receiver_.reset();
+ overlay_receiver_.reset();
+ input_event_listener_.reset();
StopRuntime();
}
void XRCompositorCommon::RequestGamepadProvider(
- mojom::IsolatedXRGamepadProviderRequest request) {
- gamepad_provider_.Close();
- gamepad_provider_.Bind(std::move(request));
+ mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> receiver) {
+ gamepad_provider_receiver_.reset();
+ gamepad_provider_receiver_.Bind(std::move(receiver));
}
void XRCompositorCommon::RequestOverlay(
- mojom::ImmersiveOverlayRequest request) {
- overlay_binding_.Close();
- overlay_binding_.Bind(std::move(request));
+ mojo::PendingReceiver<mojom::ImmersiveOverlay> receiver) {
+ overlay_receiver_.reset();
+ overlay_receiver_.Bind(std::move(receiver));
// WebXR is visible and overlay hidden by default until the overlay overrides
// this.
@@ -192,12 +188,14 @@ void XRCompositorCommon::UpdateLayerBounds(int16_t frame_id,
void XRCompositorCommon::RequestSession(
base::OnceCallback<void()> on_presentation_ended,
+ base::RepeatingCallback<void(mojom::XRVisibilityState)>
+ on_visibility_state_changed,
mojom::XRRuntimeSessionOptionsPtr options,
RequestSessionCallback callback) {
DCHECK(options->immersive);
webxr_has_pose_ = false;
- presentation_binding_.Close();
- frame_data_binding_.Close();
+ presentation_receiver_.reset();
+ frame_data_receiver_.reset();
if (!StartRuntime()) {
TRACE_EVENT_INSTANT0("xr", "Failed to start runtime",
@@ -213,10 +211,15 @@ void XRCompositorCommon::RequestSession(
// be called.
on_presentation_ended_ = std::move(on_presentation_ended);
- device::mojom::XRPresentationProviderPtr presentation_provider;
- device::mojom::XRFrameDataProviderPtr frame_data_provider;
- presentation_binding_.Bind(mojo::MakeRequest(&presentation_provider));
- frame_data_binding_.Bind(mojo::MakeRequest(&frame_data_provider));
+ on_visibility_state_changed_ = std::move(on_visibility_state_changed);
+
+ // Queue up a notification to the requester of the current visibility state,
+ // so that it can be initialized to the right value.
+ if (on_visibility_state_changed_) {
+ main_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(on_visibility_state_changed_, visibility_state_));
+ }
device::mojom::XRPresentationTransportOptionsPtr transport_options =
device::mojom::XRPresentationTransportOptions::New();
@@ -229,12 +232,14 @@ void XRCompositorCommon::RequestSession(
OnSessionStart();
auto submit_frame_sink = device::mojom::XRPresentationConnection::New();
- submit_frame_sink->provider = presentation_provider.PassInterface();
- submit_frame_sink->client_request = mojo::MakeRequest(&submit_client_);
+ submit_frame_sink->provider =
+ presentation_receiver_.BindNewPipeAndPassRemote();
+ submit_frame_sink->client_receiver =
+ submit_client_.BindNewPipeAndPassReceiver();
submit_frame_sink->transport_options = std::move(transport_options);
auto session = device::mojom::XRSession::New();
- session->data_provider = frame_data_provider.PassInterface();
+ session->data_provider = frame_data_receiver_.BindNewPipeAndPassRemote();
session->submit_frame_sink = std::move(submit_frame_sink);
session->uses_input_eventing = UsesInputEventing();
@@ -249,9 +254,9 @@ void XRCompositorCommon::ExitPresent() {
TRACE_EVENT_INSTANT0("xr", "ExitPresent", TRACE_EVENT_SCOPE_THREAD);
is_presenting_ = false;
webxr_has_pose_ = false;
- presentation_binding_.Close();
- frame_data_binding_.Close();
- submit_client_ = nullptr;
+ presentation_receiver_.reset();
+ frame_data_receiver_.reset();
+ submit_client_.reset();
StopRuntime();
pending_frame_.reset();
@@ -265,7 +270,7 @@ void XRCompositorCommon::ExitPresent() {
// Kill outstanding overlays:
overlay_visible_ = false;
- overlay_binding_.Close();
+ overlay_receiver_.reset();
texture_helper_.SetSourceAndOverlayVisible(false, false);
@@ -275,6 +280,18 @@ void XRCompositorCommon::ExitPresent() {
}
}
+void XRCompositorCommon::SetVisibilityState(
+ mojom::XRVisibilityState visibility_state) {
+ if (visibility_state_ != visibility_state) {
+ visibility_state_ = visibility_state;
+ if (on_visibility_state_changed_) {
+ main_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(on_visibility_state_changed_, visibility_state));
+ }
+ }
+}
+
void XRCompositorCommon::UpdateControllerState() {
if (!gamepad_callback_) {
// Nobody is listening to updates, so bail early.
@@ -364,10 +381,11 @@ void XRCompositorCommon::GetFrameData(
}
void XRCompositorCommon::SetInputSourceButtonListener(
- device::mojom::XRInputSourceButtonListenerAssociatedPtrInfo
- input_listener_info) {
+ mojo::PendingAssociatedRemote<device::mojom::XRInputSourceButtonListener>
+ input_listener_remote) {
DCHECK(UsesInputEventing());
- input_event_listener_.Bind(std::move(input_listener_info));
+ input_event_listener_.reset();
+ input_event_listener_.Bind(std::move(input_listener_remote));
}
void XRCompositorCommon::GetControllerDataAndSendFrameData(
@@ -377,17 +395,25 @@ void XRCompositorCommon::GetControllerDataAndSendFrameData(
// Update gamepad controllers.
UpdateControllerState();
+ // This method represents a call from the renderer process. If our visibility
+ // state is hidden, we should avoid handing "sensitive" information, like the
+ // pose back up to the renderer. Note that this check is done here as other
+ // methods (RequestNextOverlayPose) represent a call from the browser process,
+ // which should receive the pose.
+ bool is_visible =
+ (visibility_state_ != device::mojom::XRVisibilityState::HIDDEN);
+
// We have posted a message to allow other calls to get through, and now state
// may have changed. WebXR may not be presenting any more, or may be hidden.
- std::move(callback).Run(is_presenting_ &&
+ std::move(callback).Run(is_presenting_ && is_visible &&
(webxr_visible_ || on_webxr_submitted_)
? std::move(frame_data)
: mojom::XRFrameData::New());
}
void XRCompositorCommon::GetEnvironmentIntegrationProvider(
- device::mojom::XREnvironmentIntegrationProviderAssociatedRequest
- environment_provider) {
+ mojo::PendingAssociatedReceiver<
+ device::mojom::XREnvironmentIntegrationProvider> environment_provider) {
// Environment integration is not supported. This call should not
// be made on this device.
mojo::ReportBadMessage("Environment integration is not supported.");
diff --git a/chromium/device/vr/windows/compositor_base.h b/chromium/device/vr/windows/compositor_base.h
index 6b924faf9a7..a8007193077 100644
--- a/chromium/device/vr/windows/compositor_base.h
+++ b/chromium/device/vr/windows/compositor_base.h
@@ -13,7 +13,12 @@
#include "device/vr/util/fps_meter.h"
#include "device/vr/util/sliding_average.h"
#include "device/vr/vr_device.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
+#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
+#include "mojo/public/cpp/bindings/pending_associated_remote.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "ui/gfx/geometry/rect_f.h"
@@ -55,6 +60,8 @@ class XRCompositorCommon : public base::Thread,
// callback will be called (since we haven't yet stopped presenting to the
// headset).
void RequestSession(base::OnceCallback<void()> on_presentation_ended,
+ base::RepeatingCallback<void(mojom::XRVisibilityState)>
+ on_visibility_state_changed,
mojom::XRRuntimeSessionOptionsPtr options,
RequestSessionCallback callback);
void ExitPresent();
@@ -62,21 +69,24 @@ class XRCompositorCommon : public base::Thread,
void GetFrameData(mojom::XRFrameDataRequestOptionsPtr options,
XRFrameDataProvider::GetFrameDataCallback callback) final;
void SetInputSourceButtonListener(
- device::mojom::XRInputSourceButtonListenerAssociatedPtrInfo
- input_listener_info) override;
+ mojo::PendingAssociatedRemote<device::mojom::XRInputSourceButtonListener>
+ input_listener_remote) override;
void GetControllerDataAndSendFrameData(
XRFrameDataProvider::GetFrameDataCallback callback,
mojom::XRFrameDataPtr frame_data);
void GetEnvironmentIntegrationProvider(
- device::mojom::XREnvironmentIntegrationProviderAssociatedRequest
- environment_provider) final;
+ mojo::PendingAssociatedReceiver<
+ device::mojom::XREnvironmentIntegrationProvider> environment_provider)
+ final;
- void RequestGamepadProvider(mojom::IsolatedXRGamepadProviderRequest request);
- void RequestOverlay(mojom::ImmersiveOverlayRequest request);
+ void RequestGamepadProvider(
+ mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> receiver);
+ void RequestOverlay(mojo::PendingReceiver<mojom::ImmersiveOverlay> receiver);
protected:
virtual bool UsesInputEventing();
+ void SetVisibilityState(mojom::XRVisibilityState visibility_state);
#if defined(OS_WIN)
D3D11TextureHelper texture_helper_;
#endif
@@ -84,7 +94,8 @@ class XRCompositorCommon : public base::Thread,
// Allow derived classes to call methods on the main thread.
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
- mojom::XRInputSourceButtonListenerAssociatedPtr input_event_listener_;
+ mojo::AssociatedRemote<mojom::XRInputSourceButtonListener>
+ input_event_listener_;
private:
// base::Thread overrides:
@@ -166,16 +177,21 @@ class XRCompositorCommon : public base::Thread,
gfx::RectF right_webxr_bounds_;
gfx::Size source_size_;
- mojom::XRPresentationClientPtr submit_client_;
+ mojo::Remote<mojom::XRPresentationClient> submit_client_;
SubmitOverlayTextureCallback overlay_submit_callback_;
RequestNotificationOnWebXrSubmittedCallback on_webxr_submitted_;
bool webxr_has_pose_ = false;
base::OnceCallback<void()> on_presentation_ended_;
+ base::RepeatingCallback<void(mojom::XRVisibilityState)>
+ on_visibility_state_changed_;
mojom::IsolatedXRGamepadProvider::RequestUpdateCallback gamepad_callback_;
- mojo::Binding<mojom::XRPresentationProvider> presentation_binding_;
- mojo::Binding<mojom::XRFrameDataProvider> frame_data_binding_;
- mojo::Binding<mojom::IsolatedXRGamepadProvider> gamepad_provider_;
- mojo::Binding<mojom::ImmersiveOverlay> overlay_binding_;
+ mojo::Receiver<mojom::XRPresentationProvider> presentation_receiver_{this};
+ mojo::Receiver<mojom::XRFrameDataProvider> frame_data_receiver_{this};
+ mojo::Receiver<mojom::IsolatedXRGamepadProvider> gamepad_provider_receiver_{
+ this};
+ mojo::Receiver<mojom::ImmersiveOverlay> overlay_receiver_{this};
+ mojom::XRVisibilityState visibility_state_ =
+ mojom::XRVisibilityState::VISIBLE;
DISALLOW_COPY_AND_ASSIGN(XRCompositorCommon);
};
diff --git a/chromium/device/vr/windows_mixed_reality/mixed_reality_device.cc b/chromium/device/vr/windows_mixed_reality/mixed_reality_device.cc
index 0ef4c48be91..75a546dbdf8 100644
--- a/chromium/device/vr/windows_mixed_reality/mixed_reality_device.cc
+++ b/chromium/device/vr/windows_mixed_reality/mixed_reality_device.cc
@@ -15,6 +15,7 @@
#include "build/build_config.h"
#include "device/vr/util/transform_utils.h"
#include "device/vr/windows_mixed_reality/mixed_reality_renderloop.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
#include "ui/gfx/geometry/angle_conversions.h"
namespace device {
@@ -61,10 +62,7 @@ mojom::VRDisplayInfoPtr CreateFakeVRDisplayInfo(device::mojom::XRDeviceId id) {
} // namespace
MixedRealityDevice::MixedRealityDevice()
- : VRDeviceBase(device::mojom::XRDeviceId::WINDOWS_MIXED_REALITY_ID),
- gamepad_provider_factory_binding_(this),
- compositor_host_binding_(this),
- exclusive_controller_binding_(this) {
+ : VRDeviceBase(device::mojom::XRDeviceId::WINDOWS_MIXED_REALITY_ID) {
SetVRDisplayInfo(CreateFakeVRDisplayInfo(GetId()));
}
@@ -72,17 +70,14 @@ MixedRealityDevice::~MixedRealityDevice() {
Shutdown();
}
-mojom::IsolatedXRGamepadProviderFactoryPtr
+mojo::PendingRemote<mojom::IsolatedXRGamepadProviderFactory>
MixedRealityDevice::BindGamepadFactory() {
- mojom::IsolatedXRGamepadProviderFactoryPtr ret;
- gamepad_provider_factory_binding_.Bind(mojo::MakeRequest(&ret));
- return ret;
+ return gamepad_provider_factory_receiver_.BindNewPipeAndPassRemote();
}
-mojom::XRCompositorHostPtr MixedRealityDevice::BindCompositorHost() {
- mojom::XRCompositorHostPtr ret;
- compositor_host_binding_.Bind(mojo::MakeRequest(&ret));
- return ret;
+mojo::PendingRemote<mojom::XRCompositorHost>
+MixedRealityDevice::BindCompositorHost() {
+ return compositor_host_receiver_.BindNewPipeAndPassRemote();
}
void MixedRealityDevice::RequestSession(
@@ -104,22 +99,22 @@ void MixedRealityDevice::RequestSession(
// memory exhaustion). If the thread fails to start, then we fail to create
// a session.
if (!render_loop_->IsRunning()) {
- std::move(callback).Run(nullptr, nullptr);
+ std::move(callback).Run(nullptr, mojo::NullRemote());
return;
}
- if (provider_request_) {
+ if (provider_receiver_) {
render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestGamepadProvider,
base::Unretained(render_loop_.get()),
- std::move(provider_request_)));
+ std::move(provider_receiver_)));
}
- if (overlay_request_) {
+ if (overlay_receiver_) {
render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
base::Unretained(render_loop_.get()),
- std::move(overlay_request_)));
+ std::move(overlay_receiver_)));
}
}
@@ -130,10 +125,15 @@ void MixedRealityDevice::RequestSession(
auto on_presentation_ended = base::BindOnce(
&MixedRealityDevice::OnPresentationEnded, weak_ptr_factory_.GetWeakPtr());
+ auto on_visibility_state_changed =
+ base::BindRepeating(&MixedRealityDevice::OnVisibilityStateChanged,
+ weak_ptr_factory_.GetWeakPtr());
+
render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestSession,
base::Unretained(render_loop_.get()),
std::move(on_presentation_ended),
+ std::move(on_visibility_state_changed),
std::move(options), std::move(my_callback)));
}
@@ -158,51 +158,49 @@ void MixedRealityDevice::OnRequestSessionResult(
mojom::XRSessionPtr session) {
if (!result) {
OnPresentationEnded();
- std::move(callback).Run(nullptr, nullptr);
+ std::move(callback).Run(nullptr, mojo::NullRemote());
return;
}
OnStartPresenting();
- mojom::XRSessionControllerPtr session_controller;
- exclusive_controller_binding_.Bind(mojo::MakeRequest(&session_controller));
+ session->display_info = display_info_.Clone();
+ std::move(callback).Run(
+ std::move(session),
+ exclusive_controller_receiver_.BindNewPipeAndPassRemote());
// Use of Unretained is safe because the callback will only occur if the
// binding is not destroyed.
- exclusive_controller_binding_.set_connection_error_handler(base::BindOnce(
+ exclusive_controller_receiver_.set_disconnect_handler(base::BindOnce(
&MixedRealityDevice::OnPresentingControllerMojoConnectionError,
base::Unretained(this)));
-
- session->display_info = display_info_.Clone();
-
- std::move(callback).Run(std::move(session), std::move(session_controller));
}
void MixedRealityDevice::GetIsolatedXRGamepadProvider(
- mojom::IsolatedXRGamepadProviderRequest provider_request) {
+ mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver) {
if (!render_loop_)
CreateRenderLoop();
if (render_loop_->IsRunning()) {
render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestGamepadProvider,
base::Unretained(render_loop_.get()),
- std::move(provider_request)));
+ std::move(provider_receiver)));
} else {
- provider_request_ = std::move(provider_request);
+ provider_receiver_ = std::move(provider_receiver);
}
}
void MixedRealityDevice::CreateImmersiveOverlay(
- mojom::ImmersiveOverlayRequest overlay_request) {
+ mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver) {
if (!render_loop_)
CreateRenderLoop();
if (render_loop_->IsRunning()) {
render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
base::Unretained(render_loop_.get()),
- std::move(overlay_request)));
+ std::move(overlay_receiver)));
} else {
- overlay_request_ = std::move(overlay_request);
+ overlay_receiver_ = std::move(overlay_receiver);
}
}
@@ -223,7 +221,7 @@ void MixedRealityDevice::OnPresentingControllerMojoConnectionError() {
// TODO(https://crbug.com/875187): Alternatively, we could recreate the
// provider on the next session, or look into why the callback gets lost.
OnExitPresent();
- exclusive_controller_binding_.Close();
+ exclusive_controller_receiver_.reset();
}
} // namespace device
diff --git a/chromium/device/vr/windows_mixed_reality/mixed_reality_device.h b/chromium/device/vr/windows_mixed_reality/mixed_reality_device.h
index 8b13a5406b2..234dc24d6de 100644
--- a/chromium/device/vr/windows_mixed_reality/mixed_reality_device.h
+++ b/chromium/device/vr/windows_mixed_reality/mixed_reality_device.h
@@ -13,7 +13,9 @@
#include "device/vr/public/mojom/vr_service.mojom.h"
#include "device/vr/vr_device_base.h"
#include "device/vr/windows/compositor_base.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
namespace device {
@@ -26,8 +28,9 @@ class DEVICE_VR_EXPORT MixedRealityDevice
MixedRealityDevice();
~MixedRealityDevice() override;
- mojom::IsolatedXRGamepadProviderFactoryPtr BindGamepadFactory();
- mojom::XRCompositorHostPtr BindCompositorHost();
+ mojo::PendingRemote<mojom::IsolatedXRGamepadProviderFactory>
+ BindGamepadFactory();
+ mojo::PendingRemote<mojom::XRCompositorHost> BindCompositorHost();
private:
// VRDeviceBase
@@ -40,11 +43,12 @@ class DEVICE_VR_EXPORT MixedRealityDevice
// mojom::IsolatedXRGamepadProviderFactory
void GetIsolatedXRGamepadProvider(
- mojom::IsolatedXRGamepadProviderRequest provider_request) override;
+ mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver)
+ override;
// XRCompositorHost
void CreateImmersiveOverlay(
- mojom::ImmersiveOverlayRequest overlay_request) override;
+ mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver) override;
void CreateRenderLoop();
void Shutdown();
@@ -56,14 +60,15 @@ class DEVICE_VR_EXPORT MixedRealityDevice
std::unique_ptr<XRCompositorCommon> render_loop_;
- mojo::Binding<mojom::IsolatedXRGamepadProviderFactory>
- gamepad_provider_factory_binding_;
- mojom::IsolatedXRGamepadProviderRequest provider_request_;
+ mojo::Receiver<mojom::IsolatedXRGamepadProviderFactory>
+ gamepad_provider_factory_receiver_{this};
+ mojo::PendingReceiver<mojom::IsolatedXRGamepadProvider> provider_receiver_;
- mojo::Binding<mojom::XRCompositorHost> compositor_host_binding_;
- mojom::ImmersiveOverlayRequest overlay_request_;
+ mojo::Receiver<mojom::XRCompositorHost> compositor_host_receiver_{this};
+ mojo::PendingReceiver<mojom::ImmersiveOverlay> overlay_receiver_;
- mojo::Binding<mojom::XRSessionController> exclusive_controller_binding_;
+ mojo::Receiver<mojom::XRSessionController> exclusive_controller_receiver_{
+ this};
base::WeakPtrFactory<MixedRealityDevice> weak_ptr_factory_{this};
diff --git a/chromium/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc b/chromium/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc
index 688c02cdb7c..5c3f02ef21a 100644
--- a/chromium/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc
+++ b/chromium/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc
@@ -43,6 +43,8 @@ using Handedness =
using PressKind = ABI::Windows::UI::Input::Spatial::SpatialInteractionPressKind;
using SourceKind =
ABI::Windows::UI::Input::Spatial::SpatialInteractionSourceKind;
+using PositionAccuracy =
+ ABI::Windows::UI::Input::Spatial::SpatialInteractionSourcePositionAccuracy;
ParsedInputState::ParsedInputState() = default;
ParsedInputState::~ParsedInputState() = default;
@@ -503,6 +505,7 @@ ParsedInputState MixedRealityInputHelper::ParseWindowsSourceState(
// Voice input is always untracked.
gfx::Transform origin_from_grip;
bool is_tracked = false;
+ bool emulated_position = false;
if (is_controller) {
input_state.button_data = ParseButtonState(state);
std::unique_ptr<WMRInputLocation> location_in_origin =
@@ -516,6 +519,15 @@ ParsedInputState MixedRealityInputHelper::ParseWindowsSourceState(
is_tracked = true;
}
+ PositionAccuracy position_accuracy;
+ if (location_in_origin->TryGetPositionAccuracy(&position_accuracy) &&
+ (position_accuracy ==
+ PositionAccuracy::
+ SpatialInteractionSourcePositionAccuracy_Approximate)) {
+ // Controller lost precise tracking or has its position estimated.
+ emulated_position = true;
+ }
+
input_state.gamepad_pose = gamepad_pose;
}
@@ -552,8 +564,7 @@ ParsedInputState MixedRealityInputHelper::ParseWindowsSourceState(
device::mojom::XRInputSourceDescriptionPtr description =
device::mojom::XRInputSourceDescription::New();
- // If we've gotten this far we've gotten the real position.
- description->emulated_position = false;
+ source_state->emulated_position = emulated_position;
description->pointer_offset = grip_from_pointer;
if (is_voice) {
@@ -575,7 +586,8 @@ ParsedInputState MixedRealityInputHelper::ParseWindowsSourceState(
// This makes it clear that the controller actually has a grip button and
// touchpad and thumbstick input. Otherwise, it's ambiguous whether slots
// like the touchpad buttons + axes are hooked up vs just placeholders.
- description->profiles.push_back("grip-touchpad-thumbstick-controller");
+ description->profiles.push_back(
+ "generic-trigger-squeeze-touchpad-thumbstick");
source_state->gamepad = GetWebXRGamepad(input_state);
} else {
diff --git a/chromium/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc b/chromium/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc
index 747221d0a6b..5705d5160f6 100644
--- a/chromium/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc
+++ b/chromium/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc
@@ -14,7 +14,8 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/trace_event/common/trace_event_common.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
#include "base/win/com_init_util.h"
#include "base/win/core_winrt_util.h"
#include "base/win/scoped_co_mem.h"
@@ -44,6 +45,8 @@ using SpatialMovementRange =
using ABI::Windows::Foundation::DateTime;
using ABI::Windows::Foundation::TimeSpan;
using ABI::Windows::Foundation::Numerics::Matrix4x4;
+using HolographicSpaceUserPresence =
+ ABI::Windows::Graphics::Holographic::HolographicSpaceUserPresence;
using ABI::Windows::Graphics::Holographic::HolographicStereoTransform;
using Microsoft::WRL::ComPtr;
@@ -221,6 +224,15 @@ bool MixedRealityRenderLoop::StartRuntime() {
if (!holographic_space_)
return false;
+ // Since we explicitly null out both the holographic_space and the
+ // subscription during StopRuntime (which happens before destruction),
+ // base::Unretained is safe.
+ user_presence_changed_subscription_ =
+ holographic_space_->AddUserPresenceChangedCallback(
+ base::BindRepeating(&MixedRealityRenderLoop::OnUserPresenceChanged,
+ base::Unretained(this)));
+ UpdateVisibilityState();
+
input_helper_ = std::make_unique<MixedRealityInputHelper>(
window_->hwnd(), weak_ptr_factory_.GetWeakPtr());
@@ -252,7 +264,19 @@ bool MixedRealityRenderLoop::StartRuntime() {
if (FAILED(hr))
return false;
- return holographic_space_->TrySetDirect3D11Device(device);
+ if (!holographic_space_->TrySetDirect3D11Device(device))
+ return false;
+
+ // Go through one initial dummy frame to update the display info and notify
+ // the device of the correct values before it sends the initial info to the
+ // renderer. The frame must be submitted because WMR requires frames to be
+ // submitted in the order they're created.
+ UpdateWMRDataForNextFrame();
+ UpdateDisplayInfo();
+ main_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(on_display_info_changed_, current_display_info_.Clone()));
+ return SubmitCompositedFrame();
}
void MixedRealityRenderLoop::StopRuntime() {
@@ -272,6 +296,8 @@ void MixedRealityRenderLoop::StopRuntime() {
rendering_params_ = nullptr;
camera_ = nullptr;
+ user_presence_changed_subscription_ = nullptr;
+
if (input_helper_)
input_helper_->Dispose();
input_helper_ = nullptr;
@@ -378,6 +404,51 @@ void MixedRealityRenderLoop::OnCurrentStageChanged() {
base::Unretained(this)));
}
+void MixedRealityRenderLoop::OnUserPresenceChanged() {
+ // Unretained is safe here because the task_runner() gets invalidated
+ // during Stop() which happens before our destruction
+ task_runner()->PostTask(FROM_HERE,
+ base::BindOnce(
+ [](MixedRealityRenderLoop* render_loop) {
+ render_loop->UpdateVisibilityState();
+ },
+ base::Unretained(this)));
+}
+
+void MixedRealityRenderLoop::UpdateVisibilityState() {
+ // We could've had a task get queued up during or before a StopRuntime call.
+ // Which would lead to the holographic space being null. In that case, don't
+ // update the visibility state. We'll get the fresh state when and if the
+ // runtime starts back up again.
+ if (!holographic_space_) {
+ return;
+ }
+
+ switch (holographic_space_->UserPresence()) {
+ // Indicates that the browsers immersive content is visible in the headset
+ // receiving input, and the headset is being worn.
+ case HolographicSpaceUserPresence::
+ HolographicSpaceUserPresence_PresentActive:
+ SetVisibilityState(device::mojom::XRVisibilityState::VISIBLE);
+ return;
+ // Indicates that the browsers immersive content is visible in the headset
+ // and the headset is being worn, but a modal dialog is capturing input.
+ case HolographicSpaceUserPresence::
+ HolographicSpaceUserPresence_PresentPassive:
+ // TODO(1016907): Should report VISIBLE_BLURRED, but changed to VISIBLE to
+ // work around an issue in some versions of Windows Mixed Reality which
+ // only report PresentPassive and never PresentActive. Should be reverted
+ // after the Windows fix has been widely released.
+ SetVisibilityState(device::mojom::XRVisibilityState::VISIBLE);
+ return;
+ // Indicates that the browsers immersive content is not visible in the
+ // headset or the user is not wearing the headset.
+ case HolographicSpaceUserPresence::HolographicSpaceUserPresence_Absent:
+ SetVisibilityState(device::mojom::XRVisibilityState::HIDDEN);
+ return;
+ }
+}
+
void MixedRealityRenderLoop::EnsureStageBounds() {
if (!spatial_stage_)
return;
@@ -759,8 +830,6 @@ mojom::XRFrameDataPtr MixedRealityRenderLoop::GetNextFrameData() {
if (anchor_origin_ &&
pose_->TryGetViewTransform(anchor_origin_.get(), &view)) {
got_view = true;
- // TODO(http://crbug.com/931393): Send down emulated_position_, and report
- // reset events when this changes.
emulated_position_ = false;
ABI::Windows::Foundation::Numerics::Matrix4x4 origin_from_attached;
if (attached_coordinates->TryGetTransformTo(anchor_origin_.get(),
@@ -836,6 +905,8 @@ mojom::XRFrameDataPtr MixedRealityRenderLoop::GetNextFrameData() {
ret->pose->input_state =
input_helper_->GetInputState(anchor_origin_.get(), timestamp_.get());
+ ret->pose->emulated_position = emulated_position_;
+
if (emulated_position_ && last_origin_from_attached_) {
gfx::DecomposedTransform attached_from_view_decomp;
attached_from_view_decomp.quaternion = (*ret->pose->orientation);
diff --git a/chromium/device/vr/windows_mixed_reality/mixed_reality_renderloop.h b/chromium/device/vr/windows_mixed_reality/mixed_reality_renderloop.h
index 863d04056a7..05f1cdfbbe1 100644
--- a/chromium/device/vr/windows_mixed_reality/mixed_reality_renderloop.h
+++ b/chromium/device/vr/windows_mixed_reality/mixed_reality_renderloop.h
@@ -79,6 +79,9 @@ class MixedRealityRenderLoop : public XRCompositorCommon {
void ClearStageStatics();
void OnCurrentStageChanged();
+ void OnUserPresenceChanged();
+ void UpdateVisibilityState();
+
// Will try to update the stage bounds if the following are true:
// 1) We have a spatial_stage.
// 2) That spatial stage supports bounded movement.
@@ -119,6 +122,9 @@ class MixedRealityRenderLoop : public XRCompositorCommon {
std::unique_ptr<base::CallbackList<void()>::Subscription>
stage_changed_subscription_;
+ std::unique_ptr<base::CallbackList<void()>::Subscription>
+ user_presence_changed_subscription_;
+
std::vector<gfx::Point3F> bounds_;
bool bounds_updated_ = false;
diff --git a/chromium/device/vr/windows_mixed_reality/mixed_reality_statics.cc b/chromium/device/vr/windows_mixed_reality/mixed_reality_statics.cc
index b58e5f3ef18..138333ddf2b 100644
--- a/chromium/device/vr/windows_mixed_reality/mixed_reality_statics.cc
+++ b/chromium/device/vr/windows_mixed_reality/mixed_reality_statics.cc
@@ -17,11 +17,8 @@
namespace device {
-// TODO(crbug.com/941546): Remove namespaces to comply with coding standard.
-using namespace ABI::Windows::Graphics::Holographic;
-using namespace Microsoft::WRL;
-using namespace Microsoft::WRL::Wrappers;
-using namespace Windows::Foundation;
+namespace Holographic = ABI::Windows::Graphics::Holographic;
+using Microsoft::WRL::ComPtr;
class DEVICE_VR_EXPORT MixedRealityDeviceStaticsImpl
: public MixedRealityDeviceStatics {
@@ -34,7 +31,7 @@ class DEVICE_VR_EXPORT MixedRealityDeviceStaticsImpl
private:
// Adds get_IsAvailable and get_IsSupported to HolographicSpaceStatics.
- ComPtr<IHolographicSpaceStatics2> holographic_space_statics_;
+ ComPtr<Holographic::IHolographicSpaceStatics2> holographic_space_statics_;
};
VRTestHook* MixedRealityDeviceStatics::test_hook_ = nullptr;
@@ -73,7 +70,7 @@ MixedRealityDeviceStaticsImpl::MixedRealityDeviceStaticsImpl() {
base::win::ScopedHString holographic_space_string =
base::win::ScopedHString::Create(
RuntimeClass_Windows_Graphics_Holographic_HolographicSpace);
- ComPtr<IHolographicSpaceStatics> holographic_space_statics;
+ ComPtr<Holographic::IHolographicSpaceStatics> holographic_space_statics;
HRESULT hr = base::win::RoGetActivationFactory(
holographic_space_string.get(), IID_PPV_ARGS(&holographic_space_statics));
if (FAILED(hr))
diff --git a/chromium/device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.cc b/chromium/device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.cc
index d45d7c208c6..8c55dfbcb05 100644
--- a/chromium/device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.cc
+++ b/chromium/device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.cc
@@ -18,21 +18,36 @@
#include "device/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_space.h"
#include "device/vr/windows_mixed_reality/wrappers/wmr_holographic_frame.h"
+using ABI::Windows::Foundation::ITypedEventHandler;
using ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice;
using ABI::Windows::Graphics::Holographic::HolographicAdapterId;
+using ABI::Windows::Graphics::Holographic::HolographicSpace;
+using HolographicSpaceUserPresence =
+ ABI::Windows::Graphics::Holographic::HolographicSpaceUserPresence;
using ABI::Windows::Graphics::Holographic::IHolographicFrame;
using ABI::Windows::Graphics::Holographic::IHolographicSpace;
+using ABI::Windows::Graphics::Holographic::IHolographicSpace2;
+using Microsoft::WRL::Callback;
using Microsoft::WRL::ComPtr;
+typedef ITypedEventHandler<HolographicSpace*, IInspectable*>
+ HolographicSpaceEventHandler;
+
namespace device {
WMRHolographicSpaceImpl::WMRHolographicSpaceImpl(
ComPtr<IHolographicSpace> space)
: space_(space) {
DCHECK(space_);
+ HRESULT hr = space_.As(&space2_);
+ if (SUCCEEDED(hr)) {
+ SubscribeEvents();
+ }
}
-WMRHolographicSpaceImpl::~WMRHolographicSpaceImpl() = default;
+WMRHolographicSpaceImpl::~WMRHolographicSpaceImpl() {
+ UnsubscribeEvents();
+}
HolographicAdapterId WMRHolographicSpaceImpl::PrimaryAdapterId() {
HolographicAdapterId id;
@@ -55,4 +70,52 @@ bool WMRHolographicSpaceImpl::TrySetDirect3D11Device(
HRESULT hr = space_->SetDirect3D11Device(device.Get());
return SUCCEEDED(hr);
}
+
+HolographicSpaceUserPresence WMRHolographicSpaceImpl::UserPresence() {
+ HolographicSpaceUserPresence user_presence =
+ HolographicSpaceUserPresence::HolographicSpaceUserPresence_PresentActive;
+ if (space2_) {
+ HRESULT hr = space2_->get_UserPresence(&user_presence);
+ DCHECK(SUCCEEDED(hr));
+ }
+ return user_presence;
+}
+
+std::unique_ptr<base::CallbackList<void()>::Subscription>
+WMRHolographicSpaceImpl::AddUserPresenceChangedCallback(
+ const base::RepeatingCallback<void()>& cb) {
+ return user_presence_changed_callback_list_.Add(cb);
+}
+
+HRESULT WMRHolographicSpaceImpl::OnUserPresenceChanged(IHolographicSpace*,
+ IInspectable*) {
+ user_presence_changed_callback_list_.Notify();
+ return S_OK;
+}
+
+void WMRHolographicSpaceImpl::SubscribeEvents() {
+ if (!space2_) {
+ return;
+ }
+ // The destructor ensures that we're unsubscribed so raw this is fine.
+ auto user_presence_changed_callback = Callback<HolographicSpaceEventHandler>(
+ this, &WMRHolographicSpaceImpl::OnUserPresenceChanged);
+ HRESULT hr = space2_->add_UserPresenceChanged(
+ user_presence_changed_callback.Get(), &user_presence_changed_token_);
+ DCHECK(SUCCEEDED(hr));
+}
+
+void WMRHolographicSpaceImpl::UnsubscribeEvents() {
+ if (!space2_) {
+ return;
+ }
+
+ HRESULT hr = S_OK;
+ if (user_presence_changed_token_.value != 0) {
+ hr = space2_->remove_UserPresenceChanged(user_presence_changed_token_);
+ user_presence_changed_token_.value = 0;
+ DCHECK(SUCCEEDED(hr));
+ }
+}
+
} // namespace device
diff --git a/chromium/device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.h b/chromium/device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.h
index f213a7a6c74..f63859b1aa8 100644
--- a/chromium/device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.h
+++ b/chromium/device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.h
@@ -9,6 +9,7 @@
#include <memory>
+#include "base/callback_list.h"
#include "base/macros.h"
namespace device {
@@ -24,6 +25,10 @@ class WMRHolographicSpace {
const Microsoft::WRL::ComPtr<
ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice>&
device) = 0;
+ virtual ABI::Windows::Graphics::Holographic::HolographicSpaceUserPresence
+ UserPresence() = 0;
+ virtual std::unique_ptr<base::CallbackList<void()>::Subscription>
+ AddUserPresenceChangedCallback(const base::RepeatingCallback<void()>& cb) = 0;
};
class WMRHolographicSpaceImpl : public WMRHolographicSpace {
@@ -40,10 +45,28 @@ class WMRHolographicSpaceImpl : public WMRHolographicSpace {
const Microsoft::WRL::ComPtr<
ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice>& device)
override;
+ ABI::Windows::Graphics::Holographic::HolographicSpaceUserPresence
+ UserPresence() override;
+ std::unique_ptr<base::CallbackList<void()>::Subscription>
+ AddUserPresenceChangedCallback(
+ const base::RepeatingCallback<void()>& cb) override;
private:
+ void SubscribeEvents();
+ void UnsubscribeEvents();
+
+ HRESULT OnUserPresenceChanged(
+ ABI::Windows::Graphics::Holographic::IHolographicSpace*,
+ IInspectable*);
+
Microsoft::WRL::ComPtr<ABI::Windows::Graphics::Holographic::IHolographicSpace>
space_;
+ Microsoft::WRL::ComPtr<
+ ABI::Windows::Graphics::Holographic::IHolographicSpace2>
+ space2_;
+
+ EventRegistrationToken user_presence_changed_token_;
+ base::CallbackList<void()> user_presence_changed_callback_list_;
DISALLOW_COPY_AND_ASSIGN(WMRHolographicSpaceImpl);
};
diff --git a/chromium/device/vr/windows_mixed_reality/wrappers/wmr_input_location.cc b/chromium/device/vr/windows_mixed_reality/wrappers/wmr_input_location.cc
index 8f2b7714a26..e0b8c9b2bf1 100644
--- a/chromium/device/vr/windows_mixed_reality/wrappers/wmr_input_location.cc
+++ b/chromium/device/vr/windows_mixed_reality/wrappers/wmr_input_location.cc
@@ -83,4 +83,15 @@ bool WMRInputLocationImpl::TryGetAngularVelocity(
return TryGetValue(ref, angular_velocity);
}
+bool WMRInputLocationImpl::TryGetPositionAccuracy(
+ ABI::Windows::UI::Input::Spatial::SpatialInteractionSourcePositionAccuracy*
+ position_accuracy) const {
+ DCHECK(position_accuracy);
+ if (!location3_)
+ return false;
+ HRESULT hr = location3_->get_PositionAccuracy(position_accuracy);
+ DCHECK(SUCCEEDED(hr));
+ return true;
+}
+
} // namespace device
diff --git a/chromium/device/vr/windows_mixed_reality/wrappers/wmr_input_location.h b/chromium/device/vr/windows_mixed_reality/wrappers/wmr_input_location.h
index 7052cc141d7..2d61915aa02 100644
--- a/chromium/device/vr/windows_mixed_reality/wrappers/wmr_input_location.h
+++ b/chromium/device/vr/windows_mixed_reality/wrappers/wmr_input_location.h
@@ -24,6 +24,10 @@ class WMRInputLocation {
virtual bool TryGetAngularVelocity(
ABI::Windows::Foundation::Numerics::Vector3* angular_velocity) const = 0;
+ virtual bool TryGetPositionAccuracy(
+ ABI::Windows::UI::Input::Spatial::
+ SpatialInteractionSourcePositionAccuracy* position_accuracy)
+ const = 0;
};
class WMRInputLocationImpl : public WMRInputLocation {
@@ -47,6 +51,9 @@ class WMRInputLocationImpl : public WMRInputLocation {
// Uses ISpatialInteractionSourceLocation3.
bool TryGetAngularVelocity(ABI::Windows::Foundation::Numerics::Vector3*
angular_velocity) const override;
+ bool TryGetPositionAccuracy(ABI::Windows::UI::Input::Spatial::
+ SpatialInteractionSourcePositionAccuracy*
+ position_accuracy) const override;
private:
Microsoft::WRL::ComPtr<