// Copyright (c) 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 "chromeos/dbus/power_policy_controller.h" #include "base/format_macros.h" #include "base/logging.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "chromeos/dbus/dbus_thread_manager.h" namespace chromeos { namespace { // Appends a description of |field|, a field within |delays|, a // power_manager::PowerManagementPolicy::Delays object, to |str|, an // std::string, if the field is set. |name| is a char* describing the // field. #define APPEND_DELAY(str, delays, field, name) \ { \ if (delays.has_##field()) \ str += base::StringPrintf(name "=%" PRId64 " ", delays.field()); \ } // Appends descriptions of all of the set delays in |delays|, a // power_manager::PowerManagementPolicy::Delays object, to |str|, an // std::string. |prefix| should be a char* containing either "ac" or // "battery". #define APPEND_DELAYS(str, delays, prefix) \ { \ APPEND_DELAY(str, delays, screen_dim_ms, prefix "_screen_dim_ms"); \ APPEND_DELAY(str, delays, screen_off_ms, prefix "_screen_off_ms"); \ APPEND_DELAY(str, delays, screen_lock_ms, prefix "_screen_lock_ms"); \ APPEND_DELAY(str, delays, idle_warning_ms, prefix "_idle_warning_ms"); \ APPEND_DELAY(str, delays, idle_ms, prefix "_idle_ms"); \ } // Returns the power_manager::PowerManagementPolicy_Action value // corresponding to |action|. power_manager::PowerManagementPolicy_Action GetProtoAction( PowerPolicyController::Action action) { switch (action) { case PowerPolicyController::ACTION_SUSPEND: return power_manager::PowerManagementPolicy_Action_SUSPEND; case PowerPolicyController::ACTION_STOP_SESSION: return power_manager::PowerManagementPolicy_Action_STOP_SESSION; case PowerPolicyController::ACTION_SHUT_DOWN: return power_manager::PowerManagementPolicy_Action_SHUT_DOWN; case PowerPolicyController::ACTION_DO_NOTHING: return power_manager::PowerManagementPolicy_Action_DO_NOTHING; default: NOTREACHED() << "Unhandled action " << action; return power_manager::PowerManagementPolicy_Action_DO_NOTHING; } } } // namespace const int PowerPolicyController::kScreenLockAfterOffDelayMs = 10000; // 10 sec. // -1 is interpreted as "unset" by powerd, resulting in powerd's default // delays being used instead. There are no similarly-interpreted values // for the other fields, unfortunately (but the constructor-assigned values // will only reach powerd if Chrome messes up and forgets to override them // with the pref-assigned values). PowerPolicyController::PrefValues::PrefValues() : ac_screen_dim_delay_ms(-1), ac_screen_off_delay_ms(-1), ac_screen_lock_delay_ms(-1), ac_idle_warning_delay_ms(-1), ac_idle_delay_ms(-1), battery_screen_dim_delay_ms(-1), battery_screen_off_delay_ms(-1), battery_screen_lock_delay_ms(-1), battery_idle_warning_delay_ms(-1), battery_idle_delay_ms(-1), ac_idle_action(ACTION_SUSPEND), battery_idle_action(ACTION_SUSPEND), lid_closed_action(ACTION_SUSPEND), use_audio_activity(true), use_video_activity(true), allow_screen_wake_locks(true), enable_screen_lock(false), presentation_screen_dim_delay_factor(1.0), user_activity_screen_dim_delay_factor(1.0) {} // static std::string PowerPolicyController::GetPolicyDebugString( const power_manager::PowerManagementPolicy& policy) { std::string str; if (policy.has_ac_delays()) APPEND_DELAYS(str, policy.ac_delays(), "ac"); if (policy.has_battery_delays()) APPEND_DELAYS(str, policy.battery_delays(), "battery"); if (policy.has_ac_idle_action()) str += base::StringPrintf("ac_idle=%d ", policy.ac_idle_action()); if (policy.has_battery_idle_action()) str += base::StringPrintf("battery_idle=%d ", policy.battery_idle_action()); if (policy.has_lid_closed_action()) str += base::StringPrintf("lid_closed=%d ", policy.lid_closed_action()); if (policy.has_use_audio_activity()) str += base::StringPrintf("use_audio=%d ", policy.use_audio_activity()); if (policy.has_use_video_activity()) str += base::StringPrintf("use_video=%d ", policy.use_audio_activity()); if (policy.has_presentation_screen_dim_delay_factor()) { str += base::StringPrintf("presentation_screen_dim_delay_factor=%f ", policy.presentation_screen_dim_delay_factor()); } if (policy.has_user_activity_screen_dim_delay_factor()) { str += base::StringPrintf("user_activity_screen_dim_delay_factor=%f ", policy.user_activity_screen_dim_delay_factor()); } if (policy.has_reason()) str += base::StringPrintf("reason=\"%s\" ", policy.reason().c_str()); TrimWhitespace(str, TRIM_TRAILING, &str); return str; } PowerPolicyController::PowerPolicyController(DBusThreadManager* manager, PowerManagerClient* client) : manager_(manager), client_(client), prefs_were_set_(false), honor_screen_wake_locks_(true), next_wake_lock_id_(1) { manager_->AddObserver(this); client_->AddObserver(this); SendCurrentPolicy(); } PowerPolicyController::~PowerPolicyController() { // The power manager's policy is reset before this point, in // OnDBusThreadManagerDestroying(). At the time that // PowerPolicyController is destroyed, PowerManagerClient's D-Bus proxy // to the power manager is already gone. client_->RemoveObserver(this); client_ = NULL; manager_->RemoveObserver(this); manager_ = NULL; } void PowerPolicyController::ApplyPrefs(const PrefValues& values) { prefs_policy_.Clear(); power_manager::PowerManagementPolicy::Delays* delays = prefs_policy_.mutable_ac_delays(); delays->set_screen_dim_ms(values.ac_screen_dim_delay_ms); delays->set_screen_off_ms(values.ac_screen_off_delay_ms); delays->set_screen_lock_ms(values.ac_screen_lock_delay_ms); delays->set_idle_warning_ms(values.ac_idle_warning_delay_ms); delays->set_idle_ms(values.ac_idle_delay_ms); // If screen-locking is enabled, ensure that the screen is locked soon // after it's turned off due to user inactivity. int64 lock_ms = delays->screen_off_ms() + kScreenLockAfterOffDelayMs; if (values.enable_screen_lock && delays->screen_off_ms() > 0 && (delays->screen_lock_ms() <= 0 || lock_ms < delays->screen_lock_ms()) && lock_ms < delays->idle_ms()) { delays->set_screen_lock_ms(lock_ms); } delays = prefs_policy_.mutable_battery_delays(); delays->set_screen_dim_ms(values.battery_screen_dim_delay_ms); delays->set_screen_off_ms(values.battery_screen_off_delay_ms); delays->set_screen_lock_ms(values.battery_screen_lock_delay_ms); delays->set_idle_warning_ms(values.battery_idle_warning_delay_ms); delays->set_idle_ms(values.battery_idle_delay_ms); lock_ms = delays->screen_off_ms() + kScreenLockAfterOffDelayMs; if (values.enable_screen_lock && delays->screen_off_ms() > 0 && (delays->screen_lock_ms() <= 0 || lock_ms < delays->screen_lock_ms()) && lock_ms < delays->idle_ms()) { delays->set_screen_lock_ms(lock_ms); } prefs_policy_.set_ac_idle_action(GetProtoAction(values.ac_idle_action)); prefs_policy_.set_battery_idle_action( GetProtoAction(values.battery_idle_action)); prefs_policy_.set_lid_closed_action(GetProtoAction(values.lid_closed_action)); prefs_policy_.set_use_audio_activity(values.use_audio_activity); prefs_policy_.set_use_video_activity(values.use_video_activity); prefs_policy_.set_presentation_screen_dim_delay_factor( values.presentation_screen_dim_delay_factor); prefs_policy_.set_user_activity_screen_dim_delay_factor( values.user_activity_screen_dim_delay_factor); honor_screen_wake_locks_ = values.allow_screen_wake_locks; prefs_were_set_ = true; SendCurrentPolicy(); } void PowerPolicyController::ClearPrefs() { prefs_policy_.Clear(); honor_screen_wake_locks_ = true; prefs_were_set_ = false; SendCurrentPolicy(); } int PowerPolicyController::AddScreenWakeLock(const std::string& reason) { int id = next_wake_lock_id_++; screen_wake_locks_[id] = reason; SendCurrentPolicy(); return id; } int PowerPolicyController::AddSystemWakeLock(const std::string& reason) { int id = next_wake_lock_id_++; system_wake_locks_[id] = reason; SendCurrentPolicy(); return id; } void PowerPolicyController::RemoveWakeLock(int id) { if (!screen_wake_locks_.erase(id) && !system_wake_locks_.erase(id)) LOG(WARNING) << "Ignoring request to remove nonexistent wake lock " << id; else SendCurrentPolicy(); } void PowerPolicyController::OnDBusThreadManagerDestroying( DBusThreadManager* manager) { DCHECK_EQ(manager, manager_); SendEmptyPolicy(); } void PowerPolicyController::PowerManagerRestarted() { SendCurrentPolicy(); } void PowerPolicyController::SendCurrentPolicy() { std::string reason; power_manager::PowerManagementPolicy policy = prefs_policy_; if (prefs_were_set_) reason = "Prefs"; if (honor_screen_wake_locks_ && !screen_wake_locks_.empty()) { policy.mutable_ac_delays()->set_screen_dim_ms(0); policy.mutable_ac_delays()->set_screen_off_ms(0); policy.mutable_ac_delays()->set_screen_lock_ms(0); policy.mutable_battery_delays()->set_screen_dim_ms(0); policy.mutable_battery_delays()->set_screen_off_ms(0); policy.mutable_battery_delays()->set_screen_lock_ms(0); } if (!screen_wake_locks_.empty() || !system_wake_locks_.empty()) { if (!policy.has_ac_idle_action() || policy.ac_idle_action() == power_manager::PowerManagementPolicy_Action_SUSPEND) { policy.set_ac_idle_action( power_manager::PowerManagementPolicy_Action_DO_NOTHING); } if (!policy.has_battery_idle_action() || policy.battery_idle_action() == power_manager::PowerManagementPolicy_Action_SUSPEND) { policy.set_battery_idle_action( power_manager::PowerManagementPolicy_Action_DO_NOTHING); } } for (WakeLockMap::const_iterator it = screen_wake_locks_.begin(); it != screen_wake_locks_.end(); ++it) { reason += (reason.empty() ? "" : ", ") + it->second; } for (WakeLockMap::const_iterator it = system_wake_locks_.begin(); it != system_wake_locks_.end(); ++it) { reason += (reason.empty() ? "" : ", ") + it->second; } if (!reason.empty()) policy.set_reason(reason); client_->SetPolicy(policy); } void PowerPolicyController::SendEmptyPolicy() { client_->SetPolicy(power_manager::PowerManagementPolicy()); } } // namespace chromeos