blob: 9c3d7f1d698142a253a657134b7876e1f8b517ff [file] [log] [blame]
// Copyright 2012 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/sync_preferences/pref_service_syncable.h"
#include <utility>
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/observer_list.h"
#include "base/scoped_observation.h"
#include "components/metrics/demographics/user_demographics.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/in_memory_pref_store.h"
#include "components/prefs/overlay_user_pref_store.h"
#include "components/prefs/pref_notifier_impl.h"
#include "components/prefs/pref_registry.h"
#include "components/prefs/pref_value_store.h"
#include "components/signin/public/base/signin_switches.h"
#include "components/sync/base/features.h"
#include "components/sync/service/sync_service.h"
#include "components/sync_preferences/dual_layer_user_pref_store.h"
#include "components/sync_preferences/pref_model_associator.h"
#include "components/sync_preferences/pref_service_syncable_observer.h"
#include "components/sync_preferences/synced_pref_observer.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "ash/constants/ash_features.h"
#endif
namespace sync_preferences {
class PrefServiceSyncable::DemographicsPrefsClearer
: public syncer::SyncServiceObserver {
public:
DemographicsPrefsClearer(PrefService* pref_service,
syncer::SyncService* sync_service)
: pref_service_(pref_service) {
if (sync_service) {
sync_observation_.Observe(sync_service);
}
}
void OnStateChanged(syncer::SyncService* sync) override {
switch (sync->GetTransportState()) {
case syncer::SyncService::TransportState::DISABLED:
metrics::ClearDemographicsPrefs(pref_service_);
break;
case syncer::SyncService::TransportState::PAUSED:
case syncer::SyncService::TransportState::START_DEFERRED:
case syncer::SyncService::TransportState::INITIALIZING:
case syncer::SyncService::TransportState::PENDING_DESIRED_CONFIGURATION:
case syncer::SyncService::TransportState::CONFIGURING:
case syncer::SyncService::TransportState::ACTIVE:
break;
}
}
void OnSyncShutdown(syncer::SyncService* sync) override {
sync_observation_.Reset();
}
private:
const raw_ptr<PrefService> pref_service_;
base::ScopedObservation<syncer::SyncService, syncer::SyncServiceObserver>
sync_observation_{this};
};
PrefServiceSyncable::PrefServiceSyncable(
std::unique_ptr<PrefNotifierImpl> pref_notifier,
std::unique_ptr<PrefValueStore> pref_value_store,
scoped_refptr<PersistentPrefStore> user_prefs,
scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry,
scoped_refptr<PrefModelAssociatorClient> pref_model_associator_client,
base::RepeatingCallback<void(PersistentPrefStore::PrefReadError)>
read_error_callback,
bool async)
: PrefService(std::move(pref_notifier),
std::move(pref_value_store),
user_prefs,
pref_registry,
std::move(read_error_callback),
async),
pref_sync_associator_(pref_model_associator_client,
user_prefs,
syncer::PREFERENCES),
priority_pref_sync_associator_(pref_model_associator_client,
user_prefs,
syncer::PRIORITY_PREFERENCES),
#if BUILDFLAG(IS_CHROMEOS)
os_pref_sync_associator_(pref_model_associator_client,
user_prefs,
syncer::OS_PREFERENCES),
os_priority_pref_sync_associator_(pref_model_associator_client,
user_prefs,
syncer::OS_PRIORITY_PREFERENCES),
#endif
pref_registry_(std::move(pref_registry)) {
ConnectAssociatorsAndRegisterPreferences();
}
PrefServiceSyncable::PrefServiceSyncable(
std::unique_ptr<PrefNotifierImpl> pref_notifier,
std::unique_ptr<PrefValueStore> pref_value_store,
scoped_refptr<DualLayerUserPrefStore> dual_layer_user_prefs,
scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry,
scoped_refptr<PrefModelAssociatorClient> pref_model_associator_client,
base::RepeatingCallback<void(PersistentPrefStore::PrefReadError)>
read_error_callback,
bool async)
: PrefService(std::move(pref_notifier),
std::move(pref_value_store),
dual_layer_user_prefs,
pref_registry,
std::move(read_error_callback),
async),
pref_sync_associator_(pref_model_associator_client,
dual_layer_user_prefs,
syncer::PREFERENCES),
priority_pref_sync_associator_(pref_model_associator_client,
dual_layer_user_prefs,
syncer::PRIORITY_PREFERENCES),
#if BUILDFLAG(IS_CHROMEOS)
os_pref_sync_associator_(pref_model_associator_client,
dual_layer_user_prefs,
syncer::OS_PREFERENCES),
os_priority_pref_sync_associator_(pref_model_associator_client,
dual_layer_user_prefs,
syncer::OS_PRIORITY_PREFERENCES),
#endif
pref_registry_(std::move(pref_registry)),
dual_layer_user_prefs_(std::move(dual_layer_user_prefs)) {
CHECK(
base::FeatureList::IsEnabled(switches::kEnablePreferencesAccountStorage));
CHECK(dual_layer_user_prefs_);
ConnectAssociatorsAndRegisterPreferences();
}
void PrefServiceSyncable::ConnectAssociatorsAndRegisterPreferences() {
pref_sync_associator_.SetPrefService(this);
priority_pref_sync_associator_.SetPrefService(this);
#if BUILDFLAG(IS_CHROMEOS)
os_pref_sync_associator_.SetPrefService(this);
os_priority_pref_sync_associator_.SetPrefService(this);
#endif
// Add already-registered syncable preferences to PrefModelAssociator.
for (const auto& [path, value] : *pref_registry_) {
AddRegisteredSyncablePreference(path,
pref_registry_->GetRegistrationFlags(path));
}
// Watch for syncable preferences registered after this point.
pref_registry_->SetSyncableRegistrationCallback(base::BindRepeating(
&PrefServiceSyncable::AddRegisteredSyncablePreference,
base::Unretained(this)));
}
PrefServiceSyncable::~PrefServiceSyncable() {
// Remove our callback from the registry, since it may outlive us.
pref_registry_->SetSyncableRegistrationCallback(base::NullCallback());
}
std::unique_ptr<PrefServiceSyncable>
PrefServiceSyncable::CreateIncognitoPrefService(
PrefStore* incognito_extension_pref_store,
const std::vector<const char*>& persistent_pref_names) {
pref_service_forked_ = true;
auto pref_notifier = std::make_unique<PrefNotifierImpl>();
scoped_refptr<user_prefs::PrefRegistrySyncable> forked_registry =
pref_registry_->ForkForIncognito();
auto overlay = base::MakeRefCounted<InMemoryPrefStore>();
auto incognito_pref_store = base::MakeRefCounted<OverlayUserPrefStore>(
overlay.get(), user_pref_store_.get());
for (const char* persistent_pref_name : persistent_pref_names) {
incognito_pref_store->RegisterPersistentPref(persistent_pref_name);
}
auto pref_value_store = pref_value_store_->CloneAndSpecialize(
nullptr, // managed
nullptr, // supervised_user
incognito_extension_pref_store,
nullptr, // command_line_prefs
incognito_pref_store.get(),
nullptr, // recommended
forked_registry->defaults().get(), pref_notifier.get());
return std::make_unique<PrefServiceSyncable>(
std::move(pref_notifier), std::move(pref_value_store),
incognito_pref_store,
std::move(forked_registry), pref_sync_associator_.client(),
read_error_callback_, false);
}
bool PrefServiceSyncable::IsSyncing() {
return pref_sync_associator_.models_associated();
}
bool PrefServiceSyncable::IsPrioritySyncing() {
return priority_pref_sync_associator_.models_associated();
}
#if BUILDFLAG(IS_CHROMEOS)
bool PrefServiceSyncable::AreOsPrefsSyncing() {
return os_pref_sync_associator_.models_associated();
}
bool PrefServiceSyncable::AreOsPriorityPrefsSyncing() {
return os_priority_pref_sync_associator_.models_associated();
}
#endif // BUILDFLAG(IS_CHROMEOS)
void PrefServiceSyncable::AddObserver(PrefServiceSyncableObserver* observer) {
observer_list_.AddObserver(observer);
}
void PrefServiceSyncable::RemoveObserver(
PrefServiceSyncableObserver* observer) {
observer_list_.RemoveObserver(observer);
}
syncer::SyncableService* PrefServiceSyncable::GetSyncableService(
const syncer::DataType& type) {
switch (type) {
case syncer::PREFERENCES:
return &pref_sync_associator_;
case syncer::PRIORITY_PREFERENCES:
return &priority_pref_sync_associator_;
#if BUILDFLAG(IS_CHROMEOS)
case syncer::OS_PREFERENCES:
return &os_pref_sync_associator_;
case syncer::OS_PRIORITY_PREFERENCES:
return &os_priority_pref_sync_associator_;
#endif
default:
NOTREACHED() << "invalid data type: " << type;
}
}
void PrefServiceSyncable::UpdateCommandLinePrefStore(
PrefStore* cmd_line_store) {
// If |pref_service_forked_| is true, then this PrefService and the forked
// copies will be out of sync.
DCHECK(!pref_service_forked_);
PrefService::UpdateCommandLinePrefStore(cmd_line_store);
}
void PrefServiceSyncable::AddSyncedPrefObserver(const std::string& name,
SyncedPrefObserver* observer) {
pref_sync_associator_.AddSyncedPrefObserver(name, observer);
priority_pref_sync_associator_.AddSyncedPrefObserver(name, observer);
#if BUILDFLAG(IS_CHROMEOS)
os_pref_sync_associator_.AddSyncedPrefObserver(name, observer);
os_priority_pref_sync_associator_.AddSyncedPrefObserver(name, observer);
#endif
}
void PrefServiceSyncable::RemoveSyncedPrefObserver(
const std::string& name,
SyncedPrefObserver* observer) {
pref_sync_associator_.RemoveSyncedPrefObserver(name, observer);
priority_pref_sync_associator_.RemoveSyncedPrefObserver(name, observer);
#if BUILDFLAG(IS_CHROMEOS)
os_pref_sync_associator_.RemoveSyncedPrefObserver(name, observer);
os_priority_pref_sync_associator_.RemoveSyncedPrefObserver(name, observer);
#endif
}
void PrefServiceSyncable::AddRegisteredSyncablePreference(std::string_view path,
uint32_t flags) {
DCHECK(FindPreference(path));
if (flags & user_prefs::PrefRegistrySyncable::SYNCABLE_PREF) {
pref_sync_associator_.RegisterPref(path);
return;
}
if (flags & user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF) {
priority_pref_sync_associator_.RegisterPref(path);
return;
}
#if BUILDFLAG(IS_CHROMEOS)
if (flags & user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PREF) {
os_pref_sync_associator_.RegisterPref(path);
return;
}
if (flags & user_prefs::PrefRegistrySyncable::SYNCABLE_OS_PRIORITY_PREF) {
os_priority_pref_sync_associator_.RegisterPref(path);
return;
}
#endif
}
base::Value::Type PrefServiceSyncable::GetRegisteredPrefType(
std::string_view pref_name) const {
const Preference* pref = FindPreference(pref_name);
DCHECK(pref);
return pref->GetType();
}
void PrefServiceSyncable::OnIsSyncingChanged() {
for (auto& observer : observer_list_) {
observer.OnIsSyncingChanged();
}
}
uint32_t PrefServiceSyncable::GetWriteFlags(std::string_view pref_name) const {
const Preference* pref = FindPreference(pref_name);
return PrefService::GetWriteFlags(pref);
}
void PrefServiceSyncable::OnSyncServiceInitialized(
syncer::SyncService* sync_service) {
if (dual_layer_user_prefs_) {
dual_layer_user_prefs_->OnSyncServiceInitialized(sync_service);
}
demographics_prefs_clearer_ =
std::make_unique<DemographicsPrefsClearer>(this, sync_service);
}
} // namespace sync_preferences