chromium/chrome/browser/lacros/chrome_browser_main_extra_parts_lacros.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/lacros/chrome_browser_main_extra_parts_lacros.h"

#include <memory>

#include "base/check_is_test.h"
#include "base/feature_list.h"
#include "base/unguessable_token.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_platform_part.h"
#include "chrome/browser/chromeos/launcher_search/search_util.h"
#include "chrome/browser/chromeos/mahi/mahi_web_contents_manager.h"
#include "chrome/browser/chromeos/printing/print_preview/print_preview_webcontents_manager.h"
#include "chrome/browser/chromeos/reporting/metric_reporting_manager_lacros_factory.h"
#include "chrome/browser/chromeos/smart_reader/smart_reader_client_impl.h"
#include "chrome/browser/chromeos/tablet_mode/tablet_mode_page_behavior.h"
#include "chrome/browser/chromeos/video_conference/video_conference_manager_client.h"
#include "chrome/browser/lacros/app_mode/chrome_kiosk_launch_controller_lacros.h"
#include "chrome/browser/lacros/app_mode/device_local_account_extension_installer_lacros.h"
#include "chrome/browser/lacros/app_mode/kiosk_session_service_lacros.h"
#include "chrome/browser/lacros/app_mode/web_kiosk_installer_lacros.h"
#include "chrome/browser/lacros/arc/arc_icon_cache.h"
#include "chrome/browser/lacros/automation_manager_lacros.h"
#include "chrome/browser/lacros/browser_service_lacros.h"
#include "chrome/browser/lacros/clipboard_history_lacros.h"
#include "chrome/browser/lacros/cloud_file_system_path_cache.h"
#include "chrome/browser/lacros/debug_interface_lacros.h"
#include "chrome/browser/lacros/desk_profiles_lacros.h"
#include "chrome/browser/lacros/desk_template_client_lacros.h"
#include "chrome/browser/lacros/download_controller_client_lacros.h"
#include "chrome/browser/lacros/drivefs_native_message_host_bridge_lacros.h"
#include "chrome/browser/lacros/embedded_a11y_manager_lacros.h"
#include "chrome/browser/lacros/field_trial_observer.h"
#include "chrome/browser/lacros/force_installed_tracker_lacros.h"
#include "chrome/browser/lacros/full_restore_client_lacros.h"
#include "chrome/browser/lacros/fullscreen_controller_client_lacros.h"
#include "chrome/browser/lacros/geolocation/system_geolocation_source_lacros.h"
#include "chrome/browser/lacros/guest_os/vm_sk_forwarding_service.h"
#include "chrome/browser/lacros/lacros_apps_publisher.h"
#include "chrome/browser/lacros/lacros_extension_apps_controller.h"
#include "chrome/browser/lacros/lacros_extension_apps_publisher.h"
#include "chrome/browser/lacros/lacros_file_system_provider.h"
#include "chrome/browser/lacros/lacros_memory_pressure_evaluator.h"
#include "chrome/browser/lacros/launcher_search/search_controller_factory_lacros.h"
#include "chrome/browser/lacros/launcher_search/search_controller_lacros.h"
#include "chrome/browser/lacros/media_app_lacros.h"
#include "chrome/browser/lacros/multitask_menu_nudge_delegate_lacros.h"
#include "chrome/browser/lacros/net/network_change_manager_bridge.h"
#include "chrome/browser/lacros/net/network_settings_observer.h"
#include "chrome/browser/lacros/screen_orientation_delegate_lacros.h"
#include "chrome/browser/lacros/suggestion_service_lacros.h"
#include "chrome/browser/lacros/sync/sync_crosapi_manager_lacros.h"
#include "chrome/browser/lacros/task_manager_lacros.h"
#include "chrome/browser/lacros/views_text_services_context_menu_lacros.h"
#include "chrome/browser/lacros/vpn_extension_tracker_lacros.h"
#include "chrome/browser/lacros/web_app_provider_bridge_lacros.h"
#include "chrome/browser/lacros/web_page_info_lacros.h"
#include "chrome/browser/lacros/webauthn_request_registrar_lacros.h"
#include "chrome/browser/memory/oom_kills_monitor.h"
#include "chrome/browser/metrics/structured/chrome_structured_metrics_delegate.h"
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/ui/chromeos/read_write_cards/read_write_cards_manager_impl.h"
#include "chrome/common/chrome_features.h"
#include "chromeos/components/kiosk/kiosk_utils.h"
#include "chromeos/constants/chromeos_features.h"
#include "chromeos/crosapi/mojom/crosapi.mojom.h"
#include "chromeos/crosapi/mojom/mahi.mojom.h"
#include "chromeos/crosapi/mojom/print_preview_cros.mojom.h"
#include "chromeos/lacros/lacros_service.h"
#include "chromeos/startup/browser_params_proxy.h"
#include "chromeos/ui/clipboard_history/clipboard_history_util.h"
#include "components/arc/common/intent_helper/arc_icon_cache_delegate.h"
#include "components/nacl/common/buildflags.h"
#include "components/policy/core/common/policy_pref_names.h"
#include "extensions/common/features/feature_session_type.h"
#include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h"
#include "ui/views/controls/views_text_services_context_menu_chromeos.h"

