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/stringprintf.h"
18 #include "base/threading/platform_thread.h"
19 #include "base/time/time.h"
20 #include "base/timer/timer.h"
21 #include "chromeos/chromeos_switches.h"
22 #include "chromeos/dbus/power_manager/input_event.pb.h"
23 #include "chromeos/dbus/power_manager/peripheral_battery_status.pb.h"
24 #include "chromeos/dbus/power_manager/policy.pb.h"
25 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
26 #include "chromeos/dbus/power_manager/suspend.pb.h"
28 #include "dbus/message.h"
29 #include "dbus/object_path.h"
30 #include "dbus/object_proxy.h"
34 // Maximum amount of time that the power manager will wait for Chrome to
35 // say that it's ready for the system to be suspended, in milliseconds.
36 const int kSuspendDelayTimeoutMs = 5000;
38 // Human-readable description of Chrome's suspend delay.
39 const char kSuspendDelayDescription[] = "chrome";
41 // The PowerManagerClient implementation used in production.
42 class PowerManagerClientImpl : public PowerManagerClient {
44 PowerManagerClientImpl()
45 : origin_thread_id_(base::PlatformThread::CurrentId()),
46 power_manager_proxy_(NULL),
47 suspend_delay_id_(-1),
48 has_suspend_delay_id_(false),
49 pending_suspend_id_(-1),
50 suspend_is_pending_(false),
51 num_pending_suspend_readiness_callbacks_(0),
52 last_is_projecting_(false),
53 weak_ptr_factory_(this) {}
55 virtual ~PowerManagerClientImpl() {
56 // Here we should unregister suspend notifications from powerd,
58 // - The lifetime of the PowerManagerClientImpl can extend past that of
60 // - power_manager can already detect that the client is gone and
61 // unregister our suspend delay.
64 // PowerManagerClient overrides:
66 virtual void AddObserver(Observer* observer) OVERRIDE {
67 CHECK(observer); // http://crbug.com/119976
68 observers_.AddObserver(observer);
71 virtual void RemoveObserver(Observer* observer) OVERRIDE {
72 observers_.RemoveObserver(observer);
75 virtual bool HasObserver(Observer* observer) OVERRIDE {
76 return observers_.HasObserver(observer);
79 virtual void DecreaseScreenBrightness(bool allow_off) OVERRIDE {
80 dbus::MethodCall method_call(
81 power_manager::kPowerManagerInterface,
82 power_manager::kDecreaseScreenBrightness);
83 dbus::MessageWriter writer(&method_call);
84 writer.AppendBool(allow_off);
85 power_manager_proxy_->CallMethod(
87 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
88 dbus::ObjectProxy::EmptyResponseCallback());
91 virtual void IncreaseScreenBrightness() OVERRIDE {
92 SimpleMethodCallToPowerManager(power_manager::kIncreaseScreenBrightness);
95 virtual void DecreaseKeyboardBrightness() OVERRIDE {
96 SimpleMethodCallToPowerManager(power_manager::kDecreaseKeyboardBrightness);
99 virtual void IncreaseKeyboardBrightness() OVERRIDE {
100 SimpleMethodCallToPowerManager(power_manager::kIncreaseKeyboardBrightness);
103 virtual void SetScreenBrightnessPercent(double percent,
104 bool gradual) OVERRIDE {
105 dbus::MethodCall method_call(
106 power_manager::kPowerManagerInterface,
107 power_manager::kSetScreenBrightnessPercent);
108 dbus::MessageWriter writer(&method_call);
109 writer.AppendDouble(percent);
112 power_manager::kBrightnessTransitionGradual :
113 power_manager::kBrightnessTransitionInstant);
114 power_manager_proxy_->CallMethod(
116 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
117 dbus::ObjectProxy::EmptyResponseCallback());
120 virtual void GetScreenBrightnessPercent(
121 const GetScreenBrightnessPercentCallback& callback) OVERRIDE {
122 dbus::MethodCall method_call(power_manager::kPowerManagerInterface,
123 power_manager::kGetScreenBrightnessPercent);
124 power_manager_proxy_->CallMethod(
126 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
127 base::Bind(&PowerManagerClientImpl::OnGetScreenBrightnessPercent,
128 weak_ptr_factory_.GetWeakPtr(), callback));
131 virtual void RequestStatusUpdate() OVERRIDE {
132 dbus::MethodCall method_call(
133 power_manager::kPowerManagerInterface,
134 power_manager::kGetPowerSupplyPropertiesMethod);
135 power_manager_proxy_->CallMethod(
137 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
138 base::Bind(&PowerManagerClientImpl::OnGetPowerSupplyPropertiesMethod,
139 weak_ptr_factory_.GetWeakPtr()));
142 virtual void RequestRestart() OVERRIDE {
143 SimpleMethodCallToPowerManager(power_manager::kRequestRestartMethod);
146 virtual void RequestShutdown() OVERRIDE {
147 SimpleMethodCallToPowerManager(power_manager::kRequestShutdownMethod);
150 virtual void NotifyUserActivity(
151 power_manager::UserActivityType type) OVERRIDE {
152 dbus::MethodCall method_call(
153 power_manager::kPowerManagerInterface,
154 power_manager::kHandleUserActivityMethod);
155 dbus::MessageWriter writer(&method_call);
156 writer.AppendInt32(type);
158 power_manager_proxy_->CallMethod(
160 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
161 dbus::ObjectProxy::EmptyResponseCallback());
164 virtual void NotifyVideoActivity(bool is_fullscreen) OVERRIDE {
165 dbus::MethodCall method_call(
166 power_manager::kPowerManagerInterface,
167 power_manager::kHandleVideoActivityMethod);
168 dbus::MessageWriter writer(&method_call);
169 writer.AppendBool(is_fullscreen);
171 power_manager_proxy_->CallMethod(
173 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
174 dbus::ObjectProxy::EmptyResponseCallback());
177 virtual void SetPolicy(
178 const power_manager::PowerManagementPolicy& policy) OVERRIDE {
179 dbus::MethodCall method_call(
180 power_manager::kPowerManagerInterface,
181 power_manager::kSetPolicyMethod);
182 dbus::MessageWriter writer(&method_call);
183 if (!writer.AppendProtoAsArrayOfBytes(policy)) {
184 LOG(ERROR) << "Error calling " << power_manager::kSetPolicyMethod;
187 power_manager_proxy_->CallMethod(
189 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
190 dbus::ObjectProxy::EmptyResponseCallback());
193 virtual void SetIsProjecting(bool is_projecting) OVERRIDE {
194 dbus::MethodCall method_call(
195 power_manager::kPowerManagerInterface,
196 power_manager::kSetIsProjectingMethod);
197 dbus::MessageWriter writer(&method_call);
198 writer.AppendBool(is_projecting);
199 power_manager_proxy_->CallMethod(
201 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
202 dbus::ObjectProxy::EmptyResponseCallback());
203 last_is_projecting_ = is_projecting;
206 virtual base::Closure GetSuspendReadinessCallback() OVERRIDE {
207 DCHECK(OnOriginThread());
208 DCHECK(suspend_is_pending_);
209 num_pending_suspend_readiness_callbacks_++;
210 return base::Bind(&PowerManagerClientImpl::HandleObserverSuspendReadiness,
211 weak_ptr_factory_.GetWeakPtr(), pending_suspend_id_);
214 virtual int GetNumPendingSuspendReadinessCallbacks() OVERRIDE {
215 return num_pending_suspend_readiness_callbacks_;
219 virtual void Init(dbus::Bus* bus) OVERRIDE {
220 power_manager_proxy_ = bus->GetObjectProxy(
221 power_manager::kPowerManagerServiceName,
222 dbus::ObjectPath(power_manager::kPowerManagerServicePath));
224 power_manager_proxy_->SetNameOwnerChangedCallback(
225 base::Bind(&PowerManagerClientImpl::NameOwnerChangedReceived,
226 weak_ptr_factory_.GetWeakPtr()));
228 // Monitor the D-Bus signal for brightness changes. Only the power
229 // manager knows the actual brightness level. We don't cache the
230 // brightness level in Chrome as it'll make things less reliable.
231 power_manager_proxy_->ConnectToSignal(
232 power_manager::kPowerManagerInterface,
233 power_manager::kBrightnessChangedSignal,
234 base::Bind(&PowerManagerClientImpl::BrightnessChangedReceived,
235 weak_ptr_factory_.GetWeakPtr()),
236 base::Bind(&PowerManagerClientImpl::SignalConnected,
237 weak_ptr_factory_.GetWeakPtr()));
239 power_manager_proxy_->ConnectToSignal(
240 power_manager::kPowerManagerInterface,
241 power_manager::kPeripheralBatteryStatusSignal,
242 base::Bind(&PowerManagerClientImpl::PeripheralBatteryStatusReceived,
243 weak_ptr_factory_.GetWeakPtr()),
244 base::Bind(&PowerManagerClientImpl::SignalConnected,
245 weak_ptr_factory_.GetWeakPtr()));
247 power_manager_proxy_->ConnectToSignal(
248 power_manager::kPowerManagerInterface,
249 power_manager::kPowerSupplyPollSignal,
250 base::Bind(&PowerManagerClientImpl::PowerSupplyPollReceived,
251 weak_ptr_factory_.GetWeakPtr()),
252 base::Bind(&PowerManagerClientImpl::SignalConnected,
253 weak_ptr_factory_.GetWeakPtr()));
255 power_manager_proxy_->ConnectToSignal(
256 power_manager::kPowerManagerInterface,
257 power_manager::kInputEventSignal,
258 base::Bind(&PowerManagerClientImpl::InputEventReceived,
259 weak_ptr_factory_.GetWeakPtr()),
260 base::Bind(&PowerManagerClientImpl::SignalConnected,
261 weak_ptr_factory_.GetWeakPtr()));
263 power_manager_proxy_->ConnectToSignal(
264 power_manager::kPowerManagerInterface,
265 power_manager::kSuspendStateChangedSignal,
266 base::Bind(&PowerManagerClientImpl::SuspendStateChangedReceived,
267 weak_ptr_factory_.GetWeakPtr()),
268 base::Bind(&PowerManagerClientImpl::SignalConnected,
269 weak_ptr_factory_.GetWeakPtr()));
271 power_manager_proxy_->ConnectToSignal(
272 power_manager::kPowerManagerInterface,
273 power_manager::kSuspendImminentSignal,
275 &PowerManagerClientImpl::SuspendImminentReceived,
276 weak_ptr_factory_.GetWeakPtr()),
277 base::Bind(&PowerManagerClientImpl::SignalConnected,
278 weak_ptr_factory_.GetWeakPtr()));
280 power_manager_proxy_->ConnectToSignal(
281 power_manager::kPowerManagerInterface,
282 power_manager::kIdleActionImminentSignal,
284 &PowerManagerClientImpl::IdleActionImminentReceived,
285 weak_ptr_factory_.GetWeakPtr()),
286 base::Bind(&PowerManagerClientImpl::SignalConnected,
287 weak_ptr_factory_.GetWeakPtr()));
289 power_manager_proxy_->ConnectToSignal(
290 power_manager::kPowerManagerInterface,
291 power_manager::kIdleActionDeferredSignal,
293 &PowerManagerClientImpl::IdleActionDeferredReceived,
294 weak_ptr_factory_.GetWeakPtr()),
295 base::Bind(&PowerManagerClientImpl::SignalConnected,
296 weak_ptr_factory_.GetWeakPtr()));
298 RegisterSuspendDelay();
302 // Returns true if the current thread is the origin thread.
303 bool OnOriginThread() {
304 return base::PlatformThread::CurrentId() == origin_thread_id_;
307 // Called when a dbus signal is initially connected.
308 void SignalConnected(const std::string& interface_name,
309 const std::string& signal_name,
311 LOG_IF(WARNING, !success) << "Failed to connect to signal "
312 << signal_name << ".";
315 // Make a method call to power manager with no arguments and no response.
316 void SimpleMethodCallToPowerManager(const std::string& method_name) {
317 dbus::MethodCall method_call(power_manager::kPowerManagerInterface,
319 power_manager_proxy_->CallMethod(
321 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
322 dbus::ObjectProxy::EmptyResponseCallback());
325 void NameOwnerChangedReceived(const std::string& old_owner,
326 const std::string& new_owner) {
327 VLOG(1) << "Power manager restarted";
328 RegisterSuspendDelay();
329 SetIsProjecting(last_is_projecting_);
330 FOR_EACH_OBSERVER(Observer, observers_, PowerManagerRestarted());
333 void BrightnessChangedReceived(dbus::Signal* signal) {
334 dbus::MessageReader reader(signal);
335 int32 brightness_level = 0;
336 bool user_initiated = 0;
337 if (!(reader.PopInt32(&brightness_level) &&
338 reader.PopBool(&user_initiated))) {
339 LOG(ERROR) << "Brightness changed signal had incorrect parameters: "
340 << signal->ToString();
343 VLOG(1) << "Brightness changed to " << brightness_level
344 << ": user initiated " << user_initiated;
345 FOR_EACH_OBSERVER(Observer, observers_,
346 BrightnessChanged(brightness_level, user_initiated));
349 void PeripheralBatteryStatusReceived(dbus::Signal* signal) {
350 dbus::MessageReader reader(signal);
351 power_manager::PeripheralBatteryStatus protobuf_status;
352 if (!reader.PopArrayOfBytesAsProto(&protobuf_status)) {
353 LOG(ERROR) << "Unable to decode protocol buffer from "
354 << power_manager::kPeripheralBatteryStatusSignal << " signal";
358 std::string path = protobuf_status.path();
359 std::string name = protobuf_status.name();
360 int level = protobuf_status.has_level() ? protobuf_status.level() : -1;
362 VLOG(1) << "Device battery status received " << level
363 << " for " << name << " at " << path;
365 FOR_EACH_OBSERVER(Observer, observers_,
366 PeripheralBatteryStatusReceived(path, name, level));
369 void PowerSupplyPollReceived(dbus::Signal* signal) {
370 VLOG(1) << "Received power supply poll signal.";
371 dbus::MessageReader reader(signal);
372 power_manager::PowerSupplyProperties protobuf;
373 if (reader.PopArrayOfBytesAsProto(&protobuf)) {
374 FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(protobuf));
376 LOG(ERROR) << "Unable to decode "
377 << power_manager::kPowerSupplyPollSignal << "signal";
381 void OnGetPowerSupplyPropertiesMethod(dbus::Response* response) {
383 LOG(ERROR) << "Error calling "
384 << power_manager::kGetPowerSupplyPropertiesMethod;
388 dbus::MessageReader reader(response);
389 power_manager::PowerSupplyProperties protobuf;
390 if (reader.PopArrayOfBytesAsProto(&protobuf)) {
391 FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(protobuf));
393 LOG(ERROR) << "Unable to decode "
394 << power_manager::kGetPowerSupplyPropertiesMethod
399 void OnGetScreenBrightnessPercent(
400 const GetScreenBrightnessPercentCallback& callback,
401 dbus::Response* response) {
403 LOG(ERROR) << "Error calling "
404 << power_manager::kGetScreenBrightnessPercent;
407 dbus::MessageReader reader(response);
408 double percent = 0.0;
409 if (!reader.PopDouble(&percent))
410 LOG(ERROR) << "Error reading response from powerd: "
411 << response->ToString();
412 callback.Run(percent);
415 void OnRegisterSuspendDelayReply(dbus::Response* response) {
417 LOG(ERROR) << "Error calling "
418 << power_manager::kRegisterSuspendDelayMethod;
422 dbus::MessageReader reader(response);
423 power_manager::RegisterSuspendDelayReply protobuf;
424 if (!reader.PopArrayOfBytesAsProto(&protobuf)) {
425 LOG(ERROR) << "Unable to parse reply from "
426 << power_manager::kRegisterSuspendDelayMethod;
430 suspend_delay_id_ = protobuf.delay_id();
431 has_suspend_delay_id_ = true;
432 VLOG(1) << "Registered suspend delay " << suspend_delay_id_;
435 void SuspendImminentReceived(dbus::Signal* signal) {
436 if (!has_suspend_delay_id_) {
437 LOG(ERROR) << "Received unrequested "
438 << power_manager::kSuspendImminentSignal << " signal";
442 dbus::MessageReader reader(signal);
443 power_manager::SuspendImminent protobuf_imminent;
444 if (!reader.PopArrayOfBytesAsProto(&protobuf_imminent)) {
445 LOG(ERROR) << "Unable to decode protocol buffer from "
446 << power_manager::kSuspendImminentSignal << " signal";
450 if (suspend_is_pending_) {
451 LOG(WARNING) << "Got " << power_manager::kSuspendImminentSignal
452 << " signal about pending suspend attempt "
453 << protobuf_imminent.suspend_id() << " while still waiting "
454 << "on attempt " << pending_suspend_id_;
457 pending_suspend_id_ = protobuf_imminent.suspend_id();
458 suspend_is_pending_ = true;
459 num_pending_suspend_readiness_callbacks_ = 0;
460 FOR_EACH_OBSERVER(Observer, observers_, SuspendImminent());
461 MaybeReportSuspendReadiness();
464 void IdleActionImminentReceived(dbus::Signal* signal) {
465 FOR_EACH_OBSERVER(Observer, observers_, IdleActionImminent());
468 void IdleActionDeferredReceived(dbus::Signal* signal) {
469 FOR_EACH_OBSERVER(Observer, observers_, IdleActionDeferred());
472 void InputEventReceived(dbus::Signal* signal) {
473 dbus::MessageReader reader(signal);
474 power_manager::InputEvent proto;
475 if (!reader.PopArrayOfBytesAsProto(&proto)) {
476 LOG(ERROR) << "Unable to decode protocol buffer from "
477 << power_manager::kInputEventSignal << " signal";
481 base::TimeTicks timestamp =
482 base::TimeTicks::FromInternalValue(proto.timestamp());
483 VLOG(1) << "Got " << power_manager::kInputEventSignal << " signal:"
484 << " type=" << proto.type() << " timestamp=" << proto.timestamp();
485 switch (proto.type()) {
486 case power_manager::InputEvent_Type_POWER_BUTTON_DOWN:
487 case power_manager::InputEvent_Type_POWER_BUTTON_UP: {
489 (proto.type() == power_manager::InputEvent_Type_POWER_BUTTON_DOWN);
490 FOR_EACH_OBSERVER(PowerManagerClient::Observer, observers_,
491 PowerButtonEventReceived(down, timestamp));
494 case power_manager::InputEvent_Type_LID_OPEN:
495 case power_manager::InputEvent_Type_LID_CLOSED: {
497 (proto.type() == power_manager::InputEvent_Type_LID_OPEN);
498 FOR_EACH_OBSERVER(PowerManagerClient::Observer, observers_,
499 LidEventReceived(open, timestamp));
505 void SuspendStateChangedReceived(dbus::Signal* signal) {
506 dbus::MessageReader reader(signal);
507 power_manager::SuspendState proto;
508 if (!reader.PopArrayOfBytesAsProto(&proto)) {
509 LOG(ERROR) << "Unable to decode protocol buffer from "
510 << power_manager::kSuspendStateChangedSignal << " signal";
514 VLOG(1) << "Got " << power_manager::kSuspendStateChangedSignal << " signal:"
515 << " type=" << proto.type() << " wall_time=" << proto.wall_time();
516 base::Time wall_time =
517 base::Time::FromInternalValue(proto.wall_time());
518 switch (proto.type()) {
519 case power_manager::SuspendState_Type_SUSPEND_TO_MEMORY:
520 last_suspend_wall_time_ = wall_time;
522 case power_manager::SuspendState_Type_RESUME:
524 PowerManagerClient::Observer, observers_,
525 SystemResumed(wall_time - last_suspend_wall_time_));
530 // Registers a suspend delay with the power manager. This is usually
531 // only called at startup, but if the power manager restarts, we need to
532 // create a new delay.
533 void RegisterSuspendDelay() {
534 // Throw out any old delay that was registered.
535 suspend_delay_id_ = -1;
536 has_suspend_delay_id_ = false;
538 dbus::MethodCall method_call(
539 power_manager::kPowerManagerInterface,
540 power_manager::kRegisterSuspendDelayMethod);
541 dbus::MessageWriter writer(&method_call);
543 power_manager::RegisterSuspendDelayRequest protobuf_request;
544 base::TimeDelta timeout =
545 base::TimeDelta::FromMilliseconds(kSuspendDelayTimeoutMs);
546 protobuf_request.set_timeout(timeout.ToInternalValue());
547 protobuf_request.set_description(kSuspendDelayDescription);
549 if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) {
550 LOG(ERROR) << "Error constructing message for "
551 << power_manager::kRegisterSuspendDelayMethod;
554 power_manager_proxy_->CallMethod(
556 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
558 &PowerManagerClientImpl::OnRegisterSuspendDelayReply,
559 weak_ptr_factory_.GetWeakPtr()));
562 // Records the fact that an observer has finished doing asynchronous work
563 // that was blocking a pending suspend attempt and possibly reports
564 // suspend readiness to powerd. Called by callbacks returned via
565 // GetSuspendReadinessCallback().
566 void HandleObserverSuspendReadiness(int32 suspend_id) {
567 DCHECK(OnOriginThread());
568 if (!suspend_is_pending_ || suspend_id != pending_suspend_id_)
571 num_pending_suspend_readiness_callbacks_--;
572 MaybeReportSuspendReadiness();
575 // Reports suspend readiness to powerd if no observers are still holding
576 // suspend readiness callbacks.
577 void MaybeReportSuspendReadiness() {
578 if (!suspend_is_pending_ || num_pending_suspend_readiness_callbacks_ > 0)
581 dbus::MethodCall method_call(
582 power_manager::kPowerManagerInterface,
583 power_manager::kHandleSuspendReadinessMethod);
584 dbus::MessageWriter writer(&method_call);
586 power_manager::SuspendReadinessInfo protobuf_request;
587 protobuf_request.set_delay_id(suspend_delay_id_);
588 protobuf_request.set_suspend_id(pending_suspend_id_);
590 pending_suspend_id_ = -1;
591 suspend_is_pending_ = false;
593 if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) {
594 LOG(ERROR) << "Error constructing message for "
595 << power_manager::kHandleSuspendReadinessMethod;
598 power_manager_proxy_->CallMethod(
600 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
601 dbus::ObjectProxy::EmptyResponseCallback());
604 // Origin thread (i.e. the UI thread in production).
605 base::PlatformThreadId origin_thread_id_;
607 dbus::ObjectProxy* power_manager_proxy_;
608 ObserverList<Observer> observers_;
610 // The delay_id_ obtained from the RegisterSuspendDelay request.
611 int32 suspend_delay_id_;
612 bool has_suspend_delay_id_;
614 // powerd-supplied ID corresponding to an imminent suspend attempt that is
615 // currently being delayed.
616 int32 pending_suspend_id_;
617 bool suspend_is_pending_;
619 // Number of callbacks that have been returned by
620 // GetSuspendReadinessCallback() during the currently-pending suspend
621 // attempt but have not yet been called.
622 int num_pending_suspend_readiness_callbacks_;
624 // Wall time from the latest signal telling us that the system was about to
625 // suspend to memory.
626 base::Time last_suspend_wall_time_;
628 // Last state passed to SetIsProjecting().
629 bool last_is_projecting_;
631 // Note: This should remain the last member so it'll be destroyed and
632 // invalidate its weak pointers before any other members are destroyed.
633 base::WeakPtrFactory<PowerManagerClientImpl> weak_ptr_factory_;
635 DISALLOW_COPY_AND_ASSIGN(PowerManagerClientImpl);
638 // The PowerManagerClient implementation used on Linux desktop,
639 // which does nothing.
640 class PowerManagerClientStubImpl : public PowerManagerClient {
642 PowerManagerClientStubImpl()
643 : discharging_(true),
644 battery_percentage_(40),
648 num_pending_suspend_readiness_callbacks_(0),
649 weak_ptr_factory_(this) {}
651 virtual ~PowerManagerClientStubImpl() {}
653 int num_pending_suspend_readiness_callbacks() const {
654 return num_pending_suspend_readiness_callbacks_;
657 // PowerManagerClient overrides:
658 virtual void Init(dbus::Bus* bus) OVERRIDE {
659 if (CommandLine::ForCurrentProcess()->HasSwitch(
660 chromeos::switches::kEnableStubInteractive)) {
661 const int kStatusUpdateMs = 1000;
662 update_timer_.Start(FROM_HERE,
663 base::TimeDelta::FromMilliseconds(kStatusUpdateMs), this,
664 &PowerManagerClientStubImpl::UpdateStatus);
668 virtual void AddObserver(Observer* observer) OVERRIDE {
669 observers_.AddObserver(observer);
672 virtual void RemoveObserver(Observer* observer) OVERRIDE {
673 observers_.RemoveObserver(observer);
676 virtual bool HasObserver(Observer* observer) OVERRIDE {
677 return observers_.HasObserver(observer);
680 virtual void DecreaseScreenBrightness(bool allow_off) OVERRIDE {
681 VLOG(1) << "Requested to descrease screen brightness";
682 SetBrightness(brightness_ - 5.0, true);
685 virtual void IncreaseScreenBrightness() OVERRIDE {
686 VLOG(1) << "Requested to increase screen brightness";
687 SetBrightness(brightness_ + 5.0, true);
690 virtual void SetScreenBrightnessPercent(double percent,
691 bool gradual) OVERRIDE {
692 VLOG(1) << "Requested to set screen brightness to " << percent << "% "
693 << (gradual ? "gradually" : "instantaneously");
694 SetBrightness(percent, false);
697 virtual void GetScreenBrightnessPercent(
698 const GetScreenBrightnessPercentCallback& callback) OVERRIDE {
699 callback.Run(brightness_);
702 virtual void DecreaseKeyboardBrightness() OVERRIDE {
703 VLOG(1) << "Requested to descrease keyboard brightness";
706 virtual void IncreaseKeyboardBrightness() OVERRIDE {
707 VLOG(1) << "Requested to increase keyboard brightness";
710 virtual void RequestStatusUpdate() OVERRIDE {
711 base::MessageLoop::current()->PostTask(FROM_HERE,
712 base::Bind(&PowerManagerClientStubImpl::UpdateStatus,
713 weak_ptr_factory_.GetWeakPtr()));
716 virtual void RequestRestart() OVERRIDE {}
717 virtual void RequestShutdown() OVERRIDE {}
719 virtual void NotifyUserActivity(
720 power_manager::UserActivityType type) OVERRIDE {}
721 virtual void NotifyVideoActivity(bool is_fullscreen) OVERRIDE {}
722 virtual void SetPolicy(
723 const power_manager::PowerManagementPolicy& policy) OVERRIDE {}
724 virtual void SetIsProjecting(bool is_projecting) OVERRIDE {}
725 virtual base::Closure GetSuspendReadinessCallback() OVERRIDE {
726 num_pending_suspend_readiness_callbacks_++;
727 return base::Bind(&PowerManagerClientStubImpl::HandleSuspendReadiness,
728 weak_ptr_factory_.GetWeakPtr());
730 virtual int GetNumPendingSuspendReadinessCallbacks() OVERRIDE {
731 return num_pending_suspend_readiness_callbacks_;
735 void HandleSuspendReadiness() {
736 num_pending_suspend_readiness_callbacks_--;
739 void UpdateStatus() {
740 if (pause_count_ > 0) {
742 if (pause_count_ == 2)
743 discharging_ = !discharging_;
746 battery_percentage_ -= (battery_percentage_ <= 10 ? 1 : 10);
748 battery_percentage_ += (battery_percentage_ >= 10 ? 10 : 1);
749 battery_percentage_ = std::min(std::max(battery_percentage_, 0), 100);
750 // We pause at 0 and 100% so that it's easier to check those conditions.
751 if (battery_percentage_ == 0 || battery_percentage_ == 100) {
753 if (battery_percentage_ == 100)
754 cycle_count_ = (cycle_count_ + 1) % 3;
758 const int kSecondsToEmptyFullBattery = 3 * 60 * 60; // 3 hours.
759 int64 remaining_battery_time =
760 std::max(1, battery_percentage_ * kSecondsToEmptyFullBattery / 100);
764 switch (cycle_count_) {
766 // Say that the system is charging with AC connected and
767 // discharging without any charger connected.
768 props_.set_external_power(discharging_ ?
769 power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED :
770 power_manager::PowerSupplyProperties_ExternalPower_AC);
773 // Say that the system is both charging and discharging on USB
774 // (i.e. a low-power charger).
775 props_.set_external_power(
776 power_manager::PowerSupplyProperties_ExternalPower_USB);
779 // Say that the system is both charging and discharging on AC.
780 props_.set_external_power(
781 power_manager::PowerSupplyProperties_ExternalPower_AC);
784 NOTREACHED() << "Unhandled cycle " << cycle_count_;
787 if (battery_percentage_ == 100 && !discharging_) {
788 props_.set_battery_state(
789 power_manager::PowerSupplyProperties_BatteryState_FULL);
790 } else if (!discharging_) {
791 props_.set_battery_state(
792 power_manager::PowerSupplyProperties_BatteryState_CHARGING);
793 props_.set_battery_time_to_full_sec(std::max(static_cast<int64>(1),
794 kSecondsToEmptyFullBattery - remaining_battery_time));
796 props_.set_battery_state(
797 power_manager::PowerSupplyProperties_BatteryState_DISCHARGING);
798 props_.set_battery_time_to_empty_sec(remaining_battery_time);
801 props_.set_battery_percent(battery_percentage_);
802 props_.set_is_calculating_battery_time(pause_count_ > 1);
804 FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(props_));
807 void SetBrightness(double percent, bool user_initiated) {
808 brightness_ = std::min(std::max(0.0, percent), 100.0);
809 int brightness_level = static_cast<int>(brightness_);
810 FOR_EACH_OBSERVER(Observer, observers_,
811 BrightnessChanged(brightness_level, user_initiated));
815 int battery_percentage_;
819 ObserverList<Observer> observers_;
820 base::RepeatingTimer<PowerManagerClientStubImpl> update_timer_;
821 power_manager::PowerSupplyProperties props_;
823 // Number of callbacks returned by GetSuspendReadinessCallback() but not yet
825 int num_pending_suspend_readiness_callbacks_;
827 // Note: This should remain the last member so it'll be destroyed and
828 // invalidate its weak pointers before any other members are destroyed.
829 base::WeakPtrFactory<PowerManagerClientStubImpl> weak_ptr_factory_;
832 PowerManagerClient::PowerManagerClient() {
835 PowerManagerClient::~PowerManagerClient() {
839 PowerManagerClient* PowerManagerClient::Create(
840 DBusClientImplementationType type) {
841 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
842 return new PowerManagerClientImpl();
843 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
844 return new PowerManagerClientStubImpl();
847 } // namespace chromeos