chromium/chrome/browser/password_manager/android/password_manager_settings_service_android_impl.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/password_manager/android/password_manager_settings_service_android_impl.h"

#include <optional>
#include <vector>

#include "base/barrier_callback.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/strcat.h"
#include "chrome/browser/password_manager/android/password_manager_android_util.h"
#include "chrome/browser/password_manager/android/password_manager_eviction_util.h"
#include "chrome/browser/password_manager/android/password_manager_lifecycle_helper_impl.h"
#include "chrome/browser/password_manager/android/password_settings_updater_android_bridge_helper.h"
#include "components/password_manager/core/browser/features/password_features.h"
#include "components/password_manager/core/browser/password_manager_setting.h"
#include "components/password_manager/core/browser/password_sync_util.h"
#include "components/password_manager/core/browser/split_stores_and_local_upm.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/base/signin_pref_names.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/sync/base/features.h"
#include "components/sync/base/user_selectable_type.h"
#include "components/sync/service/sync_service.h"
#include "components/sync/service/sync_user_settings.h"

using password_manager::PasswordManagerSetting;
using password_manager::PasswordSettingsUpdaterAndroidBridgeHelper;
using password_manager::UsesSplitStoresAndUPMForLocal;
using password_manager_upm_eviction::IsCurrentUserEvicted;

