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 pending_suspend_id_(-1),
52 suspend_is_pending_(false),
53 num_pending_suspend_readiness_callbacks_(0),
54 last_is_projecting_(false),
55 weak_ptr_factory_(this) {}
57 virtual ~PowerManagerClientImpl() {
58 // Here we should unregister suspend notifications from powerd,
60 // - The lifetime of the PowerManagerClientImpl can extend past that of
62 // - power_manager can already detect that the client is gone and
63 // unregister our suspend delay.
66 // PowerManagerClient overrides:
68 virtual void AddObserver(Observer
* observer
) OVERRIDE
{
69 CHECK(observer
); // http://crbug.com/119976
70 observers_
.AddObserver(observer
);
73 virtual void RemoveObserver(Observer
* observer
) OVERRIDE
{
74 observers_
.RemoveObserver(observer
);
77 virtual bool HasObserver(Observer
* observer
) OVERRIDE
{
78 return observers_
.HasObserver(observer
);
81 virtual void DecreaseScreenBrightness(bool allow_off
) OVERRIDE
{
82 dbus::MethodCall
method_call(
83 power_manager::kPowerManagerInterface
,
84 power_manager::kDecreaseScreenBrightnessMethod
);
85 dbus::MessageWriter
writer(&method_call
);
86 writer
.AppendBool(allow_off
);
87 power_manager_proxy_
->CallMethod(
89 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
90 dbus::ObjectProxy::EmptyResponseCallback());
93 virtual void IncreaseScreenBrightness() OVERRIDE
{
94 SimpleMethodCallToPowerManager(
95 power_manager::kIncreaseScreenBrightnessMethod
);
98 virtual void DecreaseKeyboardBrightness() OVERRIDE
{
99 SimpleMethodCallToPowerManager(
100 power_manager::kDecreaseKeyboardBrightnessMethod
);
103 virtual void IncreaseKeyboardBrightness() OVERRIDE
{
104 SimpleMethodCallToPowerManager(
105 power_manager::kIncreaseKeyboardBrightnessMethod
);
108 virtual void SetScreenBrightnessPercent(double percent
,
109 bool gradual
) OVERRIDE
{
110 dbus::MethodCall
method_call(
111 power_manager::kPowerManagerInterface
,
112 power_manager::kSetScreenBrightnessPercentMethod
);
113 dbus::MessageWriter
writer(&method_call
);
114 writer
.AppendDouble(percent
);
117 power_manager::kBrightnessTransitionGradual
:
118 power_manager::kBrightnessTransitionInstant
);
119 power_manager_proxy_
->CallMethod(
121 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
122 dbus::ObjectProxy::EmptyResponseCallback());
125 virtual void GetScreenBrightnessPercent(
126 const GetScreenBrightnessPercentCallback
& callback
) OVERRIDE
{
127 dbus::MethodCall
method_call(
128 power_manager::kPowerManagerInterface
,
129 power_manager::kGetScreenBrightnessPercentMethod
);
130 power_manager_proxy_
->CallMethod(
132 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
133 base::Bind(&PowerManagerClientImpl::OnGetScreenBrightnessPercent
,
134 weak_ptr_factory_
.GetWeakPtr(), callback
));
137 virtual void RequestStatusUpdate() OVERRIDE
{
138 dbus::MethodCall
method_call(
139 power_manager::kPowerManagerInterface
,
140 power_manager::kGetPowerSupplyPropertiesMethod
);
141 power_manager_proxy_
->CallMethod(
143 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
144 base::Bind(&PowerManagerClientImpl::OnGetPowerSupplyPropertiesMethod
,
145 weak_ptr_factory_
.GetWeakPtr()));
148 virtual void RequestRestart() OVERRIDE
{
149 SimpleMethodCallToPowerManager(power_manager::kRequestRestartMethod
);
152 virtual void RequestShutdown() OVERRIDE
{
153 SimpleMethodCallToPowerManager(power_manager::kRequestShutdownMethod
);
156 virtual void NotifyUserActivity(
157 power_manager::UserActivityType type
) OVERRIDE
{
158 dbus::MethodCall
method_call(
159 power_manager::kPowerManagerInterface
,
160 power_manager::kHandleUserActivityMethod
);
161 dbus::MessageWriter
writer(&method_call
);
162 writer
.AppendInt32(type
);
164 power_manager_proxy_
->CallMethod(
166 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
167 dbus::ObjectProxy::EmptyResponseCallback());
170 virtual void NotifyVideoActivity(bool is_fullscreen
) OVERRIDE
{
171 dbus::MethodCall
method_call(
172 power_manager::kPowerManagerInterface
,
173 power_manager::kHandleVideoActivityMethod
);
174 dbus::MessageWriter
writer(&method_call
);
175 writer
.AppendBool(is_fullscreen
);
177 power_manager_proxy_
->CallMethod(
179 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
180 dbus::ObjectProxy::EmptyResponseCallback());
183 virtual void SetPolicy(
184 const power_manager::PowerManagementPolicy
& policy
) OVERRIDE
{
185 dbus::MethodCall
method_call(
186 power_manager::kPowerManagerInterface
,
187 power_manager::kSetPolicyMethod
);
188 dbus::MessageWriter
writer(&method_call
);
189 if (!writer
.AppendProtoAsArrayOfBytes(policy
)) {
190 LOG(ERROR
) << "Error calling " << power_manager::kSetPolicyMethod
;
193 power_manager_proxy_
->CallMethod(
195 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
196 dbus::ObjectProxy::EmptyResponseCallback());
199 virtual void SetIsProjecting(bool is_projecting
) OVERRIDE
{
200 dbus::MethodCall
method_call(
201 power_manager::kPowerManagerInterface
,
202 power_manager::kSetIsProjectingMethod
);
203 dbus::MessageWriter
writer(&method_call
);
204 writer
.AppendBool(is_projecting
);
205 power_manager_proxy_
->CallMethod(
207 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
208 dbus::ObjectProxy::EmptyResponseCallback());
209 last_is_projecting_
= is_projecting
;
212 virtual base::Closure
GetSuspendReadinessCallback() OVERRIDE
{
213 DCHECK(OnOriginThread());
214 DCHECK(suspend_is_pending_
);
215 num_pending_suspend_readiness_callbacks_
++;
216 return base::Bind(&PowerManagerClientImpl::HandleObserverSuspendReadiness
,
217 weak_ptr_factory_
.GetWeakPtr(), pending_suspend_id_
);
220 virtual int GetNumPendingSuspendReadinessCallbacks() OVERRIDE
{
221 return num_pending_suspend_readiness_callbacks_
;
225 virtual void Init(dbus::Bus
* bus
) OVERRIDE
{
226 power_manager_proxy_
= bus
->GetObjectProxy(
227 power_manager::kPowerManagerServiceName
,
228 dbus::ObjectPath(power_manager::kPowerManagerServicePath
));
230 power_manager_proxy_
->SetNameOwnerChangedCallback(
231 base::Bind(&PowerManagerClientImpl::NameOwnerChangedReceived
,
232 weak_ptr_factory_
.GetWeakPtr()));
234 // Monitor the D-Bus signal for brightness changes. Only the power
235 // manager knows the actual brightness level. We don't cache the
236 // brightness level in Chrome as it'll make things less reliable.
237 power_manager_proxy_
->ConnectToSignal(
238 power_manager::kPowerManagerInterface
,
239 power_manager::kBrightnessChangedSignal
,
240 base::Bind(&PowerManagerClientImpl::BrightnessChangedReceived
,
241 weak_ptr_factory_
.GetWeakPtr()),
242 base::Bind(&PowerManagerClientImpl::SignalConnected
,
243 weak_ptr_factory_
.GetWeakPtr()));
245 power_manager_proxy_
->ConnectToSignal(
246 power_manager::kPowerManagerInterface
,
247 power_manager::kPeripheralBatteryStatusSignal
,
248 base::Bind(&PowerManagerClientImpl::PeripheralBatteryStatusReceived
,
249 weak_ptr_factory_
.GetWeakPtr()),
250 base::Bind(&PowerManagerClientImpl::SignalConnected
,
251 weak_ptr_factory_
.GetWeakPtr()));
253 power_manager_proxy_
->ConnectToSignal(
254 power_manager::kPowerManagerInterface
,
255 power_manager::kPowerSupplyPollSignal
,
256 base::Bind(&PowerManagerClientImpl::PowerSupplyPollReceived
,
257 weak_ptr_factory_
.GetWeakPtr()),
258 base::Bind(&PowerManagerClientImpl::SignalConnected
,
259 weak_ptr_factory_
.GetWeakPtr()));
261 power_manager_proxy_
->ConnectToSignal(
262 power_manager::kPowerManagerInterface
,
263 power_manager::kInputEventSignal
,
264 base::Bind(&PowerManagerClientImpl::InputEventReceived
,
265 weak_ptr_factory_
.GetWeakPtr()),
266 base::Bind(&PowerManagerClientImpl::SignalConnected
,
267 weak_ptr_factory_
.GetWeakPtr()));
269 power_manager_proxy_
->ConnectToSignal(
270 power_manager::kPowerManagerInterface
,
271 power_manager::kSuspendImminentSignal
,
273 &PowerManagerClientImpl::SuspendImminentReceived
,
274 weak_ptr_factory_
.GetWeakPtr()),
275 base::Bind(&PowerManagerClientImpl::SignalConnected
,
276 weak_ptr_factory_
.GetWeakPtr()));
278 power_manager_proxy_
->ConnectToSignal(
279 power_manager::kPowerManagerInterface
,
280 power_manager::kSuspendDoneSignal
,
281 base::Bind(&PowerManagerClientImpl::SuspendDoneReceived
,
282 weak_ptr_factory_
.GetWeakPtr()),
283 base::Bind(&PowerManagerClientImpl::SignalConnected
,
284 weak_ptr_factory_
.GetWeakPtr()));
286 power_manager_proxy_
->ConnectToSignal(
287 power_manager::kPowerManagerInterface
,
288 power_manager::kIdleActionImminentSignal
,
290 &PowerManagerClientImpl::IdleActionImminentReceived
,
291 weak_ptr_factory_
.GetWeakPtr()),
292 base::Bind(&PowerManagerClientImpl::SignalConnected
,
293 weak_ptr_factory_
.GetWeakPtr()));
295 power_manager_proxy_
->ConnectToSignal(
296 power_manager::kPowerManagerInterface
,
297 power_manager::kIdleActionDeferredSignal
,
299 &PowerManagerClientImpl::IdleActionDeferredReceived
,
300 weak_ptr_factory_
.GetWeakPtr()),
301 base::Bind(&PowerManagerClientImpl::SignalConnected
,
302 weak_ptr_factory_
.GetWeakPtr()));
304 RegisterSuspendDelay();
308 // Returns true if the current thread is the origin thread.
309 bool OnOriginThread() {
310 return base::PlatformThread::CurrentId() == origin_thread_id_
;
313 // Called when a dbus signal is initially connected.
314 void SignalConnected(const std::string
& interface_name
,
315 const std::string
& signal_name
,
317 LOG_IF(WARNING
, !success
) << "Failed to connect to signal "
318 << signal_name
<< ".";
321 // Makes a method call to power manager with no arguments and no response.
322 void SimpleMethodCallToPowerManager(const std::string
& method_name
) {
323 dbus::MethodCall
method_call(power_manager::kPowerManagerInterface
,
325 power_manager_proxy_
->CallMethod(
327 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
328 dbus::ObjectProxy::EmptyResponseCallback());
331 void NameOwnerChangedReceived(const std::string
& old_owner
,
332 const std::string
& new_owner
) {
333 VLOG(1) << "Power manager restarted (old owner was "
334 << (old_owner
.empty() ? "[none]" : old_owner
.c_str())
336 << (new_owner
.empty() ? "[none]" : new_owner
.c_str()) << ")";
337 if (!new_owner
.empty()) {
338 VLOG(1) << "Sending initial state to power manager";
339 RegisterSuspendDelay();
340 SetIsProjecting(last_is_projecting_
);
341 FOR_EACH_OBSERVER(Observer
, observers_
, PowerManagerRestarted());
345 void BrightnessChangedReceived(dbus::Signal
* signal
) {
346 dbus::MessageReader
reader(signal
);
347 int32 brightness_level
= 0;
348 bool user_initiated
= 0;
349 if (!(reader
.PopInt32(&brightness_level
) &&
350 reader
.PopBool(&user_initiated
))) {
351 LOG(ERROR
) << "Brightness changed signal had incorrect parameters: "
352 << signal
->ToString();
355 VLOG(1) << "Brightness changed to " << brightness_level
356 << ": user initiated " << user_initiated
;
357 FOR_EACH_OBSERVER(Observer
, observers_
,
358 BrightnessChanged(brightness_level
, user_initiated
));
361 void PeripheralBatteryStatusReceived(dbus::Signal
* signal
) {
362 dbus::MessageReader
reader(signal
);
363 power_manager::PeripheralBatteryStatus protobuf_status
;
364 if (!reader
.PopArrayOfBytesAsProto(&protobuf_status
)) {
365 LOG(ERROR
) << "Unable to decode protocol buffer from "
366 << power_manager::kPeripheralBatteryStatusSignal
<< " signal";
370 std::string path
= protobuf_status
.path();
371 std::string name
= protobuf_status
.name();
372 int level
= protobuf_status
.has_level() ? protobuf_status
.level() : -1;
374 VLOG(1) << "Device battery status received " << level
375 << " for " << name
<< " at " << path
;
377 FOR_EACH_OBSERVER(Observer
, observers_
,
378 PeripheralBatteryStatusReceived(path
, name
, level
));
381 void PowerSupplyPollReceived(dbus::Signal
* signal
) {
382 VLOG(1) << "Received power supply poll signal.";
383 dbus::MessageReader
reader(signal
);
384 power_manager::PowerSupplyProperties protobuf
;
385 if (reader
.PopArrayOfBytesAsProto(&protobuf
)) {
386 FOR_EACH_OBSERVER(Observer
, observers_
, PowerChanged(protobuf
));
388 LOG(ERROR
) << "Unable to decode "
389 << power_manager::kPowerSupplyPollSignal
<< "signal";
393 void OnGetPowerSupplyPropertiesMethod(dbus::Response
* response
) {
395 LOG(ERROR
) << "Error calling "
396 << power_manager::kGetPowerSupplyPropertiesMethod
;
400 dbus::MessageReader
reader(response
);
401 power_manager::PowerSupplyProperties protobuf
;
402 if (reader
.PopArrayOfBytesAsProto(&protobuf
)) {
403 FOR_EACH_OBSERVER(Observer
, observers_
, PowerChanged(protobuf
));
405 LOG(ERROR
) << "Unable to decode "
406 << power_manager::kGetPowerSupplyPropertiesMethod
411 void OnGetScreenBrightnessPercent(
412 const GetScreenBrightnessPercentCallback
& callback
,
413 dbus::Response
* response
) {
415 LOG(ERROR
) << "Error calling "
416 << power_manager::kGetScreenBrightnessPercentMethod
;
419 dbus::MessageReader
reader(response
);
420 double percent
= 0.0;
421 if (!reader
.PopDouble(&percent
))
422 LOG(ERROR
) << "Error reading response from powerd: "
423 << response
->ToString();
424 callback
.Run(percent
);
427 void OnRegisterSuspendDelayReply(dbus::Response
* response
) {
429 LOG(ERROR
) << "Error calling "
430 << power_manager::kRegisterSuspendDelayMethod
;
434 dbus::MessageReader
reader(response
);
435 power_manager::RegisterSuspendDelayReply protobuf
;
436 if (!reader
.PopArrayOfBytesAsProto(&protobuf
)) {
437 LOG(ERROR
) << "Unable to parse reply from "
438 << power_manager::kRegisterSuspendDelayMethod
;
442 suspend_delay_id_
= protobuf
.delay_id();
443 has_suspend_delay_id_
= true;
444 VLOG(1) << "Registered suspend delay " << suspend_delay_id_
;
447 void SuspendImminentReceived(dbus::Signal
* signal
) {
448 if (!has_suspend_delay_id_
) {
449 LOG(ERROR
) << "Received unrequested "
450 << power_manager::kSuspendImminentSignal
<< " signal";
454 dbus::MessageReader
reader(signal
);
455 power_manager::SuspendImminent proto
;
456 if (!reader
.PopArrayOfBytesAsProto(&proto
)) {
457 LOG(ERROR
) << "Unable to decode protocol buffer from "
458 << power_manager::kSuspendImminentSignal
<< " signal";
462 VLOG(1) << "Got " << power_manager::kSuspendImminentSignal
<< " signal "
463 << "announcing suspend attempt " << proto
.suspend_id();
464 if (suspend_is_pending_
) {
465 LOG(WARNING
) << "Got " << power_manager::kSuspendImminentSignal
466 << " signal about pending suspend attempt "
467 << proto
.suspend_id() << " while still waiting "
468 << "on attempt " << pending_suspend_id_
;
471 pending_suspend_id_
= proto
.suspend_id();
472 suspend_is_pending_
= true;
473 num_pending_suspend_readiness_callbacks_
= 0;
474 FOR_EACH_OBSERVER(Observer
, observers_
, SuspendImminent());
475 MaybeReportSuspendReadiness();
478 void SuspendDoneReceived(dbus::Signal
* signal
) {
479 dbus::MessageReader
reader(signal
);
480 power_manager::SuspendDone proto
;
481 if (!reader
.PopArrayOfBytesAsProto(&proto
)) {
482 LOG(ERROR
) << "Unable to decode protocol buffer from "
483 << power_manager::kSuspendDoneSignal
<< " signal";
487 const base::TimeDelta duration
=
488 base::TimeDelta::FromInternalValue(proto
.suspend_duration());
489 VLOG(1) << "Got " << power_manager::kSuspendDoneSignal
<< " signal:"
490 << " suspend_id=" << proto
.suspend_id()
491 << " duration=" << duration
.InSeconds() << " sec";
493 PowerManagerClient::Observer
, observers_
, SuspendDone(duration
));
496 void IdleActionImminentReceived(dbus::Signal
* signal
) {
497 dbus::MessageReader
reader(signal
);
498 power_manager::IdleActionImminent proto
;
499 if (!reader
.PopArrayOfBytesAsProto(&proto
)) {
500 LOG(ERROR
) << "Unable to decode protocol buffer from "
501 << power_manager::kIdleActionImminentSignal
<< " signal";
504 FOR_EACH_OBSERVER(Observer
, observers_
,
505 IdleActionImminent(base::TimeDelta::FromInternalValue(
506 proto
.time_until_idle_action())));
509 void IdleActionDeferredReceived(dbus::Signal
* signal
) {
510 FOR_EACH_OBSERVER(Observer
, observers_
, IdleActionDeferred());
513 void InputEventReceived(dbus::Signal
* signal
) {
514 dbus::MessageReader
reader(signal
);
515 power_manager::InputEvent proto
;
516 if (!reader
.PopArrayOfBytesAsProto(&proto
)) {
517 LOG(ERROR
) << "Unable to decode protocol buffer from "
518 << power_manager::kInputEventSignal
<< " signal";
522 base::TimeTicks timestamp
=
523 base::TimeTicks::FromInternalValue(proto
.timestamp());
524 VLOG(1) << "Got " << power_manager::kInputEventSignal
<< " signal:"
525 << " type=" << proto
.type() << " timestamp=" << proto
.timestamp();
526 switch (proto
.type()) {
527 case power_manager::InputEvent_Type_POWER_BUTTON_DOWN
:
528 case power_manager::InputEvent_Type_POWER_BUTTON_UP
: {
530 (proto
.type() == power_manager::InputEvent_Type_POWER_BUTTON_DOWN
);
531 FOR_EACH_OBSERVER(PowerManagerClient::Observer
, observers_
,
532 PowerButtonEventReceived(down
, timestamp
));
534 // Tell powerd that Chrome has handled power button presses.
536 dbus::MethodCall
method_call(
537 power_manager::kPowerManagerInterface
,
538 power_manager::kHandlePowerButtonAcknowledgmentMethod
);
539 dbus::MessageWriter
writer(&method_call
);
540 writer
.AppendInt64(proto
.timestamp());
541 power_manager_proxy_
->CallMethod(
543 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
544 dbus::ObjectProxy::EmptyResponseCallback());
548 case power_manager::InputEvent_Type_LID_OPEN
:
549 case power_manager::InputEvent_Type_LID_CLOSED
: {
551 (proto
.type() == power_manager::InputEvent_Type_LID_OPEN
);
552 FOR_EACH_OBSERVER(PowerManagerClient::Observer
, observers_
,
553 LidEventReceived(open
, timestamp
));
559 // Registers a suspend delay with the power manager. This is usually
560 // only called at startup, but if the power manager restarts, we need to
561 // create a new delay.
562 void RegisterSuspendDelay() {
563 // Throw out any old delay that was registered.
564 suspend_delay_id_
= -1;
565 has_suspend_delay_id_
= false;
567 dbus::MethodCall
method_call(
568 power_manager::kPowerManagerInterface
,
569 power_manager::kRegisterSuspendDelayMethod
);
570 dbus::MessageWriter
writer(&method_call
);
572 power_manager::RegisterSuspendDelayRequest protobuf_request
;
573 base::TimeDelta timeout
=
574 base::TimeDelta::FromMilliseconds(kSuspendDelayTimeoutMs
);
575 protobuf_request
.set_timeout(timeout
.ToInternalValue());
576 protobuf_request
.set_description(kSuspendDelayDescription
);
578 if (!writer
.AppendProtoAsArrayOfBytes(protobuf_request
)) {
579 LOG(ERROR
) << "Error constructing message for "
580 << power_manager::kRegisterSuspendDelayMethod
;
583 power_manager_proxy_
->CallMethod(
585 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
587 &PowerManagerClientImpl::OnRegisterSuspendDelayReply
,
588 weak_ptr_factory_
.GetWeakPtr()));
591 // Records the fact that an observer has finished doing asynchronous work
592 // that was blocking a pending suspend attempt and possibly reports
593 // suspend readiness to powerd. Called by callbacks returned via
594 // GetSuspendReadinessCallback().
595 void HandleObserverSuspendReadiness(int32 suspend_id
) {
596 DCHECK(OnOriginThread());
597 if (!suspend_is_pending_
|| suspend_id
!= pending_suspend_id_
)
600 num_pending_suspend_readiness_callbacks_
--;
601 MaybeReportSuspendReadiness();
604 // Reports suspend readiness to powerd if no observers are still holding
605 // suspend readiness callbacks.
606 void MaybeReportSuspendReadiness() {
607 if (!suspend_is_pending_
|| num_pending_suspend_readiness_callbacks_
> 0)
610 dbus::MethodCall
method_call(
611 power_manager::kPowerManagerInterface
,
612 power_manager::kHandleSuspendReadinessMethod
);
613 dbus::MessageWriter
writer(&method_call
);
615 VLOG(1) << "Announcing readiness of suspend delay " << suspend_delay_id_
616 << " for suspend attempt " << pending_suspend_id_
;
617 power_manager::SuspendReadinessInfo protobuf_request
;
618 protobuf_request
.set_delay_id(suspend_delay_id_
);
619 protobuf_request
.set_suspend_id(pending_suspend_id_
);
621 pending_suspend_id_
= -1;
622 suspend_is_pending_
= false;
624 if (!writer
.AppendProtoAsArrayOfBytes(protobuf_request
)) {
625 LOG(ERROR
) << "Error constructing message for "
626 << power_manager::kHandleSuspendReadinessMethod
;
629 power_manager_proxy_
->CallMethod(
631 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
632 dbus::ObjectProxy::EmptyResponseCallback());
635 // Origin thread (i.e. the UI thread in production).
636 base::PlatformThreadId origin_thread_id_
;
638 dbus::ObjectProxy
* power_manager_proxy_
;
639 ObserverList
<Observer
> observers_
;
641 // The delay_id_ obtained from the RegisterSuspendDelay request.
642 int32 suspend_delay_id_
;
643 bool has_suspend_delay_id_
;
645 // powerd-supplied ID corresponding to an imminent suspend attempt that is
646 // currently being delayed.
647 int32 pending_suspend_id_
;
648 bool suspend_is_pending_
;
650 // Number of callbacks that have been returned by
651 // GetSuspendReadinessCallback() during the currently-pending suspend
652 // attempt but have not yet been called.
653 int num_pending_suspend_readiness_callbacks_
;
655 // Last state passed to SetIsProjecting().
656 bool last_is_projecting_
;
658 // Note: This should remain the last member so it'll be destroyed and
659 // invalidate its weak pointers before any other members are destroyed.
660 base::WeakPtrFactory
<PowerManagerClientImpl
> weak_ptr_factory_
;
662 DISALLOW_COPY_AND_ASSIGN(PowerManagerClientImpl
);
665 // The PowerManagerClient implementation used on Linux desktop,
666 // which does nothing.
667 class PowerManagerClientStubImpl
: public PowerManagerClient
{
669 PowerManagerClientStubImpl()
670 : discharging_(true),
671 battery_percentage_(40),
675 num_pending_suspend_readiness_callbacks_(0),
676 weak_ptr_factory_(this) {}
678 virtual ~PowerManagerClientStubImpl() {}
680 int num_pending_suspend_readiness_callbacks() const {
681 return num_pending_suspend_readiness_callbacks_
;
684 // PowerManagerClient overrides:
685 virtual void Init(dbus::Bus
* bus
) OVERRIDE
{
686 ParseCommandLineSwitch();
687 if (power_cycle_delay_
!= base::TimeDelta()) {
688 update_timer_
.Start(FROM_HERE
,
691 &PowerManagerClientStubImpl::UpdateStatus
);
695 virtual void AddObserver(Observer
* observer
) OVERRIDE
{
696 observers_
.AddObserver(observer
);
699 virtual void RemoveObserver(Observer
* observer
) OVERRIDE
{
700 observers_
.RemoveObserver(observer
);
703 virtual bool HasObserver(Observer
* observer
) OVERRIDE
{
704 return observers_
.HasObserver(observer
);
707 virtual void DecreaseScreenBrightness(bool allow_off
) OVERRIDE
{
708 VLOG(1) << "Requested to descrease screen brightness";
709 SetBrightness(brightness_
- 5.0, true);
712 virtual void IncreaseScreenBrightness() OVERRIDE
{
713 VLOG(1) << "Requested to increase screen brightness";
714 SetBrightness(brightness_
+ 5.0, true);
717 virtual void SetScreenBrightnessPercent(double percent
,
718 bool gradual
) OVERRIDE
{
719 VLOG(1) << "Requested to set screen brightness to " << percent
<< "% "
720 << (gradual
? "gradually" : "instantaneously");
721 SetBrightness(percent
, false);
724 virtual void GetScreenBrightnessPercent(
725 const GetScreenBrightnessPercentCallback
& callback
) OVERRIDE
{
726 callback
.Run(brightness_
);
729 virtual void DecreaseKeyboardBrightness() OVERRIDE
{
730 VLOG(1) << "Requested to descrease keyboard brightness";
733 virtual void IncreaseKeyboardBrightness() OVERRIDE
{
734 VLOG(1) << "Requested to increase keyboard brightness";
737 virtual void RequestStatusUpdate() OVERRIDE
{
738 base::MessageLoop::current()->PostTask(FROM_HERE
,
739 base::Bind(&PowerManagerClientStubImpl::UpdateStatus
,
740 weak_ptr_factory_
.GetWeakPtr()));
743 virtual void RequestRestart() OVERRIDE
{}
744 virtual void RequestShutdown() OVERRIDE
{}
746 virtual void NotifyUserActivity(
747 power_manager::UserActivityType type
) OVERRIDE
{}
748 virtual void NotifyVideoActivity(bool is_fullscreen
) OVERRIDE
{}
749 virtual void SetPolicy(
750 const power_manager::PowerManagementPolicy
& policy
) OVERRIDE
{}
751 virtual void SetIsProjecting(bool is_projecting
) OVERRIDE
{}
752 virtual base::Closure
GetSuspendReadinessCallback() OVERRIDE
{
753 num_pending_suspend_readiness_callbacks_
++;
754 return base::Bind(&PowerManagerClientStubImpl::HandleSuspendReadiness
,
755 weak_ptr_factory_
.GetWeakPtr());
757 virtual int GetNumPendingSuspendReadinessCallbacks() OVERRIDE
{
758 return num_pending_suspend_readiness_callbacks_
;
762 void HandleSuspendReadiness() {
763 num_pending_suspend_readiness_callbacks_
--;
766 void UpdateStatus() {
767 if (pause_count_
> 0) {
769 if (pause_count_
== 2)
770 discharging_
= !discharging_
;
773 battery_percentage_
-= (battery_percentage_
<= 10 ? 1 : 10);
775 battery_percentage_
+= (battery_percentage_
>= 10 ? 10 : 1);
776 battery_percentage_
= std::min(std::max(battery_percentage_
, 0), 100);
777 // We pause at 0 and 100% so that it's easier to check those conditions.
778 if (battery_percentage_
== 0 || battery_percentage_
== 100) {
780 if (battery_percentage_
== 100)
781 cycle_count_
= (cycle_count_
+ 1) % 3;
785 const int kSecondsToEmptyFullBattery
= 3 * 60 * 60; // 3 hours.
786 int64 remaining_battery_time
=
787 std::max(1, battery_percentage_
* kSecondsToEmptyFullBattery
/ 100);
791 switch (cycle_count_
) {
793 // Say that the system is charging with AC connected and
794 // discharging without any charger connected.
795 props_
.set_external_power(discharging_
?
796 power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED
:
797 power_manager::PowerSupplyProperties_ExternalPower_AC
);
800 // Say that the system is both charging and discharging on USB
801 // (i.e. a low-power charger).
802 props_
.set_external_power(
803 power_manager::PowerSupplyProperties_ExternalPower_USB
);
806 // Say that the system is both charging and discharging on AC.
807 props_
.set_external_power(
808 power_manager::PowerSupplyProperties_ExternalPower_AC
);
811 NOTREACHED() << "Unhandled cycle " << cycle_count_
;
814 if (battery_percentage_
== 100 && !discharging_
) {
815 props_
.set_battery_state(
816 power_manager::PowerSupplyProperties_BatteryState_FULL
);
817 } else if (!discharging_
) {
818 props_
.set_battery_state(
819 power_manager::PowerSupplyProperties_BatteryState_CHARGING
);
820 props_
.set_battery_time_to_full_sec(std::max(static_cast<int64
>(1),
821 kSecondsToEmptyFullBattery
- remaining_battery_time
));
823 props_
.set_battery_state(
824 power_manager::PowerSupplyProperties_BatteryState_DISCHARGING
);
825 props_
.set_battery_time_to_empty_sec(remaining_battery_time
);
828 props_
.set_battery_percent(battery_percentage_
);
829 props_
.set_is_calculating_battery_time(pause_count_
> 1);
831 FOR_EACH_OBSERVER(Observer
, observers_
, PowerChanged(props_
));
834 void SetBrightness(double percent
, bool user_initiated
) {
835 brightness_
= std::min(std::max(0.0, percent
), 100.0);
836 int brightness_level
= static_cast<int>(brightness_
);
837 FOR_EACH_OBSERVER(Observer
, observers_
,
838 BrightnessChanged(brightness_level
, user_initiated
));
841 void ParseCommandLineSwitch() {
842 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
843 if (!command_line
|| !command_line
->HasSwitch(switches::kPowerStub
))
845 std::string option_str
=
846 command_line
->GetSwitchValueASCII(switches::kPowerStub
);
847 base::StringPairs string_pairs
;
848 base::SplitStringIntoKeyValuePairs(option_str
, '=', ',', &string_pairs
);
849 for (base::StringPairs::iterator iter
= string_pairs
.begin();
850 iter
!= string_pairs
.end(); ++iter
) {
851 ParseOption((*iter
).first
, (*iter
).second
);
855 void ParseOption(const std::string
& arg0
, const std::string
& arg1
) {
856 if (arg0
== "cycle" || arg0
== "interactive") {
859 base::StringToInt(arg1
, &seconds
);
860 power_cycle_delay_
= base::TimeDelta::FromSeconds(seconds
);
864 base::TimeDelta power_cycle_delay_
; // Time over which to cycle power state
866 int battery_percentage_
;
870 ObserverList
<Observer
> observers_
;
871 base::RepeatingTimer
<PowerManagerClientStubImpl
> update_timer_
;
872 power_manager::PowerSupplyProperties props_
;
874 // Number of callbacks returned by GetSuspendReadinessCallback() but not yet
876 int num_pending_suspend_readiness_callbacks_
;
878 // Note: This should remain the last member so it'll be destroyed and
879 // invalidate its weak pointers before any other members are destroyed.
880 base::WeakPtrFactory
<PowerManagerClientStubImpl
> weak_ptr_factory_
;
883 PowerManagerClient::PowerManagerClient() {
886 PowerManagerClient::~PowerManagerClient() {
890 PowerManagerClient
* PowerManagerClient::Create(
891 DBusClientImplementationType type
) {
892 if (type
== REAL_DBUS_CLIENT_IMPLEMENTATION
)
893 return new PowerManagerClientImpl();
894 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION
, type
);
895 return new PowerManagerClientStubImpl();
898 } // namespace chromeos