blob: 1523882ec57c127b449c5ef12d5a12ce9bccc349 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/unified_consent/unified_consent_service.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/scoped_observer.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "build/build_config.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/sync/base/user_selectable_type.h"
#include "components/sync/driver/sync_service.h"
#include "components/sync/driver/sync_user_settings.h"
#include "components/sync_preferences/pref_service_syncable.h"
#include "components/unified_consent/feature.h"
#include "components/unified_consent/pref_names.h"
namespace unified_consent {
UnifiedConsentService::UnifiedConsentService(
sync_preferences::PrefServiceSyncable* pref_service,
identity::IdentityManager* identity_manager,
syncer::SyncService* sync_service,
const std::vector<std::string>& service_pref_names)
: pref_service_(pref_service),
identity_manager_(identity_manager),
sync_service_(sync_service),
service_pref_names_(service_pref_names) {
DCHECK(pref_service_);
DCHECK(identity_manager_);
DCHECK(sync_service_);
if (GetMigrationState() == MigrationState::kNotInitialized)
MigrateProfileToUnifiedConsent();
pref_service_->AddObserver(this);
identity_manager_->AddObserver(this);
sync_service_->AddObserver(this);
}
UnifiedConsentService::~UnifiedConsentService() {}
// static
void UnifiedConsentService::RegisterPrefs(
user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterBooleanPref(prefs::kUrlKeyedAnonymizedDataCollectionEnabled,
false);
registry->RegisterIntegerPref(
prefs::kUnifiedConsentMigrationState,
static_cast<int>(MigrationState::kNotInitialized));
}
// static
void UnifiedConsentService::RollbackIfNeeded(
PrefService* user_pref_service,
syncer::SyncService* sync_service) {
DCHECK(user_pref_service);
if (user_pref_service->GetInteger(prefs::kUnifiedConsentMigrationState) ==
static_cast<int>(MigrationState::kNotInitialized)) {
// If there was no migration yet, nothing has to be rolled back.
return;
}
// Clear all unified consent prefs.
user_pref_service->ClearPref(prefs::kUrlKeyedAnonymizedDataCollectionEnabled);
user_pref_service->ClearPref(prefs::kUnifiedConsentMigrationState);
}
void UnifiedConsentService::SetUrlKeyedAnonymizedDataCollectionEnabled(
bool enabled) {
if (GetMigrationState() != MigrationState::kCompleted)
SetMigrationState(MigrationState::kCompleted);
pref_service_->SetBoolean(prefs::kUrlKeyedAnonymizedDataCollectionEnabled,
enabled);
}
void UnifiedConsentService::Shutdown() {
pref_service_->RemoveObserver(this);
identity_manager_->RemoveObserver(this);
sync_service_->RemoveObserver(this);
}
void UnifiedConsentService::OnPrimaryAccountCleared(
const CoreAccountInfo& account_info) {
// By design, clearing the primary account disables URL-keyed data collection.
SetUrlKeyedAnonymizedDataCollectionEnabled(false);
}
void UnifiedConsentService::OnStateChanged(syncer::SyncService* sync) {
// Start observing pref changes when the user enters sync setup.
// Note: Only |sync->IsSetupInProgress()| is used (i.e. no check for
// |IsFirstSetupComplete()|), because on Android |SetFirstSetupComplete()| is
// called automatically during the first setup, i.e. the value could change in
// the meantime.
if (sync->IsSetupInProgress() && !pref_service_->IsSyncing()) {
StartObservingServicePrefChanges();
} else {
StopObservingServicePrefChanges();
// If the user cancelled the sync setup, clear all observed changes.
if (!sync->CanSyncFeatureStart())
service_pref_changes_.clear();
}
if (!sync_service_->CanSyncFeatureStart() ||
!sync_service_->IsEngineInitialized()) {
return;
}
if (GetMigrationState() == MigrationState::kInProgressWaitForSyncInit)
UpdateSettingsForMigration();
}
void UnifiedConsentService::OnIsSyncingChanged() {
if (pref_service_->IsSyncing() && !service_pref_changes_.empty()) {
// Re-apply all observed service pref changes.
// If any service prefs had a value coming in through Sync, then that
// would've overridden any changes that the user made during the first sync
// setup. So re-apply the local changes to make sure they stick.
for (const auto& pref_change : service_pref_changes_) {
pref_service_->Set(pref_change.first, pref_change.second);
}
service_pref_changes_.clear();
}
}
void UnifiedConsentService::StartObservingServicePrefChanges() {
if (!service_pref_change_registrar_.IsEmpty())
return;
service_pref_change_registrar_.Init(pref_service_);
for (const std::string& pref_name : service_pref_names_) {
service_pref_change_registrar_.Add(
pref_name,
base::BindRepeating(&UnifiedConsentService::ServicePrefChanged,
base::Unretained(this)));
}
}
void UnifiedConsentService::StopObservingServicePrefChanges() {
service_pref_change_registrar_.RemoveAll();
}
void UnifiedConsentService::ServicePrefChanged(const std::string& name) {
DCHECK(sync_service_->IsSetupInProgress());
const base::Value* value = pref_service_->Get(name);
DCHECK(value);
service_pref_changes_[name] = value->Clone();
}
MigrationState UnifiedConsentService::GetMigrationState() {
int migration_state_int =
pref_service_->GetInteger(prefs::kUnifiedConsentMigrationState);
DCHECK_LE(static_cast<int>(MigrationState::kNotInitialized),
migration_state_int);
DCHECK_GE(static_cast<int>(MigrationState::kCompleted), migration_state_int);
return static_cast<MigrationState>(migration_state_int);
}
void UnifiedConsentService::SetMigrationState(MigrationState migration_state) {
pref_service_->SetInteger(prefs::kUnifiedConsentMigrationState,
static_cast<int>(migration_state));
}
void UnifiedConsentService::MigrateProfileToUnifiedConsent() {
DCHECK_EQ(GetMigrationState(), MigrationState::kNotInitialized);
if (!identity_manager_->HasPrimaryAccount()) {
SetMigrationState(MigrationState::kCompleted);
return;
}
UpdateSettingsForMigration();
}
void UnifiedConsentService::UpdateSettingsForMigration() {
if (!sync_service_->IsEngineInitialized()) {
SetMigrationState(MigrationState::kInProgressWaitForSyncInit);
return;
}
// Set URL-keyed anonymized metrics to the state it had before unified
// consent.
bool url_keyed_metrics_enabled =
sync_service_->IsSyncFeatureEnabled() &&
sync_service_->GetUserSettings()->GetSelectedTypes().Has(
syncer::UserSelectableType::kHistory) &&
!sync_service_->GetUserSettings()->IsUsingSecondaryPassphrase();
SetUrlKeyedAnonymizedDataCollectionEnabled(url_keyed_metrics_enabled);
}
} // namespace unified_consent