namespace {

using Consumer =
    password_manager::PasswordSettingsUpdaterAndroidReceiverBridge::Consumer;
using SyncingAccount = password_manager::
    PasswordSettingsUpdaterAndroidReceiverBridge::SyncingAccount;
using password_manager::prefs::UseUpmLocalAndSeparateStoresState;

const std::vector<PasswordManagerSetting> GetAllPasswordSettings() {
  return base::FeatureList::IsEnabled(
             password_manager::features::kBiometricTouchToFill)
             ? std::vector(
                   {PasswordManagerSetting::kOfferToSavePasswords,
                    PasswordManagerSetting::kAutoSignIn,
                    PasswordManagerSetting::kBiometricReauthBeforePwdFilling})
             : std::vector({PasswordManagerSetting::kOfferToSavePasswords,
                            PasswordManagerSetting::kAutoSignIn});
}

constexpr PasswordManagerSetting kMigratablePasswordSettings[] = {
    PasswordManagerSetting::kOfferToSavePasswords,
    PasswordManagerSetting::kAutoSignIn,
};

// Returns the preference in which a setting value coming from Google Mobile
// Services should be stored.
const PrefService::Preference* GetGMSPrefFromSetting(
    PrefService* pref_service,
    PasswordManagerSetting setting) {
  switch (setting) {
    case PasswordManagerSetting::kOfferToSavePasswords:
      return pref_service->FindPreference(
          password_manager::prefs::kOfferToSavePasswordsEnabledGMS);
    case PasswordManagerSetting::kAutoSignIn:
      return pref_service->FindPreference(
          password_manager::prefs::kAutoSignInEnabledGMS);
    case PasswordManagerSetting::kBiometricReauthBeforePwdFilling:
      return pref_service->FindPreference(
          password_manager::prefs::kBiometricAuthenticationBeforeFilling);
  }
}

// Returns the cross-platform preferences in which password manager settings
// are stored. These are not directly used on Android when the unified password
// manager is enabled.
const PrefService::Preference* GetRegularPrefFromSetting(
    PrefService* pref_service,
    PasswordManagerSetting setting) {
  switch (setting) {
    case PasswordManagerSetting::kOfferToSavePasswords:
      return pref_service->FindPreference(
          password_manager::prefs::kCredentialsEnableService);
    case PasswordManagerSetting::kAutoSignIn:
      return pref_service->FindPreference(
          password_manager::prefs::kCredentialsEnableAutosignin);
    // Never existed in Chrome on Android before.
    case PasswordManagerSetting::kBiometricReauthBeforePwdFilling:
      return pref_service->FindPreference(
          password_manager::prefs::kBiometricAuthenticationBeforeFilling);
  }
}

bool HasChosenToSyncPreferences(const syncer::SyncService* sync_service) {
  return sync_service && sync_service->GetDisableReasons().empty() &&
         sync_service->GetUserSettings()->GetSelectedTypes().Has(
             syncer::UserSelectableType::kPreferences);
}

bool DoesUpmPrefAllowForSettingsMigration(PrefService* pref_service) {
  return static_cast<UseUpmLocalAndSeparateStoresState>(
             pref_service->GetInteger(
                 password_manager::prefs::
                     kPasswordsUseUPMLocalAndSeparateStores)) !=
         UseUpmLocalAndSeparateStoresState::kOff;
}

bool ShouldMigrateLocalSettings(PrefService* pref_service,
                                bool is_password_sync_enabled) {
  // Settings should be migrated if the user is enrolled in UPM with local
  // passwords and they have never successfully completed settings migration.
  return !is_password_sync_enabled &&
         !pref_service->GetBoolean(
             password_manager::prefs::kSettingsMigratedToUPMLocal) &&
         DoesUpmPrefAllowForSettingsMigration(pref_service);
}

// This function is called after a setting is fetched from
// GMS Core to update the cache. Updating the non-cache (regular)
// prefs is also done in cases where sync isn't running so that the value
// is up-to-data in case of rollback.
bool ShouldWriteToRegularPref(syncer::SyncService* sync_service,
                              PrefService* pref_service) {
  // We should write to regular pref if sync for preferences is disabled and:
  // 1) User is using upm with local passwords and their settings migration
  // finished.
  // 2) User is not using upm with local passwords.
  bool is_using_upm_with_local_passwords_and_had_settings_migrated =
      DoesUpmPrefAllowForSettingsMigration(pref_service) &&
      pref_service->GetBoolean(
          password_manager::prefs::kSettingsMigratedToUPMLocal);
  bool is_not_using_upm_with_local_passwords =
      !DoesUpmPrefAllowForSettingsMigration(pref_service);
  return !HasChosenToSyncPreferences(sync_service) &&
         (is_using_upm_with_local_passwords_and_had_settings_migrated ||
          is_not_using_upm_with_local_passwords);
}

bool DidAccessingGMSPrefsFailed(
    const std::vector<PasswordManagerSettingGmsAccessResult>& results) {
  return !results[0].was_successful || !results[1].was_successful ||
         results[0].setting == results[1].setting;
}

std::string_view GetMetricsInfixForSetting(
    password_manager::PasswordManagerSetting setting) {
  switch (setting) {
    case password_manager::PasswordManagerSetting::kOfferToSavePasswords:
      return "OfferToSavePasswords";
    case password_manager::PasswordManagerSetting::kAutoSignIn:
      return "AutoSignIn";
    case password_manager::PasswordManagerSetting::
        kBiometricReauthBeforePwdFilling:
      return "BiometricReauthBeforePwdFilling";
  }
}

void RecordFailedMigrationMetric(std::string_view infix_for_setting,
                                 AndroidBackendAPIErrorCode api_error) {
  base::UmaHistogramSparse(
      base::StrCat({"PasswordManager.PasswordSettingsMigrationFailed.",
                    infix_for_setting, ".APIError2"}),
      static_cast<int>(api_error));
}

void RecordMigrationResult(bool result) {
  base::UmaHistogramBoolean(
      "PasswordManager.PasswordSettingsMigrationSucceeded2", result);
}

void MarkSettingsMigrationAsSuccessfulIfNothingToMigrate(PrefService* prefs) {
  if (GetRegularPrefFromSetting(prefs, PasswordManagerSetting::kAutoSignIn)
          ->IsDefaultValue() &&
      GetRegularPrefFromSetting(prefs,
                                PasswordManagerSetting::kOfferToSavePasswords)
          ->IsDefaultValue()) {
    RecordMigrationResult(true);
    prefs->SetBoolean(password_manager::prefs::kSettingsMigratedToUPMLocal,
                      true);
  }
}

}  // namespace

PasswordManagerSettingsServiceAndroidImpl::
    PasswordManagerSettingsServiceAndroidImpl(PrefService* pref_service,
                                              syncer::SyncService* sync_service)
    : pref_service_(pref_service), sync_service_(sync_service) {
  CHECK(pref_service_);
  bridge_helper_ = PasswordSettingsUpdaterAndroidBridgeHelper::Create();
  lifecycle_helper_ = std::make_unique<PasswordManagerLifecycleHelperImpl>();
  Init();
}

