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/power_monitor/power_monitor_device_source.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_split.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/threading/platform_thread.h"
22 #include "base/time/time.h"
23 #include "base/timer/timer.h"
24 #include "chromeos/chromeos_switches.h"
25 #include "chromeos/dbus/power_manager/input_event.pb.h"
26 #include "chromeos/dbus/power_manager/peripheral_battery_status.pb.h"
27 #include "chromeos/dbus/power_manager/policy.pb.h"
28 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
29 #include "chromeos/dbus/power_manager/suspend.pb.h"
31 #include "dbus/message.h"
32 #include "dbus/object_path.h"
33 #include "dbus/object_proxy.h"
37 // Maximum amount of time that the power manager will wait for Chrome to
38 // say that it's ready for the system to be suspended, in milliseconds.
39 const int kSuspendDelayTimeoutMs = 5000;
41 // Human-readable description of Chrome's suspend delay.
42 const char kSuspendDelayDescription[] = "chrome";
44 // The PowerManagerClient implementation used in production.
45 class PowerManagerClientImpl : public PowerManagerClient {
47 PowerManagerClientImpl()
48 : origin_thread_id_(base::PlatformThread::CurrentId()),
49 power_manager_proxy_(NULL),
50 suspend_delay_id_(-1),
51 has_suspend_delay_id_(false),
52 dark_suspend_delay_id_(-1),
53 has_dark_suspend_delay_id_(false),
54 pending_suspend_id_(-1),
55 suspend_is_pending_(false),
56 suspending_from_dark_resume_(false),
57 num_pending_suspend_readiness_callbacks_(0),
58 last_is_projecting_(false),
59 weak_ptr_factory_(this) {}
61 virtual ~PowerManagerClientImpl() {
62 // Here we should unregister suspend notifications from powerd,
64 // - The lifetime of the PowerManagerClientImpl can extend past that of
66 // - power_manager can already detect that the client is gone and
67 // unregister our suspend delay.
70 // PowerManagerClient overrides:
72 virtual void AddObserver(Observer* observer) override {
73 CHECK(observer); // http://crbug.com/119976
74 observers_.AddObserver(observer);
77 virtual void RemoveObserver(Observer* observer) override {
78 observers_.RemoveObserver(observer);
81 virtual bool HasObserver(Observer* observer) override {
82 return observers_.HasObserver(observer);
85 virtual void DecreaseScreenBrightness(bool allow_off) override {
86 dbus::MethodCall method_call(
87 power_manager::kPowerManagerInterface,
88 power_manager::kDecreaseScreenBrightnessMethod);
89 dbus::MessageWriter writer(&method_call);
90 writer.AppendBool(allow_off);
91 power_manager_proxy_->CallMethod(
93 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
94 dbus::ObjectProxy::EmptyResponseCallback());
97 virtual void IncreaseScreenBrightness() override {
98 SimpleMethodCallToPowerManager(
99 power_manager::kIncreaseScreenBrightnessMethod);
102 virtual void DecreaseKeyboardBrightness() override {
103 SimpleMethodCallToPowerManager(
104 power_manager::kDecreaseKeyboardBrightnessMethod);
107 virtual void IncreaseKeyboardBrightness() override {
108 SimpleMethodCallToPowerManager(
109 power_manager::kIncreaseKeyboardBrightnessMethod);
112 virtual void SetScreenBrightnessPercent(double percent,
113 bool gradual) override {
114 dbus::MethodCall method_call(
115 power_manager::kPowerManagerInterface,
116 power_manager::kSetScreenBrightnessPercentMethod);
117 dbus::MessageWriter writer(&method_call);
118 writer.AppendDouble(percent);
121 power_manager::kBrightnessTransitionGradual :
122 power_manager::kBrightnessTransitionInstant);
123 power_manager_proxy_->CallMethod(
125 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
126 dbus::ObjectProxy::EmptyResponseCallback());
129 virtual void GetScreenBrightnessPercent(
130 const GetScreenBrightnessPercentCallback& callback) override {
131 dbus::MethodCall method_call(
132 power_manager::kPowerManagerInterface,
133 power_manager::kGetScreenBrightnessPercentMethod);
134 power_manager_proxy_->CallMethod(
136 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
137 base::Bind(&PowerManagerClientImpl::OnGetScreenBrightnessPercent,
138 weak_ptr_factory_.GetWeakPtr(), callback));
141 virtual void RequestStatusUpdate() override {
142 dbus::MethodCall method_call(
143 power_manager::kPowerManagerInterface,
144 power_manager::kGetPowerSupplyPropertiesMethod);
145 power_manager_proxy_->CallMethod(
147 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
148 base::Bind(&PowerManagerClientImpl::OnGetPowerSupplyPropertiesMethod,
149 weak_ptr_factory_.GetWeakPtr()));
152 virtual void RequestSuspend() override {
153 SimpleMethodCallToPowerManager(power_manager::kRequestSuspendMethod);
156 virtual void RequestRestart() override {
157 SimpleMethodCallToPowerManager(power_manager::kRequestRestartMethod);
160 virtual void RequestShutdown() override {
161 SimpleMethodCallToPowerManager(power_manager::kRequestShutdownMethod);
164 virtual void NotifyUserActivity(
165 power_manager::UserActivityType type) override {
166 dbus::MethodCall method_call(
167 power_manager::kPowerManagerInterface,
168 power_manager::kHandleUserActivityMethod);
169 dbus::MessageWriter writer(&method_call);
170 writer.AppendInt32(type);
172 power_manager_proxy_->CallMethod(
174 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
175 dbus::ObjectProxy::EmptyResponseCallback());
178 virtual void NotifyVideoActivity(bool is_fullscreen) override {
179 dbus::MethodCall method_call(
180 power_manager::kPowerManagerInterface,
181 power_manager::kHandleVideoActivityMethod);
182 dbus::MessageWriter writer(&method_call);
183 writer.AppendBool(is_fullscreen);
185 power_manager_proxy_->CallMethod(
187 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
188 dbus::ObjectProxy::EmptyResponseCallback());
191 virtual void SetPolicy(
192 const power_manager::PowerManagementPolicy& policy) override {
193 dbus::MethodCall method_call(
194 power_manager::kPowerManagerInterface,
195 power_manager::kSetPolicyMethod);
196 dbus::MessageWriter writer(&method_call);
197 if (!writer.AppendProtoAsArrayOfBytes(policy)) {
198 LOG(ERROR) << "Error calling " << power_manager::kSetPolicyMethod;
201 power_manager_proxy_->CallMethod(
203 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
204 dbus::ObjectProxy::EmptyResponseCallback());
207 virtual void SetIsProjecting(bool is_projecting) override {
208 dbus::MethodCall method_call(
209 power_manager::kPowerManagerInterface,
210 power_manager::kSetIsProjectingMethod);
211 dbus::MessageWriter writer(&method_call);
212 writer.AppendBool(is_projecting);
213 power_manager_proxy_->CallMethod(
215 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
216 dbus::ObjectProxy::EmptyResponseCallback());
217 last_is_projecting_ = is_projecting;
220 virtual base::Closure GetSuspendReadinessCallback() override {
221 DCHECK(OnOriginThread());
222 DCHECK(suspend_is_pending_);
223 num_pending_suspend_readiness_callbacks_++;
224 return base::Bind(&PowerManagerClientImpl::HandleObserverSuspendReadiness,
225 weak_ptr_factory_.GetWeakPtr(), pending_suspend_id_,
226 suspending_from_dark_resume_);
229 virtual int GetNumPendingSuspendReadinessCallbacks() override {
230 return num_pending_suspend_readiness_callbacks_;
234 virtual void Init(dbus::Bus* bus) override {
235 power_manager_proxy_ = bus->GetObjectProxy(
236 power_manager::kPowerManagerServiceName,
237 dbus::ObjectPath(power_manager::kPowerManagerServicePath));
239 power_manager_proxy_->SetNameOwnerChangedCallback(
240 base::Bind(&PowerManagerClientImpl::NameOwnerChangedReceived,
241 weak_ptr_factory_.GetWeakPtr()));
243 // Monitor the D-Bus signal for brightness changes. Only the power
244 // manager knows the actual brightness level. We don't cache the
245 // brightness level in Chrome as it'll make things less reliable.
246 power_manager_proxy_->ConnectToSignal(
247 power_manager::kPowerManagerInterface,
248 power_manager::kBrightnessChangedSignal,
249 base::Bind(&PowerManagerClientImpl::BrightnessChangedReceived,
250 weak_ptr_factory_.GetWeakPtr()),
251 base::Bind(&PowerManagerClientImpl::SignalConnected,
252 weak_ptr_factory_.GetWeakPtr()));
254 power_manager_proxy_->ConnectToSignal(
255 power_manager::kPowerManagerInterface,
256 power_manager::kPeripheralBatteryStatusSignal,
257 base::Bind(&PowerManagerClientImpl::PeripheralBatteryStatusReceived,
258 weak_ptr_factory_.GetWeakPtr()),
259 base::Bind(&PowerManagerClientImpl::SignalConnected,
260 weak_ptr_factory_.GetWeakPtr()));
262 power_manager_proxy_->ConnectToSignal(
263 power_manager::kPowerManagerInterface,
264 power_manager::kPowerSupplyPollSignal,
265 base::Bind(&PowerManagerClientImpl::PowerSupplyPollReceived,
266 weak_ptr_factory_.GetWeakPtr()),
267 base::Bind(&PowerManagerClientImpl::SignalConnected,
268 weak_ptr_factory_.GetWeakPtr()));
270 power_manager_proxy_->ConnectToSignal(
271 power_manager::kPowerManagerInterface,
272 power_manager::kInputEventSignal,
273 base::Bind(&PowerManagerClientImpl::InputEventReceived,
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::kSuspendImminentSignal,
282 &PowerManagerClientImpl::HandleSuspendImminent,
283 weak_ptr_factory_.GetWeakPtr(), false),
284 base::Bind(&PowerManagerClientImpl::SignalConnected,
285 weak_ptr_factory_.GetWeakPtr()));
287 power_manager_proxy_->ConnectToSignal(
288 power_manager::kPowerManagerInterface,
289 power_manager::kSuspendDoneSignal,
290 base::Bind(&PowerManagerClientImpl::SuspendDoneReceived,
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::kDarkSuspendImminentSignal,
299 &PowerManagerClientImpl::HandleSuspendImminent,
300 weak_ptr_factory_.GetWeakPtr(), true),
301 base::Bind(&PowerManagerClientImpl::SignalConnected,
302 weak_ptr_factory_.GetWeakPtr()));
304 power_manager_proxy_->ConnectToSignal(
305 power_manager::kPowerManagerInterface,
306 power_manager::kIdleActionImminentSignal,
308 &PowerManagerClientImpl::IdleActionImminentReceived,
309 weak_ptr_factory_.GetWeakPtr()),
310 base::Bind(&PowerManagerClientImpl::SignalConnected,
311 weak_ptr_factory_.GetWeakPtr()));
313 power_manager_proxy_->ConnectToSignal(
314 power_manager::kPowerManagerInterface,
315 power_manager::kIdleActionDeferredSignal,
317 &PowerManagerClientImpl::IdleActionDeferredReceived,
318 weak_ptr_factory_.GetWeakPtr()),
319 base::Bind(&PowerManagerClientImpl::SignalConnected,
320 weak_ptr_factory_.GetWeakPtr()));
322 RegisterSuspendDelays();
326 // Returns true if the current thread is the origin thread.
327 bool OnOriginThread() {
328 return base::PlatformThread::CurrentId() == origin_thread_id_;
331 // Called when a dbus signal is initially connected.
332 void SignalConnected(const std::string& interface_name,
333 const std::string& signal_name,
335 LOG_IF(WARNING, !success) << "Failed to connect to signal "
336 << signal_name << ".";
339 // Makes a method call to power manager with no arguments and no response.
340 void SimpleMethodCallToPowerManager(const std::string& method_name) {
341 dbus::MethodCall method_call(power_manager::kPowerManagerInterface,
343 power_manager_proxy_->CallMethod(
345 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
346 dbus::ObjectProxy::EmptyResponseCallback());
349 void NameOwnerChangedReceived(const std::string& old_owner,
350 const std::string& new_owner) {
351 VLOG(1) << "Power manager restarted (old owner was "
352 << (old_owner.empty() ? "[none]" : old_owner.c_str())
354 << (new_owner.empty() ? "[none]" : new_owner.c_str()) << ")";
355 suspend_is_pending_ = false;
356 pending_suspend_id_ = -1;
357 suspending_from_dark_resume_ = false;
358 if (!new_owner.empty()) {
359 VLOG(1) << "Sending initial state to power manager";
360 RegisterSuspendDelays();
361 SetIsProjecting(last_is_projecting_);
362 FOR_EACH_OBSERVER(Observer, observers_, PowerManagerRestarted());
366 void BrightnessChangedReceived(dbus::Signal* signal) {
367 dbus::MessageReader reader(signal);
368 int32_t brightness_level = 0;
369 bool user_initiated = 0;
370 if (!(reader.PopInt32(&brightness_level) &&
371 reader.PopBool(&user_initiated))) {
372 LOG(ERROR) << "Brightness changed signal had incorrect parameters: "
373 << signal->ToString();
376 VLOG(1) << "Brightness changed to " << brightness_level
377 << ": user initiated " << user_initiated;
378 FOR_EACH_OBSERVER(Observer, observers_,
379 BrightnessChanged(brightness_level, user_initiated));
382 void PeripheralBatteryStatusReceived(dbus::Signal* signal) {
383 dbus::MessageReader reader(signal);
384 power_manager::PeripheralBatteryStatus protobuf_status;
385 if (!reader.PopArrayOfBytesAsProto(&protobuf_status)) {
386 LOG(ERROR) << "Unable to decode protocol buffer from "
387 << power_manager::kPeripheralBatteryStatusSignal << " signal";
391 std::string path = protobuf_status.path();
392 std::string name = protobuf_status.name();
393 int level = protobuf_status.has_level() ? protobuf_status.level() : -1;
395 VLOG(1) << "Device battery status received " << level
396 << " for " << name << " at " << path;
398 FOR_EACH_OBSERVER(Observer, observers_,
399 PeripheralBatteryStatusReceived(path, name, level));
402 void PowerSupplyPollReceived(dbus::Signal* signal) {
403 VLOG(1) << "Received power supply poll signal.";
404 dbus::MessageReader reader(signal);
405 power_manager::PowerSupplyProperties protobuf;
406 if (reader.PopArrayOfBytesAsProto(&protobuf)) {
407 HandlePowerSupplyProperties(protobuf);
409 LOG(ERROR) << "Unable to decode "
410 << power_manager::kPowerSupplyPollSignal << "signal";
414 void OnGetPowerSupplyPropertiesMethod(dbus::Response* response) {
416 LOG(ERROR) << "Error calling "
417 << power_manager::kGetPowerSupplyPropertiesMethod;
421 dbus::MessageReader reader(response);
422 power_manager::PowerSupplyProperties protobuf;
423 if (reader.PopArrayOfBytesAsProto(&protobuf)) {
424 HandlePowerSupplyProperties(protobuf);
426 LOG(ERROR) << "Unable to decode "
427 << power_manager::kGetPowerSupplyPropertiesMethod
432 void OnGetScreenBrightnessPercent(
433 const GetScreenBrightnessPercentCallback& callback,
434 dbus::Response* response) {
436 LOG(ERROR) << "Error calling "
437 << power_manager::kGetScreenBrightnessPercentMethod;
440 dbus::MessageReader reader(response);
441 double percent = 0.0;
442 if (!reader.PopDouble(&percent))
443 LOG(ERROR) << "Error reading response from powerd: "
444 << response->ToString();
445 callback.Run(percent);
448 void HandlePowerSupplyProperties(
449 const power_manager::PowerSupplyProperties& proto) {
450 FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(proto));
451 const bool on_battery = proto.external_power() ==
452 power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED;
453 base::PowerMonitorDeviceSource::SetPowerSource(on_battery);
456 void HandleRegisterSuspendDelayReply(bool dark_suspend,
457 const std::string& method_name,
458 dbus::Response* response) {
460 LOG(ERROR) << "Error calling " << method_name;
464 dbus::MessageReader reader(response);
465 power_manager::RegisterSuspendDelayReply protobuf;
466 if (!reader.PopArrayOfBytesAsProto(&protobuf)) {
467 LOG(ERROR) << "Unable to parse reply from " << method_name;
472 dark_suspend_delay_id_ = protobuf.delay_id();
473 has_dark_suspend_delay_id_ = true;
474 VLOG(1) << "Registered dark suspend delay " << dark_suspend_delay_id_;
476 suspend_delay_id_ = protobuf.delay_id();
477 has_suspend_delay_id_ = true;
478 VLOG(1) << "Registered suspend delay " << suspend_delay_id_;
482 void HandleSuspendImminent(bool in_dark_resume, dbus::Signal* signal) {
483 std::string signal_name = signal->GetMember();
484 if ((in_dark_resume && !has_dark_suspend_delay_id_) ||
485 (!in_dark_resume && !has_suspend_delay_id_)) {
486 LOG(ERROR) << "Received unrequested " << signal_name << " signal";
490 dbus::MessageReader reader(signal);
491 power_manager::SuspendImminent proto;
492 if (!reader.PopArrayOfBytesAsProto(&proto)) {
493 LOG(ERROR) << "Unable to decode protocol buffer from " << signal_name
498 VLOG(1) << "Got " << signal_name << " signal announcing suspend attempt "
499 << proto.suspend_id();
501 // If a previous suspend is pending from the same state we are currently in
502 // (fully powered on or in dark resume), then something's gone a little
504 if (suspend_is_pending_ &&
505 suspending_from_dark_resume_ == in_dark_resume) {
506 LOG(WARNING) << "Got " << signal_name << " signal about pending suspend "
507 << "attempt " << proto.suspend_id() << " while still "
508 << "waiting on attempt " << pending_suspend_id_;
511 pending_suspend_id_ = proto.suspend_id();
512 suspend_is_pending_ = true;
513 suspending_from_dark_resume_ = in_dark_resume;
514 num_pending_suspend_readiness_callbacks_ = 0;
515 if (suspending_from_dark_resume_)
516 FOR_EACH_OBSERVER(Observer, observers_, DarkSuspendImminent());
518 FOR_EACH_OBSERVER(Observer, observers_, SuspendImminent());
519 base::PowerMonitorDeviceSource::HandleSystemSuspending();
520 MaybeReportSuspendReadiness();
523 void SuspendDoneReceived(dbus::Signal* signal) {
524 dbus::MessageReader reader(signal);
525 power_manager::SuspendDone proto;
526 if (!reader.PopArrayOfBytesAsProto(&proto)) {
527 LOG(ERROR) << "Unable to decode protocol buffer from "
528 << power_manager::kSuspendDoneSignal << " signal";
532 const base::TimeDelta duration =
533 base::TimeDelta::FromInternalValue(proto.suspend_duration());
534 VLOG(1) << "Got " << power_manager::kSuspendDoneSignal << " signal:"
535 << " suspend_id=" << proto.suspend_id()
536 << " duration=" << duration.InSeconds() << " sec";
538 PowerManagerClient::Observer, observers_, SuspendDone(duration));
539 base::PowerMonitorDeviceSource::HandleSystemResumed();
542 void IdleActionImminentReceived(dbus::Signal* signal) {
543 dbus::MessageReader reader(signal);
544 power_manager::IdleActionImminent proto;
545 if (!reader.PopArrayOfBytesAsProto(&proto)) {
546 LOG(ERROR) << "Unable to decode protocol buffer from "
547 << power_manager::kIdleActionImminentSignal << " signal";
550 FOR_EACH_OBSERVER(Observer, observers_,
551 IdleActionImminent(base::TimeDelta::FromInternalValue(
552 proto.time_until_idle_action())));
555 void IdleActionDeferredReceived(dbus::Signal* signal) {
556 FOR_EACH_OBSERVER(Observer, observers_, IdleActionDeferred());
559 void InputEventReceived(dbus::Signal* signal) {
560 dbus::MessageReader reader(signal);
561 power_manager::InputEvent proto;
562 if (!reader.PopArrayOfBytesAsProto(&proto)) {
563 LOG(ERROR) << "Unable to decode protocol buffer from "
564 << power_manager::kInputEventSignal << " signal";
568 base::TimeTicks timestamp =
569 base::TimeTicks::FromInternalValue(proto.timestamp());
570 VLOG(1) << "Got " << power_manager::kInputEventSignal << " signal:"
571 << " type=" << proto.type() << " timestamp=" << proto.timestamp();
572 switch (proto.type()) {
573 case power_manager::InputEvent_Type_POWER_BUTTON_DOWN:
574 case power_manager::InputEvent_Type_POWER_BUTTON_UP: {
576 (proto.type() == power_manager::InputEvent_Type_POWER_BUTTON_DOWN);
577 FOR_EACH_OBSERVER(PowerManagerClient::Observer, observers_,
578 PowerButtonEventReceived(down, timestamp));
580 // Tell powerd that Chrome has handled power button presses.
582 dbus::MethodCall method_call(
583 power_manager::kPowerManagerInterface,
584 power_manager::kHandlePowerButtonAcknowledgmentMethod);
585 dbus::MessageWriter writer(&method_call);
586 writer.AppendInt64(proto.timestamp());
587 power_manager_proxy_->CallMethod(
589 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
590 dbus::ObjectProxy::EmptyResponseCallback());
594 case power_manager::InputEvent_Type_LID_OPEN:
595 case power_manager::InputEvent_Type_LID_CLOSED: {
597 (proto.type() == power_manager::InputEvent_Type_LID_OPEN);
598 FOR_EACH_OBSERVER(PowerManagerClient::Observer, observers_,
599 LidEventReceived(open, timestamp));
605 void RegisterSuspendDelayImpl(
606 const std::string& method_name,
607 const power_manager::RegisterSuspendDelayRequest& protobuf_request,
608 dbus::ObjectProxy::ResponseCallback callback) {
609 dbus::MethodCall method_call(
610 power_manager::kPowerManagerInterface, method_name);
611 dbus::MessageWriter writer(&method_call);
613 if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) {
614 LOG(ERROR) << "Error constructing message for " << method_name;
618 power_manager_proxy_->CallMethod(
619 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, callback);
622 // Registers suspend delays with the power manager. This is usually only
623 // called at startup, but if the power manager restarts, we need to create new
625 void RegisterSuspendDelays() {
626 // Throw out any old delay that was registered.
627 suspend_delay_id_ = -1;
628 has_suspend_delay_id_ = false;
629 dark_suspend_delay_id_ = -1;
630 has_dark_suspend_delay_id_ = false;
632 power_manager::RegisterSuspendDelayRequest protobuf_request;
633 base::TimeDelta timeout =
634 base::TimeDelta::FromMilliseconds(kSuspendDelayTimeoutMs);
635 protobuf_request.set_timeout(timeout.ToInternalValue());
636 protobuf_request.set_description(kSuspendDelayDescription);
638 RegisterSuspendDelayImpl(
639 power_manager::kRegisterSuspendDelayMethod,
641 base::Bind(&PowerManagerClientImpl::HandleRegisterSuspendDelayReply,
642 weak_ptr_factory_.GetWeakPtr(), false,
643 power_manager::kRegisterSuspendDelayMethod));
644 RegisterSuspendDelayImpl(
645 power_manager::kRegisterDarkSuspendDelayMethod,
647 base::Bind(&PowerManagerClientImpl::HandleRegisterSuspendDelayReply,
648 weak_ptr_factory_.GetWeakPtr(), true,
649 power_manager::kRegisterDarkSuspendDelayMethod));
652 // Records the fact that an observer has finished doing asynchronous work
653 // that was blocking a pending suspend attempt and possibly reports
654 // suspend readiness to powerd. Called by callbacks returned via
655 // GetSuspendReadinessCallback().
656 void HandleObserverSuspendReadiness(int32_t suspend_id, bool in_dark_resume) {
657 DCHECK(OnOriginThread());
658 if (!suspend_is_pending_ || suspend_id != pending_suspend_id_ ||
659 in_dark_resume != suspending_from_dark_resume_)
662 num_pending_suspend_readiness_callbacks_--;
663 MaybeReportSuspendReadiness();
666 // Reports suspend readiness to powerd if no observers are still holding
667 // suspend readiness callbacks.
668 void MaybeReportSuspendReadiness() {
669 if (!suspend_is_pending_ || num_pending_suspend_readiness_callbacks_ > 0)
672 std::string method_name;
673 int32_t delay_id = -1;
674 if (suspending_from_dark_resume_) {
675 method_name = power_manager::kHandleDarkSuspendReadinessMethod;
676 delay_id = dark_suspend_delay_id_;
678 method_name = power_manager::kHandleSuspendReadinessMethod;
679 delay_id = suspend_delay_id_;
682 dbus::MethodCall method_call(
683 power_manager::kPowerManagerInterface, method_name);
684 dbus::MessageWriter writer(&method_call);
686 VLOG(1) << "Announcing readiness of suspend delay " << delay_id
687 << " for suspend attempt " << pending_suspend_id_;
688 power_manager::SuspendReadinessInfo protobuf_request;
689 protobuf_request.set_delay_id(delay_id);
690 protobuf_request.set_suspend_id(pending_suspend_id_);
692 pending_suspend_id_ = -1;
693 suspend_is_pending_ = false;
695 if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) {
696 LOG(ERROR) << "Error constructing message for " << method_name;
699 power_manager_proxy_->CallMethod(
701 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
702 dbus::ObjectProxy::EmptyResponseCallback());
705 // Origin thread (i.e. the UI thread in production).
706 base::PlatformThreadId origin_thread_id_;
708 dbus::ObjectProxy* power_manager_proxy_;
709 ObserverList<Observer> observers_;
711 // The delay_id_ obtained from the RegisterSuspendDelay request.
712 int32_t suspend_delay_id_;
713 bool has_suspend_delay_id_;
715 // The delay_id_ obtained from the RegisterDarkSuspendDelay request.
716 int32_t dark_suspend_delay_id_;
717 bool has_dark_suspend_delay_id_;
719 // powerd-supplied ID corresponding to an imminent suspend attempt that is
720 // currently being delayed.
721 int32_t pending_suspend_id_;
722 bool suspend_is_pending_;
724 // Set to true when the suspend currently being delayed was triggered during a
725 // dark resume. Since |pending_suspend_id_| and |suspend_is_pending_| are
726 // both shared by normal and dark suspends, |suspending_from_dark_resume_|
727 // helps distinguish the context within which these variables are being used.
728 bool suspending_from_dark_resume_;
730 // Number of callbacks that have been returned by
731 // GetSuspendReadinessCallback() during the currently-pending suspend
732 // attempt but have not yet been called.
733 int num_pending_suspend_readiness_callbacks_;
735 // Last state passed to SetIsProjecting().
736 bool last_is_projecting_;
738 // Note: This should remain the last member so it'll be destroyed and
739 // invalidate its weak pointers before any other members are destroyed.
740 base::WeakPtrFactory<PowerManagerClientImpl> weak_ptr_factory_;
742 DISALLOW_COPY_AND_ASSIGN(PowerManagerClientImpl);
745 // The PowerManagerClient implementation used on Linux desktop,
746 // which does nothing.
747 class PowerManagerClientStubImpl : public PowerManagerClient {
749 PowerManagerClientStubImpl()
750 : discharging_(true),
751 battery_percentage_(40),
755 num_pending_suspend_readiness_callbacks_(0),
756 weak_ptr_factory_(this) {}
758 virtual ~PowerManagerClientStubImpl() {}
760 int num_pending_suspend_readiness_callbacks() const {
761 return num_pending_suspend_readiness_callbacks_;
764 // PowerManagerClient overrides:
765 virtual void Init(dbus::Bus* bus) override {
766 ParseCommandLineSwitch();
767 if (power_cycle_delay_ != base::TimeDelta()) {
768 update_timer_.Start(FROM_HERE,
771 &PowerManagerClientStubImpl::UpdateStatus);
775 virtual void AddObserver(Observer* observer) override {
776 observers_.AddObserver(observer);
779 virtual void RemoveObserver(Observer* observer) override {
780 observers_.RemoveObserver(observer);
783 virtual bool HasObserver(Observer* observer) override {
784 return observers_.HasObserver(observer);
787 virtual void DecreaseScreenBrightness(bool allow_off) override {
788 VLOG(1) << "Requested to descrease screen brightness";
789 SetBrightness(brightness_ - 5.0, true);
792 virtual void IncreaseScreenBrightness() override {
793 VLOG(1) << "Requested to increase screen brightness";
794 SetBrightness(brightness_ + 5.0, true);
797 virtual void SetScreenBrightnessPercent(double percent,
798 bool gradual) override {
799 VLOG(1) << "Requested to set screen brightness to " << percent << "% "
800 << (gradual ? "gradually" : "instantaneously");
801 SetBrightness(percent, false);
804 virtual void GetScreenBrightnessPercent(
805 const GetScreenBrightnessPercentCallback& callback) override {
806 callback.Run(brightness_);
809 virtual void DecreaseKeyboardBrightness() override {
810 VLOG(1) << "Requested to descrease keyboard brightness";
813 virtual void IncreaseKeyboardBrightness() override {
814 VLOG(1) << "Requested to increase keyboard brightness";
817 virtual void RequestStatusUpdate() override {
818 base::MessageLoop::current()->PostTask(FROM_HERE,
819 base::Bind(&PowerManagerClientStubImpl::UpdateStatus,
820 weak_ptr_factory_.GetWeakPtr()));
823 virtual void RequestSuspend() override {}
824 virtual void RequestRestart() override {}
825 virtual void RequestShutdown() override {}
827 virtual void NotifyUserActivity(
828 power_manager::UserActivityType type) override {}
829 virtual void NotifyVideoActivity(bool is_fullscreen) override {}
830 virtual void SetPolicy(
831 const power_manager::PowerManagementPolicy& policy) override {}
832 virtual void SetIsProjecting(bool is_projecting) override {}
833 virtual base::Closure GetSuspendReadinessCallback() override {
834 num_pending_suspend_readiness_callbacks_++;
835 return base::Bind(&PowerManagerClientStubImpl::HandleSuspendReadiness,
836 weak_ptr_factory_.GetWeakPtr());
838 virtual int GetNumPendingSuspendReadinessCallbacks() override {
839 return num_pending_suspend_readiness_callbacks_;
843 void HandleSuspendReadiness() {
844 num_pending_suspend_readiness_callbacks_--;
847 void UpdateStatus() {
848 if (pause_count_ > 0) {
850 if (pause_count_ == 2)
851 discharging_ = !discharging_;
854 battery_percentage_ -= (battery_percentage_ <= 10 ? 1 : 10);
856 battery_percentage_ += (battery_percentage_ >= 10 ? 10 : 1);
857 battery_percentage_ = std::min(std::max(battery_percentage_, 0), 100);
858 // We pause at 0 and 100% so that it's easier to check those conditions.
859 if (battery_percentage_ == 0 || battery_percentage_ == 100) {
861 if (battery_percentage_ == 100)
862 cycle_count_ = (cycle_count_ + 1) % 3;
866 const int kSecondsToEmptyFullBattery = 3 * 60 * 60; // 3 hours.
867 int64 remaining_battery_time =
868 std::max(1, battery_percentage_ * kSecondsToEmptyFullBattery / 100);
872 switch (cycle_count_) {
874 // Say that the system is charging with AC connected and
875 // discharging without any charger connected.
876 props_.set_external_power(discharging_ ?
877 power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED :
878 power_manager::PowerSupplyProperties_ExternalPower_AC);
881 // Say that the system is both charging and discharging on USB
882 // (i.e. a low-power charger).
883 props_.set_external_power(
884 power_manager::PowerSupplyProperties_ExternalPower_USB);
887 // Say that the system is both charging and discharging on AC.
888 props_.set_external_power(
889 power_manager::PowerSupplyProperties_ExternalPower_AC);
892 NOTREACHED() << "Unhandled cycle " << cycle_count_;
895 if (battery_percentage_ == 100 && !discharging_) {
896 props_.set_battery_state(
897 power_manager::PowerSupplyProperties_BatteryState_FULL);
898 } else if (!discharging_) {
899 props_.set_battery_state(
900 power_manager::PowerSupplyProperties_BatteryState_CHARGING);
901 props_.set_battery_time_to_full_sec(std::max(static_cast<int64>(1),
902 kSecondsToEmptyFullBattery - remaining_battery_time));
904 props_.set_battery_state(
905 power_manager::PowerSupplyProperties_BatteryState_DISCHARGING);
906 props_.set_battery_time_to_empty_sec(remaining_battery_time);
909 props_.set_battery_percent(battery_percentage_);
910 props_.set_is_calculating_battery_time(pause_count_ > 1);
912 FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(props_));
915 void SetBrightness(double percent, bool user_initiated) {
916 brightness_ = std::min(std::max(0.0, percent), 100.0);
917 int brightness_level = static_cast<int>(brightness_);
918 FOR_EACH_OBSERVER(Observer, observers_,
919 BrightnessChanged(brightness_level, user_initiated));
922 void ParseCommandLineSwitch() {
923 CommandLine* command_line = CommandLine::ForCurrentProcess();
924 if (!command_line || !command_line->HasSwitch(switches::kPowerStub))
926 std::string option_str =
927 command_line->GetSwitchValueASCII(switches::kPowerStub);
928 base::StringPairs string_pairs;
929 base::SplitStringIntoKeyValuePairs(option_str, '=', ',', &string_pairs);
930 for (base::StringPairs::iterator iter = string_pairs.begin();
931 iter != string_pairs.end(); ++iter) {
932 ParseOption((*iter).first, (*iter).second);
936 void ParseOption(const std::string& arg0, const std::string& arg1) {
937 if (arg0 == "cycle" || arg0 == "interactive") {
940 base::StringToInt(arg1, &seconds);
941 power_cycle_delay_ = base::TimeDelta::FromSeconds(seconds);
945 base::TimeDelta power_cycle_delay_; // Time over which to cycle power state
947 int battery_percentage_;
951 ObserverList<Observer> observers_;
952 base::RepeatingTimer<PowerManagerClientStubImpl> update_timer_;
953 power_manager::PowerSupplyProperties props_;
955 // Number of callbacks returned by GetSuspendReadinessCallback() but not yet
957 int num_pending_suspend_readiness_callbacks_;
959 // Note: This should remain the last member so it'll be destroyed and
960 // invalidate its weak pointers before any other members are destroyed.
961 base::WeakPtrFactory<PowerManagerClientStubImpl> weak_ptr_factory_;
964 PowerManagerClient::PowerManagerClient() {
967 PowerManagerClient::~PowerManagerClient() {
971 PowerManagerClient* PowerManagerClient::Create(
972 DBusClientImplementationType type) {
973 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
974 return new PowerManagerClientImpl();
975 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
976 return new PowerManagerClientStubImpl();
979 } // namespace chromeos