blob: 6397937995e6a2374b41857c201d50e6262e5b42 [file] [log] [blame]
// Copyright 2013 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 "ash/system/power/power_prefs.h"
#include <string>
#include "ash/public/cpp/ash_pref_names.h"
#include "ash/session/session_controller.h"
#include "ash/shell.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/time/default_tick_clock.h"
#include "chromeos/constants/chromeos_features.h"
#include "chromeos/dbus/power_manager/idle.pb.h"
#include "chromeos/dbus/power_policy_controller.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_registry.h"
#include "components/prefs/pref_service.h"
namespace ash {
namespace {
chromeos::PowerPolicyController::Action GetPowerPolicyAction(
const PrefService* prefs,
const std::string& pref_name) {
const chromeos::PowerPolicyController::Action pref_action =
static_cast<chromeos::PowerPolicyController::Action>(
prefs->GetInteger(pref_name));
// Transform the power policy action when the lock screen is disabled and
// power preferences request to lock the screen: the session stop should be
// requested instead.
//
// This resolves potential privacy issues when the device could suspend
// before the session stop is fully finished and the login screen is shown.
//
// Note that the power policy prefs related to showing the lock screen on idle
// don't have to be adjusted accordingly, as Chrome itself will perform
// session stop instead of screen lock when the latter one is not available.
if (pref_action == chromeos::PowerPolicyController::ACTION_SUSPEND &&
prefs->GetBoolean(prefs::kEnableAutoScreenLock) &&
!prefs->GetBoolean(prefs::kAllowScreenLock)) {
return chromeos::PowerPolicyController::ACTION_STOP_SESSION;
}
return pref_action;
}
// Returns the PrefService that should be used for determining power-related
// behavior. When one or more users are logged in, the primary user's prefs are
// used: if more-restrictive power-related prefs are set by policy, it's most
// likely to be on this profile.
PrefService* GetPrefService() {
ash::SessionController* controller = Shell::Get()->session_controller();
PrefService* prefs = controller->GetPrimaryUserPrefService();
return prefs ? prefs : controller->GetActivePrefService();
}
// Registers power prefs whose default values are the same in user prefs and
// signin prefs.
void RegisterProfilePrefs(PrefRegistrySimple* registry, bool for_test) {
registry->RegisterIntegerPref(prefs::kPowerAcScreenBrightnessPercent, -1,
PrefRegistry::PUBLIC);
registry->RegisterIntegerPref(prefs::kPowerAcScreenDimDelayMs, 420000,
PrefRegistry::PUBLIC);
registry->RegisterIntegerPref(prefs::kPowerAcScreenOffDelayMs, 450000,
PrefRegistry::PUBLIC);
registry->RegisterIntegerPref(prefs::kPowerAcScreenLockDelayMs, 0,
PrefRegistry::PUBLIC);
registry->RegisterIntegerPref(prefs::kPowerAcIdleWarningDelayMs, 0,
PrefRegistry::PUBLIC);
registry->RegisterIntegerPref(prefs::kPowerAcIdleDelayMs, 510000,
PrefRegistry::PUBLIC);
registry->RegisterIntegerPref(prefs::kPowerBatteryScreenBrightnessPercent, -1,
PrefRegistry::PUBLIC);
registry->RegisterIntegerPref(prefs::kPowerBatteryScreenDimDelayMs, 300000,
PrefRegistry::PUBLIC);
registry->RegisterIntegerPref(prefs::kPowerBatteryScreenOffDelayMs, 330000,
PrefRegistry::PUBLIC);
registry->RegisterIntegerPref(prefs::kPowerBatteryScreenLockDelayMs, 0,
PrefRegistry::PUBLIC);
registry->RegisterIntegerPref(prefs::kPowerBatteryIdleWarningDelayMs, 0,
PrefRegistry::PUBLIC);
registry->RegisterIntegerPref(prefs::kPowerBatteryIdleDelayMs, 390000,
PrefRegistry::PUBLIC);
registry->RegisterIntegerPref(prefs::kPowerLockScreenDimDelayMs, 30000,
PrefRegistry::PUBLIC);
registry->RegisterIntegerPref(prefs::kPowerLockScreenOffDelayMs, 40000,
PrefRegistry::PUBLIC);
registry->RegisterIntegerPref(prefs::kPowerAcIdleAction,
chromeos::PowerPolicyController::ACTION_SUSPEND,
PrefRegistry::PUBLIC);
registry->RegisterBooleanPref(prefs::kPowerUseAudioActivity, true,
PrefRegistry::PUBLIC);
registry->RegisterBooleanPref(prefs::kPowerUseVideoActivity, true,
PrefRegistry::PUBLIC);
registry->RegisterBooleanPref(prefs::kPowerAllowWakeLocks, true,
PrefRegistry::PUBLIC);
registry->RegisterBooleanPref(prefs::kPowerAllowScreenWakeLocks, true,
PrefRegistry::PUBLIC);
registry->RegisterDoublePref(prefs::kPowerPresentationScreenDimDelayFactor,
2.0, PrefRegistry::PUBLIC);
registry->RegisterDoublePref(prefs::kPowerUserActivityScreenDimDelayFactor,
2.0, PrefRegistry::PUBLIC);
registry->RegisterBooleanPref(prefs::kPowerWaitForInitialUserActivity, false,
PrefRegistry::PUBLIC);
registry->RegisterBooleanPref(
prefs::kPowerForceNonzeroBrightnessForUserActivity, true,
PrefRegistry::PUBLIC);
registry->RegisterBooleanPref(prefs::kPowerSmartDimEnabled, true,
PrefRegistry::PUBLIC);
if (for_test) {
registry->RegisterBooleanPref(prefs::kAllowScreenLock, true,
PrefRegistry::PUBLIC);
registry->RegisterBooleanPref(
prefs::kEnableAutoScreenLock, false,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF | PrefRegistry::PUBLIC);
} else {
registry->RegisterForeignPref(prefs::kAllowScreenLock);
registry->RegisterForeignPref(prefs::kEnableAutoScreenLock);
}
}
} // namespace
PowerPrefs::PowerPrefs(chromeos::PowerPolicyController* power_policy_controller,
chromeos::PowerManagerClient* power_manager_client)
: power_policy_controller_(power_policy_controller),
power_manager_client_observer_(this),
tick_clock_(base::DefaultTickClock::GetInstance()) {
DCHECK(power_manager_client);
DCHECK(power_policy_controller_);
DCHECK(tick_clock_);
power_manager_client_observer_.Add(power_manager_client);
Shell::Get()->session_controller()->AddObserver(this);
}
PowerPrefs::~PowerPrefs() {
Shell::Get()->session_controller()->RemoveObserver(this);
}
// static
void PowerPrefs::RegisterSigninProfilePrefs(PrefRegistrySimple* registry,
bool for_test) {
RegisterProfilePrefs(registry, for_test);
registry->RegisterIntegerPref(
prefs::kPowerBatteryIdleAction,
chromeos::PowerPolicyController::ACTION_SHUT_DOWN, PrefRegistry::PUBLIC);
registry->RegisterIntegerPref(
prefs::kPowerLidClosedAction,
chromeos::PowerPolicyController::ACTION_SHUT_DOWN, PrefRegistry::PUBLIC);
}
// static
void PowerPrefs::RegisterUserProfilePrefs(PrefRegistrySimple* registry,
bool for_test) {
RegisterProfilePrefs(registry, for_test);
registry->RegisterIntegerPref(prefs::kPowerBatteryIdleAction,
chromeos::PowerPolicyController::ACTION_SUSPEND,
PrefRegistry::PUBLIC);
registry->RegisterIntegerPref(prefs::kPowerLidClosedAction,
chromeos::PowerPolicyController::ACTION_SUSPEND,
PrefRegistry::PUBLIC);
}
void PowerPrefs::ScreenIdleStateChanged(
const power_manager::ScreenIdleState& proto) {
const bool already_off = !screen_idle_off_time_.is_null();
if (proto.off() == already_off)
return;
screen_idle_off_time_ =
proto.off() ? tick_clock_->NowTicks() : base::TimeTicks();
// If the screen is locked and we're no longer idle, we may need to switch to
// the lock-based delays.
if (!screen_lock_time_.is_null() && !proto.off())
UpdatePowerPolicyFromPrefs();
}
void PowerPrefs::OnLockStateChanged(bool locked) {
const bool already_locked = !screen_lock_time_.is_null();
if (locked == already_locked)
return;
screen_lock_time_ = locked ? tick_clock_->NowTicks() : base::TimeTicks();
// OnLockStateChanged could be called before ash connects user prefs in tests.
if (GetPrefService())
UpdatePowerPolicyFromPrefs();
}
void PowerPrefs::OnSigninScreenPrefServiceInitialized(PrefService* prefs) {
ObservePrefs(prefs);
}
void PowerPrefs::OnActiveUserPrefServiceChanged(PrefService* prefs) {
ObservePrefs(prefs);
}
void PowerPrefs::UpdatePowerPolicyFromPrefs() {
PrefService* prefs = GetPrefService();
DCHECK(prefs);
// It's possible to end up in a situation where a shortened lock-screen idle
// delay would cause the system to suspend immediately as soon as the screen
// is locked due to inactivity; see https://crbug.com/807861 for the gory
// details. To avoid this, don't switch to the shorter delays immediately when
// the screen is locked automatically (as indicated by the screen having been
// previously turned off for inactivity).
bool use_lock_delays = !screen_lock_time_.is_null() &&
(screen_idle_off_time_.is_null() ||
screen_idle_off_time_ > screen_lock_time_);
chromeos::PowerPolicyController::PrefValues values;
values.ac_brightness_percent =
prefs->GetInteger(prefs::kPowerAcScreenBrightnessPercent);
values.ac_screen_dim_delay_ms =
prefs->GetInteger(use_lock_delays ? prefs::kPowerLockScreenDimDelayMs
: prefs::kPowerAcScreenDimDelayMs);
values.ac_screen_off_delay_ms =
prefs->GetInteger(use_lock_delays ? prefs::kPowerLockScreenOffDelayMs
: prefs::kPowerAcScreenOffDelayMs);
values.ac_screen_lock_delay_ms =
prefs->GetInteger(prefs::kPowerAcScreenLockDelayMs);
values.ac_idle_warning_delay_ms =
prefs->GetInteger(prefs::kPowerAcIdleWarningDelayMs);
values.ac_idle_delay_ms = prefs->GetInteger(prefs::kPowerAcIdleDelayMs);
values.battery_brightness_percent =
prefs->GetInteger(prefs::kPowerBatteryScreenBrightnessPercent);
values.battery_screen_dim_delay_ms =
prefs->GetInteger(use_lock_delays ? prefs::kPowerLockScreenDimDelayMs
: prefs::kPowerBatteryScreenDimDelayMs);
values.battery_screen_off_delay_ms =
prefs->GetInteger(use_lock_delays ? prefs::kPowerLockScreenOffDelayMs
: prefs::kPowerBatteryScreenOffDelayMs);
values.battery_screen_lock_delay_ms =
prefs->GetInteger(prefs::kPowerBatteryScreenLockDelayMs);
values.battery_idle_warning_delay_ms =
prefs->GetInteger(prefs::kPowerBatteryIdleWarningDelayMs);
values.battery_idle_delay_ms =
prefs->GetInteger(prefs::kPowerBatteryIdleDelayMs);
values.ac_idle_action =
GetPowerPolicyAction(prefs, prefs::kPowerAcIdleAction);
values.battery_idle_action =
GetPowerPolicyAction(prefs, prefs::kPowerBatteryIdleAction);
values.lid_closed_action =
GetPowerPolicyAction(prefs, prefs::kPowerLidClosedAction);
values.use_audio_activity = prefs->GetBoolean(prefs::kPowerUseAudioActivity);
values.use_video_activity = prefs->GetBoolean(prefs::kPowerUseVideoActivity);
values.allow_wake_locks = prefs->GetBoolean(prefs::kPowerAllowWakeLocks);
values.allow_screen_wake_locks =
prefs->GetBoolean(prefs::kPowerAllowScreenWakeLocks);
values.enable_auto_screen_lock =
prefs->GetBoolean(prefs::kEnableAutoScreenLock);
// Screen-dim deferral in response to user activity predictions can interact
// poorly with delay scaling, resulting in the system staying awake for a long
// time if a prediction is wrong. https://crbug.com/888392.
if (prefs->GetBoolean(prefs::kPowerSmartDimEnabled) &&
base::FeatureList::IsEnabled(
chromeos::features::kUserActivityPrediction)) {
values.presentation_screen_dim_delay_factor = 1.0;
values.user_activity_screen_dim_delay_factor = 1.0;
} else {
values.presentation_screen_dim_delay_factor =
prefs->GetDouble(prefs::kPowerPresentationScreenDimDelayFactor);
values.user_activity_screen_dim_delay_factor =
prefs->GetDouble(prefs::kPowerUserActivityScreenDimDelayFactor);
}
values.wait_for_initial_user_activity =
prefs->GetBoolean(prefs::kPowerWaitForInitialUserActivity);
values.force_nonzero_brightness_for_user_activity =
prefs->GetBoolean(prefs::kPowerForceNonzeroBrightnessForUserActivity);
power_policy_controller_->ApplyPrefs(values);
}
void PowerPrefs::ObservePrefs(PrefService* prefs) {
// Observe pref updates from locked state change and policy.
base::RepeatingClosure update_callback(base::BindRepeating(
&PowerPrefs::UpdatePowerPolicyFromPrefs, base::Unretained(this)));
pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
pref_change_registrar_->Init(prefs);
pref_change_registrar_->Add(prefs::kPowerAcScreenBrightnessPercent,
update_callback);
pref_change_registrar_->Add(prefs::kPowerAcScreenDimDelayMs, update_callback);
pref_change_registrar_->Add(prefs::kPowerAcScreenOffDelayMs, update_callback);
pref_change_registrar_->Add(prefs::kPowerAcScreenLockDelayMs,
update_callback);
pref_change_registrar_->Add(prefs::kPowerAcIdleWarningDelayMs,
update_callback);
pref_change_registrar_->Add(prefs::kPowerAcIdleDelayMs, update_callback);
pref_change_registrar_->Add(prefs::kPowerBatteryScreenBrightnessPercent,
update_callback);
pref_change_registrar_->Add(prefs::kPowerBatteryScreenDimDelayMs,
update_callback);
pref_change_registrar_->Add(prefs::kPowerBatteryScreenOffDelayMs,
update_callback);
pref_change_registrar_->Add(prefs::kPowerBatteryScreenLockDelayMs,
update_callback);
pref_change_registrar_->Add(prefs::kPowerBatteryIdleWarningDelayMs,
update_callback);
pref_change_registrar_->Add(prefs::kPowerBatteryIdleDelayMs, update_callback);
pref_change_registrar_->Add(prefs::kPowerLockScreenDimDelayMs,
update_callback);
pref_change_registrar_->Add(prefs::kPowerLockScreenOffDelayMs,
update_callback);
pref_change_registrar_->Add(prefs::kPowerAcIdleAction, update_callback);
pref_change_registrar_->Add(prefs::kPowerBatteryIdleAction, update_callback);
pref_change_registrar_->Add(prefs::kPowerLidClosedAction, update_callback);
pref_change_registrar_->Add(prefs::kPowerUseAudioActivity, update_callback);
pref_change_registrar_->Add(prefs::kPowerUseVideoActivity, update_callback);
pref_change_registrar_->Add(prefs::kPowerAllowWakeLocks, update_callback);
pref_change_registrar_->Add(prefs::kPowerAllowScreenWakeLocks,
update_callback);
pref_change_registrar_->Add(prefs::kEnableAutoScreenLock, update_callback);
pref_change_registrar_->Add(prefs::kPowerPresentationScreenDimDelayFactor,
update_callback);
pref_change_registrar_->Add(prefs::kPowerUserActivityScreenDimDelayFactor,
update_callback);
pref_change_registrar_->Add(prefs::kPowerWaitForInitialUserActivity,
update_callback);
pref_change_registrar_->Add(
prefs::kPowerForceNonzeroBrightnessForUserActivity, update_callback);
pref_change_registrar_->Add(prefs::kAllowScreenLock, update_callback);
pref_change_registrar_->Add(prefs::kPowerSmartDimEnabled, update_callback);
UpdatePowerPolicyFromPrefs();
}
} // namespace ash