#if BUILDFLAG(ENABLE_NACL)
#include "base/base_paths.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "chrome/common/chrome_paths.h"
#include "chromeos/lacros/lacros_paths.h"
#endif  // BUILDFLAG(ENABLE_NACL)

namespace {

// Creates a `crosapi::ClipboardHistoryLacros` instance. This function should
// only be called if the clipboard history refresh is enabled.
std::unique_ptr<crosapi::ClipboardHistoryLacros>
CreateClipboardHistoryLacros() {
  CHECK(chromeos::features::IsClipboardHistoryRefreshEnabled());

  if (chromeos::LacrosService* const service = chromeos::LacrosService::Get();
      service->IsAvailable<crosapi::mojom::ClipboardHistory>() &&
      service->GetInterfaceVersion<crosapi::mojom::ClipboardHistory>() >=
          int{crosapi::mojom::ClipboardHistory::MethodMinVersions::
                  kRegisterClientMinVersion}) {
    return std::make_unique<crosapi::ClipboardHistoryLacros>(
        service->GetRemote<crosapi::mojom::ClipboardHistory>().get());
  }

  return nullptr;
}

bool IsFloatingWorkspaceV2Enabled() {
  PrefService* pref_service =
      ProfileManager::GetPrimaryUserProfile()->GetPrefs();
  if (!pref_service) {
    return false;
  }
  const PrefService::Preference* floating_workspace_pref =
      pref_service->FindPreference(
          policy::policy_prefs::kFloatingWorkspaceEnabled);

  return (floating_workspace_pref && floating_workspace_pref->IsManaged() &&
          pref_service->GetBoolean(
              policy::policy_prefs::kFloatingWorkspaceEnabled));
}

std::unique_ptr<crosapi::DeskProfilesLacros> CreateDeskProfilesLacros() {
  CHECK(chromeos::features::IsDeskProfilesEnabled() ||
        IsFloatingWorkspaceV2Enabled());
  if (chromeos::LacrosService* const service = chromeos::LacrosService::Get();
      service->IsAvailable<crosapi::mojom::DeskProfileObserver>() &&
      g_browser_process) {
    return std::make_unique<crosapi::DeskProfilesLacros>(
        g_browser_process->profile_manager(),
        service->GetRemote<crosapi::mojom::DeskProfileObserver>().get());
  }

  return nullptr;
}

extensions::mojom::FeatureSessionType GetExtSessionType() {
  using extensions::mojom::FeatureSessionType;

  if (chromeos::IsKioskSession()) {
    return FeatureSessionType::kKiosk;
  }

  if (profiles::SessionHasGaiaAccount()) {
    return FeatureSessionType::kRegular;
  }

  // TODO: how to implement IsKioskAutolaunchedSession in Lacros
  // http://b/227564794
  return FeatureSessionType::kUnknown;
}

bool IsSessionTypeDeviceLocalAccountSession(
    crosapi::mojom::SessionType session_type) {
  using crosapi::mojom::SessionType;

  return session_type == SessionType::kAppKioskSession ||
         session_type == crosapi::mojom::SessionType::kWebKioskSession ||
         session_type == crosapi::mojom::SessionType::kPublicSession;
}

}  // namespace