// Constructor for tests
PasswordManagerSettingsServiceAndroidImpl::
    PasswordManagerSettingsServiceAndroidImpl(
        base::PassKey<class PasswordManagerSettingsServiceAndroidImplBaseTest>,
        PrefService* pref_service,
        syncer::SyncService* sync_service,
        std::unique_ptr<PasswordSettingsUpdaterAndroidBridgeHelper>
            bridge_helper,
        std::unique_ptr<PasswordManagerLifecycleHelper> lifecycle_helper)
    : pref_service_(pref_service),
      sync_service_(sync_service),
      bridge_helper_(std::move(bridge_helper)),
      lifecycle_helper_(std::move(lifecycle_helper)) {
  CHECK(pref_service_);
  CHECK(bridge_helper_);
  Init();
}

PasswordManagerSettingsServiceAndroidImpl::
    ~PasswordManagerSettingsServiceAndroidImpl() {
  if (lifecycle_helper_) {
    lifecycle_helper_->UnregisterObserver();
  }
}

bool PasswordManagerSettingsServiceAndroidImpl::IsSettingEnabled(
    PasswordManagerSetting setting) const {
  const PrefService::Preference* regular_pref =
      GetRegularPrefFromSetting(pref_service_, setting);
  CHECK(regular_pref);

  if (!UsesUPMBackend()) {
    return regular_pref->GetValue()->GetBool();
  }

  if (regular_pref->IsManaged() || regular_pref->IsManagedByCustodian()) {
    return regular_pref->GetValue()->GetBool();
  }

  // Until the settings migration finished successfully, Chrome's setting value
  // will be returned.
  if (!is_password_sync_enabled_ &&
      !pref_service_->GetBoolean(
          password_manager::prefs::kSettingsMigratedToUPMLocal)) {
    return regular_pref->GetValue()->GetBool();
  }

  const PrefService::Preference* android_pref =
      GetGMSPrefFromSetting(pref_service_, setting);
  CHECK(android_pref);
  return android_pref->GetValue()->GetBool();
}

void PasswordManagerSettingsServiceAndroidImpl::RequestSettingsFromBackend() {
  if (!UsesUPMBackend()) {
    return;
  }
  FetchSettings();
}

void PasswordManagerSettingsServiceAndroidImpl::TurnOffAutoSignIn() {
  if (!UsesUPMBackend()) {
    pref_service_->SetBoolean(
        password_manager::prefs::kCredentialsEnableAutosignin, false);
    return;
  }
  if (!HasChosenToSyncPreferences(sync_service_)) {
    pref_service_->SetBoolean(
        password_manager::prefs::kCredentialsEnableAutosignin, false);
  }

  pref_service_->SetBoolean(password_manager::prefs::kAutoSignInEnabledGMS,
                            false);
  std::optional<SyncingAccount> account = std::nullopt;
  if (is_password_sync_enabled_) {
    account = SyncingAccount(sync_service_->GetAccountInfo().email);
  }
  // TODO(crbug.com/40285405): Implement retries for writing to GMSCore.
  bridge_helper_->SetPasswordSettingValue(
      account, PasswordManagerSetting::kAutoSignIn, false);
}

