blob: 4cc95e204227afcbd05bd80030393632a4248a8d [file] [log] [blame]
// 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 "components/password_manager/core/browser/password_store_proxy_backend.h"
#include <memory>
#include <utility>
#include <vector>
#include "base/barrier_callback.h"
#include "base/barrier_closure.h"
#include "base/functional/callback.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/functional/identity.h"
#include "base/memory/scoped_refptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
#include "base/ranges/algorithm.h"
#include "base/strings/strcat.h"
#include "components/password_manager/core/browser/field_info_table.h"
#include "components/password_manager/core/browser/password_store_backend.h"
#include "components/password_manager/core/browser/password_store_backend_error.h"
#include "components/password_manager/core/browser/password_sync_util.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/sync/driver/sync_service.h"
#include "components/sync/model/proxy_model_type_controller_delegate.h"
#include "google_apis/gaia/google_service_auth_error.h"
namespace password_manager {
namespace {
using sync_util::IsPasswordSyncEnabled;
bool ShouldExecuteModifyOperationsOnShadowBackend(PrefService* prefs,
bool is_syncing) {
return false;
}
bool ShouldExecuteReadOperationsOnShadowBackend(PrefService* prefs,
bool is_syncing) {
return false;
}
bool ShouldExecuteDeletionsOnShadowBackend(PrefService* prefs,
bool is_syncing) {
return is_syncing;
}
bool ShouldErrorResultInFallback(PasswordStoreBackendError error) {
switch (error.recovery_type) {
case PasswordStoreBackendErrorRecoveryType::kUnrecoverable:
case PasswordStoreBackendErrorRecoveryType::kUnspecified:
return true;
case PasswordStoreBackendErrorRecoveryType::kRetriable:
case PasswordStoreBackendErrorRecoveryType::kRecoverable:
return false;
}
}
bool IsBuiltInBackendSyncEnabled() {
return true;
}
void CallOnSyncEnabledOrDisabledForEnabledBackend(
bool originates_from_android,
base::RepeatingClosure sync_enabled_or_disabled_cb) {
if (IsBuiltInBackendSyncEnabled()) {
if (!originates_from_android) {
sync_enabled_or_disabled_cb.Run();
}
return;
}
sync_enabled_or_disabled_cb.Run();
}
using MethodName = base::StrongAlias<struct MethodNameTag, std::string>;
struct LoginsResultImpl {
using ResultType = LoginsResult;
using ElementsType = LoginsResult;
static LoginsResult* GetElements(LoginsResult& logins) { return &logins; }
static std::unique_ptr<PasswordForm> Clone(
const std::unique_ptr<PasswordForm>& login) {
return std::make_unique<PasswordForm>(*login);
}
static bool IsLess(const std::unique_ptr<PasswordForm>& lhs,
const std::unique_ptr<PasswordForm>& rhs) {
return PasswordFormUniqueKey(*lhs) < PasswordFormUniqueKey(*rhs);
}
static bool HaveInconsistentPasswords(
const std::unique_ptr<PasswordForm>& lhs,
const std::unique_ptr<PasswordForm>& rhs) {
return lhs->password_value != rhs->password_value;
}
};
struct LoginsResultOrErrorImpl {
using ResultType = LoginsResultOrError;
using ElementsType = LoginsResult;
static LoginsResult* GetElements(LoginsResultOrError& logins_or_error) {
return absl::holds_alternative<PasswordStoreBackendError>(logins_or_error)
? nullptr
: &absl::get<LoginsResult>(logins_or_error);
}
static std::unique_ptr<PasswordForm> Clone(
const std::unique_ptr<PasswordForm>& login) {
return std::make_unique<PasswordForm>(*login);
}
static bool IsLess(const std::unique_ptr<PasswordForm>& lhs,
const std::unique_ptr<PasswordForm>& rhs) {
return PasswordFormUniqueKey(*lhs) < PasswordFormUniqueKey(*rhs);
}
static bool HaveInconsistentPasswords(
const std::unique_ptr<PasswordForm>& lhs,
const std::unique_ptr<PasswordForm>& rhs) {
return lhs->password_value != rhs->password_value;
}
};
// An `ApiMethodImpl` for `ShadowTrafficMetricsRecorder` implementing support
// for the database modification methods returning `PasswordChangesOrError`.
struct PasswordChangesOrErrorImpl {
using ResultType = PasswordChangesOrError;
using ElementsType = PasswordStoreChangeList;
static const PasswordStoreChangeList* GetElements(
const PasswordChangesOrError& changelist_or_error) {
if (absl::holds_alternative<PasswordStoreBackendError>(changelist_or_error))
return nullptr;
const PasswordChanges& changelist =
absl::get<PasswordChanges>(changelist_or_error);
return changelist.has_value() ? &changelist.value() : nullptr;
}
static PasswordStoreChange Clone(const PasswordStoreChange& change) {
return change;
}
static bool IsLess(const PasswordStoreChange& lhs,
const PasswordStoreChange& rhs) {
return std::forward_as_tuple(PasswordFormUniqueKey(lhs.form()),
lhs.type()) <
std::forward_as_tuple(PasswordFormUniqueKey(rhs.form()), rhs.type());
}
static bool HaveInconsistentPasswords(const PasswordStoreChange& lhs,
const PasswordStoreChange& rhs) {
// We never consider PasswordStoreChange having inconsistent passwords.
return false;
}
};
void InvokeCallbackWithCombinedStatus(base::OnceCallback<void(bool)> completion,
std::vector<bool> statuses) {
std::move(completion).Run(base::ranges::all_of(statuses, base::identity()));
}
// Records the difference metrics between |main_result| and |backend_result|
// when returned by |method_name|. |main_result| and |backend_result| must be
// vectors of type T. |is_less| can be used to compare two objects of type T.
// |is_inconsistent| can be used to compute if the two objects have inconsistent
// password values.
template <typename T, typename IsLess, typename IsInconsistent>
void RecordMetrics(const MethodName& method_name,
const std::vector<T>& main_result,
const std::vector<T>& backend_result,
IsLess is_less,
IsInconsistent is_inconsistent) {
// Comparison is done by creating two sets that contain pointers to the
// objects stored in |main_result| and |backend_result|. Using the passed
// comparison methods, we compute and report metrics regarding the difference
// between both result vectors.
auto is_less_ptr = [is_less](const T* lhs, const T* rhs) {
return is_less(*lhs, *rhs);
};
auto address_of = [](const T& object) { return &object; };
auto main_elements =
base::MakeFlatSet<const T*>(main_result, is_less_ptr, address_of);
auto shadow_elements =
base::MakeFlatSet<const T*>(backend_result, is_less_ptr, address_of);
auto common_elements = [&] {
std::vector<const T*> vec;
vec.reserve(main_elements.size());
base::ranges::set_intersection(main_elements, shadow_elements,
std::back_inserter(vec), is_less_ptr);
return base::flat_set<const T*, decltype(is_less_ptr)>(std::move(vec),
is_less_ptr);
}();
// The cardinalities from which we compute the metrics.
size_t main_minus_shadow = main_elements.size() - common_elements.size();
size_t shadow_minus_main = shadow_elements.size() - common_elements.size();
size_t diff = main_minus_shadow + shadow_minus_main;
size_t total = diff + common_elements.size();
size_t inconsistent = base::ranges::count_if(common_elements, [&](auto* f) {
auto lhs = main_elements.find(f);
auto rhs = shadow_elements.find(f);
DCHECK(lhs != main_elements.end());
DCHECK(rhs != shadow_elements.end());
return (*is_inconsistent)(**lhs, **rhs);
});
// Emits a pair of absolute and relative metrics.
auto Emit = [&method_name](base::StringPiece metric_infix, size_t nominator,
size_t denominator) {
std::string prefix =
base::StrCat({"PasswordManager.PasswordStoreProxyBackend.",
method_name.value(), ".", metric_infix, "."});
base::UmaHistogramCounts1M(prefix + "Abs", nominator);
if (denominator != 0) {
size_t ceiling_of_percentage =
(nominator * 100 + denominator - 1) / denominator;
base::UmaHistogramPercentage(prefix + "Rel", ceiling_of_percentage);
}
};
Emit("Diff", diff, total);
Emit("MainMinusShadow", main_minus_shadow, total);
Emit("ShadowMinusMain", shadow_minus_main, total);
Emit("InconsistentPasswords", inconsistent, common_elements.size());
}
// Records the metrics of a pair of MethodName calls to the main and
// the shadow backends once both calls are finished. MethodName() is expected to
// return an std::vector<ApiMethodImpl::ResultType>. ApiMethodImpl classes need
// to provide 4 methods:
// - GetElements(): returns the elements to be compared
// - Clone(): Returns a copy of an element, used to cache the main results.
// - IsLess(): to compare elements.
// - HaveInconsistentPasswords(): Whether elements have inconsistent passwords
//
// The class is ref-counted because it is equally owned by the two parallel
// method calls : it must outlive the first returning one and shall be
// destroyed after the second one returns.
template <typename ApiMethodImpl>
class ShadowTrafficMetricsRecorder
: public base::RefCounted<ShadowTrafficMetricsRecorder<ApiMethodImpl>> {
public:
explicit ShadowTrafficMetricsRecorder(MethodName method_name)
: method_name_(std::move(method_name)) {}
// Returns the unchanged |result| so it can be passed to the main handler.
typename ApiMethodImpl::ResultType RecordMainResult(
typename ApiMethodImpl::ResultType result) {
if (auto* elements = ApiMethodImpl::GetElements(result)) {
if (!first_result_) {
first_result_ =
absl::make_optional<typename ApiMethodImpl::ElementsType>();
first_result_->reserve(elements->size());
for (const auto& e : *elements)
first_result_->push_back(ApiMethodImpl::Clone(e));
} else {
RecordMetrics(method_name_, /*main_result=*/*elements,
/*shadow_result=*/*first_result_, &ApiMethodImpl::IsLess,
&ApiMethodImpl::HaveInconsistentPasswords);
}
}
return result;
}
void RecordShadowResult(typename ApiMethodImpl::ResultType result) {
if (auto* elements = ApiMethodImpl::GetElements(result)) {
if (!first_result_) {
first_result_ = std::move(*elements);
} else {
RecordMetrics(method_name_,
/*main_result=*/*first_result_,
/*shadow_result=*/*elements, &ApiMethodImpl::IsLess,
&ApiMethodImpl::HaveInconsistentPasswords);
}
}
}
private:
friend class base::RefCounted<ShadowTrafficMetricsRecorder<ApiMethodImpl>>;
~ShadowTrafficMetricsRecorder() = default;
// Stores the result of the backend that returns first.
absl::optional<typename ApiMethodImpl::ElementsType> first_result_;
const MethodName method_name_;
};
std::string GetFallbackMetricNameForMethod(const MethodName& method_name) {
return base::StrCat({"PasswordManager.PasswordStoreProxyBackend.",
method_name.value(), ".Fallback"});
}
} // namespace
PasswordStoreProxyBackend::PasswordStoreProxyBackend(
PasswordStoreBackend* built_in_backend,
PasswordStoreBackend* android_backend,
PrefService* prefs)
: built_in_backend_(built_in_backend),
android_backend_(android_backend),
prefs_(prefs) {}
PasswordStoreProxyBackend::~PasswordStoreProxyBackend() = default;
void PasswordStoreProxyBackend::InitBackend(
RemoteChangesReceived remote_form_changes_received,
base::RepeatingClosure sync_enabled_or_disabled_cb,
base::OnceCallback<void(bool)> completion) {
base::RepeatingCallback<void(bool)> pending_initialization_calls =
base::BarrierCallback<bool>(
/*num_callbacks=*/2, base::BindOnce(&InvokeCallbackWithCombinedStatus,
std::move(completion)));
// Both backends need to be initialized, so using the helpers for main/shadow
// backend is unnecessary and won't work since the sync status may not be
// available yet.
built_in_backend_->InitBackend(
base::BindRepeating(
&PasswordStoreProxyBackend::OnRemoteFormChangesReceived,
weak_ptr_factory_.GetWeakPtr(),
CallbackOriginatesFromAndroidBackend(false),
remote_form_changes_received),
base::BindRepeating(&CallOnSyncEnabledOrDisabledForEnabledBackend,
/*originates_from_android=*/false,
sync_enabled_or_disabled_cb),
base::BindOnce(pending_initialization_calls));
android_backend_->InitBackend(
base::BindRepeating(
&PasswordStoreProxyBackend::OnRemoteFormChangesReceived,
weak_ptr_factory_.GetWeakPtr(),
CallbackOriginatesFromAndroidBackend(true),
std::move(remote_form_changes_received)),
base::BindRepeating(&CallOnSyncEnabledOrDisabledForEnabledBackend,
/*originates_from_android=*/true,
std::move(sync_enabled_or_disabled_cb)),
base::BindOnce(pending_initialization_calls));
}
void PasswordStoreProxyBackend::Shutdown(base::OnceClosure shutdown_completed) {
base::RepeatingClosure pending_shutdown_calls = base::BarrierClosure(
/*num_closures=*/2, std::move(shutdown_completed));
android_backend_->Shutdown(pending_shutdown_calls);
built_in_backend_->Shutdown(pending_shutdown_calls);
}
void PasswordStoreProxyBackend::GetAllLoginsAsync(LoginsOrErrorReply callback) {
auto handler = base::MakeRefCounted<
ShadowTrafficMetricsRecorder<LoginsResultOrErrorImpl>>(
MethodName("GetAllLoginsAsync"));
main_backend()->GetAllLoginsAsync(
base::BindOnce(&ShadowTrafficMetricsRecorder<
LoginsResultOrErrorImpl>::RecordMainResult,
handler)
.Then(std::move(callback)));
if (ShouldExecuteReadOperationsOnShadowBackend(
prefs_, IsPasswordSyncEnabled(sync_service_))) {
shadow_backend()->GetAllLoginsAsync(
base::BindOnce(&ShadowTrafficMetricsRecorder<
LoginsResultOrErrorImpl>::RecordShadowResult,
handler));
}
}
void PasswordStoreProxyBackend::GetAutofillableLoginsAsync(
LoginsOrErrorReply callback) {
auto handler = base::MakeRefCounted<
ShadowTrafficMetricsRecorder<LoginsResultOrErrorImpl>>(
MethodName("GetAutofillableLoginsAsync"));
main_backend()->GetAutofillableLoginsAsync(
base::BindOnce(&ShadowTrafficMetricsRecorder<
LoginsResultOrErrorImpl>::RecordMainResult,
handler)
.Then(std::move(callback)));
if (ShouldExecuteReadOperationsOnShadowBackend(
prefs_, IsPasswordSyncEnabled(sync_service_))) {
shadow_backend()->GetAutofillableLoginsAsync(
base::BindOnce(&ShadowTrafficMetricsRecorder<
LoginsResultOrErrorImpl>::RecordShadowResult,
handler));
}
}
void PasswordStoreProxyBackend::GetAllLoginsForAccountAsync(
absl::optional<std::string> account,
LoginsOrErrorReply callback) {
NOTREACHED();
}
void PasswordStoreProxyBackend::FillMatchingLoginsAsync(
LoginsOrErrorReply callback,
bool include_psl,
const std::vector<PasswordFormDigest>& forms) {
auto handler = base::MakeRefCounted<
ShadowTrafficMetricsRecorder<LoginsResultOrErrorImpl>>(
MethodName("FillMatchingLoginsAsync"));
LoginsOrErrorReply result_callback;
if (UsesAndroidBackendAsMainBackend()) {
// Lambda is used to reorder |FillMatchingLoginsAsync| arguments so all but
// the |reply_callback| could be binded.
auto execute_on_built_in_backend = base::BindOnce(
[](PasswordStoreBackend* backend, bool include_psl,
const std::vector<PasswordFormDigest>& forms,
LoginsOrErrorReply reply_callback) {
backend->FillMatchingLoginsAsync(std::move(reply_callback),
include_psl, forms);
},
base::Unretained(built_in_backend_), include_psl, forms);
result_callback = base::BindOnce(
&PasswordStoreProxyBackend::MaybeFallbackOnOperation<
LoginsResultOrError>,
weak_ptr_factory_.GetWeakPtr(), std::move(execute_on_built_in_backend),
MethodName("FillMatchingLoginsAsync"), std::move(callback));
} else {
result_callback = std::move(callback);
}
main_backend()->FillMatchingLoginsAsync(
base::BindOnce(&ShadowTrafficMetricsRecorder<
LoginsResultOrErrorImpl>::RecordMainResult,
handler)
.Then(std::move(result_callback)),
include_psl, forms);
if (ShouldExecuteReadOperationsOnShadowBackend(
prefs_, IsPasswordSyncEnabled(sync_service_))) {
shadow_backend()->FillMatchingLoginsAsync(
base::BindOnce(&ShadowTrafficMetricsRecorder<
LoginsResultOrErrorImpl>::RecordShadowResult,
handler),
include_psl, forms);
}
}
void PasswordStoreProxyBackend::AddLoginAsync(
const PasswordForm& form,
PasswordChangesOrErrorReply callback) {
auto handler = base::MakeRefCounted<
ShadowTrafficMetricsRecorder<PasswordChangesOrErrorImpl>>(
MethodName("AddLoginAsync"));
PasswordChangesOrErrorReply result_callback;
if (UsesAndroidBackendAsMainBackend()) {
auto execute_on_built_in_backend =
base::BindOnce(&PasswordStoreBackend::AddLoginAsync,
base::Unretained(built_in_backend_), form);
result_callback = base::BindOnce(
&PasswordStoreProxyBackend::MaybeFallbackOnOperation<
PasswordChangesOrError>,
weak_ptr_factory_.GetWeakPtr(), std::move(execute_on_built_in_backend),
MethodName("AddLoginAsync"), std::move(callback));
} else {
result_callback = std::move(callback);
}
main_backend()->AddLoginAsync(
form, base::BindOnce(&ShadowTrafficMetricsRecorder<
PasswordChangesOrErrorImpl>::RecordMainResult,
handler)
.Then(std::move(result_callback)));
if (ShouldExecuteModifyOperationsOnShadowBackend(
prefs_, IsPasswordSyncEnabled(sync_service_))) {
shadow_backend()->AddLoginAsync(
form,
base::BindOnce(&ShadowTrafficMetricsRecorder<
PasswordChangesOrErrorImpl>::RecordShadowResult,
handler));
}
}
void PasswordStoreProxyBackend::UpdateLoginAsync(
const PasswordForm& form,
PasswordChangesOrErrorReply callback) {
auto handler = base::MakeRefCounted<
ShadowTrafficMetricsRecorder<PasswordChangesOrErrorImpl>>(
MethodName("UpdateLoginAsync"));
PasswordChangesOrErrorReply result_callback;
if (UsesAndroidBackendAsMainBackend()) {
auto execute_on_built_in_backend =
base::BindOnce(&PasswordStoreBackend::UpdateLoginAsync,
base::Unretained(built_in_backend_), form);
result_callback = base::BindOnce(
&PasswordStoreProxyBackend::MaybeFallbackOnOperation<
PasswordChangesOrError>,
weak_ptr_factory_.GetWeakPtr(), std::move(execute_on_built_in_backend),
MethodName("UpdateLoginAsync"), std::move(callback));
} else {
result_callback = std::move(callback);
}
main_backend()->UpdateLoginAsync(
form, base::BindOnce(&ShadowTrafficMetricsRecorder<
PasswordChangesOrErrorImpl>::RecordMainResult,
handler)
.Then(std::move(result_callback)));
if (ShouldExecuteModifyOperationsOnShadowBackend(
prefs_, IsPasswordSyncEnabled(sync_service_))) {
shadow_backend()->UpdateLoginAsync(
form,
base::BindOnce(&ShadowTrafficMetricsRecorder<
PasswordChangesOrErrorImpl>::RecordShadowResult,
handler));
}
}
void PasswordStoreProxyBackend::RemoveLoginAsync(
const PasswordForm& form,
PasswordChangesOrErrorReply callback) {
auto handler = base::MakeRefCounted<
ShadowTrafficMetricsRecorder<PasswordChangesOrErrorImpl>>(
MethodName("RemoveLoginAsync"));
main_backend()->RemoveLoginAsync(
form, base::BindOnce(&ShadowTrafficMetricsRecorder<
PasswordChangesOrErrorImpl>::RecordMainResult,
handler)
.Then(std::move(callback)));
if (ShouldExecuteDeletionsOnShadowBackend(
prefs_, IsPasswordSyncEnabled(sync_service_))) {
shadow_backend()->RemoveLoginAsync(
form,
base::BindOnce(&ShadowTrafficMetricsRecorder<
PasswordChangesOrErrorImpl>::RecordShadowResult,
handler));
}
}
void PasswordStoreProxyBackend::RemoveLoginsByURLAndTimeAsync(
const base::RepeatingCallback<bool(const GURL&)>& url_filter,
base::Time delete_begin,
base::Time delete_end,
base::OnceCallback<void(bool)> sync_completion,
PasswordChangesOrErrorReply callback) {
// The `sync_completion` callback is only relevant for account passwords
// which don't exist on Android, so it is not passed in and can be ignored
// later.
CHECK(!sync_completion);
auto handler = base::MakeRefCounted<
ShadowTrafficMetricsRecorder<PasswordChangesOrErrorImpl>>(
MethodName("RemoveLoginsByURLAndTimeAsync"));
main_backend()->RemoveLoginsByURLAndTimeAsync(
url_filter, delete_begin, delete_end, base::NullCallback(),
base::BindOnce(&ShadowTrafficMetricsRecorder<
PasswordChangesOrErrorImpl>::RecordMainResult,
handler)
.Then(std::move(callback)));
if (ShouldExecuteDeletionsOnShadowBackend(
prefs_, IsPasswordSyncEnabled(sync_service_))) {
shadow_backend()->RemoveLoginsByURLAndTimeAsync(
url_filter, std::move(delete_begin), std::move(delete_end),
base::NullCallback(),
base::BindOnce(&ShadowTrafficMetricsRecorder<
PasswordChangesOrErrorImpl>::RecordShadowResult,
handler));
}
}
void PasswordStoreProxyBackend::RemoveLoginsCreatedBetweenAsync(
base::Time delete_begin,
base::Time delete_end,
PasswordChangesOrErrorReply callback) {
auto handler = base::MakeRefCounted<
ShadowTrafficMetricsRecorder<PasswordChangesOrErrorImpl>>(
MethodName("RemoveLoginsCreatedBetweenAsync"));
main_backend()->RemoveLoginsCreatedBetweenAsync(
delete_begin, delete_end,
base::BindOnce(&ShadowTrafficMetricsRecorder<
PasswordChangesOrErrorImpl>::RecordMainResult,
handler)
.Then(std::move(callback)));
if (ShouldExecuteDeletionsOnShadowBackend(
prefs_, IsPasswordSyncEnabled(sync_service_))) {
shadow_backend()->RemoveLoginsCreatedBetweenAsync(
std::move(delete_begin), std::move(delete_end),
base::BindOnce(&ShadowTrafficMetricsRecorder<
PasswordChangesOrErrorImpl>::RecordShadowResult,
handler));
}
}
void PasswordStoreProxyBackend::DisableAutoSignInForOriginsAsync(
const base::RepeatingCallback<bool(const GURL&)>& origin_filter,
base::OnceClosure completion) {
// TODO(https://crbug.com/1278807): Implement error handling, when actual
// store changes will be received from the store.
main_backend()->DisableAutoSignInForOriginsAsync(origin_filter,
std::move(completion));
if (ShouldExecuteModifyOperationsOnShadowBackend(
prefs_, IsPasswordSyncEnabled(sync_service_))) {
shadow_backend()->DisableAutoSignInForOriginsAsync(
origin_filter,
/*completion=*/base::DoNothing());
}
}
SmartBubbleStatsStore* PasswordStoreProxyBackend::GetSmartBubbleStatsStore() {
return main_backend()->GetSmartBubbleStatsStore();
}
FieldInfoStore* PasswordStoreProxyBackend::GetFieldInfoStore() {
return main_backend()->GetFieldInfoStore();
}
std::unique_ptr<syncer::ProxyModelTypeControllerDelegate>
PasswordStoreProxyBackend::CreateSyncControllerDelegate() {
if (base::FeatureList::IsEnabled(
features::kUnifiedPasswordManagerSyncUsingAndroidBackendOnly)) {
// The android backend (PasswordStoreAndroidBackend) creates a controller
// delegate that prevents sync from actually communicating with the sync
// server using the built in SyncEngine.
return android_backend_->CreateSyncControllerDelegate();
}
return built_in_backend_->CreateSyncControllerDelegate();
}
void PasswordStoreProxyBackend::ClearAllLocalPasswords() {
NOTIMPLEMENTED();
}
void PasswordStoreProxyBackend::OnSyncServiceInitialized(
syncer::SyncService* sync_service) {
sync_service_ = sync_service;
android_backend_->OnSyncServiceInitialized(sync_service);
}
template <typename ResultT>
void PasswordStoreProxyBackend::MaybeFallbackOnOperation(
base::OnceCallback<void(base::OnceCallback<void(ResultT)> callback)>
retry_callback,
const MethodName& method_name,
base::OnceCallback<void(ResultT)> result_callback,
ResultT result) {
if (absl::holds_alternative<PasswordStoreBackendError>(result) &&
ShouldErrorResultInFallback(
absl::get<PasswordStoreBackendError>(result))) {
base::UmaHistogramBoolean(GetFallbackMetricNameForMethod(method_name),
true);
std::move(retry_callback).Run(std::move(result_callback));
} else {
std::move(result_callback).Run(std::move(result));
}
}
PasswordStoreBackend* PasswordStoreProxyBackend::main_backend() {
return UsesAndroidBackendAsMainBackend() ? android_backend_
: built_in_backend_;
}
PasswordStoreBackend* PasswordStoreProxyBackend::shadow_backend() {
return UsesAndroidBackendAsMainBackend() ? built_in_backend_
: android_backend_;
}
void PasswordStoreProxyBackend::OnRemoteFormChangesReceived(
CallbackOriginatesFromAndroidBackend originates_from_android,
RemoteChangesReceived remote_form_changes_received,
absl::optional<PasswordStoreChangeList> changes) {
// `remote_form_changes_received` is used to inform observers about changes in
// the backend. This check guarantees observers are informed only about
// changes in the main backend.
if (originates_from_android.value() == UsesAndroidBackendAsMainBackend()) {
remote_form_changes_received.Run(std::move(changes));
}
}
bool PasswordStoreProxyBackend::UsesAndroidBackendAsMainBackend() {
if (prefs_->GetBoolean(
prefs::kUnenrolledFromGoogleMobileServicesDueToErrors)) {
return false;
}
if (!IsPasswordSyncEnabled(sync_service_))
return false;
return true;
}
} // namespace password_manager