chromium/chrome/browser/lacros/sync/sync_crosapi_manager_lacros.cc

// Copyright 2022 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/sync/sync_crosapi_manager_lacros.h"

#include <cstdint>
#include <memory>
#include <utility>

#include "base/feature_list.h"
#include "chrome/browser/favicon/history_ui_favicon_request_handler_factory.h"
#include "chrome/browser/lacros/sync/crosapi_session_sync_notifier.h"
#include "chrome/browser/lacros/sync/sync_explicit_passphrase_client_lacros.h"
#include "chrome/browser/lacros/sync/sync_user_settings_client_lacros.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/session_sync_service_factory.h"
#include "chrome/browser/sync/sync_service_factory.h"
#include "chromeos/crosapi/mojom/sync.mojom.h"
#include "chromeos/lacros/lacros_service.h"
#include "chromeos/startup/browser_params_proxy.h"
#include "components/sync/base/features.h"
#include "components/sync/service/sync_service.h"
#include "components/sync/service/sync_user_settings.h"
#include "mojo/public/cpp/bindings/remote.h"

namespace {

// Version of crosapi that is guaranteed to have SyncUserSettingsClient API (
// exposed by SyncService crosapi).
const uint32_t kMinCrosapiVersionWithSyncUserSettingsClient = 80;

// Creates SyncExplicitPassphraseClientLacros if preconditions are met, returns
// nullptr otherwise. Preconditions are:
// 1. Sync passphrase sharing feature is enabled.
// 2. SyncService crosapi is available.
// `lacros_service` and `sync_service` must not be null.
std::unique_ptr<SyncExplicitPassphraseClientLacros>
MaybeCreateSyncExplicitPassphraseClient(chromeos::LacrosService* lacros_service,
                                        syncer::SyncService* sync_service) {
  DCHECK(lacros_service);
  DCHECK(sync_service);

  if (!base::FeatureList::IsEnabled(
          syncer::kSyncChromeOSExplicitPassphraseSharing)) {
    return nullptr;
  }

  if (!lacros_service->IsAvailable<crosapi::mojom::SyncService>()) {
    return nullptr;
  }

  mojo::Remote<crosapi::mojom::SyncExplicitPassphraseClient> client_remote;
  lacros_service->GetRemote<crosapi::mojom::SyncService>()
      ->BindExplicitPassphraseClient(
          client_remote.BindNewPipeAndPassReceiver());
  return std::make_unique<SyncExplicitPassphraseClientLacros>(
      std::move(client_remote), sync_service);
}

// Creates SyncUserSettingsClientLacros if preconditions are met, returns
// nullptr otherwise. Preconditions are:
// 1. Sync apps toggle sharing feature is enabled.
// 2. SyncService crosapi is available.
// 3. SyncService crosapi exposes SyncUserSettingsClient (e.g. Ash-side crosapi
// has sufficient version).
// `lacros_service` and `sync_service` must not be null.
std::unique_ptr<SyncUserSettingsClientLacros> MaybeCreateSyncUserSettingsClient(
    chromeos::LacrosService* lacros_service,
    syncer::SyncUserSettings* sync_user_settings) {
  DCHECK(lacros_service);
  DCHECK(sync_user_settings);

  if (!base::FeatureList::IsEnabled(syncer::kSyncChromeOSAppsToggleSharing)) {
    return nullptr;
  }

  if (!lacros_service->IsAvailable<crosapi::mojom::SyncService>()) {
    return nullptr;
  }

  if (chromeos::BrowserParamsProxy::Get()->CrosapiVersion() <
      kMinCrosapiVersionWithSyncUserSettingsClient) {
    return nullptr;
  }

  mojo::Remote<crosapi::mojom::SyncUserSettingsClient> client_remote;
  lacros_service->GetRemote<crosapi::mojom::SyncService>()
      ->BindUserSettingsClient(client_remote.BindNewPipeAndPassReceiver());
  return std::make_unique<SyncUserSettingsClientLacros>(
      std::move(client_remote), sync_user_settings);
}

}  // namespace

SyncCrosapiManagerLacros::SyncCrosapiManagerLacros() = default;

SyncCrosapiManagerLacros::~SyncCrosapiManagerLacros() = default;

void SyncCrosapiManagerLacros::PostProfileInit(Profile* profile) {
  if (!profile->IsMainProfile()) {
    return;
  }

  DCHECK(!profile_);
  profile_ = profile;
  auto* lacros_service = chromeos::LacrosService::Get();
  auto* sync_service = SyncServiceFactory::GetForProfile(profile);
  if (!lacros_service || !sync_service) {
    return;
  }
  sync_service->AddObserver(this);

  DCHECK(!crosapi_session_sync_notifier_);
  profile->AddObserver(this);
  MaybeCreateCrosapiSessionSyncNotifier();

  DCHECK(!sync_explicit_passphrase_client_);
  sync_explicit_passphrase_client_ =
      MaybeCreateSyncExplicitPassphraseClient(lacros_service, sync_service);

  DCHECK(!sync_user_settings_client_);
  sync_user_settings_client_ = MaybeCreateSyncUserSettingsClient(
      lacros_service, sync_service->GetUserSettings());
}

void SyncCrosapiManagerLacros::OnProfileWillBeDestroyed(Profile* profile) {
  profile_ = nullptr;
  crosapi_session_sync_notifier_.reset();
  profile->RemoveObserver(this);
}

void SyncCrosapiManagerLacros::OnSyncShutdown(
    syncer::SyncService* sync_service) {
  sync_explicit_passphrase_client_.reset();
  sync_user_settings_client_.reset();
  sync_service->RemoveObserver(this);
}

void SyncCrosapiManagerLacros::MaybeCreateCrosapiSessionSyncNotifier() {
  if (!base::FeatureList::IsEnabled(syncer::kChromeOSSyncedSessionSharing)) {
    return;
  }

  auto* lacros_service = chromeos::LacrosService::Get();
  if (lacros_service->GetInterfaceVersion<crosapi::mojom::SyncService>() <
      static_cast<int>(
          crosapi::mojom::SyncService::kCreateSyncedSessionClientMinVersion)) {
    return;
  }

  lacros_service->GetRemote<crosapi::mojom::SyncService>()
      ->CreateSyncedSessionClient(
          base::BindOnce(&SyncCrosapiManagerLacros::OnCreateSyncedSessionClient,
                         weak_ptr_factory_.GetWeakPtr()));
}

void SyncCrosapiManagerLacros::OnCreateSyncedSessionClient(
    mojo::PendingRemote<crosapi::mojom::SyncedSessionClient> pending_remote) {
  if (!pending_remote || !profile_) {
    return;
  }

  syncer::SyncService* sync_service =
      SyncServiceFactory::GetForProfile(profile_);
  if (!sync_service) {
    return;
  }

  sync_sessions::SessionSyncService* session_sync_service =
      SessionSyncServiceFactory::GetInstance()->GetForProfile(profile_);
  if (!session_sync_service) {
    return;
  }

  favicon::HistoryUiFaviconRequestHandler* favicon_request_handler =
      HistoryUiFaviconRequestHandlerFactory::GetInstance()
          ->GetForBrowserContext(profile_);

  DCHECK(!crosapi_session_sync_notifier_);
  crosapi_session_sync_notifier_ = std::make_unique<CrosapiSessionSyncNotifier>(
      session_sync_service, std::move(pending_remote), sync_service,
      favicon_request_handler);
}