void PasswordManagerSettingsServiceAndroidImpl::Init() {
  CHECK(bridge_helper_);
  // TODO(crbug.com/40282601): Copy the pref values to GMSCore for local users.
  bridge_helper_->SetConsumer(weak_ptr_factory_.GetWeakPtr());

  lifecycle_helper_->RegisterObserver(base::BindRepeating(
      &PasswordManagerSettingsServiceAndroidImpl::OnChromeForegrounded,
      weak_ptr_factory_.GetWeakPtr()));
  is_password_sync_enabled_ = false;
  if (sync_service_) {
    is_password_sync_enabled_ =
        password_manager::sync_util::HasChosenToSyncPasswords(sync_service_);
    // The `sync_service_` can be null when --disable-sync has been passed in as
    // a command line flag.
    sync_service_->AddObserver(this);
  }

  pref_change_registrar_.Init(pref_service_);
  pref_change_registrar_.Add(
      password_manager::prefs::kUnenrolledFromGoogleMobileServicesDueToErrors,
      base::BindRepeating(&PasswordManagerSettingsServiceAndroidImpl::
                              OnUnenrollmentPreferenceChanged,
                          weak_ptr_factory_.GetWeakPtr()));

  if (ShouldMigrateLocalSettings(pref_service_, is_password_sync_enabled_)) {
    MarkSettingsMigrationAsSuccessfulIfNothingToMigrate(pref_service_);
    // If the migration was marked as done because there was nothing to migrate,
    // there is no reason to create the migration callback.
    if (!pref_service_->GetBoolean(
            password_manager::prefs::kSettingsMigratedToUPMLocal)) {
      start_migration_callback_ = base::BarrierCallback<
          PasswordManagerSettingGmsAccessResult>(
          2,
          base::BindOnce(
              &PasswordManagerSettingsServiceAndroidImpl::MigratePrefsIfNeeded,
              weak_ptr_factory_.GetWeakPtr()));
    }
  }

  // Unset the pref that marks the settings migration done, if the user is not
  // eligible for split stores and UPM for local. This is useful in case of
  // rollback and it also fixes the issue of the pref being set to true for
  // not-yet-enrolled users that had default prefs.
  if (password_manager_android_util::GetSplitStoresAndLocalUpmPrefValue(
          pref_service_) == UseUpmLocalAndSeparateStoresState::kOff) {
    pref_service_->SetBoolean(
        password_manager::prefs::kSettingsMigratedToUPMLocal, false);
  }
}

void PasswordManagerSettingsServiceAndroidImpl::OnChromeForegrounded() {
  RequestSettingsFromBackend();
}

void PasswordManagerSettingsServiceAndroidImpl::OnSettingValueFetched(
    PasswordManagerSetting setting,
    bool value) {
  UpdateSettingFetchState(setting);
  // For the users not using the UPM backend, the setting value should not be
  // written to the cache and the regular pref, unless this call to
  // `OnSettingValueFetched` was part of the final fetch after a sync state
  // change.
  if (!UsesUPMBackend() && !fetch_after_sync_status_change_in_progress_) {
    return;
  }

  WriteToTheCacheAndRegularPref(setting, value);
  if (start_migration_callback_) {
    start_migration_callback_.Run(PasswordManagerSettingGmsAccessResult(
        setting, /*was_successful=*/true));
  }
}

void PasswordManagerSettingsServiceAndroidImpl::OnSettingValueAbsent(
    password_manager::PasswordManagerSetting setting) {
  CHECK(bridge_helper_);
  UpdateSettingFetchState(setting);

  if (!UsesUPMBackend()) {
    return;
  }

  // This code is currently called only for UPM users. If the setting value
  // is absent in GMSCore, the cached setting value is set to the default
  // value, which is true for both of the password-related settings:
  // AutoSignIn and OfferToSavePasswords.
  WriteToTheCacheAndRegularPref(setting, std::nullopt);
  if (start_migration_callback_) {
    start_migration_callback_.Run(PasswordManagerSettingGmsAccessResult(
        setting, /*was_successful=*/true));
  }
}

void PasswordManagerSettingsServiceAndroidImpl::OnSettingFetchingError(
    password_manager::PasswordManagerSetting setting,
    AndroidBackendAPIErrorCode api_error_code) {
  CHECK(bridge_helper_);
  if (!UsesUPMBackend()) {
    return;
  }
  if (start_migration_callback_) {
    RecordFailedMigrationMetric(GetMetricsInfixForSetting(setting),
                                api_error_code);
    start_migration_callback_.Run(PasswordManagerSettingGmsAccessResult(
        setting, /*was_successful=*/false));
  }
}

void PasswordManagerSettingsServiceAndroidImpl::OnSuccessfulSettingChange(
    password_manager::PasswordManagerSetting setting) {
  CHECK(bridge_helper_);
  if (!UsesUPMBackend()) {
    return;
  }
  if (migration_finished_callback_) {
    migration_finished_callback_.Run(PasswordManagerSettingGmsAccessResult(
        setting, /*was_successful=*/true));
  }
}
void PasswordManagerSettingsServiceAndroidImpl::OnFailedSettingChange(
    password_manager::PasswordManagerSetting setting,
    AndroidBackendAPIErrorCode api_error_code) {
  CHECK(bridge_helper_);
  if (!UsesUPMBackend()) {
    return;
  }
  if (migration_finished_callback_) {
    RecordFailedMigrationMetric(GetMetricsInfixForSetting(setting),
                                api_error_code);
    migration_finished_callback_.Run(PasswordManagerSettingGmsAccessResult(
        setting, /*was_successful=*/false));
  }
}