ChromeBrowserMainExtraPartsLacros::ChromeBrowserMainExtraPartsLacros() =
    default;
ChromeBrowserMainExtraPartsLacros::~ChromeBrowserMainExtraPartsLacros() =
    default;

void ChromeBrowserMainExtraPartsLacros::PreProfileInit() {
#if BUILDFLAG(ENABLE_EXTENSIONS)
  extensions::SetCurrentFeatureSessionType(GetExtSessionType());
#endif  // BUILDFLAG(ENABLE_EXTENSIONS)
  tablet_mode_page_behavior_ = std::make_unique<TabletModePageBehavior>();

  if (IsSessionTypeDeviceLocalAccountSession(
          chromeos::BrowserParamsProxy::Get()->SessionType())) {
    device_local_account_extension_installer_ =
        std::make_unique<DeviceLocalAccountExtensionInstallerLacros>();
  }

  DCHECK(!device::GeolocationSystemPermissionManager::GetInstance());
  device::GeolocationSystemPermissionManager::SetInstance(
      SystemGeolocationSourceLacros::
          CreateGeolocationSystemPermissionManagerOnLacros());

#if BUILDFLAG(ENABLE_NACL)
  // Ash ships PNaCl as part of rootfs, but Lacros doesn't ship it at all.
  // Since the required binaries are guaranteed to be the same, even on
  // different Chrome versions (since 2016), just use the PNaCl binaries shipped
  // with Ash.
  base::FilePath ash_resources_dir;
  if (!base::PathService::Get(chromeos::lacros_paths::ASH_RESOURCES_DIR,
                              &ash_resources_dir)) {
    LOG(WARNING) << "Could not find Ash PNaCl - PNaCl may be unavailable";
    CHECK_IS_TEST();
  } else {
    base::FilePath ash_pnacl =
        ash_resources_dir.Append(FILE_PATH_LITERAL("pnacl"));
    base::PathService::Override(chrome::DIR_PNACL_COMPONENT, ash_pnacl);
  }
#endif  // BUILDFLAG(ENABLE_NACL)
}

