1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chromeos/dbus/power_policy_controller.h"
6
7#include "base/format_macros.h"
8#include "base/logging.h"
9#include "base/strings/string_util.h"
10#include "base/strings/stringprintf.h"
11#include "chromeos/dbus/dbus_thread_manager.h"
12
13namespace chromeos {
14
15namespace {
16
17// Appends a description of |field|, a field within |delays|, a
18// power_manager::PowerManagementPolicy::Delays object, to |str|, an
19// std::string, if the field is set.  |name| is a char* describing the
20// field.
21#define APPEND_DELAY(str, delays, field, name)                                 \
22    {                                                                          \
23      if (delays.has_##field())                                                \
24        str += base::StringPrintf(name "=%" PRId64 " ", delays.field());       \
25    }
26
27// Appends descriptions of all of the set delays in |delays|, a
28// power_manager::PowerManagementPolicy::Delays object, to |str|, an
29// std::string.  |prefix| should be a char* containing either "ac" or
30// "battery".
31#define APPEND_DELAYS(str, delays, prefix)                                     \
32    {                                                                          \
33      APPEND_DELAY(str, delays, screen_dim_ms, prefix "_screen_dim_ms");       \
34      APPEND_DELAY(str, delays, screen_off_ms, prefix "_screen_off_ms");       \
35      APPEND_DELAY(str, delays, screen_lock_ms, prefix "_screen_lock_ms");     \
36      APPEND_DELAY(str, delays, idle_warning_ms, prefix "_idle_warning_ms");   \
37      APPEND_DELAY(str, delays, idle_ms, prefix "_idle_ms");                   \
38    }
39
40// Returns the power_manager::PowerManagementPolicy_Action value
41// corresponding to |action|.
42power_manager::PowerManagementPolicy_Action GetProtoAction(
43    PowerPolicyController::Action action) {
44  switch (action) {
45    case PowerPolicyController::ACTION_SUSPEND:
46      return power_manager::PowerManagementPolicy_Action_SUSPEND;
47    case PowerPolicyController::ACTION_STOP_SESSION:
48      return power_manager::PowerManagementPolicy_Action_STOP_SESSION;
49    case PowerPolicyController::ACTION_SHUT_DOWN:
50      return power_manager::PowerManagementPolicy_Action_SHUT_DOWN;
51    case PowerPolicyController::ACTION_DO_NOTHING:
52      return power_manager::PowerManagementPolicy_Action_DO_NOTHING;
53    default:
54      NOTREACHED() << "Unhandled action " << action;
55      return power_manager::PowerManagementPolicy_Action_DO_NOTHING;
56  }
57}
58
59}  // namespace
60
61const int PowerPolicyController::kScreenLockAfterOffDelayMs = 10000;  // 10 sec.
62
63// -1 is interpreted as "unset" by powerd, resulting in powerd's default
64// delays being used instead.  There are no similarly-interpreted values
65// for the other fields, unfortunately (but the constructor-assigned values
66// will only reach powerd if Chrome messes up and forgets to override them
67// with the pref-assigned values).
68PowerPolicyController::PrefValues::PrefValues()
69    : ac_screen_dim_delay_ms(-1),
70      ac_screen_off_delay_ms(-1),
71      ac_screen_lock_delay_ms(-1),
72      ac_idle_warning_delay_ms(-1),
73      ac_idle_delay_ms(-1),
74      battery_screen_dim_delay_ms(-1),
75      battery_screen_off_delay_ms(-1),
76      battery_screen_lock_delay_ms(-1),
77      battery_idle_warning_delay_ms(-1),
78      battery_idle_delay_ms(-1),
79      ac_idle_action(ACTION_SUSPEND),
80      battery_idle_action(ACTION_SUSPEND),
81      lid_closed_action(ACTION_SUSPEND),
82      use_audio_activity(true),
83      use_video_activity(true),
84      ac_brightness_percent(-1.0),
85      battery_brightness_percent(-1.0),
86      allow_screen_wake_locks(true),
87      enable_auto_screen_lock(false),
88      presentation_screen_dim_delay_factor(1.0),
89      user_activity_screen_dim_delay_factor(1.0),
90      wait_for_initial_user_activity(false) {}
91
92// static
93std::string PowerPolicyController::GetPolicyDebugString(
94    const power_manager::PowerManagementPolicy& policy) {
95  std::string str;
96  if (policy.has_ac_delays())
97    APPEND_DELAYS(str, policy.ac_delays(), "ac");
98  if (policy.has_battery_delays())
99    APPEND_DELAYS(str, policy.battery_delays(), "battery");
100  if (policy.has_ac_idle_action())
101    str += base::StringPrintf("ac_idle=%d ", policy.ac_idle_action());
102  if (policy.has_battery_idle_action())
103    str += base::StringPrintf("battery_idle=%d ", policy.battery_idle_action());
104  if (policy.has_lid_closed_action())
105    str += base::StringPrintf("lid_closed=%d ", policy.lid_closed_action());
106  if (policy.has_use_audio_activity())
107    str += base::StringPrintf("use_audio=%d ", policy.use_audio_activity());
108  if (policy.has_use_video_activity())
109    str += base::StringPrintf("use_video=%d ", policy.use_audio_activity());
110  if (policy.has_ac_brightness_percent()) {
111    str += base::StringPrintf("ac_brightness_percent=%f ",
112        policy.ac_brightness_percent());
113  }
114  if (policy.has_battery_brightness_percent()) {
115    str += base::StringPrintf("battery_brightness_percent=%f ",
116        policy.battery_brightness_percent());
117  }
118  if (policy.has_presentation_screen_dim_delay_factor()) {
119    str += base::StringPrintf("presentation_screen_dim_delay_factor=%f ",
120        policy.presentation_screen_dim_delay_factor());
121  }
122  if (policy.has_user_activity_screen_dim_delay_factor()) {
123    str += base::StringPrintf("user_activity_screen_dim_delay_factor=%f ",
124        policy.user_activity_screen_dim_delay_factor());
125  }
126  if (policy.has_wait_for_initial_user_activity()) {
127    str += base::StringPrintf("wait_for_initial_user_activity=%d ",
128        policy.wait_for_initial_user_activity());
129  }
130  if (policy.has_reason())
131    str += base::StringPrintf("reason=\"%s\" ", policy.reason().c_str());
132  base::TrimWhitespace(str, base::TRIM_TRAILING, &str);
133  return str;
134}
135
136PowerPolicyController::PowerPolicyController()
137    : client_(NULL),
138      prefs_were_set_(false),
139      honor_screen_wake_locks_(true),
140      next_wake_lock_id_(1) {
141}
142
143PowerPolicyController::~PowerPolicyController() {
144  if (client_) {
145    client_->RemoveObserver(this);
146    client_ = NULL;
147  }
148}
149
150void PowerPolicyController::Init(DBusThreadManager* manager) {
151  client_ = manager->GetPowerManagerClient();
152  client_->AddObserver(this);
153}
154
155void PowerPolicyController::ApplyPrefs(const PrefValues& values) {
156  prefs_policy_.Clear();
157
158  power_manager::PowerManagementPolicy::Delays* delays =
159      prefs_policy_.mutable_ac_delays();
160  delays->set_screen_dim_ms(values.ac_screen_dim_delay_ms);
161  delays->set_screen_off_ms(values.ac_screen_off_delay_ms);
162  delays->set_screen_lock_ms(values.ac_screen_lock_delay_ms);
163  delays->set_idle_warning_ms(values.ac_idle_warning_delay_ms);
164  delays->set_idle_ms(values.ac_idle_delay_ms);
165
166  // If auto screen-locking is enabled, ensure that the screen is locked soon
167  // after it's turned off due to user inactivity.
168  int64 lock_ms = delays->screen_off_ms() + kScreenLockAfterOffDelayMs;
169  if (values.enable_auto_screen_lock && delays->screen_off_ms() > 0 &&
170      (delays->screen_lock_ms() <= 0 || lock_ms < delays->screen_lock_ms()) &&
171      lock_ms < delays->idle_ms()) {
172    delays->set_screen_lock_ms(lock_ms);
173  }
174
175  delays = prefs_policy_.mutable_battery_delays();
176  delays->set_screen_dim_ms(values.battery_screen_dim_delay_ms);
177  delays->set_screen_off_ms(values.battery_screen_off_delay_ms);
178  delays->set_screen_lock_ms(values.battery_screen_lock_delay_ms);
179  delays->set_idle_warning_ms(values.battery_idle_warning_delay_ms);
180  delays->set_idle_ms(values.battery_idle_delay_ms);
181
182  lock_ms = delays->screen_off_ms() + kScreenLockAfterOffDelayMs;
183  if (values.enable_auto_screen_lock && delays->screen_off_ms() > 0 &&
184      (delays->screen_lock_ms() <= 0 || lock_ms < delays->screen_lock_ms()) &&
185      lock_ms < delays->idle_ms()) {
186    delays->set_screen_lock_ms(lock_ms);
187  }
188
189  prefs_policy_.set_ac_idle_action(GetProtoAction(values.ac_idle_action));
190  prefs_policy_.set_battery_idle_action(
191      GetProtoAction(values.battery_idle_action));
192  prefs_policy_.set_lid_closed_action(GetProtoAction(values.lid_closed_action));
193  prefs_policy_.set_use_audio_activity(values.use_audio_activity);
194  prefs_policy_.set_use_video_activity(values.use_video_activity);
195  if (values.ac_brightness_percent >= 0.0)
196    prefs_policy_.set_ac_brightness_percent(values.ac_brightness_percent);
197  if (values.battery_brightness_percent >= 0.0) {
198    prefs_policy_.set_battery_brightness_percent(
199        values.battery_brightness_percent);
200  }
201  prefs_policy_.set_presentation_screen_dim_delay_factor(
202      values.presentation_screen_dim_delay_factor);
203  prefs_policy_.set_user_activity_screen_dim_delay_factor(
204      values.user_activity_screen_dim_delay_factor);
205  prefs_policy_.set_wait_for_initial_user_activity(
206      values.wait_for_initial_user_activity);
207
208  honor_screen_wake_locks_ = values.allow_screen_wake_locks;
209
210  prefs_were_set_ = true;
211  SendCurrentPolicy();
212}
213
214int PowerPolicyController::AddScreenWakeLock(const std::string& reason) {
215  int id = next_wake_lock_id_++;
216  screen_wake_locks_[id] = reason;
217  SendCurrentPolicy();
218  return id;
219}
220
221int PowerPolicyController::AddSystemWakeLock(const std::string& reason) {
222  int id = next_wake_lock_id_++;
223  system_wake_locks_[id] = reason;
224  SendCurrentPolicy();
225  return id;
226}
227
228void PowerPolicyController::RemoveWakeLock(int id) {
229  if (!screen_wake_locks_.erase(id) && !system_wake_locks_.erase(id))
230    LOG(WARNING) << "Ignoring request to remove nonexistent wake lock " << id;
231  else
232    SendCurrentPolicy();
233}
234
235void PowerPolicyController::PowerManagerRestarted() {
236  SendCurrentPolicy();
237}
238
239void PowerPolicyController::SendCurrentPolicy() {
240  std::string reason;
241
242  power_manager::PowerManagementPolicy policy = prefs_policy_;
243  if (prefs_were_set_)
244    reason = "Prefs";
245
246  if (honor_screen_wake_locks_ && !screen_wake_locks_.empty()) {
247    policy.mutable_ac_delays()->set_screen_dim_ms(0);
248    policy.mutable_ac_delays()->set_screen_off_ms(0);
249    policy.mutable_ac_delays()->set_screen_lock_ms(0);
250    policy.mutable_battery_delays()->set_screen_dim_ms(0);
251    policy.mutable_battery_delays()->set_screen_off_ms(0);
252    policy.mutable_battery_delays()->set_screen_lock_ms(0);
253  }
254
255  if (!screen_wake_locks_.empty() || !system_wake_locks_.empty()) {
256    if (!policy.has_ac_idle_action() || policy.ac_idle_action() ==
257        power_manager::PowerManagementPolicy_Action_SUSPEND) {
258      policy.set_ac_idle_action(
259          power_manager::PowerManagementPolicy_Action_DO_NOTHING);
260    }
261    if (!policy.has_battery_idle_action() || policy.battery_idle_action() ==
262        power_manager::PowerManagementPolicy_Action_SUSPEND) {
263      policy.set_battery_idle_action(
264          power_manager::PowerManagementPolicy_Action_DO_NOTHING);
265    }
266  }
267
268  for (WakeLockMap::const_iterator it = screen_wake_locks_.begin();
269       it != screen_wake_locks_.end(); ++it) {
270    reason += (reason.empty() ? "" : ", ") + it->second;
271  }
272  for (WakeLockMap::const_iterator it = system_wake_locks_.begin();
273       it != system_wake_locks_.end(); ++it) {
274    reason += (reason.empty() ? "" : ", ") + it->second;
275  }
276
277  if (!reason.empty())
278    policy.set_reason(reason);
279  client_->SetPolicy(policy);
280}
281
282}  // namespace chromeos
283