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.
5 #include "chromeos/dbus/power_manager_client.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"
30 #include "dbus/message.h"
31 #include "dbus/object_path.h"
32 #include "dbus/object_proxy.h"
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;
40 // Human-readable description of Chrome's suspend delay.
41 const char kSuspendDelayDescription
[] = "chrome";
43 // The PowerManagerClient implementation used in production.
44 class PowerManagerClientImpl
: public PowerManagerClient
{
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) {}
60 virtual ~PowerManagerClientImpl() {
61 // Here we should unregister suspend notifications from powerd,
63 // - The lifetime of the PowerManagerClientImpl can extend past that of
65 // - power_manager can already detect that the client is gone and
66 // unregister our suspend delay.
69 // PowerManagerClient overrides:
71 virtual void AddObserver(Observer
* observer
) OVERRIDE
{
72 CHECK(observer
); // http://crbug.com/119976
73 observers_
.AddObserver(observer
);
76 virtual void RemoveObserver(Observer
* observer
) OVERRIDE
{
77 observers_
.RemoveObserver(observer
);
80 virtual bool HasObserver(Observer
* observer
) OVERRIDE
{
81 return observers_
.HasObserver(observer
);
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(
92 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
93 dbus::ObjectProxy::EmptyResponseCallback());
96 virtual void IncreaseScreenBrightness() OVERRIDE
{
97 SimpleMethodCallToPowerManager(
98 power_manager::kIncreaseScreenBrightnessMethod
);
101 virtual void DecreaseKeyboardBrightness() OVERRIDE
{
102 SimpleMethodCallToPowerManager(
103 power_manager::kDecreaseKeyboardBrightnessMethod
);
106 virtual void IncreaseKeyboardBrightness() OVERRIDE
{
107 SimpleMethodCallToPowerManager(
108 power_manager::kIncreaseKeyboardBrightnessMethod
);
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
);
120 power_manager::kBrightnessTransitionGradual
:
121 power_manager::kBrightnessTransitionInstant
);
122 power_manager_proxy_
->CallMethod(
124 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
125 dbus::ObjectProxy::EmptyResponseCallback());
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(
135 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
136 base::Bind(&PowerManagerClientImpl::OnGetScreenBrightnessPercent
,
137 weak_ptr_factory_
.GetWeakPtr(), callback
));
140 virtual void RequestStatusUpdate() OVERRIDE
{
141 dbus::MethodCall
method_call(
142 power_manager::kPowerManagerInterface
,
143 power_manager::kGetPowerSupplyPropertiesMethod
);
144 power_manager_proxy_
->CallMethod(
146 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
147 base::Bind(&PowerManagerClientImpl::OnGetPowerSupplyPropertiesMethod
,
148 weak_ptr_factory_
.GetWeakPtr()));
151 virtual void RequestRestart() OVERRIDE
{
152 SimpleMethodCallToPowerManager(power_manager::kRequestRestartMethod
);
155 virtual void RequestShutdown() OVERRIDE
{
156 SimpleMethodCallToPowerManager(power_manager::kRequestShutdownMethod
);
159 virtual void NotifyUserActivity(
160 power_manager::UserActivityType type
) OVERRIDE
{
161 dbus::MethodCall
method_call(
162 power_manager::kPowerManagerInterface
,
163 power_manager::kHandleUserActivityMethod
);
164 dbus::MessageWriter
writer(&method_call
);
165 writer
.AppendInt32(type
);
167 power_manager_proxy_
->CallMethod(
169 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
170 dbus::ObjectProxy::EmptyResponseCallback());
173 virtual void NotifyVideoActivity(bool is_fullscreen
) OVERRIDE
{
174 dbus::MethodCall
method_call(
175 power_manager::kPowerManagerInterface
,
176 power_manager::kHandleVideoActivityMethod
);
177 dbus::MessageWriter
writer(&method_call
);
178 writer
.AppendBool(is_fullscreen
);
180 power_manager_proxy_
->CallMethod(
182 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
183 dbus::ObjectProxy::EmptyResponseCallback());
186 virtual void SetPolicy(
187 const power_manager::PowerManagementPolicy
& policy
) OVERRIDE
{
188 dbus::MethodCall
method_call(
189 power_manager::kPowerManagerInterface
,
190 power_manager::kSetPolicyMethod
);
191 dbus::MessageWriter
writer(&method_call
);
192 if (!writer
.AppendProtoAsArrayOfBytes(policy
)) {
193 LOG(ERROR
) << "Error calling " << power_manager::kSetPolicyMethod
;
196 power_manager_proxy_
->CallMethod(
198 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
199 dbus::ObjectProxy::EmptyResponseCallback());
202 virtual void SetIsProjecting(bool is_projecting
) OVERRIDE
{
203 dbus::MethodCall
method_call(
204 power_manager::kPowerManagerInterface
,
205 power_manager::kSetIsProjectingMethod
);
206 dbus::MessageWriter
writer(&method_call
);
207 writer
.AppendBool(is_projecting
);
208 power_manager_proxy_
->CallMethod(
210 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
211 dbus::ObjectProxy::EmptyResponseCallback());
212 last_is_projecting_
= is_projecting
;
215 virtual base::Closure
GetSuspendReadinessCallback() OVERRIDE
{
216 DCHECK(OnOriginThread());
217 DCHECK(suspend_is_pending_
);
218 num_pending_suspend_readiness_callbacks_
++;
219 return base::Bind(&PowerManagerClientImpl::HandleObserverSuspendReadiness
,
220 weak_ptr_factory_
.GetWeakPtr(), pending_suspend_id_
,
221 suspending_from_dark_resume_
);
224 virtual int GetNumPendingSuspendReadinessCallbacks() OVERRIDE
{
225 return num_pending_suspend_readiness_callbacks_
;
229 virtual void Init(dbus::Bus
* bus
) OVERRIDE
{
230 power_manager_proxy_
= bus
->GetObjectProxy(
231 power_manager::kPowerManagerServiceName
,
232 dbus::ObjectPath(power_manager::kPowerManagerServicePath
));
234 power_manager_proxy_
->SetNameOwnerChangedCallback(
235 base::Bind(&PowerManagerClientImpl::NameOwnerChangedReceived
,
236 weak_ptr_factory_
.GetWeakPtr()));
238 // Monitor the D-Bus signal for brightness changes. Only the power
239 // manager knows the actual brightness level. We don't cache the
240 // brightness level in Chrome as it'll make things less reliable.
241 power_manager_proxy_
->ConnectToSignal(
242 power_manager::kPowerManagerInterface
,
243 power_manager::kBrightnessChangedSignal
,
244 base::Bind(&PowerManagerClientImpl::BrightnessChangedReceived
,
245 weak_ptr_factory_
.GetWeakPtr()),
246 base::Bind(&PowerManagerClientImpl::SignalConnected
,
247 weak_ptr_factory_
.GetWeakPtr()));
249 power_manager_proxy_
->ConnectToSignal(
250 power_manager::kPowerManagerInterface
,
251 power_manager::kPeripheralBatteryStatusSignal
,
252 base::Bind(&PowerManagerClientImpl::PeripheralBatteryStatusReceived
,
253 weak_ptr_factory_
.GetWeakPtr()),
254 base::Bind(&PowerManagerClientImpl::SignalConnected
,
255 weak_ptr_factory_
.GetWeakPtr()));
257 power_manager_proxy_
->ConnectToSignal(
258 power_manager::kPowerManagerInterface
,
259 power_manager::kPowerSupplyPollSignal
,
260 base::Bind(&PowerManagerClientImpl::PowerSupplyPollReceived
,
261 weak_ptr_factory_
.GetWeakPtr()),
262 base::Bind(&PowerManagerClientImpl::SignalConnected
,
263 weak_ptr_factory_
.GetWeakPtr()));
265 power_manager_proxy_
->ConnectToSignal(
266 power_manager::kPowerManagerInterface
,
267 power_manager::kInputEventSignal
,
268 base::Bind(&PowerManagerClientImpl::InputEventReceived
,
269 weak_ptr_factory_
.GetWeakPtr()),
270 base::Bind(&PowerManagerClientImpl::SignalConnected
,
271 weak_ptr_factory_
.GetWeakPtr()));
273 power_manager_proxy_
->ConnectToSignal(
274 power_manager::kPowerManagerInterface
,
275 power_manager::kSuspendImminentSignal
,
277 &PowerManagerClientImpl::HandleSuspendImminent
,
278 weak_ptr_factory_
.GetWeakPtr(), false),
279 base::Bind(&PowerManagerClientImpl::SignalConnected
,
280 weak_ptr_factory_
.GetWeakPtr()));
282 power_manager_proxy_
->ConnectToSignal(
283 power_manager::kPowerManagerInterface
,
284 power_manager::kSuspendDoneSignal
,
285 base::Bind(&PowerManagerClientImpl::SuspendDoneReceived
,
286 weak_ptr_factory_
.GetWeakPtr()),
287 base::Bind(&PowerManagerClientImpl::SignalConnected
,
288 weak_ptr_factory_
.GetWeakPtr()));
290 power_manager_proxy_
->ConnectToSignal(
291 power_manager::kPowerManagerInterface
,
292 power_manager::kDarkSuspendImminentSignal
,
294 &PowerManagerClientImpl::HandleSuspendImminent
,
295 weak_ptr_factory_
.GetWeakPtr(), true),
296 base::Bind(&PowerManagerClientImpl::SignalConnected
,
297 weak_ptr_factory_
.GetWeakPtr()));
299 power_manager_proxy_
->ConnectToSignal(
300 power_manager::kPowerManagerInterface
,
301 power_manager::kIdleActionImminentSignal
,
303 &PowerManagerClientImpl::IdleActionImminentReceived
,
304 weak_ptr_factory_
.GetWeakPtr()),
305 base::Bind(&PowerManagerClientImpl::SignalConnected
,
306 weak_ptr_factory_
.GetWeakPtr()));
308 power_manager_proxy_
->ConnectToSignal(
309 power_manager::kPowerManagerInterface
,
310 power_manager::kIdleActionDeferredSignal
,
312 &PowerManagerClientImpl::IdleActionDeferredReceived
,
313 weak_ptr_factory_
.GetWeakPtr()),
314 base::Bind(&PowerManagerClientImpl::SignalConnected
,
315 weak_ptr_factory_
.GetWeakPtr()));
317 RegisterSuspendDelays();
321 // Returns true if the current thread is the origin thread.
322 bool OnOriginThread() {
323 return base::PlatformThread::CurrentId() == origin_thread_id_
;
326 // Called when a dbus signal is initially connected.
327 void SignalConnected(const std::string
& interface_name
,
328 const std::string
& signal_name
,
330 LOG_IF(WARNING
, !success
) << "Failed to connect to signal "
331 << signal_name
<< ".";
334 // Makes a method call to power manager with no arguments and no response.
335 void SimpleMethodCallToPowerManager(const std::string
& method_name
) {
336 dbus::MethodCall
method_call(power_manager::kPowerManagerInterface
,
338 power_manager_proxy_
->CallMethod(
340 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
341 dbus::ObjectProxy::EmptyResponseCallback());
344 void NameOwnerChangedReceived(const std::string
& old_owner
,
345 const std::string
& new_owner
) {
346 VLOG(1) << "Power manager restarted (old owner was "
347 << (old_owner
.empty() ? "[none]" : old_owner
.c_str())
349 << (new_owner
.empty() ? "[none]" : new_owner
.c_str()) << ")";
350 suspend_is_pending_
= false;
351 pending_suspend_id_
= -1;
352 suspending_from_dark_resume_
= false;
353 if (!new_owner
.empty()) {
354 VLOG(1) << "Sending initial state to power manager";
355 RegisterSuspendDelays();
356 SetIsProjecting(last_is_projecting_
);
357 FOR_EACH_OBSERVER(Observer
, observers_
, PowerManagerRestarted());
361 void BrightnessChangedReceived(dbus::Signal
* signal
) {
362 dbus::MessageReader
reader(signal
);
363 int32_t brightness_level
= 0;
364 bool user_initiated
= 0;
365 if (!(reader
.PopInt32(&brightness_level
) &&
366 reader
.PopBool(&user_initiated
))) {
367 LOG(ERROR
) << "Brightness changed signal had incorrect parameters: "
368 << signal
->ToString();
371 VLOG(1) << "Brightness changed to " << brightness_level
372 << ": user initiated " << user_initiated
;
373 FOR_EACH_OBSERVER(Observer
, observers_
,
374 BrightnessChanged(brightness_level
, user_initiated
));
377 void PeripheralBatteryStatusReceived(dbus::Signal
* signal
) {
378 dbus::MessageReader
reader(signal
);
379 power_manager::PeripheralBatteryStatus protobuf_status
;
380 if (!reader
.PopArrayOfBytesAsProto(&protobuf_status
)) {
381 LOG(ERROR
) << "Unable to decode protocol buffer from "
382 << power_manager::kPeripheralBatteryStatusSignal
<< " signal";
386 std::string path
= protobuf_status
.path();
387 std::string name
= protobuf_status
.name();
388 int level
= protobuf_status
.has_level() ? protobuf_status
.level() : -1;
390 VLOG(1) << "Device battery status received " << level
391 << " for " << name
<< " at " << path
;
393 FOR_EACH_OBSERVER(Observer
, observers_
,
394 PeripheralBatteryStatusReceived(path
, name
, level
));
397 void PowerSupplyPollReceived(dbus::Signal
* signal
) {
398 VLOG(1) << "Received power supply poll signal.";
399 dbus::MessageReader
reader(signal
);
400 power_manager::PowerSupplyProperties protobuf
;
401 if (reader
.PopArrayOfBytesAsProto(&protobuf
)) {
402 FOR_EACH_OBSERVER(Observer
, observers_
, PowerChanged(protobuf
));
404 LOG(ERROR
) << "Unable to decode "
405 << power_manager::kPowerSupplyPollSignal
<< "signal";
409 void OnGetPowerSupplyPropertiesMethod(dbus::Response
* response
) {
411 LOG(ERROR
) << "Error calling "
412 << power_manager::kGetPowerSupplyPropertiesMethod
;
416 dbus::MessageReader
reader(response
);
417 power_manager::PowerSupplyProperties protobuf
;
418 if (reader
.PopArrayOfBytesAsProto(&protobuf
)) {
419 FOR_EACH_OBSERVER(Observer
, observers_
, PowerChanged(protobuf
));
421 LOG(ERROR
) << "Unable to decode "
422 << power_manager::kGetPowerSupplyPropertiesMethod
427 void OnGetScreenBrightnessPercent(
428 const GetScreenBrightnessPercentCallback
& callback
,
429 dbus::Response
* response
) {
431 LOG(ERROR
) << "Error calling "
432 << power_manager::kGetScreenBrightnessPercentMethod
;
435 dbus::MessageReader
reader(response
);
436 double percent
= 0.0;
437 if (!reader
.PopDouble(&percent
))
438 LOG(ERROR
) << "Error reading response from powerd: "
439 << response
->ToString();
440 callback
.Run(percent
);
443 void HandleRegisterSuspendDelayReply(bool dark_suspend
,
444 const std::string
& method_name
,
445 dbus::Response
* response
) {
447 LOG(ERROR
) << "Error calling " << method_name
;
451 dbus::MessageReader
reader(response
);
452 power_manager::RegisterSuspendDelayReply protobuf
;
453 if (!reader
.PopArrayOfBytesAsProto(&protobuf
)) {
454 LOG(ERROR
) << "Unable to parse reply from " << method_name
;
459 dark_suspend_delay_id_
= protobuf
.delay_id();
460 has_dark_suspend_delay_id_
= true;
461 VLOG(1) << "Registered dark suspend delay " << dark_suspend_delay_id_
;
463 suspend_delay_id_
= protobuf
.delay_id();
464 has_suspend_delay_id_
= true;
465 VLOG(1) << "Registered suspend delay " << suspend_delay_id_
;
469 void HandleSuspendImminent(bool in_dark_resume
, dbus::Signal
* signal
) {
470 std::string signal_name
= signal
->GetMember();
471 if ((in_dark_resume
&& !has_dark_suspend_delay_id_
) ||
472 (!in_dark_resume
&& !has_suspend_delay_id_
)) {
473 LOG(ERROR
) << "Received unrequested " << signal_name
<< " signal";
477 dbus::MessageReader
reader(signal
);
478 power_manager::SuspendImminent proto
;
479 if (!reader
.PopArrayOfBytesAsProto(&proto
)) {
480 LOG(ERROR
) << "Unable to decode protocol buffer from " << signal_name
485 VLOG(1) << "Got " << signal_name
<< " signal announcing suspend attempt "
486 << proto
.suspend_id();
488 // If a previous suspend is pending from the same state we are currently in
489 // (fully powered on or in dark resume), then something's gone a little
491 if (suspend_is_pending_
&&
492 suspending_from_dark_resume_
== in_dark_resume
) {
493 LOG(WARNING
) << "Got " << signal_name
<< " signal about pending suspend "
494 << "attempt " << proto
.suspend_id() << " while still "
495 << "waiting on attempt " << pending_suspend_id_
;
498 pending_suspend_id_
= proto
.suspend_id();
499 suspend_is_pending_
= true;
500 suspending_from_dark_resume_
= in_dark_resume
;
501 num_pending_suspend_readiness_callbacks_
= 0;
502 if (suspending_from_dark_resume_
)
503 FOR_EACH_OBSERVER(Observer
, observers_
, DarkSuspendImminent());
505 FOR_EACH_OBSERVER(Observer
, observers_
, SuspendImminent());
506 MaybeReportSuspendReadiness();
509 void SuspendDoneReceived(dbus::Signal
* signal
) {
510 dbus::MessageReader
reader(signal
);
511 power_manager::SuspendDone proto
;
512 if (!reader
.PopArrayOfBytesAsProto(&proto
)) {
513 LOG(ERROR
) << "Unable to decode protocol buffer from "
514 << power_manager::kSuspendDoneSignal
<< " signal";
518 const base::TimeDelta duration
=
519 base::TimeDelta::FromInternalValue(proto
.suspend_duration());
520 VLOG(1) << "Got " << power_manager::kSuspendDoneSignal
<< " signal:"
521 << " suspend_id=" << proto
.suspend_id()
522 << " duration=" << duration
.InSeconds() << " sec";
524 PowerManagerClient::Observer
, observers_
, SuspendDone(duration
));
527 void IdleActionImminentReceived(dbus::Signal
* signal
) {
528 dbus::MessageReader
reader(signal
);
529 power_manager::IdleActionImminent proto
;
530 if (!reader
.PopArrayOfBytesAsProto(&proto
)) {
531 LOG(ERROR
) << "Unable to decode protocol buffer from "
532 << power_manager::kIdleActionImminentSignal
<< " signal";
535 FOR_EACH_OBSERVER(Observer
, observers_
,
536 IdleActionImminent(base::TimeDelta::FromInternalValue(
537 proto
.time_until_idle_action())));
540 void IdleActionDeferredReceived(dbus::Signal
* signal
) {
541 FOR_EACH_OBSERVER(Observer
, observers_
, IdleActionDeferred());
544 void InputEventReceived(dbus::Signal
* signal
) {
545 dbus::MessageReader
reader(signal
);
546 power_manager::InputEvent proto
;
547 if (!reader
.PopArrayOfBytesAsProto(&proto
)) {
548 LOG(ERROR
) << "Unable to decode protocol buffer from "
549 << power_manager::kInputEventSignal
<< " signal";
553 base::TimeTicks timestamp
=
554 base::TimeTicks::FromInternalValue(proto
.timestamp());
555 VLOG(1) << "Got " << power_manager::kInputEventSignal
<< " signal:"
556 << " type=" << proto
.type() << " timestamp=" << proto
.timestamp();
557 switch (proto
.type()) {
558 case power_manager::InputEvent_Type_POWER_BUTTON_DOWN
:
559 case power_manager::InputEvent_Type_POWER_BUTTON_UP
: {
561 (proto
.type() == power_manager::InputEvent_Type_POWER_BUTTON_DOWN
);
562 FOR_EACH_OBSERVER(PowerManagerClient::Observer
, observers_
,
563 PowerButtonEventReceived(down
, timestamp
));
565 // Tell powerd that Chrome has handled power button presses.
567 dbus::MethodCall
method_call(
568 power_manager::kPowerManagerInterface
,
569 power_manager::kHandlePowerButtonAcknowledgmentMethod
);
570 dbus::MessageWriter
writer(&method_call
);
571 writer
.AppendInt64(proto
.timestamp());
572 power_manager_proxy_
->CallMethod(
574 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
575 dbus::ObjectProxy::EmptyResponseCallback());
579 case power_manager::InputEvent_Type_LID_OPEN
:
580 case power_manager::InputEvent_Type_LID_CLOSED
: {
582 (proto
.type() == power_manager::InputEvent_Type_LID_OPEN
);
583 FOR_EACH_OBSERVER(PowerManagerClient::Observer
, observers_
,
584 LidEventReceived(open
, timestamp
));
590 void RegisterSuspendDelayImpl(
591 const std::string
& method_name
,
592 const power_manager::RegisterSuspendDelayRequest
& protobuf_request
,
593 dbus::ObjectProxy::ResponseCallback callback
) {
594 dbus::MethodCall
method_call(
595 power_manager::kPowerManagerInterface
, method_name
);
596 dbus::MessageWriter
writer(&method_call
);
598 if (!writer
.AppendProtoAsArrayOfBytes(protobuf_request
)) {
599 LOG(ERROR
) << "Error constructing message for " << method_name
;
603 power_manager_proxy_
->CallMethod(
604 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
, callback
);
607 // Registers suspend delays with the power manager. This is usually only
608 // called at startup, but if the power manager restarts, we need to create new
610 void RegisterSuspendDelays() {
611 // Throw out any old delay that was registered.
612 suspend_delay_id_
= -1;
613 has_suspend_delay_id_
= false;
614 dark_suspend_delay_id_
= -1;
615 has_dark_suspend_delay_id_
= false;
617 power_manager::RegisterSuspendDelayRequest protobuf_request
;
618 base::TimeDelta timeout
=
619 base::TimeDelta::FromMilliseconds(kSuspendDelayTimeoutMs
);
620 protobuf_request
.set_timeout(timeout
.ToInternalValue());
621 protobuf_request
.set_description(kSuspendDelayDescription
);
623 RegisterSuspendDelayImpl(
624 power_manager::kRegisterSuspendDelayMethod
,
626 base::Bind(&PowerManagerClientImpl::HandleRegisterSuspendDelayReply
,
627 weak_ptr_factory_
.GetWeakPtr(), false,
628 power_manager::kRegisterSuspendDelayMethod
));
629 RegisterSuspendDelayImpl(
630 power_manager::kRegisterDarkSuspendDelayMethod
,
632 base::Bind(&PowerManagerClientImpl::HandleRegisterSuspendDelayReply
,
633 weak_ptr_factory_
.GetWeakPtr(), true,
634 power_manager::kRegisterDarkSuspendDelayMethod
));
637 // Records the fact that an observer has finished doing asynchronous work
638 // that was blocking a pending suspend attempt and possibly reports
639 // suspend readiness to powerd. Called by callbacks returned via
640 // GetSuspendReadinessCallback().
641 void HandleObserverSuspendReadiness(int32_t suspend_id
, bool in_dark_resume
) {
642 DCHECK(OnOriginThread());
643 if (!suspend_is_pending_
|| suspend_id
!= pending_suspend_id_
||
644 in_dark_resume
!= suspending_from_dark_resume_
)
647 num_pending_suspend_readiness_callbacks_
--;
648 MaybeReportSuspendReadiness();
651 // Reports suspend readiness to powerd if no observers are still holding
652 // suspend readiness callbacks.
653 void MaybeReportSuspendReadiness() {
654 if (!suspend_is_pending_
|| num_pending_suspend_readiness_callbacks_
> 0)
657 std::string method_name
;
658 int32_t delay_id
= -1;
659 if (suspending_from_dark_resume_
) {
660 method_name
= power_manager::kHandleDarkSuspendReadinessMethod
;
661 delay_id
= dark_suspend_delay_id_
;
663 method_name
= power_manager::kHandleSuspendReadinessMethod
;
664 delay_id
= suspend_delay_id_
;
667 dbus::MethodCall
method_call(
668 power_manager::kPowerManagerInterface
, method_name
);
669 dbus::MessageWriter
writer(&method_call
);
671 VLOG(1) << "Announcing readiness of suspend delay " << delay_id
672 << " for suspend attempt " << pending_suspend_id_
;
673 power_manager::SuspendReadinessInfo protobuf_request
;
674 protobuf_request
.set_delay_id(delay_id
);
675 protobuf_request
.set_suspend_id(pending_suspend_id_
);
677 pending_suspend_id_
= -1;
678 suspend_is_pending_
= false;
680 if (!writer
.AppendProtoAsArrayOfBytes(protobuf_request
)) {
681 LOG(ERROR
) << "Error constructing message for " << method_name
;
684 power_manager_proxy_
->CallMethod(
686 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
687 dbus::ObjectProxy::EmptyResponseCallback());
690 // Origin thread (i.e. the UI thread in production).
691 base::PlatformThreadId origin_thread_id_
;
693 dbus::ObjectProxy
* power_manager_proxy_
;
694 ObserverList
<Observer
> observers_
;
696 // The delay_id_ obtained from the RegisterSuspendDelay request.
697 int32_t suspend_delay_id_
;
698 bool has_suspend_delay_id_
;
700 // The delay_id_ obtained from the RegisterDarkSuspendDelay request.
701 int32_t dark_suspend_delay_id_
;
702 bool has_dark_suspend_delay_id_
;
704 // powerd-supplied ID corresponding to an imminent suspend attempt that is
705 // currently being delayed.
706 int32_t pending_suspend_id_
;
707 bool suspend_is_pending_
;
709 // Set to true when the suspend currently being delayed was triggered during a
710 // dark resume. Since |pending_suspend_id_| and |suspend_is_pending_| are
711 // both shared by normal and dark suspends, |suspending_from_dark_resume_|
712 // helps distinguish the context within which these variables are being used.
713 bool suspending_from_dark_resume_
;
715 // Number of callbacks that have been returned by
716 // GetSuspendReadinessCallback() during the currently-pending suspend
717 // attempt but have not yet been called.
718 int num_pending_suspend_readiness_callbacks_
;
720 // Last state passed to SetIsProjecting().
721 bool last_is_projecting_
;
723 // Note: This should remain the last member so it'll be destroyed and
724 // invalidate its weak pointers before any other members are destroyed.
725 base::WeakPtrFactory
<PowerManagerClientImpl
> weak_ptr_factory_
;
727 DISALLOW_COPY_AND_ASSIGN(PowerManagerClientImpl
);
730 // The PowerManagerClient implementation used on Linux desktop,
731 // which does nothing.
732 class PowerManagerClientStubImpl
: public PowerManagerClient
{
734 PowerManagerClientStubImpl()
735 : discharging_(true),
736 battery_percentage_(40),
740 num_pending_suspend_readiness_callbacks_(0),
741 weak_ptr_factory_(this) {}
743 virtual ~PowerManagerClientStubImpl() {}
745 int num_pending_suspend_readiness_callbacks() const {
746 return num_pending_suspend_readiness_callbacks_
;
749 // PowerManagerClient overrides:
750 virtual void Init(dbus::Bus
* bus
) OVERRIDE
{
751 ParseCommandLineSwitch();
752 if (power_cycle_delay_
!= base::TimeDelta()) {
753 update_timer_
.Start(FROM_HERE
,
756 &PowerManagerClientStubImpl::UpdateStatus
);
760 virtual void AddObserver(Observer
* observer
) OVERRIDE
{
761 observers_
.AddObserver(observer
);
764 virtual void RemoveObserver(Observer
* observer
) OVERRIDE
{
765 observers_
.RemoveObserver(observer
);
768 virtual bool HasObserver(Observer
* observer
) OVERRIDE
{
769 return observers_
.HasObserver(observer
);
772 virtual void DecreaseScreenBrightness(bool allow_off
) OVERRIDE
{
773 VLOG(1) << "Requested to descrease screen brightness";
774 SetBrightness(brightness_
- 5.0, true);
777 virtual void IncreaseScreenBrightness() OVERRIDE
{
778 VLOG(1) << "Requested to increase screen brightness";
779 SetBrightness(brightness_
+ 5.0, true);
782 virtual void SetScreenBrightnessPercent(double percent
,
783 bool gradual
) OVERRIDE
{
784 VLOG(1) << "Requested to set screen brightness to " << percent
<< "% "
785 << (gradual
? "gradually" : "instantaneously");
786 SetBrightness(percent
, false);
789 virtual void GetScreenBrightnessPercent(
790 const GetScreenBrightnessPercentCallback
& callback
) OVERRIDE
{
791 callback
.Run(brightness_
);
794 virtual void DecreaseKeyboardBrightness() OVERRIDE
{
795 VLOG(1) << "Requested to descrease keyboard brightness";
798 virtual void IncreaseKeyboardBrightness() OVERRIDE
{
799 VLOG(1) << "Requested to increase keyboard brightness";
802 virtual void RequestStatusUpdate() OVERRIDE
{
803 base::MessageLoop::current()->PostTask(FROM_HERE
,
804 base::Bind(&PowerManagerClientStubImpl::UpdateStatus
,
805 weak_ptr_factory_
.GetWeakPtr()));
808 virtual void RequestRestart() OVERRIDE
{}
809 virtual void RequestShutdown() OVERRIDE
{}
811 virtual void NotifyUserActivity(
812 power_manager::UserActivityType type
) OVERRIDE
{}
813 virtual void NotifyVideoActivity(bool is_fullscreen
) OVERRIDE
{}
814 virtual void SetPolicy(
815 const power_manager::PowerManagementPolicy
& policy
) OVERRIDE
{}
816 virtual void SetIsProjecting(bool is_projecting
) OVERRIDE
{}
817 virtual base::Closure
GetSuspendReadinessCallback() OVERRIDE
{
818 num_pending_suspend_readiness_callbacks_
++;
819 return base::Bind(&PowerManagerClientStubImpl::HandleSuspendReadiness
,
820 weak_ptr_factory_
.GetWeakPtr());
822 virtual int GetNumPendingSuspendReadinessCallbacks() OVERRIDE
{
823 return num_pending_suspend_readiness_callbacks_
;
827 void HandleSuspendReadiness() {
828 num_pending_suspend_readiness_callbacks_
--;
831 void UpdateStatus() {
832 if (pause_count_
> 0) {
834 if (pause_count_
== 2)
835 discharging_
= !discharging_
;
838 battery_percentage_
-= (battery_percentage_
<= 10 ? 1 : 10);
840 battery_percentage_
+= (battery_percentage_
>= 10 ? 10 : 1);
841 battery_percentage_
= std::min(std::max(battery_percentage_
, 0), 100);
842 // We pause at 0 and 100% so that it's easier to check those conditions.
843 if (battery_percentage_
== 0 || battery_percentage_
== 100) {
845 if (battery_percentage_
== 100)
846 cycle_count_
= (cycle_count_
+ 1) % 3;
850 const int kSecondsToEmptyFullBattery
= 3 * 60 * 60; // 3 hours.
851 int64 remaining_battery_time
=
852 std::max(1, battery_percentage_
* kSecondsToEmptyFullBattery
/ 100);
856 switch (cycle_count_
) {
858 // Say that the system is charging with AC connected and
859 // discharging without any charger connected.
860 props_
.set_external_power(discharging_
?
861 power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED
:
862 power_manager::PowerSupplyProperties_ExternalPower_AC
);
865 // Say that the system is both charging and discharging on USB
866 // (i.e. a low-power charger).
867 props_
.set_external_power(
868 power_manager::PowerSupplyProperties_ExternalPower_USB
);
871 // Say that the system is both charging and discharging on AC.
872 props_
.set_external_power(
873 power_manager::PowerSupplyProperties_ExternalPower_AC
);
876 NOTREACHED() << "Unhandled cycle " << cycle_count_
;
879 if (battery_percentage_
== 100 && !discharging_
) {
880 props_
.set_battery_state(
881 power_manager::PowerSupplyProperties_BatteryState_FULL
);
882 } else if (!discharging_
) {
883 props_
.set_battery_state(
884 power_manager::PowerSupplyProperties_BatteryState_CHARGING
);
885 props_
.set_battery_time_to_full_sec(std::max(static_cast<int64
>(1),
886 kSecondsToEmptyFullBattery
- remaining_battery_time
));
888 props_
.set_battery_state(
889 power_manager::PowerSupplyProperties_BatteryState_DISCHARGING
);
890 props_
.set_battery_time_to_empty_sec(remaining_battery_time
);
893 props_
.set_battery_percent(battery_percentage_
);
894 props_
.set_is_calculating_battery_time(pause_count_
> 1);
896 FOR_EACH_OBSERVER(Observer
, observers_
, PowerChanged(props_
));
899 void SetBrightness(double percent
, bool user_initiated
) {
900 brightness_
= std::min(std::max(0.0, percent
), 100.0);
901 int brightness_level
= static_cast<int>(brightness_
);
902 FOR_EACH_OBSERVER(Observer
, observers_
,
903 BrightnessChanged(brightness_level
, user_initiated
));
906 void ParseCommandLineSwitch() {
907 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
908 if (!command_line
|| !command_line
->HasSwitch(switches::kPowerStub
))
910 std::string option_str
=
911 command_line
->GetSwitchValueASCII(switches::kPowerStub
);
912 base::StringPairs string_pairs
;
913 base::SplitStringIntoKeyValuePairs(option_str
, '=', ',', &string_pairs
);
914 for (base::StringPairs::iterator iter
= string_pairs
.begin();
915 iter
!= string_pairs
.end(); ++iter
) {
916 ParseOption((*iter
).first
, (*iter
).second
);
920 void ParseOption(const std::string
& arg0
, const std::string
& arg1
) {
921 if (arg0
== "cycle" || arg0
== "interactive") {
924 base::StringToInt(arg1
, &seconds
);
925 power_cycle_delay_
= base::TimeDelta::FromSeconds(seconds
);
929 base::TimeDelta power_cycle_delay_
; // Time over which to cycle power state
931 int battery_percentage_
;
935 ObserverList
<Observer
> observers_
;
936 base::RepeatingTimer
<PowerManagerClientStubImpl
> update_timer_
;
937 power_manager::PowerSupplyProperties props_
;
939 // Number of callbacks returned by GetSuspendReadinessCallback() but not yet
941 int num_pending_suspend_readiness_callbacks_
;
943 // Note: This should remain the last member so it'll be destroyed and
944 // invalidate its weak pointers before any other members are destroyed.
945 base::WeakPtrFactory
<PowerManagerClientStubImpl
> weak_ptr_factory_
;
948 PowerManagerClient::PowerManagerClient() {
951 PowerManagerClient::~PowerManagerClient() {
955 PowerManagerClient
* PowerManagerClient::Create(
956 DBusClientImplementationType type
) {
957 if (type
== REAL_DBUS_CLIENT_IMPLEMENTATION
)
958 return new PowerManagerClientImpl();
959 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION
, type
);
960 return new PowerManagerClientStubImpl();
963 } // namespace chromeos