void ChromeBrowserMainExtraPartsLacros::PostBrowserStart() {
  automation_manager_ = std::make_unique<AutomationManagerLacros>();
  browser_service_ = std::make_unique<BrowserServiceLacros>();
  debug_interface_ = std::make_unique<crosapi::DebugInterfaceLacros>();
  desk_template_client_ = std::make_unique<DeskTemplateClientLacros>();
  if (chromeos::features::IsDeskProfilesEnabled() ||
      IsFloatingWorkspaceV2Enabled()) {
    desk_profiles_lacros_ = CreateDeskProfilesLacros();
  }
  drivefs_native_message_host_bridge_ =
      std::make_unique<drive::DriveFsNativeMessageHostBridge>();
  download_controller_client_ =
      std::make_unique<DownloadControllerClientLacros>();
  file_system_provider_ = std::make_unique<LacrosFileSystemProvider>();
  full_restore_client_ = std::make_unique<FullRestoreClientLacros>();
  fullscreen_controller_client_ =
      std::make_unique<FullscreenControllerClientLacros>();
  kiosk_session_service_ = std::make_unique<KioskSessionServiceLacros>();
  media_app_ = std::make_unique<crosapi::MediaAppLacros>();
  network_change_manager_bridge_ =
      std::make_unique<NetworkChangeManagerBridge>();
  screen_orientation_delegate_ =
      std::make_unique<ScreenOrientationDelegateLacros>();
  search_controller_ = std::make_unique<crosapi::SearchControllerLacros>(
      crosapi::ProviderTypes());
  search_controller_->RegisterWithAsh();
  search_controller_factory_ =
      std::make_unique<crosapi::SearchControllerFactoryLacros>();
  task_manager_provider_ = std::make_unique<crosapi::TaskManagerLacros>();
  web_page_info_provider_ =
      std::make_unique<crosapi::WebPageInfoProviderLacros>();
  if (chromeos::features::IsClipboardHistoryRefreshEnabled()) {
    clipboard_history_lacros_ = CreateClipboardHistoryLacros();
  }
  vm_sk_forwarding_service_ =
      std::make_unique<guest_os::VmSkForwardingService>();

  memory_pressure::MultiSourceMemoryPressureMonitor* monitor =
      static_cast<memory_pressure::MultiSourceMemoryPressureMonitor*>(
          base::MemoryPressureMonitor::Get());
  if (monitor) {
    monitor->SetSystemEvaluator(std::make_unique<LacrosMemoryPressureEvaluator>(
        monitor->CreateVoter()));
  }

  lacros_apps_publisher_ = std::make_unique<LacrosAppsPublisher>();
  lacros_apps_publisher_->Initialize();

  if (chromeos::BrowserParamsProxy::Get()->PublishChromeApps()) {
    chrome_apps_publisher_ = LacrosExtensionAppsPublisher::MakeForChromeApps();
    chrome_apps_publisher_->Initialize();
    chrome_apps_controller_ =
        LacrosExtensionAppsController::MakeForChromeApps();
    chrome_apps_controller_->Initialize(chrome_apps_publisher_->publisher());
    chrome_apps_controller_->SetPublisher(chrome_apps_publisher_.get());

    extensions_publisher_ = LacrosExtensionAppsPublisher::MakeForExtensions();
    extensions_publisher_->Initialize();
    extensions_controller_ = LacrosExtensionAppsController::MakeForExtensions();
    extensions_controller_->Initialize(extensions_publisher_->publisher());
  }

  web_app_provider_bridge_ =
      std::make_unique<crosapi::WebAppProviderBridgeLacros>();

  EmbeddedA11yManagerLacros::GetInstance()->Init();

  // Construct ArcIconCache and set it to provider.
  arc_icon_cache_ = std::make_unique<ArcIconCache>();
  arc_icon_cache_->Start();
  arc_icon_cache_delegate_provider_ =
      std::make_unique<arc::ArcIconCacheDelegateProvider>(
          arc_icon_cache_.get());

  // Start Lacros' cloud file systems mount points paths caching, since they are
  // available in Ash.
  cloud_file_system_cache_ = std::make_unique<CloudFileSystemPathCache>();
  // After construction finishes, start caching.
  cloud_file_system_cache_->Start();

  field_trial_observer_ = std::make_unique<FieldTrialObserver>();
  field_trial_observer_->Start();

  force_installed_tracker_ = std::make_unique<ForceInstalledTrackerLacros>();
  force_installed_tracker_->Start();

  vpn_extension_tracker_ = std::make_unique<VpnExtensionTrackerLacros>();
  vpn_extension_tracker_->Start();

  webauthn_request_registrar_lacros_ =
      std::make_unique<WebAuthnRequestRegistrarLacros>();

  metrics::structured::ChromeStructuredMetricsDelegate::Get()->Initialize();

  if (g_browser_process != nullptr &&
      g_browser_process->local_state() != nullptr) {
    ::memory::OOMKillsMonitor::GetInstance().Initialize(
        g_browser_process->local_state());
  }

  if (chromeos::BrowserParamsProxy::Get()->VcControlsUiEnabled() &&
      chromeos::LacrosService::Get()
          ->IsAvailable<crosapi::mojom::VideoConferenceManager>()) {
    video_conference_manager_client_ =
        std::make_unique<video_conference::VideoConferenceManagerClientImpl>();
  }

  smart_reader_client_ =
      std::make_unique<smart_reader::SmartReaderClientImpl>();

  multitask_menu_nudge_delegate_ =
      std::make_unique<MultitaskMenuNudgeDelegateLacros>();

  if (chromeos::features::IsMahiEnabled() &&
      chromeos::LacrosService::Get()
          ->IsAvailable<crosapi::mojom::MahiBrowserDelegate>()) {
    mahi::MahiWebContentsManager::Get()->Initialize();
  }

  if (base::FeatureList::IsEnabled(::features::kPrintPreviewCrosPrimary) &&
      chromeos::LacrosService::Get()
          ->IsAvailable<crosapi::mojom::PrintPreviewCrosDelegate>()) {
    chromeos::PrintPreviewWebcontentsManager::Get()->Initialize();
  }
  suggestion_service_ = std::make_unique<SuggestionServiceLacros>();
}

