blob: 54eee6249e196c9a9a2c179552eb38a015cae09a [file] [log] [blame]
// Copyright 2024 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/sync/chrome_sync_controller_builder.h"
#include <memory>
#include <utility>
#include <vector>
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "build/build_config.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/security_events/security_event_recorder.h"
#include "chrome/browser/spellchecker/spellcheck_service.h"
#include "chrome/browser/themes/theme_local_data_batch_uploader.h"
#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/themes/theme_syncable_service.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/common/buildflags.h"
#include "chrome/common/channel_info.h"
#include "components/desks_storage/core/desk_sync_service.h"
#include "components/spellcheck/spellcheck_buildflags.h"
#include "components/sync/base/data_type.h"
#include "components/sync/base/features.h"
#include "components/sync/base/pref_names.h"
#include "components/sync/base/report_unrecoverable_error.h"
#include "components/sync/model/data_type_controller_delegate.h"
#include "components/sync/model/data_type_store.h"
#include "components/sync/model/data_type_store_service.h"
#include "components/sync/model/forwarding_data_type_controller_delegate.h"
#include "components/sync/service/data_type_controller.h"
#include "components/sync/service/syncable_service_based_data_type_controller.h"
#include "content/public/browser/browser_thread.h"
#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
#include "chrome/browser/extensions/api/storage/settings_sync_util.h" // nogncheck
#include "chrome/browser/extensions/sync/extension_sync_service.h" // nogncheck
#include "chrome/browser/sync/glue/extension_data_type_controller.h"
#include "chrome/browser/sync/glue/extension_setting_data_type_controller.h"
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_sync_bridge.h"
#include "chrome/browser/web_applications/web_app_utils.h"
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(IS_CHROMEOS)
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_switches.h"
#include "chrome/browser/ash/app_list/app_list_syncable_service.h"
#include "chrome/browser/ash/app_list/arc/arc_package_sync_data_type_controller.h"
#include "chrome/browser/ash/app_list/arc/arc_package_syncable_service.h"
#include "chrome/browser/ash/arc/arc_util.h"
#include "chrome/browser/ash/floating_sso/cookie_sync_data_type_controller.h"
#include "chrome/browser/ash/floating_sso/floating_sso_service.h"
#include "chrome/browser/ash/printing/oauth2/authorization_zones_manager.h"
#include "chrome/browser/ash/printing/printers_sync_bridge.h"
#include "chrome/browser/ash/printing/synced_printers_manager.h"
#include "chromeos/ash/components/sync_wifi/wifi_configuration_sync_service.h"
#include "chromeos/ash/experiences/arc/arc_util.h"
#include "components/sync_preferences/pref_service_syncable.h"
#endif // BUILDFLAG(IS_CHROMEOS)
#if BUILDFLAG(IS_ANDROID)
#include "chrome/browser/android/webapk/webapk_sync_service.h"
#endif // BUILDFLAG(IS_ANDROID)
ChromeSyncControllerBuilder::ChromeSyncControllerBuilder() = default;
ChromeSyncControllerBuilder::~ChromeSyncControllerBuilder() = default;
void ChromeSyncControllerBuilder::SetDataTypeStoreService(
syncer::DataTypeStoreService* data_type_store_service) {
data_type_store_service_.Set(data_type_store_service);
}
void ChromeSyncControllerBuilder::SetSecurityEventRecorder(
SecurityEventRecorder* security_event_recorder) {
security_event_recorder_.Set(security_event_recorder);
}
#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
void ChromeSyncControllerBuilder::SetExtensionSyncService(
ExtensionSyncService* extension_sync_service) {
extension_sync_service_.Set(extension_sync_service);
}
void ChromeSyncControllerBuilder::SetExtensionSystemProfile(Profile* profile) {
extension_system_profile_.Set(profile);
}
#endif // BUILDFLAG(ENABLE_EXTENSIONS_CORE)
#if BUILDFLAG(ENABLE_EXTENSIONS)
void ChromeSyncControllerBuilder::SetThemeService(ThemeService* theme_service) {
theme_service_.Set(theme_service);
}
void ChromeSyncControllerBuilder::SetWebAppProvider(
web_app::WebAppProvider* web_app_provider) {
web_app_provider_.Set(web_app_provider);
}
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_SPELLCHECK)
void ChromeSyncControllerBuilder::SetSpellcheckService(
SpellcheckService* spellcheck_service) {
spellcheck_service_.Set(spellcheck_service);
}
#endif // BUILDFLAG(ENABLE_SPELLCHECK)
#if BUILDFLAG(IS_ANDROID)
void ChromeSyncControllerBuilder::SetWebApkSyncService(
webapk::WebApkSyncService* web_apk_sync_service) {
web_apk_sync_service_.Set(web_apk_sync_service);
}
#endif // BUILDFLAG(IS_ANDROID)
#if BUILDFLAG(IS_CHROMEOS)
void ChromeSyncControllerBuilder::SetAppListSyncableService(
app_list::AppListSyncableService* app_list_syncable_service) {
app_list_syncable_service_.Set(app_list_syncable_service);
}
void ChromeSyncControllerBuilder::SetAuthorizationZonesManager(
ash::printing::oauth2::AuthorizationZonesManager*
authorization_zones_manager) {
authorization_zones_manager_.Set(authorization_zones_manager);
}
void ChromeSyncControllerBuilder::SetArcPackageSyncableService(
arc::ArcPackageSyncableService* arc_package_syncable_service,
Profile* arc_package_profile) {
arc_package_syncable_service_.Set(arc_package_syncable_service);
arc_package_profile_.Set(arc_package_profile);
}
void ChromeSyncControllerBuilder::SetDeskSyncService(
desks_storage::DeskSyncService* desk_sync_service) {
desk_sync_service_.Set(desk_sync_service);
}
void ChromeSyncControllerBuilder::SetFloatingSsoService(
ash::floating_sso::FloatingSsoService* floating_sso_service) {
floating_sso_service_.Set(floating_sso_service);
}
void ChromeSyncControllerBuilder::SetOsPrefServiceSyncable(
sync_preferences::PrefServiceSyncable* os_pref_service_syncable) {
os_pref_service_syncable_.Set(os_pref_service_syncable);
}
void ChromeSyncControllerBuilder::SetPrefService(PrefService* pref_service) {
pref_service_.Set(pref_service);
}
void ChromeSyncControllerBuilder::SetSyncedPrintersManager(
ash::SyncedPrintersManager* synced_printer_manager) {
synced_printer_manager_.Set(synced_printer_manager);
}
void ChromeSyncControllerBuilder::SetWifiConfigurationSyncService(
ash::sync_wifi::WifiConfigurationSyncService*
wifi_configuration_sync_service) {
wifi_configuration_sync_service_.Set(wifi_configuration_sync_service);
}
#endif // BUILDFLAG(IS_CHROMEOS)
std::vector<std::unique_ptr<syncer::DataTypeController>>
ChromeSyncControllerBuilder::Build(syncer::SyncService* sync_service) {
std::vector<std::unique_ptr<syncer::DataTypeController>> controllers;
const base::RepeatingClosure dump_stack = base::BindRepeating(
&syncer::ReportUnrecoverableError, chrome::GetChannel());
syncer::RepeatingDataTypeStoreFactory data_type_store_factory =
data_type_store_service_.value()->GetStoreFactory();
syncer::DataTypeControllerDelegate* security_events_delegate =
security_event_recorder_.value()->GetControllerDelegate().get();
// Forward both full-sync and transport-only modes to the same delegate,
// since behavior for SECURITY_EVENTS does not differ.
controllers.push_back(std::make_unique<syncer::DataTypeController>(
syncer::SECURITY_EVENTS,
/*delegate_for_full_sync_mode=*/
std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
security_events_delegate),
/*delegate_for_transport_mode=*/
std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
security_events_delegate)));
#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
if (extension_sync_service_.value()) {
controllers.push_back(
std::make_unique<browser_sync::ExtensionDataTypeController>(
syncer::EXTENSIONS, data_type_store_factory,
extension_sync_service_.value()->AsWeakPtr(), dump_stack,
browser_sync::ExtensionDataTypeController::DelegateMode::
kTransportModeWithSingleModel,
extension_system_profile_.value()));
controllers.push_back(
std::make_unique<browser_sync::ExtensionSettingDataTypeController>(
syncer::EXTENSION_SETTINGS, data_type_store_factory,
extensions::settings_sync_util::GetSyncableServiceProvider(
extension_system_profile_.value(),
syncer::EXTENSION_SETTINGS),
dump_stack,
browser_sync::ExtensionSettingDataTypeController::DelegateMode::
kTransportModeWithSingleModel,
extension_system_profile_.value()));
}
#endif // BUILDFLAG(ENABLE_EXTENSIONS_CORE)
#if BUILDFLAG(ENABLE_EXTENSIONS)
if (extension_sync_service_.value()) {
controllers.push_back(
std::make_unique<browser_sync::ExtensionDataTypeController>(
syncer::APPS, data_type_store_factory,
extension_sync_service_.value()->AsWeakPtr(), dump_stack,
browser_sync::ExtensionDataTypeController::DelegateMode::
kLegacyFullSyncModeOnly,
extension_system_profile_.value()));
controllers.push_back(
std::make_unique<browser_sync::ExtensionSettingDataTypeController>(
syncer::APP_SETTINGS, data_type_store_factory,
extensions::settings_sync_util::GetSyncableServiceProvider(
extension_system_profile_.value(), syncer::APP_SETTINGS),
dump_stack,
browser_sync::ExtensionSettingDataTypeController::DelegateMode::
kLegacyFullSyncModeOnly,
extension_system_profile_.value()));
}
if (theme_service_.value()) {
controllers.push_back(
std::make_unique<browser_sync::ExtensionDataTypeController>(
syncer::THEMES, data_type_store_factory,
theme_service_.value()->GetThemeSyncableService()->AsWeakPtr(),
dump_stack,
base::FeatureList::IsEnabled(
syncer::kSeparateLocalAndAccountThemes)
? browser_sync::ExtensionDataTypeController::DelegateMode::
kTransportModeWithSingleModel
: browser_sync::ExtensionDataTypeController::DelegateMode::
kLegacyFullSyncModeOnly,
extension_system_profile_.value(),
// SyncService depends on ThemeService. So the
// ThemeSyncableService instance should outlive the controller.
std::make_unique<ThemeLocalDataBatchUploader>(
theme_service_.value()->GetThemeSyncableService())));
}
if (web_app_provider_.value()) {
syncer::DataTypeControllerDelegate* delegate =
web_app_provider_.value()
->sync_bridge_unsafe()
.change_processor()
->GetControllerDelegate()
.get();
controllers.push_back(std::make_unique<syncer::DataTypeController>(
syncer::WEB_APPS,
/*delegate_for_full_sync_mode=*/
std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
delegate),
// TODO(crbug.com/424698545): This special-casing shouldn't be necessary
// for ChromeOS, but currently the transport mode delegate may be
// exercised in some unexpected cases.
#if BUILDFLAG(IS_CHROMEOS)
/*delegate_for_transport_mode=*/nullptr
#else // BUILDFLAG(IS_CHROMEOS)
/*delegate_for_transport_mode=*/
std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
delegate)
#endif // BUILDFLAG(IS_CHROMEOS)
));
}
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(IS_ANDROID)
if (web_apk_sync_service_.value()) {
syncer::DataTypeControllerDelegate* delegate =
web_apk_sync_service_.value()->GetDataTypeControllerDelegate().get();
controllers.push_back(std::make_unique<syncer::DataTypeController>(
syncer::WEB_APKS,
/*delegate_for_full_sync_mode=*/
std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
delegate),
/*delegate_for_transport_mode=*/
std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
delegate)));
}
#endif // BUILDFLAG(IS_ANDROID)
#if BUILDFLAG(ENABLE_SPELLCHECK)
// Chrome prefers OS provided spell checkers where they exist. So only sync
// the custom dictionary on platforms that typically don't provide one.
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
// Dictionary sync is enabled by default.
if (spellcheck_service_.value()) {
controllers.push_back(
std::make_unique<syncer::SyncableServiceBasedDataTypeController>(
syncer::DICTIONARY, data_type_store_factory,
spellcheck_service_.value()->GetCustomDictionary()->AsWeakPtr(),
dump_stack,
syncer::SyncableServiceBasedDataTypeController::DelegateMode::
kLegacyFullSyncModeOnly));
}
#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
#endif // BUILDFLAG(ENABLE_SPELLCHECK)
#if BUILDFLAG(IS_CHROMEOS)
CHECK(os_pref_service_syncable_.value());
controllers.push_back(
std::make_unique<syncer::SyncableServiceBasedDataTypeController>(
syncer::OS_PREFERENCES, data_type_store_factory,
os_pref_service_syncable_.value()
->GetSyncableService(syncer::OS_PREFERENCES)
->AsWeakPtr(),
dump_stack,
syncer::SyncableServiceBasedDataTypeController::DelegateMode::
kTransportModeWithSingleModel));
controllers.push_back(
std::make_unique<syncer::SyncableServiceBasedDataTypeController>(
syncer::OS_PRIORITY_PREFERENCES, data_type_store_factory,
os_pref_service_syncable_.value()
->GetSyncableService(syncer::OS_PRIORITY_PREFERENCES)
->AsWeakPtr(),
dump_stack,
syncer::SyncableServiceBasedDataTypeController::DelegateMode::
kTransportModeWithSingleModel));
CHECK(synced_printer_manager_.value());
controllers.push_back(std::make_unique<syncer::DataTypeController>(
syncer::PRINTERS,
std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
synced_printer_manager_.value()
->GetSyncBridge()
->change_processor()
->GetControllerDelegate()
.get()),
/*delegate_for_transport_mode=*/nullptr));
// Some profile types (e.g. sign-in screen) don't support app list.
// Temporarily Disable AppListSyncableService for tablet form factor
// devices. See crbug/1013732 for details.
if (app_list_syncable_service_.value() &&
!ash::switches::IsTabletFormFactor()) {
// Runs in sync transport-mode and full-sync mode.
controllers.push_back(
std::make_unique<syncer::SyncableServiceBasedDataTypeController>(
syncer::APP_LIST, data_type_store_factory,
app_list_syncable_service_.value()->AsWeakPtr(), dump_stack,
syncer::SyncableServiceBasedDataTypeController::DelegateMode::
kTransportModeWithSingleModel));
}
if (arc_package_syncable_service_.value()) {
controllers.push_back(std::make_unique<ArcPackageSyncDataTypeController>(
data_type_store_factory,
arc_package_syncable_service_.value()->AsWeakPtr(), dump_stack,
sync_service, arc_package_profile_.value()));
}
if (wifi_configuration_sync_service_.value()) {
syncer::DataTypeControllerDelegate* wifi_configurations_delegate =
wifi_configuration_sync_service_.value()
->GetControllerDelegate()
.get();
controllers.push_back(std::make_unique<syncer::DataTypeController>(
syncer::WIFI_CONFIGURATIONS,
std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
wifi_configurations_delegate),
/*delegate_for_transport_mode=*/nullptr));
}
CHECK(desk_sync_service_.value());
controllers.push_back(std::make_unique<syncer::DataTypeController>(
syncer::WORKSPACE_DESK,
std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
desk_sync_service_.value()->GetControllerDelegate().get()),
/*delegate_for_transport_mode=*/nullptr));
if (authorization_zones_manager_.value()) {
syncer::DataTypeControllerDelegate*
printers_authorization_servers_delegate =
authorization_zones_manager_.value()
->GetDataTypeSyncBridge()
->change_processor()
->GetControllerDelegate()
.get();
controllers.push_back(std::make_unique<syncer::DataTypeController>(
syncer::PRINTERS_AUTHORIZATION_SERVERS,
std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
printers_authorization_servers_delegate),
/*delegate_for_transport_mode=*/nullptr));
}
if (floating_sso_service_.value()) {
controllers.push_back(
std::make_unique<ash::floating_sso::CookieSyncDataTypeController>(
/*delegate_for_full_sync_mode=*/
std::make_unique<syncer::ForwardingDataTypeControllerDelegate>(
floating_sso_service_.value()->GetControllerDelegate().get()),
sync_service, pref_service_.value()));
}
#endif // BUILDFLAG(IS_CHROMEOS)
return controllers;
}