From c8c2d1901aec01e934adf561a9fdf0cc776cdef8 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 29 Jan 2018 16:35:13 +0100 Subject: BASELINE: Update Chromium to 64.0.3282.139 Change-Id: I1cae68fe9c94ff7608b26b8382fc19862cdb293a Reviewed-by: Alexandru Croitor --- chromium/components/arc/BUILD.gn | 98 +-- chromium/components/arc/DEPS | 3 + chromium/components/arc/arc_bridge_host_impl.cc | 40 +- chromium/components/arc/arc_bridge_host_impl.h | 9 +- chromium/components/arc/arc_bridge_service.cc | 2 + chromium/components/arc/arc_bridge_service.h | 231 ++++--- .../components/arc/arc_data_remover_unittest.cc | 1 + chromium/components/arc/arc_features.cc | 4 +- chromium/components/arc/arc_instance_mode.cc | 21 +- chromium/components/arc/arc_instance_mode.h | 4 + chromium/components/arc/arc_prefs.cc | 8 +- chromium/components/arc/arc_prefs.h | 1 - chromium/components/arc/arc_session.cc | 681 +-------------------- chromium/components/arc/arc_session.h | 31 +- chromium/components/arc/arc_session_impl.cc | 637 +++++++++++++++++++ chromium/components/arc/arc_session_impl.h | 242 ++++++++ .../components/arc/arc_session_impl_unittest.cc | 648 ++++++++++++++++++++ chromium/components/arc/arc_session_runner.cc | 119 +++- chromium/components/arc/arc_session_runner.h | 23 +- .../components/arc/arc_session_runner_unittest.cc | 164 ++++- chromium/components/arc/arc_stop_reason.h | 5 +- chromium/components/arc/arc_util.cc | 5 + chromium/components/arc/arc_util_unittest.cc | 43 +- chromium/components/arc/audio/arc_audio_bridge.cc | 15 +- chromium/components/arc/audio/arc_audio_bridge.h | 13 +- .../bluetooth_type_converters_unittest.cc | 616 +++++++++---------- .../arc/clipboard/arc_clipboard_bridge.cc | 14 +- .../arc/clipboard/arc_clipboard_bridge.h | 14 +- chromium/components/arc/common/BUILD.gn | 76 +++ chromium/components/arc/common/DEPS | 3 + .../arc/common/accessibility_helper.mojom | 50 +- chromium/components/arc/common/app.mojom | 59 +- chromium/components/arc/common/app.typemap | 15 - .../components/arc/common/app_struct_traits.cc | 20 - chromium/components/arc/common/app_struct_traits.h | 24 - chromium/components/arc/common/arc_bridge.mojom | 8 +- .../components/arc/common/arc_gfx_struct_traits.cc | 28 + .../components/arc/common/arc_gfx_struct_traits.h | 34 + chromium/components/arc/common/audio.mojom | 9 +- chromium/components/arc/common/auth.mojom | 9 +- .../components/arc/common/backup_settings.mojom | 16 + chromium/components/arc/common/bluetooth.mojom | 10 +- chromium/components/arc/common/bluetooth.typemap | 3 + .../components/arc/common/boot_phase_monitor.mojom | 9 +- chromium/components/arc/common/cert_store.mojom | 9 +- chromium/components/arc/common/clipboard.mojom | 13 +- .../components/arc/common/crash_collector.mojom | 10 +- .../arc/common/enterprise_reporting.mojom | 9 +- chromium/components/arc/common/file_system.mojom | 9 +- chromium/components/arc/common/file_system.typemap | 3 + chromium/components/arc/common/gfx.mojom | 28 + chromium/components/arc/common/gfx.typemap | 25 + chromium/components/arc/common/ime.mojom | 41 +- chromium/components/arc/common/ime.typemap | 20 - chromium/components/arc/common/intent_helper.mojom | 44 +- chromium/components/arc/common/kiosk.mojom | 11 +- chromium/components/arc/common/metrics.mojom | 10 +- chromium/components/arc/common/midis.mojom | 10 +- chromium/components/arc/common/net.mojom | 9 +- chromium/components/arc/common/notifications.mojom | 31 +- chromium/components/arc/common/obb_mounter.mojom | 10 +- chromium/components/arc/common/oemcrypto.mojom | 10 +- .../components/arc/common/oemcrypto_daemon.mojom | 2 +- chromium/components/arc/common/policy.mojom | 9 +- chromium/components/arc/common/power.mojom | 9 +- chromium/components/arc/common/print.mojom | 9 +- .../arc/common/protected_buffer_manager.mojom | 2 +- chromium/components/arc/common/screen_rect.mojom | 13 - chromium/components/arc/common/tts.mojom | 9 +- chromium/components/arc/common/typemaps.gni | 4 +- chromium/components/arc/common/video.mojom | 14 +- .../arc/common/video_accelerator_struct_traits.cc | 30 + .../arc/common/video_accelerator_struct_traits.h | 46 ++ .../components/arc/common/video_common.typemap | 10 +- .../arc/common/video_decode_accelerator.mojom | 10 +- .../arc/common/video_encode_accelerator.mojom | 15 +- .../arc/common/video_encode_accelerator.typemap | 7 +- .../video_encode_accelerator_struct_traits.cc | 169 +++++ .../video_encode_accelerator_struct_traits.h | 68 ++ .../arc/common/voice_interaction_arc_home.mojom | 23 +- .../arc/common/voice_interaction_framework.mojom | 31 +- .../arc/common/voice_interaction_framework.typemap | 13 - .../components/arc/common/volume_mounter.typemap | 10 +- chromium/components/arc/common/wallpaper.mojom | 13 +- chromium/components/arc/connection_holder.h | 386 ++++++++++++ chromium/components/arc/connection_notifier.cc | 39 ++ chromium/components/arc/connection_notifier.h | 43 ++ chromium/components/arc/connection_observer.h | 38 ++ .../crash_collector/arc_crash_collector_bridge.cc | 15 +- .../crash_collector/arc_crash_collector_bridge.h | 8 - chromium/components/arc/ime/arc_ime_bridge_impl.cc | 22 +- chromium/components/arc/ime/arc_ime_bridge_impl.h | 18 +- chromium/components/arc/ime/arc_ime_service.cc | 8 + chromium/components/arc/ime/arc_ime_service.h | 7 +- .../components/arc/ime/arc_ime_service_unittest.cc | 1 - .../components/arc/ime/arc_ime_struct_traits.cc | 27 - .../components/arc/ime/arc_ime_struct_traits.h | 33 - chromium/components/arc/instance_holder.h | 133 ---- chromium/components/arc/intent_helper/DEPS | 1 + .../arc/intent_helper/activity_icon_loader.cc | 32 +- .../arc/intent_helper/activity_icon_loader.h | 10 +- .../intent_helper/activity_icon_loader_unittest.cc | 4 +- .../arc/intent_helper/arc_intent_helper_bridge.cc | 148 +++-- .../arc/intent_helper/arc_intent_helper_bridge.h | 26 +- .../arc_intent_helper_bridge_unittest.cc | 178 +++++- .../components/arc/intent_helper/intent_filter.cc | 7 +- .../arc/intent_helper/link_handler_model.cc | 4 +- .../arc/lock_screen/arc_lock_screen_bridge.cc | 2 +- .../arc/lock_screen/arc_lock_screen_bridge.h | 8 +- .../components/arc/metrics/arc_metrics_service.cc | 92 ++- .../components/arc/metrics/arc_metrics_service.h | 41 +- .../arc/metrics/arc_metrics_service_unittest.cc | 228 +++++++ chromium/components/arc/midis/arc_midis_bridge.cc | 20 +- chromium/components/arc/midis/arc_midis_bridge.h | 7 - chromium/components/arc/net/arc_net_host_impl.cc | 93 +-- chromium/components/arc/net/arc_net_host_impl.h | 15 +- .../arc/obb_mounter/arc_obb_mounter_bridge.cc | 15 +- .../arc/obb_mounter/arc_obb_mounter_bridge.h | 8 - chromium/components/arc/power/DEPS | 3 + chromium/components/arc/power/arc_power_bridge.cc | 188 ++++-- chromium/components/arc/power/arc_power_bridge.h | 52 +- .../arc/power/arc_power_bridge_unittest.cc | 235 +++++++ .../arc/rotation_lock/arc_rotation_lock_bridge.cc | 16 +- .../arc/rotation_lock/arc_rotation_lock_bridge.h | 8 +- .../arc/storage_manager/arc_storage_manager.cc | 5 +- .../arc/storage_manager/arc_storage_manager.h | 4 +- chromium/components/arc/video_accelerator/BUILD.gn | 25 + chromium/components/arc/video_accelerator/DEPS | 11 +- chromium/components/arc/video_accelerator/OWNERS | 7 +- .../arc_video_decode_accelerator.h | 182 ++++++ .../chrome_arc_video_decode_accelerator.cc | 633 +++++++++++++++++++ .../chrome_arc_video_decode_accelerator.h | 194 ++++++ .../gpu_arc_video_decode_accelerator.cc | 269 ++++++++ .../gpu_arc_video_decode_accelerator.h | 88 +++ .../gpu_arc_video_encode_accelerator.cc | 257 ++++++++ .../gpu_arc_video_encode_accelerator.h | 88 +++ .../video_accelerator/protected_buffer_manager.cc | 408 ++++++++++++ .../video_accelerator/protected_buffer_manager.h | 143 +++++ .../protected_buffer_manager_proxy.cc | 51 ++ .../protected_buffer_manager_proxy.h | 37 ++ .../arc/video_accelerator/video_accelerator.h | 17 - .../video_accelerator_struct_traits.cc | 30 - .../video_accelerator_struct_traits.h | 46 -- .../video_encode_accelerator_struct_traits.cc | 167 ----- .../video_encode_accelerator_struct_traits.h | 68 -- .../arc/video_accelerator/video_frame_plane.h | 19 + chromium/components/arc/voice_interaction/OWNERS | 3 - .../voice_interaction_struct_traits.h | 53 -- .../volume_mounter/arc_volume_mounter_bridge.cc | 2 +- .../arc/volume_mounter/arc_volume_mounter_bridge.h | 8 +- 150 files changed, 7318 insertions(+), 2599 deletions(-) create mode 100644 chromium/components/arc/arc_session_impl.cc create mode 100644 chromium/components/arc/arc_session_impl.h create mode 100644 chromium/components/arc/arc_session_impl_unittest.cc create mode 100644 chromium/components/arc/common/BUILD.gn create mode 100644 chromium/components/arc/common/DEPS delete mode 100644 chromium/components/arc/common/app.typemap delete mode 100644 chromium/components/arc/common/app_struct_traits.cc delete mode 100644 chromium/components/arc/common/app_struct_traits.h create mode 100644 chromium/components/arc/common/arc_gfx_struct_traits.cc create mode 100644 chromium/components/arc/common/arc_gfx_struct_traits.h create mode 100644 chromium/components/arc/common/backup_settings.mojom create mode 100644 chromium/components/arc/common/gfx.mojom create mode 100644 chromium/components/arc/common/gfx.typemap delete mode 100644 chromium/components/arc/common/ime.typemap delete mode 100644 chromium/components/arc/common/screen_rect.mojom create mode 100644 chromium/components/arc/common/video_accelerator_struct_traits.cc create mode 100644 chromium/components/arc/common/video_accelerator_struct_traits.h create mode 100644 chromium/components/arc/common/video_encode_accelerator_struct_traits.cc create mode 100644 chromium/components/arc/common/video_encode_accelerator_struct_traits.h delete mode 100644 chromium/components/arc/common/voice_interaction_framework.typemap create mode 100644 chromium/components/arc/connection_holder.h create mode 100644 chromium/components/arc/connection_notifier.cc create mode 100644 chromium/components/arc/connection_notifier.h create mode 100644 chromium/components/arc/connection_observer.h delete mode 100644 chromium/components/arc/ime/arc_ime_struct_traits.cc delete mode 100644 chromium/components/arc/ime/arc_ime_struct_traits.h delete mode 100644 chromium/components/arc/instance_holder.h create mode 100644 chromium/components/arc/metrics/arc_metrics_service_unittest.cc create mode 100644 chromium/components/arc/power/arc_power_bridge_unittest.cc create mode 100644 chromium/components/arc/video_accelerator/BUILD.gn create mode 100644 chromium/components/arc/video_accelerator/arc_video_decode_accelerator.h create mode 100644 chromium/components/arc/video_accelerator/chrome_arc_video_decode_accelerator.cc create mode 100644 chromium/components/arc/video_accelerator/chrome_arc_video_decode_accelerator.h create mode 100644 chromium/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.cc create mode 100644 chromium/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.h create mode 100644 chromium/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc create mode 100644 chromium/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.h create mode 100644 chromium/components/arc/video_accelerator/protected_buffer_manager.cc create mode 100644 chromium/components/arc/video_accelerator/protected_buffer_manager.h create mode 100644 chromium/components/arc/video_accelerator/protected_buffer_manager_proxy.cc create mode 100644 chromium/components/arc/video_accelerator/protected_buffer_manager_proxy.h delete mode 100644 chromium/components/arc/video_accelerator/video_accelerator.h delete mode 100644 chromium/components/arc/video_accelerator/video_accelerator_struct_traits.cc delete mode 100644 chromium/components/arc/video_accelerator/video_accelerator_struct_traits.h delete mode 100644 chromium/components/arc/video_accelerator/video_encode_accelerator_struct_traits.cc delete mode 100644 chromium/components/arc/video_accelerator/video_encode_accelerator_struct_traits.h create mode 100644 chromium/components/arc/video_accelerator/video_frame_plane.h delete mode 100644 chromium/components/arc/voice_interaction/OWNERS delete mode 100644 chromium/components/arc/voice_interaction/voice_interaction_struct_traits.h (limited to 'chromium/components/arc') diff --git a/chromium/components/arc/BUILD.gn b/chromium/components/arc/BUILD.gn index 3785ffe4dbb..a4550c6f2a9 100644 --- a/chromium/components/arc/BUILD.gn +++ b/chromium/components/arc/BUILD.gn @@ -2,23 +2,18 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//mojo/public/tools/bindings/mojom.gni") import("//testing/test.gni") static_library("arc") { sources = [ "audio/arc_audio_bridge.cc", "audio/arc_audio_bridge.h", - "bluetooth/bluetooth_struct_traits.cc", - "bluetooth/bluetooth_struct_traits.h", "bluetooth/bluetooth_type_converters.cc", "bluetooth/bluetooth_type_converters.h", "clipboard/arc_clipboard_bridge.cc", "clipboard/arc_clipboard_bridge.h", "crash_collector/arc_crash_collector_bridge.cc", "crash_collector/arc_crash_collector_bridge.h", - "file_system/file_system_struct_traits.cc", - "file_system/file_system_struct_traits.h", "ime/arc_ime_bridge.h", "ime/arc_ime_bridge_impl.cc", "ime/arc_ime_bridge_impl.h", @@ -55,8 +50,6 @@ static_library("arc") { "rotation_lock/arc_rotation_lock_bridge.h", "storage_manager/arc_storage_manager.cc", "storage_manager/arc_storage_manager.h", - "video_accelerator/video_accelerator_struct_traits.cc", - "video_accelerator/video_accelerator_struct_traits.h", "volume_mounter/arc_volume_mounter_bridge.cc", "volume_mounter/arc_volume_mounter_bridge.h", ] @@ -68,7 +61,7 @@ static_library("arc") { deps = [ "//ash:ash", - "//ash/public/cpp:ash_public_cpp", + "//ash/public/cpp", "//base", "//chromeos", "//chromeos:login_manager_proto", @@ -79,10 +72,13 @@ static_library("arc") { "//components/prefs", "//components/session_manager/core", "//components/signin/core/account_id", + "//components/url_formatter", "//components/user_manager", + "//content/public/common", "//device/bluetooth", "//google_apis", "//mojo/edk/system", + "//services/device/public/interfaces", "//skia", "//third_party/re2:re2", "//ui/aura", @@ -129,16 +125,22 @@ static_library("arc_base") { "arc_service_manager.h", "arc_session.cc", "arc_session.h", + "arc_session_impl.cc", + "arc_session_impl.h", "arc_session_runner.cc", "arc_session_runner.h", "arc_stop_reason.cc", "arc_stop_reason.h", "arc_util.cc", "arc_util.h", - "instance_holder.h", + "connection_holder.h", + "connection_notifier.cc", + "connection_notifier.h", + "connection_observer.h", ] deps = [ + "//ash/public/cpp", "//base", "//chromeos", "//components/keyed_service/content", @@ -150,62 +152,8 @@ static_library("arc_base") { ] public_deps = [ - ":arc_bindings", ":prefs", - ] -} - -mojom("arc_bindings") { - sources = [ - "common/accessibility_helper.mojom", - "common/app.mojom", - "common/arc_bridge.mojom", - "common/audio.mojom", - "common/auth.mojom", - "common/bitmap.mojom", - "common/bluetooth.mojom", - "common/boot_phase_monitor.mojom", - "common/cast_receiver.mojom", - "common/cert_store.mojom", - "common/clipboard.mojom", - "common/crash_collector.mojom", - "common/enterprise_reporting.mojom", - "common/file_system.mojom", - "common/ime.mojom", - "common/intent_helper.mojom", - "common/kiosk.mojom", - "common/lock_screen.mojom", - "common/metrics.mojom", - "common/midis.mojom", - "common/net.mojom", - "common/notifications.mojom", - "common/obb_mounter.mojom", - "common/oemcrypto.mojom", - "common/oemcrypto_daemon.mojom", - "common/policy.mojom", - "common/power.mojom", - "common/print.mojom", - "common/process.mojom", - "common/protected_buffer_manager.mojom", - "common/rotation_lock.mojom", - "common/scale_factor.mojom", - "common/screen_rect.mojom", - "common/storage_manager.mojom", - "common/tracing.mojom", - "common/tts.mojom", - "common/video.mojom", - "common/video_common.mojom", - "common/video_decode_accelerator.mojom", - "common/video_encode_accelerator.mojom", - "common/voice_interaction_arc_home.mojom", - "common/voice_interaction_framework.mojom", - "common/volume_mounter.mojom", - "common/wallpaper.mojom", - ] - - public_deps = [ - "//mojo/common:common_custom_types", - "//ui/gfx/geometry/mojo", + "//components/arc/common", ] } @@ -214,6 +162,8 @@ static_library("arc_test_support") { sources = [ "test/fake_app_instance.cc", "test/fake_app_instance.h", + "test/fake_arc_bridge_host.cc", + "test/fake_arc_bridge_host.h", "test/fake_arc_session.cc", "test/fake_arc_session.h", "test/fake_bluetooth_instance.cc", @@ -226,10 +176,14 @@ static_library("arc_test_support") { "test/fake_notifications_instance.h", "test/fake_policy_instance.cc", "test/fake_policy_instance.h", + "test/fake_power_instance.cc", + "test/fake_power_instance.h", "test/fake_voice_interaction_framework_instance.cc", "test/fake_voice_interaction_framework_instance.h", "test/fake_wallpaper_instance.cc", "test/fake_wallpaper_instance.h", + "test/test_browser_context.cc", + "test/test_browser_context.h", ] public_deps = [ @@ -238,6 +192,10 @@ static_library("arc_test_support") { deps = [ "//base", + "//components/keyed_service/content", + "//components/prefs:test_support", + "//components/user_prefs", + "//content/test:test_support", "//mojo/common:common_base", "//mojo/edk/embedder:headers", ] @@ -247,6 +205,7 @@ source_set("unit_tests") { testonly = true sources = [ "arc_data_remover_unittest.cc", + "arc_session_impl_unittest.cc", "arc_session_runner_unittest.cc", "arc_util_unittest.cc", "bluetooth/bluetooth_struct_traits_unittest.cc", @@ -258,21 +217,30 @@ source_set("unit_tests") { "intent_helper/intent_filter_unittest.cc", "intent_helper/link_handler_model_unittest.cc", "intent_helper/page_transition_util_unittest.cc", + "metrics/arc_metrics_service_unittest.cc", + "power/arc_power_bridge_unittest.cc", ] deps = [ ":arc_test_support", - "//ash/public/cpp:ash_public_cpp", + "//ash/public/cpp", "//base", "//base/test:test_support", "//chromeos", + "//chromeos:power_manager_proto", "//chromeos:test_support_without_gmock", + "//components/keyed_service/content", "//components/prefs:test_support", "//components/signin/core/account_id", "//components/user_manager", "//components/user_manager:test_support", + "//content/public/common", + "//content/test:test_support", "//device/bluetooth", "//mojo/public/cpp/system:system", + "//services/device/public/cpp/test:test_support", + "//services/device/public/interfaces:interfaces", + "//services/service_manager/public/cpp/test:test_support", "//testing/gmock", "//testing/gtest", "//ui/aura", diff --git a/chromium/components/arc/DEPS b/chromium/components/arc/DEPS index cbf51bdb619..adc47438ce3 100644 --- a/chromium/components/arc/DEPS +++ b/chromium/components/arc/DEPS @@ -25,4 +25,7 @@ specific_include_rules = { "arc_util_unittest.cc": [ "+ui/aura", ], + ".*_unittest.cc": [ + "+content/public/test/test_browser_thread_bundle.h" + ] } diff --git a/chromium/components/arc/arc_bridge_host_impl.cc b/chromium/components/arc/arc_bridge_host_impl.cc index 08101dbd975..a0f3b962b0b 100644 --- a/chromium/components/arc/arc_bridge_host_impl.cc +++ b/chromium/components/arc/arc_bridge_host_impl.cc @@ -10,7 +10,6 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "components/arc/arc_bridge_service.h" -#include "components/arc/instance_holder.h" namespace arc { @@ -30,24 +29,25 @@ namespace { // The thin wrapper for InterfacePtr, where T is one of ARC mojo Instance // class. -template +template class MojoChannelImpl : public ArcBridgeHostImpl::MojoChannel { public: - MojoChannelImpl(InstanceHolder* holder, mojo::InterfacePtr ptr) + MojoChannelImpl(ConnectionHolder* holder, + mojo::InterfacePtr ptr) : holder_(holder), ptr_(std::move(ptr)) { - // Delay registration to the InstanceHolder until the version is ready. + // Delay registration to the ConnectionHolder until the version is ready. } ~MojoChannelImpl() override { holder_->SetInstance(nullptr, 0); } - void set_connection_error_handler(const base::Closure& error_handler) { - ptr_.set_connection_error_handler(error_handler); + void set_connection_error_handler(base::OnceClosure error_handler) { + ptr_.set_connection_error_handler(std::move(error_handler)); } void QueryVersion() { // Note: the callback will not be called if |ptr_| is destroyed. - ptr_.QueryVersion(base::Bind(&MojoChannelImpl::OnVersionReady, - base::Unretained(this))); + ptr_.QueryVersion( + base::Bind(&MojoChannelImpl::OnVersionReady, base::Unretained(this))); } private: @@ -56,11 +56,11 @@ class MojoChannelImpl : public ArcBridgeHostImpl::MojoChannel { } // Owned by ArcBridgeService. - InstanceHolder* const holder_; + ConnectionHolder* const holder_; // Put as a last member to ensure that any callback tied to the |ptr_| // is not invoked. - mojo::InterfacePtr ptr_; + mojo::InterfacePtr ptr_; DISALLOW_COPY_AND_ASSIGN(MojoChannelImpl); }; @@ -75,7 +75,7 @@ ArcBridgeHostImpl::ArcBridgeHostImpl(ArcBridgeService* arc_bridge_service, DCHECK(arc_bridge_service_); DCHECK(instance_.is_bound()); instance_.set_connection_error_handler( - base::Bind(&ArcBridgeHostImpl::OnClosed, base::Unretained(this))); + base::BindOnce(&ArcBridgeHostImpl::OnClosed, base::Unretained(this))); mojom::ArcBridgeHostPtr host_proxy; binding_.Bind(mojo::MakeRequest(&host_proxy)); instance_->Init(std::move(host_proxy)); @@ -104,6 +104,12 @@ void ArcBridgeHostImpl::OnAuthInstanceReady(mojom::AuthInstancePtr auth_ptr) { OnInstanceReady(arc_bridge_service_->auth(), std::move(auth_ptr)); } +void ArcBridgeHostImpl::OnBackupSettingsInstanceReady( + mojom::BackupSettingsInstancePtr backup_settings_ptr) { + OnInstanceReady(arc_bridge_service_->backup_settings(), + std::move(backup_settings_ptr)); +} + void ArcBridgeHostImpl::OnBluetoothInstanceReady( mojom::BluetoothInstancePtr bluetooth_ptr) { OnInstanceReady(arc_bridge_service_->bluetooth(), std::move(bluetooth_ptr)); @@ -281,9 +287,10 @@ void ArcBridgeHostImpl::OnClosed() { binding_.Close(); } -template -void ArcBridgeHostImpl::OnInstanceReady(InstanceHolder* holder, - mojo::InterfacePtr ptr) { +template +void ArcBridgeHostImpl::OnInstanceReady( + ConnectionHolder* holder, + mojo::InterfacePtr ptr) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(binding_.is_bound()); DCHECK(ptr.is_bound()); @@ -291,13 +298,14 @@ void ArcBridgeHostImpl::OnInstanceReady(InstanceHolder* holder, // Track |channel|'s lifetime via |mojo_channels_| so that it will be // closed on ArcBridgeHost/Instance closing or the ArcBridgeHostImpl's // destruction. - auto* channel = new MojoChannelImpl(holder, std::move(ptr)); + auto* channel = + new MojoChannelImpl(holder, std::move(ptr)); mojo_channels_.emplace_back(channel); // Since |channel| is managed by |mojo_channels_|, its lifetime is shorter // than |this|. Thus, the connection error handler will be invoked only // when |this| is alive and base::Unretained is safe here. - channel->set_connection_error_handler(base::Bind( + channel->set_connection_error_handler(base::BindOnce( &ArcBridgeHostImpl::OnChannelClosed, base::Unretained(this), channel)); // Call QueryVersion so that the version info is properly stored in the diff --git a/chromium/components/arc/arc_bridge_host_impl.h b/chromium/components/arc/arc_bridge_host_impl.h index d5695f7e405..604aedb252e 100644 --- a/chromium/components/arc/arc_bridge_host_impl.h +++ b/chromium/components/arc/arc_bridge_host_impl.h @@ -11,7 +11,7 @@ #include "base/macros.h" #include "base/threading/thread_checker.h" #include "components/arc/common/arc_bridge.mojom.h" -#include "components/arc/instance_holder.h" +#include "components/arc/connection_holder.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/interface_ptr.h" @@ -43,6 +43,8 @@ class ArcBridgeHostImpl : public mojom::ArcBridgeHost { void OnAppInstanceReady(mojom::AppInstancePtr app_ptr) override; void OnAudioInstanceReady(mojom::AudioInstancePtr audio_ptr) override; void OnAuthInstanceReady(mojom::AuthInstancePtr auth_ptr) override; + void OnBackupSettingsInstanceReady( + mojom::BackupSettingsInstancePtr backup_settings_ptr) override; void OnBluetoothInstanceReady( mojom::BluetoothInstancePtr bluetooth_ptr) override; void OnBootPhaseMonitorInstanceReady( @@ -101,8 +103,9 @@ class ArcBridgeHostImpl : public mojom::ArcBridgeHost { // The common implementation to handle ArcBridgeHost overrides. // |T| is a ARC Mojo Instance type. - template - void OnInstanceReady(InstanceHolder* holder, mojo::InterfacePtr ptr); + template + void OnInstanceReady(ConnectionHolder* holder, + mojo::InterfacePtr ptr); // Called if one of the established channels is closed. void OnChannelClosed(MojoChannel* channel); diff --git a/chromium/components/arc/arc_bridge_service.cc b/chromium/components/arc/arc_bridge_service.cc index e1ed78ac8a3..3c1b50402bf 100644 --- a/chromium/components/arc/arc_bridge_service.cc +++ b/chromium/components/arc/arc_bridge_service.cc @@ -4,6 +4,8 @@ #include "components/arc/arc_bridge_service.h" +#include "components/arc/common/arc_bridge.mojom.h" + namespace arc { ArcBridgeService::ArcBridgeService() = default; diff --git a/chromium/components/arc/arc_bridge_service.h b/chromium/components/arc/arc_bridge_service.h index f37e4fb5e66..50aef34ec23 100644 --- a/chromium/components/arc/arc_bridge_service.h +++ b/chromium/components/arc/arc_bridge_service.h @@ -6,7 +6,7 @@ #define COMPONENTS_ARC_ARC_BRIDGE_SERVICE_H_ #include "base/macros.h" -#include "components/arc/instance_holder.h" +#include "components/arc/connection_holder.h" namespace arc { @@ -14,40 +14,69 @@ namespace mojom { // Instead of including components/arc/common/arc_bridge.mojom.h, list all the // instance classes here for faster build. +class AccessibilityHelperHost; class AccessibilityHelperInstance; +class AppHost; class AppInstance; +class AudioHost; class AudioInstance; +class AuthHost; class AuthInstance; +class BackupSettingsInstance; +class BluetoothHost; class BluetoothInstance; +class BootPhaseMonitorHost; class BootPhaseMonitorInstance; class CastReceiverInstance; +class CertStoreHost; class CertStoreInstance; +class ClipboardHost; class ClipboardInstance; +class CrashCollectorHost; class CrashCollectorInstance; +class EnterpriseReportingHost; class EnterpriseReportingInstance; +class FileSystemHost; class FileSystemInstance; +class ImeHost; class ImeInstance; +class IntentHelperHost; class IntentHelperInstance; +class KioskHost; class KioskInstance; class LockScreenInstance; +class MetricsHost; class MetricsInstance; +class MidisHost; class MidisInstance; +class NetHost; class NetInstance; +class NotificationsHost; class NotificationsInstance; +class ObbMounterHost; class ObbMounterInstance; +class OemCryptoHost; class OemCryptoInstance; +class PolicyHost; class PolicyInstance; +class PowerHost; class PowerInstance; +class PrintHost; class PrintInstance; class ProcessInstance; class RotationLockInstance; class StorageManagerInstance; class TracingInstance; +class TtsHost; class TtsInstance; +class VideoHost; class VideoInstance; +class VoiceInteractionArcHomeHost; class VoiceInteractionArcHomeInstance; +class VoiceInteractionFrameworkHost; class VoiceInteractionFrameworkInstance; class VolumeMounterInstance; +class WallpaperHost; class WallpaperInstance; } // namespace mojom @@ -59,114 +88,174 @@ class ArcBridgeService { ArcBridgeService(); ~ArcBridgeService(); - InstanceHolder* accessibility_helper() { + ConnectionHolder* + accessibility_helper() { return &accessibility_helper_; } - InstanceHolder* app() { return &app_; } - InstanceHolder* audio() { return &audio_; } - InstanceHolder* auth() { return &auth_; } - InstanceHolder* bluetooth() { return &bluetooth_; } - InstanceHolder* boot_phase_monitor() { + ConnectionHolder* app() { return &app_; } + ConnectionHolder* audio() { + return &audio_; + } + ConnectionHolder* auth() { + return &auth_; + } + ConnectionHolder* backup_settings() { + return &backup_settings_; + } + ConnectionHolder* + bluetooth() { + return &bluetooth_; + } + ConnectionHolder* + boot_phase_monitor() { return &boot_phase_monitor_; } - InstanceHolder* cast_receiver() { + ConnectionHolder* cast_receiver() { return &cast_receiver_; } - InstanceHolder* cert_store() { + ConnectionHolder* + cert_store() { return &cert_store_; } - InstanceHolder* clipboard() { return &clipboard_; } - InstanceHolder* crash_collector() { + ConnectionHolder* + clipboard() { + return &clipboard_; + } + ConnectionHolder* + crash_collector() { return &crash_collector_; } - InstanceHolder* enterprise_reporting() { + ConnectionHolder* + enterprise_reporting() { return &enterprise_reporting_; } - InstanceHolder* file_system() { + ConnectionHolder* + file_system() { return &file_system_; } - InstanceHolder* ime() { return &ime_; } - InstanceHolder* intent_helper() { + ConnectionHolder* ime() { return &ime_; } + ConnectionHolder* + intent_helper() { return &intent_helper_; } - InstanceHolder* kiosk() { return &kiosk_; } - InstanceHolder* lock_screen() { + ConnectionHolder* kiosk() { + return &kiosk_; + } + ConnectionHolder* lock_screen() { return &lock_screen_; } - InstanceHolder* metrics() { return &metrics_; } - InstanceHolder* midis() { return &midis_; } - InstanceHolder* net() { return &net_; } - InstanceHolder* notifications() { + ConnectionHolder* metrics() { + return &metrics_; + } + ConnectionHolder* midis() { + return &midis_; + } + ConnectionHolder* net() { return &net_; } + ConnectionHolder* + notifications() { return ¬ifications_; } - InstanceHolder* obb_mounter() { + ConnectionHolder* + obb_mounter() { return &obb_mounter_; } - InstanceHolder* oemcrypto() { return &oemcrypto_; } - InstanceHolder* policy() { return &policy_; } - InstanceHolder* power() { return &power_; } - InstanceHolder* print() { return &print_; } - InstanceHolder* process() { return &process_; } - InstanceHolder* rotation_lock() { + ConnectionHolder* + oemcrypto() { + return &oemcrypto_; + } + ConnectionHolder* policy() { + return &policy_; + } + ConnectionHolder* power() { + return &power_; + } + ConnectionHolder* print() { + return &print_; + } + ConnectionHolder* process() { return &process_; } + ConnectionHolder* rotation_lock() { return &rotation_lock_; } - InstanceHolder* storage_manager() { + ConnectionHolder* storage_manager() { return &storage_manager_; } - InstanceHolder* tracing() { return &tracing_; } - InstanceHolder* tts() { return &tts_; } - InstanceHolder* video() { return &video_; } - InstanceHolder* + ConnectionHolder* tracing() { return &tracing_; } + ConnectionHolder* tts() { return &tts_; } + ConnectionHolder* video() { + return &video_; + } + ConnectionHolder* voice_interaction_arc_home() { return &voice_interaction_arc_home_; } - InstanceHolder* + ConnectionHolder* voice_interaction_framework() { return &voice_interaction_framework_; } - InstanceHolder* volume_mounter() { + ConnectionHolder* volume_mounter() { return &volume_mounter_; } - InstanceHolder* wallpaper() { return &wallpaper_; } + ConnectionHolder* + wallpaper() { + return &wallpaper_; + } private: - InstanceHolder accessibility_helper_; - InstanceHolder app_; - InstanceHolder audio_; - InstanceHolder auth_; - InstanceHolder bluetooth_; - InstanceHolder boot_phase_monitor_; - InstanceHolder cast_receiver_; - InstanceHolder cert_store_; - InstanceHolder clipboard_; - InstanceHolder crash_collector_; - InstanceHolder enterprise_reporting_; - InstanceHolder file_system_; - InstanceHolder ime_; - InstanceHolder intent_helper_; - InstanceHolder kiosk_; - InstanceHolder lock_screen_; - InstanceHolder metrics_; - InstanceHolder midis_; - InstanceHolder net_; - InstanceHolder notifications_; - InstanceHolder obb_mounter_; - InstanceHolder oemcrypto_; - InstanceHolder policy_; - InstanceHolder power_; - InstanceHolder print_; - InstanceHolder process_; - InstanceHolder rotation_lock_; - InstanceHolder storage_manager_; - InstanceHolder tracing_; - InstanceHolder tts_; - InstanceHolder video_; - InstanceHolder + ConnectionHolder + accessibility_helper_; + ConnectionHolder app_; + ConnectionHolder audio_; + ConnectionHolder auth_; + ConnectionHolder backup_settings_; + ConnectionHolder bluetooth_; + ConnectionHolder + boot_phase_monitor_; + ConnectionHolder cast_receiver_; + ConnectionHolder cert_store_; + ConnectionHolder clipboard_; + ConnectionHolder + crash_collector_; + ConnectionHolder + enterprise_reporting_; + ConnectionHolder + file_system_; + ConnectionHolder ime_; + ConnectionHolder + intent_helper_; + ConnectionHolder kiosk_; + ConnectionHolder lock_screen_; + ConnectionHolder metrics_; + ConnectionHolder midis_; + ConnectionHolder net_; + ConnectionHolder + notifications_; + ConnectionHolder + obb_mounter_; + ConnectionHolder oemcrypto_; + ConnectionHolder policy_; + ConnectionHolder power_; + ConnectionHolder print_; + ConnectionHolder process_; + ConnectionHolder rotation_lock_; + ConnectionHolder storage_manager_; + ConnectionHolder tracing_; + ConnectionHolder tts_; + ConnectionHolder video_; + ConnectionHolder voice_interaction_arc_home_; - InstanceHolder + ConnectionHolder voice_interaction_framework_; - InstanceHolder volume_mounter_; - InstanceHolder wallpaper_; + ConnectionHolder volume_mounter_; + ConnectionHolder wallpaper_; DISALLOW_COPY_AND_ASSIGN(ArcBridgeService); }; diff --git a/chromium/components/arc/arc_data_remover_unittest.cc b/chromium/components/arc/arc_data_remover_unittest.cc index 175026bc8a3..d2ea11ea977 100644 --- a/chromium/components/arc/arc_data_remover_unittest.cc +++ b/chromium/components/arc/arc_data_remover_unittest.cc @@ -7,6 +7,7 @@ #include #include "base/bind.h" +#include "base/run_loop.h" #include "base/test/scoped_task_environment.h" #include "chromeos/cryptohome/cryptohome_parameters.h" #include "chromeos/dbus/dbus_thread_manager.h" diff --git a/chromium/components/arc/arc_features.cc b/chromium/components/arc/arc_features.cc index cc3b2a84871..3ce91e5d263 100644 --- a/chromium/components/arc/arc_features.cc +++ b/chromium/components/arc/arc_features.cc @@ -14,12 +14,12 @@ const base::Feature kBootCompletedBroadcastFeature { // Controls experimental native bridge feature for ARC. const base::Feature kNativeBridgeExperimentFeature { - "ArcNativeBridgeExperiment", base::FEATURE_DISABLED_BY_DEFAULT + "ArcNativeBridgeExperiment", base::FEATURE_ENABLED_BY_DEFAULT }; // Controls ARC VPN integration. // When enabled, Chrome traffic will be routed through VPNs connected in // Android apps. -const base::Feature kVpnFeature{"ArcVpn", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kVpnFeature{"ArcVpn", base::FEATURE_ENABLED_BY_DEFAULT}; } // namespace arc diff --git a/chromium/components/arc/arc_instance_mode.cc b/chromium/components/arc/arc_instance_mode.cc index 3f6b67c1f96..de0439afd68 100644 --- a/chromium/components/arc/arc_instance_mode.cc +++ b/chromium/components/arc/arc_instance_mode.cc @@ -4,14 +4,17 @@ #include "components/arc/arc_instance_mode.h" +#include + #include "base/logging.h" namespace arc { +namespace { -std::ostream& operator<<(std::ostream& os, ArcInstanceMode mode) { +std::string ArcInstanceModeToString(ArcInstanceMode mode) { #define MAP_MODE(name) \ case ArcInstanceMode::name: \ - return os << #name + return #name switch (mode) { MAP_MODE(MINI_INSTANCE); @@ -22,7 +25,19 @@ std::ostream& operator<<(std::ostream& os, ArcInstanceMode mode) { // Some compilers report an error even if all values of an enum-class are // covered exhaustively in a switch statement. NOTREACHED() << "Invalid value " << static_cast(mode); - return os; + return std::string(); +} + +} // namespace + +std::ostream& operator<<(std::ostream& os, ArcInstanceMode mode) { + return os << ArcInstanceModeToString(mode); +} + +std::ostream& operator<<(std::ostream& os, + base::Optional mode) { + return os << (mode.has_value() ? ArcInstanceModeToString(mode.value()) + : "(nullopt)"); } } // namespace arc diff --git a/chromium/components/arc/arc_instance_mode.h b/chromium/components/arc/arc_instance_mode.h index 86b3d0b5428..5f97a74cceb 100644 --- a/chromium/components/arc/arc_instance_mode.h +++ b/chromium/components/arc/arc_instance_mode.h @@ -7,6 +7,8 @@ #include +#include "base/optional.h" + namespace arc { enum class ArcInstanceMode { @@ -20,6 +22,8 @@ enum class ArcInstanceMode { // Stringified output for logging purpose. std::ostream& operator<<(std::ostream& os, ArcInstanceMode mode); +std::ostream& operator<<(std::ostream& os, + base::Optional mode); } // namespace arc diff --git a/chromium/components/arc/arc_prefs.cc b/chromium/components/arc/arc_prefs.cc index 6aad8315032..5f4fc858c54 100644 --- a/chromium/components/arc/arc_prefs.cc +++ b/chromium/components/arc/arc_prefs.cc @@ -47,7 +47,7 @@ const char kArcSetNotificationsEnabledDeferred[] = const char kArcSignedIn[] = "arc.signedin"; // A preference that indicates an ARC comaptible filesystem was chosen for // the user directory (i.e., the user finished required migration.) -extern const char kArcCompatibleFilesystemChosen[] = +const char kArcCompatibleFilesystemChosen[] = "arc.compatible_filesystem.chosen"; // A preference that indicates that user accepted Voice Interaction Value Prop. const char kArcVoiceInteractionValuePropAccepted[] = @@ -64,11 +64,6 @@ const char kVoiceInteractionEnabled[] = "settings.voice_interaction.enabled"; // screen). const char kVoiceInteractionContextEnabled[] = "settings.voice_interaction.context.enabled"; -// A preference indicating whether voice interaction settings have been read -// from ARC. This synchronization only happens when user goes through the flow -// to set up voice interaction. -const char kVoiceInteractionPrefSynced[] = - "settings.voice_interaction.context.synced"; void RegisterProfilePrefs(PrefRegistrySimple* registry) { // TODO(dspaid): Implement a mechanism to allow this to sync on first boot @@ -99,7 +94,6 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry) { registry->RegisterBooleanPref(kSmsConnectEnabled, true); registry->RegisterBooleanPref(kVoiceInteractionContextEnabled, false); registry->RegisterBooleanPref(kVoiceInteractionEnabled, false); - registry->RegisterBooleanPref(kVoiceInteractionPrefSynced, false); } } // namespace prefs diff --git a/chromium/components/arc/arc_prefs.h b/chromium/components/arc/arc_prefs.h index b3608afc4e7..16c37e3aa6d 100644 --- a/chromium/components/arc/arc_prefs.h +++ b/chromium/components/arc/arc_prefs.h @@ -31,7 +31,6 @@ ARC_EXPORT extern const char kEcryptfsMigrationStrategy[]; ARC_EXPORT extern const char kSmsConnectEnabled[]; ARC_EXPORT extern const char kVoiceInteractionEnabled[]; ARC_EXPORT extern const char kVoiceInteractionContextEnabled[]; -ARC_EXPORT extern const char kVoiceInteractionPrefSynced[]; void RegisterProfilePrefs(PrefRegistrySimple* registry); diff --git a/chromium/components/arc/arc_session.cc b/chromium/components/arc/arc_session.cc index 9a7b6dcff7b..d5c887a1136 100644 --- a/chromium/components/arc/arc_session.cc +++ b/chromium/components/arc/arc_session.cc @@ -4,686 +4,10 @@ #include "components/arc/arc_session.h" -#include -#include -#include -#include - -#include -#include - -#include "base/files/file_util.h" -#include "base/location.h" -#include "base/macros.h" -#include "base/posix/eintr_wrapper.h" -#include "base/sys_info.h" -#include "base/task_scheduler/post_task.h" -#include "base/task_scheduler/task_traits.h" -#include "base/threading/thread_checker.h" -#include "base/threading/thread_task_runner_handle.h" -#include "chromeos/chromeos_switches.h" -#include "chromeos/cryptohome/cryptohome_parameters.h" -#include "chromeos/dbus/dbus_method_call_status.h" -#include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/session_manager_client.h" -#include "components/arc/arc_bridge_host_impl.h" -#include "components/arc/arc_features.h" -#include "components/user_manager/user_manager.h" -#include "mojo/edk/embedder/embedder.h" -#include "mojo/edk/embedder/named_platform_handle.h" -#include "mojo/edk/embedder/named_platform_handle_utils.h" -#include "mojo/edk/embedder/outgoing_broker_client_invitation.h" -#include "mojo/edk/embedder/platform_channel_pair.h" -#include "mojo/edk/embedder/platform_channel_utils_posix.h" -#include "mojo/edk/embedder/platform_handle_vector.h" -#include "mojo/edk/embedder/scoped_platform_handle.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "components/arc/arc_session_impl.h" namespace arc { -namespace { - -using StartArcInstanceResult = - chromeos::SessionManagerClient::StartArcInstanceResult; - -// This is called when StopArcInstance D-Bus method completes. Since we have the -// ArcInstanceStopped() callback and are notified if StartArcInstance fails, we -// don't need to do anything when StopArcInstance completes. -void DoNothingInstanceStopped(bool) {} - -chromeos::SessionManagerClient* GetSessionManagerClient() { - // If the DBusThreadManager or the SessionManagerClient aren't available, - // there isn't much we can do. This should only happen when running tests. - if (!chromeos::DBusThreadManager::IsInitialized() || - !chromeos::DBusThreadManager::Get() || - !chromeos::DBusThreadManager::Get()->GetSessionManagerClient()) - return nullptr; - return chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); -} - -// Creates a pipe. Returns true on success, otherwise false. -// On success, |read_fd| will be set to the fd of the read side, and -// |write_fd| will be set to the one of write side. -bool CreatePipe(base::ScopedFD* read_fd, base::ScopedFD* write_fd) { - int fds[2]; - if (pipe2(fds, O_NONBLOCK | O_CLOEXEC) < 0) { - PLOG(ERROR) << "pipe2()"; - return false; - } - - read_fd->reset(fds[0]); - write_fd->reset(fds[1]); - return true; -} - -// Waits until |raw_socket_fd| is readable. -// The operation may be cancelled originally triggered by user interaction to -// disable ARC, or ARC instance is unexpectedly stopped (e.g. crash). -// To notify such a situation, |raw_cancel_fd| is also passed to here, and the -// write side will be closed in such a case. -bool WaitForSocketReadable(int raw_socket_fd, int raw_cancel_fd) { - struct pollfd fds[2] = { - {raw_socket_fd, POLLIN, 0}, {raw_cancel_fd, POLLIN, 0}, - }; - - if (HANDLE_EINTR(poll(fds, arraysize(fds), -1)) <= 0) { - PLOG(ERROR) << "poll()"; - return false; - } - - if (fds[1].revents) { - // Notified that Stop() is invoked. Cancel the Mojo connecting. - VLOG(1) << "Stop() was called during ConnectMojo()"; - return false; - } - - DCHECK(fds[0].revents); - return true; -} - -// TODO(hidehiko): Refactor more to make this class unittest-able, for at least -// state-machine part. -class ArcSessionImpl : public ArcSession, - public chromeos::SessionManagerClient::Observer { - public: - // The possible states of the session. In the normal flow, the state changes - // in the following sequence: - // - // NOT_STARTED - // Start() -> - // STARTING_INSTANCE - // -> OnInstanceStarted() -> - // CONNECTING_MOJO - // ConnectMojo() -> OnMojoConnected() -> - // RUNNING - // - // Also, StartForLoginScreen() may start ARC instance with - // |login_screen_instance_requested_| set to |true|. In that case, the state - // changes like the following: - // - // NOT_STARTED - // StartForLoginScreen() -> - // STARTING_INSTANCE - // -> OnInstanceStarted() -> - // RUNNING_FOR_LOGIN_SCREEN - // - // Start() can also be used at both STARTING_INSTANCE and - // RUNNING_FOR_LOGIN_SCREEN to turn the instance for login screen into a - // fully functional one. - // - // Regardless of whether the instance is for login screen or not, at any - // state, Stop() can be called. It may not immediately stop the instance, - // but will eventually stop it. The actual stop will be notified via - // ArcSession::Observer::OnSessionStopped(). - // - // When Stop() is called, it makes various behavior based on the current - // phase. - // - // NOT_STARTED: - // Do nothing. Immediately transition to the STOPPED state. - // STARTING_INSTANCE: - // The ARC instance is starting via SessionManager. Stop() just sets the - // flag and return. On the main task completion, a callback will run on the - // thread, and the flag is checked at the beginning of them. This should - // work under the assumption that the main tasks do not block indefinitely. - // In its callback, it checks if ARC instance is successfully started or - // not. In case of success, a request to stop the ARC instance is sent to - // SessionManager. Its completion will be notified via ArcInstanceStopped. - // Otherwise, it just turns into STOPPED state. - // CONNECTING_MOJO: - // The main task runs on TaskScheduler's thread, but it is a blocking call. - // So, Stop() sends a request to cancel the blocking by closing the pipe - // whose read side is also polled. Then, in its callback, similar to - // STARTING_INSTANCE, a request to stop the ARC instance is sent to - // SessionManager, and ArcInstanceStopped handles remaining procedure. - // RUNNING_FOR_LOGIN_SCREEN: - // RUNNING: - // There is no more callback which runs on normal flow, so Stop() requests - // to stop the ARC instance via SessionManager. - // - // Another trigger to change the state coming from outside of this class - // is an event ArcInstanceStopped() sent from SessionManager, when ARC - // instace unexpectedly terminates. ArcInstanceStopped() turns the state into - // STOPPED immediately. - // - // In NOT_STARTED or STOPPED state, the instance can be safely destructed. - // Specifically, in STOPPED state, there may be inflight operations or - // pending callbacks. Though, what they do is just do-nothing conceptually - // and they can be safely ignored. - // - // Note: Order of constants below matters. Please make sure to sort them - // in chronological order. - enum class State { - // ARC is not yet started. - NOT_STARTED, - - // The request to start or resume the instance has been sent. - STARTING_INSTANCE, - - // The instance is set up, but only a handful of processes NOT including - // arcbridgeservice (i.e. mojo endpoint) are running. - RUNNING_FOR_LOGIN_SCREEN, - - // The instance has started. Waiting for it to connect to the IPC bridge. - CONNECTING_MOJO, - - // The instance is fully set up. - RUNNING, - - // ARC is terminated. - STOPPED, - }; - - explicit ArcSessionImpl(ArcBridgeService* arc_bridge_service); - ~ArcSessionImpl() override; - - // ArcSession overrides: - void StartForLoginScreen() override; - bool IsForLoginScreen() override; - void Start() override; - bool IsRunning() override; - void Stop() override; - bool IsStopRequested() override; - void OnShutdown() override; - - private: - // DBus callback for StartArcInstance(). - void OnInstanceStarted(bool instance_is_for_login_screen, - StartArcInstanceResult result, - const std::string& container_instance_id, - base::ScopedFD socket_fd); - - // Synchronously accepts a connection on |socket_fd| and then processes the - // connected socket's file descriptor. - static mojo::ScopedMessagePipeHandle ConnectMojo( - mojo::edk::ScopedPlatformHandle socket_fd, - base::ScopedFD cancel_fd); - void OnMojoConnected(mojo::ScopedMessagePipeHandle server_pipe); - - // Request to stop ARC instance via DBus. - void StopArcInstance(); - - // chromeos::SessionManagerClient::Observer: - void ArcInstanceStopped(bool clean, - const std::string& container_instance_id) override; - - // Completes the termination procedure. Note that calling this may end up with - // deleting |this| because the function calls observers' OnSessionStopped(). - void OnStopped(ArcStopReason reason); - - // Sends a StartArcInstance D-Bus request to session_manager. - static void SendStartArcInstanceDBusMessage( - bool instance_is_for_login_screen, - const chromeos::SessionManagerClient::StartArcInstanceCallback& cb); - - // Checks whether a function runs on the thread where the instance is - // created. - THREAD_CHECKER(thread_checker_); - - // Owned by ArcServiceManager. - ArcBridgeService* const arc_bridge_service_; - - // The state of the session. - State state_ = State::NOT_STARTED; - - // When Stop() is called, this flag is set. - bool stop_requested_ = false; - - // When StartForLoginScreen() is called, this flag is set. After - // that, when Start() is called to resume the boot, the flag is unset. - bool login_screen_instance_requested_ = false; - - // Container instance id passed from session_manager. - // Should be available only after OnInstanceStarted(). - std::string container_instance_id_; - - // In CONNECTING_MOJO state, this is set to the write side of the pipe - // to notify cancelling of the procedure. - base::ScopedFD accept_cancel_pipe_; - - // Mojo endpoint. - std::unique_ptr arc_bridge_host_; - - // WeakPtrFactory to use callbacks. - base::WeakPtrFactory weak_factory_; - - private: - DISALLOW_COPY_AND_ASSIGN(ArcSessionImpl); -}; - -ArcSessionImpl::ArcSessionImpl(ArcBridgeService* arc_bridge_service) - : arc_bridge_service_(arc_bridge_service), weak_factory_(this) { - chromeos::SessionManagerClient* client = GetSessionManagerClient(); - if (client == nullptr) - return; - client->AddObserver(this); -} - -ArcSessionImpl::~ArcSessionImpl() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(state_ == State::NOT_STARTED || state_ == State::STOPPED); - chromeos::SessionManagerClient* client = GetSessionManagerClient(); - if (client == nullptr) - return; - client->RemoveObserver(this); -} - -void ArcSessionImpl::Start() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - // Start() can be called either for starting ARC from scratch or for - // resuming an existing one. Start() must be able to start a fully - // functional instance from all of |state_| up to and including - // RUNNING_FOR_LOGIN_SCREEN. - DCHECK_GE(State::RUNNING_FOR_LOGIN_SCREEN, state_); - - // Flip the flag now so that callback functions like OnInstanceStarted() - // can do the right thing. - login_screen_instance_requested_ = false; - - if (state_ == State::NOT_STARTED) { - // An instance for login screen does not exist. Start a new one from - // scratch. - VLOG(2) << "Starting ARC session"; - state_ = State::STARTING_INSTANCE; - SendStartArcInstanceDBusMessage( - false /* instance_is_for_login_screen */, - base::Bind(&ArcSessionImpl::OnInstanceStarted, - weak_factory_.GetWeakPtr(), - false /* instance_is_for_login_screen */)); - - } else if (state_ == State::STARTING_INSTANCE) { - VLOG(2) << "Requested to resume an existing ARC instance"; - // OnInstanceStarted() will start a fully featured instance. - } else if (state_ == State::RUNNING_FOR_LOGIN_SCREEN) { - VLOG(2) << "Resuming an existing ARC instance"; - state_ = State::STARTING_INSTANCE; - SendStartArcInstanceDBusMessage( - false /* instance_is_for_login_screen */, - base::Bind(&ArcSessionImpl::OnInstanceStarted, - weak_factory_.GetWeakPtr(), - false /* instance_is_for_login_screen */)); - } -} - -// static -void ArcSessionImpl::SendStartArcInstanceDBusMessage( - bool instance_is_for_login_screen, - const chromeos::SessionManagerClient::StartArcInstanceCallback& cb) { - chromeos::SessionManagerClient* session_manager_client = - chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); - const bool native_bridge_experiment = - base::FeatureList::IsEnabled(arc::kNativeBridgeExperimentFeature); - if (instance_is_for_login_screen) { - session_manager_client->StartArcInstance( - chromeos::SessionManagerClient::ArcStartupMode::LOGIN_SCREEN, - // All variables below except |cb| will be ignored. - cryptohome::Identification(), false, false, - native_bridge_experiment, cb); - return; - } - - user_manager::UserManager* user_manager = user_manager::UserManager::Get(); - DCHECK(user_manager->GetPrimaryUser()); - const cryptohome::Identification cryptohome_id( - user_manager->GetPrimaryUser()->GetAccountId()); - - const bool skip_boot_completed_broadcast = - !base::FeatureList::IsEnabled(arc::kBootCompletedBroadcastFeature); - - // We only enable /vendor/priv-app when voice interaction is enabled because - // voice interaction service apk would be bundled in this location. - const bool scan_vendor_priv_app = - chromeos::switches::IsVoiceInteractionEnabled(); - - session_manager_client->StartArcInstance( - chromeos::SessionManagerClient::ArcStartupMode::FULL, cryptohome_id, - skip_boot_completed_broadcast, scan_vendor_priv_app, - native_bridge_experiment, cb); -} - -void ArcSessionImpl::OnInstanceStarted(bool instance_is_for_login_screen, - StartArcInstanceResult result, - const std::string& container_instance_id, - base::ScopedFD socket_fd) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK_EQ(state_, State::STARTING_INSTANCE); - - bool resumed = false; - if (!container_instance_id_.empty()) { - // |container_instance_id_| has already been initialized when the instance - // for login screen was started. - DCHECK(container_instance_id.empty()); - DCHECK(!instance_is_for_login_screen); - resumed = true; - } else { - container_instance_id_ = container_instance_id; - } - - if (stop_requested_) { - if (result == StartArcInstanceResult::SUCCESS) { - // The ARC instance has started to run. Request to stop. - StopArcInstance(); - return; - } - OnStopped(ArcStopReason::SHUTDOWN); - return; - } - - if (result != StartArcInstanceResult::SUCCESS) { - LOG(ERROR) << "Failed to start ARC instance"; - OnStopped(result == StartArcInstanceResult::LOW_FREE_DISK_SPACE - ? ArcStopReason::LOW_DISK_SPACE - : ArcStopReason::GENERIC_BOOT_FAILURE); - return; - } - - if (instance_is_for_login_screen) { - VLOG(2) << "ARC instance for login screen is successfully started."; - if (login_screen_instance_requested_) { - state_ = State::RUNNING_FOR_LOGIN_SCREEN; - } else { - // Start() has been called. - VLOG(2) << "Resuming an existing ARC instance"; - state_ = State::STARTING_INSTANCE; - SendStartArcInstanceDBusMessage( - false /* instance_is_for_login_screen */, - base::Bind(&ArcSessionImpl::OnInstanceStarted, - weak_factory_.GetWeakPtr(), - false /* instance_is_for_login_screen */)); - } - return; - } - - VLOG(2) << "ARC instance is successfully " - << (resumed ? "resumed" : "started") << ". Connecting Mojo..."; - state_ = State::CONNECTING_MOJO; - - // Prepare a pipe so that AcceptInstanceConnection can be interrupted on - // Stop(). - base::ScopedFD cancel_fd; - if (!CreatePipe(&cancel_fd, &accept_cancel_pipe_)) { - StopArcInstance(); - return; - } - - // For production, |socket_fd| passed from session_manager is either a valid - // socket or a valid file descriptor (/dev/null). For testing, |socket_fd| - // might be invalid. - mojo::edk::PlatformHandle raw_handle(socket_fd.release()); - raw_handle.needs_connection = true; - - mojo::edk::ScopedPlatformHandle mojo_socket_fd(raw_handle); - base::PostTaskWithTraitsAndReplyWithResult( - FROM_HERE, {base::MayBlock()}, - base::Bind(&ArcSessionImpl::ConnectMojo, base::Passed(&mojo_socket_fd), - base::Passed(&cancel_fd)), - base::Bind(&ArcSessionImpl::OnMojoConnected, weak_factory_.GetWeakPtr())); -} - -// static -mojo::ScopedMessagePipeHandle ArcSessionImpl::ConnectMojo( - mojo::edk::ScopedPlatformHandle socket_fd, - base::ScopedFD cancel_fd) { - if (!WaitForSocketReadable(socket_fd.get().handle, cancel_fd.get())) { - VLOG(1) << "Mojo connection was cancelled."; - return mojo::ScopedMessagePipeHandle(); - } - - mojo::edk::ScopedPlatformHandle scoped_fd; - if (!mojo::edk::ServerAcceptConnection(socket_fd.get(), &scoped_fd, - /* check_peer_user = */ false) || - !scoped_fd.is_valid()) { - return mojo::ScopedMessagePipeHandle(); - } - - // Hardcode pid 0 since it is unused in mojo. - const base::ProcessHandle kUnusedChildProcessHandle = 0; - mojo::edk::PlatformChannelPair channel_pair; - mojo::edk::OutgoingBrokerClientInvitation invitation; - - std::string token = mojo::edk::GenerateRandomToken(); - mojo::ScopedMessagePipeHandle pipe = invitation.AttachMessagePipe(token); - - invitation.Send( - kUnusedChildProcessHandle, - mojo::edk::ConnectionParams(mojo::edk::TransportProtocol::kLegacy, - channel_pair.PassServerHandle())); - - mojo::edk::ScopedPlatformHandleVectorPtr handles( - new mojo::edk::PlatformHandleVector{ - channel_pair.PassClientHandle().release()}); - - // We need to send the length of the message as a single byte, so make sure it - // fits. - DCHECK_LT(token.size(), 256u); - uint8_t message_length = static_cast(token.size()); - struct iovec iov[] = {{&message_length, sizeof(message_length)}, - {const_cast(token.c_str()), token.size()}}; - ssize_t result = mojo::edk::PlatformChannelSendmsgWithHandles( - scoped_fd.get(), iov, sizeof(iov) / sizeof(iov[0]), handles->data(), - handles->size()); - if (result == -1) { - PLOG(ERROR) << "sendmsg"; - return mojo::ScopedMessagePipeHandle(); - } - - return pipe; -} - -void ArcSessionImpl::OnMojoConnected( - mojo::ScopedMessagePipeHandle server_pipe) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK_EQ(state_, State::CONNECTING_MOJO); - accept_cancel_pipe_.reset(); - - if (stop_requested_) { - StopArcInstance(); - return; - } - - if (!server_pipe.is_valid()) { - LOG(ERROR) << "Invalid pipe"; - StopArcInstance(); - return; - } - - mojom::ArcBridgeInstancePtr instance; - instance.Bind(mojo::InterfacePtrInfo( - std::move(server_pipe), 0u)); - arc_bridge_host_ = std::make_unique(arc_bridge_service_, - std::move(instance)); - - VLOG(0) << "ARC ready."; - state_ = State::RUNNING; -} - -void ArcSessionImpl::Stop() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - VLOG(2) << "Stopping ARC session is requested."; - - // For second time or later, just do nothing. - // It is already in the stopping phase. - if (stop_requested_) - return; - - stop_requested_ = true; - arc_bridge_host_.reset(); - switch (state_) { - case State::NOT_STARTED: - OnStopped(ArcStopReason::SHUTDOWN); - return; - - case State::STARTING_INSTANCE: - // Before starting the ARC instance, we do nothing here. - // At some point, a callback will be invoked on UI thread, - // and stopping procedure will be run there. - // On Chrome shutdown, it is not the case because the message loop is - // already stopped here. Practically, it is not a problem because; - // - On starting instance, the container instance can be leaked. - // Practically it is not problematic because the session manager will - // clean it up. - return; - - case State::RUNNING_FOR_LOGIN_SCREEN: - // An ARC instance for login screen is running. Request to stop it. - StopArcInstance(); - return; - - case State::CONNECTING_MOJO: - // Mojo connection is being waited on TaskScheduler's thread. - // Request to cancel it. Following stopping procedure will run - // in its callback. - accept_cancel_pipe_.reset(); - return; - - case State::RUNNING: - // Now ARC instance is running. Request to stop it. - StopArcInstance(); - return; - - case State::STOPPED: - // The instance is already stopped. Do nothing. - return; - } -} - -void ArcSessionImpl::StopArcInstance() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(state_ == State::STARTING_INSTANCE || - state_ == State::RUNNING_FOR_LOGIN_SCREEN || - state_ == State::CONNECTING_MOJO || state_ == State::RUNNING); - - VLOG(2) << "Requesting session_manager to stop ARC instance"; - - // When the instance is not for login screen, change the |state_| in - // ArcInstanceStopped(). - chromeos::SessionManagerClient* session_manager_client = - chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); - session_manager_client->StopArcInstance( - base::Bind(&DoNothingInstanceStopped)); -} - -void ArcSessionImpl::ArcInstanceStopped( - bool clean, - const std::string& container_instance_id) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - VLOG(1) << "Notified that ARC instance is stopped " - << (clean ? "cleanly" : "uncleanly"); - - if (container_instance_id != container_instance_id_) { - VLOG(1) << "Container instance id mismatch. Do nothing." - << container_instance_id << " vs " << container_instance_id_; - return; - } - - // Release |container_instance_id_| to avoid duplicate invocation situation. - container_instance_id_.clear(); - - // In case that crash happens during before the Mojo channel is connected, - // unlock the TaskScheduler's thread. - accept_cancel_pipe_.reset(); - - ArcStopReason reason; - if (stop_requested_) { - // If the ARC instance is stopped after its explicit request, - // return SHUTDOWN. - reason = ArcStopReason::SHUTDOWN; - } else if (clean) { - // If the ARC instance is stopped, but it is not explicitly requested, - // then this is triggered by some failure during the starting procedure. - // Return GENERIC_BOOT_FAILURE for the case. - reason = ArcStopReason::GENERIC_BOOT_FAILURE; - } else { - // Otherwise, this is caused by CRASH occured inside of the ARC instance. - reason = ArcStopReason::CRASH; - } - OnStopped(reason); -} - -void ArcSessionImpl::StartForLoginScreen() { - DCHECK_EQ(State::NOT_STARTED, state_); - - VLOG(2) << "Starting ARC session for login screen"; - login_screen_instance_requested_ = true; - state_ = State::STARTING_INSTANCE; - SendStartArcInstanceDBusMessage( - true /* instance_is_for_login_screen */, - base::Bind(&ArcSessionImpl::OnInstanceStarted, weak_factory_.GetWeakPtr(), - true /* instance_is_for_login_screen */)); -} - -bool ArcSessionImpl::IsForLoginScreen() { - return login_screen_instance_requested_; -} - -bool ArcSessionImpl::IsRunning() { - return state_ == State::RUNNING; -} - -bool ArcSessionImpl::IsStopRequested() { - return stop_requested_; -} - -void ArcSessionImpl::OnStopped(ArcStopReason reason) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - // OnStopped() should be called once per instance. - DCHECK_NE(state_, State::STOPPED); - VLOG(2) << "ARC session is stopped."; - const bool was_running = IsRunning(); - arc_bridge_host_.reset(); - state_ = State::STOPPED; - for (auto& observer : observer_list_) - observer.OnSessionStopped(reason, was_running); -} - -void ArcSessionImpl::OnShutdown() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - stop_requested_ = true; - if (state_ == State::STOPPED) - return; - - // Here, the message loop is already stopped, and the Chrome will be soon - // shutdown. Thus, it is not necessary to take care about restarting case. - // If ArcSession is waiting for mojo connection, cancels it. - accept_cancel_pipe_.reset(); - - // Stops the ARC instance to let it graceful shutdown. - // Note that this may fail if ARC container is not actually running, but - // ignore an error as described below. - if (state_ == State::STARTING_INSTANCE || - state_ == State::RUNNING_FOR_LOGIN_SCREEN || - state_ == State::CONNECTING_MOJO || state_ == State::RUNNING) { - StopArcInstance(); - } - - // Directly set to the STOPPED state by OnStopped(). Note that calling - // StopArcInstance() may not work well. At least, because the UI thread is - // already stopped here, ArcInstanceStopped() callback cannot be invoked. - OnStopped(ArcStopReason::SHUTDOWN); -} - -} // namespace - ArcSession::ArcSession() = default; ArcSession::~ArcSession() = default; @@ -698,7 +22,8 @@ void ArcSession::RemoveObserver(Observer* observer) { // static std::unique_ptr ArcSession::Create( ArcBridgeService* arc_bridge_service) { - return std::make_unique(arc_bridge_service); + return std::make_unique( + ArcSessionImpl::CreateDelegate(arc_bridge_service)); } } // namespace arc diff --git a/chromium/components/arc/arc_session.h b/chromium/components/arc/arc_session.h index be033514b65..6e303c93e75 100644 --- a/chromium/components/arc/arc_session.h +++ b/chromium/components/arc/arc_session.h @@ -9,6 +9,8 @@ #include "base/macros.h" #include "base/observer_list.h" +#include "base/optional.h" +#include "components/arc/arc_instance_mode.h" #include "components/arc/arc_stop_reason.h" namespace arc { @@ -18,7 +20,7 @@ class ArcBridgeService; // Starts the ARC instance and bootstraps the bridge connection. // Clients should implement the Delegate to be notified upon communications // being available. -// The instance can be safely removed 1) before Start*() is called, or 2) after +// The instance can be safely removed 1) before Start() is called, or 2) after // OnSessionStopped() is called. // The number of instances must be at most one. Otherwise, ARC instances will // conflict. @@ -42,27 +44,20 @@ class ArcSession { ArcBridgeService* arc_bridge_service); virtual ~ArcSession(); - // Starts an instance for login screen. The instance is not a fully functional - // one. - virtual void StartForLoginScreen() = 0; + // Starts an instance in the |request_mode|. Start(FULL_INSTANCE) should + // not be called twice or more. When Start(MINI_INSTANCE) was called then + // Start(FULL_INSTANCE) is called, it upgrades the mini instance to a full + // instance. + virtual void Start(ArcInstanceMode request_mode) = 0; - // Returns true if StartForLoginScreen() has been called but Start() hasn't. - virtual bool IsForLoginScreen() = 0; - - // Starts and bootstraps a connection with the instance. Start() should not - // be called twice or more. When StartForLoginScreen() has already been - // called, Start() turns the mini instance to a fully functional one. - virtual void Start() = 0; - - // Requests to stop the currently-running instance whether or not it is for - // login screen. + // Requests to stop the currently-running instance regardless of its mode. // The completion is notified via OnSessionStopped() of the Observer. virtual void Stop() = 0; - // Returns true if this instance is fully set up successfully, and running. - // Currently, this means, this is a fully functional instance, and - // Mojo connection is already connected successfully. - virtual bool IsRunning() = 0; + // Returns the current target mode, in which eventually this instance is + // running. + // If the instance is not yet started, this returns nullopt. + virtual base::Optional GetTargetMode() = 0; // Returns true if Stop() has been called already. virtual bool IsStopRequested() = 0; diff --git a/chromium/components/arc/arc_session_impl.cc b/chromium/components/arc/arc_session_impl.cc new file mode 100644 index 00000000000..d01edde3a38 --- /dev/null +++ b/chromium/components/arc/arc_session_impl.cc @@ -0,0 +1,637 @@ +// Copyright 2017 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 "components/arc/arc_session_impl.h" + +#include +#include +#include + +#include +#include + +#include "base/location.h" +#include "base/posix/eintr_wrapper.h" +#include "base/task_scheduler/post_task.h" +#include "base/task_scheduler/task_traits.h" +#include "chromeos/chromeos_switches.h" +#include "chromeos/cryptohome/cryptohome_parameters.h" +#include "chromeos/dbus/dbus_method_call_status.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "components/arc/arc_bridge_host_impl.h" +#include "components/arc/arc_features.h" +#include "components/user_manager/user_manager.h" +#include "mojo/edk/embedder/embedder.h" +#include "mojo/edk/embedder/named_platform_handle.h" +#include "mojo/edk/embedder/named_platform_handle_utils.h" +#include "mojo/edk/embedder/outgoing_broker_client_invitation.h" +#include "mojo/edk/embedder/platform_channel_pair.h" +#include "mojo/edk/embedder/platform_channel_utils_posix.h" +#include "mojo/edk/embedder/scoped_platform_handle.h" +#include "mojo/public/cpp/bindings/binding.h" + +namespace arc { + +namespace { + +using StartArcInstanceResult = + chromeos::SessionManagerClient::StartArcInstanceResult; + +chromeos::SessionManagerClient* GetSessionManagerClient() { + // If the DBusThreadManager or the SessionManagerClient aren't available, + // there isn't much we can do. This should only happen when running tests. + if (!chromeos::DBusThreadManager::IsInitialized() || + !chromeos::DBusThreadManager::Get() || + !chromeos::DBusThreadManager::Get()->GetSessionManagerClient()) { + return nullptr; + } + return chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); +} + +// Creates a pipe. Returns true on success, otherwise false. +// On success, |read_fd| will be set to the fd of the read side, and +// |write_fd| will be set to the one of write side. +bool CreatePipe(base::ScopedFD* read_fd, base::ScopedFD* write_fd) { + int fds[2]; + if (pipe2(fds, O_NONBLOCK | O_CLOEXEC) < 0) { + PLOG(ERROR) << "pipe2()"; + return false; + } + + read_fd->reset(fds[0]); + write_fd->reset(fds[1]); + return true; +} + +// Waits until |raw_socket_fd| is readable. +// The operation may be cancelled originally triggered by user interaction to +// disable ARC, or ARC instance is unexpectedly stopped (e.g. crash). +// To notify such a situation, |raw_cancel_fd| is also passed to here, and the +// write side will be closed in such a case. +bool WaitForSocketReadable(int raw_socket_fd, int raw_cancel_fd) { + struct pollfd fds[2] = { + {raw_socket_fd, POLLIN, 0}, {raw_cancel_fd, POLLIN, 0}, + }; + + if (HANDLE_EINTR(poll(fds, arraysize(fds), -1)) <= 0) { + PLOG(ERROR) << "poll()"; + return false; + } + + if (fds[1].revents) { + // Notified that Stop() is invoked. Cancel the Mojo connecting. + VLOG(1) << "Stop() was called during ConnectMojo()"; + return false; + } + + DCHECK(fds[0].revents); + return true; +} + +// Returns the ArcStopReason corresponding to the ARC instance staring failure. +ArcStopReason GetArcStopReason(StartArcInstanceResult result, + bool stop_requested) { + if (stop_requested) + return ArcStopReason::SHUTDOWN; + + switch (result) { + case StartArcInstanceResult::SUCCESS: + NOTREACHED(); + break; + case StartArcInstanceResult::UNKNOWN_ERROR: + return ArcStopReason::GENERIC_BOOT_FAILURE; + case StartArcInstanceResult::LOW_FREE_DISK_SPACE: + return ArcStopReason::LOW_DISK_SPACE; + } + + NOTREACHED(); + return ArcStopReason::GENERIC_BOOT_FAILURE; +} + +// Real Delegate implementation to connect Mojo. +class ArcSessionDelegateImpl : public ArcSessionImpl::Delegate { + public: + explicit ArcSessionDelegateImpl(ArcBridgeService* arc_bridge_service); + ~ArcSessionDelegateImpl() override = default; + + // ArcSessionImpl::Delegate override. + base::ScopedFD ConnectMojo(base::ScopedFD socket_fd, + ConnectMojoCallback callback) override; + + private: + // Synchronously accepts a connection on |socket_fd| and then processes the + // connected socket's file descriptor. This is designed to run on a + // blocking thread. + static mojo::ScopedMessagePipeHandle ConnectMojoInternal( + mojo::edk::ScopedPlatformHandle socket_fd, + base::ScopedFD cancel_fd); + + // Called when Mojo connection is established or canceled. + // In case of cancel or error, |server_pipe| is invalid. + void OnMojoConnected(ConnectMojoCallback callback, + mojo::ScopedMessagePipeHandle server_pipe); + + // Owned by ArcServiceManager. + ArcBridgeService* const arc_bridge_service_; + + // WeakPtrFactory to use callbacks. + base::WeakPtrFactory weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(ArcSessionDelegateImpl); +}; + +ArcSessionDelegateImpl::ArcSessionDelegateImpl( + ArcBridgeService* arc_bridge_service) + : arc_bridge_service_(arc_bridge_service), weak_factory_(this) {} + +base::ScopedFD ArcSessionDelegateImpl::ConnectMojo( + base::ScopedFD socket_fd, + ConnectMojoCallback callback) { + // Prepare a pipe so that AcceptInstanceConnection can be interrupted on + // Stop(). + base::ScopedFD cancel_fd; + base::ScopedFD return_fd; + if (!CreatePipe(&cancel_fd, &return_fd)) { + LOG(ERROR) << "Failed to create a pipe to cancel accept()"; + return base::ScopedFD(); + } + + // For production, |socket_fd| passed from session_manager is either a valid + // socket or a valid file descriptor (/dev/null). For testing, |socket_fd| + // might be invalid. + mojo::edk::PlatformHandle raw_handle(socket_fd.release()); + raw_handle.needs_connection = true; + + mojo::edk::ScopedPlatformHandle mojo_socket_fd(raw_handle); + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, {base::MayBlock()}, + base::BindOnce(&ArcSessionDelegateImpl::ConnectMojoInternal, + std::move(mojo_socket_fd), std::move(cancel_fd)), + base::BindOnce(&ArcSessionDelegateImpl::OnMojoConnected, + weak_factory_.GetWeakPtr(), std::move(callback))); + return return_fd; +} + +// static +mojo::ScopedMessagePipeHandle ArcSessionDelegateImpl::ConnectMojoInternal( + mojo::edk::ScopedPlatformHandle socket_fd, + base::ScopedFD cancel_fd) { + if (!WaitForSocketReadable(socket_fd.get().handle, cancel_fd.get())) { + VLOG(1) << "Mojo connection was cancelled."; + return mojo::ScopedMessagePipeHandle(); + } + + mojo::edk::ScopedPlatformHandle scoped_fd; + if (!mojo::edk::ServerAcceptConnection(socket_fd, &scoped_fd, + /* check_peer_user = */ false) || + !scoped_fd.is_valid()) { + return mojo::ScopedMessagePipeHandle(); + } + + // Hardcode pid 0 since it is unused in mojo. + const base::ProcessHandle kUnusedChildProcessHandle = 0; + mojo::edk::PlatformChannelPair channel_pair; + mojo::edk::OutgoingBrokerClientInvitation invitation; + + std::string token = mojo::edk::GenerateRandomToken(); + mojo::ScopedMessagePipeHandle pipe = invitation.AttachMessagePipe(token); + + invitation.Send( + kUnusedChildProcessHandle, + mojo::edk::ConnectionParams(mojo::edk::TransportProtocol::kLegacy, + channel_pair.PassServerHandle())); + + std::vector handles; + handles.emplace_back(channel_pair.PassClientHandle()); + + // We need to send the length of the message as a single byte, so make sure it + // fits. + DCHECK_LT(token.size(), 256u); + uint8_t message_length = static_cast(token.size()); + struct iovec iov[] = {{&message_length, sizeof(message_length)}, + {const_cast(token.c_str()), token.size()}}; + ssize_t result = mojo::edk::PlatformChannelSendmsgWithHandles( + scoped_fd, iov, sizeof(iov) / sizeof(iov[0]), handles); + if (result == -1) { + PLOG(ERROR) << "sendmsg"; + return mojo::ScopedMessagePipeHandle(); + } + + return pipe; +} + +void ArcSessionDelegateImpl::OnMojoConnected( + ConnectMojoCallback callback, + mojo::ScopedMessagePipeHandle server_pipe) { + if (!server_pipe.is_valid()) { + LOG(ERROR) << "Invalid pipe"; + std::move(callback).Run(nullptr); + return; + } + + mojom::ArcBridgeInstancePtr instance; + instance.Bind(mojo::InterfacePtrInfo( + std::move(server_pipe), 0u)); + std::move(callback).Run(std::make_unique( + arc_bridge_service_, std::move(instance))); +} + +} // namespace + +// static +std::unique_ptr ArcSessionImpl::CreateDelegate( + ArcBridgeService* arc_bridge_service) { + return std::make_unique(arc_bridge_service); +} + +ArcSessionImpl::ArcSessionImpl(std::unique_ptr delegate) + : delegate_(std::move(delegate)), weak_factory_(this) { + chromeos::SessionManagerClient* client = GetSessionManagerClient(); + if (client == nullptr) + return; + client->AddObserver(this); +} + +ArcSessionImpl::~ArcSessionImpl() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(state_ == State::NOT_STARTED || state_ == State::STOPPED); + chromeos::SessionManagerClient* client = GetSessionManagerClient(); + if (client == nullptr) + return; + client->RemoveObserver(this); +} + +void ArcSessionImpl::Start(ArcInstanceMode request_mode) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + target_mode_ = request_mode; + switch (request_mode) { + case ArcInstanceMode::MINI_INSTANCE: + StartMiniInstance(); + return; + case ArcInstanceMode::FULL_INSTANCE: + StartFullInstance(); + return; + } + + NOTREACHED(); +} + +void ArcSessionImpl::StartMiniInstance() { + DCHECK_EQ(State::NOT_STARTED, state_); + + VLOG(2) << "Starting ARC mini instance"; + state_ = State::STARTING_MINI_INSTANCE; + SendStartArcInstanceDBusMessage( + target_mode_.value(), + base::BindOnce(&ArcSessionImpl::OnMiniInstanceStarted, + weak_factory_.GetWeakPtr())); +} + +void ArcSessionImpl::OnMiniInstanceStarted( + chromeos::SessionManagerClient::StartArcInstanceResult result, + const std::string& container_instance_id, + base::ScopedFD socket_fd) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK_EQ(state_, State::STARTING_MINI_INSTANCE); + + if (result != StartArcInstanceResult::SUCCESS) { + LOG(ERROR) << "Failed to start ARC instance"; + OnStopped(GetArcStopReason(result, stop_requested_)); + return; + } + + DCHECK(!container_instance_id.empty()); + container_instance_id_ = container_instance_id; + VLOG(2) << "ARC mini instance is successfully started: " + << container_instance_id_; + + if (stop_requested_) { + // The ARC instance has started to run. Request to stop. + StopArcInstance(); + return; + } + + state_ = State::RUNNING_MINI_INSTANCE; + + if (target_mode_ == ArcInstanceMode::FULL_INSTANCE) { + // Start(FULL_INSTANCE) has been called during the D-Bus call. + StartFullInstance(); + } +} + +void ArcSessionImpl::StartFullInstance() { + // StartFullInstance() can be called either for starting ARC from scratch or + // for upgrading to an existing one. StartFullInstance() must be able to + // start a fully functional instance from all of |state_| up to and including + // RUNNING_MINI_INSTANCE. + switch (state_) { + case State::NOT_STARTED: + // A mini instance does not exist. Start a new one from scratch. + VLOG(2) << "Starting ARC session"; + state_ = State::STARTING_FULL_INSTANCE; + SendStartArcInstanceDBusMessage( + target_mode_.value(), + base::BindOnce(&ArcSessionImpl::OnFullInstanceStarted, + weak_factory_.GetWeakPtr())); + break; + case State::STARTING_MINI_INSTANCE: + VLOG(2) << "Requested to upgrade a starting ARC mini instance"; + // OnMiniInstanceStarted() will restart a full instance. + break; + case State::RUNNING_MINI_INSTANCE: + VLOG(2) << "Upgrading an existing ARC mini instance"; + state_ = State::STARTING_FULL_INSTANCE; + SendStartArcInstanceDBusMessage( + target_mode_.value(), + base::BindOnce(&ArcSessionImpl::OnFullInstanceStarted, + weak_factory_.GetWeakPtr())); + break; + case State::STARTING_FULL_INSTANCE: + case State::CONNECTING_MOJO: + case State::RUNNING_FULL_INSTANCE: + case State::STOPPED: + // These mean Start(FULL_INSTANCE) is called twice or called after + // stopped, which are invalid operations. + NOTREACHED(); + break; + } +} + +void ArcSessionImpl::OnFullInstanceStarted( + chromeos::SessionManagerClient::StartArcInstanceResult result, + const std::string& container_instance_id, + base::ScopedFD socket_fd) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK_EQ(state_, State::STARTING_FULL_INSTANCE); + + if (result != StartArcInstanceResult::SUCCESS) { + LOG(ERROR) << "Failed to start ARC instance"; + OnStopped(GetArcStopReason(result, stop_requested_)); + return; + } + + if (container_instance_id.empty()) { + // This was upgrade request. + VLOG(2) << "ARC instance is successfully upgraded."; + DCHECK(!container_instance_id_.empty()); + } else { + // This was a request to start a full instance from scratch. + container_instance_id_ = container_instance_id; + VLOG(2) << "ARC instance is successfully started: " + << container_instance_id_; + } + + if (stop_requested_) { + // The ARC instance has started to run. Request to stop. + StopArcInstance(); + return; + } + + VLOG(2) << "Connecting mojo..."; + state_ = State::CONNECTING_MOJO; + accept_cancel_pipe_ = delegate_->ConnectMojo( + std::move(socket_fd), base::BindOnce(&ArcSessionImpl::OnMojoConnected, + weak_factory_.GetWeakPtr())); + if (!accept_cancel_pipe_.is_valid()) { + // Failed to post a task to accept() the request. + StopArcInstance(); + return; + } +} + +// static +void ArcSessionImpl::SendStartArcInstanceDBusMessage( + ArcInstanceMode target_mode, + chromeos::SessionManagerClient::StartArcInstanceCallback callback) { + chromeos::SessionManagerClient* session_manager_client = + chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); + const bool native_bridge_experiment = + base::FeatureList::IsEnabled(arc::kNativeBridgeExperimentFeature); + if (target_mode == ArcInstanceMode::MINI_INSTANCE) { + session_manager_client->StartArcInstance( + chromeos::SessionManagerClient::ArcStartupMode::LOGIN_SCREEN, + // All variables below except |callback| will be ignored. + cryptohome::Identification(), false, false, native_bridge_experiment, + std::move(callback)); + return; + } + DCHECK_EQ(ArcInstanceMode::FULL_INSTANCE, target_mode); + + user_manager::UserManager* user_manager = user_manager::UserManager::Get(); + DCHECK(user_manager->GetPrimaryUser()); + const cryptohome::Identification cryptohome_id( + user_manager->GetPrimaryUser()->GetAccountId()); + + const bool skip_boot_completed_broadcast = + !base::FeatureList::IsEnabled(arc::kBootCompletedBroadcastFeature); + + // We only enable /vendor/priv-app when voice interaction is enabled because + // voice interaction service apk would be bundled in this location. + const bool scan_vendor_priv_app = + chromeos::switches::IsVoiceInteractionEnabled(); + + session_manager_client->StartArcInstance( + chromeos::SessionManagerClient::ArcStartupMode::FULL, cryptohome_id, + skip_boot_completed_broadcast, scan_vendor_priv_app, + native_bridge_experiment, std::move(callback)); +} + +void ArcSessionImpl::OnMojoConnected( + std::unique_ptr arc_bridge_host) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK_EQ(state_, State::CONNECTING_MOJO); + accept_cancel_pipe_.reset(); + + if (stop_requested_) { + StopArcInstance(); + return; + } + + if (!arc_bridge_host.get()) { + LOG(ERROR) << "Invalid pipe."; + StopArcInstance(); + return; + } + arc_bridge_host_ = std::move(arc_bridge_host); + + VLOG(0) << "ARC ready."; + state_ = State::RUNNING_FULL_INSTANCE; +} + +void ArcSessionImpl::Stop() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + VLOG(2) << "Stopping ARC session is requested."; + + // For second time or later, just do nothing. + // It is already in the stopping phase. + if (stop_requested_) + return; + + stop_requested_ = true; + arc_bridge_host_.reset(); + switch (state_) { + case State::NOT_STARTED: + OnStopped(ArcStopReason::SHUTDOWN); + return; + + case State::STARTING_MINI_INSTANCE: + case State::STARTING_FULL_INSTANCE: + // Before starting the ARC instance, we do nothing here. + // At some point, a callback will be invoked on UI thread, + // and stopping procedure will be run there. + // On Chrome shutdown, it is not the case because the message loop is + // already stopped here. Practically, it is not a problem because; + // - On starting instance, the container instance can be leaked. + // Practically it is not problematic because the session manager will + // clean it up. + return; + + case State::RUNNING_MINI_INSTANCE: + case State::RUNNING_FULL_INSTANCE: + // An ARC {mini,full} instance is running. Request to stop it. + StopArcInstance(); + return; + + case State::CONNECTING_MOJO: + // Mojo connection is being waited on TaskScheduler's thread. + // Request to cancel it. Following stopping procedure will run + // in its callback. + accept_cancel_pipe_.reset(); + return; + + case State::STOPPED: + // The instance is already stopped. Do nothing. + return; + } +} + +void ArcSessionImpl::StopArcInstance() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(state_ == State::STARTING_MINI_INSTANCE || + state_ == State::RUNNING_MINI_INSTANCE || + state_ == State::STARTING_FULL_INSTANCE || + state_ == State::CONNECTING_MOJO || + state_ == State::RUNNING_FULL_INSTANCE); + + VLOG(2) << "Requesting session_manager to stop ARC instance"; + + // When the instance is full instance, change the |state_| in + // ArcInstanceStopped(). + chromeos::SessionManagerClient* session_manager_client = + chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); + // Since we have the ArcInstanceStopped() callback, we don't need to do + // anything when StopArcInstance completes. + session_manager_client->StopArcInstance( + chromeos::EmptyVoidDBusMethodCallback()); +} + +void ArcSessionImpl::ArcInstanceStopped( + bool clean, + const std::string& container_instance_id) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + VLOG(1) << "Notified that ARC instance is stopped " + << (clean ? "cleanly" : "uncleanly"); + + if (container_instance_id != container_instance_id_) { + VLOG(1) << "Container instance id mismatch. Do nothing." + << container_instance_id << " vs " << container_instance_id_; + return; + } + + // Release |container_instance_id_| to avoid duplicate invocation situation. + container_instance_id_.clear(); + + // In case that crash happens during before the Mojo channel is connected, + // unlock the TaskScheduler's thread. + accept_cancel_pipe_.reset(); + + ArcStopReason reason; + if (stop_requested_) { + // If the ARC instance is stopped after its explicit request, + // return SHUTDOWN. + reason = ArcStopReason::SHUTDOWN; + } else if (clean) { + // If the ARC instance is stopped, but it is not explicitly requested, + // then this is triggered by some failure during the starting procedure. + // Return GENERIC_BOOT_FAILURE for the case. + reason = ArcStopReason::GENERIC_BOOT_FAILURE; + } else { + // Otherwise, this is caused by CRASH occured inside of the ARC instance. + reason = ArcStopReason::CRASH; + } + OnStopped(reason); +} + +base::Optional ArcSessionImpl::GetTargetMode() { + return target_mode_; +} + +bool ArcSessionImpl::IsStopRequested() { + return stop_requested_; +} + +void ArcSessionImpl::OnStopped(ArcStopReason reason) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + // OnStopped() should be called once per instance. + DCHECK_NE(state_, State::STOPPED); + VLOG(2) << "ARC session is stopped."; + const bool was_running = (state_ == State::RUNNING_FULL_INSTANCE); + arc_bridge_host_.reset(); + state_ = State::STOPPED; + for (auto& observer : observer_list_) + observer.OnSessionStopped(reason, was_running); +} + +void ArcSessionImpl::OnShutdown() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + stop_requested_ = true; + if (state_ == State::STOPPED) + return; + + // Here, the message loop is already stopped, and the Chrome will be soon + // shutdown. Thus, it is not necessary to take care about restarting case. + // If ArcSession is waiting for mojo connection, cancels it. + accept_cancel_pipe_.reset(); + + // Stops the ARC instance to let it graceful shutdown. + // Note that this may fail if ARC container is not actually running, but + // ignore an error as described below. + if (state_ == State::STARTING_MINI_INSTANCE || + state_ == State::RUNNING_MINI_INSTANCE || + state_ == State::STARTING_FULL_INSTANCE || + state_ == State::CONNECTING_MOJO || + state_ == State::RUNNING_FULL_INSTANCE) { + StopArcInstance(); + } + + // Directly set to the STOPPED state by OnStopped(). Note that calling + // StopArcInstance() may not work well. At least, because the UI thread is + // already stopped here, ArcInstanceStopped() callback cannot be invoked. + OnStopped(ArcStopReason::SHUTDOWN); +} + +std::ostream& operator<<(std::ostream& os, ArcSessionImpl::State state) { +#define MAP_STATE(name) \ + case ArcSessionImpl::State::name: \ + return os << #name + + switch (state) { + MAP_STATE(NOT_STARTED); + MAP_STATE(STARTING_MINI_INSTANCE); + MAP_STATE(RUNNING_MINI_INSTANCE); + MAP_STATE(STARTING_FULL_INSTANCE); + MAP_STATE(CONNECTING_MOJO); + MAP_STATE(RUNNING_FULL_INSTANCE); + MAP_STATE(STOPPED); + } +#undef MAP_STATE + + // Some compilers report an error even if all values of an enum-class are + // covered exhaustively in a switch statement. + NOTREACHED() << "Invalid value " << static_cast(state); + return os; +} + +} // namespace arc diff --git a/chromium/components/arc/arc_session_impl.h b/chromium/components/arc/arc_session_impl.h new file mode 100644 index 00000000000..d52a52f5bbd --- /dev/null +++ b/chromium/components/arc/arc_session_impl.h @@ -0,0 +1,242 @@ +// Copyright 2017 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 COMPONENTS_ARC_ARC_SESSION_IMPL_H_ +#define COMPONENTS_ARC_ARC_SESSION_IMPL_H_ + +#include +#include +#include + +#include "base/callback.h" +#include "base/files/scoped_file.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/optional.h" +#include "base/threading/thread_checker.h" +#include "chromeos/dbus/session_manager_client.h" +#include "components/arc/arc_instance_mode.h" +#include "components/arc/arc_session.h" + +namespace arc { + +namespace mojom { +class ArcBridgeHost; +} // namespace mojom + +class ArcSessionImpl : public ArcSession, + public chromeos::SessionManagerClient::Observer { + public: + // The possible states of the session. Expected state changes are as follows. + // + // 1) Starting MINI_INSTANCE. + // NOT_STARTED + // -> StartMiniInstance() -> + // STARTING_MINI_INSTANCE + // -> OnMiniInstanceStarted() -> + // RUNNING_MINI_INSTANCE. + // + // 2) Starting FULL_INSTANCE. + // NOT_STARTED + // -> StartFullInstance() -> + // STARTING_FULL_INSTANCE + // -> OnFullInstanceStarted() -> + // CONNECTING_MOJO + // -> OnMojoConnected() -> + // RUNNING_FULL_INSTANCE + // + // 3) Upgrading from a MINI_INSTANCE to FULL_INSTANCE. + // RUNNING_MINI_INSTANCE + // -> StartFullInstance() -> + // STARTING_FULL_INSTANCE + // -> ... (remaining is as same as (2)). + // + // Note that, if Start(FULL_INSTANCE) is called during STARTING_MINI_INSTANCE + // state, the state change to STARTING_FULL_INSTANCE is suspended until + // the state becomes RUNNING_MINI_INSTANCE. + // + // At any state, Stop() can be called. It may not immediately stop the + // instance, but will eventually stop it. The actual stop will be notified + // via ArcSession::Observer::OnSessionStopped(). + // + // When Stop() is called, it makes various behavior based on the current + // phase. + // + // NOT_STARTED: + // Do nothing. Immediately transition to the STOPPED state. + // STARTING_{MINI,FULL}_INSTANCE: + // The ARC instance is starting via SessionManager. Stop() just sets the + // flag and return. On the main task completion, a callback will run on the + // thread, and the flag is checked at the beginning of them. This should + // work under the assumption that the main tasks do not block indefinitely. + // In its callback, it checks if ARC instance is successfully started or + // not. In case of success, a request to stop the ARC instance is sent to + // SessionManager. Its completion will be notified via ArcInstanceStopped. + // Otherwise, it just turns into STOPPED state. + // CONNECTING_MOJO: + // The main task runs on TaskScheduler's thread, but it is a blocking call. + // So, Stop() sends a request to cancel the blocking by closing the pipe + // whose read side is also polled. Then, in its callback, similar to + // STARTING_{MINI,FULL}_INSTANCE, a request to stop the ARC instance is + // sent to SessionManager, and ArcInstanceStopped handles remaining + // procedure. + // RUNNING_{MINI,FULL}_INSTANCE: + // There is no more callback which runs on normal flow, so Stop() requests + // to stop the ARC instance via SessionManager. + // + // Another trigger to change the state coming from outside of this class + // is an event ArcInstanceStopped() sent from SessionManager, when ARC + // instace unexpectedly terminates. ArcInstanceStopped() turns the state into + // STOPPED immediately. + // + // In NOT_STARTED or STOPPED state, the instance can be safely destructed. + // Specifically, in STOPPED state, there may be inflight operations or + // pending callbacks. Though, what they do is just do-nothing conceptually + // and they can be safely ignored. + // + // Note: Order of constants below matters. Please make sure to sort them + // in chronological order. + enum class State { + // ARC is not yet started. + NOT_STARTED, + + // The request to start a mini instance has been sent. + STARTING_MINI_INSTANCE, + + // The instance is set up, but only a handful of processes NOT including + // arcbridgeservice (i.e. mojo endpoint) are running. + RUNNING_MINI_INSTANCE, + + // The request to start or upgrade to a full instance has been sent. + STARTING_FULL_INSTANCE, + + // The instance has started. Waiting for it to connect to the IPC bridge. + CONNECTING_MOJO, + + // The instance is fully set up. + RUNNING_FULL_INSTANCE, + + // ARC is terminated. + STOPPED, + }; + + // Delegate interface to emulate ArcBridgeHost mojo connection establishment. + class Delegate { + public: + // Used for ConnectMojo completion callback. + using ConnectMojoCallback = + base::OnceCallback)>; + + virtual ~Delegate() = default; + + // Connects ArcBridgeHost via |socket_fd|, and invokes |callback| with + // connected ArcBridgeHost instance if succeeded (or nullptr if failed). + // Returns a FD which cancels the current connection on close(2). + virtual base::ScopedFD ConnectMojo(base::ScopedFD socket_fd, + ConnectMojoCallback callback) = 0; + }; + + explicit ArcSessionImpl(std::unique_ptr delegate); + ~ArcSessionImpl() override; + + // Returns default delegate implementation used for the production. + static std::unique_ptr CreateDelegate( + ArcBridgeService* arc_bridge_service); + + State GetStateForTesting() { return state_; } + + // ArcSession overrides: + void Start(ArcInstanceMode request_mode) override; + void Stop() override; + base::Optional GetTargetMode() override; + bool IsStopRequested() override; + void OnShutdown() override; + + private: + // Sends a D-Bus message to start a mini instance. + void StartMiniInstance(); + + // D-Bus callback for StartArcInstance() for a mini instance. + // In case of success, |container_instance_id| must not be empty, and + // |socket_fd| is /dev/null. + // TODO(hidehiko): Remove |socket_fd| from this callback. + void OnMiniInstanceStarted( + chromeos::SessionManagerClient::StartArcInstanceResult result, + const std::string& container_instance_id, + base::ScopedFD socket_fd); + + // Sends a D-Bus message to start or to upgrade to a full instance. + void StartFullInstance(); + + // D-Bus callback for StartArcInstance() for a full instance. + // In case of success, |container_instance_id| must not be empty, if this is + // actually starting an instance, or empty if this is upgrade from a mini + // instance to a full instance. + // In either start or upgrade case, |socket_fd| should be a socket which + // shold be accept(2)ed to connect ArcBridgeService Mojo channel. + void OnFullInstanceStarted( + chromeos::SessionManagerClient::StartArcInstanceResult result, + const std::string& container_instance_id, + base::ScopedFD socket_fd); + + // Called when Mojo connection is established (or canceled during the + // connect.) + void OnMojoConnected(std::unique_ptr arc_bridge_host); + + // Request to stop ARC instance via DBus. + void StopArcInstance(); + + // chromeos::SessionManagerClient::Observer: + void ArcInstanceStopped(bool clean, + const std::string& container_instance_id) override; + + // Completes the termination procedure. Note that calling this may end up with + // deleting |this| because the function calls observers' OnSessionStopped(). + void OnStopped(ArcStopReason reason); + + // Sends a StartArcInstance D-Bus request to session_manager. + static void SendStartArcInstanceDBusMessage( + ArcInstanceMode target_mode, + chromeos::SessionManagerClient::StartArcInstanceCallback callback); + + // Checks whether a function runs on the thread where the instance is + // created. + THREAD_CHECKER(thread_checker_); + + // Delegate implementation. + std::unique_ptr delegate_; + + // The state of the session. + State state_ = State::NOT_STARTED; + + // When Stop() is called, this flag is set. + bool stop_requested_ = false; + + // In which mode this instance should be running eventually. + // Initialized in nullopt. + base::Optional target_mode_; + + // Container instance id passed from session_manager. + // Should be available only after On{Mini,Full}InstanceStarted(). + std::string container_instance_id_; + + // In CONNECTING_MOJO state, this is set to the write side of the pipe + // to notify cancelling of the procedure. + base::ScopedFD accept_cancel_pipe_; + + // Mojo endpoint. + std::unique_ptr arc_bridge_host_; + + // WeakPtrFactory to use callbacks. + base::WeakPtrFactory weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(ArcSessionImpl); +}; + +// Stringified output for logging purpose. +std::ostream& operator<<(std::ostream& os, ArcSessionImpl::State state); + +} // namespace arc + +#endif // COMPONENTS_ARC_ARC_SESSION_IMPL_H_ diff --git a/chromium/components/arc/arc_session_impl_unittest.cc b/chromium/components/arc/arc_session_impl_unittest.cc new file mode 100644 index 00000000000..bf513ab63b7 --- /dev/null +++ b/chromium/components/arc/arc_session_impl_unittest.cc @@ -0,0 +1,648 @@ +// Copyright 2017 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 +#include +#include + +#include +#include + +#include "base/location.h" +#include "base/posix/eintr_wrapper.h" +#include "base/run_loop.h" +#include "base/test/scoped_task_environment.h" +#include "base/threading/thread_task_runner_handle.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/fake_session_manager_client.h" +#include "components/arc/arc_session_impl.h" +#include "components/arc/test/fake_arc_bridge_host.h" +#include "components/signin/core/account_id/account_id.h" +#include "components/user_manager/fake_user_manager.h" +#include "components/user_manager/scoped_user_manager.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace arc { +namespace { + +constexpr char kFakeGmail[] = "user@gmail.com"; +constexpr char kFakeGmailGaiaId[] = "1234567890"; + +class FakeDelegate : public ArcSessionImpl::Delegate { + public: + FakeDelegate() = default; + + // Emulates to fail Mojo connection establishing. |callback| passed to + // ConnectMojo will be called with nullptr. + void EmulateMojoConnectionFailure() { success_ = false; } + + // Suspends to complete the MojoConnection, when ConnectMojo is called. + // Later, when ResumeMojoConnection() is called, the passed callback will be + // asynchronously called. + void SuspendMojoConnection() { suspend_ = true; } + + // Resumes the pending Mojo connection establishment. Before, + // SuspendMojoConnection() must be called followed by ConnectMojo(). + // ConnectMojo's |callback| will be called asynchronously. + void ResumeMojoConnection() { + DCHECK(!pending_callback_.is_null()); + PostCallback(std::move(pending_callback_)); + } + + // ArcSessionImpl::Delegate override: + base::ScopedFD ConnectMojo(base::ScopedFD socket_fd, + ConnectMojoCallback callback) override { + if (suspend_) { + DCHECK(pending_callback_.is_null()); + pending_callback_ = std::move(callback); + } else { + PostCallback(std::move(callback)); + } + + // Open /dev/null as a dummy FD. + return base::ScopedFD(HANDLE_EINTR(open("/dev/null", O_RDONLY))); + } + + private: + void PostCallback(ConnectMojoCallback callback) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce( + std::move(callback), + success_ ? std::make_unique() : nullptr)); + } + + bool success_ = true; + bool suspend_ = false; + ConnectMojoCallback pending_callback_; + + DISALLOW_COPY_AND_ASSIGN(FakeDelegate); +}; + +class TestArcSessionObserver : public ArcSession::Observer { + public: + struct OnSessionStoppedArgs { + ArcStopReason reason; + bool was_running; + }; + + explicit TestArcSessionObserver(ArcSession* arc_session) + : arc_session_(arc_session) { + arc_session_->AddObserver(this); + } + + ~TestArcSessionObserver() override { arc_session_->RemoveObserver(this); } + + const base::Optional& on_session_stopped_args() const { + return on_session_stopped_args_; + } + + // ArcSession::Observer overrides: + void OnSessionStopped(ArcStopReason reason, bool was_running) override { + on_session_stopped_args_.emplace(OnSessionStoppedArgs{reason, was_running}); + } + + private: + ArcSession* const arc_session_; // Not owned. + base::Optional on_session_stopped_args_; + + DISALLOW_COPY_AND_ASSIGN(TestArcSessionObserver); +}; + +// Custom deleter for ArcSession testing. +struct ArcSessionDeleter { + void operator()(ArcSession* arc_session) { + // ArcSessionImpl must be in STOPPED state, if the instance is being + // destroyed. Calling OnShutdown() just before ensures it. + arc_session->OnShutdown(); + delete arc_session; + } +}; + +class ArcSessionImplTest : public testing::Test { + public: + ArcSessionImplTest() { + chromeos::DBusThreadManager::GetSetterForTesting()->SetSessionManagerClient( + std::make_unique()); + GetSessionManagerClient()->set_arc_available(true); + + // Create a user and set it as the primary user. + const AccountId account_id = + AccountId::FromUserEmailGaiaId(kFakeGmail, kFakeGmailGaiaId); + const user_manager::User* user = GetUserManager()->AddUser(account_id); + GetUserManager()->UserLoggedIn(account_id, user->username_hash(), + false /* browser_restart */, + false /* is_child */); + } + + ~ArcSessionImplTest() override { + GetUserManager()->RemoveUserFromList( + AccountId::FromUserEmailGaiaId(kFakeGmail, kFakeGmailGaiaId)); + chromeos::DBusThreadManager::Shutdown(); + } + + chromeos::FakeSessionManagerClient* GetSessionManagerClient() { + return static_cast( + chromeos::DBusThreadManager::Get()->GetSessionManagerClient()); + } + + user_manager::FakeUserManager* GetUserManager() { + return static_cast( + user_manager::UserManager::Get()); + } + + void EmulateDBusFailure() { + GetSessionManagerClient()->set_arc_available(false); + } + + std::unique_ptr CreateArcSession( + std::unique_ptr delegate = nullptr) { + if (!delegate) + delegate = std::make_unique(); + return std::unique_ptr( + new ArcSessionImpl(std::move(delegate))); + } + + void SetupMiniContainer(ArcSessionImpl* arc_session, + TestArcSessionObserver* observer) { + arc_session->Start(ArcInstanceMode::MINI_INSTANCE); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(ArcSessionImpl::State::RUNNING_MINI_INSTANCE, + arc_session->GetStateForTesting()); + ASSERT_FALSE(observer->on_session_stopped_args().has_value()); + } + + private: + base::test::ScopedTaskEnvironment scoped_task_environment_; + user_manager::ScopedUserManager scoped_user_manager_{ + std::make_unique()}; + + DISALLOW_COPY_AND_ASSIGN(ArcSessionImplTest); +}; + +// Simple case. Starting FULL_INSTANCE will eventually start the container. +TEST_F(ArcSessionImplTest, FullInstance_Success) { + auto arc_session = CreateArcSession(); + TestArcSessionObserver observer(arc_session.get()); + arc_session->Start(ArcInstanceMode::FULL_INSTANCE); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::RUNNING_FULL_INSTANCE, + arc_session->GetStateForTesting()); + EXPECT_FALSE(observer.on_session_stopped_args().has_value()); +} + +// SessionManagerClient::StartArcInstance() reports an error, so that +// the container fails to start. +TEST_F(ArcSessionImplTest, FullInstance_DBusFail) { + EmulateDBusFailure(); + + auto arc_session = CreateArcSession(); + TestArcSessionObserver observer(arc_session.get()); + arc_session->Start(ArcInstanceMode::FULL_INSTANCE); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); + ASSERT_TRUE(observer.on_session_stopped_args().has_value()); + EXPECT_EQ(ArcStopReason::GENERIC_BOOT_FAILURE, + observer.on_session_stopped_args()->reason); + EXPECT_FALSE(observer.on_session_stopped_args()->was_running); +} + +// SessionManagerClient::StartArcInstance() fails due to low disk, so that +// the container fails to start with reporting LOW_DISK_SPACE. +TEST_F(ArcSessionImplTest, FullInstance_LowDisk) { + GetSessionManagerClient()->set_low_disk(true); + + auto arc_session = CreateArcSession(); + TestArcSessionObserver observer(arc_session.get()); + arc_session->Start(ArcInstanceMode::FULL_INSTANCE); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); + ASSERT_TRUE(observer.on_session_stopped_args().has_value()); + EXPECT_EQ(ArcStopReason::LOW_DISK_SPACE, + observer.on_session_stopped_args()->reason); + EXPECT_FALSE(observer.on_session_stopped_args()->was_running); +} + +// Mojo connection fails, so that the container fails to start. +TEST_F(ArcSessionImplTest, FullInstance_MojoConnectionFail) { + auto delegate = std::make_unique(); + delegate->EmulateMojoConnectionFailure(); + + auto arc_session = CreateArcSession(std::move(delegate)); + TestArcSessionObserver observer(arc_session.get()); + arc_session->Start(ArcInstanceMode::FULL_INSTANCE); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); + ASSERT_TRUE(observer.on_session_stopped_args().has_value()); + EXPECT_EQ(ArcStopReason::GENERIC_BOOT_FAILURE, + observer.on_session_stopped_args()->reason); + EXPECT_FALSE(observer.on_session_stopped_args()->was_running); +} + +// Starting mini container success case. +TEST_F(ArcSessionImplTest, MiniInstance_Success) { + auto arc_session = CreateArcSession(); + TestArcSessionObserver observer(arc_session.get()); + arc_session->Start(ArcInstanceMode::MINI_INSTANCE); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::RUNNING_MINI_INSTANCE, + arc_session->GetStateForTesting()); + EXPECT_FALSE(observer.on_session_stopped_args().has_value()); +} + +// SessionManagerClient::StartArcInstance() reports an error, so that +// the container fails to start as a mini container. +TEST_F(ArcSessionImplTest, MiniInstance_DBusFail) { + EmulateDBusFailure(); + + auto arc_session = CreateArcSession(); + TestArcSessionObserver observer(arc_session.get()); + arc_session->Start(ArcInstanceMode::MINI_INSTANCE); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); + ASSERT_TRUE(observer.on_session_stopped_args().has_value()); + EXPECT_EQ(ArcStopReason::GENERIC_BOOT_FAILURE, + observer.on_session_stopped_args()->reason); + EXPECT_FALSE(observer.on_session_stopped_args()->was_running); +} + +// SessionManagerClient::StartArcInstance() reports an error due to low disk, +// so that the container fails to start as a mini container with reporting +// LOW_DISK_SPACE. +TEST_F(ArcSessionImplTest, MiniInstance_LowDisk) { + GetSessionManagerClient()->set_low_disk(true); + + auto arc_session = CreateArcSession(); + TestArcSessionObserver observer(arc_session.get()); + arc_session->Start(ArcInstanceMode::MINI_INSTANCE); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); + ASSERT_TRUE(observer.on_session_stopped_args().has_value()); + EXPECT_EQ(ArcStopReason::LOW_DISK_SPACE, + observer.on_session_stopped_args()->reason); + EXPECT_FALSE(observer.on_session_stopped_args()->was_running); +} + +// Upgrading a mini container to a full container. Success case. +TEST_F(ArcSessionImplTest, Upgrade_Success) { + // Set up. Start a mini instance. + auto arc_session = CreateArcSession(); + TestArcSessionObserver observer(arc_session.get()); + ASSERT_NO_FATAL_FAILURE(SetupMiniContainer(arc_session.get(), &observer)); + + // Then, upgrade to a full instance. + arc_session->Start(ArcInstanceMode::FULL_INSTANCE); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::RUNNING_FULL_INSTANCE, + arc_session->GetStateForTesting()); + EXPECT_FALSE(observer.on_session_stopped_args().has_value()); +} + +// SessionManagerClient::StartArcInstance() reports an error for upgrading +// case, then the upgrading fails. +TEST_F(ArcSessionImplTest, Upgrade_DBusFail) { + // Set up. Start a mini instance. + auto arc_session = CreateArcSession(); + TestArcSessionObserver observer(arc_session.get()); + ASSERT_NO_FATAL_FAILURE(SetupMiniContainer(arc_session.get(), &observer)); + + // Hereafter, let SessionManagerClient::StartArcInstance() fail. + EmulateDBusFailure(); + + // Then upgrade, which should fail. + arc_session->Start(ArcInstanceMode::FULL_INSTANCE); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); + ASSERT_TRUE(observer.on_session_stopped_args().has_value()); + EXPECT_EQ(ArcStopReason::GENERIC_BOOT_FAILURE, + observer.on_session_stopped_args()->reason); + EXPECT_FALSE(observer.on_session_stopped_args()->was_running); +} + +// Mojo connection fails on upgrading. Then, the upgrade fails. +TEST_F(ArcSessionImplTest, Upgrade_MojoConnectionFail) { + // Let Mojo connection fail. + auto delegate = std::make_unique(); + delegate->EmulateMojoConnectionFailure(); + + // Set up. Start mini instance. + auto arc_session = CreateArcSession(std::move(delegate)); + TestArcSessionObserver observer(arc_session.get()); + // Starting mini instance should succeed, because it is not related to + // Mojo connection. + ASSERT_NO_FATAL_FAILURE(SetupMiniContainer(arc_session.get(), &observer)); + + // Upgrade should fail, due to Mojo connection fail set above. + arc_session->Start(ArcInstanceMode::FULL_INSTANCE); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); + ASSERT_TRUE(observer.on_session_stopped_args().has_value()); + EXPECT_EQ(ArcStopReason::GENERIC_BOOT_FAILURE, + observer.on_session_stopped_args()->reason); + EXPECT_FALSE(observer.on_session_stopped_args()->was_running); +} + +// Calling StartArcInstance() during STARTING_MINI_INSTANCE should eventually +// succeed to run a full container. +TEST_F(ArcSessionImplTest, Upgrade_StartingMiniInstance) { + auto arc_session = CreateArcSession(); + TestArcSessionObserver observer(arc_session.get()); + arc_session->Start(ArcInstanceMode::MINI_INSTANCE); + ASSERT_EQ(ArcSessionImpl::State::STARTING_MINI_INSTANCE, + arc_session->GetStateForTesting()); + + // Before moving forward to RUNNING_MINI_INSTANCE, start upgrading it. + arc_session->Start(ArcInstanceMode::FULL_INSTANCE); + + // The state should not immediately switch to STARTING_FULL_INSTANCE, yet. + EXPECT_EQ(ArcSessionImpl::State::STARTING_MINI_INSTANCE, + arc_session->GetStateForTesting()); + + // Complete the upgrade procedure. + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::RUNNING_FULL_INSTANCE, + arc_session->GetStateForTesting()); + EXPECT_FALSE(observer.on_session_stopped_args().has_value()); +} + +// Testing stop during START_MINI_INSTANCE. +TEST_F(ArcSessionImplTest, Stop_StartingMiniInstance) { + auto arc_session = CreateArcSession(); + TestArcSessionObserver observer(arc_session.get()); + arc_session->Start(ArcInstanceMode::MINI_INSTANCE); + ASSERT_EQ(ArcSessionImpl::State::STARTING_MINI_INSTANCE, + arc_session->GetStateForTesting()); + + arc_session->Stop(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); + ASSERT_TRUE(observer.on_session_stopped_args().has_value()); + EXPECT_EQ(ArcStopReason::SHUTDOWN, + observer.on_session_stopped_args()->reason); + EXPECT_FALSE(observer.on_session_stopped_args()->was_running); +} + +// Testing stop during RUNNING_MINI_INSTANCE. +TEST_F(ArcSessionImplTest, Stop_RunningMiniInstance) { + auto arc_session = CreateArcSession(); + TestArcSessionObserver observer(arc_session.get()); + arc_session->Start(ArcInstanceMode::MINI_INSTANCE); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(ArcSessionImpl::State::RUNNING_MINI_INSTANCE, + arc_session->GetStateForTesting()); + + arc_session->Stop(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); + ASSERT_TRUE(observer.on_session_stopped_args().has_value()); + EXPECT_EQ(ArcStopReason::SHUTDOWN, + observer.on_session_stopped_args()->reason); + EXPECT_FALSE(observer.on_session_stopped_args()->was_running); +} + +// Testing stop during STARTING_FULL_INSTANCE. +TEST_F(ArcSessionImplTest, Stop_StartingFullInstance) { + auto arc_session = CreateArcSession(); + TestArcSessionObserver observer(arc_session.get()); + arc_session->Start(ArcInstanceMode::FULL_INSTANCE); + ASSERT_EQ(ArcSessionImpl::State::STARTING_FULL_INSTANCE, + arc_session->GetStateForTesting()); + + arc_session->Stop(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); + ASSERT_TRUE(observer.on_session_stopped_args().has_value()); + EXPECT_EQ(ArcStopReason::SHUTDOWN, + observer.on_session_stopped_args()->reason); + EXPECT_FALSE(observer.on_session_stopped_args()->was_running); +} + +// Testing stop during CONNECTING_MOJO. +TEST_F(ArcSessionImplTest, Stop_ConnectingMojo) { + // Let Mojo connection suspend. + auto delegate = std::make_unique(); + delegate->SuspendMojoConnection(); + auto* delegate_ptr = delegate.get(); + auto arc_session = CreateArcSession(std::move(delegate)); + TestArcSessionObserver observer(arc_session.get()); + arc_session->Start(ArcInstanceMode::FULL_INSTANCE); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(ArcSessionImpl::State::CONNECTING_MOJO, + arc_session->GetStateForTesting()); + + arc_session->Stop(); + delegate_ptr->ResumeMojoConnection(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); + ASSERT_TRUE(observer.on_session_stopped_args().has_value()); + EXPECT_EQ(ArcStopReason::SHUTDOWN, + observer.on_session_stopped_args()->reason); + EXPECT_FALSE(observer.on_session_stopped_args()->was_running); +} + +// Testing stop during RUNNING_FULL_INSTANCE. +TEST_F(ArcSessionImplTest, Stop_RunningFullInstance) { + auto arc_session = CreateArcSession(); + TestArcSessionObserver observer(arc_session.get()); + arc_session->Start(ArcInstanceMode::FULL_INSTANCE); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(ArcSessionImpl::State::RUNNING_FULL_INSTANCE, + arc_session->GetStateForTesting()); + + arc_session->Stop(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); + ASSERT_TRUE(observer.on_session_stopped_args().has_value()); + EXPECT_EQ(ArcStopReason::SHUTDOWN, + observer.on_session_stopped_args()->reason); + EXPECT_TRUE(observer.on_session_stopped_args()->was_running); +} + +// Testing stop during STARTING_FULL_INSTANCE for upgrade. +TEST_F(ArcSessionImplTest, Stop_StartingFullInstanceForUpgrade) { + auto arc_session = CreateArcSession(); + TestArcSessionObserver observer(arc_session.get()); + // Start mini container. + ASSERT_NO_FATAL_FAILURE(SetupMiniContainer(arc_session.get(), &observer)); + + // Then upgrade. + arc_session->Start(ArcInstanceMode::FULL_INSTANCE); + ASSERT_EQ(ArcSessionImpl::State::STARTING_FULL_INSTANCE, + arc_session->GetStateForTesting()); + + // Request to stop during STARTING_FULL_INSTANCE state. + arc_session->Stop(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); + ASSERT_TRUE(observer.on_session_stopped_args().has_value()); + EXPECT_EQ(ArcStopReason::SHUTDOWN, + observer.on_session_stopped_args()->reason); + EXPECT_FALSE(observer.on_session_stopped_args()->was_running); +} + +// Testing stop during CONNECTING_MOJO for upgrade. +TEST_F(ArcSessionImplTest, Stop_ConnectingMojoForUpgrade) { + // Let Mojo connection suspend. + auto delegate = std::make_unique(); + delegate->SuspendMojoConnection(); + auto* delegate_ptr = delegate.get(); + auto arc_session = CreateArcSession(std::move(delegate)); + TestArcSessionObserver observer(arc_session.get()); + // Start mini container. + ASSERT_NO_FATAL_FAILURE(SetupMiniContainer(arc_session.get(), &observer)); + + // Then upgrade. This should suspend at Mojo connection. + arc_session->Start(ArcInstanceMode::FULL_INSTANCE); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(ArcSessionImpl::State::CONNECTING_MOJO, + arc_session->GetStateForTesting()); + + // Request to stop, then resume the Mojo connection. + arc_session->Stop(); + delegate_ptr->ResumeMojoConnection(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); + ASSERT_TRUE(observer.on_session_stopped_args().has_value()); + EXPECT_EQ(ArcStopReason::SHUTDOWN, + observer.on_session_stopped_args()->reason); + EXPECT_FALSE(observer.on_session_stopped_args()->was_running); +} + +// Testing stop during RUNNING_FULL_INSTANCE after upgrade. +TEST_F(ArcSessionImplTest, Stop_RunningFullInstanceForUpgrade) { + auto arc_session = CreateArcSession(); + TestArcSessionObserver observer(arc_session.get()); + // Start mini container. + ASSERT_NO_FATAL_FAILURE(SetupMiniContainer(arc_session.get(), &observer)); + + // And upgrade successfully. + arc_session->Start(ArcInstanceMode::FULL_INSTANCE); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(ArcSessionImpl::State::RUNNING_FULL_INSTANCE, + arc_session->GetStateForTesting()); + + // Then request to stop. + arc_session->Stop(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); + ASSERT_TRUE(observer.on_session_stopped_args().has_value()); + EXPECT_EQ(ArcStopReason::SHUTDOWN, + observer.on_session_stopped_args()->reason); + EXPECT_TRUE(observer.on_session_stopped_args()->was_running); +} + +// Testing stop during STARTING_MINI_INSTANCE with upgrade request. +TEST_F(ArcSessionImplTest, + Stop_StartingFullInstanceForUpgradeDuringMiniInstanceStart) { + auto arc_session = CreateArcSession(); + TestArcSessionObserver observer(arc_session.get()); + arc_session->Start(ArcInstanceMode::MINI_INSTANCE); + ASSERT_EQ(ArcSessionImpl::State::STARTING_MINI_INSTANCE, + arc_session->GetStateForTesting()); + + // Request to upgrade during starting mini container. + arc_session->Start(ArcInstanceMode::FULL_INSTANCE); + // Then, the state should stay at STARTING_MINI_INSTANCE. + ASSERT_EQ(ArcSessionImpl::State::STARTING_MINI_INSTANCE, + arc_session->GetStateForTesting()); + + // Request to stop. + arc_session->Stop(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); + ASSERT_TRUE(observer.on_session_stopped_args().has_value()); + EXPECT_EQ(ArcStopReason::SHUTDOWN, + observer.on_session_stopped_args()->reason); + EXPECT_FALSE(observer.on_session_stopped_args()->was_running); +} + +// Stop is requested, but at the same time +// SessionManagerClient::StartArcInstance() reports an error. Then, it should +// be handled as regular SHUTDOWN, because graceful shutdown itself is +// difficult and sometimes reports unexpected error although it succeeds. +TEST_F(ArcSessionImplTest, Stop_ConflictWithFailure) { + // Let SessionManagerClient::StartArcInstance() fail. + EmulateDBusFailure(); + + auto arc_session = CreateArcSession(); + TestArcSessionObserver observer(arc_session.get()); + arc_session->Start(ArcInstanceMode::FULL_INSTANCE); + ASSERT_EQ(ArcSessionImpl::State::STARTING_FULL_INSTANCE, + arc_session->GetStateForTesting()); + + arc_session->Stop(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); + ASSERT_TRUE(observer.on_session_stopped_args().has_value()); + // Even if D-Bus reports an error, if Stop() is invoked, it will be handled + // as clean shutdown. + EXPECT_EQ(ArcStopReason::SHUTDOWN, + observer.on_session_stopped_args()->reason); + EXPECT_FALSE(observer.on_session_stopped_args()->was_running); +} + +// Emulating crash. +TEST_F(ArcSessionImplTest, ArcStopInstance) { + auto arc_session = CreateArcSession(); + TestArcSessionObserver observer(arc_session.get()); + arc_session->Start(ArcInstanceMode::FULL_INSTANCE); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(ArcSessionImpl::State::RUNNING_FULL_INSTANCE, + arc_session->GetStateForTesting()); + + // Deliver the ArcInstanceStopped D-Bus signal. + auto* session_manager_client = GetSessionManagerClient(); + session_manager_client->NotifyArcInstanceStopped( + false /* meaning crash */, + session_manager_client->container_instance_id()); + + EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); + ASSERT_TRUE(observer.on_session_stopped_args().has_value()); + EXPECT_EQ(ArcStopReason::CRASH, observer.on_session_stopped_args()->reason); + EXPECT_TRUE(observer.on_session_stopped_args()->was_running); +} + +// ArcStopInstance for the *previous* ARC container may be reported +// to the current instance in very racy timing. +// Unrelated ArcStopInstance signal should be ignored. +TEST_F(ArcSessionImplTest, ArcStopInstance_WrongContainerInstanceId) { + auto arc_session = CreateArcSession(); + arc_session->Start(ArcInstanceMode::FULL_INSTANCE); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(ArcSessionImpl::State::RUNNING_FULL_INSTANCE, + arc_session->GetStateForTesting()); + + // Deliver the ArcInstanceStopped D-Bus signal. + auto* session_manager_client = GetSessionManagerClient(); + session_manager_client->NotifyArcInstanceStopped(false /* meaning crash */, + "dummy instance id"); + + // The signal should be ignored. + EXPECT_EQ(ArcSessionImpl::State::RUNNING_FULL_INSTANCE, + arc_session->GetStateForTesting()); +} + +} // namespace +} // namespace arc diff --git a/chromium/components/arc/arc_session_runner.cc b/chromium/components/arc/arc_session_runner.cc index 2eed49d1d1a..1e3eccbcfe6 100644 --- a/chromium/components/arc/arc_session_runner.cc +++ b/chromium/components/arc/arc_session_runner.cc @@ -5,6 +5,8 @@ #include "components/arc/arc_session_runner.h" #include "base/logging.h" +#include "base/metrics/histogram_macros.h" +#include "base/optional.h" #include "base/task_runner.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "components/arc/arc_util.h" @@ -26,6 +28,45 @@ chromeos::SessionManagerClient* GetSessionManagerClient() { return chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); } +void RecordInstanceCrashUma(ArcContainerLifetimeEvent sample) { + UMA_HISTOGRAM_ENUMERATION("Arc.ContainerLifetimeEvent", sample, + ArcContainerLifetimeEvent::COUNT); +} + +void RecordInstanceRestartAfterCrashUma(size_t restart_after_crash_count) { + UMA_HISTOGRAM_COUNTS_100("Arc.ContainerRestartAfterCrashCount", + restart_after_crash_count); +} + +// Gets an ArcContainerLifetimeEvent value to record. Returns nullopt when no +// UMA recording is needed. +base::Optional GetArcContainerLifetimeEvent( + size_t restart_after_crash_count, + ArcStopReason stop_reason, + bool was_running) { + // Record UMA only when this is the first non-early crash. This has to be + // done before checking other conditions. Otherwise, an early crash after + // container restart might be recorded. Each CONTAINER_STARTED event can + // be paired up to one non-START event. + if (restart_after_crash_count) + return base::nullopt; + + switch (stop_reason) { + case ArcStopReason::SHUTDOWN: + case ArcStopReason::LOW_DISK_SPACE: + // We don't record these events. + return base::nullopt; + case ArcStopReason::GENERIC_BOOT_FAILURE: + return ArcContainerLifetimeEvent::CONTAINER_FAILED_TO_START; + case ArcStopReason::CRASH: + return was_running ? ArcContainerLifetimeEvent::CONTAINER_CRASHED + : ArcContainerLifetimeEvent::CONTAINER_CRASHED_EARLY; + } + + NOTREACHED(); + return base::nullopt; +} + // Returns true if restart is needed for given conditions. bool IsRestartNeeded(base::Optional target_mode, ArcStopReason stop_reason, @@ -60,15 +101,17 @@ bool IsRestartNeeded(base::Optional target_mode, return false; } -std::ostream& operator<<(std::ostream& os, - base::Optional mode) { - return mode.has_value() ? (os << mode.value()) : (os << "(nullopt)"); -} - // Returns true if the request to start/upgrade ARC instance is allowed // operation. bool IsRequestAllowed(const base::Optional& current_mode, ArcInstanceMode request_mode) { + if (request_mode == ArcInstanceMode::MINI_INSTANCE && + ShouldArcOnlyStartAfterLogin()) { + // Skip starting ARC for now. We'll have another chance to start the full + // instance after the user logs in. + return false; + } + if (!current_mode.has_value()) { // This is a request to start a new ARC instance (either mini instance // or full instance). @@ -87,10 +130,28 @@ bool IsRequestAllowed(const base::Optional& current_mode, return false; } +// Returns true if OnSessionStopped() should be called to notify observers. +bool ShouldNotifyOnSessionStopped( + const base::Optional& target_mode) { + DCHECK(target_mode.has_value()); + + switch (target_mode.value()) { + case ArcInstanceMode::MINI_INSTANCE: + return false; + case ArcInstanceMode::FULL_INSTANCE: + return true; + } + + NOTREACHED() << "Unexpeceted |target_mode|: " + << static_cast(target_mode.value()); + return false; +} + } // namespace ArcSessionRunner::ArcSessionRunner(const ArcSessionFactory& factory) : restart_delay_(kDefaultRestartDelay), + restart_after_crash_count_(0), factory_(factory), weak_ptr_factory_(this) { chromeos::SessionManagerClient* client = GetSessionManagerClient(); @@ -205,18 +266,15 @@ void ArcSessionRunner::StartArcSession() { if (!arc_session_) { arc_session_ = factory_.Run(); arc_session_->AddObserver(this); + // Record the UMA only when |restart_after_crash_count_| is zero to avoid + // recording an auto-restart-then-crash loop. Such a crash loop is recorded + // separately with RecordInstanceRestartAfterCrashUma(). + if (!restart_after_crash_count_) + RecordInstanceCrashUma(ArcContainerLifetimeEvent::CONTAINER_STARTING); } else { - DCHECK(arc_session_->IsForLoginScreen()); - } - - switch (target_mode_.value()) { - case ArcInstanceMode::MINI_INSTANCE: - arc_session_->StartForLoginScreen(); - break; - case ArcInstanceMode::FULL_INSTANCE: - arc_session_->Start(); - break; + DCHECK_EQ(ArcInstanceMode::MINI_INSTANCE, arc_session_->GetTargetMode()); } + arc_session_->Start(target_mode_.value()); } void ArcSessionRunner::RestartArcSession() { @@ -237,13 +295,29 @@ void ArcSessionRunner::OnSessionStopped(ArcStopReason stop_reason, // The observers should be agnostic to the existence of the limited-purpose // instance. - const bool notify_observers = !arc_session_->IsForLoginScreen(); + const bool notify_observers = + ShouldNotifyOnSessionStopped(arc_session_->GetTargetMode()); arc_session_->RemoveObserver(this); arc_session_.reset(); + const base::Optional uma_to_record = + GetArcContainerLifetimeEvent(restart_after_crash_count_, stop_reason, + was_running); + if (uma_to_record.has_value()) + RecordInstanceCrashUma(uma_to_record.value()); + const bool restarting = IsRestartNeeded(target_mode_, stop_reason, was_running); + + if (restarting && stop_reason == ArcStopReason::CRASH) { + ++restart_after_crash_count_; + } else { + // The session ended. Record the restart count. + RecordInstanceRestartAfterCrashUma(restart_after_crash_count_); + restart_after_crash_count_ = 0; + } + if (restarting) { // There was a previous invocation and it crashed for some reason. Try // starting ARC instance later again. @@ -262,17 +336,12 @@ void ArcSessionRunner::OnSessionStopped(ArcStopReason stop_reason, } void ArcSessionRunner::EmitLoginPromptVisibleCalled() { - if (ShouldArcOnlyStartAfterLogin()) { - // Skip starting ARC for now. We'll have another chance to start the full - // instance after the user logs in. - return; - } - // Since 'login-prompt-visible' Upstart signal starts all Upstart jobs the - // container may depend on such as cras, EmitLoginPromptVisibleCalled() is the - // safe place to start the container for login screen. + // instance may depend on such as cras, EmitLoginPromptVisibleCalled() is the + // safe place to start a mini instance. DCHECK(!arc_session_); - RequestStart(ArcInstanceMode::MINI_INSTANCE); + if (IsArcAvailable()) + RequestStart(ArcInstanceMode::MINI_INSTANCE); } } // namespace arc diff --git a/chromium/components/arc/arc_session_runner.h b/chromium/components/arc/arc_session_runner.h index 97703bbaf8a..5db59916480 100644 --- a/chromium/components/arc/arc_session_runner.h +++ b/chromium/components/arc/arc_session_runner.h @@ -21,6 +21,25 @@ namespace arc { +// These enums are used to define the buckets for an enumerated UMA histogram +// and need to be synced with tools/metrics/histograms/enums.xml. This enum +// class should also be treated as append-only. +enum class ArcContainerLifetimeEvent { + // Note: "container" here means "instance". Outside Chromium, like UMA + // dashboard, we use the former term. + + // Chrome asked session_manager to start an ARC instance (of any kind). We + // record this as a baseline. + CONTAINER_STARTING = 0, + // The instance failed to start or exited unexpectedly. + CONTAINER_FAILED_TO_START = 1, + // The instance crashed before establishing an IPC connection to Chrome. + CONTAINER_CRASHED_EARLY = 2, + // The instance crashed after establishing the connection. + CONTAINER_CRASHED = 3, + COUNT +}; + // Accept requests to start/stop ARC instance. Also supports automatic // restarting on unexpected ARC instance crash. class ArcSessionRunner : public ArcSession::Observer, @@ -47,7 +66,8 @@ class ArcSessionRunner : public ArcSession::Observer, // This is the factory interface to inject ArcSession instance // for testing purpose. - using ArcSessionFactory = base::Callback()>; + using ArcSessionFactory = + base::RepeatingCallback()>; explicit ArcSessionRunner(const ArcSessionFactory& factory); ~ArcSessionRunner() override; @@ -102,6 +122,7 @@ class ArcSessionRunner : public ArcSession::Observer, // to finish tearing down in case it is still in the process of stopping. base::TimeDelta restart_delay_; base::OneShotTimer restart_timer_; + size_t restart_after_crash_count_; // for UMA recording. // Factory to inject a fake ArcSession instance for testing. ArcSessionFactory factory_; diff --git a/chromium/components/arc/arc_session_runner_unittest.cc b/chromium/components/arc/arc_session_runner_unittest.cc index 627c8cee9af..8a531e88dc3 100644 --- a/chromium/components/arc/arc_session_runner_unittest.cc +++ b/chromium/components/arc/arc_session_runner_unittest.cc @@ -8,13 +8,16 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/callback_helpers.h" +#include "base/command_line.h" #include "base/macros.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" +#include "base/test/histogram_tester.h" #include "base/test/scoped_task_environment.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/fake_session_manager_client.h" #include "components/arc/arc_session_runner.h" +#include "components/arc/arc_util.h" #include "components/arc/test/fake_arc_session.h" #include "mojo/public/cpp/system/message_pipe.h" #include "testing/gtest/include/gtest/gtest.h" @@ -23,6 +26,15 @@ namespace arc { namespace { +constexpr int kContainerStarting = + static_cast(ArcContainerLifetimeEvent::CONTAINER_STARTING); +constexpr int kContainerFailedToStart = + static_cast(ArcContainerLifetimeEvent::CONTAINER_FAILED_TO_START); +constexpr int kContainerCrashedEarly = + static_cast(ArcContainerLifetimeEvent::CONTAINER_CRASHED_EARLY); +constexpr int kContainerCrashed = + static_cast(ArcContainerLifetimeEvent::CONTAINER_CRASHED); + class DoNothingObserver : public ArcSessionRunner::Observer { public: void OnSessionStopped(ArcStopReason reason, bool restarting) override { @@ -160,7 +172,7 @@ TEST_F(ArcSessionRunnerTest, Basic) { arc_session_runner()->RequestStart(ArcInstanceMode::FULL_INSTANCE); ASSERT_TRUE(arc_session()); - EXPECT_TRUE(arc_session()->IsRunning()); + EXPECT_TRUE(arc_session()->is_running()); arc_session_runner()->RequestStop(); EXPECT_FALSE(arc_session()); @@ -176,7 +188,7 @@ TEST_F(ArcSessionRunnerTest, StopMidStartup) { arc_session_runner()->RequestStart(ArcInstanceMode::FULL_INSTANCE); ASSERT_TRUE(arc_session()); - EXPECT_FALSE(arc_session()->IsRunning()); + EXPECT_FALSE(arc_session()->is_running()); arc_session_runner()->RequestStop(); EXPECT_FALSE(arc_session()); @@ -191,7 +203,7 @@ TEST_F(ArcSessionRunnerTest, StopMidStartup_MiniInstance) { arc_session_runner()->RequestStart(ArcInstanceMode::MINI_INSTANCE); ASSERT_TRUE(arc_session()); - EXPECT_FALSE(arc_session()->IsRunning()); + EXPECT_FALSE(arc_session()->is_running()); arc_session_runner()->RequestStop(); EXPECT_FALSE(arc_session()); @@ -229,7 +241,7 @@ TEST_F(ArcSessionRunnerTest, BootFailure_MiniInstance) { ResetArcSessionFactory(base::Bind(FakeArcSession::Create)); arc_session_runner()->RequestStart(ArcInstanceMode::FULL_INSTANCE); ASSERT_TRUE(arc_session()); - EXPECT_TRUE(arc_session()->IsRunning()); + EXPECT_TRUE(arc_session()->is_running()); } // Similary, CRASH should do same for GENERIC_BOOT_FAILURE case, because @@ -254,11 +266,11 @@ TEST_F(ArcSessionRunnerTest, Upgrade) { arc_session_runner()->RequestStart(ArcInstanceMode::MINI_INSTANCE); ASSERT_TRUE(arc_session()); - EXPECT_FALSE(arc_session()->IsRunning()); + EXPECT_FALSE(arc_session()->is_running()); arc_session_runner()->RequestStart(ArcInstanceMode::FULL_INSTANCE); ASSERT_TRUE(arc_session()); - EXPECT_TRUE(arc_session()->IsRunning()); + EXPECT_TRUE(arc_session()->is_running()); } // We expect mini instance starts to run if EmitLoginPromptVisible signal is @@ -266,11 +278,24 @@ TEST_F(ArcSessionRunnerTest, Upgrade) { TEST_F(ArcSessionRunnerTest, EmitLoginPromptVisible) { EXPECT_FALSE(arc_session()); + SetArcAvailableCommandLineForTesting(base::CommandLine::ForCurrentProcess()); + chromeos::DBusThreadManager::Get() ->GetSessionManagerClient() ->EmitLoginPromptVisible(); ASSERT_TRUE(arc_session()); - EXPECT_FALSE(arc_session()->IsRunning()); + EXPECT_FALSE(arc_session()->is_running()); +} + +// We expect mini instance does not start on EmitLoginPromptVisible when ARC +// is not available. +TEST_F(ArcSessionRunnerTest, EmitLoginPromptVisible_NoOp) { + EXPECT_FALSE(arc_session()); + + chromeos::DBusThreadManager::Get() + ->GetSessionManagerClient() + ->EmitLoginPromptVisible(); + EXPECT_FALSE(arc_session()); } // If the instance is stopped, it should be re-started. @@ -280,7 +305,7 @@ TEST_F(ArcSessionRunnerTest, Restart) { arc_session_runner()->RequestStart(ArcInstanceMode::FULL_INSTANCE); ASSERT_TRUE(arc_session()); - EXPECT_TRUE(arc_session()->IsRunning()); + EXPECT_TRUE(arc_session()->is_running()); // Simulate a connection loss. ASSERT_TRUE(arc_session()); @@ -290,7 +315,7 @@ TEST_F(ArcSessionRunnerTest, Restart) { base::RunLoop().RunUntilIdle(); EXPECT_TRUE(restarting_called()); ASSERT_TRUE(arc_session()); - EXPECT_TRUE(arc_session()->IsRunning()); + EXPECT_TRUE(arc_session()->is_running()); arc_session_runner()->RequestStop(); EXPECT_FALSE(arc_session()); @@ -302,7 +327,7 @@ TEST_F(ArcSessionRunnerTest, GracefulStop) { arc_session_runner()->RequestStart(ArcInstanceMode::FULL_INSTANCE); ASSERT_TRUE(arc_session()); - EXPECT_TRUE(arc_session()->IsRunning()); + EXPECT_TRUE(arc_session()->is_running()); // Graceful stop. arc_session_runner()->RequestStop(); @@ -318,7 +343,7 @@ TEST_F(ArcSessionRunnerTest, Shutdown) { arc_session_runner()->RequestStart(ArcInstanceMode::FULL_INSTANCE); ASSERT_TRUE(arc_session()); - EXPECT_TRUE(arc_session()->IsRunning()); + EXPECT_TRUE(arc_session()->is_running()); // Simulate shutdown. arc_session_runner()->OnShutdown(); @@ -345,4 +370,121 @@ TEST_F(ArcSessionRunnerTest, RemoveUnknownObserver) { arc_session_runner()->RemoveObserver(&do_nothing_observer); } +// Tests UMA recording on mini instance -> full instance -> shutdown case. +TEST_F(ArcSessionRunnerTest, UmaRecording_StartUpgradeShutdown) { + base::HistogramTester tester; + + arc_session_runner()->RequestStart(ArcInstanceMode::MINI_INSTANCE); + tester.ExpectUniqueSample("Arc.ContainerLifetimeEvent", kContainerStarting, + 1 /* count of the sample */); + + // Boot continue should not increase the count. + arc_session_runner()->RequestStart(ArcInstanceMode::FULL_INSTANCE); + tester.ExpectUniqueSample("Arc.ContainerLifetimeEvent", kContainerStarting, + 1); + + // "0" should be recorded as a restart count on shutdown. + arc_session_runner()->OnShutdown(); + tester.ExpectUniqueSample("Arc.ContainerRestartAfterCrashCount", + 0 /* sample */, 1 /* count of the sample */); +} + +// Tests UMA recording on full instance -> shutdown case. +TEST_F(ArcSessionRunnerTest, UmaRecording_StartShutdown) { + base::HistogramTester tester; + + arc_session_runner()->RequestStart(ArcInstanceMode::FULL_INSTANCE); + tester.ExpectUniqueSample("Arc.ContainerLifetimeEvent", kContainerStarting, + 1); + // "0" should be recorded as a restart count on shutdown. + arc_session_runner()->OnShutdown(); + tester.ExpectUniqueSample("Arc.ContainerRestartAfterCrashCount", 0, 1); +} + +// Tests UMA recording on mini instance -> full instance -> crash -> shutdown +// case. +TEST_F(ArcSessionRunnerTest, UmaRecording_CrashTwice) { + base::HistogramTester tester; + + arc_session_runner()->SetRestartDelayForTesting(base::TimeDelta()); + EXPECT_FALSE(arc_session()); + + arc_session_runner()->RequestStart(ArcInstanceMode::MINI_INSTANCE); + tester.ExpectUniqueSample("Arc.ContainerLifetimeEvent", kContainerStarting, + 1); + arc_session_runner()->RequestStart(ArcInstanceMode::FULL_INSTANCE); + + // Stop the instance with CRASH. + arc_session()->StopWithReason(ArcStopReason::CRASH); + tester.ExpectBucketCount("Arc.ContainerLifetimeEvent", kContainerCrashed, 1); + tester.ExpectTotalCount("Arc.ContainerLifetimeEvent", 2); + + // Restart the instance, then crash the instance again. The second CRASH + // should not affect Arc.ContainerLifetimeEvent. + base::RunLoop().RunUntilIdle(); + arc_session()->StopWithReason(ArcStopReason::CRASH); + tester.ExpectBucketCount("Arc.ContainerLifetimeEvent", kContainerCrashed, 1); + tester.ExpectTotalCount("Arc.ContainerLifetimeEvent", 2); + + // However, "2" should be recorded as a restart count on shutdown. + base::RunLoop().RunUntilIdle(); + arc_session_runner()->OnShutdown(); + tester.ExpectUniqueSample("Arc.ContainerRestartAfterCrashCount", 2, 1); +} + +// Tests UMA recording on mini instance -> crash -> shutdown case. +TEST_F(ArcSessionRunnerTest, UmaRecording_CrashMini) { + base::HistogramTester tester; + + arc_session_runner()->RequestStart(ArcInstanceMode::MINI_INSTANCE); + tester.ExpectUniqueSample("Arc.ContainerLifetimeEvent", kContainerStarting, + 1); + + // Stop the instance with CRASH. + arc_session()->StopWithReason(ArcStopReason::CRASH); + tester.ExpectBucketCount("Arc.ContainerLifetimeEvent", kContainerCrashedEarly, + 1); + tester.ExpectTotalCount("Arc.ContainerLifetimeEvent", 2); + + // In this case, no restart happened. "0" should be recorded. + arc_session_runner()->OnShutdown(); + tester.ExpectUniqueSample("Arc.ContainerRestartAfterCrashCount", 0, 1); +} + +// Tests UMA recording on mini instance -> boot fail -> shutdown case. +TEST_F(ArcSessionRunnerTest, UmaRecording_BootFail) { + base::HistogramTester tester; + + arc_session_runner()->RequestStart(ArcInstanceMode::MINI_INSTANCE); + tester.ExpectUniqueSample("Arc.ContainerLifetimeEvent", kContainerStarting, + 1); + + arc_session()->StopWithReason(ArcStopReason::GENERIC_BOOT_FAILURE); + tester.ExpectBucketCount("Arc.ContainerLifetimeEvent", + kContainerFailedToStart, 1); + tester.ExpectTotalCount("Arc.ContainerLifetimeEvent", 2); + + // No restart happened. "0" should be recorded. + arc_session_runner()->OnShutdown(); + tester.ExpectUniqueSample("Arc.ContainerRestartAfterCrashCount", 0, 1); +} + +// Tests UMA recording on full instance -> low disk -> shutdown case. +TEST_F(ArcSessionRunnerTest, UmaRecording_LowDisk) { + base::HistogramTester tester; + + arc_session_runner()->RequestStart(ArcInstanceMode::FULL_INSTANCE); + tester.ExpectUniqueSample("Arc.ContainerLifetimeEvent", kContainerStarting, + 1); + + // We don't record UMA for LOW_DISK_SPACE. + arc_session()->StopWithReason(ArcStopReason::LOW_DISK_SPACE); + tester.ExpectUniqueSample("Arc.ContainerLifetimeEvent", kContainerStarting, + 1); + + // No restart happened. "0" should be recorded. + arc_session_runner()->OnShutdown(); + tester.ExpectUniqueSample("Arc.ContainerRestartAfterCrashCount", 0, 1); +} + } // namespace arc diff --git a/chromium/components/arc/arc_stop_reason.h b/chromium/components/arc/arc_stop_reason.h index df104439e7a..bdf08e1fa80 100644 --- a/chromium/components/arc/arc_stop_reason.h +++ b/chromium/components/arc/arc_stop_reason.h @@ -15,8 +15,9 @@ enum class ArcStopReason { SHUTDOWN, // Errors occurred during the ARC instance boot. This includes any failures - // before the instance is actually attempted to be started, and also - // failures on bootstrapping IPC channels with Android. + // before the instance is actually attempted to be started (e.g. + // session_manager failed to fork/exec the instance), and also a "clean" + // (non crashy) but unexpected container shutdown. GENERIC_BOOT_FAILURE, // The device is critically low on disk space. diff --git a/chromium/components/arc/arc_util.cc b/chromium/components/arc/arc_util.cc index 83436fe2d1e..f0033f4751b 100644 --- a/chromium/components/arc/arc_util.cc +++ b/chromium/components/arc/arc_util.cc @@ -172,6 +172,11 @@ bool IsArcAllowedForUser(const user_manager::User* user) { return false; } + if (user->GetType() == user_manager::USER_TYPE_CHILD) { + VLOG(1) << "ARC usage by Child users is prohibited"; + return false; + } + return true; } diff --git a/chromium/components/arc/arc_util_unittest.cc b/chromium/components/arc/arc_util_unittest.cc index 51b8a41b6da..bc476adefa3 100644 --- a/chromium/components/arc/arc_util_unittest.cc +++ b/chromium/components/arc/arc_util_unittest.cc @@ -14,6 +14,7 @@ #include "base/test/scoped_feature_list.h" #include "components/signin/core/account_id/account_id.h" #include "components/user_manager/fake_user_manager.h" +#include "components/user_manager/scoped_user_manager.h" #include "components/user_manager/user.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/aura/client/aura_constants.h" @@ -42,32 +43,11 @@ class ScopedArcFeature { DISALLOW_COPY_AND_ASSIGN(ScopedArcFeature); }; -// Helper to enable user_manager::FakeUserManager while it is in scope. -// TODO(xiyuan): Remove after ScopedUserManagerEnabler is moved to user_manager. -class ScopedUserManager { - public: - explicit ScopedUserManager(user_manager::UserManager* user_manager) - : user_manager_(user_manager) { - DCHECK(!user_manager::UserManager::IsInitialized()); - user_manager->Initialize(); - } - ~ScopedUserManager() { - DCHECK_EQ(user_manager::UserManager::Get(), user_manager_); - user_manager_->Shutdown(); - user_manager_->Destroy(); - } - - private: - user_manager::UserManager* const user_manager_; - - DISALLOW_COPY_AND_ASSIGN(ScopedUserManager); -}; - // Fake user that can be created with a specified type. class FakeUser : public user_manager::User { public: explicit FakeUser(user_manager::UserType user_type) - : User(AccountId::FromUserEmail("user@test.com")), + : User(AccountId::FromUserEmailGaiaId("user@test.com", "1234567890")), user_type_(user_type) {} ~FakeUser() override = default; @@ -203,8 +183,10 @@ TEST_F(ArcUtilTest, IsArcAppWindow) { } TEST_F(ArcUtilTest, IsArcAllowedForUser) { - user_manager::FakeUserManager fake_user_manager; - ScopedUserManager scoped_user_manager(&fake_user_manager); + user_manager::FakeUserManager* fake_user_manager = + new user_manager::FakeUserManager(); + user_manager::ScopedUserManager scoped_user_manager( + base::WrapUnique(fake_user_manager)); struct { user_manager::UserType user_type; @@ -215,7 +197,7 @@ TEST_F(ArcUtilTest, IsArcAllowedForUser) { {user_manager::USER_TYPE_PUBLIC_ACCOUNT, false}, {user_manager::USER_TYPE_SUPERVISED, false}, {user_manager::USER_TYPE_KIOSK_APP, false}, - {user_manager::USER_TYPE_CHILD, true}, + {user_manager::USER_TYPE_CHILD, false}, {user_manager::USER_TYPE_ARC_KIOSK_APP, true}, {user_manager::USER_TYPE_ACTIVE_DIRECTORY, true}, }; @@ -227,12 +209,13 @@ TEST_F(ArcUtilTest, IsArcAllowedForUser) { // An ephemeral user is a logged in user but unknown to UserManager when // ephemeral policy is set. - fake_user_manager.SetEphemeralUsersEnabled(true); - fake_user_manager.UserLoggedIn(AccountId::FromUserEmail("test@test.com"), - "test@test.com-hash", false); - const user_manager::User* ephemeral_user = fake_user_manager.GetActiveUser(); + fake_user_manager->SetEphemeralUsersEnabled(true); + fake_user_manager->UserLoggedIn( + AccountId::FromUserEmailGaiaId("test@test.com", "9876543210"), + "test@test.com-hash", false /* browser_restart */, false /* is_child */); + const user_manager::User* ephemeral_user = fake_user_manager->GetActiveUser(); ASSERT_TRUE(ephemeral_user); - ASSERT_TRUE(fake_user_manager.IsUserCryptohomeDataEphemeral( + ASSERT_TRUE(fake_user_manager->IsUserCryptohomeDataEphemeral( ephemeral_user->GetAccountId())); // Ephemeral user is not allowed for ARC. diff --git a/chromium/components/arc/audio/arc_audio_bridge.cc b/chromium/components/arc/audio/arc_audio_bridge.cc index 880acb390ae..72a8106d695 100644 --- a/chromium/components/arc/audio/arc_audio_bridge.cc +++ b/chromium/components/arc/audio/arc_audio_bridge.cc @@ -45,7 +45,8 @@ ArcAudioBridge* ArcAudioBridge::GetForBrowserContext( ArcAudioBridge::ArcAudioBridge(content::BrowserContext* context, ArcBridgeService* bridge_service) - : arc_bridge_service_(bridge_service), binding_(this) { + : arc_bridge_service_(bridge_service) { + arc_bridge_service_->audio()->SetHost(this); arc_bridge_service_->audio()->AddObserver(this); if (chromeos::CrasAudioHandler::IsInitialized()) { cras_audio_handler_ = chromeos::CrasAudioHandler::Get(); @@ -57,19 +58,15 @@ ArcAudioBridge::~ArcAudioBridge() { if (cras_audio_handler_) cras_audio_handler_->RemoveAudioObserver(this); arc_bridge_service_->audio()->RemoveObserver(this); + arc_bridge_service_->audio()->SetHost(nullptr); } -void ArcAudioBridge::OnInstanceReady() { - mojom::AudioInstance* audio_instance = - ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->audio(), Init); - DCHECK(audio_instance); // the instance on ARC side is too old. - mojom::AudioHostPtr host_proxy; - binding_.Bind(mojo::MakeRequest(&host_proxy)); - audio_instance->Init(std::move(host_proxy)); +void ArcAudioBridge::OnConnectionReady() { + // TODO(hidehiko): Replace with ConnectionHolder::IsConnected(). available_ = true; } -void ArcAudioBridge::OnInstanceClosed() { +void ArcAudioBridge::OnConnectionClosed() { available_ = false; } diff --git a/chromium/components/arc/audio/arc_audio_bridge.h b/chromium/components/arc/audio/arc_audio_bridge.h index 7938f6f57e0..ab068f6c29b 100644 --- a/chromium/components/arc/audio/arc_audio_bridge.h +++ b/chromium/components/arc/audio/arc_audio_bridge.h @@ -10,9 +10,8 @@ #include "base/macros.h" #include "chromeos/audio/cras_audio_handler.h" #include "components/arc/common/audio.mojom.h" -#include "components/arc/instance_holder.h" +#include "components/arc/connection_observer.h" #include "components/keyed_service/core/keyed_service.h" -#include "mojo/public/cpp/bindings/binding.h" namespace content { class BrowserContext; @@ -23,7 +22,7 @@ namespace arc { class ArcBridgeService; class ArcAudioBridge : public KeyedService, - public InstanceHolder::Observer, + public ConnectionObserver, public mojom::AudioHost, public chromeos::CrasAudioHandler::AudioObserver { public: @@ -35,9 +34,9 @@ class ArcAudioBridge : public KeyedService, ArcBridgeService* bridge_service); ~ArcAudioBridge() override; - // InstanceHolder::Observer overrides. - void OnInstanceReady() override; - void OnInstanceClosed() override; + // ConnectionObserver overrides. + void OnConnectionReady() override; + void OnConnectionClosed() override; // mojom::AudioHost overrides. void ShowVolumeControls() override; @@ -54,8 +53,6 @@ class ArcAudioBridge : public KeyedService, ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager. - mojo::Binding binding_; - chromeos::CrasAudioHandler* cras_audio_handler_ = nullptr; int volume_ = 0; // Volume range: 0-100. diff --git a/chromium/components/arc/bluetooth/bluetooth_type_converters_unittest.cc b/chromium/components/arc/bluetooth/bluetooth_type_converters_unittest.cc index 9ed5d7e531a..213c8f0efdf 100644 --- a/chromium/components/arc/bluetooth/bluetooth_type_converters_unittest.cc +++ b/chromium/components/arc/bluetooth/bluetooth_type_converters_unittest.cc @@ -58,15 +58,15 @@ size_t GetDepthOfMojoAttribute( bluez::BluetoothServiceAttributeValueBlueZ CreateDeepBlueZSequenceAttribute( size_t depth) { if (depth > 0u) { - std::unique_ptr - sequence(new bluez::BluetoothServiceAttributeValueBlueZ::Sequence()); + auto sequence = std::make_unique< + bluez::BluetoothServiceAttributeValueBlueZ::Sequence>(); sequence->push_back(CreateDeepBlueZSequenceAttribute(depth - 1)); return bluez::BluetoothServiceAttributeValueBlueZ(std::move(sequence)); } else { return bluez::BluetoothServiceAttributeValueBlueZ( bluez::BluetoothServiceAttributeValueBlueZ::UINT, sizeof(uint16_t), - base::WrapUnique(new base::Value(3))); + std::make_unique(3)); } } @@ -81,420 +81,392 @@ size_t GetDepthOfBlueZAttribute( return depth; } +std::string ValueToJson(const base::Value& value) { + std::string json; + base::JSONWriter::Write(value, &json); + return json; +} + } // namespace namespace mojo { -TEST(BluetoothTypeConvertorTest, ConvertMojoBluetoothAddressFromString) { - arc::mojom::BluetoothAddressPtr addressMojo = +TEST(BluetoothTypeConverterTest, ConvertMojoBluetoothAddressFromString) { + arc::mojom::BluetoothAddressPtr address_mojo = arc::mojom::BluetoothAddress::From(std::string(kAddressStr)); - EXPECT_EQ(kAddressSize, addressMojo->address.size()); - for (size_t i = 0; i < kAddressSize; i++) { - EXPECT_EQ(kAddressArray[i], addressMojo->address[i]); - } + EXPECT_EQ(kAddressSize, address_mojo->address.size()); + for (size_t i = 0; i < kAddressSize; i++) + EXPECT_EQ(kAddressArray[i], address_mojo->address[i]); } -TEST(BluetoothTypeConvertorTest, ConvertMojoBluetoothAddressToString) { - arc::mojom::BluetoothAddressPtr addressMojo = +TEST(BluetoothTypeConverterTest, ConvertMojoBluetoothAddressToString) { + arc::mojom::BluetoothAddressPtr address_mojo = arc::mojom::BluetoothAddress::New(); - for (size_t i = 0; i < kAddressSize - 1; i++) { - addressMojo->address.push_back(kAddressArray[i]); - } - EXPECT_EQ(std::string(kInvalidAddressStr), addressMojo->To()); + // Test address is shorter than expected (invalid address). + for (size_t i = 0; i < kAddressSize - 1; i++) + address_mojo->address.push_back(kAddressArray[i]); + EXPECT_EQ(kInvalidAddressStr, address_mojo->To()); + + // Test success case. + address_mojo->address.push_back(kAddressArray[kAddressSize - 1]); + EXPECT_EQ(kAddressStr, address_mojo->To()); + + // Test address is longer than expected (invalid address). + address_mojo->address.push_back(kFillerByte); + EXPECT_EQ(kInvalidAddressStr, address_mojo->To()); +} + +TEST(BluetoothTypeConverterTest, + ConvertMojoValueAttributeToBlueZAttribute_NullType) { + auto mojo = arc::mojom::BluetoothSdpAttribute::New(); + mojo->type = bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE; + mojo->type_size = 0; + + auto blue_z = mojo.To(); - addressMojo->address.push_back(kAddressArray[kAddressSize - 1]); - EXPECT_EQ(std::string(kAddressStr), addressMojo->To()); + EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE, + blue_z.type()); + EXPECT_EQ(0u, blue_z.size()); + EXPECT_EQ(base::Value::Type::NONE, blue_z.value().type()); +} - addressMojo->address.push_back(kFillerByte); +TEST(BluetoothTypeConverterTest, + ConvertMojoValueAttributeToBlueZAttribute_BoolType) { + auto mojo = arc::mojom::BluetoothSdpAttribute::New(); + mojo->type = bluez::BluetoothServiceAttributeValueBlueZ::BOOL; + mojo->type_size = static_cast(sizeof(bool)); + mojo->json_value = ValueToJson(base::Value(true)); - EXPECT_EQ(std::string(kInvalidAddressStr), addressMojo->To()); + auto blue_z = mojo.To(); + + EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::BOOL, blue_z.type()); + EXPECT_EQ(sizeof(bool), blue_z.size()); + ASSERT_EQ(base::Value::Type::BOOLEAN, blue_z.value().type()); + EXPECT_TRUE(blue_z.value().GetBool()); } +TEST(BluetoothTypeConverterTest, + ConvertMojoValueAttributeToBlueZAttribute_UintType) { + constexpr uint16_t kValue = 10; + auto mojo = arc::mojom::BluetoothSdpAttribute::New(); + mojo->type = bluez::BluetoothServiceAttributeValueBlueZ::UINT; + mojo->type_size = static_cast(sizeof(kValue)); + mojo->json_value = ValueToJson(base::Value(static_cast(kValue))); + + auto blue_z = mojo.To(); -TEST(BluetoothTypeConvertorTest, ConvertMojoValueAttributeToBlueZAttribute) { - // Construct Mojo attribute with NULLTYPE value. - auto nulltypeAttributeMojo = arc::mojom::BluetoothSdpAttribute::New(); - nulltypeAttributeMojo->type = - bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE; - nulltypeAttributeMojo->type_size = 0; + EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::UINT, blue_z.type()); + EXPECT_EQ(sizeof(kValue), blue_z.size()); + ASSERT_EQ(base::Value::Type::INTEGER, blue_z.value().type()); + EXPECT_EQ(kValue, static_cast(blue_z.value().GetInt())); +} - auto nulltypeAttributeBlueZ = - nulltypeAttributeMojo.To(); +TEST(BluetoothTypeConverterTest, + ConvertMojoValueAttributeToBlueZAttribute_IntType) { + constexpr int16_t kValue = 20; + auto mojo = arc::mojom::BluetoothSdpAttribute::New(); + mojo->type = bluez::BluetoothServiceAttributeValueBlueZ::INT; + mojo->type_size = static_cast(sizeof(kValue)); + mojo->json_value = ValueToJson(base::Value(static_cast(kValue))); - EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE, - nulltypeAttributeBlueZ.type()); - EXPECT_EQ(0u, nulltypeAttributeBlueZ.size()); - EXPECT_EQ(base::Value::Type::NONE, nulltypeAttributeBlueZ.value().GetType()); - - // Construct Mojo attribute with TYPE_BOOLEAN value. - bool valueBool = true; - auto boolAttributeMojo = arc::mojom::BluetoothSdpAttribute::New(); - boolAttributeMojo->type = bluez::BluetoothServiceAttributeValueBlueZ::BOOL; - boolAttributeMojo->type_size = static_cast(sizeof(valueBool)); - std::string json; - base::JSONWriter::Write(base::Value(valueBool), &json); - boolAttributeMojo->json_value = std::move(json); - auto boolAttributeBlueZ = - boolAttributeMojo.To(); - - EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::BOOL, - boolAttributeBlueZ.type()); - EXPECT_EQ(sizeof(valueBool), boolAttributeBlueZ.size()); - EXPECT_EQ(base::Value::Type::BOOLEAN, boolAttributeBlueZ.value().GetType()); - EXPECT_TRUE(boolAttributeBlueZ.value().GetAsBoolean(&valueBool)); - EXPECT_TRUE(valueBool); - - // Construct Mojo attribute with TYPE_UINT value. - uint16_t valueUint16 = 10; - int valueUint16AsInt = 0; - auto uintAttributeMojo = arc::mojom::BluetoothSdpAttribute::New(); - uintAttributeMojo->type = bluez::BluetoothServiceAttributeValueBlueZ::UINT; - uintAttributeMojo->type_size = static_cast(sizeof(valueUint16)); - json.clear(); - base::JSONWriter::Write(base::Value(static_cast(valueUint16)), &json); - uintAttributeMojo->json_value = std::move(json); - - auto uintAttributeBlueZ = - uintAttributeMojo.To(); - - EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::UINT, - uintAttributeBlueZ.type()); - EXPECT_EQ(sizeof(valueUint16), uintAttributeBlueZ.size()); - EXPECT_EQ(base::Value::Type::INTEGER, uintAttributeBlueZ.value().GetType()); - EXPECT_TRUE(uintAttributeBlueZ.value().GetAsInteger(&valueUint16AsInt)); - EXPECT_EQ(valueUint16, static_cast(valueUint16AsInt)); - - // Construct Mojo attribute with TYPE_INT value. - int16_t valueInt16 = 20; - int valueInt16AsInt = 0; - auto intAttributeMojo = arc::mojom::BluetoothSdpAttribute::New(); - intAttributeMojo->type = bluez::BluetoothServiceAttributeValueBlueZ::INT; - intAttributeMojo->type_size = static_cast(sizeof(valueInt16)); - json.clear(); - base::JSONWriter::Write(base::Value(static_cast(valueInt16)), &json); - intAttributeMojo->json_value = std::move(json); - - auto intAttributeBlueZ = - intAttributeMojo.To(); - - EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::INT, - intAttributeBlueZ.type()); - EXPECT_EQ(sizeof(valueInt16), intAttributeBlueZ.size()); - EXPECT_EQ(base::Value::Type::INTEGER, intAttributeBlueZ.value().GetType()); - EXPECT_TRUE(intAttributeBlueZ.value().GetAsInteger(&valueInt16AsInt)); - EXPECT_EQ(valueInt16, static_cast(valueInt16AsInt)); + auto blue_z = mojo.To(); + EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::INT, blue_z.type()); + EXPECT_EQ(sizeof(kValue), blue_z.size()); + ASSERT_EQ(base::Value::Type::INTEGER, blue_z.value().type()); + EXPECT_EQ(kValue, static_cast(blue_z.value().GetInt())); +} + +TEST(BluetoothTypeConverterTest, + ConvertMojoValueAttributeToBlueZAttribute_UuidType) { // Construct Mojo attribute with TYPE_UUID. - std::string expectedUUID("00000000-0000-1000-8000-00805f9b34fb"); - std::string actualUUID; - auto uuidAttributeMojo = arc::mojom::BluetoothSdpAttribute::New(); - uuidAttributeMojo->type = bluez::BluetoothServiceAttributeValueBlueZ::UUID; + constexpr char kValue[] = "00000000-0000-1000-8000-00805f9b34fb"; + auto mojo = arc::mojom::BluetoothSdpAttribute::New(); + mojo->type = bluez::BluetoothServiceAttributeValueBlueZ::UUID; // UUIDs are all stored in string form, but it can be converted to one of // UUID16, UUID32 and UUID128. - uuidAttributeMojo->type_size = static_cast(sizeof(uint16_t)); - json.clear(); - base::JSONWriter::Write(base::Value(expectedUUID), &json); - uuidAttributeMojo->json_value = std::move(json); + mojo->type_size = static_cast(sizeof(uint16_t)); + mojo->json_value = ValueToJson(base::Value(kValue)); - auto uuidAttributeBlueZ = - uuidAttributeMojo.To(); + auto blue_z = mojo.To(); - EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::UUID, - uuidAttributeBlueZ.type()); - EXPECT_EQ(sizeof(uint16_t), uuidAttributeBlueZ.size()); - EXPECT_EQ(base::Value::Type::STRING, uuidAttributeBlueZ.value().GetType()); - EXPECT_TRUE(uuidAttributeBlueZ.value().GetAsString(&actualUUID)); - EXPECT_EQ(expectedUUID, actualUUID); + EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::UUID, blue_z.type()); + EXPECT_EQ(sizeof(uint16_t), blue_z.size()); + ASSERT_EQ(base::Value::Type::STRING, blue_z.value().type()); + EXPECT_EQ(kValue, blue_z.value().GetString()); +} +TEST(BluetoothTypeConverterTest, + ConvertMojoValueAttributeToBlueZAttribute_StringType) { // Construct Mojo attribute with TYPE_STRING. TYPE_URL is the same case as // TYPE_STRING. - std::string expectedString("Some SDP service"); - std::string actualString; - auto stringAttributeMojo = arc::mojom::BluetoothSdpAttribute::New(); - stringAttributeMojo->type = - bluez::BluetoothServiceAttributeValueBlueZ::STRING; - stringAttributeMojo->type_size = - static_cast(expectedString.length()); - json.clear(); - base::JSONWriter::Write(base::Value(expectedString), &json); - stringAttributeMojo->json_value = std::move(json); - - auto stringAttributeBlueZ = - stringAttributeMojo.To(); - - EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::STRING, - stringAttributeBlueZ.type()); - EXPECT_EQ(expectedString.length(), stringAttributeBlueZ.size()); - EXPECT_EQ(base::Value::Type::STRING, stringAttributeBlueZ.value().GetType()); - EXPECT_TRUE(stringAttributeBlueZ.value().GetAsString(&actualString)); - EXPECT_EQ(expectedString, actualString); + constexpr char kValue[] = "Some SDP service"; + constexpr size_t kValueSize = sizeof(kValue) - 1; // Subtract '\0' size. + auto mojo = arc::mojom::BluetoothSdpAttribute::New(); + mojo->type = bluez::BluetoothServiceAttributeValueBlueZ::STRING; + // Subtract '\0'-terminate size. + mojo->type_size = static_cast(kValueSize); + mojo->json_value = ValueToJson(base::Value(kValue)); + + auto blue_z = mojo.To(); + + EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::STRING, blue_z.type()); + EXPECT_EQ(kValueSize, blue_z.size()); + ASSERT_EQ(base::Value::Type::STRING, blue_z.value().type()); + EXPECT_EQ(kValue, blue_z.value().GetString()); } -TEST(BluetoothTypeConvertorTest, ConvertMojoSequenceAttributeToBlueZAttribute) { - // Create an UUID value. - std::string l2capUUID("00000100-0000-1000-8000-00805f9b34fb"); - auto valueUUID = arc::mojom::BluetoothSdpAttribute::New(); - valueUUID->type = bluez::BluetoothServiceAttributeValueBlueZ::UUID; - valueUUID->type_size = static_cast(sizeof(uint16_t)); - std::string json; - base::JSONWriter::Write(base::Value(l2capUUID), &json); - valueUUID->json_value = std::move(json); - - // Create an UINT value. - uint16_t l2capChannel = 3; - auto valueUint16 = arc::mojom::BluetoothSdpAttribute::New(); - valueUint16->type = bluez::BluetoothServiceAttributeValueBlueZ::UINT; - valueUint16->type_size = static_cast(sizeof(l2capChannel)); - json.clear(); - base::JSONWriter::Write(base::Value(static_cast(l2capChannel)), &json); - valueUint16->json_value = std::move(json); +TEST(BluetoothTypeConverterTest, ConvertMojoSequenceAttributeToBlueZAttribute) { + constexpr char kL2capUuid[] = "00000100-0000-1000-8000-00805f9b34fb"; + constexpr uint16_t kL2capChannel = 3; // Create a sequence with the above two values. - auto sequenceMojo = arc::mojom::BluetoothSdpAttribute::New(); - sequenceMojo->type = bluez::BluetoothServiceAttributeValueBlueZ::SEQUENCE; - sequenceMojo->sequence.push_back(std::move(valueUUID)); - sequenceMojo->sequence.push_back(std::move(valueUint16)); - sequenceMojo->type_size = sequenceMojo->sequence.size(); - sequenceMojo->json_value = base::nullopt; + auto sequence_mojo = arc::mojom::BluetoothSdpAttribute::New(); + sequence_mojo->type = bluez::BluetoothServiceAttributeValueBlueZ::SEQUENCE; + { + // Create an UUID value. + auto value_uuid = arc::mojom::BluetoothSdpAttribute::New(); + value_uuid->type = bluez::BluetoothServiceAttributeValueBlueZ::UUID; + value_uuid->type_size = static_cast(sizeof(uint16_t)); + value_uuid->json_value = ValueToJson(base::Value(kL2capUuid)); + sequence_mojo->sequence.push_back(std::move(value_uuid)); + } + { + // Create an UINT value. + auto value_channel = arc::mojom::BluetoothSdpAttribute::New(); + value_channel->type = bluez::BluetoothServiceAttributeValueBlueZ::UINT; + value_channel->type_size = static_cast(sizeof(kL2capChannel)); + value_channel->json_value = + ValueToJson(base::Value(static_cast(kL2capChannel))); + sequence_mojo->sequence.push_back(std::move(value_channel)); + } + sequence_mojo->type_size = sequence_mojo->sequence.size(); + sequence_mojo->json_value = base::nullopt; - auto sequenceBlueZ = - sequenceMojo.To(); + auto sequence_blue_z = + sequence_mojo.To(); EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::SEQUENCE, - sequenceBlueZ.type()); - EXPECT_EQ(sequenceMojo->sequence.size(), sequenceBlueZ.sequence().size()); - - const auto& sequence = sequenceBlueZ.sequence(); - std::string uuid; - EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::UUID, - sequence.at(0).type()); - EXPECT_EQ(sizeof(uint16_t), sequence.at(0).size()); - EXPECT_TRUE(sequence.at(0).value().GetAsString(&uuid)); - EXPECT_EQ(l2capUUID, uuid); - - int channel; - EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::UINT, - sequence.at(1).type()); - EXPECT_EQ(sizeof(l2capChannel), sequence.at(1).size()); - EXPECT_TRUE(sequence.at(1).value().GetAsInteger(&channel)); - EXPECT_EQ(l2capChannel, static_cast(channel)); + sequence_blue_z.type()); + EXPECT_EQ(sequence_mojo->sequence.size(), sequence_blue_z.sequence().size()); + + const auto& sequence = sequence_blue_z.sequence(); + ASSERT_EQ(2u, sequence.size()); + { + const auto& blue_z = sequence[0]; + EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::UUID, blue_z.type()); + EXPECT_EQ(sizeof(uint16_t), blue_z.size()); + ASSERT_EQ(base::Value::Type::STRING, blue_z.value().type()); + EXPECT_EQ(kL2capUuid, blue_z.value().GetString()); + } + + { + const auto& blue_z = sequence[1]; + EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::UINT, blue_z.type()); + EXPECT_EQ(sizeof(kL2capChannel), blue_z.size()); + ASSERT_EQ(base::Value::Type::INTEGER, blue_z.value().type()); + EXPECT_EQ(kL2capChannel, static_cast(blue_z.value().GetInt())); + } } -TEST(BluetoothTypeConvertorTest, +TEST(BluetoothTypeConverterTest, ConvertInvalidMojoValueAttributeToBlueZAttribute) { // Create a Mojo attribute without value defined. - auto valueNoData = arc::mojom::BluetoothSdpAttribute::New(); - valueNoData->type = bluez::BluetoothServiceAttributeValueBlueZ::UINT; - valueNoData->type_size = static_cast(sizeof(uint32_t)); - valueNoData->json_value = base::nullopt; + auto mojo = arc::mojom::BluetoothSdpAttribute::New(); + mojo->type = bluez::BluetoothServiceAttributeValueBlueZ::UINT; + mojo->type_size = static_cast(sizeof(uint32_t)); + mojo->json_value = base::nullopt; - auto valueNoDataBlueZ = - valueNoData.To(); + auto blue_z = mojo.To(); EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE, - valueNoDataBlueZ.type()); - EXPECT_EQ(0u, valueNoDataBlueZ.size()); - EXPECT_EQ(base::Value::Type::NONE, valueNoDataBlueZ.value().GetType()); + blue_z.type()); + EXPECT_EQ(0u, blue_z.size()); + EXPECT_EQ(base::Value::Type::NONE, blue_z.value().type()); } -TEST(BluetoothTypeConvertorTest, - ConvertInvalidMojoSequenceAttributeToBlueZAttribute) { +TEST(BluetoothTypeConverterTest, + ConvertInvalidMojoSequenceAttributeToBlueZAttribute_NoData) { // Create a Mojo attribute with an empty sequence. - auto sequenceNoData = arc::mojom::BluetoothSdpAttribute::New(); - sequenceNoData->type = bluez::BluetoothServiceAttributeValueBlueZ::SEQUENCE; - sequenceNoData->type_size = 0; - sequenceNoData->json_value = base::nullopt; + auto mojo = arc::mojom::BluetoothSdpAttribute::New(); + mojo->type = bluez::BluetoothServiceAttributeValueBlueZ::SEQUENCE; + mojo->type_size = 0; + mojo->json_value = base::nullopt; - auto sequenceNoDataBlueZ = - sequenceNoData.To(); + auto blue_z = mojo.To(); EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE, - sequenceNoDataBlueZ.type()); - EXPECT_EQ(0u, sequenceNoDataBlueZ.size()); - EXPECT_EQ(base::Value::Type::NONE, sequenceNoDataBlueZ.value().GetType()); + blue_z.type()); + EXPECT_EQ(0u, blue_z.size()); + EXPECT_EQ(base::Value::Type::NONE, blue_z.value().type()); +} +TEST(BluetoothTypeConverterTest, + ConvertInvalidMojoSequenceAttributeToBlueZAttribute_TooDeep) { // Create a Mojo attribute with the depth = arc::kBluetoothSDPMaxDepth + 3. - auto sequenceTooDeepMojo = - CreateDeepMojoSequenceAttribute(arc::kBluetoothSDPMaxDepth + 3); - auto sequenceTooDeepBlueZ = - sequenceTooDeepMojo.To(); + auto mojo = CreateDeepMojoSequenceAttribute(arc::kBluetoothSDPMaxDepth + 3); + + auto blue_z = mojo.To(); EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::SEQUENCE, - sequenceTooDeepBlueZ.type()); - EXPECT_EQ(1u, sequenceTooDeepBlueZ.size()); - EXPECT_EQ(arc::kBluetoothSDPMaxDepth, - GetDepthOfBlueZAttribute(sequenceTooDeepBlueZ)); + blue_z.type()); + EXPECT_EQ(1u, blue_z.size()); + EXPECT_EQ(arc::kBluetoothSDPMaxDepth, GetDepthOfBlueZAttribute(blue_z)); } -TEST(BluetoothTypeConvertorTest, ConvertBlueZValueAttributeToMojoAttribute) { +TEST(BluetoothTypeConverterTest, + ConvertBlueZValueAttributeToMojoAttribute_NullType) { // Check NULL type. - auto nulltypeAttributeBlueZ = bluez::BluetoothServiceAttributeValueBlueZ(); + auto blue_z = bluez::BluetoothServiceAttributeValueBlueZ(); - auto nulltypeAttributeMojo = - ConvertTo(nulltypeAttributeBlueZ); + auto mojo = ConvertTo(blue_z); - EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE, - nulltypeAttributeMojo->type); - EXPECT_EQ(0u, nulltypeAttributeMojo->type_size); - { - ASSERT_TRUE(nulltypeAttributeMojo->json_value.has_value()); - auto value = - base::JSONReader::Read(nulltypeAttributeMojo->json_value.value()); - ASSERT_TRUE(value); - EXPECT_TRUE(value->is_none()); - } + EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::NULLTYPE, mojo->type); + EXPECT_EQ(0u, mojo->type_size); + ASSERT_TRUE(mojo->json_value.has_value()); + auto value = base::JSONReader::Read(mojo->json_value.value()); + ASSERT_TRUE(value); + EXPECT_TRUE(value->is_none()); +} + +TEST(BluetoothTypeConverterTest, + ConvertBlueZValueAttributeToMojoAttribute_UintType) { // Check integer types (INT, UINT). - uint16_t valueUint16 = 10; - auto uintAttributeBlueZ = bluez::BluetoothServiceAttributeValueBlueZ( - bluez::BluetoothServiceAttributeValueBlueZ::UINT, sizeof(valueUint16), - std::make_unique(static_cast(valueUint16))); + constexpr uint16_t kValue = 10; + auto blue_z = bluez::BluetoothServiceAttributeValueBlueZ( + bluez::BluetoothServiceAttributeValueBlueZ::UINT, sizeof(kValue), + std::make_unique(static_cast(kValue))); - auto uintAttributeMojo = - ConvertTo(uintAttributeBlueZ); + auto mojo = ConvertTo(blue_z); - EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::UINT, - uintAttributeMojo->type); - EXPECT_EQ(sizeof(valueUint16), uintAttributeMojo->type_size); - { - ASSERT_TRUE(uintAttributeMojo->json_value.has_value()); - auto value = base::JSONReader::Read(uintAttributeMojo->json_value.value()); - ASSERT_TRUE(value); - ASSERT_TRUE(value->is_int()); - EXPECT_EQ(valueUint16, static_cast(value->GetInt())); - } + EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::UINT, mojo->type); + EXPECT_EQ(sizeof(kValue), mojo->type_size); + + ASSERT_TRUE(mojo->json_value.has_value()); + auto value = base::JSONReader::Read(mojo->json_value.value()); + ASSERT_TRUE(value); + ASSERT_TRUE(value->is_int()); + EXPECT_EQ(kValue, static_cast(value->GetInt())); +} +TEST(BluetoothTypeConverterTest, + ConvertBlueZValueAttributeToMojoAttribute_BoolType) { // Check bool type. - bool valueBool = false; - auto boolAttributeBlueZ = bluez::BluetoothServiceAttributeValueBlueZ( + auto blue_z = bluez::BluetoothServiceAttributeValueBlueZ( bluez::BluetoothServiceAttributeValueBlueZ::BOOL, sizeof(bool), - std::make_unique(valueBool)); + std::make_unique(false)); - auto boolAttributeMojo = - ConvertTo(boolAttributeBlueZ); + auto mojo = ConvertTo(blue_z); - EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::BOOL, - boolAttributeMojo->type); - EXPECT_EQ(static_cast(sizeof(valueBool)), - boolAttributeMojo->type_size); - { - ASSERT_TRUE(boolAttributeMojo->json_value.has_value()); - auto value = base::JSONReader::Read(boolAttributeMojo->json_value.value()); - ASSERT_TRUE(value); - ASSERT_TRUE(value->is_bool()); - EXPECT_FALSE(value->GetBool()); - } + EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::BOOL, mojo->type); + EXPECT_EQ(static_cast(sizeof(bool)), mojo->type_size); + ASSERT_TRUE(mojo->json_value.has_value()); + auto value = base::JSONReader::Read(mojo->json_value.value()); + ASSERT_TRUE(value); + ASSERT_TRUE(value->is_bool()); + EXPECT_FALSE(value->GetBool()); +} + +TEST(BluetoothTypeConverterTest, + ConvertBlueZValueAttributeToMojoAttribute_UuidType) { // Check UUID type. - std::string valueUUID("00000100-0000-1000-8000-00805f9b34fb"); - auto uuidAttributeBlueZ = bluez::BluetoothServiceAttributeValueBlueZ( + constexpr char kValue[] = "00000100-0000-1000-8000-00805f9b34fb"; + auto blue_z = bluez::BluetoothServiceAttributeValueBlueZ( bluez::BluetoothServiceAttributeValueBlueZ::UUID, sizeof(uint16_t), - std::make_unique(valueUUID)); + std::make_unique(kValue)); - auto uuidAttributeMojo = - ConvertTo(uuidAttributeBlueZ); + auto mojo = ConvertTo(blue_z); - EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::UUID, - uuidAttributeMojo->type); - EXPECT_EQ(static_cast(sizeof(uint16_t)), - uuidAttributeMojo->type_size); - { - ASSERT_TRUE(uuidAttributeMojo->json_value.has_value()); - auto value = base::JSONReader::Read(uuidAttributeMojo->json_value.value()); - ASSERT_TRUE(value); - ASSERT_TRUE(value->is_string()); - EXPECT_EQ(valueUUID, value->GetString()); - } + EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::UUID, mojo->type); + EXPECT_EQ(static_cast(sizeof(uint16_t)), mojo->type_size); + + ASSERT_TRUE(mojo->json_value.has_value()); + auto value = base::JSONReader::Read(mojo->json_value.value()); + ASSERT_TRUE(value); + ASSERT_TRUE(value->is_string()); + EXPECT_EQ(kValue, value->GetString()); +} +TEST(BluetoothTypeConverterTest, + ConvertBlueZValueAttributeToMojoAttribute_StringType) { // Check string types (STRING, URL). - std::string valueString("Some Service Name"); - auto stringAttributeBlueZ = bluez::BluetoothServiceAttributeValueBlueZ( - bluez::BluetoothServiceAttributeValueBlueZ::STRING, valueString.length(), - std::make_unique(valueString)); - - auto stringAttributeMojo = - ConvertTo(stringAttributeBlueZ); - - EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::STRING, - stringAttributeMojo->type); - EXPECT_EQ(static_cast(valueString.length()), - stringAttributeMojo->type_size); - { - ASSERT_TRUE(stringAttributeMojo->json_value.has_value()); - auto value = - base::JSONReader::Read(stringAttributeMojo->json_value.value()); - ASSERT_TRUE(value); - ASSERT_TRUE(value->is_string()); - EXPECT_EQ(valueString, value->GetString()); - } + constexpr char kValue[] = "Some Service Name"; + constexpr size_t kValueSize = sizeof(kValue) - 1; // Subtract '\0' size. + auto blue_z = bluez::BluetoothServiceAttributeValueBlueZ( + bluez::BluetoothServiceAttributeValueBlueZ::STRING, kValueSize, + std::make_unique(kValue)); + + auto mojo = ConvertTo(blue_z); + + EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::STRING, mojo->type); + EXPECT_EQ(static_cast(kValueSize), mojo->type_size); + + ASSERT_TRUE(mojo->json_value.has_value()); + auto value = base::JSONReader::Read(mojo->json_value.value()); + ASSERT_TRUE(value); + ASSERT_TRUE(value->is_string()); + EXPECT_EQ(kValue, value->GetString()); } -TEST(BluetoothTypeConvertorTest, ConvertBlueZSequenceAttributeToMojoAttribute) { - std::string l2capUUID("00000100-0000-1000-8000-00805f9b34fb"); - uint16_t l2capChannel = 3; +TEST(BluetoothTypeConverterTest, ConvertBlueZSequenceAttributeToMojoAttribute) { + constexpr char kL2capUuid[] = "00000100-0000-1000-8000-00805f9b34fb"; + constexpr uint16_t kL2capChannel = 3; - std::unique_ptr - sequence(new bluez::BluetoothServiceAttributeValueBlueZ::Sequence()); + auto sequence = + std::make_unique(); sequence->push_back(bluez::BluetoothServiceAttributeValueBlueZ( bluez::BluetoothServiceAttributeValueBlueZ::UUID, sizeof(uint16_t), - std::make_unique(l2capUUID))); + std::make_unique(kL2capUuid))); sequence->push_back(bluez::BluetoothServiceAttributeValueBlueZ( bluez::BluetoothServiceAttributeValueBlueZ::UINT, sizeof(uint16_t), - std::make_unique(l2capChannel))); - - auto sequenceBlueZ = - bluez::BluetoothServiceAttributeValueBlueZ(std::move(sequence)); + std::make_unique(kL2capChannel))); - ASSERT_EQ(2u, sequenceBlueZ.sequence().size()); + auto blue_z = bluez::BluetoothServiceAttributeValueBlueZ(std::move(sequence)); + ASSERT_EQ(2u, blue_z.sequence().size()); - auto sequenceMojo = - ConvertTo(sequenceBlueZ); + auto sequence_mojo = ConvertTo(blue_z); EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::SEQUENCE, - sequenceMojo->type); - EXPECT_EQ(static_cast(sequenceBlueZ.size()), - sequenceMojo->type_size); - EXPECT_EQ(sequenceMojo->type_size, sequenceMojo->sequence.size()); - - EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::UUID, - sequenceMojo->sequence[0]->type); - EXPECT_EQ(static_cast(sizeof(uint16_t)), - sequenceMojo->sequence[0]->type_size); + sequence_mojo->type); + EXPECT_EQ(static_cast(blue_z.size()), sequence_mojo->type_size); + EXPECT_EQ(sequence_mojo->type_size, sequence_mojo->sequence.size()); + { - ASSERT_TRUE(sequenceMojo->sequence[0]->json_value.has_value()); - auto value = - base::JSONReader::Read(sequenceMojo->sequence[0]->json_value.value()); + const auto& mojo = sequence_mojo->sequence[0]; + EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::UUID, mojo->type); + EXPECT_EQ(static_cast(sizeof(uint16_t)), mojo->type_size); + + ASSERT_TRUE(mojo->json_value.has_value()); + auto value = base::JSONReader::Read(mojo->json_value.value()); ASSERT_TRUE(value); ASSERT_TRUE(value->is_string()); - EXPECT_EQ(l2capUUID, value->GetString()); + EXPECT_EQ(kL2capUuid, value->GetString()); } - EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::UINT, - sequenceMojo->sequence[1]->type); - EXPECT_EQ(static_cast(sizeof(uint16_t)), - sequenceMojo->sequence[1]->type_size); { - ASSERT_TRUE(sequenceMojo->sequence[1]->json_value.has_value()); - auto value = - base::JSONReader::Read(sequenceMojo->sequence[1]->json_value.value()); + const auto& mojo = sequence_mojo->sequence[1]; + EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::UINT, mojo->type); + EXPECT_EQ(static_cast(sizeof(uint16_t)), mojo->type_size); + ASSERT_TRUE(mojo->json_value.has_value()); + auto value = base::JSONReader::Read(mojo->json_value.value()); ASSERT_TRUE(value); ASSERT_TRUE(value->is_int()); - EXPECT_EQ(l2capChannel, static_cast(value->GetInt())); + EXPECT_EQ(kL2capChannel, static_cast(value->GetInt())); } } -TEST(BluetoothTypeConvertorTest, - ConvertDeepBlueZSequenceAttributeToBlueZAttribute) { - bluez::BluetoothServiceAttributeValueBlueZ sequenceBlueZ = +TEST(BluetoothTypeConverterTest, + ConvertInvalidBlueZSequenceAttributeToBlueZAttribute_TooDeep) { + bluez::BluetoothServiceAttributeValueBlueZ blue_z = CreateDeepBlueZSequenceAttribute(arc::kBluetoothSDPMaxDepth + 3); - auto sequenceMojo = - ConvertTo(sequenceBlueZ); + auto mojo = ConvertTo(blue_z); - EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::SEQUENCE, - sequenceMojo->type); - EXPECT_EQ((uint32_t)1, sequenceMojo->type_size); - EXPECT_EQ(arc::kBluetoothSDPMaxDepth, GetDepthOfMojoAttribute(sequenceMojo)); + EXPECT_EQ(bluez::BluetoothServiceAttributeValueBlueZ::SEQUENCE, mojo->type); + EXPECT_EQ(1u, mojo->type_size); + EXPECT_EQ(arc::kBluetoothSDPMaxDepth, GetDepthOfMojoAttribute(mojo)); } } // namespace mojo diff --git a/chromium/components/arc/clipboard/arc_clipboard_bridge.cc b/chromium/components/arc/clipboard/arc_clipboard_bridge.cc index 7517dab7cb8..2c05eb1c088 100644 --- a/chromium/components/arc/clipboard/arc_clipboard_bridge.cc +++ b/chromium/components/arc/clipboard/arc_clipboard_bridge.cc @@ -150,25 +150,15 @@ ArcClipboardBridge* ArcClipboardBridge::GetForBrowserContext( ArcClipboardBridge::ArcClipboardBridge(content::BrowserContext* context, ArcBridgeService* bridge_service) : arc_bridge_service_(bridge_service), - binding_(this), event_originated_at_instance_(false) { - arc_bridge_service_->clipboard()->AddObserver(this); + arc_bridge_service_->clipboard()->SetHost(this); ui::ClipboardMonitor::GetInstance()->AddObserver(this); } ArcClipboardBridge::~ArcClipboardBridge() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); ui::ClipboardMonitor::GetInstance()->RemoveObserver(this); - arc_bridge_service_->clipboard()->RemoveObserver(this); -} - -void ArcClipboardBridge::OnInstanceReady() { - mojom::ClipboardInstance* clipboard_instance = - ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->clipboard(), Init); - DCHECK(clipboard_instance); - mojom::ClipboardHostPtr host_proxy; - binding_.Bind(mojo::MakeRequest(&host_proxy)); - clipboard_instance->Init(std::move(host_proxy)); + arc_bridge_service_->clipboard()->SetHost(nullptr); } void ArcClipboardBridge::OnClipboardDataChanged() { diff --git a/chromium/components/arc/clipboard/arc_clipboard_bridge.h b/chromium/components/arc/clipboard/arc_clipboard_bridge.h index 053ae8bb374..35b92f17c3c 100644 --- a/chromium/components/arc/clipboard/arc_clipboard_bridge.h +++ b/chromium/components/arc/clipboard/arc_clipboard_bridge.h @@ -10,9 +10,7 @@ #include "base/macros.h" #include "base/threading/thread_checker.h" #include "components/arc/common/clipboard.mojom.h" -#include "components/arc/instance_holder.h" #include "components/keyed_service/core/keyed_service.h" -#include "mojo/public/cpp/bindings/binding.h" #include "ui/base/clipboard/clipboard_observer.h" namespace content { @@ -23,11 +21,9 @@ namespace arc { class ArcBridgeService; -class ArcClipboardBridge - : public KeyedService, - public ui::ClipboardObserver, - public InstanceHolder::Observer, - public mojom::ClipboardHost { +class ArcClipboardBridge : public KeyedService, + public ui::ClipboardObserver, + public mojom::ClipboardHost { public: // Returns singleton instance for the given BrowserContext, // or nullptr if the browser |context| is not allowed to use ARC. @@ -38,9 +34,6 @@ class ArcClipboardBridge ArcBridgeService* bridge_service); ~ArcClipboardBridge() override; - // InstanceHolder::Observer overrides. - void OnInstanceReady() override; - // ClipboardObserver overrides. void OnClipboardDataChanged() override; @@ -52,7 +45,6 @@ class ArcClipboardBridge private: ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager. - mojo::Binding binding_; bool event_originated_at_instance_; diff --git a/chromium/components/arc/common/BUILD.gn b/chromium/components/arc/common/BUILD.gn new file mode 100644 index 00000000000..a60852bbab1 --- /dev/null +++ b/chromium/components/arc/common/BUILD.gn @@ -0,0 +1,76 @@ +# Copyright 2017 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. + +import("//mojo/public/tools/bindings/mojom.gni") + +if (is_chromeos) { + mojom("common") { + sources = [ + "accessibility_helper.mojom", + "app.mojom", + "arc_bridge.mojom", + "audio.mojom", + "auth.mojom", + "backup_settings.mojom", + "bitmap.mojom", + "bluetooth.mojom", + "boot_phase_monitor.mojom", + "cast_receiver.mojom", + "cert_store.mojom", + "clipboard.mojom", + "crash_collector.mojom", + "enterprise_reporting.mojom", + "file_system.mojom", + "gfx.mojom", + "ime.mojom", + "intent_helper.mojom", + "kiosk.mojom", + "lock_screen.mojom", + "metrics.mojom", + "midis.mojom", + "net.mojom", + "notifications.mojom", + "obb_mounter.mojom", + "oemcrypto.mojom", + "oemcrypto_daemon.mojom", + "policy.mojom", + "power.mojom", + "print.mojom", + "process.mojom", + "rotation_lock.mojom", + "scale_factor.mojom", + "storage_manager.mojom", + "tracing.mojom", + "tts.mojom", + "voice_interaction_arc_home.mojom", + "voice_interaction_framework.mojom", + "volume_mounter.mojom", + "wallpaper.mojom", + ] + + public_deps = [ + ":media", + "//mojo/common:common_custom_types", + "//ui/gfx/geometry/mojo", + ] + } +} + +# Media related mojo interfaces. There are used by +# //services/ui/public/interfaces. We have this separate mojom target to avoid +# pulling in unnecessary interfaces, +mojom("media") { + sources = [ + "protected_buffer_manager.mojom", + "video.mojom", + "video_common.mojom", + "video_decode_accelerator.mojom", + "video_encode_accelerator.mojom", + ] + + public_deps = [ + "//mojo/common:common_custom_types", + "//ui/gfx/geometry/mojo", + ] +} diff --git a/chromium/components/arc/common/DEPS b/chromium/components/arc/common/DEPS new file mode 100644 index 00000000000..04dd5ab2b11 --- /dev/null +++ b/chromium/components/arc/common/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+media/video/video_encode_accelerator.h", +] diff --git a/chromium/components/arc/common/accessibility_helper.mojom b/chromium/components/arc/common/accessibility_helper.mojom index 7cc1327546c..9e6eebabe90 100644 --- a/chromium/components/arc/common/accessibility_helper.mojom +++ b/chromium/components/arc/common/accessibility_helper.mojom @@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Next MinVersion: 9 +// Next MinVersion: 10 module arc.mojom; -import "screen_rect.mojom"; +import "gfx.mojom"; // For future maintainers, each of the below enums were hand picked // from their equivalents in the Android source. Keep them in the @@ -211,20 +211,20 @@ struct AccessibilityRangeInfoData { // AccessibilityNodeInfoData is a struct to contain info of // AccessibilityNodeInfo in Android. struct AccessibilityNodeInfoData { - ScreenRect bounds_in_screen; - [MinVersion=1]int32 id; - [MinVersion=1]map? boolean_properties; - [MinVersion=1]map? string_properties; - [MinVersion=1]map? int_properties; + Rect bounds_in_screen; + [MinVersion=1] int32 id; + [MinVersion=1] map? boolean_properties; + [MinVersion=1] map? string_properties; + [MinVersion=1] map? int_properties; [MinVersion=1] map>? int_list_properties; - [MinVersion=3]map>? + [MinVersion=3] map>? string_list_properties; - [MinVersion=5]map>? + [MinVersion=5] map>? spannable_string_properties; - [MinVersion=5]AccessibilityCollectionInfoData? collection_info; - [MinVersion=5]AccessibilityCollectionItemInfoData? collection_item_info; - [MinVersion=5]AccessibilityRangeInfoData? range_info; + [MinVersion=5] AccessibilityCollectionInfoData? collection_info; + [MinVersion=5] AccessibilityCollectionItemInfoData? collection_item_info; + [MinVersion=5] AccessibilityRangeInfoData? range_info; }; // Filters the event type (and implicitly the data) sent by the ARC @@ -241,7 +241,7 @@ enum AccessibilityFilterType { ALL, // Send complete subtrees for root nodes with whitelisted package names. - [MinVersion=2]WHITELISTED_PACKAGE_NAME + [MinVersion=2] WHITELISTED_PACKAGE_NAME }; // AccessibilityEventData is a struct to contain info of @@ -253,16 +253,16 @@ struct AccessibilityEventData { array node_data; // notification_key is set only for an event on an Android notification. - [MinVersion=6]string? notification_key; + [MinVersion=6] string? notification_key; // window_id where this event is dispatched for. While this window_id matches // with AccessibilityNodeInfo.getWindowId now, do not expect that it always // matches with it. - [MinVersion=6]int32 window_id; + [MinVersion=6] int32 window_id; // Task associated with this event (usually the front task when this event // gets dispatched). - [MinVersion=8]int32 task_id; + [MinVersion=8] int32 task_id; }; // AccessibilityActionData is a struct to contain info of AccessibilityAction in @@ -277,7 +277,7 @@ struct AccessibilityActionData { int32 custom_action_id; // window_id where the action is performed on. - [MinVersion=6]int32 window_id; + [MinVersion=6] int32 window_id; }; // Next method ID: 2 @@ -290,28 +290,32 @@ interface AccessibilityHelperHost { OnAccessibilityEvent@1(AccessibilityEventData event_data); }; -// Next method ID: 7 +// Next method ID: 8 interface AccessibilityHelperInstance { - Init@0(AccessibilityHelperHost host); + // DEPRECATED: Please use Init@7 instead. + InitDeprecated@0(AccessibilityHelperHost host); + + // Establishes full-duplex communication with the host. + [MinVersion=9] Init@7(AccessibilityHelperHost host) => (); PerformActionDeprecated@1(int32 id, AccessibilityActionType action); // Set a filter on the event types received. SetFilter@2(AccessibilityFilterType filter_type); - [MinVersion=3]PerformActionDeprecated2@3(AccessibilityActionData action_data); + [MinVersion=3] PerformActionDeprecated2@3(AccessibilityActionData action_data); // Perform an action on a node requested by a Chrome client. - [MinVersion=4]PerformAction@4(AccessibilityActionData action_data) + [MinVersion=4] PerformAction@4(AccessibilityActionData action_data) => (bool result); // Sets the package to use ChromeVox (true) or TalkBack (false). Returns true // if the request was processed. - [MinVersion=7]SetNativeChromeVoxArcSupportDeprecated@5( + [MinVersion=7] SetNativeChromeVoxArcSupportDeprecated@5( string package_name, bool enabled) => (bool processed); // Sets the focused window's package to use ChromeVox (true) or TalkBack // (false). - [MinVersion=8]SetNativeChromeVoxArcSupportForFocusedWindow@6( + [MinVersion=8] SetNativeChromeVoxArcSupportForFocusedWindow@6( bool enabled) => (bool processed); }; diff --git a/chromium/components/arc/common/app.mojom b/chromium/components/arc/common/app.mojom index 48b66bb8baf..c00f4c4e838 100644 --- a/chromium/components/arc/common/app.mojom +++ b/chromium/components/arc/common/app.mojom @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 24 +// Next MinVersion: 27 module arc.mojom; +import "gfx.mojom"; import "scale_factor.mojom"; -import "screen_rect.mojom"; // Describes OrientationLock request. // Note: ChromeOS currently assumes the internal panel is always landscape. @@ -55,6 +55,8 @@ struct ArcPackageInfo { int64 last_backup_time; bool sync; // true if package installation should be synced [MinVersion=11] bool system; // true if package is system package. + // true if package registers VPNService intent. + [MinVersion=25] bool vpn_provider; }; // Describes ARC app shortcut. @@ -89,7 +91,8 @@ struct AppDiscoveryResult { [MinVersion=22] string? package_name; }; -// Describes the status of an app discovery request. +// Describes the status of an app discovery request, including completed +// states and all possible anomalies. [Extensible] enum AppDiscoveryRequestState { // Request handled successfully. @@ -97,7 +100,37 @@ enum AppDiscoveryRequestState { // Request canceled when a newer request is sent. CANCELED = 1, // Request failed due to any communication error or Play Store internal error. - ERROR = 2, + ERROR_DEPRECATED = 2, + + // All possible reasons of ending a request: + // PlayStoreProxyService is not available. + PLAY_STORE_PROXY_NOT_AVAILABLE = 3, + // It fails to cancel the previous request. + FAILED_TO_CALL_CANCEL = 4, + // It fails to call findApps API. + FAILED_TO_CALL_FINDAPPS = 5, + // It comes with invalid parameters. + REQUEST_HAS_INVALID_PARAMS = 6, + // It times out. + REQUEST_TIMEOUT = 7, + // At least one result returned from Phonesky has an unmatched request code. + PHONESKY_RESULT_REQUEST_CODE_UNMATCHED = 8, + // At least one result returned from Phonesky has an unmatched session id. + PHONESKY_RESULT_SESSION_ID_UNMATCHED = 9, + // Phonesky returns with an unmatched request code. + PHONESKY_REQUEST_REQUEST_CODE_UNMATCHED = 10, + // The app discovery service is not available. + PHONESKY_APP_DISCOVERY_NOT_AVAILABLE = 11, + // The installed Phonesky version doesn't support app discovery. + PHONESKY_VERSION_NOT_SUPPORTED = 12, + // It gets an unexpected exception from Phonesky. + PHONESKY_UNEXPECTED_EXCEPTION = 13, + // The Phonesky app discovery service thinks it's malformed. + PHONESKY_MALFORMED_QUERY = 14, + // An internal error happens in Phonesky while processing the request. + PHONESKY_INTERNAL_ERROR = 15, + // At least one result returned with invalid app data. + PHONESKY_RESULT_INVALID_DATA = 16, }; // Next method ID: 18 @@ -186,12 +219,16 @@ interface AppHost { }; // TODO(lhchavez): Migrate all request/response messages to Mojo. -// Next method ID: 21 +// Next method ID: 22 interface AppInstance { - Init@0(AppHost host_ptr); + // DEPRECATED: Please use Init@21 instead. + InitDeprecated@0(AppHost host_ptr); + + // Establishes full-duplex communication with the host. + [MinVersion=26] Init@21(AppHost host_ptr) => (); [MinVersion=1] CanHandleResolutionDeprecated@4( - string package_name, string activity, ScreenRect dimension) => + string package_name, string activity, Rect dimension) => (bool can_handle); // Closes the the given task. @@ -205,7 +242,7 @@ interface AppInstance { [MinVersion=8] InstallPackage@11(ArcPackageInfo arcPackageInfo); LaunchAppDeprecated@1(string package_name, string activity, - [MinVersion=1] ScreenRect? dimension_on_screen); + [MinVersion=1] Rect? dimension_on_screen); // Sends a request to ARC to launch an ARC app defined by |package_name| and // |activity|, which cannot be empty. @@ -213,7 +250,7 @@ interface AppInstance { int64 display_id); [MinVersion=9] LaunchIntentDeprecated@12(string intent_uri, - ScreenRect? dimension_on_screen); + Rect? dimension_on_screen); // Sends a request to ARC to launch an intent. The intent is encoded as a URI // string. See Intent.toUri(). @@ -244,11 +281,11 @@ interface AppInstance { [MinVersion=4] SetTaskActive@7(int32 task_id); [MinVersion=5] ShowPackageInfoDeprecated@9(string package_name, - ScreenRect dimension_on_screen); + Rect dimension_on_screen); [MinVersion=10] ShowPackageInfoOnPageDeprecated@15(string package_name, ShowPackageInfoPage page, - ScreenRect dimension_on_screen); + Rect dimension_on_screen); // Sends a request to ARC to show package info for given package on the // specified page. diff --git a/chromium/components/arc/common/app.typemap b/chromium/components/arc/common/app.typemap deleted file mode 100644 index 83cac7b5174..00000000000 --- a/chromium/components/arc/common/app.typemap +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright 2016 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. - -mojom = "//components/arc/common/app.mojom" -public_headers = [ - "//ui/gfx/geometry/rect.h", -] -traits_headers = [ "//components/arc/common/app_struct_traits.h" ] -sources = [ - "//components/arc/common/app_struct_traits.cc" -] -type_mappings = [ - "arc.mojom.ScreenRect=gfx::Rect" -] diff --git a/chromium/components/arc/common/app_struct_traits.cc b/chromium/components/arc/common/app_struct_traits.cc deleted file mode 100644 index 46c8ac0a22c..00000000000 --- a/chromium/components/arc/common/app_struct_traits.cc +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2016 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 "components/arc/common/app_struct_traits.h" - -namespace mojo { - -bool StructTraits::Read( - arc::mojom::ScreenRectDataView data, - gfx::Rect* out) { - if (data.right() < data.left() || data.bottom() < data.top()) - return false; - - out->SetRect(data.left(), data.top(), data.right() - data.left(), - data.bottom() - data.top()); - return true; -} - -} // namespace mojo diff --git a/chromium/components/arc/common/app_struct_traits.h b/chromium/components/arc/common/app_struct_traits.h deleted file mode 100644 index e0ada3d9e8c..00000000000 --- a/chromium/components/arc/common/app_struct_traits.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2016 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 COMPONENTS_ARC_COMMON_APP_STRUCT_TRAITS_H_ -#define COMPONENTS_ARC_COMMON_APP_STRUCT_TRAITS_H_ - -#include "components/arc/common/app.mojom.h" -#include "ui/gfx/geometry/rect.h" - -namespace mojo { - -template <> -struct StructTraits { - static int32_t left(const gfx::Rect& p) { return p.x(); } - static int32_t top(const gfx::Rect& p) { return p.y(); } - static int32_t right(const gfx::Rect& p) { return p.right(); } - static int32_t bottom(const gfx::Rect& p) { return p.bottom(); } - static bool Read(arc::mojom::ScreenRectDataView data, gfx::Rect* out); -}; - -} // namespace mojo - -#endif // COMPONENTS_ARC_COMMON_APP_STRUCT_TRAITS_H_ diff --git a/chromium/components/arc/common/arc_bridge.mojom b/chromium/components/arc/common/arc_bridge.mojom index e8f613983c2..297c99a3a37 100644 --- a/chromium/components/arc/common/arc_bridge.mojom +++ b/chromium/components/arc/common/arc_bridge.mojom @@ -8,6 +8,7 @@ import "accessibility_helper.mojom"; import "app.mojom"; import "audio.mojom"; import "auth.mojom"; +import "backup_settings.mojom"; import "bluetooth.mojom"; import "boot_phase_monitor.mojom"; import "cast_receiver.mojom"; @@ -40,9 +41,9 @@ import "voice_interaction_framework.mojom"; import "volume_mounter.mojom"; import "wallpaper.mojom"; -// Next MinVersion: 33 +// Next MinVersion: 34 // Deprecated method IDs: 101, 105 -// Next method ID: 138 +// Next method ID: 139 interface ArcBridgeHost { // Keep the entries alphabetical. In order to do so without breaking // compatibility with the ARC instance, explicitly assign each interface a @@ -61,6 +62,9 @@ interface ArcBridgeHost { // Notifies Chrome that the AuthInstance interface is ready. [MinVersion=1] OnAuthInstanceReady@106(AuthInstance instance_ptr); + // Notifies Chrome that the BackupSettingsInstance interface is ready. + [MinVersion=33] OnBackupSettingsInstanceReady@138(BackupSettingsInstance instance_ptr); + // Notifies Chrome that the BluetoothInstance interface is ready. [MinVersion=9] OnBluetoothInstanceReady@113(BluetoothInstance instance_ptr); diff --git a/chromium/components/arc/common/arc_gfx_struct_traits.cc b/chromium/components/arc/common/arc_gfx_struct_traits.cc new file mode 100644 index 00000000000..20858df1123 --- /dev/null +++ b/chromium/components/arc/common/arc_gfx_struct_traits.cc @@ -0,0 +1,28 @@ +// Copyright 2017 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 "components/arc/common/arc_gfx_struct_traits.h" + +namespace mojo { + +bool StructTraits::Read( + arc::mojom::RectDataView data, + gfx::Rect* out) { + if (data.right() < data.left() || data.bottom() < data.top()) + return false; + + out->SetRect(data.left(), data.top(), data.right() - data.left(), + data.bottom() - data.top()); + return true; +} + +bool StructTraits::Read( + arc::mojom::RangeDataView data, + gfx::Range* out) { + out->set_start(data.start()); + out->set_end(data.end()); + return true; +} + +} // namespace mojo diff --git a/chromium/components/arc/common/arc_gfx_struct_traits.h b/chromium/components/arc/common/arc_gfx_struct_traits.h new file mode 100644 index 00000000000..02c4edf9023 --- /dev/null +++ b/chromium/components/arc/common/arc_gfx_struct_traits.h @@ -0,0 +1,34 @@ +// Copyright 2017 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 COMPONENTS_ARC_COMMON_ARC_GFX_STRUCT_TRAITS_H_ +#define COMPONENTS_ARC_COMMON_ARC_GFX_STRUCT_TRAITS_H_ + +#include "components/arc/common/gfx.mojom.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/range/range.h" + +namespace mojo { + +template <> +struct StructTraits { + static int32_t left(const gfx::Rect& r) { return r.x(); } + static int32_t top(const gfx::Rect& r) { return r.y(); } + static int32_t right(const gfx::Rect& r) { return r.right(); } + static int32_t bottom(const gfx::Rect& r) { return r.bottom(); } + + static bool Read(arc::mojom::RectDataView data, gfx::Rect* out); +}; + +template <> +struct StructTraits { + static uint32_t start(const gfx::Range& r) { return r.start(); } + static uint32_t end(const gfx::Range& r) { return r.end(); } + + static bool Read(arc::mojom::RangeDataView data, gfx::Range* out); +}; + +} // namespace mojo + +#endif // COMPONENTS_ARC_COMMON_ARC_GFX_STRUCT_TRAITS_H_ diff --git a/chromium/components/arc/common/audio.mojom b/chromium/components/arc/common/audio.mojom index 07e2b2eace3..eceb20e4cdf 100644 --- a/chromium/components/arc/common/audio.mojom +++ b/chromium/components/arc/common/audio.mojom @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Next MinVersion: 4 +// Next MinVersion: 5 module arc.mojom; @@ -24,10 +24,13 @@ interface AudioHost { [MinVersion=3] OnSystemVolumeUpdateRequest@1(int32 percent); }; -// Next method ID: 3 +// Next method ID: 4 interface AudioInstance { + // DEPRECATED: Please use Init@3 instead. + [MinVersion=1] InitDeprecated@1(AudioHost host); + // Establishes full-duplex communication with the host. - [MinVersion=1] Init@1(AudioHost host); + [MinVersion=4] Init@3(AudioHost host) => (); // Notify plug states of headphone, microphone, etc. Each switch state is // represented by the corresponding bit, if the bit is set then the switch diff --git a/chromium/components/arc/common/auth.mojom b/chromium/components/arc/common/auth.mojom index bee59b6c84c..54334bc9bae 100644 --- a/chromium/components/arc/common/auth.mojom +++ b/chromium/components/arc/common/auth.mojom @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Next MinVersion: 12 +// Next MinVersion: 13 module arc.mojom; @@ -184,10 +184,13 @@ interface AuthHost { [MinVersion=9] ReportAccountCheckStatus@9(AccountCheckStatus status); }; -// Next Method ID: 2 +// Next Method ID: 3 interface AuthInstance { + // DEPRECATED: Please use Init@2 instead. + InitDeprecated@0(AuthHost host_ptr); + // Establishes full-duplex communication with the host. - Init@0(AuthHost host_ptr); + [MinVersion=12] Init@2(AuthHost host_ptr) => (); // Callback from RequestAccountInfo. This cannot be a normal callback since // the result can sometimes take a few minutes in some cases (Kiosk mode), diff --git a/chromium/components/arc/common/backup_settings.mojom b/chromium/components/arc/common/backup_settings.mojom new file mode 100644 index 00000000000..4ebb2ce2e09 --- /dev/null +++ b/chromium/components/arc/common/backup_settings.mojom @@ -0,0 +1,16 @@ +// Copyright 2017 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. +// +// Next MinVersion: 1 + +module arc.mojom; + +// Controls the setting entries for the ARC backup and restore feature. +// Next method ID: 1 +interface BackupSettingsInstance { + // Enables or disables the backup feature as specified by the |enabled| + // parameter. The |managed| parameter indicates whether or not this setting + // is managed by the enterprise policy. + SetBackupEnabled@0(bool enabled, bool managed); +}; diff --git a/chromium/components/arc/common/bluetooth.mojom b/chromium/components/arc/common/bluetooth.mojom index f6e41c9f561..f22585f8ec1 100644 --- a/chromium/components/arc/common/bluetooth.mojom +++ b/chromium/components/arc/common/bluetooth.mojom @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Next MinVersion: 7 +// Next MinVersion: 8 module arc.mojom; @@ -403,9 +403,13 @@ interface BluetoothHost { => (BluetoothGattStatus status); }; -// Next Method ID: 18 +// Next Method ID: 19 interface BluetoothInstance { - Init@0(BluetoothHost host_ptr); + // DEPRECATED: Please use Init@18 instead. + InitDeprecated@0(BluetoothHost host_ptr); + + // Establishes full-duplex communication with the host. + [MinVersion=7] Init@18(BluetoothHost host_ptr) => (); OnAdapterProperties@1(BluetoothStatus status, array properties); diff --git a/chromium/components/arc/common/bluetooth.typemap b/chromium/components/arc/common/bluetooth.typemap index fc86d17a20e..b59c8707820 100644 --- a/chromium/components/arc/common/bluetooth.typemap +++ b/chromium/components/arc/common/bluetooth.typemap @@ -6,6 +6,9 @@ public_headers = [ "//device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.h", ] traits_headers = [ "//components/arc/bluetooth/bluetooth_struct_traits.h" ] +sources = [ + "//components/arc/bluetooth/bluetooth_struct_traits.cc", +] deps = [ "//device/bluetooth", ] diff --git a/chromium/components/arc/common/boot_phase_monitor.mojom b/chromium/components/arc/common/boot_phase_monitor.mojom index e642f2656da..045270f3e1f 100644 --- a/chromium/components/arc/common/boot_phase_monitor.mojom +++ b/chromium/components/arc/common/boot_phase_monitor.mojom @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 1 +// Next MinVersion: 2 module arc.mojom; @@ -12,8 +12,11 @@ interface BootPhaseMonitorHost { OnBootCompleted@0(); }; -// Next method ID: 1 +// Next method ID: 2 interface BootPhaseMonitorInstance { + // DEPRECATED: Please use Init@1 instead. + InitDeprecated@0(BootPhaseMonitorHost host_ptr); + // Establishes full-duplex communication with the host. - Init@0(BootPhaseMonitorHost host_ptr); + [MinVersion=1] Init@1(BootPhaseMonitorHost host_ptr) => (); }; diff --git a/chromium/components/arc/common/cert_store.mojom b/chromium/components/arc/common/cert_store.mojom index 6af522bd9bb..eabf6b13731 100644 --- a/chromium/components/arc/common/cert_store.mojom +++ b/chromium/components/arc/common/cert_store.mojom @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Next MinVersion: 2 + // // CertStoreHost is modeled after Android keymaster interface // hardware/libhardware/include/hardware/keymaster2.h @@ -106,10 +108,13 @@ interface CertStoreHost { Abort@5(uint64 operation_handle) => (KeymasterError error); }; -// Next method ID: 3 +// Next method ID: 4 interface CertStoreInstance { + // DEPRECATED: Please use Init@3 instead. + InitDeprecated@0(CertStoreHost host_ptr); + // Establishes full-duplex communication with the host. - Init@0(CertStoreHost host_ptr); + [MinVersion=1] Init@3(CertStoreHost host_ptr) => (); // Informs the key permissions are changed: only listed packages are allowed // to use exposed certificates. diff --git a/chromium/components/arc/common/clipboard.mojom b/chromium/components/arc/common/clipboard.mojom index d10183e1a26..db8d434e6f6 100644 --- a/chromium/components/arc/common/clipboard.mojom +++ b/chromium/components/arc/common/clipboard.mojom @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Next MinVersion: 3 module arc.mojom; @@ -10,7 +11,6 @@ module arc.mojom; // either a |blob| or a |text|. // Value for |ClipRepresentation|. -// Next MinVersion: 1 // Next ID: 2 union ClipValue { // For images and other opaque structures. @@ -20,7 +20,6 @@ union ClipValue { }; // One possible representation of the |ClipData|: |mime_type| + its |value|. -// Next MinVersion: 1 // Next ID: 2 struct ClipRepresentation { // The mime type. @@ -30,7 +29,6 @@ struct ClipRepresentation { }; // The |ClipData| to transfer. -// Next MinVersion: 1 // Next ID: 1 struct ClipData { // A |ClipData| could have multiple representations. @@ -38,7 +36,6 @@ struct ClipData { array representations@0; }; -// Next MinVersion: 2 // Next method ID: 4 // IDs to be removed 18 weeks after being up revved: 0, 1 interface ClipboardHost { @@ -61,12 +58,14 @@ interface ClipboardHost { [MinVersion=1] GetClipContent@3() => (ClipData data); }; -// Next MinVersion: 2 -// Next method ID: 3 +// Next method ID: 4 // IDs to be removed 18 weeks after being up revved: 1 interface ClipboardInstance { + // DEPRECATED: Please use Init@3 instead. + InitDeprecated@0(ClipboardHost host_ptr); + // Establishes full-duplex communication with the host. - Init@0(ClipboardHost host_ptr); + [MinVersion=2] Init@3(ClipboardHost host_ptr) => (); // Passes the result of ClipboardHost.GetTextContentDeprecated(). OnGetTextContentDeprecated@1(string returned_text); diff --git a/chromium/components/arc/common/crash_collector.mojom b/chromium/components/arc/common/crash_collector.mojom index b61963cfcba..fb827b89f3f 100644 --- a/chromium/components/arc/common/crash_collector.mojom +++ b/chromium/components/arc/common/crash_collector.mojom @@ -2,8 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Next MinVersion: 3 + module arc.mojom; +// Next Method ID: 2 interface CrashCollectorHost { // Sends a dump for a non-native crash of the given |type|. The host reads // the dump from |pipe|, or rejects the dump by closing |pipe|. Note that @@ -17,6 +20,11 @@ interface CrashCollectorHost { string cpu_abi); }; +// Next Method ID: 2 interface CrashCollectorInstance { - Init@0(CrashCollectorHost host_ptr); + // DEPRECATED: Please use Init@1 instead. + InitDeprecated@0(CrashCollectorHost host_ptr); + + // Establishes full-duplex communication with the host. + [MinVersion=2] Init@1(CrashCollectorHost host_ptr) => (); }; diff --git a/chromium/components/arc/common/enterprise_reporting.mojom b/chromium/components/arc/common/enterprise_reporting.mojom index 0ad1ffab2a5..3130ee9fc54 100644 --- a/chromium/components/arc/common/enterprise_reporting.mojom +++ b/chromium/components/arc/common/enterprise_reporting.mojom @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 2 +// Next MinVersion: 3 module arc.mojom; // Enumerates the states that management can be in for a user. @@ -25,10 +25,13 @@ interface EnterpriseReportingHost { ReportManagementState@0(ManagementState state); }; -// Next method ID: 2 +// Next method ID: 3 interface EnterpriseReportingInstance { + // DEPRECATED: Please use Init@2 instead. + InitDeprecated@0(EnterpriseReportingHost host_ptr); + // Establishes full-duplex communication with the host. - Init@0(EnterpriseReportingHost host_ptr); + [MinVersion=2] Init@2(EnterpriseReportingHost host_ptr) => (); // Requests that a JSON status blob be generated and passed to the // host. diff --git a/chromium/components/arc/common/file_system.mojom b/chromium/components/arc/common/file_system.mojom index dae4ef28a45..b3c2ef235b1 100644 --- a/chromium/components/arc/common/file_system.mojom +++ b/chromium/components/arc/common/file_system.mojom @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 7 +// Next MinVersion: 8 module arc.mojom; @@ -73,7 +73,7 @@ interface FileSystemHost { [MinVersion=6] OpenFileToRead@4(string url) => (handle? fd); }; -// Next method ID: 10 +// Next method ID: 11 interface FileSystemInstance { // Notes about Android Documents Provider: // @@ -140,8 +140,11 @@ interface FileSystemInstance { [MinVersion=5] GetRecentDocuments@9(string authority, string root_id) => (array? documents); + // DEPRECATED: Please use Init@10 instead. + [MinVersion=3] InitDeprecated@5(FileSystemHost host_ptr); + // Establishes full-duplex communication with the host. - [MinVersion=3] Init@5(FileSystemHost host_ptr); + [MinVersion=7] Init@10(FileSystemHost host_ptr) => (); // Asks the ContentResolver to get a FD to read the file specified by the // URL. diff --git a/chromium/components/arc/common/file_system.typemap b/chromium/components/arc/common/file_system.typemap index cb71bf2d616..e21e8490f6a 100644 --- a/chromium/components/arc/common/file_system.typemap +++ b/chromium/components/arc/common/file_system.typemap @@ -8,4 +8,7 @@ public_deps = [ "//storage/browser", ] traits_headers = [ "//components/arc/file_system/file_system_struct_traits.h" ] +sources = [ + "//components/arc/file_system/file_system_struct_traits.cc", +] type_mappings = [ "arc.mojom.ChangeType=storage::WatcherManager::ChangeType" ] diff --git a/chromium/components/arc/common/gfx.mojom b/chromium/components/arc/common/gfx.mojom new file mode 100644 index 00000000000..aaf58a27b7e --- /dev/null +++ b/chromium/components/arc/common/gfx.mojom @@ -0,0 +1,28 @@ +// Copyright 2017 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. + +// Defines structs (and its related type mappings) related gfx. +// Eventually, we may want to migrate mojom files under ui/gfx. +// However, currently there is no well developed roll mechanism, so +// API diverge can be more problematic, unfortunately. So, instead of sharing, +// defines structs by ourselves. + +module arc.mojom; + +// Represents a rectangle. Note that the wire format is different from +// the one defined in geometry.mojom in ui/gfx for backward compatibility. +struct Rect { + int32 left; + int32 top; + int32 right; + int32 bottom; +}; + +// Represents a range in a text. It is an open interval [start, end). +struct Range { + // Start offset in UTF-16 index. + uint32 start; + // End offset in UTF-16 index. + uint32 end; +}; diff --git a/chromium/components/arc/common/gfx.typemap b/chromium/components/arc/common/gfx.typemap new file mode 100644 index 00000000000..be462bc0ab5 --- /dev/null +++ b/chromium/components/arc/common/gfx.typemap @@ -0,0 +1,25 @@ +# Copyright 2017 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. + +mojom = "//components/arc/common/gfx.mojom" + +public_headers = [ + "//ui/gfx/geometry/rect.h", + "//ui/gfx/range/range.h", +] + +deps = [ + "//ui/gfx", +] + +traits_headers = [ "//components/arc/common/arc_gfx_struct_traits.h" ] + +sources = [ + "//components/arc/common/arc_gfx_struct_traits.cc", +] + +type_mappings = [ + "arc.mojom.Rect=::gfx::Rect", + "arc.mojom.Range=::gfx::Range", +] diff --git a/chromium/components/arc/common/ime.mojom b/chromium/components/arc/common/ime.mojom index fd945302c3c..1dd59177d38 100644 --- a/chromium/components/arc/common/ime.mojom +++ b/chromium/components/arc/common/ime.mojom @@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Next MinVersion: 6 +// Next MinVersion: 7 module arc.mojom; -import "screen_rect.mojom"; +import "gfx.mojom"; // Represents the type of text input field currently focused. [Extensible] @@ -24,25 +24,6 @@ enum TextInputType { DATETIME, }; -// TODO(yhanada): Switch to use gfx.mojom.Rect. See crbug.com/723224. -// Represents the text insertion points in the container screen coordinates. -struct CursorRect { - int32 left; - int32 top; - int32 right; - int32 bottom; -}; - -// TODO(yhanada): Switch to use gfx.mojom.Range. See crbug.com/723224. -// Represents the range in the text. It is an open interval [start, end). -[MinVersion=5] -struct TextRange { - // Start offset in UTF-16 index. - uint32 start; - // End offset in UTF-16 index. - uint32 end; -}; - // Represents a single segment of text currently composed by IME. struct CompositionSegment { // Start offset of the segment in UTF-16 index. @@ -59,7 +40,7 @@ interface ImeHost { OnTextInputTypeChanged@0(TextInputType type); // Notifies Chrome that the cursor poisition has changed. - OnCursorRectChanged@1(CursorRect rect); + OnCursorRectChanged@1(Rect rect); // Notifies Chrome that the current composition is canceled. [MinVersion=1] OnCancelComposition@2(); @@ -74,18 +55,22 @@ interface ImeHost { // into this method because Chrome OS IME tries to retrieve these information // synchronously, so we need to update them all at once to keep consistency. [MinVersion=5] OnCursorRectChangedWithSurroundingText@4( - CursorRect rect, // The cursor position. - TextRange text_range, // The range of |text_in_range| in the current + Rect rect, // The cursor position. + Range text_range, // The range of |text_in_range| in the current // text in the editor. string text_in_range, // The text around the cursor. - TextRange selection_range // The range of the selected text + Range selection_range // The range of the selected text // in the current text in the editor. ); }; -// Next method ID: 6 +// Next method ID: 7 interface ImeInstance { - Init@0(ImeHost host_ptr); + // DEPRECATED: Please use Init@6 instead. + InitDeprecated@0(ImeHost host_ptr); + + // Establishes full-duplex communication with the host. + [MinVersion=6] Init@6(ImeHost host_ptr) => (); // Sets composition text and attributes requested by the host IME. SetCompositionText@1(string text, array segments); @@ -100,7 +85,7 @@ interface ImeInstance { // |new_bounds| Represents a ChromeOS virtual keyboard bounds in ChromeOS // screen coordinate, physical pixel as a unit. // When all members are zero value, virtual keyboard is being hidden. - [MinVersion=3] OnKeyboardBoundsChanging@4(ScreenRect new_bounds); + [MinVersion=3] OnKeyboardBoundsChanging@4(Rect new_bounds); // Deletes current selection plus the specified number of char16 values // before and after selection or caret. diff --git a/chromium/components/arc/common/ime.typemap b/chromium/components/arc/common/ime.typemap deleted file mode 100644 index 141f4ad18ce..00000000000 --- a/chromium/components/arc/common/ime.typemap +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2017 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. - -mojom = "//components/arc/common/ime.mojom" -public_headers = [ - "//ui/gfx/geometry/rect.h", - "//ui/gfx/range/range.h", -] -deps = [ - "//ui/gfx", -] -traits_headers = [ "//components/arc/ime/arc_ime_struct_traits.h" ] -sources = [ - "//components/arc/ime/arc_ime_struct_traits.cc", -] -type_mappings = [ - "arc.mojom.CursorRect=::gfx::Rect[move_only]", - "arc.mojom.TextRange=::gfx::Range[move_only]", -] diff --git a/chromium/components/arc/common/intent_helper.mojom b/chromium/components/arc/common/intent_helper.mojom index e62874f6669..4cc56de151d 100644 --- a/chromium/components/arc/common/intent_helper.mojom +++ b/chromium/components/arc/common/intent_helper.mojom @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 19 +// Next MinVersion: 20 module arc.mojom; @@ -82,9 +82,9 @@ struct UrlWithMimeType { string mime_type; }; -// Describes a specific page in chrome://settings. +// Describes a specific page in chrome://, about:blank, about:downloads and about:history. [Extensible] -enum SettingsPage { +enum ChromePage { MULTIDEVICE, MAIN, POWER, @@ -92,9 +92,34 @@ enum SettingsPage { DATETIME, DISPLAY, WIFI, - LANGUAGE, + LANGUAGES, PRIVACY, HELP, + ACCOUNTS, + APPEARANCE, + AUTOFILL, + BLUETOOTHDEVICES, + CHANGEPICTURE, + CLEARBROWSERDATA, + CLOUDPRINTERS, + CUPSPRINTERS, + DOWNLOADS, + KEYBOARDOVERLAY, + LOCKSCREEN, + MANAGEACCESSIBILITY, + NETWORKSTYPEVPN, + ONSTARTUP, + PASSWORDS, + POINTEROVERLAY, + RESET, + SEARCH, + STORAGE, + SYNCSETUP, + ABOUTBLANK, + ABOUTDOWNLOADS, + ABOUTHISTORY, + + LAST = ABOUTHISTORY, }; // Handles intents from ARC in Chrome. @@ -126,12 +151,12 @@ interface IntentHelperHost { // Opens the volume control. [MinVersion=16] OpenVolumeControl@6(); - // Opens the specified settings page in the Chrome browser. - [MinVersion=17] OnOpenChromeSettings@7([MinVersion=18] SettingsPage page); + // Opens the specified Chrome page in the Chrome browser. + [MinVersion=17] OnOpenChromePage@7([MinVersion=18] ChromePage page); }; // Sends intents to ARC on behalf of Chrome. -// Next method ID: 13 +// Next method ID: 14 interface IntentHelperInstance { // Sets the given package as a preferred package. The next time an ACTION_VIEW // intent is sent with a URL that requires disambiguation, instead of opening @@ -154,8 +179,11 @@ interface IntentHelperInstance { ActivityName activity, ActionType action_type); + // DEPRECATED: Please use Init@13 instead. + InitDeprecated@0(IntentHelperHost host_ptr); + // Establishes full-duplex communication with the host. - Init@0(IntentHelperHost host_ptr); + [MinVersion=19] Init@13(IntentHelperHost host_ptr) => (); // DEPRECATED. Use FileSystemInstance.OpenFileToRead() instead. [MinVersion=15] OpenFileToReadDeprecated@12(string url) => (handle? fd); diff --git a/chromium/components/arc/common/kiosk.mojom b/chromium/components/arc/common/kiosk.mojom index f2903b380e8..39beb508f79 100644 --- a/chromium/components/arc/common/kiosk.mojom +++ b/chromium/components/arc/common/kiosk.mojom @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 1 +// Next MinVersion: 2 module arc.mojom; @@ -20,10 +20,11 @@ interface KioskHost { OnMaintenanceSessionFinished@1(int32 session_id, bool succeeded); }; -// Next method ID: 1 +// Next method ID: 2 interface KioskInstance { + // DEPRECATED: Please use Init@1 instead. + InitDeprecated@0(KioskHost host_ptr); + // Establishes full-duplex communication with the host. - // |host_ptr| is the MessagePipe endpoint that is bound to the - // KioskHost binding. - Init@0(KioskHost host_ptr); + [MinVersion=1] Init@1(KioskHost host_ptr) => (); }; diff --git a/chromium/components/arc/common/metrics.mojom b/chromium/components/arc/common/metrics.mojom index d1c997a52a1..4f98a2b6513 100644 --- a/chromium/components/arc/common/metrics.mojom +++ b/chromium/components/arc/common/metrics.mojom @@ -1,7 +1,7 @@ // Copyright 2016 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. -// Next MinVersion: 2 +// Next MinVersion: 3 module arc.mojom; @@ -46,7 +46,11 @@ interface MetricsHost { [MinVersion=1] BootType boot_type); }; -// Next method ID: 1 +// Next method ID: 2 interface MetricsInstance { - Init@0(MetricsHost host_ptr); + // DEPRECATED: Please use Init@1 instead. + InitDeprecated@0(MetricsHost host_ptr); + + // Establishes full-duplex communication with the host. + [MinVersion=2] Init@1(MetricsHost host_ptr) => (); }; diff --git a/chromium/components/arc/common/midis.mojom b/chromium/components/arc/common/midis.mojom index 3342f21bc8b..bea75fb0287 100644 --- a/chromium/components/arc/common/midis.mojom +++ b/chromium/components/arc/common/midis.mojom @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Next MinVersion: 2 + // This file defines the mojo interface between Android, Chrome and the // Chrome OS daemon for the MIDI implementation used in ARC. @@ -66,7 +68,11 @@ interface MidisHost { // MidisInstance is implemented in the ARC MIDI JNI code that // runs in Android and handles the Android side of the ArcBridge connection. -// Next Method ID: 1 +// Next Method ID: 2 interface MidisInstance { - Init@0(MidisHost host_ptr); + // DEPRECATED: Please use Init@1 instead. + InitDeprecated@0(MidisHost host_ptr); + + // Establishes full-duplex communication with the host. + [MinVersion=1] Init@1(MidisHost host_ptr) => (); }; diff --git a/chromium/components/arc/common/net.mojom b/chromium/components/arc/common/net.mojom index c29a96e594c..d162a242564 100644 --- a/chromium/components/arc/common/net.mojom +++ b/chromium/components/arc/common/net.mojom @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Next MinVersion: 8 +// Next MinVersion: 9 module arc.mojom; @@ -162,6 +162,7 @@ struct AndroidVpnConfiguration { array domains@8; }; +// Next Method ID: 13 interface NetHost { // Sends a request to get enabled / disabled status of WiFi. GetWifiEnabledState@1() => (bool is_enabled); @@ -210,9 +211,13 @@ interface NetHost { [MinVersion=7] AndroidVpnStateChanged@12(ConnectionStateType state); }; +// Next Method ID: 7 interface NetInstance { + // DEPRECATED: Please use Init@6 instead. + InitDeprecated@0(NetHost host_ptr); + // Establishes full-duplex communication with the host. - Init@0(NetHost host_ptr); + [MinVersion=8] Init@6(NetHost host_ptr) => (); // Notifies the instance of a WiFI AP scan being completed. [MinVersion=1] ScanCompleted@1(); diff --git a/chromium/components/arc/common/notifications.mojom b/chromium/components/arc/common/notifications.mojom index ae9a48cc9d8..b63bde26697 100644 --- a/chromium/components/arc/common/notifications.mojom +++ b/chromium/components/arc/common/notifications.mojom @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 11 +// Next MinVersion: 15 module arc.mojom; import "bitmap.mojom"; +import "gfx.mojom"; // These values must be matched with the NOTIFICATION_EVENT_* constants in // com.android.server.ArcNotificationListenerService. @@ -55,6 +56,12 @@ enum ArcNotificationExpandState { EXPANDED = 2, }; +[Extensible, MinVersion=12] +enum ArcNotificationRemoteInputState { + CLOSED = 0, + OPENED = 1, +}; + // These values represent what shows in an ARC custom notification. [Extensible, MinVersion=11] enum ArcNotificationShownContents { @@ -120,6 +127,14 @@ struct ArcNotificationData { // Flag for what shows in a notification. [MinVersion=11] ArcNotificationShownContents shown_contents; + [MinVersion=12] + ArcNotificationRemoteInputState remote_input_state; + // Indicates a rect for which Android wants to handle swipe events for by + // itself. The coordinates in this Rect are in Android pixels and represent + // a sub-rectangle of the notification, with the origin being the top left + // of the notification. + [MinVersion=14] + Rect? swipe_input_rect; }; [MinVersion=2] @@ -137,9 +152,11 @@ struct ArcToastData { string? dismiss_text; }; +// Next Method ID: 6 interface NotificationsHost { // Tells the Chrome that a notification is posted (created or updated) on - // Android. + // Android. If you know that the notification exists, please consider to use + // OnNotificationUpdate instead. // |notification_data| is the data of notification (id, texts, icon and ...). OnNotificationPosted@0(ArcNotificationData notification_data); @@ -154,12 +171,20 @@ interface NotificationsHost { [MinVersion=2] // Hides the visible toast immediately, or cancels the scheduled one. OnToastCancelled@3(ArcToastData data); + + [MinVersion=13] + // Notifies that an existing notiication is updated on Android. + OnNotificationUpdated@5(ArcNotificationData notification_data); }; +// Next Method ID: 6 // TODO(lhchavez): Migrate all request/response messages to Mojo. interface NotificationsInstance { + // DEPRECATED: Please use Init@5 instead. + InitDeprecated@0(NotificationsHost host_ptr); + // Establishes full-duplex communication with the host. - Init@0(NotificationsHost host_ptr); + [MinVersion=14] Init@5(NotificationsHost host_ptr) => (); // Sends an event from Chrome notification UI to Android. // |event| is a type of occured event. diff --git a/chromium/components/arc/common/obb_mounter.mojom b/chromium/components/arc/common/obb_mounter.mojom index d47dcb6168b..d3659753320 100644 --- a/chromium/components/arc/common/obb_mounter.mojom +++ b/chromium/components/arc/common/obb_mounter.mojom @@ -2,8 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Next MinVersion: 2 + module arc.mojom; +// Next Method ID: 2 interface ObbMounterHost { // Mounts the specified OBB file to the target path, the owner GID will be set // to the specified value. @@ -15,6 +18,11 @@ interface ObbMounterHost { UnmountObb@1(string target_path) => (bool success); }; +// Next Method ID: 2 interface ObbMounterInstance { - Init@0(ObbMounterHost host_ptr); + // DEPRECATED: Please use Init@1 instead. + InitDeprecated@0(ObbMounterHost host_ptr); + + // Establishes full-duplex communication with the host. + [MinVersion=1] Init@1(ObbMounterHost host_ptr) => (); }; diff --git a/chromium/components/arc/common/oemcrypto.mojom b/chromium/components/arc/common/oemcrypto.mojom index b228cd0b8e7..9d43e224e5c 100644 --- a/chromium/components/arc/common/oemcrypto.mojom +++ b/chromium/components/arc/common/oemcrypto.mojom @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Next MinVersion: 2 + // The original version of this file lives in the Chromium repository at: // src/components/arc/common/oemcrypto.mojom @@ -225,7 +227,11 @@ interface OemCryptoHost { // OemCryptoInstance is implemented in the liboemcrypto.so library that runs in // Android and handles the Android side of the ArcBridge connection. -// Next Method ID: 1 +// Next Method ID: 2 interface OemCryptoInstance { - Init@0(OemCryptoHost host_ptr); + // DEPRECATED: Please use Init@1 instead. + InitDeprecated@0(OemCryptoHost host_ptr); + + // Establishes full-duplex communication with the host. + [MinVersion=1] Init@1(OemCryptoHost host_ptr) => (); }; diff --git a/chromium/components/arc/common/oemcrypto_daemon.mojom b/chromium/components/arc/common/oemcrypto_daemon.mojom index 5b2b7827eaa..b75db2d4efb 100644 --- a/chromium/components/arc/common/oemcrypto_daemon.mojom +++ b/chromium/components/arc/common/oemcrypto_daemon.mojom @@ -21,5 +21,5 @@ import "protected_buffer_manager.mojom"; // Next Method ID: 1 interface OemCryptoHostDaemon { Connect@0(arc.mojom.OemCryptoService& oemcryptor, - media.mojom.ProtectedBufferManager protected_buffer_manager); + arc.mojom.ProtectedBufferManager protected_buffer_manager); }; diff --git a/chromium/components/arc/common/policy.mojom b/chromium/components/arc/common/policy.mojom index 742d0e710cc..08294b4cabd 100644 --- a/chromium/components/arc/common/policy.mojom +++ b/chromium/components/arc/common/policy.mojom @@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 2 +// Next MinVersion: 3 module arc.mojom; +// Next Method ID: 2 interface PolicyHost { // Get policies from Chrome OS, as JSON-encoded dictionary with the policies' // names as keys and their values as values. The list of possible policies can @@ -19,9 +20,13 @@ interface PolicyHost { [MinVersion=1] ReportCompliance@1(string request) => (string response); }; +// Next Method ID: 3 interface PolicyInstance { + // DEPRECATED: Please use Init@2 instead. + InitDeprecated@0(PolicyHost host_ptr); + // Establishes full-duplex communication with the host. - Init@0(PolicyHost host_ptr); + [MinVersion=2] Init@2(PolicyHost host_ptr) => (); // Indicates some policies have changed OnPolicyUpdated@1(); diff --git a/chromium/components/arc/common/power.mojom b/chromium/components/arc/common/power.mojom index f2fc4d87de9..048f8c63ba8 100644 --- a/chromium/components/arc/common/power.mojom +++ b/chromium/components/arc/common/power.mojom @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Next min version: 4 +// Next MinVersion: 5 module arc.mojom; @@ -33,10 +33,13 @@ interface PowerHost { [MinVersion=3] OnScreenBrightnessUpdateRequest@3(double percent); }; -// Next method ID: 5 +// Next method ID: 6 interface PowerInstance { + // DEPRECATED: Please use Init@5 instead. + InitDeprecated@0(PowerHost host_ptr); + // Establishes full-duplex communication with the host. - Init@0(PowerHost host_ptr); + [MinVersion=4] Init@5(PowerHost host_ptr) => (); // Alerts the instance to a change in interactive state. [MinVersion=1] SetInteractive@1(bool enabled); diff --git a/chromium/components/arc/common/print.mojom b/chromium/components/arc/common/print.mojom index c72a7898726..3f03b7ff82c 100644 --- a/chromium/components/arc/common/print.mojom +++ b/chromium/components/arc/common/print.mojom @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 1 +// Next MinVersion: 2 module arc.mojom; @@ -11,8 +11,11 @@ interface PrintHost { Print@0(handle file); }; -// Next method ID: 1 +// Next method ID: 2 interface PrintInstance { + // DEPRECATED: Please use Init@1 instead. + InitDeprecated@0(PrintHost host_ptr); + // Establishes full-duplex communication with the host. - Init@0(PrintHost host_ptr); + [MinVersion=1] Init@1(PrintHost host_ptr) => (); }; diff --git a/chromium/components/arc/common/protected_buffer_manager.mojom b/chromium/components/arc/common/protected_buffer_manager.mojom index b226ea3d347..298f6d3bbf2 100644 --- a/chromium/components/arc/common/protected_buffer_manager.mojom +++ b/chromium/components/arc/common/protected_buffer_manager.mojom @@ -5,7 +5,7 @@ // The original version of this file lives in the Chromium repository at: // src/components/arc/common/protected_buffer_manager.mojom -module media.mojom; +module arc.mojom; // This interface is exposed by the GPU process for translating dummy handles // for secure buffers into a usable shared memory handle. The output of a diff --git a/chromium/components/arc/common/screen_rect.mojom b/chromium/components/arc/common/screen_rect.mojom deleted file mode 100644 index baafbcdd70e..00000000000 --- a/chromium/components/arc/common/screen_rect.mojom +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2016 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. - -module arc.mojom; - -// Represents a rectangle to specify screen coordinates. -struct ScreenRect { - int32 left; - int32 top; - int32 right; - int32 bottom; -}; diff --git a/chromium/components/arc/common/tts.mojom b/chromium/components/arc/common/tts.mojom index 4b7f044db11..b013a1b2c21 100644 --- a/chromium/components/arc/common/tts.mojom +++ b/chromium/components/arc/common/tts.mojom @@ -1,7 +1,7 @@ // Copyright 2016 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. -// Next MinVersion: 1 +// Next MinVersion: 2 module arc.mojom; @@ -30,10 +30,13 @@ interface TtsHost { string error_msg); }; -// Next Method ID: 3 +// Next Method ID: 4 interface TtsInstance { + // DEPRECATED: Please use Init@3 instead. + InitDeprecated@0(TtsHost host_ptr); + // Establishes full-duplex communication with the host. - Init@0(TtsHost host_ptr); + [MinVersion=1] Init@3(TtsHost host_ptr) => (); // Sends an utterance to Android for synthesis. Speak@1(TtsUtterance utterance); diff --git a/chromium/components/arc/common/typemaps.gni b/chromium/components/arc/common/typemaps.gni index 8902a9b60cb..62c81904348 100644 --- a/chromium/components/arc/common/typemaps.gni +++ b/chromium/components/arc/common/typemaps.gni @@ -3,14 +3,12 @@ # found in the LICENSE file. typemaps = [ - "//components/arc/common/app.typemap", "//components/arc/common/bitmap.typemap", "//components/arc/common/bluetooth.typemap", "//components/arc/common/file_system.typemap", - "//components/arc/common/ime.typemap", + "//components/arc/common/gfx.typemap", "//components/arc/common/intent_helper.typemap", "//components/arc/common/video_common.typemap", "//components/arc/common/video_encode_accelerator.typemap", - "//components/arc/common/voice_interaction_framework.typemap", "//components/arc/common/volume_mounter.typemap", ] diff --git a/chromium/components/arc/common/video.mojom b/chromium/components/arc/common/video.mojom index 42755ada236..9b048960057 100644 --- a/chromium/components/arc/common/video.mojom +++ b/chromium/components/arc/common/video.mojom @@ -2,12 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Next MinVersion: 6 + module arc.mojom; import "video_decode_accelerator.mojom"; import "video_encode_accelerator.mojom"; -// Next MinVersion: 5 // Deprecated method IDs: 0 // Next method ID: 2 interface VideoHost { @@ -19,15 +20,16 @@ interface VideoHost { string token); }; -// Next MinVersion: 1 -// Next method ID: 1 +// Next method ID: 2 interface VideoInstance { + // DEPRECATED: Please use Init@1 instead. + InitDeprecated@0(VideoHost host_ptr); + // Establishes full-duplex communication with the host. - Init@0(VideoHost host_ptr); + [MinVersion=5] Init@1(VideoHost host_ptr) => (); }; -// Next MinVersion: 2 -// Next method ID: 3 +// Next method ID: 2 interface VideoAcceleratorFactory { CreateDecodeAccelerator@0(VideoDecodeAccelerator& decoder); diff --git a/chromium/components/arc/common/video_accelerator_struct_traits.cc b/chromium/components/arc/common/video_accelerator_struct_traits.cc new file mode 100644 index 00000000000..a0061dc0324 --- /dev/null +++ b/chromium/components/arc/common/video_accelerator_struct_traits.cc @@ -0,0 +1,30 @@ +// Copyright 2016 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 "components/arc/common/video_accelerator_struct_traits.h" + +namespace mojo { + +// static +bool StructTraits:: + Read(arc::mojom::VideoFramePlaneDataView data, arc::VideoFramePlane* out) { + if (data.offset() < 0 || data.stride() < 0) + return false; + + out->offset = data.offset(); + out->stride = data.stride(); + return true; +} + +// static +bool StructTraits::Read( + arc::mojom::SizeDataView data, + gfx::Size* out) { + if (data.width() < 0 || data.height() < 0) + return false; + + out->SetSize(data.width(), data.height()); + return true; +} +} // namespace mojo diff --git a/chromium/components/arc/common/video_accelerator_struct_traits.h b/chromium/components/arc/common/video_accelerator_struct_traits.h new file mode 100644 index 00000000000..8c1ff484697 --- /dev/null +++ b/chromium/components/arc/common/video_accelerator_struct_traits.h @@ -0,0 +1,46 @@ +// Copyright 2016 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 COMPONENTS_ARC_COMMON_VIDEO_ACCELERATOR_STRUCT_TRAITS_H_ +#define COMPONENTS_ARC_COMMON_VIDEO_ACCELERATOR_STRUCT_TRAITS_H_ + +#include "components/arc/common/video_decode_accelerator.mojom.h" +#include "components/arc/video_accelerator/video_frame_plane.h" +#include "ui/gfx/geometry/size.h" + +namespace mojo { + +template <> +struct StructTraits { + static int32_t offset(const arc::VideoFramePlane& r) { + DCHECK_GE(r.offset, 0); + return r.offset; + } + + static int32_t stride(const arc::VideoFramePlane& r) { + DCHECK_GE(r.stride, 0); + return r.stride; + } + + static bool Read(arc::mojom::VideoFramePlaneDataView data, + arc::VideoFramePlane* out); +}; + +template <> +struct StructTraits { + static int width(const gfx::Size& r) { + DCHECK_GE(r.width(), 0); + return r.width(); + } + + static int height(const gfx::Size& r) { + DCHECK_GE(r.height(), 0); + return r.height(); + } + + static bool Read(arc::mojom::SizeDataView data, gfx::Size* out); +}; +} // namespace mojo + +#endif // COMPONENTS_ARC_COMMON_VIDEO_ACCELERATOR_STRUCT_TRAITS_H_ diff --git a/chromium/components/arc/common/video_common.typemap b/chromium/components/arc/common/video_common.typemap index 04e082d329e..3bc56045ac0 100644 --- a/chromium/components/arc/common/video_common.typemap +++ b/chromium/components/arc/common/video_common.typemap @@ -4,13 +4,15 @@ mojom = "//components/arc/common/video_common.mojom" public_headers = [ - "//components/arc/video_accelerator/video_accelerator.h", + "//components/arc/video_accelerator/video_frame_plane.h", "//ui/gfx/geometry/size.h", ] -traits_headers = - [ "//components/arc/video_accelerator/video_accelerator_struct_traits.h" ] +traits_headers = [ "//components/arc/common/video_accelerator_struct_traits.h" ] sources = [ - "//components/arc/video_accelerator/video_accelerator_struct_traits.cc", + "//components/arc/common/video_accelerator_struct_traits.cc", +] +deps = [ + "//ui/gfx/geometry", ] type_mappings = [ "arc.mojom.VideoFramePlane=arc::VideoFramePlane[move_only]", diff --git a/chromium/components/arc/common/video_decode_accelerator.mojom b/chromium/components/arc/common/video_decode_accelerator.mojom index bb732f96caa..530759453b8 100644 --- a/chromium/components/arc/common/video_decode_accelerator.mojom +++ b/chromium/components/arc/common/video_decode_accelerator.mojom @@ -40,6 +40,7 @@ struct VideoFormat { uint32 crop_height; }; +// Next MinVersion: 2 struct VideoDecodeAcceleratorConfig { // Deprecated. This config struct is used for decoder only. enum DeviceTypeDeprecated { @@ -51,11 +52,12 @@ struct VideoDecodeAcceleratorConfig { DeviceTypeDeprecated device_type_deprecated; uint32 num_input_buffers; uint32 input_pixel_format; + [MinVersion=1] bool secure_mode; }; -// Next MinVersion: 4 +// Next MinVersion: 5 // Deprecated method IDs: 2, 7 -// Next method ID: 10 +// Next method ID: 11 interface VideoDecodeAccelerator { enum Result { SUCCESS = 0, @@ -70,6 +72,10 @@ interface VideoDecodeAccelerator { Initialize@8(VideoDecodeAcceleratorConfig config, VideoDecodeClient client) => (Result result); + [MinVersion=4] + AllocateProtectedBuffer@10(PortType port, uint32 index, handle handle_fd, + uint64 size) => (bool result); + BindSharedMemory@1(PortType port, uint32 index, handle ashmem_fd, uint32 offset, uint32 length); diff --git a/chromium/components/arc/common/video_encode_accelerator.mojom b/chromium/components/arc/common/video_encode_accelerator.mojom index 2aaf61e541b..9278f3b0310 100644 --- a/chromium/components/arc/common/video_encode_accelerator.mojom +++ b/chromium/components/arc/common/video_encode_accelerator.mojom @@ -59,7 +59,10 @@ enum VideoCodecProfile { THEORAPROFILE_MIN = 23, THEORAPROFILE_ANY = THEORAPROFILE_MIN, THEORAPROFILE_MAX = THEORAPROFILE_ANY, - VIDEO_CODEC_PROFILE_MAX = THEORAPROFILE_ANY, + AV1PROFILE_MIN = 24, + AV1PROFILE_PROFILE0 = AV1PROFILE_MIN, + AV1PROFILE_MAX = AV1PROFILE_PROFILE0, + VIDEO_CODEC_PROFILE_MAX = AV1PROFILE_PROFILE0, }; // Specification of an encoding profile supported by an encoder. @@ -72,7 +75,7 @@ struct VideoEncodeProfile { // Video encoder IPC interface. // Next MinVersion: 1 -// Next Method ID: 5 +// Next Method ID: 6 interface VideoEncodeAccelerator { // The input buffer storage type. @@ -162,6 +165,14 @@ interface VideoEncodeAccelerator { // |framerate| is the requested new framerate, in frames per second. RequestEncodingParametersChange@4(uint32 bitrate, uint32 framerate); + + // Flushes the encoder: all pending inputs will be encoded and all bitstreams + // handed back to the client. The client should not invoke Flush() or + // Encode() before the previous Flush() is finished. + // Callback: + // Called with |true| if Flush() is complete; with |false| if Flush() is + // canceled. + Flush@5() => (bool flush_done); }; // Interface for clients that use VideoEncodeAccelerator. These callbacks will diff --git a/chromium/components/arc/common/video_encode_accelerator.typemap b/chromium/components/arc/common/video_encode_accelerator.typemap index 61b8db22915..a7453766a3f 100644 --- a/chromium/components/arc/common/video_encode_accelerator.typemap +++ b/chromium/components/arc/common/video_encode_accelerator.typemap @@ -5,11 +5,12 @@ mojom = "//components/arc/common/video_encode_accelerator.mojom" public_headers = [ "//media/video/video_encode_accelerator.h" ] public_deps = [ - "//media", + "//media/gpu", ] -traits_headers = [ "//components/arc/video_accelerator/video_encode_accelerator_struct_traits.h" ] +traits_headers = + [ "//components/arc/common/video_encode_accelerator_struct_traits.h" ] sources = [ - "//components/arc/video_accelerator/video_encode_accelerator_struct_traits.cc", + "//components/arc/common/video_encode_accelerator_struct_traits.cc", ] type_mappings = [ "arc.mojom.VideoEncodeAccelerator.Error=media::VideoEncodeAccelerator::Error", diff --git a/chromium/components/arc/common/video_encode_accelerator_struct_traits.cc b/chromium/components/arc/common/video_encode_accelerator_struct_traits.cc new file mode 100644 index 00000000000..d1fee57cb23 --- /dev/null +++ b/chromium/components/arc/common/video_encode_accelerator_struct_traits.cc @@ -0,0 +1,169 @@ +// Copyright 2017 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 "components/arc/common/video_encode_accelerator_struct_traits.h" + +namespace mojo { + +// Make sure values in arc::mojom::VideoEncodeAccelerator::Error and +// media::VideoEncodeAccelerator::Error match. +#define CHECK_ERROR_ENUM(value) \ + static_assert( \ + static_cast(arc::mojom::VideoEncodeAccelerator::Error::value) == \ + media::VideoEncodeAccelerator::Error::value, \ + "enum ##value mismatch") + +CHECK_ERROR_ENUM(kIllegalStateError); +CHECK_ERROR_ENUM(kInvalidArgumentError); +CHECK_ERROR_ENUM(kPlatformFailureError); +CHECK_ERROR_ENUM(kErrorMax); + +#undef CHECK_ERROR_ENUM + +// static +arc::mojom::VideoEncodeAccelerator::Error +EnumTraits:: + ToMojom(media::VideoEncodeAccelerator::Error input) { + return static_cast(input); +} + +// static +bool EnumTraits:: + FromMojom(arc::mojom::VideoEncodeAccelerator::Error input, + media::VideoEncodeAccelerator::Error* output) { + NOTIMPLEMENTED(); + return false; +} + +// Make sure values in arc::mojom::VideoPixelFormat match to the values in +// media::VideoPixelFormat. The former is a subset of the later. +#define CHECK_PIXEL_FORMAT_ENUM(value) \ + static_assert( \ + static_cast(arc::mojom::VideoPixelFormat::value) == media::value, \ + "enum ##value mismatch") + +CHECK_PIXEL_FORMAT_ENUM(PIXEL_FORMAT_I420); + +#undef CHECK_PXIEL_FORMAT_ENUM + +// static +arc::mojom::VideoPixelFormat +EnumTraits::ToMojom( + media::VideoPixelFormat input) { + NOTIMPLEMENTED(); + return arc::mojom::VideoPixelFormat::PIXEL_FORMAT_I420; +} + +// static +bool EnumTraits:: + FromMojom(arc::mojom::VideoPixelFormat input, + media::VideoPixelFormat* output) { + switch (input) { + case arc::mojom::VideoPixelFormat::PIXEL_FORMAT_I420: + *output = static_cast(input); + return true; + default: + DLOG(ERROR) << "Unknown VideoPixelFormat: " << input; + return false; + } +} + +// Make sure values in arc::mojom::VideoCodecProfile match to the values in +// media::VideoCodecProfile. +#define CHECK_PROFILE_ENUM(value) \ + static_assert( \ + static_cast(arc::mojom::VideoCodecProfile::value) == media::value, \ + "enum ##value mismatch") + +CHECK_PROFILE_ENUM(VIDEO_CODEC_PROFILE_UNKNOWN); +CHECK_PROFILE_ENUM(VIDEO_CODEC_PROFILE_MIN); +CHECK_PROFILE_ENUM(H264PROFILE_MIN); +CHECK_PROFILE_ENUM(H264PROFILE_BASELINE); +CHECK_PROFILE_ENUM(H264PROFILE_MAIN); +CHECK_PROFILE_ENUM(H264PROFILE_EXTENDED); +CHECK_PROFILE_ENUM(H264PROFILE_HIGH); +CHECK_PROFILE_ENUM(H264PROFILE_HIGH10PROFILE); +CHECK_PROFILE_ENUM(H264PROFILE_HIGH422PROFILE); +CHECK_PROFILE_ENUM(H264PROFILE_HIGH444PREDICTIVEPROFILE); +CHECK_PROFILE_ENUM(H264PROFILE_SCALABLEBASELINE); +CHECK_PROFILE_ENUM(H264PROFILE_SCALABLEHIGH); +CHECK_PROFILE_ENUM(H264PROFILE_STEREOHIGH); +CHECK_PROFILE_ENUM(H264PROFILE_MULTIVIEWHIGH); +CHECK_PROFILE_ENUM(H264PROFILE_MAX); +CHECK_PROFILE_ENUM(VP8PROFILE_MIN); +CHECK_PROFILE_ENUM(VP8PROFILE_ANY); +CHECK_PROFILE_ENUM(VP8PROFILE_MAX); +CHECK_PROFILE_ENUM(VP9PROFILE_MIN); +CHECK_PROFILE_ENUM(VP9PROFILE_PROFILE0); +CHECK_PROFILE_ENUM(VP9PROFILE_PROFILE1); +CHECK_PROFILE_ENUM(VP9PROFILE_PROFILE2); +CHECK_PROFILE_ENUM(VP9PROFILE_PROFILE3); +CHECK_PROFILE_ENUM(VP9PROFILE_MAX); +CHECK_PROFILE_ENUM(HEVCPROFILE_MIN); +CHECK_PROFILE_ENUM(HEVCPROFILE_MAIN); +CHECK_PROFILE_ENUM(HEVCPROFILE_MAIN10); +CHECK_PROFILE_ENUM(HEVCPROFILE_MAIN_STILL_PICTURE); +CHECK_PROFILE_ENUM(HEVCPROFILE_MAX); +CHECK_PROFILE_ENUM(DOLBYVISION_MIN); +CHECK_PROFILE_ENUM(DOLBYVISION_PROFILE0); +CHECK_PROFILE_ENUM(DOLBYVISION_PROFILE4); +CHECK_PROFILE_ENUM(DOLBYVISION_PROFILE5); +CHECK_PROFILE_ENUM(DOLBYVISION_PROFILE7); +CHECK_PROFILE_ENUM(DOLBYVISION_MAX); +CHECK_PROFILE_ENUM(THEORAPROFILE_MIN); +CHECK_PROFILE_ENUM(THEORAPROFILE_ANY); +CHECK_PROFILE_ENUM(THEORAPROFILE_MAX); +CHECK_PROFILE_ENUM(AV1PROFILE_PROFILE0); +CHECK_PROFILE_ENUM(VIDEO_CODEC_PROFILE_MAX); + +#undef CHECK_PROFILE_ENUM + +// static +arc::mojom::VideoCodecProfile +EnumTraits::ToMojom( + media::VideoCodecProfile input) { + return static_cast(input); +} + +// static +bool EnumTraits:: + FromMojom(arc::mojom::VideoCodecProfile input, + media::VideoCodecProfile* output) { + switch (input) { + case arc::mojom::VideoCodecProfile::VIDEO_CODEC_PROFILE_UNKNOWN: + case arc::mojom::VideoCodecProfile::H264PROFILE_BASELINE: + case arc::mojom::VideoCodecProfile::H264PROFILE_MAIN: + case arc::mojom::VideoCodecProfile::H264PROFILE_EXTENDED: + case arc::mojom::VideoCodecProfile::H264PROFILE_HIGH: + case arc::mojom::VideoCodecProfile::H264PROFILE_HIGH10PROFILE: + case arc::mojom::VideoCodecProfile::H264PROFILE_HIGH422PROFILE: + case arc::mojom::VideoCodecProfile::H264PROFILE_HIGH444PREDICTIVEPROFILE: + case arc::mojom::VideoCodecProfile::H264PROFILE_SCALABLEBASELINE: + case arc::mojom::VideoCodecProfile::H264PROFILE_SCALABLEHIGH: + case arc::mojom::VideoCodecProfile::H264PROFILE_STEREOHIGH: + case arc::mojom::VideoCodecProfile::H264PROFILE_MULTIVIEWHIGH: + case arc::mojom::VideoCodecProfile::VP8PROFILE_ANY: + case arc::mojom::VideoCodecProfile::VP9PROFILE_PROFILE0: + case arc::mojom::VideoCodecProfile::VP9PROFILE_PROFILE1: + case arc::mojom::VideoCodecProfile::VP9PROFILE_PROFILE2: + case arc::mojom::VideoCodecProfile::VP9PROFILE_PROFILE3: + case arc::mojom::VideoCodecProfile::HEVCPROFILE_MAIN: + case arc::mojom::VideoCodecProfile::HEVCPROFILE_MAIN10: + case arc::mojom::VideoCodecProfile::HEVCPROFILE_MAIN_STILL_PICTURE: + case arc::mojom::VideoCodecProfile::DOLBYVISION_PROFILE0: + case arc::mojom::VideoCodecProfile::DOLBYVISION_PROFILE4: + case arc::mojom::VideoCodecProfile::DOLBYVISION_PROFILE5: + case arc::mojom::VideoCodecProfile::DOLBYVISION_PROFILE7: + case arc::mojom::VideoCodecProfile::THEORAPROFILE_ANY: + case arc::mojom::VideoCodecProfile::AV1PROFILE_PROFILE0: + *output = static_cast(input); + return true; + } + DLOG(ERROR) << "unknown profile: " << input; + return false; +} + +} // namespace mojo diff --git a/chromium/components/arc/common/video_encode_accelerator_struct_traits.h b/chromium/components/arc/common/video_encode_accelerator_struct_traits.h new file mode 100644 index 00000000000..060b2ad4277 --- /dev/null +++ b/chromium/components/arc/common/video_encode_accelerator_struct_traits.h @@ -0,0 +1,68 @@ +// Copyright 2017 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 COMPONENTS_ARC_COMMON_VIDEO_ENCODE_ACCELERATOR_STRUCT_TRAITS_H_ +#define COMPONENTS_ARC_COMMON_VIDEO_ENCODE_ACCELERATOR_STRUCT_TRAITS_H_ + +#include "components/arc/common/video_encode_accelerator.mojom.h" +#include "media/video/video_encode_accelerator.h" + +namespace mojo { + +template <> +struct EnumTraits { + static arc::mojom::VideoEncodeAccelerator::Error ToMojom( + media::VideoEncodeAccelerator::Error input); + + static bool FromMojom(arc::mojom::VideoEncodeAccelerator::Error input, + media::VideoEncodeAccelerator::Error* output); +}; + +template <> +struct EnumTraits { + static arc::mojom::VideoPixelFormat ToMojom(media::VideoPixelFormat input); + + static bool FromMojom(arc::mojom::VideoPixelFormat input, + media::VideoPixelFormat* output); +}; + +template <> +struct EnumTraits { + static arc::mojom::VideoCodecProfile ToMojom(media::VideoCodecProfile input); + + static bool FromMojom(arc::mojom::VideoCodecProfile input, + media::VideoCodecProfile* output); +}; + +template <> +struct StructTraits { + static media::VideoCodecProfile profile( + const media::VideoEncodeAccelerator::SupportedProfile& r) { + return r.profile; + } + static const gfx::Size& max_resolution( + const media::VideoEncodeAccelerator::SupportedProfile& r) { + return r.max_resolution; + } + static uint32_t max_framerate_numerator( + const media::VideoEncodeAccelerator::SupportedProfile& r) { + return r.max_framerate_numerator; + } + static uint32_t max_framerate_denominator( + const media::VideoEncodeAccelerator::SupportedProfile& r) { + return r.max_framerate_denominator; + } + + static bool Read(arc::mojom::VideoEncodeProfileDataView data, + media::VideoEncodeAccelerator::SupportedProfile* out) { + NOTIMPLEMENTED(); + return false; + } +}; + +} // namespace mojo + +#endif // COMPONENTS_ARC_COMMON_VIDEO_ENCODE_ACCELERATOR_STRUCT_TRAITS_H_ diff --git a/chromium/components/arc/common/voice_interaction_arc_home.mojom b/chromium/components/arc/common/voice_interaction_arc_home.mojom index 4db7ffffbd9..ebe7be2e898 100644 --- a/chromium/components/arc/common/voice_interaction_arc_home.mojom +++ b/chromium/components/arc/common/voice_interaction_arc_home.mojom @@ -2,19 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 3 +// Next MinVersion: 4 module arc.mojom; +import "gfx.mojom"; import "mojo/common/string16.mojom"; -import "screen_rect.mojom"; - -// Represents the start and end unicode char indices of the selected -// portion of the text [start, end). -struct TextSelection { - int32 start_selection; - int32 end_selection; -}; // Represents view structure to be passed to ARC. The view // structure is synthesized from the AXStructure, which @@ -24,7 +17,7 @@ struct TextSelection { // AccessibilitySnapshotNode.java used in Android Chromium. struct VoiceInteractionStructure { // Geometry of the view in pixels - ScreenRect rect; + Rect rect; // Text of the view. mojo.common.mojom.String16 text; @@ -39,7 +32,7 @@ struct VoiceInteractionStructure { bool line_through; // Selected portion of the text. - TextSelection? selection; + Range? selection; // Fake Android view class name of the element. Each node is assigned // a closest approximation of Android's views. @@ -67,7 +60,11 @@ interface VoiceInteractionArcHomeHost { }; // Connects with ArcHome. -// Next method ID: 1 +// Next method ID: 2 interface VoiceInteractionArcHomeInstance { - Init@0(VoiceInteractionArcHomeHost host_ptr); + // DEPRECATED: Please use Init@1 instead. + InitDeprecated@0(VoiceInteractionArcHomeHost host_ptr); + + // Establishes full-duplex communication with the host. + [MinVersion=3] Init@1(VoiceInteractionArcHomeHost host_ptr) => (); }; diff --git a/chromium/components/arc/common/voice_interaction_framework.mojom b/chromium/components/arc/common/voice_interaction_framework.mojom index 53e33f53b6c..2aedfa1fea7 100644 --- a/chromium/components/arc/common/voice_interaction_framework.mojom +++ b/chromium/components/arc/common/voice_interaction_framework.mojom @@ -2,11 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 13 +// Next MinVersion: 14 module arc.mojom; -import "screen_rect.mojom"; +import "gfx.mojom"; + +// There is another copy of the VoiceInteractionState definition in +// //ash/public/interfaces/voice_interaction_controller.mojom +// Please also update the other one if you change it. +// The duplicate definition is because we do not use extensible widely +// (crbug.com/731893). [Extensible] enum VoiceInteractionState { @@ -17,21 +23,12 @@ enum VoiceInteractionState { // Handles voice interaction queries from Android. // Next method ID: 6 -// Deprecated method ID: 0 +// Deprecated method ID: 0, 2, 3, 4 interface VoiceInteractionFrameworkHost { // Returns a fullscreen screenshot of the primary display. // |data| represents the image encoded in JPEG format. [MinVersion=1]CaptureFullscreen@1() => (array data); - // Notifies the host that the metalayer has closed or could not open. - [MinVersion=2]OnMetalayerClosed@2(); - - // Enables/disables screenshot taking. - [MinVersion=3]SetMetalayerEnabled@3(bool enabled); - - // Notifies Chrome whether voice interaction session is running. - [MinVersion=6]SetVoiceInteractionRunning@4(bool running); - // Notifies Chrome the state of voice interaction session. [MinVersion=8]SetVoiceInteractionState@5(VoiceInteractionState state); }; @@ -49,10 +46,14 @@ struct VoiceInteractionStatus { }; // Connects with Android system server. -// Next method ID: 11 +// Next method ID: 12 // Deprecated method ID: 4 interface VoiceInteractionFrameworkInstance { - Init@0(VoiceInteractionFrameworkHost host_ptr); + // DEPRECATED: Please use Init@11 instead. + InitDeprecated@0(VoiceInteractionFrameworkHost host_ptr); + + // Establishes full-duplex communication with the host. + [MinVersion=13] Init@11(VoiceInteractionFrameworkHost host_ptr) => (); // Starts the voice interaction session in container. // |homescreen_is_active| is true if the session was invoked when homescreen is active. @@ -64,7 +65,7 @@ interface VoiceInteractionFrameworkInstance { // Starts the voice interaction session in container, with a screen region // selected. - [MinVersion=1] StartVoiceInteractionSessionForRegion@2(ScreenRect region); + [MinVersion=1] StartVoiceInteractionSessionForRegion@2(Rect region); // Shows/hides the metalayer in the container. [MinVersion=1] SetMetalayerVisibility@3([MinVersion=2] bool visible); diff --git a/chromium/components/arc/common/voice_interaction_framework.typemap b/chromium/components/arc/common/voice_interaction_framework.typemap deleted file mode 100644 index 825471951f7..00000000000 --- a/chromium/components/arc/common/voice_interaction_framework.typemap +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2017 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. - -mojom = "//components/arc/common/voice_interaction_framework.mojom" -public_headers = [ "//ash/public/cpp/voice_interaction_state.h" ] -public_deps = [ - "//ash/public/cpp:ash_public_cpp", -] -traits_headers = - [ "//components/arc/voice_interaction/voice_interaction_struct_traits.h" ] -sources = [] -type_mappings = [ "arc.mojom.VoiceInteractionState=ash::VoiceInteractionState" ] diff --git a/chromium/components/arc/common/volume_mounter.typemap b/chromium/components/arc/common/volume_mounter.typemap index 6198166d87e..0b905728284 100644 --- a/chromium/components/arc/common/volume_mounter.typemap +++ b/chromium/components/arc/common/volume_mounter.typemap @@ -3,14 +3,16 @@ # found in the LICENSE file. mojom = "//components/arc/common/volume_mounter.mojom" -public_headers = [ "//chromeos/disks/disk_mount_manager.h" ] +public_headers = [ + "//chromeos/chromeos_export.h", + "//chromeos/dbus/cros_disks_client.h", + "//chromeos/dbus/dbus_client_implementation_type.h", + "//chromeos/disks/disk_mount_manager.h", +] traits_headers = [ "//components/arc/volume_mounter/volume_mounter_traits.h" ] sources = [ "//components/arc/volume_mounter/volume_mounter_traits.cc", ] -deps = [ - "//chromeos", -] type_mappings = [ "arc.mojom.DeviceType=chromeos::DeviceType", "arc.mojom.MountEvent=chromeos::disks::DiskMountManager::MountEvent", diff --git a/chromium/components/arc/common/wallpaper.mojom b/chromium/components/arc/common/wallpaper.mojom index d2dd78dc52f..3048e4560a7 100644 --- a/chromium/components/arc/common/wallpaper.mojom +++ b/chromium/components/arc/common/wallpaper.mojom @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Next MinVersion: 3 +// Next MinVersion: 4 module arc.mojom; // Handles wallpaper calls from ARC in Chrome. -// Next method ID:3 +// Next method ID: 3 interface WallpaperHost { // Gets current wallpaper encoded in PNG and send it back to ARC. GetWallpaper@0() => (array wallpaper); @@ -21,10 +21,13 @@ interface WallpaperHost { }; // Connects with container side to publish wallpaper related intents. -// Next method ID:3 +// Next method ID: 4 interface WallpaperInstance { - // Establishes communication with the container side. - Init@0(WallpaperHost host_ptr); + // DEPRECATED: Please use Init@3 instead. + InitDeprecated@0(WallpaperHost host_ptr); + + // Establishes full-duplex communication with the host. + [MinVersion=3] Init@3(WallpaperHost host_ptr) => (); // Notifies ArcWallpaperManagerService that wallpaper is changed. [MinVersion=1] OnWallpaperChanged@1([MinVersion=2] int32 wallpaper_id); diff --git a/chromium/components/arc/connection_holder.h b/chromium/components/arc/connection_holder.h new file mode 100644 index 00000000000..72cd6478cc3 --- /dev/null +++ b/chromium/components/arc/connection_holder.h @@ -0,0 +1,386 @@ +// Copyright 2015 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 COMPONENTS_ARC_CONNECTION_HOLDER_H_ +#define COMPONENTS_ARC_CONNECTION_HOLDER_H_ + +#include +#include +#include +#include + +#include "base/bind.h" +#include "base/macros.h" +#include "base/observer_list.h" +#include "base/threading/thread_checker.h" +#include "components/arc/connection_notifier.h" +#include "components/arc/connection_observer.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/interface_ptr.h" +#include "mojo/public/cpp/bindings/interface_request.h" + +// A macro to call +// ConnectionHolder::GetInstanceForVersionDoNotCallDirectly(). In order to +// avoid exposing method names from within the Mojo bindings, we will rely on +// stringification and the fact that the method min versions have a consistent +// naming scheme. +#define ARC_GET_INSTANCE_FOR_METHOD(holder, method_name) \ + (holder)->GetInstanceForVersionDoNotCallDirectly( \ + std::remove_pointer::type::Instance::k##method_name##MinVersion, \ + #method_name) + +namespace arc { + +namespace internal { + +// Small helper to implement HasInit<> trait below. +// Note that only Check() declaration is needed. +// - If InstanceType::Init exists, Check(InstanceType()) would return +// std::true_type, because 1) the template param is successfully substituted, +// and 2) Check(...) is weaker than the template's so there is no overload +// conflict. +// - If not, Check(InstanceType()) would return std::false_type, because +// template param substitution is failed, but it won't be compile error +// thanks to SFINAE, thus Check(...) is the only candidate. +struct HasInitImpl { + template + static auto Check(InstanceType* v) + -> decltype(&InstanceType::Init, std::true_type()); + static std::false_type Check(...); +}; + +// Type trait to return whether InstanceType has Init() or not. +template +using HasInit = + decltype(HasInitImpl::Check(static_cast(nullptr))); + +// Same as above, but for InstanceType::InitDeprecated. +struct HasInitDeprecatedImpl { + template + static auto Check(InstanceType* v) + -> decltype(&InstanceType::InitDeprecated, std::true_type()); + static std::false_type Check(...); +}; + +// Type trait to return whether InstanceType has InitDeprecated() or not. +template +using HasInitDeprecated = + decltype(HasInitDeprecatedImpl::Check(static_cast(nullptr))); + +// Templates to count the number of arguments in a function. This is used to +// distinguish between interfaces that do not declare an Init() method, a +// one-argument (single-duplex) Init() and the two-argument (full-duplex) +// Init(). +// TODO(crbug.com/750563): Simplify the templates once InitDeprecated() is +// removed. +template +struct CountInitArgsImpl; + +template +struct CountInitArgsImpl { + static constexpr size_t value = sizeof...(Args); +}; + +template +struct Void { + typedef void type; +}; + +template +struct CountInitArgs { + static constexpr size_t value = 0; +}; + +template +struct CountInitArgs::type> { + static constexpr size_t value = CountInitArgsImpl::value; +}; + +// Full duplex Mojo connection holder implementation. +// InstanceType and HostType are Mojo interface types (arc::mojom::XxxInstance, +// and arc::mojom::XxxHost respectively). +template +class ConnectionHolderImpl { + public: + explicit ConnectionHolderImpl(ConnectionNotifier* connection_notifier) + : connection_notifier_(connection_notifier), weak_ptr_factory_(this) {} + + InstanceType* instance() { return instance_; } + uint32_t instance_version() const { return instance_version_; } + + // Returns true if |binding_| is set. + bool IsConnected() const { return binding_.get(); } + + // Sets (or resets if |host| is nullptr) the host. + void SetHost(HostType* host) { + // Some tests overwrite host, now. It is safe iff the |instance_| is + // not yet set. + // TODO(hidehiko): Make check more strict. + DCHECK(host == nullptr || host_ == nullptr || instance_ == nullptr); + + if (host_ == host) + return; + + host_ = host; + OnChanged(); + } + + // Sets (or resets if |instance| is nullptr) the instance. + void SetInstance(InstanceType* instance, + uint32_t version = InstanceType::version_) { + DCHECK(instance == nullptr || instance_ == nullptr); + + // Note: This can be called with nullptr even if |instance_| is still + // nullptr for just in case clean up purpose. No-op in such a case. + if (instance == instance_) + return; + + instance_ = instance; + instance_version_ = version; + OnChanged(); + } + + private: + // Called when |instance_| or |host_| is updated from null to non-null or + // from non-null to null. + void OnChanged() { + if (instance_ && host_) { + // When both get ready, start connection. + // TODO(crbug.com/750563): Fix the race issue. + binding_ = std::make_unique>(host_); + mojo::InterfacePtr host_proxy; + binding_->Bind(mojo::MakeRequest(&host_proxy)); + // Note: because the callback will be destroyed with |binding_|, + // base::Unretained() can be safely used. + binding_->set_connection_error_handler(base::BindOnce( + &mojo::Binding::Close, base::Unretained(binding_.get()))); + + // Call the appropriate version of Init(). + CallInstanceInit(std::move(host_proxy), + HasInitDeprecated()); + } else if (binding_.get()) { + // Otherwise, the connection is closed. If it was connected, + // reset the host binding and notify. + binding_.reset(); + connection_notifier_->NotifyConnectionClosed(); + } + } + + // Dispatches the correct version of Init(). The template type is needed + // because std::enable_if<> needs to depend on a template parameter in order + // for SFINAE to work. The second parameter (std::true_type or + // std::false_type) refers to whether InstanceType::DeprecatedInit() exists. + template + typename std::enable_if::value == 2, void>::type + CallInstanceInit(mojo::InterfacePtr host_proxy, std::true_type) { + if (instance_version_ < InstanceType::kInitMinVersion) { + // The instance is too old to know about the new Init() version. For now, + // call the deprecated version for backwards-compatibility. + // TODO(crbug.com/750563): Deprecate this version. + CallInstanceInitDeprecated(std::move(host_proxy), + HasInitDeprecated()); + return; + } + + instance_->Init(std::move(host_proxy), + base::BindOnce(&ConnectionHolderImpl::OnConnectionReady, + weak_ptr_factory_.GetWeakPtr())); + } + + template + typename std::enable_if::value == 2, void>::type + CallInstanceInit(mojo::InterfacePtr host_proxy, std::false_type) { + instance_->Init(std::move(host_proxy), + base::BindOnce(&ConnectionHolderImpl::OnConnectionReady, + weak_ptr_factory_.GetWeakPtr())); + } + + // TODO(crbug.com/750563): Deprecate this version. + template + typename std::enable_if::value == 1, void>::type + CallInstanceInit(mojo::InterfacePtr host_proxy, ...) { + instance_->Init(std::move(host_proxy)); + OnConnectionReady(); + } + + void CallInstanceInitDeprecated(mojo::InterfacePtr host_proxy, + std::true_type) { + instance_->InitDeprecated(std::move(host_proxy)); + OnConnectionReady(); + } + + void CallInstanceInitDeprecated(mojo::InterfacePtr host_proxy, + std::false_type) { + // If InitDeprecated does not exists, ARC container must support + // Init() with callback, already. Thus, this should not be called. + NOTREACHED(); + } + + // Notifies all the observers that the connection is ready. + void OnConnectionReady() { connection_notifier_->NotifyConnectionReady(); } + + // This class does not have ownership. The pointers should be managed by the + // caller. + ConnectionNotifier* const connection_notifier_; + InstanceType* instance_ = nullptr; + uint32_t instance_version_ = 0; + HostType* host_ = nullptr; + + // Created when both |instance_| and |host_| ptr are set. + std::unique_ptr> binding_; + + base::WeakPtrFactory weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(ConnectionHolderImpl); +}; + +// Single direction Mojo connection holder implementation. +// (HostType == void means single direction). +// InstanceType should be Mojo interface type (arc::mojom::XxxInstance). +template +class ConnectionHolderImpl { + public: + // InstanceType must not have Init() method, which should be for a + // full-duplex connection. + static_assert(!HasInit::value, + "Full duplex ConnectionHolderImpl should be used instead"); + + explicit ConnectionHolderImpl(ConnectionNotifier* connection_notifier) + : connection_notifier_(connection_notifier) {} + + InstanceType* instance() { return instance_; } + uint32_t instance_version() const { return instance_version_; } + + // For single direction connection, when Instance proxy is obtained, + // it means connected. + bool IsConnected() const { return instance_; } + + void SetHost(void* unused) { + static_assert(!sizeof(*this), + "ConnectionHolder::SetHost for single direction connection " + "is called unexpectedly."); + NOTREACHED(); + } + + // Sets (or resets if |instance| is nullptr) the instance. + void SetInstance(InstanceType* instance, + uint32_t version = InstanceType::version_) { + DCHECK(instance == nullptr || instance_ == nullptr); + + // Note: This can be called with nullptr even if |instance_| is still + // nullptr for just in case clean up purpose. No-op in such a case. + if (instance == instance_) + return; + + instance_ = instance; + instance_version_ = version; + + // There is nothing more than setting in this case. Notify observers. + if (instance_) + connection_notifier_->NotifyConnectionReady(); + else + connection_notifier_->NotifyConnectionClosed(); + } + + private: + // This class does not have ownership. The pointers should be managed by the + // caller. + ConnectionNotifier* const connection_notifier_; + InstanceType* instance_ = nullptr; + uint32_t instance_version_ = 0; + + DISALLOW_COPY_AND_ASSIGN(ConnectionHolderImpl); +}; + +} // namespace internal + +// Holds a Mojo connection. This also allows for listening for state changes +// for the particular connection. +// InstanceType and HostType should be Mojo interface type +// (arc::mojom::XxxInstance and arc::mojom::XxxHost respectively). +// If HostType is void, it is single direction Mojo connection, so it only +// looks at Instance pointer. +// Otherwise, it is full duplex Mojo connection. When both Instance and Host +// pointers are set, it calls Instance::Init() method to pass Host pointer +// to the ARC container. +template +class ConnectionHolder { + public: + using Observer = ConnectionObserver; + using Instance = InstanceType; + + ConnectionHolder() = default; + + // Returns true if the Mojo interface is ready at least for its version 0 + // interface. Use an Observer if you want to be notified when this is ready. + // This can only be called on the thread that this class was created on. + bool IsConnected() const { return impl_.IsConnected(); } + + // Gets the Mojo interface that's intended to call for + // |method_name_for_logging|, but only if its reported version is at least + // |min_version|. Returns nullptr if the connection is either not ready or + // the instance does not have the requested version, and logs appropriately. + // This function should not be called directly. Instead, use the + // ARC_GET_INSTANCE_FOR_METHOD() macro. + InstanceType* GetInstanceForVersionDoNotCallDirectly( + uint32_t min_version, + const char method_name_for_logging[]) { + if (!impl_.IsConnected()) { + VLOG(1) << "Instance " << InstanceType::Name_ << " not available."; + return nullptr; + } + if (impl_.instance_version() < min_version) { + LOG(ERROR) << "Instance for " << InstanceType::Name_ + << "::" << method_name_for_logging + << " version mismatch. Expected " << min_version << " got " + << impl_.instance_version(); + return nullptr; + } + return impl_.instance(); + } + + // Adds or removes observers. This can only be called on the thread that this + // class was created on. RemoveObserver does nothing if |observer| is not in + // the list. + void AddObserver(Observer* observer) { + connection_notifier_.AddObserver(observer); + if (impl_.IsConnected()) + connection_notifier_.NotifyConnectionReady(); + } + + void RemoveObserver(Observer* observer) { + connection_notifier_.RemoveObserver(observer); + } + + // Sets |host|. This can be called in both cases; on ready, or on closed. + // Passing nullptr to |host| means closing. + // This must not be called if HostType is void (i.e. single direciton + // connection). + void SetHost(HostType* host) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + impl_.SetHost(host); + } + + // Sets |instance| with |version|. + // This can be called in both case; on ready, and on closed. + // Passing nullptr to |instance| means closing. + void SetInstance(InstanceType* instance, + uint32_t version = InstanceType::Version_) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + impl_.SetInstance(instance, version); + } + + private: + THREAD_CHECKER(thread_checker_); + internal::ConnectionNotifier connection_notifier_; + internal::ConnectionHolderImpl impl_{ + &connection_notifier_}; + + DISALLOW_COPY_AND_ASSIGN(ConnectionHolder); +}; + +} // namespace arc + +#endif // COMPONENTS_ARC_CONNECTION_HOLDER_H_ diff --git a/chromium/components/arc/connection_notifier.cc b/chromium/components/arc/connection_notifier.cc new file mode 100644 index 00000000000..b3b1e17aab0 --- /dev/null +++ b/chromium/components/arc/connection_notifier.cc @@ -0,0 +1,39 @@ +// Copyright 2017 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 "components/arc/connection_notifier.h" + +#include "components/arc/connection_observer.h" + +namespace arc { +namespace internal { + +ConnectionNotifier::ConnectionNotifier() = default; + +ConnectionNotifier::~ConnectionNotifier() = default; + +void ConnectionNotifier::AddObserver(ConnectionObserverBase* observer) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + observer_list_.AddObserver(observer); +} + +void ConnectionNotifier::RemoveObserver(ConnectionObserverBase* observer) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + observer_list_.RemoveObserver(observer); +} + +void ConnectionNotifier::NotifyConnectionReady() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + for (auto& observer : observer_list_) + observer.OnConnectionReady(); +} + +void ConnectionNotifier::NotifyConnectionClosed() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + for (auto& observer : observer_list_) + observer.OnConnectionClosed(); +} + +} // namespace internal +} // namespace arc diff --git a/chromium/components/arc/connection_notifier.h b/chromium/components/arc/connection_notifier.h new file mode 100644 index 00000000000..05a9cac2d30 --- /dev/null +++ b/chromium/components/arc/connection_notifier.h @@ -0,0 +1,43 @@ +// Copyright 2017 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 COMPONENTS_ARC_CONNECTION_NOTIFIER_H_ +#define COMPONENTS_ARC_CONNECTION_NOTIFIER_H_ + +#include "base/macros.h" +#include "base/observer_list.h" +#include "base/threading/thread_checker.h" + +namespace arc { +namespace internal { + +class ConnectionObserverBase; + +// Manages events related to connection. Designed to be used only by +// ConnectionHolder. +class ConnectionNotifier { + public: + ConnectionNotifier(); + ~ConnectionNotifier(); + + void AddObserver(ConnectionObserverBase* observer); + void RemoveObserver(ConnectionObserverBase* observer); + + // Notifies observers that connection gets ready. + void NotifyConnectionReady(); + + // Notifies observers that connection is closed. + void NotifyConnectionClosed(); + + private: + THREAD_CHECKER(thread_checker_); + base::ObserverList observer_list_; + + DISALLOW_COPY_AND_ASSIGN(ConnectionNotifier); +}; + +} // namespace internal +} // namespace arc + +#endif // COMPONENTS_ARC_CONNECTION_NOTIFIER_H_ diff --git a/chromium/components/arc/connection_observer.h b/chromium/components/arc/connection_observer.h new file mode 100644 index 00000000000..a3eaaa7dd40 --- /dev/null +++ b/chromium/components/arc/connection_observer.h @@ -0,0 +1,38 @@ +// Copyright 2017 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 COMPONENTS_ARC_CONNECTION_OBSERVER_H_ +#define COMPONENTS_ARC_CONNECTION_OBSERVER_H_ + +namespace arc { +namespace internal { + +// Observer to listen events for connection. +class ConnectionObserverBase { + public: + // Called once the connection is ready. + // TODO(hidehiko): Currently, this means Instance is ready. + // Later, this will be called when Instance::Init() is completed + // for ARC full-duplex mojo connection. + virtual void OnConnectionReady() {} + + // Called once the connection is closed. + // Currently, this means Instance is closed. + virtual void OnConnectionClosed() {} + + protected: + virtual ~ConnectionObserverBase() = default; +}; + +} // namespace internal + +// Observer to listen events for connection for specific type. +// This is for type safeness to prevent listening events of unexpected mojo +// connection. +template +class ConnectionObserver : public internal::ConnectionObserverBase {}; + +} // namespace arc + +#endif // COMPONENTS_ARC_CONNECTION_OBSERVER_H_ diff --git a/chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc b/chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc index 90912eaf743..a84bb8261cc 100644 --- a/chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc +++ b/chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc @@ -81,21 +81,12 @@ ArcCrashCollectorBridge* ArcCrashCollectorBridge::GetForBrowserContext( ArcCrashCollectorBridge::ArcCrashCollectorBridge( content::BrowserContext* context, ArcBridgeService* bridge_service) - : arc_bridge_service_(bridge_service), binding_(this) { - arc_bridge_service_->crash_collector()->AddObserver(this); + : arc_bridge_service_(bridge_service) { + arc_bridge_service_->crash_collector()->SetHost(this); } ArcCrashCollectorBridge::~ArcCrashCollectorBridge() { - arc_bridge_service_->crash_collector()->RemoveObserver(this); -} - -void ArcCrashCollectorBridge::OnInstanceReady() { - mojom::CrashCollectorHostPtr host_ptr; - binding_.Bind(mojo::MakeRequest(&host_ptr)); - auto* instance = - ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->crash_collector(), Init); - DCHECK(instance); - instance->Init(std::move(host_ptr)); + arc_bridge_service_->crash_collector()->SetHost(nullptr); } void ArcCrashCollectorBridge::DumpCrash(const std::string& type, diff --git a/chromium/components/arc/crash_collector/arc_crash_collector_bridge.h b/chromium/components/arc/crash_collector/arc_crash_collector_bridge.h index 17cf7850c8b..9da78baf6e7 100644 --- a/chromium/components/arc/crash_collector/arc_crash_collector_bridge.h +++ b/chromium/components/arc/crash_collector/arc_crash_collector_bridge.h @@ -9,9 +9,7 @@ #include "base/macros.h" #include "components/arc/common/crash_collector.mojom.h" -#include "components/arc/instance_holder.h" #include "components/keyed_service/core/keyed_service.h" -#include "mojo/public/cpp/bindings/binding.h" namespace content { class BrowserContext; @@ -24,7 +22,6 @@ class ArcBridgeService; // Relays dumps for non-native ARC crashes to the crash reporter in Chrome OS. class ArcCrashCollectorBridge : public KeyedService, - public InstanceHolder::Observer, public mojom::CrashCollectorHost { public: // Returns singleton instance for the given BrowserContext, @@ -37,9 +34,6 @@ class ArcCrashCollectorBridge ~ArcCrashCollectorBridge() override; - // InstanceHolder::Observer overrides. - void OnInstanceReady() override; - // mojom::CrashCollectorHost overrides. void DumpCrash(const std::string& type, mojo::ScopedHandle pipe) override; @@ -50,8 +44,6 @@ class ArcCrashCollectorBridge private: ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager. - mojo::Binding binding_; - std::string device_; std::string board_; std::string cpu_abi_; diff --git a/chromium/components/arc/ime/arc_ime_bridge_impl.cc b/chromium/components/arc/ime/arc_ime_bridge_impl.cc index 304788b5ce1..6e4840ff284 100644 --- a/chromium/components/arc/ime/arc_ime_bridge_impl.cc +++ b/chromium/components/arc/ime/arc_ime_bridge_impl.cc @@ -76,20 +76,12 @@ std::vector ConvertSegments( ArcImeBridgeImpl::ArcImeBridgeImpl(Delegate* delegate, ArcBridgeService* bridge_service) - : binding_(this), delegate_(delegate), bridge_service_(bridge_service) { - bridge_service_->ime()->AddObserver(this); + : delegate_(delegate), bridge_service_(bridge_service) { + bridge_service_->ime()->SetHost(this); } ArcImeBridgeImpl::~ArcImeBridgeImpl() { - bridge_service_->ime()->RemoveObserver(this); -} - -void ArcImeBridgeImpl::OnInstanceReady() { - auto* instance = ARC_GET_INSTANCE_FOR_METHOD(bridge_service_->ime(), Init); - DCHECK(instance); - mojom::ImeHostPtr host_proxy; - binding_.Bind(mojo::MakeRequest(&host_proxy)); - instance->Init(std::move(host_proxy)); + bridge_service_->ime()->SetHost(nullptr); } void ArcImeBridgeImpl::SendSetCompositionText( @@ -145,7 +137,7 @@ void ArcImeBridgeImpl::OnTextInputTypeChanged(mojom::TextInputType type) { delegate_->OnTextInputTypeChanged(ConvertTextInputType(type)); } -void ArcImeBridgeImpl::OnCursorRectChanged(gfx::Rect rect) { +void ArcImeBridgeImpl::OnCursorRectChanged(const gfx::Rect& rect) { delegate_->OnCursorRectChanged(rect); } @@ -158,10 +150,10 @@ void ArcImeBridgeImpl::ShowImeIfNeeded() { } void ArcImeBridgeImpl::OnCursorRectChangedWithSurroundingText( - gfx::Rect rect, - gfx::Range text_range, + const gfx::Rect& rect, + const gfx::Range& text_range, const std::string& text_in_range, - gfx::Range selection_range) { + const gfx::Range& selection_range) { delegate_->OnCursorRectChangedWithSurroundingText( rect, text_range, base::UTF8ToUTF16(text_in_range), selection_range); } diff --git a/chromium/components/arc/ime/arc_ime_bridge_impl.h b/chromium/components/arc/ime/arc_ime_bridge_impl.h index ad26b7e7752..dbac40f7d8e 100644 --- a/chromium/components/arc/ime/arc_ime_bridge_impl.h +++ b/chromium/components/arc/ime/arc_ime_bridge_impl.h @@ -11,8 +11,6 @@ #include "base/strings/string16.h" #include "components/arc/common/ime.mojom.h" #include "components/arc/ime/arc_ime_bridge.h" -#include "components/arc/instance_holder.h" -#include "mojo/public/cpp/bindings/binding.h" #include "ui/base/ime/text_input_type.h" #include "ui/gfx/geometry/rect.h" @@ -26,16 +24,11 @@ class ArcBridgeService; // This class encapsulates the detail of IME related IPC between // Chromium and the ARC container. -class ArcImeBridgeImpl : public ArcImeBridge, - public mojom::ImeHost, - public InstanceHolder::Observer { +class ArcImeBridgeImpl : public ArcImeBridge, public mojom::ImeHost { public: ArcImeBridgeImpl(Delegate* delegate, ArcBridgeService* bridge_service); ~ArcImeBridgeImpl() override; - // InstanceHolder::Observer overrides: - void OnInstanceReady() override; - // ArcImeBridge overrides: void SendSetCompositionText(const ui::CompositionText& composition) override; void SendConfirmCompositionText() override; @@ -45,17 +38,16 @@ class ArcImeBridgeImpl : public ArcImeBridge, // mojom::ImeHost overrides: void OnTextInputTypeChanged(mojom::TextInputType type) override; - void OnCursorRectChanged(gfx::Rect rect) override; + void OnCursorRectChanged(const gfx::Rect& rect) override; void OnCancelComposition() override; void ShowImeIfNeeded() override; void OnCursorRectChangedWithSurroundingText( - gfx::Rect rect, - gfx::Range text_range, + const gfx::Rect& rect, + const gfx::Range& text_range, const std::string& text_in_range, - gfx::Range selection_range) override; + const gfx::Range& selection_range) override; private: - mojo::Binding binding_; Delegate* const delegate_; ArcBridgeService* const bridge_service_; diff --git a/chromium/components/arc/ime/arc_ime_service.cc b/chromium/components/arc/ime/arc_ime_service.cc index 775bea2d98d..bfbc3325180 100644 --- a/chromium/components/arc/ime/arc_ime_service.cc +++ b/chromium/components/arc/ime/arc_ime_service.cc @@ -8,11 +8,13 @@ #include "base/logging.h" #include "base/memory/singleton.h" +#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "components/arc/arc_browser_context_keyed_service_factory_base.h" #include "components/arc/ime/arc_ime_bridge_impl.h" #include "components/exo/shell_surface.h" #include "components/exo/surface.h" +#include "components/exo/wm_helper.h" #include "ui/aura/env.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" @@ -465,6 +467,12 @@ bool ArcImeService::IsTextEditCommandEnabled( return false; } +const std::string& ArcImeService::GetClientSourceInfo() const { + // TODO(yhanada): Implement this method. crbug.com/752657 + NOTIMPLEMENTED_LOG_ONCE(); + return base::EmptyString(); +} + void ArcImeService::InvalidateSurroundingTextAndSelectionRange() { text_range_ = gfx::Range::InvalidRange(); text_in_range_ = base::string16(); diff --git a/chromium/components/arc/ime/arc_ime_service.h b/chromium/components/arc/ime/arc_ime_service.h index 61b7ca3834c..a09b3caac2c 100644 --- a/chromium/components/arc/ime/arc_ime_service.h +++ b/chromium/components/arc/ime/arc_ime_service.h @@ -9,8 +9,8 @@ #include "base/macros.h" #include "components/arc/ime/arc_ime_bridge.h" -#include "components/exo/wm_helper.h" #include "components/keyed_service/core/keyed_service.h" +#include "ui/aura/client/focus_change_observer.h" #include "ui/aura/env_observer.h" #include "ui/aura/window_observer.h" #include "ui/base/ime/text_input_client.h" @@ -42,7 +42,7 @@ class ArcImeService : public KeyedService, public ArcImeBridge::Delegate, public aura::EnvObserver, public aura::WindowObserver, - public exo::WMHelper::FocusObserver, + public aura::client::FocusChangeObserver, public keyboard::KeyboardControllerObserver, public ui::TextInputClient { public: @@ -79,7 +79,7 @@ class ArcImeService : public KeyedService, void OnWindowRemovingFromRootWindow(aura::Window* window, aura::Window* new_root) override; - // Overridden from exo::WMHelper::FocusObserver: + // Overridden from aura::client::FocusChangeObserver: void OnWindowFocused(aura::Window* gained_focus, aura::Window* lost_focus) override; @@ -132,6 +132,7 @@ class ArcImeService : public KeyedService, bool IsTextEditCommandEnabled(ui::TextEditCommand command) const override; void SetTextEditCommandForNextKeyEvent(ui::TextEditCommand command) override { } + const std::string& GetClientSourceInfo() const override; private: ui::InputMethod* GetInputMethod(); diff --git a/chromium/components/arc/ime/arc_ime_service_unittest.cc b/chromium/components/arc/ime/arc_ime_service_unittest.cc index f980dd93a78..45353111a74 100644 --- a/chromium/components/arc/ime/arc_ime_service_unittest.cc +++ b/chromium/components/arc/ime/arc_ime_service_unittest.cc @@ -8,7 +8,6 @@ #include #include -#include "base/memory/ptr_util.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" #include "components/arc/arc_bridge_service.h" diff --git a/chromium/components/arc/ime/arc_ime_struct_traits.cc b/chromium/components/arc/ime/arc_ime_struct_traits.cc deleted file mode 100644 index b3ca64ac47e..00000000000 --- a/chromium/components/arc/ime/arc_ime_struct_traits.cc +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2017 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 "components/arc/ime/arc_ime_struct_traits.h" - -namespace mojo { - -bool StructTraits::Read( - arc::mojom::CursorRectDataView data, - gfx::Rect* out) { - out->set_x(data.left()); - out->set_y(data.top()); - out->set_width(data.right() - out->x()); - out->set_height(data.bottom() - out->y()); - return true; -} - -bool StructTraits::Read( - arc::mojom::TextRangeDataView data, - gfx::Range* out) { - out->set_start(data.start()); - out->set_end(data.end()); - return true; -} - -} // namespace mojo diff --git a/chromium/components/arc/ime/arc_ime_struct_traits.h b/chromium/components/arc/ime/arc_ime_struct_traits.h deleted file mode 100644 index 91a7addffde..00000000000 --- a/chromium/components/arc/ime/arc_ime_struct_traits.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2017 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 COMPONENTS_ARC_IME_ARC_IME_STRUCT_TRAITS_H_ -#define COMPONENTS_ARC_IME_ARC_IME_STRUCT_TRAITS_H_ - -#include "components/arc/common/ime.mojom.h" -#include "ui/gfx/geometry/rect.h" - -namespace mojo { - -template <> -struct StructTraits { - static int32_t left(const gfx::Rect& r) { return r.x(); } - static int32_t top(const gfx::Rect& r) { return r.y(); } - static int32_t right(const gfx::Rect& r) { return r.right(); } - static int32_t bottom(const gfx::Rect& r) { return r.bottom(); } - - static bool Read(arc::mojom::CursorRectDataView data, gfx::Rect* out); -}; - -template <> -struct StructTraits { - static uint32_t start(const gfx::Range& r) { return r.start(); } - static uint32_t end(const gfx::Range& r) { return r.end(); } - - static bool Read(arc::mojom::TextRangeDataView data, gfx::Range* out); -}; - -} // namespace mojo - -#endif // COMPONENTS_ARC_IME_ARC_IME_STRUCT_TRAITS_H_ diff --git a/chromium/components/arc/instance_holder.h b/chromium/components/arc/instance_holder.h deleted file mode 100644 index 48f833f4fcc..00000000000 --- a/chromium/components/arc/instance_holder.h +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2015 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 COMPONENTS_ARC_INSTANCE_HOLDER_H_ -#define COMPONENTS_ARC_INSTANCE_HOLDER_H_ - -#include -#include -#include - -#include "base/bind.h" -#include "base/macros.h" -#include "base/observer_list.h" -#include "base/threading/thread_checker.h" - -// A macro to call InstanceHolder::GetInstanceForVersionDoNotCallDirectly(). -// In order to avoid exposing method names from within the Mojo bindings, we -// will rely on stringification and the fact that the method min versions have a -// consistent naming scheme. -#define ARC_GET_INSTANCE_FOR_METHOD(holder, method_name) \ - (holder)->GetInstanceForVersionDoNotCallDirectly( \ - std::remove_pointer::type::Instance::k##method_name##MinVersion, \ - #method_name) - -namespace arc { - -// Holds a Mojo instance+version pair. This also allows for listening for state -// changes for the particular instance. T should be a Mojo interface type -// (arc::mojom::XxxInstance). -template -class InstanceHolder { - public: - // Notifies about connection events for individual instances. - class Observer { - public: - // Called once the instance is ready. - virtual void OnInstanceReady() {} - - // Called when the connection to the instance is closed. - virtual void OnInstanceClosed() {} - - protected: - virtual ~Observer() = default; - }; - - using Instance = T; - - InstanceHolder() = default; - - // Returns true if the Mojo interface is ready at least for its version 0 - // interface. Use an Observer if you want to be notified when this is ready. - // This can only be called on the thread that this class was created on. - bool has_instance() const { return instance_; } - - // Gets the Mojo interface that's intended to call for - // |method_name_for_logging|, but only if its reported version is at least - // |min_version|. Returns nullptr if the instance is either not ready or does - // not have the requested version, and logs appropriately. - // This function should not be called directly. Instead, use the - // ARC_GET_INSTANCE_FOR_METHOD() macro. - T* GetInstanceForVersionDoNotCallDirectly( - uint32_t min_version, - const char method_name_for_logging[]) { - if (!instance_) { - VLOG(1) << "Instance " << T::Name_ << " not available."; - return nullptr; - } - if (version_ < min_version) { - LOG(ERROR) << "Instance for " << T::Name_ - << "::" << method_name_for_logging - << " version mismatch. Expected " << min_version << " got " - << version_; - return nullptr; - } - return instance_; - } - - // Adds or removes observers. This can only be called on the thread that this - // class was created on. RemoveObserver does nothing if |observer| is not in - // the list. - void AddObserver(Observer* observer) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - observer_list_.AddObserver(observer); - - if (instance_) - observer->OnInstanceReady(); - } - - void RemoveObserver(Observer* observer) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - observer_list_.RemoveObserver(observer); - } - - // Sets |instance| with |version|. - // This can be called in both case; on ready, and on closed. - // Passing nullptr to |instance| means closing. - void SetInstance(T* instance, uint32_t version = T::Version_) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(instance == nullptr || instance_ == nullptr); - - // Note: This can be called with nullptr even if |instance_| is still - // nullptr for just in case clean up purpose. No-op in such a case. - if (instance == instance_) - return; - - instance_ = instance; - version_ = version; - if (instance_) { - for (auto& observer : observer_list_) - observer.OnInstanceReady(); - } else { - for (auto& observer : observer_list_) - observer.OnInstanceClosed(); - } - } - - private: - // This class does not have ownership. The pointers should be managed by the - // callee. - T* instance_ = nullptr; - uint32_t version_ = 0; - - THREAD_CHECKER(thread_checker_); - base::ObserverList observer_list_; - - DISALLOW_COPY_AND_ASSIGN(InstanceHolder); -}; - -} // namespace arc - -#endif // COMPONENTS_ARC_INSTANCE_HOLDER_H_ diff --git a/chromium/components/arc/intent_helper/DEPS b/chromium/components/arc/intent_helper/DEPS index e2ab3722b4c..71b171809a0 100644 --- a/chromium/components/arc/intent_helper/DEPS +++ b/chromium/components/arc/intent_helper/DEPS @@ -6,6 +6,7 @@ include_rules = [ "+ash/shell_delegate.h", "+ash/wallpaper/wallpaper_controller.h", "+components/google/core/browser", + "+components/url_formatter", "+ui/base", "+ui/gfx", ] diff --git a/chromium/components/arc/intent_helper/activity_icon_loader.cc b/chromium/components/arc/intent_helper/activity_icon_loader.cc index c38ec4a0723..a864bad92e3 100644 --- a/chromium/components/arc/intent_helper/activity_icon_loader.cc +++ b/chromium/components/arc/intent_helper/activity_icon_loader.cc @@ -65,7 +65,7 @@ mojom::IntentHelperInstance* GetInstanceForRequestActivityIcons( auto* intent_helper_holder = arc_service_manager->arc_bridge_service()->intent_helper(); - if (!intent_helper_holder->has_instance()) { + if (!intent_helper_holder->IsConnected()) { VLOG(2) << "ARC intent helper instance is not ready."; if (out_error_code) *out_error_code = ActivityIconLoader::GetResult::FAILED_ARC_NOT_READY; @@ -181,7 +181,7 @@ void ActivityIconLoader::InvalidateIcons(const std::string& package_name) { ActivityIconLoader::GetResult ActivityIconLoader::GetActivityIcons( const std::vector& activities, - const OnIconsReadyCallback& cb) { + OnIconsReadyCallback cb) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); std::unique_ptr result(new ActivityToIconsMap); std::vector activities_to_fetch; @@ -200,7 +200,7 @@ ActivityIconLoader::GetResult ActivityIconLoader::GetActivityIcons( if (activities_to_fetch.empty()) { // If there's nothing to fetch, run the callback now. - cb.Run(std::move(result)); + std::move(cb).Run(std::move(result)); return GetResult::SUCCEEDED_SYNC; } @@ -209,22 +209,24 @@ ActivityIconLoader::GetResult ActivityIconLoader::GetActivityIcons( if (!instance) { // The mojo channel is not yet ready (or not supported at all). Run the // callback with |result| that could be empty. - cb.Run(std::move(result)); + std::move(cb).Run(std::move(result)); return error_code; } // Fetch icons from ARC. instance->RequestActivityIcons( std::move(activities_to_fetch), mojom::ScaleFactor(scale_factor_), - base::Bind(&ActivityIconLoader::OnIconsReady, - weak_ptr_factory_.GetWeakPtr(), base::Passed(&result), cb)); + base::BindOnce(&ActivityIconLoader::OnIconsReady, + weak_ptr_factory_.GetWeakPtr(), std::move(result), + std::move(cb))); return GetResult::SUCCEEDED_ASYNC; } void ActivityIconLoader::OnIconsResizedForTesting( - const OnIconsReadyCallback& cb, + OnIconsReadyCallback cb, std::unique_ptr result) { - OnIconsResized(std::make_unique(), cb, std::move(result)); + OnIconsResized(std::make_unique(), std::move(cb), + std::move(result)); } void ActivityIconLoader::AddCacheEntryForTesting(const ActivityName& activity) { @@ -247,20 +249,20 @@ bool ActivityIconLoader::HasIconsReadyCallbackRun(GetResult result) { void ActivityIconLoader::OnIconsReady( std::unique_ptr cached_result, - const OnIconsReadyCallback& cb, + OnIconsReadyCallback cb, std::vector icons) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); base::PostTaskAndReplyWithResult( FROM_HERE, - base::Bind(&ResizeAndEncodeIcons, base::Passed(&icons), scale_factor_), - base::Bind(&ActivityIconLoader::OnIconsResized, - weak_ptr_factory_.GetWeakPtr(), base::Passed(&cached_result), - cb)); + base::BindOnce(&ResizeAndEncodeIcons, std::move(icons), scale_factor_), + base::BindOnce(&ActivityIconLoader::OnIconsResized, + weak_ptr_factory_.GetWeakPtr(), std::move(cached_result), + std::move(cb))); } void ActivityIconLoader::OnIconsResized( std::unique_ptr cached_result, - const OnIconsReadyCallback& cb, + OnIconsReadyCallback cb, std::unique_ptr result) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // Update |cached_icons_|. @@ -271,7 +273,7 @@ void ActivityIconLoader::OnIconsResized( // Merge the results that were obtained from cache before doing IPC. result->insert(cached_result->begin(), cached_result->end()); - cb.Run(std::move(result)); + std::move(cb).Run(std::move(result)); } } // namespace internal diff --git a/chromium/components/arc/intent_helper/activity_icon_loader.h b/chromium/components/arc/intent_helper/activity_icon_loader.h index 33ac3b70d72..3b07589fd21 100644 --- a/chromium/components/arc/intent_helper/activity_icon_loader.h +++ b/chromium/components/arc/intent_helper/activity_icon_loader.h @@ -66,7 +66,7 @@ class ActivityIconLoader { using ActivityToIconsMap = std::map; using OnIconsReadyCallback = - base::Callback)>; + base::OnceCallback)>; ActivityIconLoader(); ~ActivityIconLoader(); @@ -80,9 +80,9 @@ class ActivityIconLoader { // locally or ARC is not ready/supported). Otherwise, the callback is run // later asynchronously with icons fetched from ARC side. GetResult GetActivityIcons(const std::vector& activities, - const OnIconsReadyCallback& cb); + OnIconsReadyCallback cb); - void OnIconsResizedForTesting(const OnIconsReadyCallback& cb, + void OnIconsResizedForTesting(OnIconsReadyCallback cb, std::unique_ptr result); void AddCacheEntryForTesting(const ActivityName& activity); @@ -95,13 +95,13 @@ class ActivityIconLoader { private: // A function called when the mojo IPC returns. void OnIconsReady(std::unique_ptr cached_result, - const OnIconsReadyCallback& cb, + OnIconsReadyCallback cb, std::vector icons); // A function called when ResizeIcons finishes. Append items in |result| to // |cached_icons_|. void OnIconsResized(std::unique_ptr cached_result, - const OnIconsReadyCallback& cb, + OnIconsReadyCallback cb, std::unique_ptr result); // The maximum scale factor the current platform supports. diff --git a/chromium/components/arc/intent_helper/activity_icon_loader_unittest.cc b/chromium/components/arc/intent_helper/activity_icon_loader_unittest.cc index 586897e084e..6f5cceadd45 100644 --- a/chromium/components/arc/intent_helper/activity_icon_loader_unittest.cc +++ b/chromium/components/arc/intent_helper/activity_icon_loader_unittest.cc @@ -118,7 +118,7 @@ TEST(ActivityIconLoaderTest, TestOnIconsResized) { ActivityIconLoader loader; // Call OnIconsResized() and check that the cache is properly updated. - loader.OnIconsResizedForTesting(base::Bind(&OnIconsReady0), + loader.OnIconsResizedForTesting(base::BindOnce(&OnIconsReady0), std::move(activity_to_icons)); EXPECT_EQ(3U, loader.cached_icons_for_testing().size()); EXPECT_EQ(1U, loader.cached_icons_for_testing().count( @@ -139,7 +139,7 @@ TEST(ActivityIconLoaderTest, TestOnIconsResized) { activity_to_icons->insert(std::make_pair( ActivityIconLoader::ActivityName("p2", "a2"), ActivityIconLoader::Icons(gfx::Image(), gfx::Image(), nullptr))); - loader.OnIconsResizedForTesting(base::Bind(&OnIconsReady3), + loader.OnIconsResizedForTesting(base::BindOnce(&OnIconsReady3), std::move(activity_to_icons)); EXPECT_EQ(4U, loader.cached_icons_for_testing().size()); EXPECT_EQ(1U, loader.cached_icons_for_testing().count( diff --git a/chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc b/chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc index cb841928d68..5e7e2366fff 100644 --- a/chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc +++ b/chromium/components/arc/intent_helper/arc_intent_helper_bridge.cc @@ -4,25 +4,75 @@ #include "components/arc/intent_helper/arc_intent_helper_bridge.h" +#include #include #include "ash/new_window_controller.h" #include "ash/shell.h" #include "ash/shell_delegate.h" #include "ash/wallpaper/wallpaper_controller.h" +#include "base/logging.h" #include "base/memory/singleton.h" #include "base/memory/weak_ptr.h" +#include "base/strings/string_util.h" #include "components/arc/arc_bridge_service.h" #include "components/arc/arc_browser_context_keyed_service_factory_base.h" #include "components/arc/arc_service_manager.h" #include "components/arc/audio/arc_audio_bridge.h" +#include "components/url_formatter/url_fixer.h" #include "ui/base/layout.h" -#include "url/gurl.h" +#include "url/url_constants.h" namespace arc { namespace { -constexpr char kChromeUIScheme[] = "chrome"; +constexpr std::pair kMapping[] = { + {mojom::ChromePage::MULTIDEVICE, "multidevice"}, + {mojom::ChromePage::MAIN, ""}, + {mojom::ChromePage::POWER, "power"}, + {mojom::ChromePage::BLUETOOTH, "bluetoothDevices"}, + {mojom::ChromePage::DATETIME, "dateTime"}, + {mojom::ChromePage::DISPLAY, "display"}, + {mojom::ChromePage::WIFI, "networks/?type=WiFi"}, + {mojom::ChromePage::PRIVACY, "privacy"}, + {mojom::ChromePage::HELP, "help"}, + {mojom::ChromePage::ACCOUNTS, "accounts"}, + {mojom::ChromePage::APPEARANCE, "appearance"}, + {mojom::ChromePage::AUTOFILL, "autofill"}, + {mojom::ChromePage::BLUETOOTHDEVICES, "bluetoothDevices"}, + {mojom::ChromePage::CHANGEPICTURE, "changePicture"}, + {mojom::ChromePage::CLEARBROWSERDATA, "clearBrowserData"}, + {mojom::ChromePage::CLOUDPRINTERS, "cloudPrinters"}, + {mojom::ChromePage::CUPSPRINTERS, "cupsPrinters"}, + {mojom::ChromePage::DOWNLOADS, "downloads"}, + {mojom::ChromePage::KEYBOARDOVERLAY, "keyboard-overlay"}, + {mojom::ChromePage::LANGUAGES, "languages"}, + {mojom::ChromePage::LOCKSCREEN, "lockScreen"}, + {mojom::ChromePage::MANAGEACCESSIBILITY, "manageAccessibility"}, + {mojom::ChromePage::NETWORKSTYPEVPN, "networks?type=VPN"}, + {mojom::ChromePage::ONSTARTUP, "onStartup"}, + {mojom::ChromePage::PASSWORDS, "passwords"}, + {mojom::ChromePage::POINTEROVERLAY, "pointer-overlay"}, + {mojom::ChromePage::RESET, "reset"}, + {mojom::ChromePage::SEARCH, "search"}, + {mojom::ChromePage::STORAGE, "storage"}, + {mojom::ChromePage::SYNCSETUP, "syncSetup"}, + {mojom::ChromePage::ABOUTBLANK, url::kAboutBlankURL}, + {mojom::ChromePage::ABOUTDOWNLOADS, "about:downloads"}, + {mojom::ChromePage::ABOUTHISTORY, "about:history"}}; + +// TODO(djacobo): Propose geo: as a constant. +constexpr const char* kArcSchemes[] = {url::kHttpScheme, + url::kHttpsScheme, + url::kContentScheme, + url::kFileScheme, + "geo", + url::kMailToScheme}; + +// mojom::ChromePage::LAST returns the ammout of valid entries - 1. +static_assert(arraysize(kMapping) == + static_cast(mojom::ChromePage::LAST) + 1, + "kMapping is out of sync"); class OpenUrlDelegateImpl : public ArcIntentHelperBridge::OpenUrlDelegate { public: @@ -77,32 +127,25 @@ KeyedServiceBaseFactory* ArcIntentHelperBridge::GetFactory() { return ArcIntentHelperBridgeFactory::GetInstance(); } +// static +std::string ArcIntentHelperBridge::AppendStringToIntentHelperPackageName( + const std::string& to_append) { + return base::JoinString({kArcIntentHelperPackageName, to_append}, "."); +} + ArcIntentHelperBridge::ArcIntentHelperBridge(content::BrowserContext* context, ArcBridgeService* bridge_service) : context_(context), arc_bridge_service_(bridge_service), - binding_(this), - open_url_delegate_(std::make_unique()) { - arc_bridge_service_->intent_helper()->AddObserver(this); + open_url_delegate_(std::make_unique()), + allowed_chrome_pages_map_(std::cbegin(kMapping), std::cend(kMapping)), + allowed_arc_schemes_(std::cbegin(kArcSchemes), std::cend(kArcSchemes)) { + arc_bridge_service_->intent_helper()->SetHost(this); } ArcIntentHelperBridge::~ArcIntentHelperBridge() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - arc_bridge_service_->intent_helper()->RemoveObserver(this); -} - -void ArcIntentHelperBridge::OnInstanceReady() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - auto* instance = - ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->intent_helper(), Init); - DCHECK(instance); - mojom::IntentHelperHostPtr host_proxy; - binding_.Bind(mojo::MakeRequest(&host_proxy)); - instance->Init(std::move(host_proxy)); -} - -void ArcIntentHelperBridge::OnInstanceClosed() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + arc_bridge_service_->intent_helper()->SetHost(nullptr); } void ArcIntentHelperBridge::OnIconInvalidated(const std::string& package_name) { @@ -123,56 +166,29 @@ void ArcIntentHelperBridge::OnOpenDownloads() { void ArcIntentHelperBridge::OnOpenUrl(const std::string& url) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - const GURL gurl(url); - // Disallow opening chrome:// URLs. - if (gurl.SchemeIs(kChromeUIScheme)) + // Converts |url| to a fixed-up one and checks validity. + const GURL gurl(url_formatter::FixupURL(url, std::string())); + if (!gurl.is_valid()) return; - open_url_delegate_->OpenUrl(gurl); + + if (allowed_arc_schemes_.find(gurl.scheme()) != allowed_arc_schemes_.end()) + open_url_delegate_->OpenUrl(gurl); } -void ArcIntentHelperBridge::OnOpenChromeSettings(mojom::SettingsPage page) { +void ArcIntentHelperBridge::OnOpenChromePage(mojom::ChromePage page) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - // Mapping from the mojom enum values to the URL components. - const char* sub_url = nullptr; - switch (page) { - case mojom::SettingsPage::MULTIDEVICE: - sub_url = "multidevice"; - break; - case mojom::SettingsPage::MAIN: - sub_url = ""; - break; - case mojom::SettingsPage::POWER: - sub_url = "power"; - break; - case mojom::SettingsPage::BLUETOOTH: - sub_url = "bluetoothDevices"; - break; - case mojom::SettingsPage::DATETIME: - sub_url = "dateTime"; - break; - case mojom::SettingsPage::DISPLAY: - sub_url = "display"; - break; - case mojom::SettingsPage::WIFI: - sub_url = "networks/?type=WiFi"; - break; - case mojom::SettingsPage::LANGUAGE: - sub_url = "languages"; - break; - case mojom::SettingsPage::PRIVACY: - sub_url = "privacy"; - break; - case mojom::SettingsPage::HELP: - sub_url = "help"; - break; - } - - if (!sub_url) { - LOG(ERROR) << "Invalid settings page: " << page; + auto it = allowed_chrome_pages_map_.find(page); + if (it == allowed_chrome_pages_map_.end()) { + LOG(WARNING) << "The requested ChromePage is invalid: " + << static_cast(page); return; } - open_url_delegate_->OpenUrl(GURL(kSettingsPageBaseUrl).Resolve(sub_url)); + + GURL page_gurl(it->second); + if (page_gurl.SchemeIs(url::kAboutScheme)) + open_url_delegate_->OpenUrl(page_gurl); + else + open_url_delegate_->OpenUrl(GURL(kSettingsPageBaseUrl).Resolve(it->second)); } void ArcIntentHelperBridge::OpenWallpaperPicker() { @@ -196,9 +212,9 @@ void ArcIntentHelperBridge::OpenVolumeControl() { ArcIntentHelperBridge::GetResult ArcIntentHelperBridge::GetActivityIcons( const std::vector& activities, - const OnIconsReadyCallback& callback) { + OnIconsReadyCallback callback) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - return icon_loader_.GetActivityIcons(activities, callback); + return icon_loader_.GetActivityIcons(activities, std::move(callback)); } bool ArcIntentHelperBridge::ShouldChromeHandleUrl(const GURL& url) { diff --git a/chromium/components/arc/intent_helper/arc_intent_helper_bridge.h b/chromium/components/arc/intent_helper/arc_intent_helper_bridge.h index 2fad5b12dac..9922c11922b 100644 --- a/chromium/components/arc/intent_helper/arc_intent_helper_bridge.h +++ b/chromium/components/arc/intent_helper/arc_intent_helper_bridge.h @@ -5,7 +5,9 @@ #ifndef COMPONENTS_ARC_INTENT_HELPER_ARC_INTENT_HELPER_BRIDGE_H_ #define COMPONENTS_ARC_INTENT_HELPER_ARC_INTENT_HELPER_BRIDGE_H_ +#include #include +#include #include #include @@ -13,11 +15,10 @@ #include "base/observer_list.h" #include "base/threading/thread_checker.h" #include "components/arc/common/intent_helper.mojom.h" -#include "components/arc/instance_holder.h" #include "components/arc/intent_helper/activity_icon_loader.h" #include "components/arc/intent_helper/arc_intent_helper_observer.h" #include "components/keyed_service/core/keyed_service.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "url/gurl.h" class KeyedServiceBaseFactory; @@ -33,7 +34,6 @@ class IntentFilter; // Receives intents from ARC. class ArcIntentHelperBridge : public KeyedService, - public InstanceHolder::Observer, public mojom::IntentHelperHost { public: // Returns singleton instance for the given BrowserContext, @@ -44,6 +44,10 @@ class ArcIntentHelperBridge // Returns factory for the ArcIntentHelperBridge. static KeyedServiceBaseFactory* GetFactory(); + // Appends '.' + |to_append| to the intent helper package name. + static std::string AppendStringToIntentHelperPackageName( + const std::string& to_append); + ArcIntentHelperBridge(content::BrowserContext* context, ArcBridgeService* bridge_service); ~ArcIntentHelperBridge() override; @@ -52,17 +56,13 @@ class ArcIntentHelperBridge void RemoveObserver(ArcIntentHelperObserver* observer); bool HasObserver(ArcIntentHelperObserver* observer) const; - // InstanceHolder::Observer - void OnInstanceReady() override; - void OnInstanceClosed() override; - // mojom::IntentHelperHost void OnIconInvalidated(const std::string& package_name) override; void OnIntentFiltersUpdated( std::vector intent_filters) override; void OnOpenDownloads() override; void OnOpenUrl(const std::string& url) override; - void OnOpenChromeSettings(mojom::SettingsPage page) override; + void OnOpenChromePage(mojom::ChromePage page) override; void OpenWallpaperPicker() override; void SetWallpaperDeprecated(const std::vector& jpeg_data) override; void OpenVolumeControl() override; @@ -84,7 +84,7 @@ class ArcIntentHelperBridge internal::ActivityIconLoader::OnIconsReadyCallback; using GetResult = internal::ActivityIconLoader::GetResult; GetResult GetActivityIcons(const std::vector& activities, - const OnIconsReadyCallback& callback); + OnIconsReadyCallback callback); // Returns true when |url| can only be handled by Chrome. Otherwise, which is // when there might be one or more ARC apps that can handle |url|, returns @@ -113,7 +113,6 @@ class ArcIntentHelperBridge content::BrowserContext* const context_; ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager. - mojo::Binding binding_; std::unique_ptr open_url_delegate_; internal::ActivityIconLoader icon_loader_; @@ -123,6 +122,13 @@ class ArcIntentHelperBridge base::ObserverList observer_list_; + // about: and chrome://settings pages assistant requires to launch via + // OnOpenChromePage. + const std::map allowed_chrome_pages_map_; + + // Schemes that ARC is known to send via OnOpenUrl. + const std::set allowed_arc_schemes_; + DISALLOW_COPY_AND_ASSIGN(ArcIntentHelperBridge); }; diff --git a/chromium/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc b/chromium/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc index 0a41295b955..dde660f0f8d 100644 --- a/chromium/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc +++ b/chromium/components/arc/intent_helper/arc_intent_helper_bridge_unittest.cc @@ -36,7 +36,11 @@ class ArcIntentHelperTest : public testing::Test { // ArcIntentHelperBridge::OpenUrlDelegate: void OpenUrl(const GURL& url) override { last_opened_url_ = url; } - const GURL& last_opened_url() const { return last_opened_url_; } + GURL TakeLastOpenedUrl() { + GURL result = std::move(last_opened_url_); + last_opened_url_ = GURL(); + return result; + } private: GURL last_opened_url_; @@ -271,33 +275,181 @@ TEST_F(ArcIntentHelperTest, TestMultipleUpdate) { // Tests that OnOpenUrl opens the URL in Chrome browser. TEST_F(ArcIntentHelperTest, TestOnOpenUrl) { + instance_->OnOpenUrl("http://google.com"); + EXPECT_EQ(GURL("http://google.com"), + test_open_url_delegate_->TakeLastOpenedUrl()); + instance_->OnOpenUrl("https://google.com"); EXPECT_EQ(GURL("https://google.com"), - test_open_url_delegate_->last_opened_url()); + test_open_url_delegate_->TakeLastOpenedUrl()); } -// Tests that OnOpenUrl does not open URLs with the 'chrome' scheme. +// Tests that OnOpenUrl does not open URLs with the 'chrome://' and equivalent +// schemes like 'about:'. TEST_F(ArcIntentHelperTest, TestOnOpenUrl_ChromeScheme) { instance_->OnOpenUrl("chrome://www.google.com"); - EXPECT_FALSE(test_open_url_delegate_->last_opened_url().is_valid()); + EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid()); + instance_->OnOpenUrl("chrome://settings"); - EXPECT_FALSE(test_open_url_delegate_->last_opened_url().is_valid()); + EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid()); + + instance_->OnOpenUrl("about:"); + EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid()); + + instance_->OnOpenUrl("about:settings"); + EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid()); + + instance_->OnOpenUrl("about:blank"); + EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid()); } -// Tests that OnOpenChromeSettings opens the specified settings section in the +// Tests that OnOpenChromePage opens the specified settings section in the // Chrome browser. -TEST_F(ArcIntentHelperTest, TestOnOpenChromeSettings) { - instance_->OnOpenChromeSettings(mojom::SettingsPage::MAIN); +TEST_F(ArcIntentHelperTest, TestOnOpenChromePage) { + instance_->OnOpenChromePage(mojom::ChromePage::MAIN); EXPECT_EQ(GURL("chrome://settings"), - test_open_url_delegate_->last_opened_url()); + test_open_url_delegate_->TakeLastOpenedUrl()); - instance_->OnOpenChromeSettings(mojom::SettingsPage::MULTIDEVICE); + instance_->OnOpenChromePage(mojom::ChromePage::MULTIDEVICE); EXPECT_EQ(GURL("chrome://settings/multidevice"), - test_open_url_delegate_->last_opened_url()); + test_open_url_delegate_->TakeLastOpenedUrl()); - instance_->OnOpenChromeSettings(mojom::SettingsPage::WIFI); + instance_->OnOpenChromePage(mojom::ChromePage::WIFI); EXPECT_EQ(GURL("chrome://settings/networks/?type=WiFi"), - test_open_url_delegate_->last_opened_url()); + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::POWER); + EXPECT_EQ(GURL("chrome://settings/power"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::BLUETOOTH); + EXPECT_EQ(GURL("chrome://settings/bluetoothDevices"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::DATETIME); + EXPECT_EQ(GURL("chrome://settings/dateTime"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::DISPLAY); + EXPECT_EQ(GURL("chrome://settings/display"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::PRIVACY); + EXPECT_EQ(GURL("chrome://settings/privacy"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::HELP); + EXPECT_EQ(GURL("chrome://settings/help"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::ACCOUNTS); + EXPECT_EQ(GURL("chrome://settings/accounts"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::APPEARANCE); + EXPECT_EQ(GURL("chrome://settings/appearance"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::AUTOFILL); + EXPECT_EQ(GURL("chrome://settings/autofill"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::BLUETOOTHDEVICES); + EXPECT_EQ(GURL("chrome://settings/bluetoothDevices"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::CHANGEPICTURE); + EXPECT_EQ(GURL("chrome://settings/changePicture"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::CLEARBROWSERDATA); + EXPECT_EQ(GURL("chrome://settings/clearBrowserData"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::CLOUDPRINTERS); + EXPECT_EQ(GURL("chrome://settings/cloudPrinters"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::CUPSPRINTERS); + EXPECT_EQ(GURL("chrome://settings/cupsPrinters"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::DOWNLOADS); + EXPECT_EQ(GURL("chrome://settings/downloads"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::ABOUTDOWNLOADS); + EXPECT_EQ(GURL("about:downloads"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::ABOUTHISTORY); + EXPECT_EQ(GURL("about:history"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::KEYBOARDOVERLAY); + EXPECT_EQ(GURL("chrome://settings/keyboard-overlay"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::LANGUAGES); + EXPECT_EQ(GURL("chrome://settings/languages"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::LOCKSCREEN); + EXPECT_EQ(GURL("chrome://settings/lockScreen"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::MANAGEACCESSIBILITY); + EXPECT_EQ(GURL("chrome://settings/manageAccessibility"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::NETWORKSTYPEVPN); + EXPECT_EQ(GURL("chrome://settings/networks?type=VPN"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::ONSTARTUP); + EXPECT_EQ(GURL("chrome://settings/onStartup"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::PASSWORDS); + EXPECT_EQ(GURL("chrome://settings/passwords"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::POINTEROVERLAY); + EXPECT_EQ(GURL("chrome://settings/pointer-overlay"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::RESET); + EXPECT_EQ(GURL("chrome://settings/reset"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::SEARCH); + EXPECT_EQ(GURL("chrome://settings/search"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::STORAGE); + EXPECT_EQ(GURL("chrome://settings/storage"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::SYNCSETUP); + EXPECT_EQ(GURL("chrome://settings/syncSetup"), + test_open_url_delegate_->TakeLastOpenedUrl()); + + instance_->OnOpenChromePage(mojom::ChromePage::ABOUTBLANK); + EXPECT_EQ(GURL("about:blank"), test_open_url_delegate_->TakeLastOpenedUrl()); +} + +// Tests that AppendStringToIntentHelperPackageName works. +TEST_F(ArcIntentHelperTest, TestAppendStringToIntentHelperPackageName) { + std::string package_name = ArcIntentHelperBridge::kArcIntentHelperPackageName; + std::string fake_activity = "this_is_a_fake_activity"; + EXPECT_EQ(ArcIntentHelperBridge::AppendStringToIntentHelperPackageName( + fake_activity), + package_name + "." + fake_activity); + + std::string empty_string = ""; + EXPECT_EQ(ArcIntentHelperBridge::AppendStringToIntentHelperPackageName( + empty_string), + package_name + "."); } } // namespace arc diff --git a/chromium/components/arc/intent_helper/intent_filter.cc b/chromium/components/arc/intent_helper/intent_filter.cc index e8a80455f52..32fb9a143f0 100644 --- a/chromium/components/arc/intent_helper/intent_filter.cc +++ b/chromium/components/arc/intent_helper/intent_filter.cc @@ -115,11 +115,10 @@ bool IntentFilter::AuthorityEntry::Match(const GURL& url) const { if (wild_) { return base::EndsWith(url.host_piece(), host_, base::CompareCase::INSENSITIVE_ASCII); - } else { - // TODO(kenobi): Not i18n-friendly. Figure out how to correctly deal with - // IDNs. - return host_ == base::ToLowerASCII(url.host_piece()); } + // TODO(kenobi): Not i18n-friendly. Figure out how to correctly deal with + // IDNs. + return host_ == base::ToLowerASCII(url.host_piece()); } IntentFilter::PatternMatcher::PatternMatcher() = default; diff --git a/chromium/components/arc/intent_helper/link_handler_model.cc b/chromium/components/arc/intent_helper/link_handler_model.cc index 42002920f6f..d70fcefdbc5 100644 --- a/chromium/components/arc/intent_helper/link_handler_model.cc +++ b/chromium/components/arc/intent_helper/link_handler_model.cc @@ -118,8 +118,8 @@ void LinkHandlerModel::OnUrlHandlerList( } const ArcIntentHelperBridge::GetResult result = intent_helper_bridge->GetActivityIcons( - activities, base::Bind(&LinkHandlerModel::NotifyObserver, - weak_ptr_factory_.GetWeakPtr())); + activities, base::BindOnce(&LinkHandlerModel::NotifyObserver, + weak_ptr_factory_.GetWeakPtr())); icon_info_notified = internal::ActivityIconLoader::HasIconsReadyCallbackRun(result); } diff --git a/chromium/components/arc/lock_screen/arc_lock_screen_bridge.cc b/chromium/components/arc/lock_screen/arc_lock_screen_bridge.cc index 1be29eb72ed..5c833fd3c08 100644 --- a/chromium/components/arc/lock_screen/arc_lock_screen_bridge.cc +++ b/chromium/components/arc/lock_screen/arc_lock_screen_bridge.cc @@ -57,7 +57,7 @@ ArcLockScreenBridge::~ArcLockScreenBridge() { session_manager::SessionManager::Get()->RemoveObserver(this); } -void ArcLockScreenBridge::OnInstanceReady() { +void ArcLockScreenBridge::OnConnectionReady() { SendDeviceLockedState(); } diff --git a/chromium/components/arc/lock_screen/arc_lock_screen_bridge.h b/chromium/components/arc/lock_screen/arc_lock_screen_bridge.h index 7c1aabe2de2..bd9476c995c 100644 --- a/chromium/components/arc/lock_screen/arc_lock_screen_bridge.h +++ b/chromium/components/arc/lock_screen/arc_lock_screen_bridge.h @@ -8,7 +8,7 @@ #include "base/macros.h" #include "base/threading/thread_checker.h" #include "components/arc/common/lock_screen.mojom.h" -#include "components/arc/instance_holder.h" +#include "components/arc/connection_observer.h" #include "components/keyed_service/core/keyed_service.h" #include "components/session_manager/core/session_manager_observer.h" @@ -23,7 +23,7 @@ class ArcBridgeService; // This class notifies the Chrome OS side lock screen state to the container. class ArcLockScreenBridge : public KeyedService, - public InstanceHolder::Observer, + public ConnectionObserver, public session_manager::SessionManagerObserver { public: // Returns singleton instance for the given BrowserContext, @@ -35,8 +35,8 @@ class ArcLockScreenBridge ArcBridgeService* bridge_service); ~ArcLockScreenBridge() override; - // InstanceHolder::Observer overrides: - void OnInstanceReady() override; + // ConnectionObserver overrides: + void OnConnectionReady() override; // session_manager::SessionManagerObserver overrides. void OnSessionStateChanged() override; diff --git a/chromium/components/arc/metrics/arc_metrics_service.cc b/chromium/components/arc/metrics/arc_metrics_service.cc index c1d2e3da8e2..79de7ed8d03 100644 --- a/chromium/components/arc/metrics/arc_metrics_service.cc +++ b/chromium/components/arc/metrics/arc_metrics_service.cc @@ -67,6 +67,11 @@ class ArcMetricsServiceFactory } // namespace +// static +BrowserContextKeyedServiceFactory* ArcMetricsService::GetFactory() { + return ArcMetricsServiceFactory::GetInstance(); +} + // static ArcMetricsService* ArcMetricsService::GetForBrowserContext( content::BrowserContext* context) { @@ -76,43 +81,25 @@ ArcMetricsService* ArcMetricsService::GetForBrowserContext( ArcMetricsService::ArcMetricsService(content::BrowserContext* context, ArcBridgeService* bridge_service) : arc_bridge_service_(bridge_service), - binding_(this), process_observer_(this), weak_ptr_factory_(this) { - arc_bridge_service_->metrics()->AddObserver(this); + arc_bridge_service_->metrics()->SetHost(this); arc_bridge_service_->process()->AddObserver(&process_observer_); } ArcMetricsService::~ArcMetricsService() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); arc_bridge_service_->process()->RemoveObserver(&process_observer_); - arc_bridge_service_->metrics()->RemoveObserver(this); -} - -void ArcMetricsService::OnInstanceReady() { - VLOG(2) << "Start metrics service."; - // Retrieve ARC start time from session manager. - chromeos::SessionManagerClient* session_manager_client = - chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); - session_manager_client->GetArcStartTime( - base::BindOnce(&ArcMetricsService::OnArcStartTimeRetrieved, - weak_ptr_factory_.GetWeakPtr())); + arc_bridge_service_->metrics()->SetHost(nullptr); } -void ArcMetricsService::OnInstanceClosed() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - VLOG(2) << "Close metrics service."; - if (binding_.is_bound()) - binding_.Unbind(); -} - -void ArcMetricsService::OnProcessInstanceReady() { +void ArcMetricsService::OnProcessConnectionReady() { VLOG(2) << "Start updating process list."; timer_.Start(FROM_HERE, kRequestProcessListPeriod, this, &ArcMetricsService::RequestProcessList); } -void ArcMetricsService::OnProcessInstanceClosed() { +void ArcMetricsService::OnProcessConnectionClosed() { VLOG(2) << "Stop updating process list."; timer_.Stop(); } @@ -154,46 +141,26 @@ void ArcMetricsService::ParseProcessList( } void ArcMetricsService::OnArcStartTimeRetrieved( + std::vector events, + mojom::BootType boot_type, base::Optional arc_start_time) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (!arc_start_time.has_value()) { LOG(ERROR) << "Failed to retrieve ARC start timeticks."; return; } - auto* instance = - ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->metrics(), Init); - if (!instance) - return; + VLOG(2) << "ARC start @" << arc_start_time.value(); - // The binding of host interface is deferred until the ARC start time is - // retrieved here because it prevents race condition of the ARC start - // time availability in ReportBootProgress(). - if (!binding_.is_bound()) { - mojom::MetricsHostPtr host_ptr; - binding_.Bind(mojo::MakeRequest(&host_ptr)); - instance->Init(std::move(host_ptr)); - } - arc_start_time_ = arc_start_time.value(); - VLOG(2) << "ARC start @" << arc_start_time_; -} - -void ArcMetricsService::ReportBootProgress( - std::vector events, - mojom::BootType boot_type) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (boot_type == mojom::BootType::UNKNOWN) { - LOG(WARNING) << "boot_type is unknown. Skip recording UMA."; - return; - } - int64_t arc_start_time_in_ms = - (arc_start_time_ - base::TimeTicks()).InMilliseconds(); + DCHECK_NE(mojom::BootType::UNKNOWN, boot_type); const std::string suffix = BootTypeToString(boot_type); for (const auto& event : events) { VLOG(2) << "Report boot progress event:" << event->event << "@" << event->uptimeMillis; const std::string name = "Arc." + event->event + suffix; - const base::TimeDelta elapsed_time = base::TimeDelta::FromMilliseconds( - event->uptimeMillis - arc_start_time_in_ms); + const base::TimeTicks uptime = + base::TimeDelta::FromMilliseconds(event->uptimeMillis) + + base::TimeTicks(); + const base::TimeDelta elapsed_time = uptime - arc_start_time.value(); base::UmaHistogramCustomTimes(name, elapsed_time, kUmaMinTime, kUmaMaxTime, kUmaNumBuckets); if (event->event.compare(kBootProgressEnableScreen) == 0) { @@ -204,18 +171,35 @@ void ArcMetricsService::ReportBootProgress( } } +void ArcMetricsService::ReportBootProgress( + std::vector events, + mojom::BootType boot_type) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (boot_type == mojom::BootType::UNKNOWN) { + LOG(WARNING) << "boot_type is unknown. Skip recording UMA."; + return; + } + + // Retrieve ARC start time from session manager. + chromeos::SessionManagerClient* session_manager_client = + chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); + session_manager_client->GetArcStartTime(base::BindOnce( + &ArcMetricsService::OnArcStartTimeRetrieved, + weak_ptr_factory_.GetWeakPtr(), std::move(events), boot_type)); +} + ArcMetricsService::ProcessObserver::ProcessObserver( ArcMetricsService* arc_metrics_service) : arc_metrics_service_(arc_metrics_service) {} ArcMetricsService::ProcessObserver::~ProcessObserver() = default; -void ArcMetricsService::ProcessObserver::OnInstanceReady() { - arc_metrics_service_->OnProcessInstanceReady(); +void ArcMetricsService::ProcessObserver::OnConnectionReady() { + arc_metrics_service_->OnProcessConnectionReady(); } -void ArcMetricsService::ProcessObserver::OnInstanceClosed() { - arc_metrics_service_->OnProcessInstanceClosed(); +void ArcMetricsService::ProcessObserver::OnConnectionClosed() { + arc_metrics_service_->OnProcessConnectionClosed(); } } // namespace arc diff --git a/chromium/components/arc/metrics/arc_metrics_service.h b/chromium/components/arc/metrics/arc_metrics_service.h index 2f1f6624cba..76ea2e803ed 100644 --- a/chromium/components/arc/metrics/arc_metrics_service.h +++ b/chromium/components/arc/metrics/arc_metrics_service.h @@ -14,9 +14,10 @@ #include "base/timer/timer.h" #include "components/arc/common/metrics.mojom.h" #include "components/arc/common/process.mojom.h" -#include "components/arc/instance_holder.h" +#include "components/arc/connection_observer.h" #include "components/keyed_service/core/keyed_service.h" -#include "mojo/public/cpp/bindings/binding.h" + +class BrowserContextKeyedServiceFactory; namespace content { class BrowserContext; @@ -27,11 +28,12 @@ namespace arc { class ArcBridgeService; // Collects information from other ArcServices and send UMA metrics. -class ArcMetricsService - : public KeyedService, - public InstanceHolder::Observer, - public mojom::MetricsHost { +class ArcMetricsService : public KeyedService, + public mojom::MetricsHost { public: + // Returns the factory instance for this class. + static BrowserContextKeyedServiceFactory* GetFactory(); + // Returns singleton instance for the given BrowserContext, // or nullptr if the browser |context| is not allowed to use ARC. static ArcMetricsService* GetForBrowserContext( @@ -41,13 +43,9 @@ class ArcMetricsService ArcBridgeService* bridge_service); ~ArcMetricsService() override; - // InstanceHolder::Observer overrides. - void OnInstanceReady() override; - void OnInstanceClosed() override; - - // Implementations for InstanceHolder::Observer. - void OnProcessInstanceReady(); - void OnProcessInstanceClosed(); + // Implementations for ConnectionObserver. + void OnProcessConnectionReady(); + void OnProcessConnectionClosed(); // MetricsHost overrides. void ReportBootProgress(std::vector events, @@ -55,16 +53,15 @@ class ArcMetricsService private: // Adapter to be able to also observe ProcessInstance events. - class ProcessObserver - : public InstanceHolder::Observer { + class ProcessObserver : public ConnectionObserver { public: explicit ProcessObserver(ArcMetricsService* arc_metrics_service); ~ProcessObserver() override; private: - // InstanceHolder::Observer overrides. - void OnInstanceReady() override; - void OnInstanceClosed() override; + // ConnectionObserver overrides. + void OnConnectionReady() override; + void OnConnectionClosed() override; ArcMetricsService* arc_metrics_service_; @@ -75,19 +72,17 @@ class ArcMetricsService void ParseProcessList(std::vector processes); // DBus callbacks. - void OnArcStartTimeRetrieved(base::Optional arc_start_time); + void OnArcStartTimeRetrieved(std::vector events, + mojom::BootType boot_type, + base::Optional arc_start_time); THREAD_CHECKER(thread_checker_); ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager. - mojo::Binding binding_; - ProcessObserver process_observer_; base::RepeatingTimer timer_; - base::TimeTicks arc_start_time_; - // Always keep this the last member of this class to make sure it's the // first thing to be destructed. base::WeakPtrFactory weak_ptr_factory_; diff --git a/chromium/components/arc/metrics/arc_metrics_service_unittest.cc b/chromium/components/arc/metrics/arc_metrics_service_unittest.cc new file mode 100644 index 00000000000..75fc712b10b --- /dev/null +++ b/chromium/components/arc/metrics/arc_metrics_service_unittest.cc @@ -0,0 +1,228 @@ +// Copyright 2017 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 "components/arc/metrics/arc_metrics_service.h" + +#include +#include +#include +#include +#include + +#include "base/metrics/histogram_samples.h" +#include "base/run_loop.h" +#include "base/test/histogram_tester.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/fake_session_manager_client.h" +#include "components/arc/arc_bridge_service.h" +#include "components/arc/arc_service_manager.h" +#include "components/arc/test/fake_arc_session.h" +#include "components/arc/test/test_browser_context.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace arc { +namespace { + +// The event names the container sends to Chrome. +constexpr std::array kBootEvents{ + "boot_progress_start", + "boot_progress_preload_start", + "boot_progress_preload_end", + "boot_progress_system_run", + "boot_progress_pms_start", + "boot_progress_pms_system_scan_start", + "boot_progress_pms_data_scan_start", + "boot_progress_pms_scan_end", + "boot_progress_pms_ready", + "boot_progress_ams_ready", + "boot_progress_enable_screen"}; + +ArcMetricsService* GetArcMetricsService(content::BrowserContext* context) { + ArcMetricsService::GetFactory()->SetTestingFactoryAndUse( + context, + [](content::BrowserContext* context) -> std::unique_ptr { + return std::make_unique( + context, ArcServiceManager::Get()->arc_bridge_service()); + }); + return ArcMetricsService::GetForBrowserContext(context); +} + +class ArcMetricsServiceTest : public testing::Test { + public: + ArcMetricsServiceTest() + : arc_service_manager_(std::make_unique()), + context_(std::make_unique()), + metrics_service_(GetArcMetricsService(context_.get())) { + chromeos::DBusThreadManager::GetSetterForTesting()->SetSessionManagerClient( + std::make_unique()); + GetSessionManagerClient()->set_arc_available(true); + } + + ~ArcMetricsServiceTest() override { + metrics_service_->Shutdown(); + chromeos::DBusThreadManager::Shutdown(); + } + + ArcMetricsService* metrics_service() { return metrics_service_; } + + protected: + void SetArcStartTimeInMs(uint64_t arc_start_time_in_ms) { + const base::TimeTicks arc_start_time = + base::TimeDelta::FromMilliseconds(arc_start_time_in_ms) + + base::TimeTicks(); + GetSessionManagerClient()->set_arc_start_time(arc_start_time); + } + + std::vector GetBootProgressEvents( + uint64_t start_in_ms, + uint64_t step_in_ms) { + std::vector events; + for (size_t i = 0; i < kBootEvents.size(); ++i) { + events.emplace_back(mojom::BootProgressEvent::New( + kBootEvents[i], start_in_ms + (step_in_ms * i))); + } + return events; + } + + private: + chromeos::FakeSessionManagerClient* GetSessionManagerClient() { + return static_cast( + chromeos::DBusThreadManager::Get()->GetSessionManagerClient()); + } + + content::TestBrowserThreadBundle thread_bundle_; + std::unique_ptr arc_service_manager_; + std::unique_ptr context_; + + ArcMetricsService* const metrics_service_; + + DISALLOW_COPY_AND_ASSIGN(ArcMetricsServiceTest); +}; + +// Tests that ReportBootProgress() actually records UMA stats. +TEST_F(ArcMetricsServiceTest, ReportBootProgress_FirstBoot) { + // Start the full ARC container at t=10. Also set boot_progress_start to 10, + // boot_progress_preload_start to 11, and so on. + constexpr uint64_t kArcStartTimeMs = 10; + SetArcStartTimeInMs(kArcStartTimeMs); + std::vector events( + GetBootProgressEvents(kArcStartTimeMs, 1 /* step_in_ms */)); + + // Call ReportBootProgress() and then confirm that + // Arc.boot_progress_start.FirstBoot is recorded with 0 (ms), + // Arc.boot_progress_preload_start.FirstBoot is with 1 (ms), etc. + base::HistogramTester tester; + metrics_service()->ReportBootProgress(std::move(events), + mojom::BootType::FIRST_BOOT); + base::RunLoop().RunUntilIdle(); + for (size_t i = 0; i < kBootEvents.size(); ++i) { + tester.ExpectUniqueSample( + std::string("Arc.") + kBootEvents[i] + ".FirstBoot", i, + 1 /* count of the sample */); + } + // Confirm that Arc.AndroidBootTime.FirstBoot is also recorded, and has the + // same value as "Arc.boot_progress_enable_screen.FirstBoot". + std::unique_ptr samples = + tester.GetHistogramSamplesSinceCreation( + "Arc." + std::string(kBootEvents.back()) + ".FirstBoot"); + ASSERT_TRUE(samples.get()); + tester.ExpectUniqueSample("Arc.AndroidBootTime.FirstBoot", samples->sum(), 1); +} + +// Does the same but with negative values and FIRST_BOOT_AFTER_UPDATE. +TEST_F(ArcMetricsServiceTest, ReportBootProgress_FirstBootAfterUpdate) { + // Start the full ARC container at t=10. Also set boot_progress_start to 5, + // boot_progress_preload_start to 7, and so on. This can actually happen + // because the mini container can finish up to boot_progress_preload_end + // before the full container is started. + constexpr uint64_t kArcStartTimeMs = 10; + SetArcStartTimeInMs(kArcStartTimeMs); + std::vector events( + GetBootProgressEvents(kArcStartTimeMs - 5, 2 /* step_in_ms */)); + + // Call ReportBootProgress() and then confirm that + // Arc.boot_progress_start.FirstBoot is recorded with 0 (ms), + // Arc.boot_progress_preload_start.FirstBoot is with 0 (ms), etc. Unlike our + // performance dashboard where negative performance numbers are treated as-is, + // UMA treats them as zeros. + base::HistogramTester tester; + // This time, use mojom::BootType::FIRST_BOOT_AFTER_UPDATE. + metrics_service()->ReportBootProgress( + std::move(events), mojom::BootType::FIRST_BOOT_AFTER_UPDATE); + base::RunLoop().RunUntilIdle(); + for (size_t i = 0; i < kBootEvents.size(); ++i) { + const int expected = std::max(0, i * 2 - 5); + tester.ExpectUniqueSample( + std::string("Arc.") + kBootEvents[i] + ".FirstBootAfterUpdate", + expected, 1); + } + std::unique_ptr samples = + tester.GetHistogramSamplesSinceCreation( + "Arc." + std::string(kBootEvents.back()) + ".FirstBootAfterUpdate"); + ASSERT_TRUE(samples.get()); + tester.ExpectUniqueSample("Arc.AndroidBootTime.FirstBootAfterUpdate", + samples->sum(), 1); +} + +// Does the same but with REGULAR_BOOT. +TEST_F(ArcMetricsServiceTest, ReportBootProgress_RegularBoot) { + constexpr uint64_t kArcStartTimeMs = 10; + SetArcStartTimeInMs(kArcStartTimeMs); + std::vector events( + GetBootProgressEvents(kArcStartTimeMs - 5, 2 /* step_in_ms */)); + + base::HistogramTester tester; + metrics_service()->ReportBootProgress(std::move(events), + mojom::BootType::REGULAR_BOOT); + base::RunLoop().RunUntilIdle(); + for (size_t i = 0; i < kBootEvents.size(); ++i) { + const int expected = std::max(0, i * 2 - 5); + tester.ExpectUniqueSample( + std::string("Arc.") + kBootEvents[i] + ".RegularBoot", expected, 1); + } + std::unique_ptr samples = + tester.GetHistogramSamplesSinceCreation( + "Arc." + std::string(kBootEvents.back()) + ".RegularBoot"); + ASSERT_TRUE(samples.get()); + tester.ExpectUniqueSample("Arc.AndroidBootTime.RegularBoot", samples->sum(), + 1); +} + +// Tests that no UMA is recorded when nothing is reported. +TEST_F(ArcMetricsServiceTest, ReportBootProgress_EmptyResults) { + SetArcStartTimeInMs(100); + std::vector events; // empty + + base::HistogramTester tester; + metrics_service()->ReportBootProgress(std::move(events), + mojom::BootType::FIRST_BOOT); + base::RunLoop().RunUntilIdle(); + for (size_t i = 0; i < kBootEvents.size(); ++i) { + tester.ExpectTotalCount(std::string("Arc.") + kBootEvents[i] + ".FirstBoot", + 0); + } + tester.ExpectTotalCount("Arc.AndroidBootTime.FirstBoot", 0); +} + +// Tests that no UMA is recorded when BootType is invalid. +TEST_F(ArcMetricsServiceTest, ReportBootProgress_InvalidBootType) { + SetArcStartTimeInMs(100); + std::vector events( + GetBootProgressEvents(123, 456)); + base::HistogramTester tester; + metrics_service()->ReportBootProgress(std::move(events), + mojom::BootType::UNKNOWN); + base::RunLoop().RunUntilIdle(); + for (const std::string& suffix : + {".FirstBoot", ".FirstBootAfterUpdate", ".RegularBoot"}) { + tester.ExpectTotalCount("Arc." + (kBootEvents.front() + suffix), 0); + tester.ExpectTotalCount("Arc." + (kBootEvents.back() + suffix), 0); + tester.ExpectTotalCount("Arc.AndroidBootTime" + suffix, 0); + } +} + +} // namespace +} // namespace arc diff --git a/chromium/components/arc/midis/arc_midis_bridge.cc b/chromium/components/arc/midis/arc_midis_bridge.cc index 32bec549440..657fcc4e32b 100644 --- a/chromium/components/arc/midis/arc_midis_bridge.cc +++ b/chromium/components/arc/midis/arc_midis_bridge.cc @@ -49,26 +49,12 @@ ArcMidisBridge* ArcMidisBridge::GetForBrowserContext( ArcMidisBridge::ArcMidisBridge(content::BrowserContext* context, ArcBridgeService* bridge_service) - : arc_bridge_service_(bridge_service), binding_(this), weak_factory_(this) { - arc_bridge_service_->midis()->AddObserver(this); + : arc_bridge_service_(bridge_service), weak_factory_(this) { + arc_bridge_service_->midis()->SetHost(this); } ArcMidisBridge::~ArcMidisBridge() { - arc_bridge_service_->midis()->RemoveObserver(this); -} - -void ArcMidisBridge::OnInstanceReady() { - DVLOG(1) << "ArcMidisBridge::OnInstanceReady() called."; - mojom::MidisInstance* midis_instance = - ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->midis(), Init); - DCHECK(midis_instance); - - DVLOG(1) << "Calling Init on the other side of MidisInstance."; - mojom::MidisHostPtr host_proxy; - binding_.Bind(mojo::MakeRequest(&host_proxy)); - midis_instance->Init(std::move(host_proxy)); - binding_.set_connection_error_handler(base::Bind( - &mojo::Binding::Close, base::Unretained(&binding_))); + arc_bridge_service_->midis()->SetHost(nullptr); } void ArcMidisBridge::OnBootstrapMojoConnection( diff --git a/chromium/components/arc/midis/arc_midis_bridge.h b/chromium/components/arc/midis/arc_midis_bridge.h index b08d0fc5a08..21bbf23c662 100644 --- a/chromium/components/arc/midis/arc_midis_bridge.h +++ b/chromium/components/arc/midis/arc_midis_bridge.h @@ -11,9 +11,7 @@ #include "base/macros.h" #include "components/arc/common/midis.mojom.h" -#include "components/arc/instance_holder.h" #include "components/keyed_service/core/keyed_service.h" -#include "mojo/public/cpp/bindings/binding.h" namespace content { class BrowserContext; @@ -24,7 +22,6 @@ namespace arc { class ArcBridgeService; class ArcMidisBridge : public KeyedService, - public InstanceHolder::Observer, public mojom::MidisHost { public: // Returns singleton instance for the given BrowserContext, @@ -35,9 +32,6 @@ class ArcMidisBridge : public KeyedService, ArcBridgeService* bridge_service); ~ArcMidisBridge() override; - // Overridden from InstanceHolder::Observer: - void OnInstanceReady() override; - // Midis Mojo host interface void Connect(mojom::MidisServerRequest request, mojom::MidisClientPtr client_ptr) override; @@ -48,7 +42,6 @@ class ArcMidisBridge : public KeyedService, bool result); ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager. - mojo::Binding binding_; mojom::MidisHostPtr midis_host_ptr_; // WeakPtrFactory to use for callbacks. diff --git a/chromium/components/arc/net/arc_net_host_impl.cc b/chromium/components/arc/net/arc_net_host_impl.cc index e6f3e4f7366..50f464a4fd4 100644 --- a/chromium/components/arc/net/arc_net_host_impl.cc +++ b/chromium/components/arc/net/arc_net_host_impl.cc @@ -73,14 +73,13 @@ arc::mojom::SecurityType TranslateONCWifiSecurityType( true /* required */); if (type == onc::wifi::kWEP_PSK) return arc::mojom::SecurityType::WEP_PSK; - else if (type == onc::wifi::kWEP_8021X) + if (type == onc::wifi::kWEP_8021X) return arc::mojom::SecurityType::WEP_8021X; - else if (type == onc::wifi::kWPA_PSK) + if (type == onc::wifi::kWPA_PSK) return arc::mojom::SecurityType::WPA_PSK; - else if (type == onc::wifi::kWPA_EAP) + if (type == onc::wifi::kWPA_EAP) return arc::mojom::SecurityType::WPA_EAP; - else - return arc::mojom::SecurityType::NONE; + return arc::mojom::SecurityType::NONE; } arc::mojom::WiFiPtr TranslateONCWifi(const base::DictionaryValue* dict) { @@ -171,7 +170,7 @@ arc::mojom::ConnectionStateType TranslateONCConnectionState( if (connection_state == onc::connection_state::kConnected) return arc::mojom::ConnectionStateType::CONNECTED; - else if (connection_state == onc::connection_state::kConnecting) + if (connection_state == onc::connection_state::kConnecting) return arc::mojom::ConnectionStateType::CONNECTING; return arc::mojom::ConnectionStateType::NOT_CONNECTED; } @@ -362,7 +361,8 @@ ArcNetHostImpl* ArcNetHostImpl::GetForBrowserContext( ArcNetHostImpl::ArcNetHostImpl(content::BrowserContext* context, ArcBridgeService* bridge_service) - : arc_bridge_service_(bridge_service), binding_(this), weak_factory_(this) { + : arc_bridge_service_(bridge_service), weak_factory_(this) { + arc_bridge_service_->net()->SetHost(this); arc_bridge_service_->net()->AddObserver(this); } @@ -373,18 +373,12 @@ ArcNetHostImpl::~ArcNetHostImpl() { GetNetworkConnectionHandler()->RemoveObserver(this); } arc_bridge_service_->net()->RemoveObserver(this); + arc_bridge_service_->net()->SetHost(nullptr); } -void ArcNetHostImpl::OnInstanceReady() { +void ArcNetHostImpl::OnConnectionReady() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - mojom::NetHostPtr host; - binding_.Bind(MakeRequest(&host)); - auto* instance = - ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->net(), Init); - DCHECK(instance); - instance->Init(std::move(host)); - if (chromeos::NetworkHandler::IsInitialized()) { GetStateHandler()->AddObserver(this, FROM_HERE); GetNetworkConnectionHandler()->AddObserver(this); @@ -404,7 +398,7 @@ void ArcNetHostImpl::OnInstanceReady() { } } -void ArcNetHostImpl::OnInstanceClosed() { +void ArcNetHostImpl::OnConnectionClosed() { if (!observing_network_state_) return; @@ -599,9 +593,8 @@ bool ArcNetHostImpl::GetNetworkPathFromGuid(const std::string& guid, if (cached_guid_ == guid) { *path = cached_service_path_; return true; - } else { - return false; } + return false; } void ArcNetHostImpl::ForgetNetwork(const std::string& guid, @@ -700,21 +693,21 @@ void ArcNetHostImpl::ScanCompleted(const chromeos::DeviceState* /*unused*/) { net_instance->ScanCompleted(); } -void ArcNetHostImpl::GetDefaultNetwork(GetDefaultNetworkCallback callback) { - const chromeos::NetworkState* default_network; - - // Expose Chrome OS VPNs to Android, but if ARC VPN is active, only expose - // the underlying physical interface. +const chromeos::NetworkState* ArcNetHostImpl::GetDefaultNetworkFromChrome() { + // If an Android VPN is connected, report the underlying physical + // connection only. Never tell Android about its own VPN. + // If a Chrome OS VPN is connected, report the Chrome OS VPN as the + // default connection. if (arc_vpn_service_path_.empty()) { - default_network = GetStateHandler()->DefaultNetwork(); - } else { - default_network = GetStateHandler()->FirstNetworkByType( - chromeos::NetworkTypePattern::NonVirtual()); + return GetShillBackedNetwork(GetStateHandler()->DefaultNetwork()); } - // Some network types are not backed by Shill; make sure to pass a Shill- - // backed network to ARC to ensure that it can use its network connection. - default_network = GetShillBackedNetwork(default_network); + return GetShillBackedNetwork(GetStateHandler()->ConnectedNetworkByType( + chromeos::NetworkTypePattern::NonVirtual())); +} + +void ArcNetHostImpl::GetDefaultNetwork(GetDefaultNetworkCallback callback) { + const chromeos::NetworkState* default_network = GetDefaultNetworkFromChrome(); if (!default_network) { VLOG(1) << "GetDefaultNetwork: no default network"; @@ -746,20 +739,10 @@ void ArcNetHostImpl::DefaultNetworkSuccessCallback( TranslateONCConfiguration(&dictionary)); } -void ArcNetHostImpl::DefaultNetworkChanged( - const chromeos::NetworkState* network) { - // If an ARC VPN is connected, the default network will point to the - // ARC VPN but we cannot tell ARC about that. ARC needs to continue - // believing that the current physical network is the default network. - // The medium term fix for this is go/arc-multinet which will report - // status for each interface separately. - if (!arc_vpn_service_path_.empty()) - return; +void ArcNetHostImpl::UpdateDefaultNetwork() { + const chromeos::NetworkState* default_network = GetDefaultNetworkFromChrome(); - const chromeos::NetworkState* shill_backed_network = - GetShillBackedNetwork(network); - - if (!shill_backed_network) { + if (!default_network) { VLOG(1) << "No default network"; auto* net_instance = ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->net(), DefaultNetworkChanged); @@ -768,15 +751,21 @@ void ArcNetHostImpl::DefaultNetworkChanged( return; } - VLOG(1) << "New default network: " << shill_backed_network->path(); + VLOG(1) << "New default network: " << default_network->path() << " (" + << default_network->type() << ")"; std::string user_id_hash = chromeos::LoginState::Get()->primary_user_hash(); GetManagedConfigurationHandler()->GetProperties( - user_id_hash, shill_backed_network->path(), + user_id_hash, default_network->path(), base::Bind(&ArcNetHostImpl::DefaultNetworkSuccessCallback, weak_factory_.GetWeakPtr()), base::Bind(&DefaultNetworkFailureCallback)); } +void ArcNetHostImpl::DefaultNetworkChanged( + const chromeos::NetworkState* network) { + UpdateDefaultNetwork(); +} + void ArcNetHostImpl::DeviceListChanged() { auto* net_instance = ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->net(), WifiEnabledStateChanged); @@ -961,6 +950,12 @@ void ArcNetHostImpl::DisconnectRequested(const std::string& service_path) { void ArcNetHostImpl::NetworkConnectionStateChanged( const chromeos::NetworkState* network) { + // DefaultNetworkChanged() won't be invoked if an ARC VPN is the default + // network and the underlying physical connection changed, so check for + // that condition here. This is invoked any time any service state + // changes. + UpdateDefaultNetwork(); + const chromeos::NetworkState* shill_backed_network = GetShillBackedNetwork(network); if (!shill_backed_network) @@ -979,6 +974,14 @@ void ArcNetHostImpl::NetworkConnectionStateChanged( DisconnectArcVpn(); } +void ArcNetHostImpl::NetworkListChanged() { + // This is invoked any time the list of services is reordered or changed. + // During the transition when a new service comes online, it will + // temporarily be ranked below "inferior" services. This callback + // informs us that shill's ordering has been updated. + UpdateDefaultNetwork(); +} + void ArcNetHostImpl::OnShuttingDown() { DCHECK(observing_network_state_); GetStateHandler()->RemoveObserver(this, FROM_HERE); diff --git a/chromium/components/arc/net/arc_net_host_impl.h b/chromium/components/arc/net/arc_net_host_impl.h index 51f6a304b7c..fdc133d97d2 100644 --- a/chromium/components/arc/net/arc_net_host_impl.h +++ b/chromium/components/arc/net/arc_net_host_impl.h @@ -19,9 +19,8 @@ #include "chromeos/network/network_connection_observer.h" #include "chromeos/network/network_state_handler_observer.h" #include "components/arc/common/net.mojom.h" -#include "components/arc/instance_holder.h" +#include "components/arc/connection_observer.h" #include "components/keyed_service/core/keyed_service.h" -#include "mojo/public/cpp/bindings/binding.h" namespace content { class BrowserContext; @@ -33,7 +32,7 @@ class ArcBridgeService; // Private implementation of ArcNetHost. class ArcNetHostImpl : public KeyedService, - public InstanceHolder::Observer, + public ConnectionObserver, public chromeos::NetworkConnectionObserver, public chromeos::NetworkStateHandlerObserver, public mojom::NetHost { @@ -87,17 +86,20 @@ class ArcNetHostImpl : public KeyedService, void DefaultNetworkChanged(const chromeos::NetworkState* network) override; void NetworkConnectionStateChanged( const chromeos::NetworkState* network) override; + void NetworkListChanged() override; void DeviceListChanged() override; void GetDefaultNetwork(GetDefaultNetworkCallback callback) override; // Overriden from chromeos::NetworkConnectionObserver. void DisconnectRequested(const std::string& service_path) override; - // Overridden from ArcBridgeService::InterfaceObserver: - void OnInstanceReady() override; - void OnInstanceClosed() override; + // Overridden from ConnectionObserver: + void OnConnectionReady() override; + void OnConnectionClosed() override; private: + const chromeos::NetworkState* GetDefaultNetworkFromChrome(); + void UpdateDefaultNetwork(); void DefaultNetworkSuccessCallback(const std::string& service_path, const base::DictionaryValue& dictionary); @@ -154,7 +156,6 @@ class ArcNetHostImpl : public KeyedService, std::string arc_vpn_service_path_; THREAD_CHECKER(thread_checker_); - mojo::Binding binding_; base::WeakPtrFactory weak_factory_; DISALLOW_COPY_AND_ASSIGN(ArcNetHostImpl); diff --git a/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.cc b/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.cc index 5ad2f539eb7..3764676ebf4 100644 --- a/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.cc +++ b/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.cc @@ -46,21 +46,12 @@ ArcObbMounterBridge* ArcObbMounterBridge::GetForBrowserContext( ArcObbMounterBridge::ArcObbMounterBridge(content::BrowserContext* context, ArcBridgeService* bridge_service) - : arc_bridge_service_(bridge_service), binding_(this) { - arc_bridge_service_->obb_mounter()->AddObserver(this); + : arc_bridge_service_(bridge_service) { + arc_bridge_service_->obb_mounter()->SetHost(this); } ArcObbMounterBridge::~ArcObbMounterBridge() { - arc_bridge_service_->obb_mounter()->RemoveObserver(this); -} - -void ArcObbMounterBridge::OnInstanceReady() { - mojom::ObbMounterInstance* obb_mounter_instance = - ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->obb_mounter(), Init); - DCHECK(obb_mounter_instance); - mojom::ObbMounterHostPtr host_proxy; - binding_.Bind(mojo::MakeRequest(&host_proxy)); - obb_mounter_instance->Init(std::move(host_proxy)); + arc_bridge_service_->obb_mounter()->SetHost(nullptr); } void ArcObbMounterBridge::MountObb(const std::string& obb_file, diff --git a/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.h b/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.h index 571a83e0a62..8756ab62ebf 100644 --- a/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.h +++ b/chromium/components/arc/obb_mounter/arc_obb_mounter_bridge.h @@ -9,9 +9,7 @@ #include "base/macros.h" #include "components/arc/common/obb_mounter.mojom.h" -#include "components/arc/instance_holder.h" #include "components/keyed_service/core/keyed_service.h" -#include "mojo/public/cpp/bindings/binding.h" namespace content { class BrowserContext; @@ -24,7 +22,6 @@ class ArcBridgeService; // This class handles OBB mount/unmount requests from Android. class ArcObbMounterBridge : public KeyedService, - public InstanceHolder::Observer, public mojom::ObbMounterHost { public: // Returns singleton instance for the given BrowserContext, @@ -36,9 +33,6 @@ class ArcObbMounterBridge ArcBridgeService* bridge_service); ~ArcObbMounterBridge() override; - // InstanceHolder::Observer overrides: - void OnInstanceReady() override; - // mojom::ObbMounterHost overrides: void MountObb(const std::string& obb_file, const std::string& target_path, @@ -50,8 +44,6 @@ class ArcObbMounterBridge private: ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager. - mojo::Binding binding_; - DISALLOW_COPY_AND_ASSIGN(ArcObbMounterBridge); }; diff --git a/chromium/components/arc/power/DEPS b/chromium/components/arc/power/DEPS index ac7ae6d3982..2a902196e7c 100644 --- a/chromium/components/arc/power/DEPS +++ b/chromium/components/arc/power/DEPS @@ -1,4 +1,7 @@ include_rules = [ "+ash/shell.h", + "+content/public/common/service_manager_connection.h", "+ui/display/manager/chromeos", + "+services/device/public", + "+services/service_manager/public", ] diff --git a/chromium/components/arc/power/arc_power_bridge.cc b/chromium/components/arc/power/arc_power_bridge.cc index ef6a083460d..b584cd6135c 100644 --- a/chromium/components/arc/power/arc_power_bridge.cc +++ b/chromium/components/arc/power/arc_power_bridge.cc @@ -15,6 +15,11 @@ #include "components/arc/arc_bridge_service.h" #include "components/arc/arc_browser_context_keyed_service_factory_base.h" #include "components/arc/arc_service_manager.h" +#include "content/public/common/service_manager_connection.h" +#include "services/device/public/interfaces/constants.mojom.h" +#include "services/device/public/interfaces/wake_lock.mojom.h" +#include "services/device/public/interfaces/wake_lock_provider.mojom.h" +#include "services/service_manager/public/cpp/connector.h" namespace arc { namespace { @@ -45,6 +50,71 @@ class ArcPowerBridgeFactory } // namespace +// WakeLockRequestor requests a wake lock from the device service in response +// to wake lock requests of a given type from Android. A count is kept of +// outstanding Android requests so that only a single actual wake lock is used. +class ArcPowerBridge::WakeLockRequestor { + public: + WakeLockRequestor(device::mojom::WakeLockType type, + service_manager::Connector* connector) + : type_(type), connector_(connector) {} + ~WakeLockRequestor() = default; + + // Increments the number of outstanding requests from Android and requests a + // wake lock from the device service if this is the only request. + void AddRequest() { + num_android_requests_++; + if (num_android_requests_ > 1) + return; + + // Initialize |wake_lock_| if this is the first time we're using it. + if (!wake_lock_) { + device::mojom::WakeLockProviderPtr provider; + connector_->BindInterface(device::mojom::kServiceName, + mojo::MakeRequest(&provider)); + provider->GetWakeLockWithoutContext( + type_, device::mojom::WakeLockReason::kOther, "ARC", + mojo::MakeRequest(&wake_lock_)); + } + + wake_lock_->RequestWakeLock(); + } + + // Decrements the number of outstanding Android requests. Cancels the device + // service wake lock when the request count hits zero. + void RemoveRequest() { + DCHECK_GT(num_android_requests_, 0); + num_android_requests_--; + if (num_android_requests_ >= 1) + return; + + DCHECK(wake_lock_); + wake_lock_->CancelWakeLock(); + } + + // Runs the message loop until replies have been received for all pending + // requests on |wake_lock_|. + void FlushForTesting() { + if (wake_lock_) + wake_lock_.FlushForTesting(); + } + + private: + // Type of wake lock to request. + device::mojom::WakeLockType type_; + + // Used to get services. Not owned. + service_manager::Connector* const connector_ = nullptr; + + // Number of outstanding Android requests. + int num_android_requests_ = 0; + + // Lazily initialized in response to first request. + device::mojom::WakeLockPtr wake_lock_; + + DISALLOW_COPY_AND_ASSIGN(WakeLockRequestor); +}; + // static ArcPowerBridge* ArcPowerBridge::GetForBrowserContext( content::BrowserContext* context) { @@ -54,23 +124,29 @@ ArcPowerBridge* ArcPowerBridge::GetForBrowserContext( ArcPowerBridge::ArcPowerBridge(content::BrowserContext* context, ArcBridgeService* bridge_service) : arc_bridge_service_(bridge_service), - binding_(this), weak_ptr_factory_(this) { + arc_bridge_service_->power()->SetHost(this); arc_bridge_service_->power()->AddObserver(this); } ArcPowerBridge::~ArcPowerBridge() { - ReleaseAllDisplayWakeLocks(); arc_bridge_service_->power()->RemoveObserver(this); + arc_bridge_service_->power()->SetHost(nullptr); } -void ArcPowerBridge::OnInstanceReady() { - mojom::PowerInstance* power_instance = - ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->power(), Init); - DCHECK(power_instance); - mojom::PowerHostPtr host_proxy; - binding_.Bind(mojo::MakeRequest(&host_proxy)); - power_instance->Init(std::move(host_proxy)); +bool ArcPowerBridge::TriggerNotifyBrightnessTimerForTesting() { + if (!notify_brightness_timer_.IsRunning()) + return false; + notify_brightness_timer_.user_task().Run(); + return true; +} + +void ArcPowerBridge::FlushWakeLocksForTesting() { + for (const auto& it : wake_lock_requestors_) + it.second->FlushForTesting(); +} + +void ArcPowerBridge::OnConnectionReady() { // TODO(mash): Support this functionality without ash::Shell access in Chrome. if (ash::Shell::HasInstance()) ash::Shell::Get()->display_configurator()->AddObserver(this); @@ -79,20 +155,21 @@ void ArcPowerBridge::OnInstanceReady() { chromeos::DBusThreadManager::Get() ->GetPowerManagerClient() ->GetScreenBrightnessPercent( - base::Bind(&ArcPowerBridge::UpdateAndroidScreenBrightness, - weak_ptr_factory_.GetWeakPtr())); + base::BindOnce(&ArcPowerBridge::OnGetScreenBrightnessPercent, + weak_ptr_factory_.GetWeakPtr())); } -void ArcPowerBridge::OnInstanceClosed() { +void ArcPowerBridge::OnConnectionClosed() { // TODO(mash): Support this functionality without ash::Shell access in Chrome. if (ash::Shell::HasInstance()) ash::Shell::Get()->display_configurator()->RemoveObserver(this); chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> RemoveObserver(this); - ReleaseAllDisplayWakeLocks(); + wake_lock_requestors_.clear(); } -void ArcPowerBridge::SuspendImminent() { +void ArcPowerBridge::SuspendImminent( + power_manager::SuspendImminent::Reason reason) { mojom::PowerInstance* power_instance = ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->power(), Suspend); if (!power_instance) @@ -140,50 +217,39 @@ void ArcPowerBridge::OnPowerStateChanged( } void ArcPowerBridge::OnAcquireDisplayWakeLock(mojom::DisplayWakeLockType type) { - if (!chromeos::PowerPolicyController::IsInitialized()) { - LOG(WARNING) << "PowerPolicyController is not available"; - return; - } - chromeos::PowerPolicyController* controller = - chromeos::PowerPolicyController::Get(); - - int wake_lock_id = -1; switch (type) { case mojom::DisplayWakeLockType::BRIGHT: - wake_lock_id = controller->AddScreenWakeLock( - chromeos::PowerPolicyController::REASON_OTHER, "ARC"); + GetWakeLockRequestor(device::mojom::WakeLockType::kPreventDisplaySleep) + ->AddRequest(); break; case mojom::DisplayWakeLockType::DIM: - wake_lock_id = controller->AddDimWakeLock( - chromeos::PowerPolicyController::REASON_OTHER, "ARC"); + GetWakeLockRequestor( + device::mojom::WakeLockType::kPreventDisplaySleepAllowDimming) + ->AddRequest(); break; default: LOG(WARNING) << "Tried to take invalid wake lock type " << static_cast(type); return; } - wake_locks_.insert(std::make_pair(type, wake_lock_id)); } void ArcPowerBridge::OnReleaseDisplayWakeLock(mojom::DisplayWakeLockType type) { - if (!chromeos::PowerPolicyController::IsInitialized()) { - LOG(WARNING) << "PowerPolicyController is not available"; - return; - } - chromeos::PowerPolicyController* controller = - chromeos::PowerPolicyController::Get(); - - // From the perspective of the PowerPolicyController, all wake locks - // of a given type are equivalent, so it doesn't matter which one - // we pass to the controller here. - auto it = wake_locks_.find(type); - if (it == wake_locks_.end()) { - LOG(WARNING) << "Tried to release wake lock of type " - << static_cast(type) << " when none were taken"; - return; + switch (type) { + case mojom::DisplayWakeLockType::BRIGHT: + GetWakeLockRequestor(device::mojom::WakeLockType::kPreventDisplaySleep) + ->RemoveRequest(); + break; + case mojom::DisplayWakeLockType::DIM: + GetWakeLockRequestor( + device::mojom::WakeLockType::kPreventDisplaySleepAllowDimming) + ->RemoveRequest(); + break; + default: + LOG(WARNING) << "Tried to take invalid wake lock type " + << static_cast(type); + return; } - controller->RemoveWakeLock(it->second); - wake_locks_.erase(it); } void ArcPowerBridge::IsDisplayOn(IsDisplayOnCallback callback) { @@ -200,18 +266,32 @@ void ArcPowerBridge::OnScreenBrightnessUpdateRequest(double percent) { ->SetScreenBrightnessPercent(percent, true); } -void ArcPowerBridge::ReleaseAllDisplayWakeLocks() { - if (!chromeos::PowerPolicyController::IsInitialized()) { - LOG(WARNING) << "PowerPolicyController is not available"; - return; - } - chromeos::PowerPolicyController* controller = - chromeos::PowerPolicyController::Get(); +ArcPowerBridge::WakeLockRequestor* ArcPowerBridge::GetWakeLockRequestor( + device::mojom::WakeLockType type) { + auto it = wake_lock_requestors_.find(type); + if (it != wake_lock_requestors_.end()) + return it->second.get(); + + service_manager::Connector* connector = + connector_for_test_ + ? connector_for_test_ + : content::ServiceManagerConnection::GetForProcess()->GetConnector(); + DCHECK(connector); - for (const auto& it : wake_locks_) { - controller->RemoveWakeLock(it.second); + it = wake_lock_requestors_ + .emplace(type, std::make_unique(type, connector)) + .first; + return it->second.get(); +} + +void ArcPowerBridge::OnGetScreenBrightnessPercent( + base::Optional percent) { + if (!percent.has_value()) { + LOG(ERROR) + << "PowerManagerClient::GetScreenBrightnessPercent reports an error"; + return; } - wake_locks_.clear(); + UpdateAndroidScreenBrightness(percent.value()); } void ArcPowerBridge::UpdateAndroidScreenBrightness(double percent) { diff --git a/chromium/components/arc/power/arc_power_bridge.h b/chromium/components/arc/power/arc_power_bridge.h index 5aab1655c6f..31894c4b53b 100644 --- a/chromium/components/arc/power/arc_power_bridge.h +++ b/chromium/components/arc/power/arc_power_bridge.h @@ -6,19 +6,25 @@ #define COMPONENTS_ARC_POWER_ARC_POWER_BRIDGE_H_ #include +#include #include "base/macros.h" +#include "base/optional.h" #include "chromeos/dbus/power_manager_client.h" #include "components/arc/common/power.mojom.h" -#include "components/arc/instance_holder.h" +#include "components/arc/connection_observer.h" #include "components/keyed_service/core/keyed_service.h" -#include "mojo/public/cpp/bindings/binding.h" +#include "services/device/public/interfaces/wake_lock.mojom.h" #include "ui/display/manager/chromeos/display_configurator.h" namespace content { class BrowserContext; } // namespace content +namespace service_manager { +class Connector; +} // namespace service_manager + namespace arc { class ArcBridgeService; @@ -26,7 +32,7 @@ class ArcBridgeService; // ARC Power Client sets power management policy based on requests from // ARC instances. class ArcPowerBridge : public KeyedService, - public InstanceHolder::Observer, + public ConnectionObserver, public chromeos::PowerManagerClient::Observer, public display::DisplayConfigurator::Observer, public mojom::PowerHost { @@ -39,12 +45,24 @@ class ArcPowerBridge : public KeyedService, ArcBridgeService* bridge_service); ~ArcPowerBridge() override; - // InstanceHolder::Observer overrides. - void OnInstanceReady() override; - void OnInstanceClosed() override; + void set_connector_for_test(service_manager::Connector* connector) { + connector_for_test_ = connector; + } + + // If |notify_brightness_timer_| is set, runs it and returns true. Returns + // false otherwise. + bool TriggerNotifyBrightnessTimerForTesting() WARN_UNUSED_RESULT; + + // Runs the message loop until replies have been received for all pending + // device service requests in |wake_lock_requestors_|. + void FlushWakeLocksForTesting(); + + // ConnectionObserver overrides. + void OnConnectionReady() override; + void OnConnectionClosed() override; // chromeos::PowerManagerClient::Observer overrides. - void SuspendImminent() override; + void SuspendImminent(power_manager::SuspendImminent::Reason reason) override; void SuspendDone(const base::TimeDelta& sleep_duration) override; void BrightnessChanged(int level, bool user_initiated) override; @@ -58,15 +76,25 @@ class ArcPowerBridge : public KeyedService, void OnScreenBrightnessUpdateRequest(double percent) override; private: - void ReleaseAllDisplayWakeLocks(); + class WakeLockRequestor; + + // Returns the WakeLockRequestor for |type|, creating one if needed. + WakeLockRequestor* GetWakeLockRequestor(device::mojom::WakeLockType type); + + // Called on PowerManagerClient::GetScreenBrightnessPercent() completion. + void OnGetScreenBrightnessPercent(base::Optional percent); + void UpdateAndroidScreenBrightness(double percent); ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager. - mojo::Binding binding_; - // Stores a mapping of type -> wake lock ID for all wake locks - // held by ARC. - std::multimap wake_locks_; + // If non-null, used instead of the process-wide connector to fetch services. + service_manager::Connector* connector_for_test_ = nullptr; + + // Used to track Android wake lock requests and acquire and release device + // service wake locks as needed. + std::map> + wake_lock_requestors_; // Last time that the power manager notified about a brightness change. base::TimeTicks last_brightness_changed_time_; diff --git a/chromium/components/arc/power/arc_power_bridge_unittest.cc b/chromium/components/arc/power/arc_power_bridge_unittest.cc new file mode 100644 index 00000000000..e592c28fa6e --- /dev/null +++ b/chromium/components/arc/power/arc_power_bridge_unittest.cc @@ -0,0 +1,235 @@ +// Copyright 2017 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 "components/arc/power/arc_power_bridge.h" + +#include "base/run_loop.h" +#include "base/test/scoped_task_environment.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/fake_power_manager_client.h" +#include "chromeos/dbus/power_manager/suspend.pb.h" +#include "components/arc/arc_bridge_service.h" +#include "components/arc/common/power.mojom.h" +#include "components/arc/test/fake_power_instance.h" +#include "content/public/common/service_manager_connection.h" +#include "services/device/public/cpp/test/test_wake_lock_provider.h" +#include "services/service_manager/public/cpp/test/test_connector_factory.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace arc { + +using device::mojom::WakeLockType; + +class ArcPowerBridgeTest : public testing::Test { + public: + // Initial screen brightness percent for the Chrome OS power manager. + static constexpr double kInitialBrightness = 100.0; + + ArcPowerBridgeTest() { + chromeos::DBusThreadManager::Initialize(); + power_manager_client_ = static_cast( + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()); + power_manager_client_->set_screen_brightness_percent(kInitialBrightness); + + auto wake_lock_provider_ptr = + std::make_unique(); + wake_lock_provider_ = wake_lock_provider_ptr.get(); + + connector_factory_ = + std::make_unique( + std::move(wake_lock_provider_ptr)); + connector_ = connector_factory_->CreateConnector(); + + bridge_service_ = std::make_unique(); + power_bridge_ = std::make_unique(nullptr /* context */, + bridge_service_.get()); + power_bridge_->set_connector_for_test(connector_.get()); + CreatePowerInstance(); + } + + ~ArcPowerBridgeTest() override { + DestroyPowerInstance(); + power_bridge_.reset(); + chromeos::DBusThreadManager::Shutdown(); + } + + protected: + // Creates a FakePowerInstance for |bridge_service_|. This results in + // ArcPowerBridge::OnInstanceReady() being called. + void CreatePowerInstance() { + power_instance_ = std::make_unique(); + bridge_service_->power()->SetInstance(power_instance_.get(), + mojom::PowerInstance::Version_); + } + + // Destroys the FakePowerInstance. This results in + // ArcPowerBridge::OnInstanceClosed() being called. + void DestroyPowerInstance() { + bridge_service_->power()->SetInstance(nullptr, 0); + power_instance_.reset(); + } + + // Acquires or releases a display wake lock of type |type|. + void AcquireDisplayWakeLock(mojom::DisplayWakeLockType type) { + power_bridge_->OnAcquireDisplayWakeLock(type); + power_bridge_->FlushWakeLocksForTesting(); + } + void ReleaseDisplayWakeLock(mojom::DisplayWakeLockType type) { + power_bridge_->OnReleaseDisplayWakeLock(type); + power_bridge_->FlushWakeLocksForTesting(); + } + + base::test::ScopedTaskEnvironment scoped_task_environment_; + + std::unique_ptr connector_factory_; + std::unique_ptr connector_; + device::TestWakeLockProvider* wake_lock_provider_; + + chromeos::FakePowerManagerClient* power_manager_client_; // Not owned. + + std::unique_ptr bridge_service_; + std::unique_ptr power_instance_; + std::unique_ptr power_bridge_; + + private: + DISALLOW_COPY_AND_ASSIGN(ArcPowerBridgeTest); +}; + +TEST_F(ArcPowerBridgeTest, SuspendAndResume) { + ASSERT_EQ(0, power_instance_->num_suspend()); + ASSERT_EQ(0, power_instance_->num_resume()); + + // When powerd notifies Chrome that the system is about to suspend, + // ArcPowerBridge should notify Android and take a suspend readiness callback + // to defer the suspend operation. + power_manager_client_->SendSuspendImminent( + power_manager::SuspendImminent_Reason_OTHER); + EXPECT_EQ(1, power_instance_->num_suspend()); + EXPECT_EQ(0, power_instance_->num_resume()); + EXPECT_EQ(1, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); + + // Simulate Android acknowledging that it's ready for the system to suspend. + power_instance_->GetSuspendCallback().Run(); + EXPECT_EQ(0, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); + + power_manager_client_->SendSuspendDone(); + EXPECT_EQ(1, power_instance_->num_suspend()); + EXPECT_EQ(1, power_instance_->num_resume()); + + // We shouldn't crash if the instance isn't ready. + DestroyPowerInstance(); + power_manager_client_->SendSuspendImminent( + power_manager::SuspendImminent_Reason_OTHER); + EXPECT_EQ(0, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); + power_manager_client_->SendSuspendDone(); +} + +TEST_F(ArcPowerBridgeTest, SetInteractive) { + power_bridge_->OnPowerStateChanged(chromeos::DISPLAY_POWER_ALL_OFF); + EXPECT_FALSE(power_instance_->interactive()); + + power_bridge_->OnPowerStateChanged(chromeos::DISPLAY_POWER_ALL_ON); + EXPECT_TRUE(power_instance_->interactive()); + + // We shouldn't crash if the instance isn't ready. + DestroyPowerInstance(); + power_bridge_->OnPowerStateChanged(chromeos::DISPLAY_POWER_ALL_OFF); +} + +TEST_F(ArcPowerBridgeTest, ScreenBrightness) { + // Let the initial GetScreenBrightnessPercent() task run. + base::RunLoop().RunUntilIdle(); + EXPECT_DOUBLE_EQ(kInitialBrightness, power_instance_->screen_brightness()); + + // Check that Chrome OS brightness changes are passed to Android. + const double kUpdatedBrightness = 45.0; + power_manager_client_->set_screen_brightness_percent(kUpdatedBrightness); + power_manager_client_->SendBrightnessChanged(kUpdatedBrightness, true); + EXPECT_DOUBLE_EQ(kUpdatedBrightness, power_instance_->screen_brightness()); + + // Requests from Android should update the Chrome OS brightness. + const double kAndroidBrightness = 70.0; + power_bridge_->OnScreenBrightnessUpdateRequest(kAndroidBrightness); + EXPECT_DOUBLE_EQ(kAndroidBrightness, + power_manager_client_->screen_brightness_percent()); + + // To prevent battles between Chrome OS and Android, the updated brightness + // shouldn't be passed to Android immediately, but it should be passed after + // the timer fires. + power_manager_client_->SendBrightnessChanged(kAndroidBrightness, true); + EXPECT_DOUBLE_EQ(kUpdatedBrightness, power_instance_->screen_brightness()); + ASSERT_TRUE(power_bridge_->TriggerNotifyBrightnessTimerForTesting()); + EXPECT_DOUBLE_EQ(kAndroidBrightness, power_instance_->screen_brightness()); +} + +TEST_F(ArcPowerBridgeTest, DifferentWakeLocks) { + AcquireDisplayWakeLock(mojom::DisplayWakeLockType::BRIGHT); + EXPECT_EQ(1, wake_lock_provider_->GetActiveWakeLocksOfType( + WakeLockType::kPreventDisplaySleep)); + EXPECT_EQ(0, wake_lock_provider_->GetActiveWakeLocksOfType( + WakeLockType::kPreventDisplaySleepAllowDimming)); + + AcquireDisplayWakeLock(mojom::DisplayWakeLockType::DIM); + EXPECT_EQ(1, wake_lock_provider_->GetActiveWakeLocksOfType( + WakeLockType::kPreventDisplaySleep)); + EXPECT_EQ(1, wake_lock_provider_->GetActiveWakeLocksOfType( + WakeLockType::kPreventDisplaySleepAllowDimming)); + + ReleaseDisplayWakeLock(mojom::DisplayWakeLockType::BRIGHT); + EXPECT_EQ(0, wake_lock_provider_->GetActiveWakeLocksOfType( + WakeLockType::kPreventDisplaySleep)); + EXPECT_EQ(1, wake_lock_provider_->GetActiveWakeLocksOfType( + WakeLockType::kPreventDisplaySleepAllowDimming)); + + ReleaseDisplayWakeLock(mojom::DisplayWakeLockType::DIM); + EXPECT_EQ(0, wake_lock_provider_->GetActiveWakeLocksOfType( + WakeLockType::kPreventDisplaySleep)); + EXPECT_EQ(0, wake_lock_provider_->GetActiveWakeLocksOfType( + WakeLockType::kPreventDisplaySleepAllowDimming)); +} + +TEST_F(ArcPowerBridgeTest, ConsolidateWakeLocks) { + AcquireDisplayWakeLock(mojom::DisplayWakeLockType::BRIGHT); + EXPECT_EQ(1, wake_lock_provider_->GetActiveWakeLocksOfType( + WakeLockType::kPreventDisplaySleep)); + + // Acquiring a second Android wake lock of the same time shouldn't result in a + // second device service wake lock being requested. + AcquireDisplayWakeLock(mojom::DisplayWakeLockType::BRIGHT); + EXPECT_EQ(1, wake_lock_provider_->GetActiveWakeLocksOfType( + WakeLockType::kPreventDisplaySleep)); + + ReleaseDisplayWakeLock(mojom::DisplayWakeLockType::BRIGHT); + EXPECT_EQ(1, wake_lock_provider_->GetActiveWakeLocksOfType( + WakeLockType::kPreventDisplaySleep)); + + // The device service wake lock should only be released when all Android wake + // locks have been released. + ReleaseDisplayWakeLock(mojom::DisplayWakeLockType::BRIGHT); + EXPECT_EQ(0, wake_lock_provider_->GetActiveWakeLocksOfType( + WakeLockType::kPreventDisplaySleep)); +} + +TEST_F(ArcPowerBridgeTest, ReleaseWakeLocksWhenInstanceClosed) { + AcquireDisplayWakeLock(mojom::DisplayWakeLockType::BRIGHT); + ASSERT_EQ(1, wake_lock_provider_->GetActiveWakeLocksOfType( + WakeLockType::kPreventDisplaySleep)); + + // If the instance is closed, all wake locks should be released. + base::RunLoop run_loop; + wake_lock_provider_->set_wake_lock_canceled_callback(run_loop.QuitClosure()); + DestroyPowerInstance(); + run_loop.Run(); + EXPECT_EQ(0, wake_lock_provider_->GetActiveWakeLocksOfType( + WakeLockType::kPreventDisplaySleep)); + + // Check that wake locks can be requested after the instance becomes ready + // again. + CreatePowerInstance(); + AcquireDisplayWakeLock(mojom::DisplayWakeLockType::BRIGHT); + EXPECT_EQ(1, wake_lock_provider_->GetActiveWakeLocksOfType( + WakeLockType::kPreventDisplaySleep)); +} + +} // namespace arc diff --git a/chromium/components/arc/rotation_lock/arc_rotation_lock_bridge.cc b/chromium/components/arc/rotation_lock/arc_rotation_lock_bridge.cc index c75a7d68bc5..b0816302313 100644 --- a/chromium/components/arc/rotation_lock/arc_rotation_lock_bridge.cc +++ b/chromium/components/arc/rotation_lock/arc_rotation_lock_bridge.cc @@ -48,20 +48,24 @@ ArcRotationLockBridge::ArcRotationLockBridge(content::BrowserContext* context, ArcBridgeService* bridge_service) : arc_bridge_service_(bridge_service) { arc_bridge_service_->rotation_lock()->AddObserver(this); - ash::Shell::Get()->screen_orientation_controller()->AddObserver(this); - ash::Shell::Get()->tablet_mode_controller()->AddObserver(this); + // TODO(mash): Support this functionality without ash::Shell access in Chrome. + if (ash::Shell::HasInstance()) { + ash::Shell::Get()->screen_orientation_controller()->AddObserver(this); + ash::Shell::Get()->tablet_mode_controller()->AddObserver(this); + } } ArcRotationLockBridge::~ArcRotationLockBridge() { arc_bridge_service_->rotation_lock()->RemoveObserver(this); - // TODO(mash): mash needs proper shutdown process. + // TODO(mus): mus needs proper shutdown process. + // TODO(mash): Support this functionality without ash::Shell access in Chrome. if (ash::Shell::HasInstance()) { ash::Shell::Get()->screen_orientation_controller()->RemoveObserver(this); ash::Shell::Get()->tablet_mode_controller()->RemoveObserver(this); } } -void ArcRotationLockBridge::OnInstanceReady() { +void ArcRotationLockBridge::OnConnectionReady() { SendRotationLockState(); } @@ -78,6 +82,10 @@ void ArcRotationLockBridge::OnTabletModeEnded() { } void ArcRotationLockBridge::SendRotationLockState() { + // TODO(mash): Support this functionality without ash::Shell access in Chrome. + if (!ash::Shell::HasInstance()) + return; + mojom::RotationLockInstance* rotation_lock_instance = ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->rotation_lock(), OnRotationLockStateChanged); diff --git a/chromium/components/arc/rotation_lock/arc_rotation_lock_bridge.h b/chromium/components/arc/rotation_lock/arc_rotation_lock_bridge.h index e501612748b..a0257402927 100644 --- a/chromium/components/arc/rotation_lock/arc_rotation_lock_bridge.h +++ b/chromium/components/arc/rotation_lock/arc_rotation_lock_bridge.h @@ -10,7 +10,7 @@ #include "base/macros.h" #include "base/threading/thread_checker.h" #include "components/arc/common/rotation_lock.mojom.h" -#include "components/arc/instance_holder.h" +#include "components/arc/connection_observer.h" #include "components/keyed_service/core/keyed_service.h" namespace content { @@ -25,7 +25,7 @@ class ArcBridgeService; // container. class ArcRotationLockBridge : public KeyedService, - public InstanceHolder::Observer, + public ConnectionObserver, public ash::TabletModeObserver, public ash::ScreenOrientationController::Observer { public: @@ -38,8 +38,8 @@ class ArcRotationLockBridge ArcBridgeService* bridge_service); ~ArcRotationLockBridge() override; - // InstanceHolder::Observer: - void OnInstanceReady() override; + // ConnectionObserver: + void OnConnectionReady() override; // ash::ScreenOrientationController::Observer: void OnUserRotationLockChanged() override; diff --git a/chromium/components/arc/storage_manager/arc_storage_manager.cc b/chromium/components/arc/storage_manager/arc_storage_manager.cc index b35cd7a422b..a6fb61aecb9 100644 --- a/chromium/components/arc/storage_manager/arc_storage_manager.cc +++ b/chromium/components/arc/storage_manager/arc_storage_manager.cc @@ -4,6 +4,7 @@ #include "components/arc/storage_manager/arc_storage_manager.h" +#include #include #include "base/bind.h" @@ -58,12 +59,12 @@ bool ArcStorageManager::OpenPrivateVolumeSettings() { } bool ArcStorageManager::GetApplicationsSize( - const GetApplicationsSizeCallback& callback) { + GetApplicationsSizeCallback callback) { auto* storage_manager_instance = ARC_GET_INSTANCE_FOR_METHOD( arc_bridge_service_->storage_manager(), GetApplicationsSize); if (!storage_manager_instance) return false; - storage_manager_instance->GetApplicationsSize(callback); + storage_manager_instance->GetApplicationsSize(std::move(callback)); return true; } diff --git a/chromium/components/arc/storage_manager/arc_storage_manager.h b/chromium/components/arc/storage_manager/arc_storage_manager.h index 8ed50426690..ccad8538b92 100644 --- a/chromium/components/arc/storage_manager/arc_storage_manager.h +++ b/chromium/components/arc/storage_manager/arc_storage_manager.h @@ -38,8 +38,8 @@ class ArcStorageManager : public KeyedService { // Gets storage usage of all application's APK, data, and cache size. using GetApplicationsSizeCallback = - base::Callback; - bool GetApplicationsSize(const GetApplicationsSizeCallback& callback); + base::OnceCallback; + bool GetApplicationsSize(GetApplicationsSizeCallback callback); // Deletes all applications' cache files. bool DeleteApplicationsCache(const base::Callback& callback); diff --git a/chromium/components/arc/video_accelerator/BUILD.gn b/chromium/components/arc/video_accelerator/BUILD.gn new file mode 100644 index 00000000000..49683a08b24 --- /dev/null +++ b/chromium/components/arc/video_accelerator/BUILD.gn @@ -0,0 +1,25 @@ +# Copyright 2017 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. + +static_library("video_accelerator") { + sources = [ + "arc_video_decode_accelerator.h", + "chrome_arc_video_decode_accelerator.cc", + "chrome_arc_video_decode_accelerator.h", + "gpu_arc_video_decode_accelerator.cc", + "gpu_arc_video_decode_accelerator.h", + "gpu_arc_video_encode_accelerator.cc", + "gpu_arc_video_encode_accelerator.h", + "protected_buffer_manager.cc", + "protected_buffer_manager.h", + "protected_buffer_manager_proxy.cc", + "protected_buffer_manager_proxy.h", + ] + + deps = [ + "//components/arc/common:media", + "//media/gpu", + "//ui/ozone", + ] +} diff --git a/chromium/components/arc/video_accelerator/DEPS b/chromium/components/arc/video_accelerator/DEPS index 04dd5ab2b11..be1c9c99ce2 100644 --- a/chromium/components/arc/video_accelerator/DEPS +++ b/chromium/components/arc/video_accelerator/DEPS @@ -1,3 +1,12 @@ include_rules = [ - "+media/video/video_encode_accelerator.h", + "+components/arc/common", + "+gpu/command_buffer/service/gpu_preferences.h", + "+media/video", + "+media/base/video_frame.h", + "+media/base/video_types.h", + "+media/gpu", + "+mojo/edk/embedder", + "+services/service_manager/public/cpp", + "+ui/gfx", + "+ui/ozone/public", ] diff --git a/chromium/components/arc/video_accelerator/OWNERS b/chromium/components/arc/video_accelerator/OWNERS index ef5cf841917..4e730ffd89f 100644 --- a/chromium/components/arc/video_accelerator/OWNERS +++ b/chromium/components/arc/video_accelerator/OWNERS @@ -1,3 +1,4 @@ -per-file *_struct_traits*.*=set noparent -per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS -per-file *_struct_traits*.*=file://components/arc/common/ARC_SECURITY_OWNERS +kcwu@chromium.org +piman@chromium.org +posciak@chromium.org +wuchengli@chromium.org diff --git a/chromium/components/arc/video_accelerator/arc_video_decode_accelerator.h b/chromium/components/arc/video_accelerator/arc_video_decode_accelerator.h new file mode 100644 index 00000000000..a6d563447ef --- /dev/null +++ b/chromium/components/arc/video_accelerator/arc_video_decode_accelerator.h @@ -0,0 +1,182 @@ +// Copyright 2016 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 COMPONENTS_ARC_VIDEO_ACCELERATOR_ARC_VIDEO_DECODE_ACCELERATOR_H_ +#define COMPONENTS_ARC_VIDEO_ACCELERATOR_ARC_VIDEO_DECODE_ACCELERATOR_H_ + +#include + +#include "base/files/scoped_file.h" +#include "components/arc/video_accelerator/video_frame_plane.h" + +namespace arc { + +enum HalPixelFormatExtension { + // The pixel formats defined in Android but are used here. They are defined + // in "system/core/include/system/graphics.h" + HAL_PIXEL_FORMAT_BGRA_8888 = 5, + HAL_PIXEL_FORMAT_YCbCr_420_888 = 0x23, + + // The following formats are not defined in Android, but used in + // ArcVideoDecodeAccelerator to identify the input format. + HAL_PIXEL_FORMAT_H264 = 0x34363248, + HAL_PIXEL_FORMAT_VP8 = 0x00385056, + HAL_PIXEL_FORMAT_VP9 = 0x00395056, +}; + +enum PortType { + PORT_INPUT = 0, + PORT_OUTPUT = 1, + PORT_COUNT = 2, +}; + +struct BufferMetadata { + int64_t timestamp = 0; // in microseconds + uint32_t bytes_used = 0; +}; + +struct VideoFormat { + uint32_t pixel_format = 0; + uint32_t buffer_size = 0; + + // Minimum number of buffers required to decode/encode the stream. + uint32_t min_num_buffers = 0; + uint32_t coded_width = 0; + uint32_t coded_height = 0; + uint32_t crop_left = 0; + uint32_t crop_width = 0; + uint32_t crop_top = 0; + uint32_t crop_height = 0; +}; + +// The IPC interface between Android and Chromium for video decoding. Input +// buffers are sent from Android side and get processed in Chromium and the +// output buffers are returned back to Android side. +class ArcVideoDecodeAccelerator { + public: + enum Result { + // Note: this enum is used for UMA reporting. The existing values should not + // be rearranged, reused or removed and any additions should include updates + // to UMA reporting and histograms.xml. + SUCCESS = 0, + ILLEGAL_STATE = 1, + INVALID_ARGUMENT = 2, + UNREADABLE_INPUT = 3, + PLATFORM_FAILURE = 4, + INSUFFICIENT_RESOURCES = 5, + RESULT_MAX = 6, + }; + + struct Config { + size_t num_input_buffers = 0; + uint32_t input_pixel_format = 0; + // If true, only buffers created via AllocateProtectedBuffer() may be used. + bool secure_mode = false; + // TODO(owenlin): Add output_pixel_format. For now only the native pixel + // format of each VDA on Chromium is supported. + }; + + // The callbacks of the ArcVideoDecodeAccelerator. The user of this class + // should implement this interface. + class Client { + public: + virtual ~Client() {} + + // Called when an asynchronous error happens. The errors in Initialize() + // will not be reported here, but will be indicated by a return value + // there. + virtual void OnError(Result error) = 0; + + // Called when a buffer with the specified |index| and |port| has been + // processed and is no longer used in the accelerator. For input buffers, + // the Client may fill them with new content. For output buffers, indicates + // they are ready to be consumed by the client. + virtual void OnBufferDone(PortType port, + uint32_t index, + const BufferMetadata& metadata) = 0; + + // Called when the output format has changed or the output format + // becomes available at beginning of the stream after initial parsing. + virtual void OnOutputFormatChanged(const VideoFormat& format) = 0; + + // Called as a completion notification for Reset(). + virtual void OnResetDone() = 0; + + // Called as a completion notification for Flush(). + virtual void OnFlushDone() = 0; + }; + + // Initializes the ArcVideoDecodeAccelerator with specific configuration. This + // must be called before any other methods. This call is synchronous and + // returns SUCCESS iff initialization is successful. + virtual Result Initialize(const Config& config, Client* client) = 0; + + // Allocates a new protected buffer on accelerator side for the given |port| + // and |index|, the contents of which will be inaccessible to the client. + // The protected buffer will remain valid for at least as long as the resource + // backing the passed |handle_fd| is not released (i.e. there is at least one + // reference on the file backing |handle_fd|. + // + // Usable only if the accelerator has been initialized to run in secure mode. + // Allocation for input will create a protected buffer of at least |size|; + // for output, |size| is ignored, and the currently configured output format + // is used instead to determine the required buffer size and format. + virtual bool AllocateProtectedBuffer(PortType port, + uint32_t index, + base::ScopedFD handle_fd, + size_t size) = 0; + + // Assigns a shared memory to be used for the accelerator at the specified + // port and index. A buffer must be successfully bound before it can be passed + // to the accelerator via UseBuffer(). Already bound buffers may be reused + // multiple times without additional bindings. + // Not allowed in secure_mode, where protected buffers have to be allocated + // instead. + virtual void BindSharedMemory(PortType port, + uint32_t index, + base::ScopedFD ashmem_fd, + off_t offset, + size_t length) = 0; + + // Assigns a buffer to be used for the accelerator at the specified + // port and index. A buffer must be successfully bound before it can be + // passed to the accelerator via UseBuffer(). Already bound buffers may be + // reused multiple times without additional bindings. + // Not allowed in secure_mode, where protected buffers have to be allocated + // instead. + virtual void BindDmabuf( + PortType port, + uint32_t index, + base::ScopedFD dmabuf_fd, + const std::vector<::arc::VideoFramePlane>& planes) = 0; + + // Passes a buffer to the accelerator. For input buffer, the accelerator + // will process it. For output buffer, the accelerator will output content + // to it. + // In secure mode, |port| and |index| must correspond to a protected buffer + // allocated using AllocateProtectedBuffer(). + virtual void UseBuffer(PortType port, + uint32_t index, + const BufferMetadata& metadata) = 0; + + // Sets the number of output buffers. When it fails, Client::OnError() will + // be called. + virtual void SetNumberOfOutputBuffers(size_t number) = 0; + + // Resets the accelerator. When it is done, Client::OnResetDone() will + // be called. Afterwards, all buffers won't be accessed by the accelerator + // and there won't be more callbacks. + virtual void Reset() = 0; + + // Flushes the accelerator. After all the output buffers pending decode have + // been returned to client by OnBufferDone(), Client::OnFlushDone() will be + // called. + virtual void Flush() = 0; + + virtual ~ArcVideoDecodeAccelerator() {} +}; + +} // namespace arc + +#endif // COMPONENTS_ARC_VIDEO_ACCELERATOR_ARC_VIDEO_DECODE_ACCELERATOR_H_ diff --git a/chromium/components/arc/video_accelerator/chrome_arc_video_decode_accelerator.cc b/chromium/components/arc/video_accelerator/chrome_arc_video_decode_accelerator.cc new file mode 100644 index 00000000000..38bc730733f --- /dev/null +++ b/chromium/components/arc/video_accelerator/chrome_arc_video_decode_accelerator.cc @@ -0,0 +1,633 @@ +// Copyright 2016 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 "components/arc/video_accelerator/chrome_arc_video_decode_accelerator.h" + +#include "base/callback_helpers.h" +#include "base/logging.h" +#include "base/metrics/histogram_macros.h" +#include "base/numerics/safe_math.h" +#include "base/run_loop.h" +#include "base/unguessable_token.h" +#include "components/arc/video_accelerator/protected_buffer_manager.h" +#include "media/base/video_frame.h" +#include "media/gpu/format_utils.h" +#include "media/gpu/gpu_video_decode_accelerator_factory.h" + +namespace arc { + +namespace { + +// An arbitrary chosen limit of the number of buffers. The number of +// buffers used is requested from the untrusted client side. +const size_t kMaxBufferCount = 128; + +// Maximum number of concurrent ARC video clients. +// Currently we have no way to know the resources are not enough to create more +// VDA. Arbitrarily chosen a reasonable constant as the limit. +const int kMaxConcurrentClients = 8; + +} // namespace + +int ChromeArcVideoDecodeAccelerator::client_count_ = 0; + +ChromeArcVideoDecodeAccelerator::InputRecord::InputRecord( + int32_t bitstream_buffer_id, + uint32_t buffer_index, + int64_t timestamp) + : bitstream_buffer_id(bitstream_buffer_id), + buffer_index(buffer_index), + timestamp(timestamp) {} + +ChromeArcVideoDecodeAccelerator::InputBufferInfo::InputBufferInfo() = default; + +ChromeArcVideoDecodeAccelerator::InputBufferInfo::~InputBufferInfo() { + if (shm_handle.OwnershipPassesToIPC()) + shm_handle.Close(); +} + +ChromeArcVideoDecodeAccelerator::OutputBufferInfo::OutputBufferInfo() = default; + +ChromeArcVideoDecodeAccelerator::OutputBufferInfo::~OutputBufferInfo() { + if (!gpu_memory_buffer_handle.is_null()) { + for (const auto& fd : gpu_memory_buffer_handle.native_pixmap_handle.fds) { + // Close the fd by wrapping it in a ScopedFD and letting + // it fall out of scope. + base::ScopedFD scoped_fd(fd.fd); + } + } +} + +ChromeArcVideoDecodeAccelerator::ChromeArcVideoDecodeAccelerator( + const gpu::GpuPreferences& gpu_preferences, + ProtectedBufferManager* protected_buffer_manager) + : arc_client_(nullptr), + next_bitstream_buffer_id_(0), + output_pixel_format_(media::PIXEL_FORMAT_UNKNOWN), + output_buffer_size_(0), + requested_num_of_output_buffers_(0), + gpu_preferences_(gpu_preferences), + protected_buffer_manager_(protected_buffer_manager) {} + +ChromeArcVideoDecodeAccelerator::~ChromeArcVideoDecodeAccelerator() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (vda_) { + client_count_--; + } +} + +ArcVideoDecodeAccelerator::Result ChromeArcVideoDecodeAccelerator::Initialize( + const Config& config, + ArcVideoDecodeAccelerator::Client* client) { + auto result = InitializeTask(config, client); + // Report initialization status to UMA. + UMA_HISTOGRAM_ENUMERATION( + "Media.ChromeArcVideoDecodeAccelerator.InitializeResult", result, + RESULT_MAX); + return result; +} + +ArcVideoDecodeAccelerator::Result +ChromeArcVideoDecodeAccelerator::InitializeTask( + const Config& config, + ArcVideoDecodeAccelerator::Client* client) { + DVLOG(5) << "Initialize(input_pixel_format=" << config.input_pixel_format + << ", num_input_buffers=" << config.num_input_buffers << ")"; + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(client); + + if (arc_client_) { + DLOG(ERROR) << "Re-Initialize() is not allowed"; + return ILLEGAL_STATE; + } + + arc_client_ = client; + + if (client_count_ >= kMaxConcurrentClients) { + LOG(WARNING) << "Reject to Initialize() due to too many clients: " + << client_count_; + return INSUFFICIENT_RESOURCES; + } + + if (config.secure_mode && !protected_buffer_manager_) { + DLOG(ERROR) << "Secure mode unsupported"; + return PLATFORM_FAILURE; + } + + secure_mode_ = config.secure_mode; + + if (config.num_input_buffers > kMaxBufferCount) { + DLOG(ERROR) << "Request too many buffers: " << config.num_input_buffers; + return INVALID_ARGUMENT; + } + input_buffer_info_.resize(config.num_input_buffers); + + media::VideoDecodeAccelerator::Config vda_config; + switch (config.input_pixel_format) { + case HAL_PIXEL_FORMAT_H264: + vda_config.profile = media::H264PROFILE_MAIN; + break; + case HAL_PIXEL_FORMAT_VP8: + vda_config.profile = media::VP8PROFILE_ANY; + break; + case HAL_PIXEL_FORMAT_VP9: + vda_config.profile = media::VP9PROFILE_PROFILE0; + break; + default: + DLOG(ERROR) << "Unsupported input format: " << config.input_pixel_format; + return INVALID_ARGUMENT; + } + vda_config.output_mode = + media::VideoDecodeAccelerator::Config::OutputMode::IMPORT; + + auto vda_factory = media::GpuVideoDecodeAcceleratorFactory::CreateWithNoGL(); + vda_ = vda_factory->CreateVDA( + this, vda_config, gpu::GpuDriverBugWorkarounds(), gpu_preferences_); + if (!vda_) { + DLOG(ERROR) << "Failed to create VDA."; + return PLATFORM_FAILURE; + } + + client_count_++; + DVLOG(5) << "Number of concurrent ArcVideoDecodeAccelerator clients: " + << client_count_; + + return SUCCESS; +} + +void ChromeArcVideoDecodeAccelerator::SetNumberOfOutputBuffers(size_t number) { + DVLOG(5) << "SetNumberOfOutputBuffers(" << number << ")"; + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (!vda_) { + DLOG(ERROR) << "VDA not initialized"; + return; + } + + if (number > kMaxBufferCount) { + DLOG(ERROR) << "Too many buffers: " << number; + arc_client_->OnError(INVALID_ARGUMENT); + return; + } + + std::vector buffers; + for (size_t id = 0; id < number; ++id) { + // TODO(owenlin): Make sure the |coded_size| is what we want. + buffers.push_back( + media::PictureBuffer(base::checked_cast(id), coded_size_)); + } + vda_->AssignPictureBuffers(buffers); + + buffers_pending_import_.clear(); + buffers_pending_import_.resize(number); +} + +bool ChromeArcVideoDecodeAccelerator::AllocateProtectedBuffer( + PortType port, + uint32_t index, + base::ScopedFD handle_fd, + size_t size) { + DVLOG(5) << "port=" << port << " index=" << index + << " handle=" << handle_fd.get() << " size=" << size; + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + if (!secure_mode_) { + DLOG(ERROR) << "Not in secure mode"; + arc_client_->OnError(INVALID_ARGUMENT); + return false; + } + + if (!ValidatePortAndIndex(port, index)) { + arc_client_->OnError(INVALID_ARGUMENT); + return false; + } + + if (port == PORT_INPUT) { + auto protected_shmem = + protected_buffer_manager_->AllocateProtectedSharedMemory( + std::move(handle_fd), size); + if (!protected_shmem) { + DLOG(ERROR) << "Failed allocating protected shared memory"; + return false; + } + + auto input_info = std::make_unique(); + input_info->shm_handle = protected_shmem->shm_handle(); + input_info->protected_buffer_handle = std::move(protected_shmem); + input_buffer_info_[index] = std::move(input_info); + } else if (port == PORT_OUTPUT) { + auto protected_pixmap = + protected_buffer_manager_->AllocateProtectedNativePixmap( + std::move(handle_fd), + media::VideoPixelFormatToGfxBufferFormat(output_pixel_format_), + coded_size_); + if (!protected_pixmap) { + DLOG(ERROR) << "Failed allocating a protected pixmap"; + return false; + } + auto output_info = std::make_unique(); + output_info->gpu_memory_buffer_handle.type = gfx::NATIVE_PIXMAP; + output_info->gpu_memory_buffer_handle.native_pixmap_handle = + gfx::CloneHandleForIPC(protected_pixmap->native_pixmap_handle()); + output_info->protected_buffer_handle = std::move(protected_pixmap); + buffers_pending_import_[index] = std::move(output_info); + } + + return true; +} + +void ChromeArcVideoDecodeAccelerator::BindSharedMemory(PortType port, + uint32_t index, + base::ScopedFD ashmem_fd, + off_t offset, + size_t length) { + DVLOG(5) << "ArcGVDA::BindSharedMemory, offset: " << offset + << ", length: " << length; + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + if (secure_mode_) { + DLOG(ERROR) << "not allowed in secure mode"; + arc_client_->OnError(INVALID_ARGUMENT); + return; + } + + if (!vda_) { + DLOG(ERROR) << "VDA not initialized"; + return; + } + + if (port != PORT_INPUT) { + DLOG(ERROR) << "SharedBuffer is only supported for input"; + arc_client_->OnError(INVALID_ARGUMENT); + return; + } + if (!ValidatePortAndIndex(port, index)) { + arc_client_->OnError(INVALID_ARGUMENT); + return; + } + + auto input_info = std::make_unique(); + input_info->shm_handle = + base::SharedMemoryHandle(base::FileDescriptor(ashmem_fd.release(), true), + length, base::UnguessableToken::Create()); + DCHECK(input_info->shm_handle.OwnershipPassesToIPC()); + input_info->offset = offset; + input_buffer_info_[index] = std::move(input_info); +} + +bool ChromeArcVideoDecodeAccelerator::VerifyDmabuf( + const base::ScopedFD& dmabuf_fd, + const std::vector<::arc::VideoFramePlane>& planes) const { + size_t num_planes = media::VideoFrame::NumPlanes(output_pixel_format_); + if (planes.size() != num_planes) { + DLOG(ERROR) << "Invalid number of dmabuf planes passed: " << planes.size() + << ", expected: " << num_planes; + return false; + } + + off_t size = lseek(dmabuf_fd.get(), 0, SEEK_END); + lseek(dmabuf_fd.get(), 0, SEEK_SET); + if (size < 0) { + DPLOG(ERROR) << "fail to find the size of dmabuf"; + return false; + } + + size_t i = 0; + for (const auto& plane : planes) { + DVLOG(4) << "Plane " << i << ", offset: " << plane.offset + << ", stride: " << plane.stride; + + size_t rows = + media::VideoFrame::Rows(i, output_pixel_format_, coded_size_.height()); + base::CheckedNumeric current_size(plane.offset); + current_size += base::CheckMul(plane.stride, rows); + + if (!current_size.IsValid() || current_size.ValueOrDie() > size) { + DLOG(ERROR) << "Invalid strides/offsets"; + return false; + } + + ++i; + } + + return true; +} + +void ChromeArcVideoDecodeAccelerator::BindDmabuf( + PortType port, + uint32_t index, + base::ScopedFD dmabuf_fd, + const std::vector<::arc::VideoFramePlane>& planes) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + if (secure_mode_) { + DLOG(ERROR) << "not allowed in secure mode"; + arc_client_->OnError(INVALID_ARGUMENT); + return; + } + + if (!vda_) { + DLOG(ERROR) << "VDA not initialized"; + return; + } + + if (port != PORT_OUTPUT) { + DLOG(ERROR) << "Dmabuf is only supported for input"; + arc_client_->OnError(INVALID_ARGUMENT); + return; + } + if (!ValidatePortAndIndex(port, index)) { + arc_client_->OnError(INVALID_ARGUMENT); + return; + } + if (!VerifyDmabuf(dmabuf_fd, planes)) { + arc_client_->OnError(INVALID_ARGUMENT); + return; + } + +#if defined(USE_OZONE) + auto output_info = std::make_unique(); + output_info->gpu_memory_buffer_handle.type = gfx::NATIVE_PIXMAP; + output_info->gpu_memory_buffer_handle.native_pixmap_handle.fds.emplace_back( + base::FileDescriptor(dmabuf_fd.release(), true)); + for (const auto& plane : planes) { + output_info->gpu_memory_buffer_handle.native_pixmap_handle.planes + .emplace_back(plane.stride, plane.offset, 0, 0); + } + buffers_pending_import_[index] = std::move(output_info); +#else + arc_client_->OnError(PLATFORM_FAILURE); +#endif +} + +void ChromeArcVideoDecodeAccelerator::UseBuffer( + PortType port, + uint32_t index, + const BufferMetadata& metadata) { + DVLOG(5) << "UseBuffer(port=" << port << ", index=" << index + << ", metadata=(bytes_used=" << metadata.bytes_used + << ", timestamp=" << metadata.timestamp << ")"; + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (!vda_) { + DLOG(ERROR) << "VDA not initialized"; + return; + } + if (!ValidatePortAndIndex(port, index)) { + arc_client_->OnError(INVALID_ARGUMENT); + return; + } + switch (port) { + case PORT_INPUT: { + auto& input_info = input_buffer_info_[index]; + if (!input_info) { + DLOG(ERROR) << "Buffer not initialized"; + arc_client_->OnError(INVALID_ARGUMENT); + return; + } + + int32_t bitstream_buffer_id = next_bitstream_buffer_id_; + // Mask against 30 bits, to avoid (undefined) wraparound on signed + // integer. + next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF; + + auto duplicated_handle = input_info->shm_handle.Duplicate(); + if (!duplicated_handle.IsValid()) { + arc_client_->OnError(PLATFORM_FAILURE); + return; + } + + CreateInputRecord(bitstream_buffer_id, index, metadata.timestamp); + vda_->Decode( + media::BitstreamBuffer(bitstream_buffer_id, duplicated_handle, + metadata.bytes_used, input_info->offset)); + break; + } + case PORT_OUTPUT: { + auto& output_info = buffers_pending_import_[index]; + if (!output_info) { + DLOG(ERROR) << "Buffer not initialized"; + arc_client_->OnError(INVALID_ARGUMENT); + return; + } + // is_null() is false the first time the buffer is passed to the VDA. + // In that case, VDA needs to import the buffer first. + if (!output_info->gpu_memory_buffer_handle.is_null()) { + vda_->ImportBufferForPicture(index, + output_info->gpu_memory_buffer_handle); + // VDA takes ownership, so just clear out, don't close the handle. + output_info->gpu_memory_buffer_handle = gfx::GpuMemoryBufferHandle(); + } else { + vda_->ReusePictureBuffer(index); + } + break; + } + default: + NOTREACHED(); + } +} + +void ChromeArcVideoDecodeAccelerator::Reset() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (!vda_) { + DLOG(ERROR) << "VDA not initialized"; + return; + } + vda_->Reset(); +} + +void ChromeArcVideoDecodeAccelerator::Flush() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (!vda_) { + DLOG(ERROR) << "VDA not initialized"; + return; + } + vda_->Flush(); +} + +void ChromeArcVideoDecodeAccelerator::ProvidePictureBuffers( + uint32_t requested_num_of_buffers, + media::VideoPixelFormat output_pixel_format, + uint32_t textures_per_buffer, + const gfx::Size& dimensions, + uint32_t texture_target) { + DVLOG(5) << "ProvidePictureBuffers(" + << "requested_num_of_buffers=" << requested_num_of_buffers + << ", dimensions=" << dimensions.ToString() << ")"; + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + coded_size_ = dimensions; + + // By default, use an empty rect to indicate the visible rectangle is not + // available. + visible_rect_ = gfx::Rect(); + if ((output_pixel_format_ != media::PIXEL_FORMAT_UNKNOWN) && + (output_pixel_format_ != output_pixel_format)) { + arc_client_->OnError(PLATFORM_FAILURE); + return; + } + output_pixel_format_ = output_pixel_format; + requested_num_of_output_buffers_ = requested_num_of_buffers; + output_buffer_size_ = + media::VideoFrame::AllocationSize(output_pixel_format_, coded_size_); + + NotifyOutputFormatChanged(); +} + +void ChromeArcVideoDecodeAccelerator::NotifyOutputFormatChanged() { + VideoFormat video_format; + switch (output_pixel_format_) { + case media::PIXEL_FORMAT_I420: + case media::PIXEL_FORMAT_YV12: + case media::PIXEL_FORMAT_NV12: + case media::PIXEL_FORMAT_NV21: + // HAL_PIXEL_FORMAT_YCbCr_420_888 is the flexible pixel format in Android + // which handles all 420 formats, with both orderings of chroma (CbCr and + // CrCb) as well as planar and semi-planar layouts. + video_format.pixel_format = HAL_PIXEL_FORMAT_YCbCr_420_888; + break; + case media::PIXEL_FORMAT_ARGB: + video_format.pixel_format = HAL_PIXEL_FORMAT_BGRA_8888; + break; + default: + DLOG(ERROR) << "Format not supported: " << output_pixel_format_; + arc_client_->OnError(PLATFORM_FAILURE); + return; + } + video_format.buffer_size = output_buffer_size_; + video_format.min_num_buffers = requested_num_of_output_buffers_; + video_format.coded_width = coded_size_.width(); + video_format.coded_height = coded_size_.height(); + video_format.crop_top = visible_rect_.y(); + video_format.crop_left = visible_rect_.x(); + video_format.crop_width = visible_rect_.width(); + video_format.crop_height = visible_rect_.height(); + arc_client_->OnOutputFormatChanged(video_format); +} + +void ChromeArcVideoDecodeAccelerator::DismissPictureBuffer( + int32_t picture_buffer) { + // no-op +} + +void ChromeArcVideoDecodeAccelerator::PictureReady( + const media::Picture& picture) { + DVLOG(5) << "PictureReady(picture_buffer_id=" << picture.picture_buffer_id() + << ", bitstream_buffer_id=" << picture.bitstream_buffer_id(); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + // Handle visible size change. + if (visible_rect_ != picture.visible_rect()) { + DVLOG(5) << "visible size changed: " << picture.visible_rect().ToString(); + visible_rect_ = picture.visible_rect(); + NotifyOutputFormatChanged(); + } + + InputRecord* input_record = FindInputRecord(picture.bitstream_buffer_id()); + if (input_record == nullptr) { + DLOG(ERROR) << "Cannot find for bitstream buffer id: " + << picture.bitstream_buffer_id(); + arc_client_->OnError(PLATFORM_FAILURE); + return; + } + + BufferMetadata metadata; + metadata.timestamp = input_record->timestamp; + metadata.bytes_used = output_buffer_size_; + arc_client_->OnBufferDone(PORT_OUTPUT, picture.picture_buffer_id(), metadata); +} + +void ChromeArcVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer( + int32_t bitstream_buffer_id) { + DVLOG(5) << "NotifyEndOfBitstreamBuffer(" << bitstream_buffer_id << ")"; + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + InputRecord* input_record = FindInputRecord(bitstream_buffer_id); + if (input_record == nullptr) { + arc_client_->OnError(PLATFORM_FAILURE); + return; + } + arc_client_->OnBufferDone(PORT_INPUT, input_record->buffer_index, + BufferMetadata()); +} + +void ChromeArcVideoDecodeAccelerator::NotifyFlushDone() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + arc_client_->OnFlushDone(); +} + +void ChromeArcVideoDecodeAccelerator::NotifyResetDone() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + arc_client_->OnResetDone(); +} + +static ArcVideoDecodeAccelerator::Result ConvertErrorCode( + media::VideoDecodeAccelerator::Error error) { + switch (error) { + case media::VideoDecodeAccelerator::ILLEGAL_STATE: + return ArcVideoDecodeAccelerator::ILLEGAL_STATE; + case media::VideoDecodeAccelerator::INVALID_ARGUMENT: + return ArcVideoDecodeAccelerator::INVALID_ARGUMENT; + case media::VideoDecodeAccelerator::UNREADABLE_INPUT: + return ArcVideoDecodeAccelerator::UNREADABLE_INPUT; + case media::VideoDecodeAccelerator::PLATFORM_FAILURE: + return ArcVideoDecodeAccelerator::PLATFORM_FAILURE; + default: + DLOG(ERROR) << "Unknown error: " << error; + return ArcVideoDecodeAccelerator::PLATFORM_FAILURE; + } +} + +void ChromeArcVideoDecodeAccelerator::NotifyError( + media::VideoDecodeAccelerator::Error error) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DLOG(ERROR) << "Error notified: " << error; + arc_client_->OnError(ConvertErrorCode(error)); +} + +void ChromeArcVideoDecodeAccelerator::CreateInputRecord( + int32_t bitstream_buffer_id, + uint32_t buffer_index, + int64_t timestamp) { + input_records_.push_front( + InputRecord(bitstream_buffer_id, buffer_index, timestamp)); + + // The same value copied from media::GpuVideoDecoder. The input record is + // needed when the input buffer or the corresponding output buffer are + // returned from VDA. However there is no guarantee how much buffers will be + // kept in the VDA. We kept the last |kMaxNumberOfInputRecords| in + // |input_records_| and drop the others. + const size_t kMaxNumberOfInputRecords = 128; + if (input_records_.size() > kMaxNumberOfInputRecords) + input_records_.pop_back(); +} + +ChromeArcVideoDecodeAccelerator::InputRecord* +ChromeArcVideoDecodeAccelerator::FindInputRecord(int32_t bitstream_buffer_id) { + for (auto& record : input_records_) { + if (record.bitstream_buffer_id == bitstream_buffer_id) + return &record; + } + return nullptr; +} + +bool ChromeArcVideoDecodeAccelerator::ValidatePortAndIndex( + PortType port, + uint32_t index) const { + switch (port) { + case PORT_INPUT: + if (index >= input_buffer_info_.size()) { + DLOG(ERROR) << "Invalid index: " << index; + return false; + } + return true; + case PORT_OUTPUT: + if (index >= buffers_pending_import_.size()) { + DLOG(ERROR) << "Invalid index: " << index; + return false; + } + return true; + default: + DLOG(ERROR) << "Invalid port: " << port; + return false; + } +} + +} // namespace arc diff --git a/chromium/components/arc/video_accelerator/chrome_arc_video_decode_accelerator.h b/chromium/components/arc/video_accelerator/chrome_arc_video_decode_accelerator.h new file mode 100644 index 00000000000..2e19aca65a8 --- /dev/null +++ b/chromium/components/arc/video_accelerator/chrome_arc_video_decode_accelerator.h @@ -0,0 +1,194 @@ +// Copyright 2016 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 COMPONENTS_ARC_VIDEO_ACCELERATOR_CHROME_ARC_VIDEO_DECODE_ACCELERATOR_H_ +#define COMPONENTS_ARC_VIDEO_ACCELERATOR_CHROME_ARC_VIDEO_DECODE_ACCELERATOR_H_ + +#include +#include +#include +#include + +#include "base/callback.h" +#include "base/threading/thread_checker.h" +#include "components/arc/video_accelerator/arc_video_decode_accelerator.h" +#include "gpu/command_buffer/service/gpu_preferences.h" +#include "media/video/video_decode_accelerator.h" + +namespace arc { + +class ProtectedBufferManager; +class ProtectedBufferHandle; + +// This class is executed in the GPU process. It takes decoding requests from +// ARC via IPC channels and translates and sends those requests to an +// implementation of media::VideoDecodeAccelerator. It also returns the decoded +// frames back to the ARC side. +class ChromeArcVideoDecodeAccelerator + : public ArcVideoDecodeAccelerator, + public media::VideoDecodeAccelerator::Client, + public base::SupportsWeakPtr { + public: + ChromeArcVideoDecodeAccelerator( + const gpu::GpuPreferences& gpu_preferences, + ProtectedBufferManager* protected_buffer_manager); + ~ChromeArcVideoDecodeAccelerator() override; + + // Implementation of the ArcVideoDecodeAccelerator interface. + ArcVideoDecodeAccelerator::Result Initialize( + const Config& config, + ArcVideoDecodeAccelerator::Client* client) override; + void SetNumberOfOutputBuffers(size_t number) override; + bool AllocateProtectedBuffer(PortType port, + uint32_t index, + base::ScopedFD handle_fd, + size_t size) override; + void BindSharedMemory(PortType port, + uint32_t index, + base::ScopedFD ashmem_fd, + off_t offset, + size_t length) override; + void BindDmabuf(PortType port, + uint32_t index, + base::ScopedFD dmabuf_fd, + const std::vector<::arc::VideoFramePlane>& planes) override; + void UseBuffer(PortType port, + uint32_t index, + const BufferMetadata& metadata) override; + void Reset() override; + void Flush() override; + + // Implementation of the VideoDecodeAccelerator::Client interface. + void ProvidePictureBuffers(uint32_t requested_num_of_buffers, + media::VideoPixelFormat output_format, + uint32_t textures_per_buffer, + const gfx::Size& dimensions, + uint32_t texture_target) override; + void DismissPictureBuffer(int32_t picture_buffer) override; + void PictureReady(const media::Picture& picture) override; + void NotifyEndOfBitstreamBuffer(int32_t bitstream_buffer_id) override; + void NotifyFlushDone() override; + void NotifyResetDone() override; + void NotifyError(media::VideoDecodeAccelerator::Error error) override; + + private: + // Some information related to a bitstream buffer. The information is required + // when input or output buffers are returned back to the client. + struct InputRecord { + int32_t bitstream_buffer_id; + uint32_t buffer_index; + int64_t timestamp; + + InputRecord(int32_t bitstream_buffer_id, + uint32_t buffer_index, + int64_t timestamp); + }; + + // The information about the shared memory used as an input buffer. + struct InputBufferInfo { + // SharedMemoryHandle for this buffer to be passed to accelerator. + // In non-secure mode, received via BindSharedMemory from the client, + // in secure mode, a handle for the SharedMemory in protected_shmem. + base::SharedMemoryHandle shm_handle; + + // Used only in secure mode; handle to the protected buffer backing + // this input buffer. + std::unique_ptr protected_buffer_handle; + + // Offset to the payload from the beginning of the shared memory buffer. + off_t offset = 0; + + InputBufferInfo(); + ~InputBufferInfo(); + }; + + // The information about the native pixmap used as an output buffer. + struct OutputBufferInfo { + // GpuMemoryBufferHandle for this buffer to be passed to accelerator. + // In non-secure mode, received via BindDmabuf from the client, + // in secure mode, a handle to the NativePixmap in protected_pixmap. + gfx::GpuMemoryBufferHandle gpu_memory_buffer_handle; + + // Used only in secure mode; handle to the protected buffer backing + // this output buffer. + std::unique_ptr protected_buffer_handle; + + OutputBufferInfo(); + ~OutputBufferInfo(); + }; + + // The helper method to simplify reporting of the status returned to UMA. + ArcVideoDecodeAccelerator::Result InitializeTask( + const Config& config, + ArcVideoDecodeAccelerator::Client* client); + + // Helper function to validate |port| and |index|. + bool ValidatePortAndIndex(PortType port, uint32_t index) const; + + // Return true if |planes| is valid for a dmabuf |fd|. + bool VerifyDmabuf(const base::ScopedFD& fd, + const std::vector<::arc::VideoFramePlane>& planes) const; + + // Creates an InputRecord for the given |bitstream_buffer_id|. The + // |buffer_index| is the index of the associated input buffer. The |timestamp| + // is the time the video frame should be displayed. + void CreateInputRecord(int32_t bitstream_buffer_id, + uint32_t buffer_index, + int64_t timestamp); + + // Finds the InputRecord which matches to given |bitstream_buffer_id|. + // Returns |nullptr| if it cannot be found. + InputRecord* FindInputRecord(int32_t bitstream_buffer_id); + + // Notify the client when output format changes. + void NotifyOutputFormatChanged(); + + // Global counter that keeps track the number of active clients (i.e., how + // many VDAs in use by this class). + // Since this class only works on the same thread, it's safe to access + // |client_count_| without lock. + static int client_count_; + + std::unique_ptr vda_; + + // It's safe to use the pointer here, the life cycle of the |arc_client_| + // is longer than this ChromeArcVideoDecodeAccelerator. + ArcVideoDecodeAccelerator::Client* arc_client_; + + // The next ID for the bitstream buffer, started from 0. + int32_t next_bitstream_buffer_id_; + + gfx::Size coded_size_; + gfx::Rect visible_rect_; + media::VideoPixelFormat output_pixel_format_; + + // A list of most recent |kMaxNumberOfInputRecord| InputRecords. + // |kMaxNumberOfInputRecord| is defined in the cc file. + std::list input_records_; + + // The details of the shared memory of each input buffers. + std::vector> input_buffer_info_; + + // To keep those output buffers which have been bound by bindDmabuf() but + // haven't been passed to VDA yet. Will call VDA::ImportBufferForPicture() + // when those buffers are used for the first time. + std::vector> buffers_pending_import_; + + THREAD_CHECKER(thread_checker_); + size_t output_buffer_size_; + + // The minimal number of requested output buffers. + uint32_t requested_num_of_output_buffers_; + + bool secure_mode_ = false; + + gpu::GpuPreferences gpu_preferences_; + ProtectedBufferManager* protected_buffer_manager_; + + DISALLOW_COPY_AND_ASSIGN(ChromeArcVideoDecodeAccelerator); +}; + +} // namespace arc + +#endif // COMPONENTS_ARC_VIDEO_ACCELERATOR_CHROME_ARC_VIDEO_DECODE_ACCELERATOR_H_ diff --git a/chromium/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.cc b/chromium/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.cc new file mode 100644 index 00000000000..8020a986d10 --- /dev/null +++ b/chromium/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.cc @@ -0,0 +1,269 @@ +// Copyright 2016 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 "components/arc/video_accelerator/gpu_arc_video_decode_accelerator.h" + +#include + +#include "base/bind.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/threading/thread_task_runner_handle.h" +#include "components/arc/video_accelerator/chrome_arc_video_decode_accelerator.h" +#include "mojo/public/cpp/bindings/strong_binding.h" +#include "mojo/public/cpp/bindings/type_converter.h" +#include "mojo/public/cpp/system/platform_handle.h" + +// Make sure arc::mojom::VideoDecodeAccelerator::Result and +// arc::ArcVideoDecodeAccelerator::Result match. +static_assert( + static_cast(arc::mojom::VideoDecodeAccelerator::Result::SUCCESS) == + arc::ArcVideoDecodeAccelerator::SUCCESS, + "enum mismatch"); +static_assert(static_cast( + arc::mojom::VideoDecodeAccelerator::Result::ILLEGAL_STATE) == + arc::ArcVideoDecodeAccelerator::ILLEGAL_STATE, + "enum mismatch"); +static_assert( + static_cast( + arc::mojom::VideoDecodeAccelerator::Result::INVALID_ARGUMENT) == + arc::ArcVideoDecodeAccelerator::INVALID_ARGUMENT, + "enum mismatch"); +static_assert( + static_cast( + arc::mojom::VideoDecodeAccelerator::Result::UNREADABLE_INPUT) == + arc::ArcVideoDecodeAccelerator::UNREADABLE_INPUT, + "enum mismatch"); +static_assert( + static_cast( + arc::mojom::VideoDecodeAccelerator::Result::PLATFORM_FAILURE) == + arc::ArcVideoDecodeAccelerator::PLATFORM_FAILURE, + "enum mismatch"); +static_assert( + static_cast( + arc::mojom::VideoDecodeAccelerator::Result::INSUFFICIENT_RESOURCES) == + arc::ArcVideoDecodeAccelerator::INSUFFICIENT_RESOURCES, + "enum mismatch"); + +namespace mojo { + +template <> +struct TypeConverter { + static arc::mojom::BufferMetadataPtr Convert( + const arc::BufferMetadata& input) { + arc::mojom::BufferMetadataPtr result = arc::mojom::BufferMetadata::New(); + result->timestamp = input.timestamp; + result->bytes_used = input.bytes_used; + return result; + } +}; + +template <> +struct TypeConverter { + static arc::BufferMetadata Convert( + const arc::mojom::BufferMetadataPtr& input) { + arc::BufferMetadata result; + result.timestamp = input->timestamp; + result.bytes_used = input->bytes_used; + return result; + } +}; + +template <> +struct TypeConverter { + static arc::mojom::VideoFormatPtr Convert(const arc::VideoFormat& input) { + arc::mojom::VideoFormatPtr result = arc::mojom::VideoFormat::New(); + result->pixel_format = input.pixel_format; + result->buffer_size = input.buffer_size; + result->min_num_buffers = input.min_num_buffers; + result->coded_width = input.coded_width; + result->coded_height = input.coded_height; + result->crop_left = input.crop_left; + result->crop_width = input.crop_width; + result->crop_top = input.crop_top; + result->crop_height = input.crop_height; + return result; + } +}; + +template <> +struct TypeConverter { + static arc::ArcVideoDecodeAccelerator::Config Convert( + const arc::mojom::VideoDecodeAcceleratorConfigPtr& input) { + arc::ArcVideoDecodeAccelerator::Config result; + result.num_input_buffers = input->num_input_buffers; + result.input_pixel_format = input->input_pixel_format; + result.secure_mode = input->secure_mode; + return result; + } +}; + +} // namespace mojo + +namespace arc { + +GpuArcVideoDecodeAccelerator::GpuArcVideoDecodeAccelerator( + const gpu::GpuPreferences& gpu_preferences, + ProtectedBufferManager* protected_buffer_manager) + : gpu_preferences_(gpu_preferences), + accelerator_(std::make_unique( + gpu_preferences_, + protected_buffer_manager)) {} + +GpuArcVideoDecodeAccelerator::~GpuArcVideoDecodeAccelerator() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +} + +void GpuArcVideoDecodeAccelerator::OnError( + ArcVideoDecodeAccelerator::Result error) { + DVLOG(2) << "OnError " << error; + DCHECK_NE(error, ArcVideoDecodeAccelerator::SUCCESS); + DCHECK(client_); + client_->OnError( + static_cast<::arc::mojom::VideoDecodeAccelerator::Result>(error)); +} + +void GpuArcVideoDecodeAccelerator::OnBufferDone( + PortType port, + uint32_t index, + const BufferMetadata& metadata) { + DVLOG(2) << "OnBufferDone " << port << "," << index; + DCHECK(client_); + client_->OnBufferDone(static_cast<::arc::mojom::PortType>(port), index, + ::arc::mojom::BufferMetadata::From(metadata)); +} + +void GpuArcVideoDecodeAccelerator::OnFlushDone() { + DVLOG(2) << "OnFlushDone"; + DCHECK(client_); + client_->OnFlushDone(); +} + +void GpuArcVideoDecodeAccelerator::OnResetDone() { + DVLOG(2) << "OnResetDone"; + DCHECK(client_); + client_->OnResetDone(); +} + +void GpuArcVideoDecodeAccelerator::OnOutputFormatChanged( + const VideoFormat& format) { + DVLOG(2) << "OnOutputFormatChanged"; + DCHECK(client_); + client_->OnOutputFormatChanged(::arc::mojom::VideoFormat::From(format)); +} + +void GpuArcVideoDecodeAccelerator::Initialize( + ::arc::mojom::VideoDecodeAcceleratorConfigPtr config, + ::arc::mojom::VideoDecodeClientPtr client, + InitializeCallback callback) { + DVLOG(2) << "Initialize"; + DCHECK(!client_); + + client_ = std::move(client); + ArcVideoDecodeAccelerator::Result result = accelerator_->Initialize( + config.To(), this); + std::move(callback).Run( + static_cast<::arc::mojom::VideoDecodeAccelerator::Result>(result)); +} + +base::ScopedFD GpuArcVideoDecodeAccelerator::UnwrapFdFromMojoHandle( + mojo::ScopedHandle handle) { + DCHECK(client_); + if (!handle.is_valid()) { + LOG(ERROR) << "handle is invalid"; + client_->OnError( + ::arc::mojom::VideoDecodeAccelerator::Result::INVALID_ARGUMENT); + return base::ScopedFD(); + } + + base::PlatformFile platform_file; + MojoResult mojo_result = + mojo::UnwrapPlatformFile(std::move(handle), &platform_file); + if (mojo_result != MOJO_RESULT_OK) { + LOG(ERROR) << "UnwrapPlatformFile failed: " << mojo_result; + client_->OnError( + ::arc::mojom::VideoDecodeAccelerator::Result::PLATFORM_FAILURE); + return base::ScopedFD(); + } + + return base::ScopedFD(platform_file); +} + +void GpuArcVideoDecodeAccelerator::AllocateProtectedBuffer( + ::arc::mojom::PortType port, + uint32_t index, + mojo::ScopedHandle handle, + uint64_t size, + AllocateProtectedBufferCallback callback) { + DVLOG(2) << "port=" << port << ", index=" << index << ", size=" << size; + + base::ScopedFD fd = UnwrapFdFromMojoHandle(std::move(handle)); + if (!fd.is_valid()) { + std::move(callback).Run(false); + return; + } + + bool result = accelerator_->AllocateProtectedBuffer( + static_cast(port), index, std::move(fd), size); + + std::move(callback).Run(result); +} + +void GpuArcVideoDecodeAccelerator::BindSharedMemory( + ::arc::mojom::PortType port, + uint32_t index, + mojo::ScopedHandle ashmem_handle, + uint32_t offset, + uint32_t length) { + DVLOG(2) << "BindSharedMemoryCallback port=" << port << ", index=" << index + << ", offset=" << offset << ", length=" << length; + + base::ScopedFD fd = UnwrapFdFromMojoHandle(std::move(ashmem_handle)); + if (!fd.is_valid()) + return; + accelerator_->BindSharedMemory(static_cast(port), index, + std::move(fd), offset, length); +} + +void GpuArcVideoDecodeAccelerator::BindDmabuf( + ::arc::mojom::PortType port, + uint32_t index, + mojo::ScopedHandle dmabuf_handle, + std::vector<::arc::VideoFramePlane> planes) { + DVLOG(2) << "BindDmabuf port=" << port << ", index=" << index; + + base::ScopedFD fd = UnwrapFdFromMojoHandle(std::move(dmabuf_handle)); + if (!fd.is_valid()) + return; + + accelerator_->BindDmabuf(static_cast(port), index, std::move(fd), + std::move(planes)); +} + +void GpuArcVideoDecodeAccelerator::UseBuffer( + ::arc::mojom::PortType port, + uint32_t index, + ::arc::mojom::BufferMetadataPtr metadata) { + DVLOG(2) << "UseBuffer port=" << port << ", index=" << index; + accelerator_->UseBuffer(static_cast(port), index, + metadata.To()); +} + +void GpuArcVideoDecodeAccelerator::SetNumberOfOutputBuffers(uint32_t number) { + DVLOG(2) << "SetNumberOfOutputBuffers number=" << number; + accelerator_->SetNumberOfOutputBuffers(number); +} + +void GpuArcVideoDecodeAccelerator::Reset() { + DVLOG(2) << "Reset"; + accelerator_->Reset(); +} + +void GpuArcVideoDecodeAccelerator::Flush() { + DVLOG(2) << "Flush"; + accelerator_->Flush(); +} + +} // namespace arc diff --git a/chromium/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.h b/chromium/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.h new file mode 100644 index 00000000000..6be9cae26e1 --- /dev/null +++ b/chromium/components/arc/video_accelerator/gpu_arc_video_decode_accelerator.h @@ -0,0 +1,88 @@ +// Copyright 2016 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 COMPONENTS_ARC_VIDEO_ACCELERATOR_GPU_ARC_VIDEO_DECODE_ACCELERATOR_H_ +#define COMPONENTS_ARC_VIDEO_ACCELERATOR_GPU_ARC_VIDEO_DECODE_ACCELERATOR_H_ + +#include +#include + +#include "base/files/scoped_file.h" +#include "base/macros.h" +#include "base/threading/thread_checker.h" +#include "components/arc/common/video_decode_accelerator.mojom.h" +#include "components/arc/video_accelerator/arc_video_decode_accelerator.h" +#include "components/arc/video_accelerator/video_frame_plane.h" +#include "gpu/command_buffer/service/gpu_preferences.h" + +namespace arc { + +class ProtectedBufferManager; + +// GpuArcVideoDecodeAccelerator manages life-cycle and IPC message translation +// for ArcVideoDecodeAccelerator. +// +// For each creation request from GpuArcVideoDecodeAcceleratorHost, +// GpuArcVideoDecodeAccelerator will create a new IPC channel. +class GpuArcVideoDecodeAccelerator + : public ::arc::mojom::VideoDecodeAccelerator, + public ArcVideoDecodeAccelerator::Client { + public: + GpuArcVideoDecodeAccelerator( + const gpu::GpuPreferences& gpu_preferences, + ProtectedBufferManager* protected_buffer_manager); + ~GpuArcVideoDecodeAccelerator() override; + + private: + // ArcVideoDecodeAccelerator::Client implementation. + void OnError(ArcVideoDecodeAccelerator::Result error) override; + void OnBufferDone(PortType port, + uint32_t index, + const BufferMetadata& metadata) override; + void OnFlushDone() override; + void OnResetDone() override; + void OnOutputFormatChanged(const VideoFormat& format) override; + + // ::arc::mojom::VideoDecodeAccelerator implementation. + void Initialize(::arc::mojom::VideoDecodeAcceleratorConfigPtr config, + ::arc::mojom::VideoDecodeClientPtr client, + InitializeCallback callback) override; + + void AllocateProtectedBuffer( + ::arc::mojom::PortType port, + uint32_t index, + mojo::ScopedHandle handle, + uint64_t size, + AllocateProtectedBufferCallback callback) override; + + void BindSharedMemory(::arc::mojom::PortType port, + uint32_t index, + mojo::ScopedHandle ashmem_handle, + uint32_t offset, + uint32_t length) override; + void BindDmabuf(::arc::mojom::PortType port, + uint32_t index, + mojo::ScopedHandle dmabuf_handle, + std::vector<::arc::VideoFramePlane> planes) override; + void UseBuffer(::arc::mojom::PortType port, + uint32_t index, + ::arc::mojom::BufferMetadataPtr metadata) override; + void SetNumberOfOutputBuffers(uint32_t number) override; + void Flush() override; + void Reset() override; + + base::ScopedFD UnwrapFdFromMojoHandle(mojo::ScopedHandle handle); + + THREAD_CHECKER(thread_checker_); + + gpu::GpuPreferences gpu_preferences_; + std::unique_ptr accelerator_; + ::arc::mojom::VideoDecodeClientPtr client_; + + DISALLOW_COPY_AND_ASSIGN(GpuArcVideoDecodeAccelerator); +}; + +} // namespace arc + +#endif // COMPONENTS_ARC_VIDEO_ACCELERATOR_GPU_ARC_VIDEO_DECODE_ACCELERATOR_H_ diff --git a/chromium/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc b/chromium/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc new file mode 100644 index 00000000000..2d5e7fb1ad2 --- /dev/null +++ b/chromium/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc @@ -0,0 +1,257 @@ +// Copyright 2017 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 "components/arc/video_accelerator/gpu_arc_video_encode_accelerator.h" + +#include + +#include "base/logging.h" +#include "base/sys_info.h" +#include "media/base/video_types.h" +#include "media/gpu/gpu_video_encode_accelerator_factory.h" +#include "mojo/public/cpp/bindings/strong_binding.h" +#include "mojo/public/cpp/bindings/type_converter.h" +#include "mojo/public/cpp/system/platform_handle.h" + +#define DVLOGF(x) DVLOG(x) << __func__ << "(): " + +namespace arc { + +namespace { + +// Helper class to notify client about the end of processing a video frame. +class VideoFrameDoneNotifier { + public: + explicit VideoFrameDoneNotifier(base::OnceClosure notify_closure) + : notify_closure_(std::move(notify_closure)) {} + ~VideoFrameDoneNotifier() { std::move(notify_closure_).Run(); } + + private: + base::OnceClosure notify_closure_; +}; + +} // namespace + +GpuArcVideoEncodeAccelerator::GpuArcVideoEncodeAccelerator( + const gpu::GpuPreferences& gpu_preferences) + : gpu_preferences_(gpu_preferences) {} + +GpuArcVideoEncodeAccelerator::~GpuArcVideoEncodeAccelerator() = default; + +// VideoEncodeAccelerator::Client implementation. +void GpuArcVideoEncodeAccelerator::RequireBitstreamBuffers( + unsigned int input_count, + const gfx::Size& coded_size, + size_t output_buffer_size) { + DVLOGF(2) << "input_count=" << input_count + << ", coded_size=" << coded_size.ToString() + << ", output_buffer_size=" << output_buffer_size; + DCHECK(client_); + coded_size_ = coded_size; + client_->RequireBitstreamBuffers(input_count, coded_size, output_buffer_size); +} + +void GpuArcVideoEncodeAccelerator::BitstreamBufferReady( + int32_t bitstream_buffer_id, + size_t payload_size, + bool key_frame, + base::TimeDelta timestamp) { + DVLOGF(2) << "id=" << bitstream_buffer_id; + DCHECK(client_); + auto iter = use_bitstream_cbs_.find(bitstream_buffer_id); + DCHECK(iter != use_bitstream_cbs_.end()); + std::move(iter->second) + .Run(payload_size, key_frame, timestamp.InMicroseconds()); + use_bitstream_cbs_.erase(iter); +} + +void GpuArcVideoEncodeAccelerator::NotifyError(Error error) { + DVLOGF(2) << "error=" << error; + DCHECK(client_); + client_->NotifyError(error); +} + +// ::arc::mojom::VideoEncodeAccelerator implementation. +void GpuArcVideoEncodeAccelerator::GetSupportedProfiles( + GetSupportedProfilesCallback callback) { + std::move(callback).Run( + media::GpuVideoEncodeAcceleratorFactory::GetSupportedProfiles( + gpu_preferences_)); +} + +void GpuArcVideoEncodeAccelerator::Initialize( + VideoPixelFormat input_format, + const gfx::Size& visible_size, + VideoEncodeAccelerator::StorageType input_storage, + VideoCodecProfile output_profile, + uint32_t initial_bitrate, + VideoEncodeClientPtr client, + InitializeCallback callback) { + DVLOGF(2) << "visible_size=" << visible_size.ToString() + << ", profile=" << output_profile; + + input_pixel_format_ = input_format; + visible_size_ = visible_size; + accelerator_ = media::GpuVideoEncodeAcceleratorFactory::CreateVEA( + input_pixel_format_, visible_size_, output_profile, initial_bitrate, this, + gpu_preferences_); + if (accelerator_ == nullptr) { + DLOG(ERROR) << "Failed to create a VideoEncodeAccelerator."; + std::move(callback).Run(false); + return; + } + client_ = std::move(client); + std::move(callback).Run(true); +} + +static void DropShareMemoryAndVideoFrameDoneNotifier( + std::unique_ptr shm, + std::unique_ptr notifier) { + // Just let |shm| and |notifier| fall out of scope. +} + +void GpuArcVideoEncodeAccelerator::Encode( + mojo::ScopedHandle handle, + std::vector<::arc::VideoFramePlane> planes, + int64_t timestamp, + bool force_keyframe, + EncodeCallback callback) { + DVLOGF(2) << "timestamp=" << timestamp; + if (!accelerator_) { + DLOG(ERROR) << "Accelerator is not initialized."; + return; + } + + auto notifier = std::make_unique(std::move(callback)); + + if (planes.empty()) { // EOS + accelerator_->Encode(media::VideoFrame::CreateEOSFrame(), force_keyframe); + return; + } + + base::ScopedFD fd = UnwrapFdFromMojoHandle(std::move(handle)); + if (!fd.is_valid()) + return; + + size_t allocation_size = + media::VideoFrame::AllocationSize(input_pixel_format_, coded_size_); + + // TODO(rockot): Pass GUIDs through Mojo. https://crbug.com/713763. + // TODO(rockot): This fd comes from a mojo::ScopedHandle in + // GpuArcVideoService::BindSharedMemory. That should be passed through, + // rather than pulling out the fd. https://crbug.com/713763. + // TODO(rockot): Pass through a real size rather than |0|. + base::UnguessableToken guid = base::UnguessableToken::Create(); + base::SharedMemoryHandle shm_handle(base::FileDescriptor(fd.release(), true), + 0u, guid); + auto shm = std::make_unique(shm_handle, true); + + base::CheckedNumeric map_offset = planes[0].offset; + base::CheckedNumeric map_size = allocation_size; + const uint32_t aligned_offset = + planes[0].offset % base::SysInfo::VMAllocationGranularity(); + map_offset -= aligned_offset; + map_size += aligned_offset; + + if (!map_offset.IsValid() || !map_size.IsValid()) { + DLOG(ERROR) << "Invalid map_offset or map_size"; + client_->NotifyError(Error::kInvalidArgumentError); + return; + } + if (!shm->MapAt(map_offset.ValueOrDie(), map_size.ValueOrDie())) { + DLOG(ERROR) << "Failed to map memory."; + client_->NotifyError(Error::kPlatformFailureError); + return; + } + + uint8_t* shm_memory = reinterpret_cast(shm->memory()); + auto frame = media::VideoFrame::WrapExternalSharedMemory( + input_pixel_format_, coded_size_, gfx::Rect(visible_size_), visible_size_, + shm_memory + aligned_offset, allocation_size, shm_handle, + planes[0].offset, base::TimeDelta::FromMicroseconds(timestamp)); + + // Wrap |shm| and |notifier| in a callback and add it as a destruction + // observer. When the |frame| goes out of scope, it unmaps and releases + // the shared memory as well as notifies |client_| about the end of processing + // the |frame|. + frame->AddDestructionObserver( + base::Bind(&DropShareMemoryAndVideoFrameDoneNotifier, base::Passed(&shm), + base::Passed(¬ifier))); + + accelerator_->Encode(frame, force_keyframe); +} + +void GpuArcVideoEncodeAccelerator::UseBitstreamBuffer( + mojo::ScopedHandle shmem_fd, + uint32_t offset, + uint32_t size, + UseBitstreamBufferCallback callback) { + DVLOGF(2) << "serial=" << bitstream_buffer_serial_; + if (!accelerator_) { + DLOG(ERROR) << "Accelerator is not initialized."; + return; + } + + base::ScopedFD fd = UnwrapFdFromMojoHandle(std::move(shmem_fd)); + if (!fd.is_valid()) + return; + + // TODO(rockot): Pass GUIDs through Mojo. https://crbug.com/713763. + // TODO(rockot): This fd comes from a mojo::ScopedHandle in + // GpuArcVideoService::BindSharedMemory. That should be passed through, + // rather than pulling out the fd. https://crbug.com/713763. + // TODO(rockot): Pass through a real size rather than |0|. + base::UnguessableToken guid = base::UnguessableToken::Create(); + base::SharedMemoryHandle shm_handle(base::FileDescriptor(fd.release(), true), + 0u, guid); + use_bitstream_cbs_.emplace(bitstream_buffer_serial_, std::move(callback)); + accelerator_->UseOutputBitstreamBuffer(media::BitstreamBuffer( + bitstream_buffer_serial_, shm_handle, size, offset)); + + // Mask against 30 bits to avoid (undefined) wraparound on signed integer. + bitstream_buffer_serial_ = (bitstream_buffer_serial_ + 1) & 0x3FFFFFFF; +} + +void GpuArcVideoEncodeAccelerator::RequestEncodingParametersChange( + uint32_t bitrate, + uint32_t framerate) { + DVLOGF(2) << "bitrate=" << bitrate << ", framerate=" << framerate; + if (!accelerator_) { + DLOG(ERROR) << "Accelerator is not initialized."; + return; + } + accelerator_->RequestEncodingParametersChange(bitrate, framerate); +} + +void GpuArcVideoEncodeAccelerator::Flush(FlushCallback callback) { + DVLOGF(2); + if (!accelerator_) { + DLOG(ERROR) << "Accelerator is not initialized."; + return; + } + accelerator_->Flush(std::move(callback)); +} + +base::ScopedFD GpuArcVideoEncodeAccelerator::UnwrapFdFromMojoHandle( + mojo::ScopedHandle handle) { + DCHECK(client_); + if (!handle.is_valid()) { + DLOG(ERROR) << "handle is invalid."; + client_->NotifyError(Error::kInvalidArgumentError); + return base::ScopedFD(); + } + + base::PlatformFile platform_file; + MojoResult mojo_result = + mojo::UnwrapPlatformFile(std::move(handle), &platform_file); + if (mojo_result != MOJO_RESULT_OK) { + DLOG(ERROR) << "UnwrapPlatformFile failed: " << mojo_result; + client_->NotifyError(Error::kPlatformFailureError); + return base::ScopedFD(); + } + + return base::ScopedFD(platform_file); +} + +} // namespace arc diff --git a/chromium/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.h b/chromium/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.h new file mode 100644 index 00000000000..b799ed44f1a --- /dev/null +++ b/chromium/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.h @@ -0,0 +1,88 @@ +// Copyright 2017 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 COMPONENTS_ARC_VIDEO_ACCELERATOR_GPU_ARC_VIDEO_ENCODE_ACCELERATOR_H_ +#define COMPONENTS_ARC_VIDEO_ACCELERATOR_GPU_ARC_VIDEO_ENCODE_ACCELERATOR_H_ + +#include +#include +#include + +#include "base/files/scoped_file.h" +#include "base/macros.h" +#include "components/arc/common/video_encode_accelerator.mojom.h" +#include "components/arc/video_accelerator/video_frame_plane.h" +#include "gpu/command_buffer/service/gpu_preferences.h" +#include "media/video/video_encode_accelerator.h" + +namespace arc { + +// GpuArcVideoEncodeAccelerator manages life-cycle and IPC message translation +// for media::VideoEncodeAccelerator. +class GpuArcVideoEncodeAccelerator + : public ::arc::mojom::VideoEncodeAccelerator, + public media::VideoEncodeAccelerator::Client { + public: + explicit GpuArcVideoEncodeAccelerator( + const gpu::GpuPreferences& gpu_preferences); + ~GpuArcVideoEncodeAccelerator() override; + + private: + using VideoPixelFormat = media::VideoPixelFormat; + using VideoCodecProfile = media::VideoCodecProfile; + using Error = media::VideoEncodeAccelerator::Error; + using VideoEncodeClientPtr = ::arc::mojom::VideoEncodeClientPtr; + + // VideoEncodeAccelerator::Client implementation. + void RequireBitstreamBuffers(unsigned int input_count, + const gfx::Size& input_coded_size, + size_t output_buffer_size) override; + void BitstreamBufferReady(int32_t bitstream_buffer_id, + size_t payload_size, + bool key_frame, + base::TimeDelta timestamp) override; + void NotifyError(Error error) override; + + // ::arc::mojom::VideoEncodeAccelerator implementation. + void GetSupportedProfiles(GetSupportedProfilesCallback callback) override; + void Initialize(VideoPixelFormat input_format, + const gfx::Size& visible_size, + VideoEncodeAccelerator::StorageType input_storage, + VideoCodecProfile output_profile, + uint32_t initial_bitrate, + VideoEncodeClientPtr client, + InitializeCallback callback) override; + void Encode(mojo::ScopedHandle fd, + std::vector<::arc::VideoFramePlane> planes, + int64_t timestamp, + bool force_keyframe, + EncodeCallback callback) override; + void UseBitstreamBuffer(mojo::ScopedHandle shmem_fd, + uint32_t offset, + uint32_t size, + UseBitstreamBufferCallback callback) override; + void RequestEncodingParametersChange(uint32_t bitrate, + uint32_t framerate) override; + void Flush(FlushCallback callback) override; + + // Unwraps a file descriptor from the given mojo::ScopedHandle. + // If an error is encountered, it returns an invalid base::ScopedFD and + // notifies client about the error via VideoEncodeClient::NotifyError. + base::ScopedFD UnwrapFdFromMojoHandle(mojo::ScopedHandle handle); + + gpu::GpuPreferences gpu_preferences_; + std::unique_ptr accelerator_; + ::arc::mojom::VideoEncodeClientPtr client_; + gfx::Size coded_size_; + gfx::Size visible_size_; + VideoPixelFormat input_pixel_format_; + int32_t bitstream_buffer_serial_; + std::unordered_map use_bitstream_cbs_; + + DISALLOW_COPY_AND_ASSIGN(GpuArcVideoEncodeAccelerator); +}; + +} // namespace arc + +#endif // COMPONENTS_ARC_VIDEO_ACCELERATOR_GPU_ARC_VIDEO_ENCODE_ACCELERATOR_H_ diff --git a/chromium/components/arc/video_accelerator/protected_buffer_manager.cc b/chromium/components/arc/video_accelerator/protected_buffer_manager.cc new file mode 100644 index 00000000000..60bb2be1821 --- /dev/null +++ b/chromium/components/arc/video_accelerator/protected_buffer_manager.cc @@ -0,0 +1,408 @@ +// Copyright 2017 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 "components/arc/video_accelerator/protected_buffer_manager.h" + +#include "base/bits.h" +#include "base/logging.h" +#include "base/memory/shared_memory.h" +#include "base/sys_info.h" +#include "mojo/public/cpp/system/buffer.h" +#include "mojo/public/cpp/system/platform_handle.h" +#include "ui/gfx/geometry/size.h" +#include "ui/ozone/public/ozone_platform.h" +#include "ui/ozone/public/surface_factory_ozone.h" + +#define VLOGF(level) VLOG(level) << __func__ << "(): " + +namespace arc { + +namespace { +// Size of the pixmap to be used as the dummy handle for protected buffers. +constexpr gfx::Size kDummyBufferSize(32, 32); +} // namespace + +ProtectedBufferHandle::ProtectedBufferHandle( + base::OnceClosure destruction_cb, + const base::SharedMemoryHandle& shm_handle) + : shm_handle_(shm_handle), destruction_cb_(std::move(destruction_cb)) { + DCHECK(shm_handle_.IsValid()); + DCHECK(shm_handle.OwnershipPassesToIPC()); +} + +ProtectedBufferHandle::ProtectedBufferHandle( + base::OnceClosure destruction_cb, + const gfx::NativePixmapHandle& native_pixmap_handle) + : native_pixmap_handle_(native_pixmap_handle), + destruction_cb_(std::move(destruction_cb)) { + DCHECK(!native_pixmap_handle_.fds.empty()); + for (const auto& fd : native_pixmap_handle_.fds) + DCHECK(fd.auto_close); +} + +ProtectedBufferHandle::~ProtectedBufferHandle() { + if (shm_handle_.OwnershipPassesToIPC()) + shm_handle_.Close(); + + for (const auto& fd : native_pixmap_handle_.fds) { + // Close the fd by wrapping it in a ScopedFD and letting + // it fall out of scope. + base::ScopedFD scoped_fd(fd.fd); + } + + std::move(destruction_cb_).Run(); +} + +base::SharedMemoryHandle ProtectedBufferHandle::shm_handle() const { + base::SharedMemoryHandle handle = shm_handle_; + handle.SetOwnershipPassesToIPC(false); + return handle; +} + +gfx::NativePixmapHandle ProtectedBufferHandle::native_pixmap_handle() const { + return native_pixmap_handle_; +} + +class ProtectedBufferManager::ProtectedBuffer { + public: + virtual ~ProtectedBuffer() {} + + // Downcasting methods to return duplicated handles to the underlying + // protected buffers for each buffer type, or empty/null handles if not + // applicable. + virtual base::SharedMemoryHandle DuplicateSharedMemoryHandle() const { + return base::SharedMemoryHandle(); + } + virtual gfx::NativePixmapHandle DuplicateNativePixmapHandle() const { + return gfx::NativePixmapHandle(); + } + + // Downcasting method to return a scoped_refptr to the underlying + // NativePixmap, or null if not applicable. + virtual scoped_refptr GetNativePixmap() const { + return nullptr; + } + + protected: + explicit ProtectedBuffer(scoped_refptr dummy_handle) + : dummy_handle_(std::move(dummy_handle)) {} + + private: + scoped_refptr dummy_handle_; + + DISALLOW_COPY_AND_ASSIGN(ProtectedBuffer); +}; + +class ProtectedBufferManager::ProtectedSharedMemory + : public ProtectedBufferManager::ProtectedBuffer { + public: + ~ProtectedSharedMemory() override; + + // Allocate a ProtectedSharedMemory buffer of |size| bytes. + static std::unique_ptr Create( + scoped_refptr dummy_handle, + size_t size); + + base::SharedMemoryHandle DuplicateSharedMemoryHandle() const override { + return base::SharedMemory::DuplicateHandle(shmem_->handle()); + } + + private: + explicit ProtectedSharedMemory(scoped_refptr dummy_handle); + + std::unique_ptr shmem_; +}; + +ProtectedBufferManager::ProtectedSharedMemory::ProtectedSharedMemory( + scoped_refptr dummy_handle) + : ProtectedBuffer(std::move(dummy_handle)) {} + +ProtectedBufferManager::ProtectedSharedMemory::~ProtectedSharedMemory() {} + +// static +std::unique_ptr +ProtectedBufferManager::ProtectedSharedMemory::Create( + scoped_refptr dummy_handle, + size_t size) { + std::unique_ptr protected_shmem( + new ProtectedSharedMemory(std::move(dummy_handle))); + + size_t aligned_size = + base::bits::Align(size, base::SysInfo::VMAllocationGranularity()); + + mojo::ScopedSharedBufferHandle mojo_shared_buffer = + mojo::SharedBufferHandle::Create(aligned_size); + if (!mojo_shared_buffer->is_valid()) { + VLOGF(1) << "Failed to allocate shared memory"; + return nullptr; + } + + base::SharedMemoryHandle shm_handle; + MojoResult mojo_result = mojo::UnwrapSharedMemoryHandle( + std::move(mojo_shared_buffer), &shm_handle, nullptr, nullptr); + if (mojo_result != MOJO_RESULT_OK) { + VLOGF(1) << "Failed to unwrap a mojo shared memory handle"; + return nullptr; + } + + protected_shmem->shmem_ = + std::make_unique(shm_handle, false); + return protected_shmem; +} + +class ProtectedBufferManager::ProtectedNativePixmap + : public ProtectedBufferManager::ProtectedBuffer { + public: + ~ProtectedNativePixmap() override; + + // Allocate a ProtectedNativePixmap of |format| and |size|. + static std::unique_ptr Create( + scoped_refptr dummy_handle, + gfx::BufferFormat format, + const gfx::Size& size); + + gfx::NativePixmapHandle DuplicateNativePixmapHandle() const override { + return native_pixmap_->ExportHandle(); + } + + scoped_refptr GetNativePixmap() const override { + return native_pixmap_; + } + + private: + explicit ProtectedNativePixmap(scoped_refptr dummy_handle); + + scoped_refptr native_pixmap_; +}; + +ProtectedBufferManager::ProtectedNativePixmap::ProtectedNativePixmap( + scoped_refptr dummy_handle) + : ProtectedBuffer(std::move(dummy_handle)) {} + +ProtectedBufferManager::ProtectedNativePixmap::~ProtectedNativePixmap() {} + +// static +std::unique_ptr +ProtectedBufferManager::ProtectedNativePixmap::Create( + scoped_refptr dummy_handle, + gfx::BufferFormat format, + const gfx::Size& size) { + std::unique_ptr protected_pixmap( + new ProtectedNativePixmap(std::move(dummy_handle))); + + ui::OzonePlatform* platform = ui::OzonePlatform::GetInstance(); + ui::SurfaceFactoryOzone* factory = platform->GetSurfaceFactoryOzone(); + protected_pixmap->native_pixmap_ = + factory->CreateNativePixmap(gfx::kNullAcceleratedWidget, size, format, + gfx::BufferUsage::SCANOUT_VDA_WRITE); + + if (!protected_pixmap->native_pixmap_) { + VLOGF(1) << "Failed allocating a native pixmap"; + return nullptr; + } + + return protected_pixmap; +} + +ProtectedBufferManager::ProtectedBufferManager() : weak_factory_(this) { + VLOGF(2); + weak_this_ = weak_factory_.GetWeakPtr(); +} + +ProtectedBufferManager::~ProtectedBufferManager() { + VLOGF(2); +} + +std::unique_ptr +ProtectedBufferManager::AllocateProtectedSharedMemory(base::ScopedFD dummy_fd, + size_t size) { + VLOGF(2) << "dummy_fd: " << dummy_fd.get() << ", size: " << size; + + // Import the |dummy_fd| to produce a unique id for it. + uint32_t id; + auto pixmap = ImportDummyFd(std::move(dummy_fd), &id); + if (!pixmap) + return nullptr; + + base::AutoLock lock(buffer_map_lock_); + + if (buffer_map_.find(id) != buffer_map_.end()) { + VLOGF(1) << "A protected buffer for this handle already exists"; + return nullptr; + } + + // Allocate a protected buffer and associate it with the dummy pixmap. + // The pixmap needs to be stored to ensure the id remains the same for + // the entire lifetime of the dummy pixmap. + auto protected_shmem = ProtectedSharedMemory::Create(pixmap, size); + if (!protected_shmem) { + VLOGF(1) << "Failed allocating a protected shared memory buffer"; + return nullptr; + } + + auto shm_handle = protected_shmem->DuplicateSharedMemoryHandle(); + if (!shm_handle.IsValid()) { + VLOGF(1) << "Failed duplicating SharedMemoryHandle"; + return nullptr; + } + + // Store the buffer in the buffer_map_, and return a handle to it to the + // client. The buffer will be permanently removed from the map when the + // handle is destroyed. + VLOGF(2) << "New protected shared memory buffer, handle id: " << id; + auto protected_buffer_handle = std::make_unique( + base::BindOnce(&ProtectedBufferManager::RemoveEntry, weak_this_, id), + shm_handle); + + // This will always succeed as we find() first above. + buffer_map_.emplace(id, std::move(protected_shmem)); + + return protected_buffer_handle; +} + +std::unique_ptr +ProtectedBufferManager::AllocateProtectedNativePixmap(base::ScopedFD dummy_fd, + gfx::BufferFormat format, + const gfx::Size& size) { + VLOGF(2) << "dummy_fd: " << dummy_fd.get() << ", format: " << (int)format + << ", size: " << size.ToString(); + + // Import the |dummy_fd| to produce a unique id for it. + uint32_t id = 0; + auto pixmap = ImportDummyFd(std::move(dummy_fd), &id); + if (!pixmap) + return nullptr; + + base::AutoLock lock(buffer_map_lock_); + + if (buffer_map_.find(id) != buffer_map_.end()) { + VLOGF(1) << "A protected buffer for this handle already exists"; + return nullptr; + } + + // Allocate a protected buffer and associate it with the dummy pixmap. + // The pixmap needs to be stored to ensure the id remains the same for + // the entire lifetime of the dummy pixmap. + auto protected_pixmap = ProtectedNativePixmap::Create(pixmap, format, size); + if (!protected_pixmap) { + VLOGF(1) << "Failed allocating a protected native pixmap"; + return nullptr; + } + + auto native_pixmap_handle = protected_pixmap->DuplicateNativePixmapHandle(); + if (native_pixmap_handle.planes.empty()) { + VLOGF(1) << "Failed duplicating NativePixmapHandle"; + return nullptr; + } + + // Store the buffer in the buffer_map_, and return a handle to it to the + // client. The buffer will be permanently removed from the map when the + // handle is destroyed. + VLOGF(2) << "New protected native pixmap, handle id: " << id; + auto protected_buffer_handle = std::make_unique( + base::BindOnce(&ProtectedBufferManager::RemoveEntry, weak_this_, id), + native_pixmap_handle); + + // This will always succeed as we find() first above. + buffer_map_.emplace(id, std::move(protected_pixmap)); + + return protected_buffer_handle; +} + +base::SharedMemoryHandle +ProtectedBufferManager::GetProtectedSharedMemoryHandleFor( + base::ScopedFD dummy_fd) { + uint32_t id = 0; + auto pixmap = ImportDummyFd(std::move(dummy_fd), &id); + + base::AutoLock lock(buffer_map_lock_); + const auto& iter = buffer_map_.find(id); + if (iter == buffer_map_.end()) + return base::SharedMemoryHandle(); + + return iter->second->DuplicateSharedMemoryHandle(); +} + +gfx::NativePixmapHandle +ProtectedBufferManager::GetProtectedNativePixmapHandleFor( + base::ScopedFD dummy_fd) { + uint32_t id = 0; + auto pixmap = ImportDummyFd(std::move(dummy_fd), &id); + + base::AutoLock lock(buffer_map_lock_); + const auto& iter = buffer_map_.find(id); + if (iter == buffer_map_.end()) + return gfx::NativePixmapHandle(); + + return iter->second->DuplicateNativePixmapHandle(); +} + +scoped_refptr +ProtectedBufferManager::GetProtectedNativePixmapFor( + const gfx::NativePixmapHandle& handle) { + // Only the first fd is used for lookup. + if (handle.fds.empty()) + return nullptr; + + base::ScopedFD dummy_fd(HANDLE_EINTR(dup(handle.fds[0].fd))); + uint32_t id = 0; + auto pixmap = ImportDummyFd(std::move(dummy_fd), &id); + + base::AutoLock lock(buffer_map_lock_); + const auto& iter = buffer_map_.find(id); + if (iter == buffer_map_.end()) + return nullptr; + + auto native_pixmap = iter->second->GetNativePixmap(); + if (native_pixmap) { + for (const auto& fd : handle.fds) + base::ScopedFD scoped_fd(fd.fd); + } + + return native_pixmap; +} + +scoped_refptr ProtectedBufferManager::ImportDummyFd( + base::ScopedFD dummy_fd, + uint32_t* id) const { + // 0 is an invalid handle id. + *id = 0; + + // Import dummy_fd to acquire its unique id. + // CreateNativePixmapFromHandle() takes ownership and will close the handle + // also on failure. + gfx::NativePixmapHandle pixmap_handle; + pixmap_handle.fds.emplace_back( + base::FileDescriptor(dummy_fd.release(), true)); + pixmap_handle.planes.emplace_back(gfx::NativePixmapPlane()); + ui::OzonePlatform* platform = ui::OzonePlatform::GetInstance(); + ui::SurfaceFactoryOzone* factory = platform->GetSurfaceFactoryOzone(); + scoped_refptr pixmap = + factory->CreateNativePixmapForProtectedBufferHandle( + gfx::kNullAcceleratedWidget, kDummyBufferSize, gfx::BufferFormat::R_8, + pixmap_handle); + if (!pixmap) { + VLOGF(1) << "Failed importing dummy handle"; + return nullptr; + } + + *id = pixmap->GetUniqueId(); + if (*id == 0) { + VLOGF(1) << "Failed acquiring unique id for handle"; + return nullptr; + } + + return pixmap; +} + +void ProtectedBufferManager::RemoveEntry(uint32_t id) { + VLOGF(2) << "id: " << id; + + base::AutoLock lock(buffer_map_lock_); + auto num_erased = buffer_map_.erase(id); + if (num_erased != 1) + VLOGF(1) << "No buffer id " << id << " to destroy"; +} + +} // namespace arc diff --git a/chromium/components/arc/video_accelerator/protected_buffer_manager.h b/chromium/components/arc/video_accelerator/protected_buffer_manager.h new file mode 100644 index 00000000000..ea6b1e23a3f --- /dev/null +++ b/chromium/components/arc/video_accelerator/protected_buffer_manager.h @@ -0,0 +1,143 @@ +// Copyright 2017 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 COMPONENTS_ARC_VIDEO_ACCELERATOR_PROTECTED_BUFFER_MANAGER_H_ +#define COMPONENTS_ARC_VIDEO_ACCELERATOR_PROTECTED_BUFFER_MANAGER_H_ + +#include + +#include "base/memory/ref_counted.h" +#include "base/memory/shared_memory.h" +#include "base/memory/weak_ptr.h" +#include "base/synchronization/lock.h" +#include "ui/gfx/gpu_memory_buffer.h" +#include "ui/gfx/native_pixmap.h" + +namespace arc { + +// A ProtectedBufferHandle is returned to the owning client that requested +// the underlying ProtectedBuffer to be allocated. +// +// A ProtectedBuffer is a buffer that can be referred to via a handle (a dummy +// handle), which does not provide access to the actual contents of the buffer. +// +// The client should release this handle once the buffer is no longer needed. +// Releasing triggers destruction of the ProtectedBuffer instance stored in +// the ProtectedBufferManager, via the destruction callback passed to the +// ProtectedBufferHandle's constructor. +class ProtectedBufferHandle { + public: + // ProtectedBufferHandle takes ownership of the passed |shm_handle|. + ProtectedBufferHandle(base::OnceClosure destruction_cb, + const base::SharedMemoryHandle& shm_handle); + + // ProtectedBufferHandle takes ownership of the passed |native_pixmap_handle|. + ProtectedBufferHandle(base::OnceClosure destruction_cb, + const gfx::NativePixmapHandle& native_pixmap_handle); + + // Closes the underlying handle. + ~ProtectedBufferHandle(); + + // Return a non-owned SharedMemoryHandle or NativePixmapHandle for this + // ProtectedBufferHandle, or an invalid/null handle if not applicable for the + // underlying type. + base::SharedMemoryHandle shm_handle() const; + gfx::NativePixmapHandle native_pixmap_handle() const; + + private: + // The underlying, owning handles to the protected buffer. + // Only one of the handles is valid for each instance of this class. + // Closed on destruction of this ProtectedBufferHandle. + base::SharedMemoryHandle shm_handle_; + gfx::NativePixmapHandle native_pixmap_handle_; + + base::OnceClosure destruction_cb_; +}; + +class ProtectedBufferManager { + public: + ProtectedBufferManager(); + ~ProtectedBufferManager(); + + // Allocate a ProtectedSharedMemory buffer of |size| bytes, to be referred to + // via |dummy_fd| as the dummy handle, returning a ProtectedBufferHandle to + // it. + // Destroying the ProtectedBufferHandle will result in permanently + // disassociating the |dummy_fd| with the underlying ProtectedBuffer, but may + // not free the underlying protected memory, which will remain valid as long + // as any SharedMemoryHandles to it are still in use. + // Return nullptr on failure. + std::unique_ptr AllocateProtectedSharedMemory( + base::ScopedFD dummy_fd, + size_t size); + + // Allocate a ProtectedNativePixmap of |format| and |size|, to be referred to + // via |dummy_fd| as the dummy handle, returning a ProtectedBufferHandle to + // it. + // Destroying the ProtectedBufferHandle will result in permanently + // disassociating the |dummy_fd| with the underlying ProtectedBuffer, but may + // not free the underlying protected memory, which will remain valid as long + // as any NativePixmapHandles to it are still in use. + // Return nullptr on failure. + std::unique_ptr AllocateProtectedNativePixmap( + base::ScopedFD dummy_fd, + gfx::BufferFormat format, + const gfx::Size& size); + + // Return a duplicated SharedMemoryHandle associated with the |dummy_fd|, + // if one exists, or an invalid handle otherwise. + // The client is responsible for closing the handle after use. + base::SharedMemoryHandle GetProtectedSharedMemoryHandleFor( + base::ScopedFD dummy_fd); + + // Return a duplicated NativePixmapHandle associated with the |dummy_fd|, + // if one exists, or an empty handle otherwise. + // The client is responsible for closing the handle after use. + gfx::NativePixmapHandle GetProtectedNativePixmapHandleFor( + base::ScopedFD dummy_fd); + + // Return a protected NativePixmap for a dummy |handle|, if one exists, or + // nullptr otherwise. On success, the |handle| is closed. + scoped_refptr GetProtectedNativePixmapFor( + const gfx::NativePixmapHandle& handle); + + private: + // Used internally to maintain the association between the dummy handle and + // the underlying buffer. + class ProtectedBuffer; + class ProtectedSharedMemory; + class ProtectedNativePixmap; + + // Imports the |dummy_fd| as a NativePixmap. This returns a unique |id|, + // which is guaranteed to be the same for all future imports of any fd + // referring to the buffer to which |dummy_fd| refers to, regardless of + // whether it is the same fd as the original one, or not, for the lifetime + // of the buffer. + // + // This allows us to have an unambiguous mapping from any fd referring to + // the same memory buffer to the same unique id. + // + // Returns nullptr on failure, in which case the returned id is not valid. + scoped_refptr ImportDummyFd(base::ScopedFD dummy_fd, + uint32_t* id) const; + + // Removes an entry for given |id| from buffer_map_, to be called when the + // last reference to the buffer is dropped. + void RemoveEntry(uint32_t id); + + // A map of unique ids to the ProtectedBuffers associated with them. + using ProtectedBufferMap = + std::map>; + ProtectedBufferMap buffer_map_; + base::Lock buffer_map_lock_; + + base::WeakPtr weak_this_; + base::WeakPtrFactory weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(ProtectedBufferManager); +}; + +} // namespace arc + +#endif // COMPONENTS_ARC_VIDEO_ACCELERATOR_PROTECTED_BUFFER_MANAGER_H_ diff --git a/chromium/components/arc/video_accelerator/protected_buffer_manager_proxy.cc b/chromium/components/arc/video_accelerator/protected_buffer_manager_proxy.cc new file mode 100644 index 00000000000..878eefa3ec3 --- /dev/null +++ b/chromium/components/arc/video_accelerator/protected_buffer_manager_proxy.cc @@ -0,0 +1,51 @@ +// Copyright 2017 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 "components/arc/video_accelerator/protected_buffer_manager_proxy.h" + +#include "components/arc/video_accelerator/protected_buffer_manager.h" +#include "mojo/public/cpp/system/platform_handle.h" + +#define VLOGF(level) VLOG(level) << __func__ << "(): " + +namespace arc { + +GpuArcProtectedBufferManagerProxy::GpuArcProtectedBufferManagerProxy( + arc::ProtectedBufferManager* protected_buffer_manager) + : protected_buffer_manager_(protected_buffer_manager) { + DCHECK(protected_buffer_manager_); +} + +base::ScopedFD GpuArcProtectedBufferManagerProxy::UnwrapFdFromMojoHandle( + mojo::ScopedHandle handle) { + base::PlatformFile platform_file; + MojoResult mojo_result = + mojo::UnwrapPlatformFile(std::move(handle), &platform_file); + if (mojo_result != MOJO_RESULT_OK) { + VLOGF(1) << "UnwrapPlatformFile failed: " << mojo_result; + return base::ScopedFD(); + } + + return base::ScopedFD(platform_file); +} + +mojo::ScopedHandle GpuArcProtectedBufferManagerProxy::WrapFdInMojoHandle( + base::ScopedFD fd) { + return mojo::WrapPlatformFile(fd.release()); +} + +void GpuArcProtectedBufferManagerProxy::GetProtectedSharedMemoryFromHandle( + mojo::ScopedHandle dummy_handle, + GetProtectedSharedMemoryFromHandleCallback callback) { + base::ScopedFD unwrapped_fd = UnwrapFdFromMojoHandle(std::move(dummy_handle)); + + base::ScopedFD shmem_fd( + protected_buffer_manager_ + ->GetProtectedSharedMemoryHandleFor(std::move(unwrapped_fd)) + .Release()); + + std::move(callback).Run(WrapFdInMojoHandle(std::move(shmem_fd))); +} + +} // namespace arc diff --git a/chromium/components/arc/video_accelerator/protected_buffer_manager_proxy.h b/chromium/components/arc/video_accelerator/protected_buffer_manager_proxy.h new file mode 100644 index 00000000000..15f77864d14 --- /dev/null +++ b/chromium/components/arc/video_accelerator/protected_buffer_manager_proxy.h @@ -0,0 +1,37 @@ +// Copyright 2017 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 COMPONENTS_ARC_VIDEO_ACCELERATOR_PROTECTED_BUFFER_MANAGER_PROXY_H_ +#define COMPONENTS_ARC_VIDEO_ACCELERATOR_PROTECTED_BUFFER_MANAGER_PROXY_H_ + +#include "components/arc/common/protected_buffer_manager.mojom.h" + +namespace arc { + +class ProtectedBufferManager; + +// Manages mojo IPC translation for arc::ProtectedBufferManager. +class GpuArcProtectedBufferManagerProxy + : public ::arc::mojom::ProtectedBufferManager { + public: + explicit GpuArcProtectedBufferManagerProxy( + arc::ProtectedBufferManager* protected_buffer_manager); + + // arc::mojom::ProtectedBufferManager implementation. + void GetProtectedSharedMemoryFromHandle( + mojo::ScopedHandle dummy_handle, + GetProtectedSharedMemoryFromHandleCallback callback) override; + + private: + base::ScopedFD UnwrapFdFromMojoHandle(mojo::ScopedHandle handle); + mojo::ScopedHandle WrapFdInMojoHandle(base::ScopedFD fd); + + arc::ProtectedBufferManager* protected_buffer_manager_; + + DISALLOW_COPY_AND_ASSIGN(GpuArcProtectedBufferManagerProxy); +}; + +} // namespace arc + +#endif // COMPONENTS_ARC_VIDEO_ACCELERATOR_PROTECTED_BUFFER_MANAGER_PROXY_H_ diff --git a/chromium/components/arc/video_accelerator/video_accelerator.h b/chromium/components/arc/video_accelerator/video_accelerator.h deleted file mode 100644 index 6da58930af8..00000000000 --- a/chromium/components/arc/video_accelerator/video_accelerator.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2016 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 COMPONENTS_ARC_VIDEO_ACCELERATOR_VIDEO_ACCELERATOR_H_ -#define COMPONENTS_ARC_VIDEO_ACCELERATOR_VIDEO_ACCELERATOR_H_ - -namespace arc { - -struct VideoFramePlane { - int32_t offset; // in bytes - int32_t stride; // in bytes -}; - -} // namespace arc - -#endif // COMPONENTS_ARC_VIDEO_ACCELERATOR_VIDEO_ACCELERATOR_H_ diff --git a/chromium/components/arc/video_accelerator/video_accelerator_struct_traits.cc b/chromium/components/arc/video_accelerator/video_accelerator_struct_traits.cc deleted file mode 100644 index 91028274dba..00000000000 --- a/chromium/components/arc/video_accelerator/video_accelerator_struct_traits.cc +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2016 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 "components/arc/video_accelerator/video_accelerator_struct_traits.h" - -namespace mojo { - -// static -bool StructTraits:: - Read(arc::mojom::VideoFramePlaneDataView data, arc::VideoFramePlane* out) { - if (data.offset() < 0 || data.stride() < 0) - return false; - - out->offset = data.offset(); - out->stride = data.stride(); - return true; -} - -// static -bool StructTraits::Read( - arc::mojom::SizeDataView data, - gfx::Size* out) { - if (data.width() < 0 || data.height() < 0) - return false; - - out->SetSize(data.width(), data.height()); - return true; -} -} // namespace mojo diff --git a/chromium/components/arc/video_accelerator/video_accelerator_struct_traits.h b/chromium/components/arc/video_accelerator/video_accelerator_struct_traits.h deleted file mode 100644 index c7e8d3b174a..00000000000 --- a/chromium/components/arc/video_accelerator/video_accelerator_struct_traits.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2016 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 COMPONENTS_ARC_VIDEO_ACCELERATOR_VIDEO_ACCELERATOR_STRUCT_TRAITS_H_ -#define COMPONENTS_ARC_VIDEO_ACCELERATOR_VIDEO_ACCELERATOR_STRUCT_TRAITS_H_ - -#include "components/arc/common/video_decode_accelerator.mojom.h" -#include "components/arc/video_accelerator/video_accelerator.h" -#include "ui/gfx/geometry/size.h" - -namespace mojo { - -template <> -struct StructTraits { - static int32_t offset(const arc::VideoFramePlane& r) { - DCHECK_GE(r.offset, 0); - return r.offset; - } - - static int32_t stride(const arc::VideoFramePlane& r) { - DCHECK_GE(r.stride, 0); - return r.stride; - } - - static bool Read(arc::mojom::VideoFramePlaneDataView data, - arc::VideoFramePlane* out); -}; - -template <> -struct StructTraits { - static int width(const gfx::Size& r) { - DCHECK_GE(r.width(), 0); - return r.width(); - } - - static int height(const gfx::Size& r) { - DCHECK_GE(r.height(), 0); - return r.height(); - } - - static bool Read(arc::mojom::SizeDataView data, gfx::Size* out); -}; -} // namespace mojo - -#endif // COMPONENTS_ARC_VIDEO_ACCELERATOR_VIDEO_ACCELERATOR_STRUCT_TRAITS_H_ diff --git a/chromium/components/arc/video_accelerator/video_encode_accelerator_struct_traits.cc b/chromium/components/arc/video_accelerator/video_encode_accelerator_struct_traits.cc deleted file mode 100644 index 9b3c6456045..00000000000 --- a/chromium/components/arc/video_accelerator/video_encode_accelerator_struct_traits.cc +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2017 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 "components/arc/video_accelerator/video_encode_accelerator_struct_traits.h" - -namespace mojo { - -// Make sure values in arc::mojom::VideoEncodeAccelerator::Error and -// media::VideoEncodeAccelerator::Error match. -#define CHECK_ERROR_ENUM(value) \ - static_assert( \ - static_cast(arc::mojom::VideoEncodeAccelerator::Error::value) == \ - media::VideoEncodeAccelerator::Error::value, \ - "enum ##value mismatch") - -CHECK_ERROR_ENUM(kIllegalStateError); -CHECK_ERROR_ENUM(kInvalidArgumentError); -CHECK_ERROR_ENUM(kPlatformFailureError); -CHECK_ERROR_ENUM(kErrorMax); - -#undef CHECK_ERROR_ENUM - -// static -arc::mojom::VideoEncodeAccelerator::Error -EnumTraits:: - ToMojom(media::VideoEncodeAccelerator::Error input) { - return static_cast(input); -} - -// static -bool EnumTraits:: - FromMojom(arc::mojom::VideoEncodeAccelerator::Error input, - media::VideoEncodeAccelerator::Error* output) { - NOTIMPLEMENTED(); - return false; -} - -// Make sure values in arc::mojom::VideoPixelFormat match to the values in -// media::VideoPixelFormat. The former is a subset of the later. -#define CHECK_PIXEL_FORMAT_ENUM(value) \ - static_assert( \ - static_cast(arc::mojom::VideoPixelFormat::value) == media::value, \ - "enum ##value mismatch") - -CHECK_PIXEL_FORMAT_ENUM(PIXEL_FORMAT_I420); - -#undef CHECK_PXIEL_FORMAT_ENUM - -// static -arc::mojom::VideoPixelFormat -EnumTraits::ToMojom( - media::VideoPixelFormat input) { - NOTIMPLEMENTED(); - return arc::mojom::VideoPixelFormat::PIXEL_FORMAT_I420; -} - -// static -bool EnumTraits:: - FromMojom(arc::mojom::VideoPixelFormat input, - media::VideoPixelFormat* output) { - switch (input) { - case arc::mojom::VideoPixelFormat::PIXEL_FORMAT_I420: - *output = static_cast(input); - return true; - default: - DLOG(ERROR) << "Unknown VideoPixelFormat: " << input; - return false; - } -} - -// Make sure values in arc::mojom::VideoCodecProfile match to the values in -// media::VideoCodecProfile. -#define CHECK_PROFILE_ENUM(value) \ - static_assert( \ - static_cast(arc::mojom::VideoCodecProfile::value) == media::value, \ - "enum ##value mismatch") - -CHECK_PROFILE_ENUM(VIDEO_CODEC_PROFILE_UNKNOWN); -CHECK_PROFILE_ENUM(VIDEO_CODEC_PROFILE_MIN); -CHECK_PROFILE_ENUM(H264PROFILE_MIN); -CHECK_PROFILE_ENUM(H264PROFILE_BASELINE); -CHECK_PROFILE_ENUM(H264PROFILE_MAIN); -CHECK_PROFILE_ENUM(H264PROFILE_EXTENDED); -CHECK_PROFILE_ENUM(H264PROFILE_HIGH); -CHECK_PROFILE_ENUM(H264PROFILE_HIGH10PROFILE); -CHECK_PROFILE_ENUM(H264PROFILE_HIGH422PROFILE); -CHECK_PROFILE_ENUM(H264PROFILE_HIGH444PREDICTIVEPROFILE); -CHECK_PROFILE_ENUM(H264PROFILE_SCALABLEBASELINE); -CHECK_PROFILE_ENUM(H264PROFILE_SCALABLEHIGH); -CHECK_PROFILE_ENUM(H264PROFILE_STEREOHIGH); -CHECK_PROFILE_ENUM(H264PROFILE_MULTIVIEWHIGH); -CHECK_PROFILE_ENUM(H264PROFILE_MAX); -CHECK_PROFILE_ENUM(VP8PROFILE_MIN); -CHECK_PROFILE_ENUM(VP8PROFILE_ANY); -CHECK_PROFILE_ENUM(VP8PROFILE_MAX); -CHECK_PROFILE_ENUM(VP9PROFILE_MIN); -CHECK_PROFILE_ENUM(VP9PROFILE_PROFILE0); -CHECK_PROFILE_ENUM(VP9PROFILE_PROFILE1); -CHECK_PROFILE_ENUM(VP9PROFILE_PROFILE2); -CHECK_PROFILE_ENUM(VP9PROFILE_PROFILE3); -CHECK_PROFILE_ENUM(VP9PROFILE_MAX); -CHECK_PROFILE_ENUM(HEVCPROFILE_MIN); -CHECK_PROFILE_ENUM(HEVCPROFILE_MAIN); -CHECK_PROFILE_ENUM(HEVCPROFILE_MAIN10); -CHECK_PROFILE_ENUM(HEVCPROFILE_MAIN_STILL_PICTURE); -CHECK_PROFILE_ENUM(HEVCPROFILE_MAX); -CHECK_PROFILE_ENUM(DOLBYVISION_MIN); -CHECK_PROFILE_ENUM(DOLBYVISION_PROFILE0); -CHECK_PROFILE_ENUM(DOLBYVISION_PROFILE4); -CHECK_PROFILE_ENUM(DOLBYVISION_PROFILE5); -CHECK_PROFILE_ENUM(DOLBYVISION_PROFILE7); -CHECK_PROFILE_ENUM(DOLBYVISION_MAX); -CHECK_PROFILE_ENUM(THEORAPROFILE_MIN); -CHECK_PROFILE_ENUM(THEORAPROFILE_ANY); -CHECK_PROFILE_ENUM(THEORAPROFILE_MAX); -CHECK_PROFILE_ENUM(VIDEO_CODEC_PROFILE_MAX); - -#undef CHECK_PROFILE_ENUM - -// static -arc::mojom::VideoCodecProfile -EnumTraits::ToMojom( - media::VideoCodecProfile input) { - return static_cast(input); -} - -// static -bool EnumTraits:: - FromMojom(arc::mojom::VideoCodecProfile input, - media::VideoCodecProfile* output) { - switch (input) { - case arc::mojom::VideoCodecProfile::VIDEO_CODEC_PROFILE_UNKNOWN: - case arc::mojom::VideoCodecProfile::H264PROFILE_BASELINE: - case arc::mojom::VideoCodecProfile::H264PROFILE_MAIN: - case arc::mojom::VideoCodecProfile::H264PROFILE_EXTENDED: - case arc::mojom::VideoCodecProfile::H264PROFILE_HIGH: - case arc::mojom::VideoCodecProfile::H264PROFILE_HIGH10PROFILE: - case arc::mojom::VideoCodecProfile::H264PROFILE_HIGH422PROFILE: - case arc::mojom::VideoCodecProfile::H264PROFILE_HIGH444PREDICTIVEPROFILE: - case arc::mojom::VideoCodecProfile::H264PROFILE_SCALABLEBASELINE: - case arc::mojom::VideoCodecProfile::H264PROFILE_SCALABLEHIGH: - case arc::mojom::VideoCodecProfile::H264PROFILE_STEREOHIGH: - case arc::mojom::VideoCodecProfile::H264PROFILE_MULTIVIEWHIGH: - case arc::mojom::VideoCodecProfile::VP8PROFILE_ANY: - case arc::mojom::VideoCodecProfile::VP9PROFILE_PROFILE0: - case arc::mojom::VideoCodecProfile::VP9PROFILE_PROFILE1: - case arc::mojom::VideoCodecProfile::VP9PROFILE_PROFILE2: - case arc::mojom::VideoCodecProfile::VP9PROFILE_PROFILE3: - case arc::mojom::VideoCodecProfile::HEVCPROFILE_MAIN: - case arc::mojom::VideoCodecProfile::HEVCPROFILE_MAIN10: - case arc::mojom::VideoCodecProfile::HEVCPROFILE_MAIN_STILL_PICTURE: - case arc::mojom::VideoCodecProfile::DOLBYVISION_PROFILE0: - case arc::mojom::VideoCodecProfile::DOLBYVISION_PROFILE4: - case arc::mojom::VideoCodecProfile::DOLBYVISION_PROFILE5: - case arc::mojom::VideoCodecProfile::DOLBYVISION_PROFILE7: - case arc::mojom::VideoCodecProfile::THEORAPROFILE_ANY: - *output = static_cast(input); - return true; - } - DLOG(ERROR) << "unknown profile: " << input; - return false; -} - -} // namespace mojo diff --git a/chromium/components/arc/video_accelerator/video_encode_accelerator_struct_traits.h b/chromium/components/arc/video_accelerator/video_encode_accelerator_struct_traits.h deleted file mode 100644 index c3b39e1f371..00000000000 --- a/chromium/components/arc/video_accelerator/video_encode_accelerator_struct_traits.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2017 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 COMPONENTS_ARC_VIDEO_ACCELERATOR_VIDEO_ENCODE_ACCELERATOR_STRUCT_TRAITS_H_ -#define COMPONENTS_ARC_VIDEO_ACCELERATOR_VIDEO_ENCODE_ACCELERATOR_STRUCT_TRAITS_H_ - -#include "components/arc/common/video_encode_accelerator.mojom.h" -#include "media/video/video_encode_accelerator.h" - -namespace mojo { - -template <> -struct EnumTraits { - static arc::mojom::VideoEncodeAccelerator::Error ToMojom( - media::VideoEncodeAccelerator::Error input); - - static bool FromMojom(arc::mojom::VideoEncodeAccelerator::Error input, - media::VideoEncodeAccelerator::Error* output); -}; - -template <> -struct EnumTraits { - static arc::mojom::VideoPixelFormat ToMojom(media::VideoPixelFormat input); - - static bool FromMojom(arc::mojom::VideoPixelFormat input, - media::VideoPixelFormat* output); -}; - -template <> -struct EnumTraits { - static arc::mojom::VideoCodecProfile ToMojom(media::VideoCodecProfile input); - - static bool FromMojom(arc::mojom::VideoCodecProfile input, - media::VideoCodecProfile* output); -}; - -template <> -struct StructTraits { - static media::VideoCodecProfile profile( - const media::VideoEncodeAccelerator::SupportedProfile& r) { - return r.profile; - } - static const gfx::Size& max_resolution( - const media::VideoEncodeAccelerator::SupportedProfile& r) { - return r.max_resolution; - } - static uint32_t max_framerate_numerator( - const media::VideoEncodeAccelerator::SupportedProfile& r) { - return r.max_framerate_numerator; - } - static uint32_t max_framerate_denominator( - const media::VideoEncodeAccelerator::SupportedProfile& r) { - return r.max_framerate_denominator; - } - - static bool Read(arc::mojom::VideoEncodeProfileDataView data, - media::VideoEncodeAccelerator::SupportedProfile* out) { - NOTIMPLEMENTED(); - return false; - } -}; - -} // namespace mojo - -#endif // COMPONENTS_ARC_VIDEO_ACCELERATOR_VIDEO_ENCODE_ACCELERATOR_STRUCT_TRAITS_H_ diff --git a/chromium/components/arc/video_accelerator/video_frame_plane.h b/chromium/components/arc/video_accelerator/video_frame_plane.h new file mode 100644 index 00000000000..2b45a6176b2 --- /dev/null +++ b/chromium/components/arc/video_accelerator/video_frame_plane.h @@ -0,0 +1,19 @@ +// Copyright 2016 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 COMPONENTS_ARC_VIDEO_ACCELERATOR_VIDEO_FRAME_PLANE_H_ +#define COMPONENTS_ARC_VIDEO_ACCELERATOR_VIDEO_FRAME_PLANE_H_ + +#include + +namespace arc { + +struct VideoFramePlane { + int32_t offset; // in bytes + int32_t stride; // in bytes +}; + +} // namespace arc + +#endif // COMPONENTS_ARC_VIDEO_ACCELERATOR_VIDEO_FRAME_PLANE_H_ diff --git a/chromium/components/arc/voice_interaction/OWNERS b/chromium/components/arc/voice_interaction/OWNERS deleted file mode 100644 index ef5cf841917..00000000000 --- a/chromium/components/arc/voice_interaction/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -per-file *_struct_traits*.*=set noparent -per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS -per-file *_struct_traits*.*=file://components/arc/common/ARC_SECURITY_OWNERS diff --git a/chromium/components/arc/voice_interaction/voice_interaction_struct_traits.h b/chromium/components/arc/voice_interaction/voice_interaction_struct_traits.h deleted file mode 100644 index c519f967b29..00000000000 --- a/chromium/components/arc/voice_interaction/voice_interaction_struct_traits.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2017 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 COMPONENTS_ARC_VOICE_INTERACTION_VOICE_INTERACTION_STRUCT_TRAITS_H_ -#define COMPONENTS_ARC_VOICE_INTERACTION_VOICE_INTERACTION_STRUCT_TRAITS_H_ - -#include "ash/public/cpp/voice_interaction_state.h" -#include "components/arc/common/voice_interaction_framework.mojom.h" - -namespace mojo { - -template <> -struct EnumTraits { - static arc::mojom::VoiceInteractionState ToMojom( - ash::VoiceInteractionState state) { - switch (state) { - case ash::VoiceInteractionState::NOT_READY: - return arc::mojom::VoiceInteractionState::NOT_READY; - case ash::VoiceInteractionState::STOPPED: - return arc::mojom::VoiceInteractionState::STOPPED; - case ash::VoiceInteractionState::RUNNING: - return arc::mojom::VoiceInteractionState::RUNNING; - } - - NOTREACHED() << "Invalid state: " << static_cast(state); - return arc::mojom::VoiceInteractionState::NOT_READY; - } - - static bool FromMojom(arc::mojom::VoiceInteractionState mojom_state, - ash::VoiceInteractionState* state) { - switch (mojom_state) { - case arc::mojom::VoiceInteractionState::NOT_READY: - *state = ash::VoiceInteractionState::NOT_READY; - return true; - case arc::mojom::VoiceInteractionState::STOPPED: - *state = ash::VoiceInteractionState::STOPPED; - return true; - case arc::mojom::VoiceInteractionState::RUNNING: - *state = ash::VoiceInteractionState::RUNNING; - return true; - } - - NOTREACHED() << "Invalid state: " << static_cast(mojom_state); - *state = ash::VoiceInteractionState::NOT_READY; - return false; - } -}; - -} // namespace mojo - -#endif // COMPONENTS_ARC_VOICE_INTERACTION_VOICE_INTERACTION_STRUCT_TRAITS_H_ diff --git a/chromium/components/arc/volume_mounter/arc_volume_mounter_bridge.cc b/chromium/components/arc/volume_mounter/arc_volume_mounter_bridge.cc index ce6107a218e..9412567835a 100644 --- a/chromium/components/arc/volume_mounter/arc_volume_mounter_bridge.cc +++ b/chromium/components/arc/volume_mounter/arc_volume_mounter_bridge.cc @@ -67,7 +67,7 @@ ArcVolumeMounterBridge::~ArcVolumeMounterBridge() { arc_bridge_service_->volume_mounter()->RemoveObserver(this); } -void ArcVolumeMounterBridge::OnInstanceReady() { +void ArcVolumeMounterBridge::OnConnectionReady() { base::PostTaskWithTraits(FROM_HERE, {base::TaskPriority::USER_BLOCKING, base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, diff --git a/chromium/components/arc/volume_mounter/arc_volume_mounter_bridge.h b/chromium/components/arc/volume_mounter/arc_volume_mounter_bridge.h index 2e54fe6f61e..af51cf38d9e 100644 --- a/chromium/components/arc/volume_mounter/arc_volume_mounter_bridge.h +++ b/chromium/components/arc/volume_mounter/arc_volume_mounter_bridge.h @@ -10,7 +10,7 @@ #include "base/macros.h" #include "chromeos/disks/disk_mount_manager.h" #include "components/arc/common/volume_mounter.mojom.h" -#include "components/arc/instance_holder.h" +#include "components/arc/connection_observer.h" #include "components/keyed_service/core/keyed_service.h" #include "mojo/public/cpp/bindings/binding.h" @@ -27,7 +27,7 @@ class ArcBridgeService; class ArcVolumeMounterBridge : public KeyedService, public chromeos::disks::DiskMountManager::Observer, - public InstanceHolder::Observer { + public ConnectionObserver { public: // Returns singleton instance for the given BrowserContext, // or nullptr if the browser |context| is not allowed to use ARC. @@ -38,8 +38,8 @@ class ArcVolumeMounterBridge ArcBridgeService* bridge_service); ~ArcVolumeMounterBridge() override; - // InstanceHolder::Observer overrides: - void OnInstanceReady() override; + // ConnectionObserver overrides: + void OnConnectionReady() override; // chromeos::disks::DiskMountManager::Observer overrides: void OnDiskEvent( -- cgit v1.2.1