void PasswordManagerSettingsServiceAndroidImpl::WriteToTheCacheAndRegularPref(
    PasswordManagerSetting setting,
    std::optional<bool> value) {
  const PrefService::Preference* android_pref =
      GetGMSPrefFromSetting(pref_service_, setting);
  if (value.has_value()) {
    pref_service_->SetBoolean(android_pref->name(), value.value());
  } else {
    pref_service_->ClearPref(android_pref->name());
  }

  // Updating the regular pref now will ensure that if passwods sync turns off
  // the regular pref contains the latest setting value. This can only be done
  // when preference syncing is off, otherwise it might cause sync cycles.
  // When sync is on, the regular preference gets updated via sync, so this
  // step is not necessary.
  if (ShouldWriteToRegularPref(sync_service_, pref_service_)) {
    const PrefService::Preference* regular_pref =
        GetRegularPrefFromSetting(pref_service_, setting);
    if (value.has_value()) {
      pref_service_->SetBoolean(regular_pref->name(), value.value());
    } else {
      pref_service_->ClearPref(regular_pref->name());
    }
  }
}

void PasswordManagerSettingsServiceAndroidImpl::OnStateChanged(
    syncer::SyncService* sync) {
  CHECK(sync);
  // Return early if the setting didn't change and no sync errors were resolved.
  bool is_password_sync_enabled =
      password_manager::sync_util::HasChosenToSyncPasswords(sync_service_);
  if (is_password_sync_enabled == is_password_sync_enabled_) {
    return;
  }

  is_password_sync_enabled_ = is_password_sync_enabled;

  if (is_password_sync_enabled_ && IsCurrentUserEvicted(pref_service_)) {
    return;
  }

  // If sync just turned off, but the client was unenrolled prior to the change
  // and they are not using local storage support, it means that there is no
  // backend to talk to and Chrome will be reading the settings from the regular
  // prefs, so there is no point in making a request for new settings values.
  // Users not syncing passwords that have local storage support ignore
  // unenrollment and need to fetch new settings from the local backend to
  // replace the account ones.
  if (!is_password_sync_enabled_ && IsCurrentUserEvicted(pref_service_) &&
      !UsesSplitStoresAndUPMForLocal(pref_service_)) {
    return;
  }

  // Fetch settings from the backend to align values stored in GMS Core and
  // Chrome.
  fetch_after_sync_status_change_in_progress_ = true;
  for (PasswordManagerSetting setting : GetAllPasswordSettings()) {
    awaited_settings_.insert(setting);
  }
  FetchSettings();
}

void PasswordManagerSettingsServiceAndroidImpl::UpdateSettingFetchState(
    PasswordManagerSetting received_setting) {
  if (!fetch_after_sync_status_change_in_progress_) {
    return;
  }

  awaited_settings_.erase(received_setting);
  if (awaited_settings_.empty()) {
    fetch_after_sync_status_change_in_progress_ = false;
  }
}

void PasswordManagerSettingsServiceAndroidImpl::FetchSettings() {
  CHECK(bridge_helper_);
  // This code would not be executed for syncing users who are unenrolled.
  CHECK(!is_password_sync_enabled_ || !IsCurrentUserEvicted(pref_service_));
  std::optional<SyncingAccount> account = std::nullopt;
  bool is_final_fetch_for_local_user_without_upm =
      fetch_after_sync_status_change_in_progress_ &&
      !is_password_sync_enabled_ &&
      !UsesSplitStoresAndUPMForLocal(pref_service_);
  if (is_password_sync_enabled_ || is_final_fetch_for_local_user_without_upm) {
    // Note: This method also handles the case where the previously signed-in
    // account has just signed out. So the account can't be queried via
    // `sync_service_->GetAccountInfo().email` but instead needs to be retrieved
    // via kGoogleServices*Last*SignedInUsername.
    std::string last_account_pref = pref_service_->GetString(
        base::FeatureList::IsEnabled(
            syncer::kEnablePasswordsAccountStorageForNonSyncingUsers)
            ? prefs::kGoogleServicesLastSignedInUsername
            : prefs::kGoogleServicesLastSyncingUsername);
    account = SyncingAccount(last_account_pref);
  }
  for (PasswordManagerSetting setting : GetAllPasswordSettings()) {
    bridge_helper_->GetPasswordSettingValue(account, setting);
  }
}

