blob: cfed849e32f591514cb7b9b322b22456f85e33be [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/metrics/histogram_macros.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_service.h"
#include "components/sync/base/model_type.h"
#include "components/sync/base/sync_prefs.h"
#include "components/sync/driver/sync_service.h"
#include "components/unified_consent/feature.h"
#include "components/unified_consent/pref_names.h"
#include "components/unified_consent/unified_consent_service_client.h"
namespace unified_consent {
UnifiedConsentService::UnifiedConsentService(
std::unique_ptr<UnifiedConsentServiceClient> service_client,
PrefService* pref_service,
identity::IdentityManager* identity_manager,
syncer::SyncService* sync_service)
: service_client_(std::move(service_client)),
pref_service_(pref_service),
identity_manager_(identity_manager),
sync_service_(sync_service) {
DCHECK(service_client_);
DCHECK(pref_service_);
DCHECK(identity_manager_);
DCHECK(sync_service_);
if (GetMigrationState() == MigrationState::NOT_INITIALIZED)
MigrateProfileToUnifiedConsent();
service_client_->AddObserver(this);
identity_manager_->AddObserver(this);
sync_service_->AddObserver(this);
pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
pref_change_registrar_->Init(pref_service);
pref_change_registrar_->Add(
prefs::kUnifiedConsentGiven,
base::BindRepeating(
&UnifiedConsentService::OnUnifiedConsentGivenPrefChanged,
base::Unretained(this)));
// If somebody disabled any of the non-personalized services while Chrome
// wasn't running, disable unified consent.
if (!AreAllNonPersonalizedServicesEnabled() && IsUnifiedConsentGiven()) {
SetUnifiedConsentGiven(false);
}
}
UnifiedConsentService::~UnifiedConsentService() {}
// static
void UnifiedConsentService::RegisterPrefs(
user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterBooleanPref(prefs::kUrlKeyedAnonymizedDataCollectionEnabled,
false);
registry->RegisterBooleanPref(prefs::kUnifiedConsentGiven, false);
registry->RegisterIntegerPref(
prefs::kUnifiedConsentMigrationState,
static_cast<int>(MigrationState::NOT_INITIALIZED));
}
void UnifiedConsentService::SetUnifiedConsentGiven(bool unified_consent_given) {
pref_service_->SetBoolean(prefs::kUnifiedConsentGiven, unified_consent_given);
}
bool UnifiedConsentService::IsUnifiedConsentGiven() {
return pref_service_->GetBoolean(prefs::kUnifiedConsentGiven);
}
MigrationState UnifiedConsentService::GetMigrationState() {
int migration_state_int =
pref_service_->GetInteger(prefs::kUnifiedConsentMigrationState);
DCHECK_LE(static_cast<int>(MigrationState::NOT_INITIALIZED),
migration_state_int);
DCHECK_GE(static_cast<int>(MigrationState::COMPLETED), migration_state_int);
return static_cast<MigrationState>(migration_state_int);
}
bool UnifiedConsentService::ShouldShowConsentBump() {
if (base::FeatureList::IsEnabled(unified_consent::kForceUnifiedConsentBump))
return true;
return GetMigrationState() ==
MigrationState::IN_PROGRESS_SHOULD_SHOW_CONSENT_BUMP;
}
void UnifiedConsentService::MarkMigrationComplete(
ConsentBumpSuppressReason suppress_reason) {
pref_service_->SetInteger(prefs::kUnifiedConsentMigrationState,
static_cast<int>(MigrationState::COMPLETED));
// Record the suppress reason for the consent bump. After the migration is
// marked complete, the consent bump should not be shown anymore. Note:
// |suppress_reason| can be kNone in case the consent bump was actually shown.
RecordConsentBumpSuppressReason(suppress_reason);
}
void UnifiedConsentService::RecordConsentBumpSuppressReason(
ConsentBumpSuppressReason suppress_reason) {
UMA_HISTOGRAM_ENUMERATION("UnifiedConsent.ConsentBump.SuppressReason",
suppress_reason);
}
void UnifiedConsentService::Shutdown() {
service_client_->RemoveObserver(this);
identity_manager_->RemoveObserver(this);
sync_service_->RemoveObserver(this);
}
void UnifiedConsentService::OnServiceStateChanged(Service service) {
// Unified consent is disabled when any of its dependent services gets
// disabled.
if (service_client_->GetServiceState(service) == ServiceState::kDisabled)
SetUnifiedConsentGiven(false);
}
void UnifiedConsentService::OnPrimaryAccountCleared(
const AccountInfo& account_info) {
// When signing out, the unfied consent is revoked.
pref_service_->SetBoolean(prefs::kUnifiedConsentGiven, false);
// By design, signing out of Chrome automatically disables off-by-default
// services.
pref_service_->SetBoolean(prefs::kUrlKeyedAnonymizedDataCollectionEnabled,
false);
service_client_->SetServiceEnabled(Service::kSafeBrowsingExtendedReporting,
false);
service_client_->SetServiceEnabled(Service::kSpellCheck, false);
switch (GetMigrationState()) {
case MigrationState::NOT_INITIALIZED:
NOTREACHED();
break;
case MigrationState::IN_PROGRESS_SHOULD_SHOW_CONSENT_BUMP:
// Only users that were signed in and have opted into sync before unified
// consent are eligible to see the unified consent bump. Since the user
// signs out of Chrome, mark the migration to unified consent as complete.
MarkMigrationComplete(ConsentBumpSuppressReason::kUserSignedOut);
break;
case MigrationState::COMPLETED:
break;
}
}
void UnifiedConsentService::OnStateChanged(syncer::SyncService* sync) {
syncer::SyncPrefs sync_prefs(pref_service_);
if (IsUnifiedConsentGiven() != sync_prefs.HasKeepEverythingSynced()) {
// Make sync-everything consistent with the |kUnifiedConsentGiven| pref.
SetSyncEverythingIfPossible(IsUnifiedConsentGiven());
}
}
void UnifiedConsentService::OnUnifiedConsentGivenPrefChanged() {
bool enabled = pref_service_->GetBoolean(prefs::kUnifiedConsentGiven);
if (!enabled) {
if (identity_manager_->HasPrimaryAccount()) {
// Sync-everything is set to false, so the user can select individual
// sync data types.
SetSyncEverythingIfPossible(false);
}
return;
}
DCHECK(!sync_service_->HasDisableReason(
syncer::SyncService::DISABLE_REASON_PLATFORM_OVERRIDE));
DCHECK(!sync_service_->HasDisableReason(
syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY));
DCHECK(identity_manager_->HasPrimaryAccount());
DCHECK_LT(MigrationState::NOT_INITIALIZED, GetMigrationState());
// If the user opts into unified consent throught settings, the consent bump
// doesn't need to be shown. Therefore mark the migration as complete.
if (GetMigrationState() != MigrationState::COMPLETED)
MarkMigrationComplete(ConsentBumpSuppressReason::kSettingsOptIn);
// Enable all sync data types if possible, otherwise they will be enabled with
// |OnStateChanged| once sync is active;
SetSyncEverythingIfPossible(true);
// Enable all non-personalized services.
pref_service_->SetBoolean(prefs::kUrlKeyedAnonymizedDataCollectionEnabled,
true);
// Inform client to enable non-personalized services.
for (int i = 0; i <= static_cast<int>(Service::kLast); ++i) {
Service service = static_cast<Service>(i);
if (service_client_->GetServiceState(service) !=
ServiceState::kNotSupported) {
service_client_->SetServiceEnabled(service, true);
}
}
}
void UnifiedConsentService::SetSyncEverythingIfPossible(bool sync_everything) {
syncer::SyncPrefs sync_prefs(pref_service_);
if (sync_everything == sync_prefs.HasKeepEverythingSynced())
return;
if (!sync_service_->IsEngineInitialized())
return;
if (sync_everything) {
autofill::prefs::SetPaymentsIntegrationEnabled(pref_service_, true);
sync_service_->OnUserChoseDatatypes(sync_everything,
syncer::UserSelectableTypes());
} else {
syncer::ModelTypeSet preferred = sync_service_->GetPreferredDataTypes();
preferred.RetainAll(syncer::UserSelectableTypes());
sync_service_->OnUserChoseDatatypes(false, preferred);
}
}
void UnifiedConsentService::MigrateProfileToUnifiedConsent() {
DCHECK_EQ(GetMigrationState(), MigrationState::NOT_INITIALIZED);
DCHECK(!IsUnifiedConsentGiven());
if (!identity_manager_->HasPrimaryAccount()) {
MarkMigrationComplete(ConsentBumpSuppressReason::kNotSignedIn);
return;
}
bool is_syncing_everything =
syncer::SyncPrefs(pref_service_).HasKeepEverythingSynced();
if (!is_syncing_everything) {
MarkMigrationComplete(ConsentBumpSuppressReason::kSyncEverythingOff);
return;
}
// Set sync-everything to false to match the |kUnifiedConsentGiven| pref.
// Note: If the sync engine isn't initialized at this point,
// sync-everything is set to false once the sync engine state changes.
// Sync-everything can then be set to true again after going through the
// consent bump and opting into unified consent.
SetSyncEverythingIfPossible(false);
if (!AreAllOnByDefaultPrivacySettingsOn()) {
MarkMigrationComplete(ConsentBumpSuppressReason::kPrivacySettingOff);
return;
}
// When the user was syncing everything, and all on-by-default privacy
// settings were on, the consent bump should be shown when this is possible.
pref_service_->SetInteger(
prefs::kUnifiedConsentMigrationState,
static_cast<int>(MigrationState::IN_PROGRESS_SHOULD_SHOW_CONSENT_BUMP));
}
bool UnifiedConsentService::AreAllNonPersonalizedServicesEnabled() {
for (int i = 0; i <= static_cast<int>(Service::kLast); ++i) {
Service service = static_cast<Service>(i);
if (service_client_->GetServiceState(service) == ServiceState::kDisabled)
return false;
}
if (!pref_service_->GetBoolean(
prefs::kUrlKeyedAnonymizedDataCollectionEnabled))
return false;
return true;
}
bool UnifiedConsentService::AreAllOnByDefaultPrivacySettingsOn() {
for (auto service : {Service::kAlternateErrorPages,
Service::kMetricsReporting, Service::kNetworkPrediction,
Service::kSafeBrowsing, Service::kSearchSuggest}) {
if (service_client_->GetServiceState(service) == ServiceState::kDisabled)
return false;
}
return true;
}
} // namespace unified_consent