Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chromeos / dbus / power_manager_client.cc
blobd3cbc815b8d5985330c04ff453aa69269e94aaed
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"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/format_macros.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/observer_list.h"
16 #include "base/power_monitor/power_monitor_device_source.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/timer/timer.h"
22 #include "chromeos/chromeos_switches.h"
23 #include "chromeos/dbus/fake_power_manager_client.h"
24 #include "chromeos/dbus/power_manager/input_event.pb.h"
25 #include "chromeos/dbus/power_manager/peripheral_battery_status.pb.h"
26 #include "chromeos/dbus/power_manager/policy.pb.h"
27 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
28 #include "chromeos/dbus/power_manager/suspend.pb.h"
29 #include "components/device_event_log/device_event_log.h"
30 #include "dbus/bus.h"
31 #include "dbus/message.h"
32 #include "dbus/object_path.h"
33 #include "dbus/object_proxy.h"
35 namespace chromeos {
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 {
46 public:
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 ~PowerManagerClientImpl() override {
62 // Here we should unregister suspend notifications from powerd,
63 // however:
64 // - The lifetime of the PowerManagerClientImpl can extend past that of
65 // the objectproxy,
66 // - power_manager can already detect that the client is gone and
67 // unregister our suspend delay.
70 // PowerManagerClient overrides:
72 void AddObserver(Observer* observer) override {
73 CHECK(observer); // http://crbug.com/119976
74 observers_.AddObserver(observer);
77 void RemoveObserver(Observer* observer) override {
78 observers_.RemoveObserver(observer);
81 bool HasObserver(const Observer* observer) const override {
82 return observers_.HasObserver(observer);
85 void SetRenderProcessManagerDelegate(
86 base::WeakPtr<RenderProcessManagerDelegate> delegate) override {
87 DCHECK(!render_process_manager_delegate_)
88 << "There can be only one! ...RenderProcessManagerDelegate";
89 render_process_manager_delegate_ = delegate;
92 void DecreaseScreenBrightness(bool allow_off) override {
93 dbus::MethodCall method_call(
94 power_manager::kPowerManagerInterface,
95 power_manager::kDecreaseScreenBrightnessMethod);
96 dbus::MessageWriter writer(&method_call);
97 writer.AppendBool(allow_off);
98 power_manager_proxy_->CallMethod(
99 &method_call,
100 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
101 dbus::ObjectProxy::EmptyResponseCallback());
104 void IncreaseScreenBrightness() override {
105 SimpleMethodCallToPowerManager(
106 power_manager::kIncreaseScreenBrightnessMethod);
109 void DecreaseKeyboardBrightness() override {
110 SimpleMethodCallToPowerManager(
111 power_manager::kDecreaseKeyboardBrightnessMethod);
114 void IncreaseKeyboardBrightness() override {
115 SimpleMethodCallToPowerManager(
116 power_manager::kIncreaseKeyboardBrightnessMethod);
119 void SetScreenBrightnessPercent(double percent, bool gradual) override {
120 dbus::MethodCall method_call(
121 power_manager::kPowerManagerInterface,
122 power_manager::kSetScreenBrightnessPercentMethod);
123 dbus::MessageWriter writer(&method_call);
124 writer.AppendDouble(percent);
125 writer.AppendInt32(
126 gradual ?
127 power_manager::kBrightnessTransitionGradual :
128 power_manager::kBrightnessTransitionInstant);
129 power_manager_proxy_->CallMethod(
130 &method_call,
131 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
132 dbus::ObjectProxy::EmptyResponseCallback());
135 void GetScreenBrightnessPercent(
136 const GetScreenBrightnessPercentCallback& callback) override {
137 dbus::MethodCall method_call(
138 power_manager::kPowerManagerInterface,
139 power_manager::kGetScreenBrightnessPercentMethod);
140 power_manager_proxy_->CallMethod(
141 &method_call,
142 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
143 base::Bind(&PowerManagerClientImpl::OnGetScreenBrightnessPercent,
144 weak_ptr_factory_.GetWeakPtr(), callback));
147 void RequestStatusUpdate() override {
148 POWER_LOG(USER) << "RequestStatusUpdate";
149 dbus::MethodCall method_call(
150 power_manager::kPowerManagerInterface,
151 power_manager::kGetPowerSupplyPropertiesMethod);
152 power_manager_proxy_->CallMethod(
153 &method_call,
154 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
155 base::Bind(&PowerManagerClientImpl::OnGetPowerSupplyPropertiesMethod,
156 weak_ptr_factory_.GetWeakPtr()));
159 void RequestSuspend() override {
160 POWER_LOG(USER) << "RequestSuspend";
161 SimpleMethodCallToPowerManager(power_manager::kRequestSuspendMethod);
164 void RequestRestart() override {
165 POWER_LOG(USER) << "RequestRestart";
166 SimpleMethodCallToPowerManager(power_manager::kRequestRestartMethod);
169 void RequestShutdown() override {
170 POWER_LOG(USER) << "RequestShutdown";
171 SimpleMethodCallToPowerManager(power_manager::kRequestShutdownMethod);
174 void NotifyUserActivity(power_manager::UserActivityType type) override {
175 dbus::MethodCall method_call(
176 power_manager::kPowerManagerInterface,
177 power_manager::kHandleUserActivityMethod);
178 dbus::MessageWriter writer(&method_call);
179 writer.AppendInt32(type);
181 power_manager_proxy_->CallMethod(
182 &method_call,
183 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
184 dbus::ObjectProxy::EmptyResponseCallback());
187 void NotifyVideoActivity(bool is_fullscreen) override {
188 dbus::MethodCall method_call(
189 power_manager::kPowerManagerInterface,
190 power_manager::kHandleVideoActivityMethod);
191 dbus::MessageWriter writer(&method_call);
192 writer.AppendBool(is_fullscreen);
194 power_manager_proxy_->CallMethod(
195 &method_call,
196 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
197 dbus::ObjectProxy::EmptyResponseCallback());
200 void SetPolicy(const power_manager::PowerManagementPolicy& policy) override {
201 POWER_LOG(USER) << "SetPolicy";
202 dbus::MethodCall method_call(
203 power_manager::kPowerManagerInterface,
204 power_manager::kSetPolicyMethod);
205 dbus::MessageWriter writer(&method_call);
206 if (!writer.AppendProtoAsArrayOfBytes(policy)) {
207 POWER_LOG(ERROR) << "Error calling " << power_manager::kSetPolicyMethod;
208 return;
210 power_manager_proxy_->CallMethod(
211 &method_call,
212 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
213 dbus::ObjectProxy::EmptyResponseCallback());
216 void SetIsProjecting(bool is_projecting) override {
217 POWER_LOG(USER) << "SetIsProjecting";
218 dbus::MethodCall method_call(
219 power_manager::kPowerManagerInterface,
220 power_manager::kSetIsProjectingMethod);
221 dbus::MessageWriter writer(&method_call);
222 writer.AppendBool(is_projecting);
223 power_manager_proxy_->CallMethod(
224 &method_call,
225 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
226 dbus::ObjectProxy::EmptyResponseCallback());
227 last_is_projecting_ = is_projecting;
230 base::Closure GetSuspendReadinessCallback() override {
231 DCHECK(OnOriginThread());
232 DCHECK(suspend_is_pending_);
233 num_pending_suspend_readiness_callbacks_++;
234 return base::Bind(&PowerManagerClientImpl::HandleObserverSuspendReadiness,
235 weak_ptr_factory_.GetWeakPtr(), pending_suspend_id_,
236 suspending_from_dark_resume_);
239 int GetNumPendingSuspendReadinessCallbacks() override {
240 return num_pending_suspend_readiness_callbacks_;
243 protected:
244 void Init(dbus::Bus* bus) override {
245 power_manager_proxy_ = bus->GetObjectProxy(
246 power_manager::kPowerManagerServiceName,
247 dbus::ObjectPath(power_manager::kPowerManagerServicePath));
249 power_manager_proxy_->SetNameOwnerChangedCallback(
250 base::Bind(&PowerManagerClientImpl::NameOwnerChangedReceived,
251 weak_ptr_factory_.GetWeakPtr()));
253 // Monitor the D-Bus signal for brightness changes. Only the power
254 // manager knows the actual brightness level. We don't cache the
255 // brightness level in Chrome as it'll make things less reliable.
256 power_manager_proxy_->ConnectToSignal(
257 power_manager::kPowerManagerInterface,
258 power_manager::kBrightnessChangedSignal,
259 base::Bind(&PowerManagerClientImpl::BrightnessChangedReceived,
260 weak_ptr_factory_.GetWeakPtr()),
261 base::Bind(&PowerManagerClientImpl::SignalConnected,
262 weak_ptr_factory_.GetWeakPtr()));
264 power_manager_proxy_->ConnectToSignal(
265 power_manager::kPowerManagerInterface,
266 power_manager::kPeripheralBatteryStatusSignal,
267 base::Bind(&PowerManagerClientImpl::PeripheralBatteryStatusReceived,
268 weak_ptr_factory_.GetWeakPtr()),
269 base::Bind(&PowerManagerClientImpl::SignalConnected,
270 weak_ptr_factory_.GetWeakPtr()));
272 power_manager_proxy_->ConnectToSignal(
273 power_manager::kPowerManagerInterface,
274 power_manager::kPowerSupplyPollSignal,
275 base::Bind(&PowerManagerClientImpl::PowerSupplyPollReceived,
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::kInputEventSignal,
283 base::Bind(&PowerManagerClientImpl::InputEventReceived,
284 weak_ptr_factory_.GetWeakPtr()),
285 base::Bind(&PowerManagerClientImpl::SignalConnected,
286 weak_ptr_factory_.GetWeakPtr()));
288 power_manager_proxy_->ConnectToSignal(
289 power_manager::kPowerManagerInterface,
290 power_manager::kSuspendImminentSignal,
291 base::Bind(
292 &PowerManagerClientImpl::HandleSuspendImminent,
293 weak_ptr_factory_.GetWeakPtr(), false),
294 base::Bind(&PowerManagerClientImpl::SignalConnected,
295 weak_ptr_factory_.GetWeakPtr()));
297 power_manager_proxy_->ConnectToSignal(
298 power_manager::kPowerManagerInterface,
299 power_manager::kSuspendDoneSignal,
300 base::Bind(&PowerManagerClientImpl::SuspendDoneReceived,
301 weak_ptr_factory_.GetWeakPtr()),
302 base::Bind(&PowerManagerClientImpl::SignalConnected,
303 weak_ptr_factory_.GetWeakPtr()));
305 power_manager_proxy_->ConnectToSignal(
306 power_manager::kPowerManagerInterface,
307 power_manager::kDarkSuspendImminentSignal,
308 base::Bind(
309 &PowerManagerClientImpl::HandleSuspendImminent,
310 weak_ptr_factory_.GetWeakPtr(), true),
311 base::Bind(&PowerManagerClientImpl::SignalConnected,
312 weak_ptr_factory_.GetWeakPtr()));
314 power_manager_proxy_->ConnectToSignal(
315 power_manager::kPowerManagerInterface,
316 power_manager::kIdleActionImminentSignal,
317 base::Bind(
318 &PowerManagerClientImpl::IdleActionImminentReceived,
319 weak_ptr_factory_.GetWeakPtr()),
320 base::Bind(&PowerManagerClientImpl::SignalConnected,
321 weak_ptr_factory_.GetWeakPtr()));
323 power_manager_proxy_->ConnectToSignal(
324 power_manager::kPowerManagerInterface,
325 power_manager::kIdleActionDeferredSignal,
326 base::Bind(
327 &PowerManagerClientImpl::IdleActionDeferredReceived,
328 weak_ptr_factory_.GetWeakPtr()),
329 base::Bind(&PowerManagerClientImpl::SignalConnected,
330 weak_ptr_factory_.GetWeakPtr()));
332 RegisterSuspendDelays();
335 private:
336 // Returns true if the current thread is the origin thread.
337 bool OnOriginThread() {
338 return base::PlatformThread::CurrentId() == origin_thread_id_;
341 // Called when a dbus signal is initially connected.
342 void SignalConnected(const std::string& interface_name,
343 const std::string& signal_name,
344 bool success) {
345 if (!success)
346 POWER_LOG(ERROR) << "Failed to connect to signal " << signal_name << ".";
349 // Makes a method call to power manager with no arguments and no response.
350 void SimpleMethodCallToPowerManager(const std::string& method_name) {
351 dbus::MethodCall method_call(power_manager::kPowerManagerInterface,
352 method_name);
353 power_manager_proxy_->CallMethod(
354 &method_call,
355 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
356 dbus::ObjectProxy::EmptyResponseCallback());
359 void NameOwnerChangedReceived(const std::string& old_owner,
360 const std::string& new_owner) {
361 POWER_LOG(EVENT) << "Power manager restarted. Old owner: "
362 << (old_owner.empty() ? "[none]" : old_owner.c_str())
363 << " New owner: "
364 << (new_owner.empty() ? "[none]" : new_owner.c_str());
365 suspend_is_pending_ = false;
366 pending_suspend_id_ = -1;
367 suspending_from_dark_resume_ = false;
368 if (!new_owner.empty()) {
369 POWER_LOG(EVENT) << "Sending initial state to power manager";
370 RegisterSuspendDelays();
371 SetIsProjecting(last_is_projecting_);
372 FOR_EACH_OBSERVER(Observer, observers_, PowerManagerRestarted());
376 void BrightnessChangedReceived(dbus::Signal* signal) {
377 dbus::MessageReader reader(signal);
378 int32_t brightness_level = 0;
379 bool user_initiated = 0;
380 if (!(reader.PopInt32(&brightness_level) &&
381 reader.PopBool(&user_initiated))) {
382 POWER_LOG(ERROR) << "Brightness changed signal had incorrect parameters: "
383 << signal->ToString();
384 return;
386 POWER_LOG(DEBUG) << "Brightness changed to " << brightness_level
387 << ": user initiated " << user_initiated;
388 FOR_EACH_OBSERVER(Observer, observers_,
389 BrightnessChanged(brightness_level, user_initiated));
392 void PeripheralBatteryStatusReceived(dbus::Signal* signal) {
393 dbus::MessageReader reader(signal);
394 power_manager::PeripheralBatteryStatus protobuf_status;
395 if (!reader.PopArrayOfBytesAsProto(&protobuf_status)) {
396 POWER_LOG(ERROR) << "Unable to decode protocol buffer from "
397 << power_manager::kPeripheralBatteryStatusSignal
398 << " signal";
399 return;
402 std::string path = protobuf_status.path();
403 std::string name = protobuf_status.name();
404 int level = protobuf_status.has_level() ? protobuf_status.level() : -1;
406 POWER_LOG(DEBUG) << "Device battery status received " << level << " for "
407 << name << " at " << path;
409 FOR_EACH_OBSERVER(Observer, observers_,
410 PeripheralBatteryStatusReceived(path, name, level));
413 void PowerSupplyPollReceived(dbus::Signal* signal) {
414 POWER_LOG(DEBUG) << "Received power supply poll signal.";
415 dbus::MessageReader reader(signal);
416 power_manager::PowerSupplyProperties protobuf;
417 if (reader.PopArrayOfBytesAsProto(&protobuf)) {
418 HandlePowerSupplyProperties(protobuf);
419 } else {
420 POWER_LOG(ERROR) << "Unable to decode "
421 << power_manager::kPowerSupplyPollSignal << " signal";
425 void OnGetPowerSupplyPropertiesMethod(dbus::Response* response) {
426 if (!response) {
427 POWER_LOG(ERROR) << "Error calling "
428 << power_manager::kGetPowerSupplyPropertiesMethod;
429 return;
432 dbus::MessageReader reader(response);
433 power_manager::PowerSupplyProperties protobuf;
434 if (reader.PopArrayOfBytesAsProto(&protobuf)) {
435 HandlePowerSupplyProperties(protobuf);
436 } else {
437 POWER_LOG(ERROR) << "Unable to decode "
438 << power_manager::kGetPowerSupplyPropertiesMethod
439 << " response";
443 void OnGetScreenBrightnessPercent(
444 const GetScreenBrightnessPercentCallback& callback,
445 dbus::Response* response) {
446 if (!response) {
447 POWER_LOG(ERROR) << "Error calling "
448 << power_manager::kGetScreenBrightnessPercentMethod;
449 return;
451 dbus::MessageReader reader(response);
452 double percent = 0.0;
453 if (!reader.PopDouble(&percent))
454 POWER_LOG(ERROR) << "Error reading response from powerd: "
455 << response->ToString();
456 callback.Run(percent);
459 void HandlePowerSupplyProperties(
460 const power_manager::PowerSupplyProperties& proto) {
461 FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(proto));
462 const bool on_battery = proto.external_power() ==
463 power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED;
464 base::PowerMonitorDeviceSource::SetPowerSource(on_battery);
467 void HandleRegisterSuspendDelayReply(bool dark_suspend,
468 const std::string& method_name,
469 dbus::Response* response) {
470 if (!response) {
471 POWER_LOG(ERROR) << "Error calling " << method_name;
472 return;
475 dbus::MessageReader reader(response);
476 power_manager::RegisterSuspendDelayReply protobuf;
477 if (!reader.PopArrayOfBytesAsProto(&protobuf)) {
478 POWER_LOG(ERROR) << "Unable to parse reply from " << method_name;
479 return;
482 if (dark_suspend) {
483 dark_suspend_delay_id_ = protobuf.delay_id();
484 has_dark_suspend_delay_id_ = true;
485 POWER_LOG(EVENT) << "Registered dark suspend delay "
486 << dark_suspend_delay_id_;
487 } else {
488 suspend_delay_id_ = protobuf.delay_id();
489 has_suspend_delay_id_ = true;
490 POWER_LOG(EVENT) << "Registered suspend delay " << suspend_delay_id_;
494 void HandleSuspendImminent(bool in_dark_resume, dbus::Signal* signal) {
495 std::string signal_name = signal->GetMember();
496 if ((in_dark_resume && !has_dark_suspend_delay_id_) ||
497 (!in_dark_resume && !has_suspend_delay_id_)) {
498 POWER_LOG(ERROR) << "Received unrequested " << signal_name << " signal";
499 return;
502 dbus::MessageReader reader(signal);
503 power_manager::SuspendImminent proto;
504 if (!reader.PopArrayOfBytesAsProto(&proto)) {
505 POWER_LOG(ERROR) << "Unable to decode protocol buffer from "
506 << signal_name << " signal";
507 return;
510 POWER_LOG(EVENT) << "Got " << signal_name
511 << " signal announcing suspend attempt "
512 << proto.suspend_id();
514 // If a previous suspend is pending from the same state we are currently in
515 // (fully powered on or in dark resume), then something's gone a little
516 // wonky.
517 if (suspend_is_pending_ && suspending_from_dark_resume_ == in_dark_resume) {
518 POWER_LOG(ERROR) << "Got " << signal_name
519 << " signal about pending suspend attempt "
520 << proto.suspend_id()
521 << " while still waiting on attempt "
522 << pending_suspend_id_;
525 pending_suspend_id_ = proto.suspend_id();
526 suspend_is_pending_ = true;
527 suspending_from_dark_resume_ = in_dark_resume;
528 num_pending_suspend_readiness_callbacks_ = 0;
529 if (suspending_from_dark_resume_)
530 FOR_EACH_OBSERVER(Observer, observers_, DarkSuspendImminent());
531 else
532 FOR_EACH_OBSERVER(Observer, observers_, SuspendImminent());
533 base::PowerMonitorDeviceSource::HandleSystemSuspending();
534 MaybeReportSuspendReadiness();
537 void SuspendDoneReceived(dbus::Signal* signal) {
538 dbus::MessageReader reader(signal);
539 power_manager::SuspendDone proto;
540 if (!reader.PopArrayOfBytesAsProto(&proto)) {
541 POWER_LOG(ERROR) << "Unable to decode protocol buffer from "
542 << power_manager::kSuspendDoneSignal << " signal";
543 return;
546 const base::TimeDelta duration =
547 base::TimeDelta::FromInternalValue(proto.suspend_duration());
548 POWER_LOG(EVENT) << "Got " << power_manager::kSuspendDoneSignal
549 << " signal:"
550 << " suspend_id=" << proto.suspend_id()
551 << " duration=" << duration.InSeconds() << " sec";
553 if (render_process_manager_delegate_)
554 render_process_manager_delegate_->SuspendDone();
556 FOR_EACH_OBSERVER(
557 PowerManagerClient::Observer, observers_, SuspendDone(duration));
558 base::PowerMonitorDeviceSource::HandleSystemResumed();
561 void IdleActionImminentReceived(dbus::Signal* signal) {
562 dbus::MessageReader reader(signal);
563 power_manager::IdleActionImminent proto;
564 if (!reader.PopArrayOfBytesAsProto(&proto)) {
565 POWER_LOG(ERROR) << "Unable to decode protocol buffer from "
566 << power_manager::kIdleActionImminentSignal << " signal";
567 return;
569 FOR_EACH_OBSERVER(Observer, observers_,
570 IdleActionImminent(base::TimeDelta::FromInternalValue(
571 proto.time_until_idle_action())));
574 void IdleActionDeferredReceived(dbus::Signal* signal) {
575 FOR_EACH_OBSERVER(Observer, observers_, IdleActionDeferred());
578 void InputEventReceived(dbus::Signal* signal) {
579 dbus::MessageReader reader(signal);
580 power_manager::InputEvent proto;
581 if (!reader.PopArrayOfBytesAsProto(&proto)) {
582 POWER_LOG(ERROR) << "Unable to decode protocol buffer from "
583 << power_manager::kInputEventSignal << " signal";
584 return;
587 base::TimeTicks timestamp =
588 base::TimeTicks::FromInternalValue(proto.timestamp());
589 POWER_LOG(USER) << "Got " << power_manager::kInputEventSignal << " signal:"
590 << " type=" << proto.type()
591 << " timestamp=" << proto.timestamp();
592 switch (proto.type()) {
593 case power_manager::InputEvent_Type_POWER_BUTTON_DOWN:
594 case power_manager::InputEvent_Type_POWER_BUTTON_UP: {
595 const bool down =
596 (proto.type() == power_manager::InputEvent_Type_POWER_BUTTON_DOWN);
597 FOR_EACH_OBSERVER(PowerManagerClient::Observer, observers_,
598 PowerButtonEventReceived(down, timestamp));
600 // Tell powerd that Chrome has handled power button presses.
601 if (down) {
602 dbus::MethodCall method_call(
603 power_manager::kPowerManagerInterface,
604 power_manager::kHandlePowerButtonAcknowledgmentMethod);
605 dbus::MessageWriter writer(&method_call);
606 writer.AppendInt64(proto.timestamp());
607 power_manager_proxy_->CallMethod(
608 &method_call,
609 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
610 dbus::ObjectProxy::EmptyResponseCallback());
612 break;
614 case power_manager::InputEvent_Type_LID_OPEN:
615 case power_manager::InputEvent_Type_LID_CLOSED: {
616 bool open =
617 (proto.type() == power_manager::InputEvent_Type_LID_OPEN);
618 FOR_EACH_OBSERVER(PowerManagerClient::Observer, observers_,
619 LidEventReceived(open, timestamp));
620 break;
625 void RegisterSuspendDelayImpl(
626 const std::string& method_name,
627 const power_manager::RegisterSuspendDelayRequest& protobuf_request,
628 dbus::ObjectProxy::ResponseCallback callback) {
629 dbus::MethodCall method_call(
630 power_manager::kPowerManagerInterface, method_name);
631 dbus::MessageWriter writer(&method_call);
633 if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) {
634 POWER_LOG(ERROR) << "Error constructing message for " << method_name;
635 return;
638 power_manager_proxy_->CallMethod(
639 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, callback);
642 // Registers suspend delays with the power manager. This is usually only
643 // called at startup, but if the power manager restarts, we need to create new
644 // delays.
645 void RegisterSuspendDelays() {
646 // Throw out any old delay that was registered.
647 suspend_delay_id_ = -1;
648 has_suspend_delay_id_ = false;
649 dark_suspend_delay_id_ = -1;
650 has_dark_suspend_delay_id_ = false;
652 power_manager::RegisterSuspendDelayRequest protobuf_request;
653 base::TimeDelta timeout =
654 base::TimeDelta::FromMilliseconds(kSuspendDelayTimeoutMs);
655 protobuf_request.set_timeout(timeout.ToInternalValue());
656 protobuf_request.set_description(kSuspendDelayDescription);
658 RegisterSuspendDelayImpl(
659 power_manager::kRegisterSuspendDelayMethod,
660 protobuf_request,
661 base::Bind(&PowerManagerClientImpl::HandleRegisterSuspendDelayReply,
662 weak_ptr_factory_.GetWeakPtr(), false,
663 power_manager::kRegisterSuspendDelayMethod));
664 RegisterSuspendDelayImpl(
665 power_manager::kRegisterDarkSuspendDelayMethod,
666 protobuf_request,
667 base::Bind(&PowerManagerClientImpl::HandleRegisterSuspendDelayReply,
668 weak_ptr_factory_.GetWeakPtr(), true,
669 power_manager::kRegisterDarkSuspendDelayMethod));
672 // Records the fact that an observer has finished doing asynchronous work
673 // that was blocking a pending suspend attempt and possibly reports
674 // suspend readiness to powerd. Called by callbacks returned via
675 // GetSuspendReadinessCallback().
676 void HandleObserverSuspendReadiness(int32_t suspend_id, bool in_dark_resume) {
677 DCHECK(OnOriginThread());
678 if (!suspend_is_pending_ || suspend_id != pending_suspend_id_ ||
679 in_dark_resume != suspending_from_dark_resume_)
680 return;
682 num_pending_suspend_readiness_callbacks_--;
683 MaybeReportSuspendReadiness();
686 // Reports suspend readiness to powerd if no observers are still holding
687 // suspend readiness callbacks.
688 void MaybeReportSuspendReadiness() {
689 if (!suspend_is_pending_ || num_pending_suspend_readiness_callbacks_ > 0)
690 return;
692 std::string method_name;
693 int32_t delay_id = -1;
694 if (suspending_from_dark_resume_) {
695 method_name = power_manager::kHandleDarkSuspendReadinessMethod;
696 delay_id = dark_suspend_delay_id_;
697 } else {
698 method_name = power_manager::kHandleSuspendReadinessMethod;
699 delay_id = suspend_delay_id_;
702 if (render_process_manager_delegate_ && !suspending_from_dark_resume_)
703 render_process_manager_delegate_->SuspendImminent();
705 dbus::MethodCall method_call(
706 power_manager::kPowerManagerInterface, method_name);
707 dbus::MessageWriter writer(&method_call);
709 POWER_LOG(EVENT) << "Announcing readiness of suspend delay " << delay_id
710 << " for suspend attempt " << pending_suspend_id_;
711 power_manager::SuspendReadinessInfo protobuf_request;
712 protobuf_request.set_delay_id(delay_id);
713 protobuf_request.set_suspend_id(pending_suspend_id_);
715 pending_suspend_id_ = -1;
716 suspend_is_pending_ = false;
718 if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) {
719 POWER_LOG(ERROR) << "Error constructing message for " << method_name;
720 return;
722 power_manager_proxy_->CallMethod(
723 &method_call,
724 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
725 dbus::ObjectProxy::EmptyResponseCallback());
728 // Origin thread (i.e. the UI thread in production).
729 base::PlatformThreadId origin_thread_id_;
731 dbus::ObjectProxy* power_manager_proxy_;
732 base::ObserverList<Observer> observers_;
734 // The delay_id_ obtained from the RegisterSuspendDelay request.
735 int32_t suspend_delay_id_;
736 bool has_suspend_delay_id_;
738 // The delay_id_ obtained from the RegisterDarkSuspendDelay request.
739 int32_t dark_suspend_delay_id_;
740 bool has_dark_suspend_delay_id_;
742 // powerd-supplied ID corresponding to an imminent suspend attempt that is
743 // currently being delayed.
744 int32_t pending_suspend_id_;
745 bool suspend_is_pending_;
747 // Set to true when the suspend currently being delayed was triggered during a
748 // dark resume. Since |pending_suspend_id_| and |suspend_is_pending_| are
749 // both shared by normal and dark suspends, |suspending_from_dark_resume_|
750 // helps distinguish the context within which these variables are being used.
751 bool suspending_from_dark_resume_;
753 // Number of callbacks that have been returned by
754 // GetSuspendReadinessCallback() during the currently-pending suspend
755 // attempt but have not yet been called.
756 int num_pending_suspend_readiness_callbacks_;
758 // Last state passed to SetIsProjecting().
759 bool last_is_projecting_;
761 // The delegate used to manage the power consumption of Chrome's renderer
762 // processes.
763 base::WeakPtr<RenderProcessManagerDelegate> render_process_manager_delegate_;
765 // Note: This should remain the last member so it'll be destroyed and
766 // invalidate its weak pointers before any other members are destroyed.
767 base::WeakPtrFactory<PowerManagerClientImpl> weak_ptr_factory_;
769 DISALLOW_COPY_AND_ASSIGN(PowerManagerClientImpl);
772 PowerManagerClient::PowerManagerClient() {
775 PowerManagerClient::~PowerManagerClient() {
778 // static
779 PowerManagerClient* PowerManagerClient::Create(
780 DBusClientImplementationType type) {
781 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
782 return new PowerManagerClientImpl();
783 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
784 return new FakePowerManagerClient();
787 } // namespace chromeos