chromium/components/account_manager_core/chromeos/account_manager_facade_factory_lacros.cc

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

#include "base/memory/raw_ptr.h"
#include "components/account_manager_core/chromeos/account_manager_facade_factory.h"

#include <limits>
#include <memory>

#include "base/no_destructor.h"
#include "chromeos/lacros/lacros_service.h"
#include "components/account_manager_core/account_manager_facade.h"
#include "components/account_manager_core/account_manager_facade_impl.h"
#include "components/account_manager_core/chromeos/account_manager.h"
#include "components/account_manager_core/chromeos/account_manager_mojo_service.h"
#include "mojo/public/cpp/bindings/remote.h"

namespace {

mojo::Remote<crosapi::mojom::AccountManager> GetAccountManagerRemote() {
  mojo::Remote<crosapi::mojom::AccountManager> remote;

  auto* lacros_chrome_service_impl = chromeos::LacrosService::Get();
  DCHECK(lacros_chrome_service_impl);
  if (!lacros_chrome_service_impl
           ->IsSupported<crosapi::mojom::AccountManager>()) {
    LOG(WARNING) << "Connected to an older version of ash. Account "
                    "consistency will not be available";
    return remote;
  }

  lacros_chrome_service_impl->BindAccountManagerReceiver(
      remote.BindNewPipeAndPassReceiver());

  return remote;
}

class AccountManagerFacadeFactoryLacros {
 public:
  void CreateAshAccountManagerForTests(
      std::unique_ptr<account_manager::AccountManagerUI> account_manager_ui) {
    // `account_manager_facade_` depends on `ash_account_manager_` and cannot be
    // reset, as users may be holding weak references to it.
    DCHECK(!account_manager_facade_);

    Reset();
    ash_account_manager_ = std::make_unique<account_manager::AccountManager>();
    account_manager_mojo_service_ =
        std::make_unique<crosapi::AccountManagerMojoService>(
            ash_account_manager_.get());
    account_manager_ui_ = account_manager_ui.get();
    account_manager_mojo_service_->SetAccountManagerUI(
        std::move(account_manager_ui));
  }

  account_manager::AccountManagerFacade* GetAccountManagerFacade() {
    if (!account_manager_facade_) {
      InitializeAccountManagerFacade();
    }
    return account_manager_facade_.get();
  }

  account_manager::AccountManager* MaybeGetAshAccountManagerForTests() {
    return ash_account_manager_.get();
  }

  account_manager::AccountManagerUI* MaybeGetAshAccountManagerUIForTests() {
    return account_manager_ui_;
  }

  crosapi::AccountManagerMojoService*
  MaybeGetAshAccountManagerMojoServiceForTests() {
    return account_manager_mojo_service_.get();
  }

  // Reset the pointers.
  void Reset() {
    // AccountManagerFacade depends on AccountManagerMojoService.
    account_manager_facade_.reset();
    account_manager_ui_ = nullptr;
    // AccountManagerMojoService depends on AccountManager.
    account_manager_mojo_service_.reset();
    ash_account_manager_.reset();
  }

 private:
  void InitializeAccountManagerFacade() {
    if (ash_account_manager_) {
      // Create a new `AccountManagerFacade` that is connected to
      // `AccountManagerMojoService` for tests.
      mojo::Remote<crosapi::mojom::AccountManager> remote;
      account_manager_mojo_service_->BindReceiver(
          remote.BindNewPipeAndPassReceiver());

      account_manager_facade_ =
          std::make_unique<account_manager::AccountManagerFacadeImpl>(
              std::move(remote),
              /*remote_version=*/std::numeric_limits<uint32_t>::max(),
              /*account_manager_for_tests=*/ash_account_manager_->GetWeakPtr());
      return;
    }

    account_manager_facade_ =
        std::make_unique<account_manager::AccountManagerFacadeImpl>(
            GetAccountManagerRemote(),
            /*remote_version=*/
            chromeos::LacrosService::Get()
                ->GetInterfaceVersion<crosapi::mojom::AccountManager>(),
            /*account_manager_for_tests=*/nullptr);
  }

  std::unique_ptr<account_manager::AccountManagerFacade>
      account_manager_facade_;

  // Set only in tests:
  std::unique_ptr<account_manager::AccountManager> ash_account_manager_;
  std::unique_ptr<crosapi::AccountManagerMojoService>
      account_manager_mojo_service_;
  // Owned by `account_manager_mojo_service_`:
  raw_ptr<account_manager::AccountManagerUI> account_manager_ui_ = nullptr;
};

AccountManagerFacadeFactoryLacros* GetAccountManagerFacadeFactoryLacros() {
  static base::NoDestructor<AccountManagerFacadeFactoryLacros> factory;
  return factory.get();
}

}  // namespace

ScopedAshAccountManagerForTests::ScopedAshAccountManagerForTests(
    std::unique_ptr<account_manager::AccountManagerUI> account_manager_ui) {
  DCHECK(!MaybeGetAshAccountManagerForTests())  // IN-TEST
      << "Nested ScopedAshAccountManagerForTests are not supported.";
  GetAccountManagerFacadeFactoryLacros()->CreateAshAccountManagerForTests(
      std::move(account_manager_ui));  // IN-TEST
}

ScopedAshAccountManagerForTests::~ScopedAshAccountManagerForTests() {
  GetAccountManagerFacadeFactoryLacros()->Reset();
}

account_manager::AccountManagerFacade* GetAccountManagerFacade(
    const std::string& profile_path) {
  // Multi-Login is disabled with Lacros. Always return the same instance.
  return GetAccountManagerFacadeFactoryLacros()->GetAccountManagerFacade();
}

account_manager::AccountManager* MaybeGetAshAccountManagerForTests() {
  return GetAccountManagerFacadeFactoryLacros()
      ->MaybeGetAshAccountManagerForTests();  // IN-TEST
}

account_manager::AccountManagerUI* MaybeGetAshAccountManagerUIForTests() {
  return GetAccountManagerFacadeFactoryLacros()
      ->MaybeGetAshAccountManagerUIForTests();  // IN-TEST
}

crosapi::AccountManagerMojoService*
MaybeGetAshAccountManagerMojoServiceForTests() {
  return GetAccountManagerFacadeFactoryLacros()
      ->MaybeGetAshAccountManagerMojoServiceForTests();  // IN-TEST
}