void PasswordManagerSettingsServiceAndroidImpl::
    OnUnenrollmentPreferenceChanged() {
  if (!IsCurrentUserEvicted(pref_service_)) {
    // Perform actions that are usually done on startup, but were skipped
    // for the evicted users.
    RequestSettingsFromBackend();
  }
}

bool PasswordManagerSettingsServiceAndroidImpl::UsesUPMBackend() const {
  return password_manager_android_util::ShouldUseUpmWiring(sync_service_,
                                                           pref_service_);
}

void PasswordManagerSettingsServiceAndroidImpl::MigratePrefsIfNeeded(
    const std::vector<PasswordManagerSettingGmsAccessResult>& results) {
  start_migration_callback_.Reset();
  // Check if migration should happen.
  if (!ShouldMigrateLocalSettings(pref_service_, is_password_sync_enabled_)) {
    return;
  }

  // Check if getting settings prefs failed. In rare cases (when Chrome was put
  // into the background with running migration and then to the foreground
  // again), since the settings from GMS are fetched when foregrounding Chrome,
  // it might happen that two fetches for the same pref will finish first. We
  // want to ensure that each one of the settings was fetched successfully.
  if (DidAccessingGMSPrefsFailed(results)) {
    RecordMigrationResult(false);
    return;
  }

  migration_finished_callback_ = base::BarrierCallback<
      PasswordManagerSettingGmsAccessResult>(
      2,
      base::BindOnce(
          &PasswordManagerSettingsServiceAndroidImpl::FinishSettingsMigration,
          weak_ptr_factory_.GetWeakPtr()));

  for (auto setting : kMigratablePasswordSettings) {
    const PrefService::Preference* regular_pref =
        GetRegularPrefFromSetting(pref_service_, setting);
    const PrefService::Preference* android_pref =
        GetGMSPrefFromSetting(pref_service_, setting);

    if (regular_pref->IsDefaultValue()) {
      // If Chrome had default value then value from gms is saved to Chrome.
      pref_service_->SetBoolean(regular_pref->name(),
                                android_pref->GetValue()->GetBool());
      // Migraion will finish only if this callback is called twice, but in this
      // case we didn't call gms, so we can mark this setting manually as
      // successfully migrated.
      migration_finished_callback_.Run(PasswordManagerSettingGmsAccessResult(
          setting, /*was_successful=*/true));
      continue;
    }

    if (android_pref->GetValue()->GetBool() ==
        pref_service_->GetDefaultPrefValue(android_pref->name())->GetBool()) {
      // If Chrome had user set pref value and gms had default value, then
      // Chrome value is saved in gms.
      bridge_helper_->SetPasswordSettingValue(
          std::nullopt, setting, regular_pref->GetValue()->GetBool());
      pref_service_->SetBoolean(android_pref->name(),
                                regular_pref->GetValue()->GetBool());
      continue;
    }

    // If Chrome had user set pref value and gms had non default value, then
    // the most conservative value is saved. Meaning that if either one of
    // them, had this setting disabled, it should be disabled after the
    // migration.
    bool conservative_value = regular_pref->GetValue()->GetBool() &&
                              android_pref->GetValue()->GetBool();
    bridge_helper_->SetPasswordSettingValue(std::nullopt, setting,
                                            conservative_value);
    pref_service_->SetBoolean(android_pref->name(), conservative_value);
    pref_service_->SetBoolean(regular_pref->name(), conservative_value);
  }
}

void PasswordManagerSettingsServiceAndroidImpl::FinishSettingsMigration(
    const std::vector<PasswordManagerSettingGmsAccessResult>& results) {
  migration_finished_callback_.Reset();
  // Check if setting settings prefs failed.
  if (DidAccessingGMSPrefsFailed(results)) {
    RecordMigrationResult(false);
    return;
  }

  RecordMigrationResult(true);
  pref_service_->SetBoolean(
      password_manager::prefs::kSettingsMigratedToUPMLocal, true);
}