void ChromeBrowserMainExtraPartsLacros::PostProfileInit(
    Profile* profile,
    bool is_initial_profile) {
  sync_crosapi_manager_.PostProfileInit(profile);

  // The setup below is intended to run for only the initial profile.
  if (!is_initial_profile) {
    return;
  }

  // Needs to be initialized before `read_write_cards_manager_`. This is because
  // `QuickAnswersState` needs `MagicBoostState` to be initialized before it is
  // constructed.
  magic_boost_state_lacros_ =
      std::make_unique<chromeos::MagicBoostStateLacros>();

  read_write_cards_manager_ =
      std::make_unique<chromeos::ReadWriteCardsManagerImpl>();

  // Initialize the metric reporting manager so we can start recording relevant
  // telemetry metrics and events on managed devices. The reporting manager
  // checks for profile affiliation, so we do not need any additional checks
  // here.
  ::reporting::metrics::MetricReportingManagerLacrosFactory::GetForProfile(
      profile);

  if (chromeos::BrowserParamsProxy::Get()->SessionType() ==
      crosapi::mojom::SessionType::kAppKioskSession) {
    chrome_kiosk_launch_controller_ =
        std::make_unique<ChromeKioskLaunchControllerLacros>(*profile);
  }
  if (chromeos::BrowserParamsProxy::Get()->SessionType() ==
      crosapi::mojom::SessionType::kWebKioskSession) {
    web_kiosk_installer_ = std::make_unique<WebKioskInstallerLacros>(*profile);
  }

  views::ViewsTextServicesContextMenuChromeos::SetImplFactory(
      base::BindRepeating(
          [](ui::SimpleMenuModel* menu_model, views::Textfield* textfield)
              -> std::unique_ptr<views::ViewsTextServicesContextMenu> {
            return std::make_unique<
                crosapi::ViewsTextServicesContextMenuLacros>(menu_model,
                                                             textfield);
          }));

  // Sets the implementation of clipboard history utility functions.
  if (chromeos::features::IsClipboardHistoryRefreshEnabled()) {
    chromeos::clipboard_history::SetQueryItemDescriptorsImpl(
        base::BindRepeating([]() {
          if (const crosapi::ClipboardHistoryLacros* const
                  clipboard_history_lacros =
                      crosapi::ClipboardHistoryLacros::Get()) {
            return clipboard_history_lacros->cached_descriptors();
          }

          return chromeos::clipboard_history::QueryItemDescriptorsImpl::
              ResultType();
        }));

    chromeos::clipboard_history::SetPasteClipboardItemByIdImpl(
        base::BindRepeating(
            [](const base::UnguessableToken& id, int event_flags,
               crosapi::mojom::ClipboardHistoryControllerShowSource source) {
              if (auto* lacros_service = chromeos::LacrosService::Get();
                  lacros_service &&
                  lacros_service
                      ->IsAvailable<crosapi::mojom::ClipboardHistory>() &&
                  lacros_service->GetInterfaceVersion<
                      crosapi::mojom::ClipboardHistory>() >=
                      int{crosapi::mojom::ClipboardHistory::MethodMinVersions::
                              kPasteClipboardItemByIdMinVersion}) {
                lacros_service->GetRemote<crosapi::mojom::ClipboardHistory>()
                    ->PasteClipboardItemById(id, event_flags, source);
              }
            }));
  }
  network_settings_observer_ =
      std::make_unique<NetworkSettingsObserver>(profile);
  network_settings_observer_->Start();
}

void ChromeBrowserMainExtraPartsLacros::PostMainMessageLoopRun() {
  // Must be destroyed before `chrome_kiosk_launch_controller_->profile_` is
  // destroyed.
  chrome_kiosk_launch_controller_.reset();
  web_kiosk_installer_.reset();
  // Must be destroyed before
  // `kiosk_session_service_->kiosk_browser_session_->profile_` is destroyed.
  kiosk_session_service_.reset();
  // Must be destroyed before the extension system gets destroyed.
  force_installed_tracker_.reset();

  // Initialized in PreProfileInit.
  device::GeolocationSystemPermissionManager::SetInstance(nullptr);
}