Add an extension override bubble and warning box for proxy extensions.
[chromium-blink-merge.git] / chromeos / dbus / power_manager_client.cc
blob587e43f79992af6b6acaa62f82eb49448ce849d8
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/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"
29 #include "dbus/bus.h"
30 #include "dbus/message.h"
31 #include "dbus/object_path.h"
32 #include "dbus/object_proxy.h"
34 namespace chromeos {
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 {
45 public:
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,
59 // however:
60 // - The lifetime of the PowerManagerClientImpl can extend past that of
61 // the objectproxy,
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(
88 &method_call,
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);
115 writer.AppendInt32(
116 gradual ?
117 power_manager::kBrightnessTransitionGradual :
118 power_manager::kBrightnessTransitionInstant);
119 power_manager_proxy_->CallMethod(
120 &method_call,
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(
131 &method_call,
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(
142 &method_call,
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(
165 &method_call,
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(
178 &method_call,
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;
191 return;
193 power_manager_proxy_->CallMethod(
194 &method_call,
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(
206 &method_call,
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_;
224 protected:
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,
272 base::Bind(
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,
289 base::Bind(
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,
298 base::Bind(
299 &PowerManagerClientImpl::IdleActionDeferredReceived,
300 weak_ptr_factory_.GetWeakPtr()),
301 base::Bind(&PowerManagerClientImpl::SignalConnected,
302 weak_ptr_factory_.GetWeakPtr()));
304 RegisterSuspendDelay();
307 private:
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,
316 bool success) {
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,
324 method_name);
325 power_manager_proxy_->CallMethod(
326 &method_call,
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())
335 << ", new owner is "
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();
353 return;
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";
367 return;
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));
387 } else {
388 LOG(ERROR) << "Unable to decode "
389 << power_manager::kPowerSupplyPollSignal << "signal";
393 void OnGetPowerSupplyPropertiesMethod(dbus::Response* response) {
394 if (!response) {
395 LOG(ERROR) << "Error calling "
396 << power_manager::kGetPowerSupplyPropertiesMethod;
397 return;
400 dbus::MessageReader reader(response);
401 power_manager::PowerSupplyProperties protobuf;
402 if (reader.PopArrayOfBytesAsProto(&protobuf)) {
403 FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(protobuf));
404 } else {
405 LOG(ERROR) << "Unable to decode "
406 << power_manager::kGetPowerSupplyPropertiesMethod
407 << " response";
411 void OnGetScreenBrightnessPercent(
412 const GetScreenBrightnessPercentCallback& callback,
413 dbus::Response* response) {
414 if (!response) {
415 LOG(ERROR) << "Error calling "
416 << power_manager::kGetScreenBrightnessPercentMethod;
417 return;
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) {
428 if (!response) {
429 LOG(ERROR) << "Error calling "
430 << power_manager::kRegisterSuspendDelayMethod;
431 return;
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;
439 return;
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";
451 return;
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";
459 return;
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";
484 return;
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";
492 FOR_EACH_OBSERVER(
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";
502 return;
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";
519 return;
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: {
529 const bool down =
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.
535 if (down) {
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(
542 &method_call,
543 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
544 dbus::ObjectProxy::EmptyResponseCallback());
546 break;
548 case power_manager::InputEvent_Type_LID_OPEN:
549 case power_manager::InputEvent_Type_LID_CLOSED: {
550 bool open =
551 (proto.type() == power_manager::InputEvent_Type_LID_OPEN);
552 FOR_EACH_OBSERVER(PowerManagerClient::Observer, observers_,
553 LidEventReceived(open, timestamp));
554 break;
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;
581 return;
583 power_manager_proxy_->CallMethod(
584 &method_call,
585 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
586 base::Bind(
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_)
598 return;
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)
608 return;
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;
627 return;
629 power_manager_proxy_->CallMethod(
630 &method_call,
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 {
668 public:
669 PowerManagerClientStubImpl()
670 : discharging_(true),
671 battery_percentage_(40),
672 brightness_(50.0),
673 pause_count_(2),
674 cycle_count_(0),
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,
689 power_cycle_delay_,
690 this,
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_;
761 private:
762 void HandleSuspendReadiness() {
763 num_pending_suspend_readiness_callbacks_--;
766 void UpdateStatus() {
767 if (pause_count_ > 0) {
768 pause_count_--;
769 if (pause_count_ == 2)
770 discharging_ = !discharging_;
771 } else {
772 if (discharging_)
773 battery_percentage_ -= (battery_percentage_ <= 10 ? 1 : 10);
774 else
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) {
779 pause_count_ = 4;
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);
789 props_.Clear();
791 switch (cycle_count_) {
792 case 0:
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);
798 break;
799 case 1:
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);
804 break;
805 case 2:
806 // Say that the system is both charging and discharging on AC.
807 props_.set_external_power(
808 power_manager::PowerSupplyProperties_ExternalPower_AC);
809 break;
810 default:
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));
822 } else {
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))
844 return;
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") {
857 int seconds = 1;
858 if (!arg1.empty())
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
865 bool discharging_;
866 int battery_percentage_;
867 double brightness_;
868 int pause_count_;
869 int cycle_count_;
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
875 // invoked.
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() {
889 // static
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