1 // Copyright (c) 2012 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_manager_client.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/command_line.h"
12 #include "base/format_macros.h"
13 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/observer_list.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_split.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/threading/platform_thread.h"
21 #include "base/time/time.h"
22 #include "base/timer/timer.h"
23 #include "chromeos/chromeos_switches.h"
24 #include "chromeos/dbus/power_manager/input_event.pb.h"
25 #include "chromeos/dbus/power_manager/peripheral_battery_status.pb.h"
26 #include "chromeos/dbus/power_manager/policy.pb.h"
27 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
28 #include "chromeos/dbus/power_manager/suspend.pb.h"
29 #include "dbus/bus.h"
30 #include "dbus/message.h"
31 #include "dbus/object_path.h"
32 #include "dbus/object_proxy.h"
33
34 namespace chromeos {
35
36 // Maximum amount of time that the power manager will wait for Chrome to
37 // say that it's ready for the system to be suspended, in milliseconds.
38 const int kSuspendDelayTimeoutMs = 5000;
39
40 // Human-readable description of Chrome's suspend delay.
41 const char kSuspendDelayDescription[] = "chrome";
42
43 // The PowerManagerClient implementation used in production.
44 class PowerManagerClientImpl : public PowerManagerClient {
45 public:
PowerManagerClientImpl()46 PowerManagerClientImpl()
47 : origin_thread_id_(base::PlatformThread::CurrentId()),
48 power_manager_proxy_(NULL),
49 suspend_delay_id_(-1),
50 has_suspend_delay_id_(false),
51 dark_suspend_delay_id_(-1),
52 has_dark_suspend_delay_id_(false),
53 pending_suspend_id_(-1),
54 suspend_is_pending_(false),
55 suspending_from_dark_resume_(false),
56 num_pending_suspend_readiness_callbacks_(0),
57 last_is_projecting_(false),
58 weak_ptr_factory_(this) {}
59
~PowerManagerClientImpl()60 virtual ~PowerManagerClientImpl() {
61 // Here we should unregister suspend notifications from powerd,
62 // however:
63 // - The lifetime of the PowerManagerClientImpl can extend past that of
64 // the objectproxy,
65 // - power_manager can already detect that the client is gone and
66 // unregister our suspend delay.
67 }
68
69 // PowerManagerClient overrides:
70
AddObserver(Observer * observer)71 virtual void AddObserver(Observer* observer) OVERRIDE {
72 CHECK(observer); // http://crbug.com/119976
73 observers_.AddObserver(observer);
74 }
75
RemoveObserver(Observer * observer)76 virtual void RemoveObserver(Observer* observer) OVERRIDE {
77 observers_.RemoveObserver(observer);
78 }
79
HasObserver(Observer * observer)80 virtual bool HasObserver(Observer* observer) OVERRIDE {
81 return observers_.HasObserver(observer);
82 }
83
DecreaseScreenBrightness(bool allow_off)84 virtual void DecreaseScreenBrightness(bool allow_off) OVERRIDE {
85 dbus::MethodCall method_call(
86 power_manager::kPowerManagerInterface,
87 power_manager::kDecreaseScreenBrightnessMethod);
88 dbus::MessageWriter writer(&method_call);
89 writer.AppendBool(allow_off);
90 power_manager_proxy_->CallMethod(
91 &method_call,
92 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
93 dbus::ObjectProxy::EmptyResponseCallback());
94 }
95
IncreaseScreenBrightness()96 virtual void IncreaseScreenBrightness() OVERRIDE {
97 SimpleMethodCallToPowerManager(
98 power_manager::kIncreaseScreenBrightnessMethod);
99 }
100
DecreaseKeyboardBrightness()101 virtual void DecreaseKeyboardBrightness() OVERRIDE {
102 SimpleMethodCallToPowerManager(
103 power_manager::kDecreaseKeyboardBrightnessMethod);
104 }
105
IncreaseKeyboardBrightness()106 virtual void IncreaseKeyboardBrightness() OVERRIDE {
107 SimpleMethodCallToPowerManager(
108 power_manager::kIncreaseKeyboardBrightnessMethod);
109 }
110
SetScreenBrightnessPercent(double percent,bool gradual)111 virtual void SetScreenBrightnessPercent(double percent,
112 bool gradual) OVERRIDE {
113 dbus::MethodCall method_call(
114 power_manager::kPowerManagerInterface,
115 power_manager::kSetScreenBrightnessPercentMethod);
116 dbus::MessageWriter writer(&method_call);
117 writer.AppendDouble(percent);
118 writer.AppendInt32(
119 gradual ?
120 power_manager::kBrightnessTransitionGradual :
121 power_manager::kBrightnessTransitionInstant);
122 power_manager_proxy_->CallMethod(
123 &method_call,
124 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
125 dbus::ObjectProxy::EmptyResponseCallback());
126 }
127
GetScreenBrightnessPercent(const GetScreenBrightnessPercentCallback & callback)128 virtual void GetScreenBrightnessPercent(
129 const GetScreenBrightnessPercentCallback& callback) OVERRIDE {
130 dbus::MethodCall method_call(
131 power_manager::kPowerManagerInterface,
132 power_manager::kGetScreenBrightnessPercentMethod);
133 power_manager_proxy_->CallMethod(
134 &method_call,
135 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
136 base::Bind(&PowerManagerClientImpl::OnGetScreenBrightnessPercent,
137 weak_ptr_factory_.GetWeakPtr(), callback));
138 }
139
RequestStatusUpdate()140 virtual void RequestStatusUpdate() OVERRIDE {
141 dbus::MethodCall method_call(
142 power_manager::kPowerManagerInterface,
143 power_manager::kGetPowerSupplyPropertiesMethod);
144 power_manager_proxy_->CallMethod(
145 &method_call,
146 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
147 base::Bind(&PowerManagerClientImpl::OnGetPowerSupplyPropertiesMethod,
148 weak_ptr_factory_.GetWeakPtr()));
149 }
150
RequestSuspend()151 virtual void RequestSuspend() OVERRIDE {
152 SimpleMethodCallToPowerManager(power_manager::kRequestSuspendMethod);
153 }
154
RequestRestart()155 virtual void RequestRestart() OVERRIDE {
156 SimpleMethodCallToPowerManager(power_manager::kRequestRestartMethod);
157 }
158
RequestShutdown()159 virtual void RequestShutdown() OVERRIDE {
160 SimpleMethodCallToPowerManager(power_manager::kRequestShutdownMethod);
161 }
162
NotifyUserActivity(power_manager::UserActivityType type)163 virtual void NotifyUserActivity(
164 power_manager::UserActivityType type) OVERRIDE {
165 dbus::MethodCall method_call(
166 power_manager::kPowerManagerInterface,
167 power_manager::kHandleUserActivityMethod);
168 dbus::MessageWriter writer(&method_call);
169 writer.AppendInt32(type);
170
171 power_manager_proxy_->CallMethod(
172 &method_call,
173 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
174 dbus::ObjectProxy::EmptyResponseCallback());
175 }
176
NotifyVideoActivity(bool is_fullscreen)177 virtual void NotifyVideoActivity(bool is_fullscreen) OVERRIDE {
178 dbus::MethodCall method_call(
179 power_manager::kPowerManagerInterface,
180 power_manager::kHandleVideoActivityMethod);
181 dbus::MessageWriter writer(&method_call);
182 writer.AppendBool(is_fullscreen);
183
184 power_manager_proxy_->CallMethod(
185 &method_call,
186 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
187 dbus::ObjectProxy::EmptyResponseCallback());
188 }
189
SetPolicy(const power_manager::PowerManagementPolicy & policy)190 virtual void SetPolicy(
191 const power_manager::PowerManagementPolicy& policy) OVERRIDE {
192 dbus::MethodCall method_call(
193 power_manager::kPowerManagerInterface,
194 power_manager::kSetPolicyMethod);
195 dbus::MessageWriter writer(&method_call);
196 if (!writer.AppendProtoAsArrayOfBytes(policy)) {
197 LOG(ERROR) << "Error calling " << power_manager::kSetPolicyMethod;
198 return;
199 }
200 power_manager_proxy_->CallMethod(
201 &method_call,
202 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
203 dbus::ObjectProxy::EmptyResponseCallback());
204 }
205
SetIsProjecting(bool is_projecting)206 virtual void SetIsProjecting(bool is_projecting) OVERRIDE {
207 dbus::MethodCall method_call(
208 power_manager::kPowerManagerInterface,
209 power_manager::kSetIsProjectingMethod);
210 dbus::MessageWriter writer(&method_call);
211 writer.AppendBool(is_projecting);
212 power_manager_proxy_->CallMethod(
213 &method_call,
214 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
215 dbus::ObjectProxy::EmptyResponseCallback());
216 last_is_projecting_ = is_projecting;
217 }
218
GetSuspendReadinessCallback()219 virtual base::Closure GetSuspendReadinessCallback() OVERRIDE {
220 DCHECK(OnOriginThread());
221 DCHECK(suspend_is_pending_);
222 num_pending_suspend_readiness_callbacks_++;
223 return base::Bind(&PowerManagerClientImpl::HandleObserverSuspendReadiness,
224 weak_ptr_factory_.GetWeakPtr(), pending_suspend_id_,
225 suspending_from_dark_resume_);
226 }
227
GetNumPendingSuspendReadinessCallbacks()228 virtual int GetNumPendingSuspendReadinessCallbacks() OVERRIDE {
229 return num_pending_suspend_readiness_callbacks_;
230 }
231
232 protected:
Init(dbus::Bus * bus)233 virtual void Init(dbus::Bus* bus) OVERRIDE {
234 power_manager_proxy_ = bus->GetObjectProxy(
235 power_manager::kPowerManagerServiceName,
236 dbus::ObjectPath(power_manager::kPowerManagerServicePath));
237
238 power_manager_proxy_->SetNameOwnerChangedCallback(
239 base::Bind(&PowerManagerClientImpl::NameOwnerChangedReceived,
240 weak_ptr_factory_.GetWeakPtr()));
241
242 // Monitor the D-Bus signal for brightness changes. Only the power
243 // manager knows the actual brightness level. We don't cache the
244 // brightness level in Chrome as it'll make things less reliable.
245 power_manager_proxy_->ConnectToSignal(
246 power_manager::kPowerManagerInterface,
247 power_manager::kBrightnessChangedSignal,
248 base::Bind(&PowerManagerClientImpl::BrightnessChangedReceived,
249 weak_ptr_factory_.GetWeakPtr()),
250 base::Bind(&PowerManagerClientImpl::SignalConnected,
251 weak_ptr_factory_.GetWeakPtr()));
252
253 power_manager_proxy_->ConnectToSignal(
254 power_manager::kPowerManagerInterface,
255 power_manager::kPeripheralBatteryStatusSignal,
256 base::Bind(&PowerManagerClientImpl::PeripheralBatteryStatusReceived,
257 weak_ptr_factory_.GetWeakPtr()),
258 base::Bind(&PowerManagerClientImpl::SignalConnected,
259 weak_ptr_factory_.GetWeakPtr()));
260
261 power_manager_proxy_->ConnectToSignal(
262 power_manager::kPowerManagerInterface,
263 power_manager::kPowerSupplyPollSignal,
264 base::Bind(&PowerManagerClientImpl::PowerSupplyPollReceived,
265 weak_ptr_factory_.GetWeakPtr()),
266 base::Bind(&PowerManagerClientImpl::SignalConnected,
267 weak_ptr_factory_.GetWeakPtr()));
268
269 power_manager_proxy_->ConnectToSignal(
270 power_manager::kPowerManagerInterface,
271 power_manager::kInputEventSignal,
272 base::Bind(&PowerManagerClientImpl::InputEventReceived,
273 weak_ptr_factory_.GetWeakPtr()),
274 base::Bind(&PowerManagerClientImpl::SignalConnected,
275 weak_ptr_factory_.GetWeakPtr()));
276
277 power_manager_proxy_->ConnectToSignal(
278 power_manager::kPowerManagerInterface,
279 power_manager::kSuspendImminentSignal,
280 base::Bind(
281 &PowerManagerClientImpl::HandleSuspendImminent,
282 weak_ptr_factory_.GetWeakPtr(), false),
283 base::Bind(&PowerManagerClientImpl::SignalConnected,
284 weak_ptr_factory_.GetWeakPtr()));
285
286 power_manager_proxy_->ConnectToSignal(
287 power_manager::kPowerManagerInterface,
288 power_manager::kSuspendDoneSignal,
289 base::Bind(&PowerManagerClientImpl::SuspendDoneReceived,
290 weak_ptr_factory_.GetWeakPtr()),
291 base::Bind(&PowerManagerClientImpl::SignalConnected,
292 weak_ptr_factory_.GetWeakPtr()));
293
294 power_manager_proxy_->ConnectToSignal(
295 power_manager::kPowerManagerInterface,
296 power_manager::kDarkSuspendImminentSignal,
297 base::Bind(
298 &PowerManagerClientImpl::HandleSuspendImminent,
299 weak_ptr_factory_.GetWeakPtr(), true),
300 base::Bind(&PowerManagerClientImpl::SignalConnected,
301 weak_ptr_factory_.GetWeakPtr()));
302
303 power_manager_proxy_->ConnectToSignal(
304 power_manager::kPowerManagerInterface,
305 power_manager::kIdleActionImminentSignal,
306 base::Bind(
307 &PowerManagerClientImpl::IdleActionImminentReceived,
308 weak_ptr_factory_.GetWeakPtr()),
309 base::Bind(&PowerManagerClientImpl::SignalConnected,
310 weak_ptr_factory_.GetWeakPtr()));
311
312 power_manager_proxy_->ConnectToSignal(
313 power_manager::kPowerManagerInterface,
314 power_manager::kIdleActionDeferredSignal,
315 base::Bind(
316 &PowerManagerClientImpl::IdleActionDeferredReceived,
317 weak_ptr_factory_.GetWeakPtr()),
318 base::Bind(&PowerManagerClientImpl::SignalConnected,
319 weak_ptr_factory_.GetWeakPtr()));
320
321 RegisterSuspendDelays();
322 }
323
324 private:
325 // Returns true if the current thread is the origin thread.
OnOriginThread()326 bool OnOriginThread() {
327 return base::PlatformThread::CurrentId() == origin_thread_id_;
328 }
329
330 // Called when a dbus signal is initially connected.
SignalConnected(const std::string & interface_name,const std::string & signal_name,bool success)331 void SignalConnected(const std::string& interface_name,
332 const std::string& signal_name,
333 bool success) {
334 LOG_IF(WARNING, !success) << "Failed to connect to signal "
335 << signal_name << ".";
336 }
337
338 // Makes a method call to power manager with no arguments and no response.
SimpleMethodCallToPowerManager(const std::string & method_name)339 void SimpleMethodCallToPowerManager(const std::string& method_name) {
340 dbus::MethodCall method_call(power_manager::kPowerManagerInterface,
341 method_name);
342 power_manager_proxy_->CallMethod(
343 &method_call,
344 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
345 dbus::ObjectProxy::EmptyResponseCallback());
346 }
347
NameOwnerChangedReceived(const std::string & old_owner,const std::string & new_owner)348 void NameOwnerChangedReceived(const std::string& old_owner,
349 const std::string& new_owner) {
350 VLOG(1) << "Power manager restarted (old owner was "
351 << (old_owner.empty() ? "[none]" : old_owner.c_str())
352 << ", new owner is "
353 << (new_owner.empty() ? "[none]" : new_owner.c_str()) << ")";
354 suspend_is_pending_ = false;
355 pending_suspend_id_ = -1;
356 suspending_from_dark_resume_ = false;
357 if (!new_owner.empty()) {
358 VLOG(1) << "Sending initial state to power manager";
359 RegisterSuspendDelays();
360 SetIsProjecting(last_is_projecting_);
361 FOR_EACH_OBSERVER(Observer, observers_, PowerManagerRestarted());
362 }
363 }
364
BrightnessChangedReceived(dbus::Signal * signal)365 void BrightnessChangedReceived(dbus::Signal* signal) {
366 dbus::MessageReader reader(signal);
367 int32_t brightness_level = 0;
368 bool user_initiated = 0;
369 if (!(reader.PopInt32(&brightness_level) &&
370 reader.PopBool(&user_initiated))) {
371 LOG(ERROR) << "Brightness changed signal had incorrect parameters: "
372 << signal->ToString();
373 return;
374 }
375 VLOG(1) << "Brightness changed to " << brightness_level
376 << ": user initiated " << user_initiated;
377 FOR_EACH_OBSERVER(Observer, observers_,
378 BrightnessChanged(brightness_level, user_initiated));
379 }
380
PeripheralBatteryStatusReceived(dbus::Signal * signal)381 void PeripheralBatteryStatusReceived(dbus::Signal* signal) {
382 dbus::MessageReader reader(signal);
383 power_manager::PeripheralBatteryStatus protobuf_status;
384 if (!reader.PopArrayOfBytesAsProto(&protobuf_status)) {
385 LOG(ERROR) << "Unable to decode protocol buffer from "
386 << power_manager::kPeripheralBatteryStatusSignal << " signal";
387 return;
388 }
389
390 std::string path = protobuf_status.path();
391 std::string name = protobuf_status.name();
392 int level = protobuf_status.has_level() ? protobuf_status.level() : -1;
393
394 VLOG(1) << "Device battery status received " << level
395 << " for " << name << " at " << path;
396
397 FOR_EACH_OBSERVER(Observer, observers_,
398 PeripheralBatteryStatusReceived(path, name, level));
399 }
400
PowerSupplyPollReceived(dbus::Signal * signal)401 void PowerSupplyPollReceived(dbus::Signal* signal) {
402 VLOG(1) << "Received power supply poll signal.";
403 dbus::MessageReader reader(signal);
404 power_manager::PowerSupplyProperties protobuf;
405 if (reader.PopArrayOfBytesAsProto(&protobuf)) {
406 FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(protobuf));
407 } else {
408 LOG(ERROR) << "Unable to decode "
409 << power_manager::kPowerSupplyPollSignal << "signal";
410 }
411 }
412
OnGetPowerSupplyPropertiesMethod(dbus::Response * response)413 void OnGetPowerSupplyPropertiesMethod(dbus::Response* response) {
414 if (!response) {
415 LOG(ERROR) << "Error calling "
416 << power_manager::kGetPowerSupplyPropertiesMethod;
417 return;
418 }
419
420 dbus::MessageReader reader(response);
421 power_manager::PowerSupplyProperties protobuf;
422 if (reader.PopArrayOfBytesAsProto(&protobuf)) {
423 FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(protobuf));
424 } else {
425 LOG(ERROR) << "Unable to decode "
426 << power_manager::kGetPowerSupplyPropertiesMethod
427 << " response";
428 }
429 }
430
OnGetScreenBrightnessPercent(const GetScreenBrightnessPercentCallback & callback,dbus::Response * response)431 void OnGetScreenBrightnessPercent(
432 const GetScreenBrightnessPercentCallback& callback,
433 dbus::Response* response) {
434 if (!response) {
435 LOG(ERROR) << "Error calling "
436 << power_manager::kGetScreenBrightnessPercentMethod;
437 return;
438 }
439 dbus::MessageReader reader(response);
440 double percent = 0.0;
441 if (!reader.PopDouble(&percent))
442 LOG(ERROR) << "Error reading response from powerd: "
443 << response->ToString();
444 callback.Run(percent);
445 }
446
HandleRegisterSuspendDelayReply(bool dark_suspend,const std::string & method_name,dbus::Response * response)447 void HandleRegisterSuspendDelayReply(bool dark_suspend,
448 const std::string& method_name,
449 dbus::Response* response) {
450 if (!response) {
451 LOG(ERROR) << "Error calling " << method_name;
452 return;
453 }
454
455 dbus::MessageReader reader(response);
456 power_manager::RegisterSuspendDelayReply protobuf;
457 if (!reader.PopArrayOfBytesAsProto(&protobuf)) {
458 LOG(ERROR) << "Unable to parse reply from " << method_name;
459 return;
460 }
461
462 if (dark_suspend) {
463 dark_suspend_delay_id_ = protobuf.delay_id();
464 has_dark_suspend_delay_id_ = true;
465 VLOG(1) << "Registered dark suspend delay " << dark_suspend_delay_id_;
466 } else {
467 suspend_delay_id_ = protobuf.delay_id();
468 has_suspend_delay_id_ = true;
469 VLOG(1) << "Registered suspend delay " << suspend_delay_id_;
470 }
471 }
472
HandleSuspendImminent(bool in_dark_resume,dbus::Signal * signal)473 void HandleSuspendImminent(bool in_dark_resume, dbus::Signal* signal) {
474 std::string signal_name = signal->GetMember();
475 if ((in_dark_resume && !has_dark_suspend_delay_id_) ||
476 (!in_dark_resume && !has_suspend_delay_id_)) {
477 LOG(ERROR) << "Received unrequested " << signal_name << " signal";
478 return;
479 }
480
481 dbus::MessageReader reader(signal);
482 power_manager::SuspendImminent proto;
483 if (!reader.PopArrayOfBytesAsProto(&proto)) {
484 LOG(ERROR) << "Unable to decode protocol buffer from " << signal_name
485 << " signal";
486 return;
487 }
488
489 VLOG(1) << "Got " << signal_name << " signal announcing suspend attempt "
490 << proto.suspend_id();
491
492 // If a previous suspend is pending from the same state we are currently in
493 // (fully powered on or in dark resume), then something's gone a little
494 // wonky.
495 if (suspend_is_pending_ &&
496 suspending_from_dark_resume_ == in_dark_resume) {
497 LOG(WARNING) << "Got " << signal_name << " signal about pending suspend "
498 << "attempt " << proto.suspend_id() << " while still "
499 << "waiting on attempt " << pending_suspend_id_;
500 }
501
502 pending_suspend_id_ = proto.suspend_id();
503 suspend_is_pending_ = true;
504 suspending_from_dark_resume_ = in_dark_resume;
505 num_pending_suspend_readiness_callbacks_ = 0;
506 if (suspending_from_dark_resume_)
507 FOR_EACH_OBSERVER(Observer, observers_, DarkSuspendImminent());
508 else
509 FOR_EACH_OBSERVER(Observer, observers_, SuspendImminent());
510 MaybeReportSuspendReadiness();
511 }
512
SuspendDoneReceived(dbus::Signal * signal)513 void SuspendDoneReceived(dbus::Signal* signal) {
514 dbus::MessageReader reader(signal);
515 power_manager::SuspendDone proto;
516 if (!reader.PopArrayOfBytesAsProto(&proto)) {
517 LOG(ERROR) << "Unable to decode protocol buffer from "
518 << power_manager::kSuspendDoneSignal << " signal";
519 return;
520 }
521
522 const base::TimeDelta duration =
523 base::TimeDelta::FromInternalValue(proto.suspend_duration());
524 VLOG(1) << "Got " << power_manager::kSuspendDoneSignal << " signal:"
525 << " suspend_id=" << proto.suspend_id()
526 << " duration=" << duration.InSeconds() << " sec";
527 FOR_EACH_OBSERVER(
528 PowerManagerClient::Observer, observers_, SuspendDone(duration));
529 }
530
IdleActionImminentReceived(dbus::Signal * signal)531 void IdleActionImminentReceived(dbus::Signal* signal) {
532 dbus::MessageReader reader(signal);
533 power_manager::IdleActionImminent proto;
534 if (!reader.PopArrayOfBytesAsProto(&proto)) {
535 LOG(ERROR) << "Unable to decode protocol buffer from "
536 << power_manager::kIdleActionImminentSignal << " signal";
537 return;
538 }
539 FOR_EACH_OBSERVER(Observer, observers_,
540 IdleActionImminent(base::TimeDelta::FromInternalValue(
541 proto.time_until_idle_action())));
542 }
543
IdleActionDeferredReceived(dbus::Signal * signal)544 void IdleActionDeferredReceived(dbus::Signal* signal) {
545 FOR_EACH_OBSERVER(Observer, observers_, IdleActionDeferred());
546 }
547
InputEventReceived(dbus::Signal * signal)548 void InputEventReceived(dbus::Signal* signal) {
549 dbus::MessageReader reader(signal);
550 power_manager::InputEvent proto;
551 if (!reader.PopArrayOfBytesAsProto(&proto)) {
552 LOG(ERROR) << "Unable to decode protocol buffer from "
553 << power_manager::kInputEventSignal << " signal";
554 return;
555 }
556
557 base::TimeTicks timestamp =
558 base::TimeTicks::FromInternalValue(proto.timestamp());
559 VLOG(1) << "Got " << power_manager::kInputEventSignal << " signal:"
560 << " type=" << proto.type() << " timestamp=" << proto.timestamp();
561 switch (proto.type()) {
562 case power_manager::InputEvent_Type_POWER_BUTTON_DOWN:
563 case power_manager::InputEvent_Type_POWER_BUTTON_UP: {
564 const bool down =
565 (proto.type() == power_manager::InputEvent_Type_POWER_BUTTON_DOWN);
566 FOR_EACH_OBSERVER(PowerManagerClient::Observer, observers_,
567 PowerButtonEventReceived(down, timestamp));
568
569 // Tell powerd that Chrome has handled power button presses.
570 if (down) {
571 dbus::MethodCall method_call(
572 power_manager::kPowerManagerInterface,
573 power_manager::kHandlePowerButtonAcknowledgmentMethod);
574 dbus::MessageWriter writer(&method_call);
575 writer.AppendInt64(proto.timestamp());
576 power_manager_proxy_->CallMethod(
577 &method_call,
578 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
579 dbus::ObjectProxy::EmptyResponseCallback());
580 }
581 break;
582 }
583 case power_manager::InputEvent_Type_LID_OPEN:
584 case power_manager::InputEvent_Type_LID_CLOSED: {
585 bool open =
586 (proto.type() == power_manager::InputEvent_Type_LID_OPEN);
587 FOR_EACH_OBSERVER(PowerManagerClient::Observer, observers_,
588 LidEventReceived(open, timestamp));
589 break;
590 }
591 }
592 }
593
RegisterSuspendDelayImpl(const std::string & method_name,const power_manager::RegisterSuspendDelayRequest & protobuf_request,dbus::ObjectProxy::ResponseCallback callback)594 void RegisterSuspendDelayImpl(
595 const std::string& method_name,
596 const power_manager::RegisterSuspendDelayRequest& protobuf_request,
597 dbus::ObjectProxy::ResponseCallback callback) {
598 dbus::MethodCall method_call(
599 power_manager::kPowerManagerInterface, method_name);
600 dbus::MessageWriter writer(&method_call);
601
602 if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) {
603 LOG(ERROR) << "Error constructing message for " << method_name;
604 return;
605 }
606
607 power_manager_proxy_->CallMethod(
608 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, callback);
609 }
610
611 // Registers suspend delays with the power manager. This is usually only
612 // called at startup, but if the power manager restarts, we need to create new
613 // delays.
RegisterSuspendDelays()614 void RegisterSuspendDelays() {
615 // Throw out any old delay that was registered.
616 suspend_delay_id_ = -1;
617 has_suspend_delay_id_ = false;
618 dark_suspend_delay_id_ = -1;
619 has_dark_suspend_delay_id_ = false;
620
621 power_manager::RegisterSuspendDelayRequest protobuf_request;
622 base::TimeDelta timeout =
623 base::TimeDelta::FromMilliseconds(kSuspendDelayTimeoutMs);
624 protobuf_request.set_timeout(timeout.ToInternalValue());
625 protobuf_request.set_description(kSuspendDelayDescription);
626
627 RegisterSuspendDelayImpl(
628 power_manager::kRegisterSuspendDelayMethod,
629 protobuf_request,
630 base::Bind(&PowerManagerClientImpl::HandleRegisterSuspendDelayReply,
631 weak_ptr_factory_.GetWeakPtr(), false,
632 power_manager::kRegisterSuspendDelayMethod));
633 RegisterSuspendDelayImpl(
634 power_manager::kRegisterDarkSuspendDelayMethod,
635 protobuf_request,
636 base::Bind(&PowerManagerClientImpl::HandleRegisterSuspendDelayReply,
637 weak_ptr_factory_.GetWeakPtr(), true,
638 power_manager::kRegisterDarkSuspendDelayMethod));
639 }
640
641 // Records the fact that an observer has finished doing asynchronous work
642 // that was blocking a pending suspend attempt and possibly reports
643 // suspend readiness to powerd. Called by callbacks returned via
644 // GetSuspendReadinessCallback().
HandleObserverSuspendReadiness(int32_t suspend_id,bool in_dark_resume)645 void HandleObserverSuspendReadiness(int32_t suspend_id, bool in_dark_resume) {
646 DCHECK(OnOriginThread());
647 if (!suspend_is_pending_ || suspend_id != pending_suspend_id_ ||
648 in_dark_resume != suspending_from_dark_resume_)
649 return;
650
651 num_pending_suspend_readiness_callbacks_--;
652 MaybeReportSuspendReadiness();
653 }
654
655 // Reports suspend readiness to powerd if no observers are still holding
656 // suspend readiness callbacks.
MaybeReportSuspendReadiness()657 void MaybeReportSuspendReadiness() {
658 if (!suspend_is_pending_ || num_pending_suspend_readiness_callbacks_ > 0)
659 return;
660
661 std::string method_name;
662 int32_t delay_id = -1;
663 if (suspending_from_dark_resume_) {
664 method_name = power_manager::kHandleDarkSuspendReadinessMethod;
665 delay_id = dark_suspend_delay_id_;
666 } else {
667 method_name = power_manager::kHandleSuspendReadinessMethod;
668 delay_id = suspend_delay_id_;
669 }
670
671 dbus::MethodCall method_call(
672 power_manager::kPowerManagerInterface, method_name);
673 dbus::MessageWriter writer(&method_call);
674
675 VLOG(1) << "Announcing readiness of suspend delay " << delay_id
676 << " for suspend attempt " << pending_suspend_id_;
677 power_manager::SuspendReadinessInfo protobuf_request;
678 protobuf_request.set_delay_id(delay_id);
679 protobuf_request.set_suspend_id(pending_suspend_id_);
680
681 pending_suspend_id_ = -1;
682 suspend_is_pending_ = false;
683
684 if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) {
685 LOG(ERROR) << "Error constructing message for " << method_name;
686 return;
687 }
688 power_manager_proxy_->CallMethod(
689 &method_call,
690 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
691 dbus::ObjectProxy::EmptyResponseCallback());
692 }
693
694 // Origin thread (i.e. the UI thread in production).
695 base::PlatformThreadId origin_thread_id_;
696
697 dbus::ObjectProxy* power_manager_proxy_;
698 ObserverList<Observer> observers_;
699
700 // The delay_id_ obtained from the RegisterSuspendDelay request.
701 int32_t suspend_delay_id_;
702 bool has_suspend_delay_id_;
703
704 // The delay_id_ obtained from the RegisterDarkSuspendDelay request.
705 int32_t dark_suspend_delay_id_;
706 bool has_dark_suspend_delay_id_;
707
708 // powerd-supplied ID corresponding to an imminent suspend attempt that is
709 // currently being delayed.
710 int32_t pending_suspend_id_;
711 bool suspend_is_pending_;
712
713 // Set to true when the suspend currently being delayed was triggered during a
714 // dark resume. Since |pending_suspend_id_| and |suspend_is_pending_| are
715 // both shared by normal and dark suspends, |suspending_from_dark_resume_|
716 // helps distinguish the context within which these variables are being used.
717 bool suspending_from_dark_resume_;
718
719 // Number of callbacks that have been returned by
720 // GetSuspendReadinessCallback() during the currently-pending suspend
721 // attempt but have not yet been called.
722 int num_pending_suspend_readiness_callbacks_;
723
724 // Last state passed to SetIsProjecting().
725 bool last_is_projecting_;
726
727 // Note: This should remain the last member so it'll be destroyed and
728 // invalidate its weak pointers before any other members are destroyed.
729 base::WeakPtrFactory<PowerManagerClientImpl> weak_ptr_factory_;
730
731 DISALLOW_COPY_AND_ASSIGN(PowerManagerClientImpl);
732 };
733
734 // The PowerManagerClient implementation used on Linux desktop,
735 // which does nothing.
736 class PowerManagerClientStubImpl : public PowerManagerClient {
737 public:
PowerManagerClientStubImpl()738 PowerManagerClientStubImpl()
739 : discharging_(true),
740 battery_percentage_(40),
741 brightness_(50.0),
742 pause_count_(2),
743 cycle_count_(0),
744 num_pending_suspend_readiness_callbacks_(0),
745 weak_ptr_factory_(this) {}
746
~PowerManagerClientStubImpl()747 virtual ~PowerManagerClientStubImpl() {}
748
num_pending_suspend_readiness_callbacks() const749 int num_pending_suspend_readiness_callbacks() const {
750 return num_pending_suspend_readiness_callbacks_;
751 }
752
753 // PowerManagerClient overrides:
Init(dbus::Bus * bus)754 virtual void Init(dbus::Bus* bus) OVERRIDE {
755 ParseCommandLineSwitch();
756 if (power_cycle_delay_ != base::TimeDelta()) {
757 update_timer_.Start(FROM_HERE,
758 power_cycle_delay_,
759 this,
760 &PowerManagerClientStubImpl::UpdateStatus);
761 }
762 }
763
AddObserver(Observer * observer)764 virtual void AddObserver(Observer* observer) OVERRIDE {
765 observers_.AddObserver(observer);
766 }
767
RemoveObserver(Observer * observer)768 virtual void RemoveObserver(Observer* observer) OVERRIDE {
769 observers_.RemoveObserver(observer);
770 }
771
HasObserver(Observer * observer)772 virtual bool HasObserver(Observer* observer) OVERRIDE {
773 return observers_.HasObserver(observer);
774 }
775
DecreaseScreenBrightness(bool allow_off)776 virtual void DecreaseScreenBrightness(bool allow_off) OVERRIDE {
777 VLOG(1) << "Requested to descrease screen brightness";
778 SetBrightness(brightness_ - 5.0, true);
779 }
780
IncreaseScreenBrightness()781 virtual void IncreaseScreenBrightness() OVERRIDE {
782 VLOG(1) << "Requested to increase screen brightness";
783 SetBrightness(brightness_ + 5.0, true);
784 }
785
SetScreenBrightnessPercent(double percent,bool gradual)786 virtual void SetScreenBrightnessPercent(double percent,
787 bool gradual) OVERRIDE {
788 VLOG(1) << "Requested to set screen brightness to " << percent << "% "
789 << (gradual ? "gradually" : "instantaneously");
790 SetBrightness(percent, false);
791 }
792
GetScreenBrightnessPercent(const GetScreenBrightnessPercentCallback & callback)793 virtual void GetScreenBrightnessPercent(
794 const GetScreenBrightnessPercentCallback& callback) OVERRIDE {
795 callback.Run(brightness_);
796 }
797
DecreaseKeyboardBrightness()798 virtual void DecreaseKeyboardBrightness() OVERRIDE {
799 VLOG(1) << "Requested to descrease keyboard brightness";
800 }
801
IncreaseKeyboardBrightness()802 virtual void IncreaseKeyboardBrightness() OVERRIDE {
803 VLOG(1) << "Requested to increase keyboard brightness";
804 }
805
RequestStatusUpdate()806 virtual void RequestStatusUpdate() OVERRIDE {
807 base::MessageLoop::current()->PostTask(FROM_HERE,
808 base::Bind(&PowerManagerClientStubImpl::UpdateStatus,
809 weak_ptr_factory_.GetWeakPtr()));
810 }
811
RequestSuspend()812 virtual void RequestSuspend() OVERRIDE {}
RequestRestart()813 virtual void RequestRestart() OVERRIDE {}
RequestShutdown()814 virtual void RequestShutdown() OVERRIDE {}
815
NotifyUserActivity(power_manager::UserActivityType type)816 virtual void NotifyUserActivity(
817 power_manager::UserActivityType type) OVERRIDE {}
NotifyVideoActivity(bool is_fullscreen)818 virtual void NotifyVideoActivity(bool is_fullscreen) OVERRIDE {}
SetPolicy(const power_manager::PowerManagementPolicy & policy)819 virtual void SetPolicy(
820 const power_manager::PowerManagementPolicy& policy) OVERRIDE {}
SetIsProjecting(bool is_projecting)821 virtual void SetIsProjecting(bool is_projecting) OVERRIDE {}
GetSuspendReadinessCallback()822 virtual base::Closure GetSuspendReadinessCallback() OVERRIDE {
823 num_pending_suspend_readiness_callbacks_++;
824 return base::Bind(&PowerManagerClientStubImpl::HandleSuspendReadiness,
825 weak_ptr_factory_.GetWeakPtr());
826 }
GetNumPendingSuspendReadinessCallbacks()827 virtual int GetNumPendingSuspendReadinessCallbacks() OVERRIDE {
828 return num_pending_suspend_readiness_callbacks_;
829 }
830
831 private:
HandleSuspendReadiness()832 void HandleSuspendReadiness() {
833 num_pending_suspend_readiness_callbacks_--;
834 }
835
UpdateStatus()836 void UpdateStatus() {
837 if (pause_count_ > 0) {
838 pause_count_--;
839 if (pause_count_ == 2)
840 discharging_ = !discharging_;
841 } else {
842 if (discharging_)
843 battery_percentage_ -= (battery_percentage_ <= 10 ? 1 : 10);
844 else
845 battery_percentage_ += (battery_percentage_ >= 10 ? 10 : 1);
846 battery_percentage_ = std::min(std::max(battery_percentage_, 0), 100);
847 // We pause at 0 and 100% so that it's easier to check those conditions.
848 if (battery_percentage_ == 0 || battery_percentage_ == 100) {
849 pause_count_ = 4;
850 if (battery_percentage_ == 100)
851 cycle_count_ = (cycle_count_ + 1) % 3;
852 }
853 }
854
855 const int kSecondsToEmptyFullBattery = 3 * 60 * 60; // 3 hours.
856 int64 remaining_battery_time =
857 std::max(1, battery_percentage_ * kSecondsToEmptyFullBattery / 100);
858
859 props_.Clear();
860
861 switch (cycle_count_) {
862 case 0:
863 // Say that the system is charging with AC connected and
864 // discharging without any charger connected.
865 props_.set_external_power(discharging_ ?
866 power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED :
867 power_manager::PowerSupplyProperties_ExternalPower_AC);
868 break;
869 case 1:
870 // Say that the system is both charging and discharging on USB
871 // (i.e. a low-power charger).
872 props_.set_external_power(
873 power_manager::PowerSupplyProperties_ExternalPower_USB);
874 break;
875 case 2:
876 // Say that the system is both charging and discharging on AC.
877 props_.set_external_power(
878 power_manager::PowerSupplyProperties_ExternalPower_AC);
879 break;
880 default:
881 NOTREACHED() << "Unhandled cycle " << cycle_count_;
882 }
883
884 if (battery_percentage_ == 100 && !discharging_) {
885 props_.set_battery_state(
886 power_manager::PowerSupplyProperties_BatteryState_FULL);
887 } else if (!discharging_) {
888 props_.set_battery_state(
889 power_manager::PowerSupplyProperties_BatteryState_CHARGING);
890 props_.set_battery_time_to_full_sec(std::max(static_cast<int64>(1),
891 kSecondsToEmptyFullBattery - remaining_battery_time));
892 } else {
893 props_.set_battery_state(
894 power_manager::PowerSupplyProperties_BatteryState_DISCHARGING);
895 props_.set_battery_time_to_empty_sec(remaining_battery_time);
896 }
897
898 props_.set_battery_percent(battery_percentage_);
899 props_.set_is_calculating_battery_time(pause_count_ > 1);
900
901 FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(props_));
902 }
903
SetBrightness(double percent,bool user_initiated)904 void SetBrightness(double percent, bool user_initiated) {
905 brightness_ = std::min(std::max(0.0, percent), 100.0);
906 int brightness_level = static_cast<int>(brightness_);
907 FOR_EACH_OBSERVER(Observer, observers_,
908 BrightnessChanged(brightness_level, user_initiated));
909 }
910
ParseCommandLineSwitch()911 void ParseCommandLineSwitch() {
912 CommandLine* command_line = CommandLine::ForCurrentProcess();
913 if (!command_line || !command_line->HasSwitch(switches::kPowerStub))
914 return;
915 std::string option_str =
916 command_line->GetSwitchValueASCII(switches::kPowerStub);
917 base::StringPairs string_pairs;
918 base::SplitStringIntoKeyValuePairs(option_str, '=', ',', &string_pairs);
919 for (base::StringPairs::iterator iter = string_pairs.begin();
920 iter != string_pairs.end(); ++iter) {
921 ParseOption((*iter).first, (*iter).second);
922 }
923 }
924
ParseOption(const std::string & arg0,const std::string & arg1)925 void ParseOption(const std::string& arg0, const std::string& arg1) {
926 if (arg0 == "cycle" || arg0 == "interactive") {
927 int seconds = 1;
928 if (!arg1.empty())
929 base::StringToInt(arg1, &seconds);
930 power_cycle_delay_ = base::TimeDelta::FromSeconds(seconds);
931 }
932 }
933
934 base::TimeDelta power_cycle_delay_; // Time over which to cycle power state
935 bool discharging_;
936 int battery_percentage_;
937 double brightness_;
938 int pause_count_;
939 int cycle_count_;
940 ObserverList<Observer> observers_;
941 base::RepeatingTimer<PowerManagerClientStubImpl> update_timer_;
942 power_manager::PowerSupplyProperties props_;
943
944 // Number of callbacks returned by GetSuspendReadinessCallback() but not yet
945 // invoked.
946 int num_pending_suspend_readiness_callbacks_;
947
948 // Note: This should remain the last member so it'll be destroyed and
949 // invalidate its weak pointers before any other members are destroyed.
950 base::WeakPtrFactory<PowerManagerClientStubImpl> weak_ptr_factory_;
951 };
952
PowerManagerClient()953 PowerManagerClient::PowerManagerClient() {
954 }
955
~PowerManagerClient()956 PowerManagerClient::~PowerManagerClient() {
957 }
958
959 // static
Create(DBusClientImplementationType type)960 PowerManagerClient* PowerManagerClient::Create(
961 DBusClientImplementationType type) {
962 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
963 return new PowerManagerClientImpl();
964 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
965 return new PowerManagerClientStubImpl();
966 }
967
968 } // namespace chromeos
969