Only fsync leveldb's directory when the manifest is being updated.
[chromium-blink-merge.git] / chromeos / dbus / power_manager_client.cc
blobf8c2220ed18ccc7ead6ec4f1e54ae8c2b073f4dd
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/format_macros.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/message_loop.h"
15 #include "base/observer_list.h"
16 #include "base/stringprintf.h"
17 #include "base/threading/platform_thread.h"
18 #include "base/time.h"
19 #include "base/timer.h"
20 #include "chromeos/dbus/power_manager/input_event.pb.h"
21 #include "chromeos/dbus/power_manager/peripheral_battery_status.pb.h"
22 #include "chromeos/dbus/power_manager/policy.pb.h"
23 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
24 #include "chromeos/dbus/power_manager/suspend.pb.h"
25 #include "chromeos/dbus/video_activity_update.pb.h"
26 #include "dbus/bus.h"
27 #include "dbus/message.h"
28 #include "dbus/object_path.h"
29 #include "dbus/object_proxy.h"
30 #include "third_party/cros_system_api/dbus/service_constants.h"
32 namespace chromeos {
34 // Maximum amount of time that the power manager will wait for Chrome to
35 // say that it's ready for the system to be suspended, in milliseconds.
36 const int kSuspendDelayTimeoutMs = 5000;
38 // Human-readable description of Chrome's suspend delay.
39 const char kSuspendDelayDescription[] = "chrome";
41 // The PowerManagerClient implementation used in production.
42 class PowerManagerClientImpl : public PowerManagerClient {
43 public:
44 explicit PowerManagerClientImpl(dbus::Bus* bus)
45 : origin_thread_id_(base::PlatformThread::CurrentId()),
46 power_manager_proxy_(NULL),
47 suspend_delay_id_(-1),
48 has_suspend_delay_id_(false),
49 pending_suspend_id_(-1),
50 suspend_is_pending_(false),
51 num_pending_suspend_readiness_callbacks_(0),
52 last_is_projecting_(false),
53 weak_ptr_factory_(this) {
54 power_manager_proxy_ = bus->GetObjectProxy(
55 power_manager::kPowerManagerServiceName,
56 dbus::ObjectPath(power_manager::kPowerManagerServicePath));
58 power_manager_proxy_->SetNameOwnerChangedCallback(
59 base::Bind(&PowerManagerClientImpl::NameOwnerChangedReceived,
60 weak_ptr_factory_.GetWeakPtr()));
62 // Monitor the D-Bus signal for brightness changes. Only the power
63 // manager knows the actual brightness level. We don't cache the
64 // brightness level in Chrome as it'll make things less reliable.
65 power_manager_proxy_->ConnectToSignal(
66 power_manager::kPowerManagerInterface,
67 power_manager::kBrightnessChangedSignal,
68 base::Bind(&PowerManagerClientImpl::BrightnessChangedReceived,
69 weak_ptr_factory_.GetWeakPtr()),
70 base::Bind(&PowerManagerClientImpl::SignalConnected,
71 weak_ptr_factory_.GetWeakPtr()));
73 power_manager_proxy_->ConnectToSignal(
74 power_manager::kPowerManagerInterface,
75 power_manager::kPeripheralBatteryStatusSignal,
76 base::Bind(&PowerManagerClientImpl::PeripheralBatteryStatusReceived,
77 weak_ptr_factory_.GetWeakPtr()),
78 base::Bind(&PowerManagerClientImpl::SignalConnected,
79 weak_ptr_factory_.GetWeakPtr()));
81 power_manager_proxy_->ConnectToSignal(
82 power_manager::kPowerManagerInterface,
83 power_manager::kPowerSupplyPollSignal,
84 base::Bind(&PowerManagerClientImpl::PowerSupplyPollReceived,
85 weak_ptr_factory_.GetWeakPtr()),
86 base::Bind(&PowerManagerClientImpl::SignalConnected,
87 weak_ptr_factory_.GetWeakPtr()));
89 power_manager_proxy_->ConnectToSignal(
90 power_manager::kPowerManagerInterface,
91 power_manager::kIdleNotifySignal,
92 base::Bind(&PowerManagerClientImpl::IdleNotifySignalReceived,
93 weak_ptr_factory_.GetWeakPtr()),
94 base::Bind(&PowerManagerClientImpl::SignalConnected,
95 weak_ptr_factory_.GetWeakPtr()));
97 power_manager_proxy_->ConnectToSignal(
98 power_manager::kPowerManagerInterface,
99 power_manager::kInputEventSignal,
100 base::Bind(&PowerManagerClientImpl::InputEventReceived,
101 weak_ptr_factory_.GetWeakPtr()),
102 base::Bind(&PowerManagerClientImpl::SignalConnected,
103 weak_ptr_factory_.GetWeakPtr()));
105 power_manager_proxy_->ConnectToSignal(
106 power_manager::kPowerManagerInterface,
107 power_manager::kSuspendStateChangedSignal,
108 base::Bind(&PowerManagerClientImpl::SuspendStateChangedReceived,
109 weak_ptr_factory_.GetWeakPtr()),
110 base::Bind(&PowerManagerClientImpl::SignalConnected,
111 weak_ptr_factory_.GetWeakPtr()));
113 power_manager_proxy_->ConnectToSignal(
114 power_manager::kPowerManagerInterface,
115 power_manager::kSuspendImminentSignal,
116 base::Bind(
117 &PowerManagerClientImpl::SuspendImminentReceived,
118 weak_ptr_factory_.GetWeakPtr()),
119 base::Bind(&PowerManagerClientImpl::SignalConnected,
120 weak_ptr_factory_.GetWeakPtr()));
122 power_manager_proxy_->ConnectToSignal(
123 power_manager::kPowerManagerInterface,
124 power_manager::kIdleActionImminentSignal,
125 base::Bind(
126 &PowerManagerClientImpl::IdleActionImminentReceived,
127 weak_ptr_factory_.GetWeakPtr()),
128 base::Bind(&PowerManagerClientImpl::SignalConnected,
129 weak_ptr_factory_.GetWeakPtr()));
131 power_manager_proxy_->ConnectToSignal(
132 power_manager::kPowerManagerInterface,
133 power_manager::kIdleActionDeferredSignal,
134 base::Bind(
135 &PowerManagerClientImpl::IdleActionDeferredReceived,
136 weak_ptr_factory_.GetWeakPtr()),
137 base::Bind(&PowerManagerClientImpl::SignalConnected,
138 weak_ptr_factory_.GetWeakPtr()));
140 RegisterSuspendDelay();
143 virtual ~PowerManagerClientImpl() {
144 // Here we should unregister suspend notifications from powerd,
145 // however:
146 // - The lifetime of the PowerManagerClientImpl can extend past that of
147 // the objectproxy,
148 // - power_manager can already detect that the client is gone and
149 // unregister our suspend delay.
152 // PowerManagerClient overrides:
154 virtual void AddObserver(Observer* observer) OVERRIDE {
155 CHECK(observer); // http://crbug.com/119976
156 observers_.AddObserver(observer);
159 virtual void RemoveObserver(Observer* observer) OVERRIDE {
160 observers_.RemoveObserver(observer);
163 virtual bool HasObserver(Observer* observer) OVERRIDE {
164 return observers_.HasObserver(observer);
167 virtual void DecreaseScreenBrightness(bool allow_off) OVERRIDE {
168 dbus::MethodCall method_call(
169 power_manager::kPowerManagerInterface,
170 power_manager::kDecreaseScreenBrightness);
171 dbus::MessageWriter writer(&method_call);
172 writer.AppendBool(allow_off);
173 power_manager_proxy_->CallMethod(
174 &method_call,
175 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
176 dbus::ObjectProxy::EmptyResponseCallback());
179 virtual void IncreaseScreenBrightness() OVERRIDE {
180 SimpleMethodCallToPowerManager(power_manager::kIncreaseScreenBrightness);
183 virtual void DecreaseKeyboardBrightness() OVERRIDE {
184 SimpleMethodCallToPowerManager(power_manager::kDecreaseKeyboardBrightness);
187 virtual void IncreaseKeyboardBrightness() OVERRIDE {
188 SimpleMethodCallToPowerManager(power_manager::kIncreaseKeyboardBrightness);
191 virtual void SetScreenBrightnessPercent(double percent,
192 bool gradual) OVERRIDE {
193 dbus::MethodCall method_call(
194 power_manager::kPowerManagerInterface,
195 power_manager::kSetScreenBrightnessPercent);
196 dbus::MessageWriter writer(&method_call);
197 writer.AppendDouble(percent);
198 writer.AppendInt32(
199 gradual ?
200 power_manager::kBrightnessTransitionGradual :
201 power_manager::kBrightnessTransitionInstant);
202 power_manager_proxy_->CallMethod(
203 &method_call,
204 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
205 dbus::ObjectProxy::EmptyResponseCallback());
208 virtual void GetScreenBrightnessPercent(
209 const GetScreenBrightnessPercentCallback& callback) OVERRIDE {
210 dbus::MethodCall method_call(power_manager::kPowerManagerInterface,
211 power_manager::kGetScreenBrightnessPercent);
212 power_manager_proxy_->CallMethod(
213 &method_call,
214 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
215 base::Bind(&PowerManagerClientImpl::OnGetScreenBrightnessPercent,
216 weak_ptr_factory_.GetWeakPtr(), callback));
219 virtual void RequestStatusUpdate(UpdateRequestType update_type) OVERRIDE {
220 dbus::MethodCall method_call(
221 power_manager::kPowerManagerInterface,
222 power_manager::kGetPowerSupplyPropertiesMethod);
223 power_manager_proxy_->CallMethod(
224 &method_call,
225 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
226 base::Bind(&PowerManagerClientImpl::OnGetPowerSupplyPropertiesMethod,
227 weak_ptr_factory_.GetWeakPtr()));
230 virtual void RequestRestart() OVERRIDE {
231 SimpleMethodCallToPowerManager(power_manager::kRequestRestartMethod);
234 virtual void RequestShutdown() OVERRIDE {
235 SimpleMethodCallToPowerManager(power_manager::kRequestShutdownMethod);
238 virtual void RequestIdleNotification(int64 threshold) OVERRIDE {
239 dbus::MethodCall method_call(power_manager::kPowerManagerInterface,
240 power_manager::kRequestIdleNotification);
241 dbus::MessageWriter writer(&method_call);
242 writer.AppendInt64(threshold);
244 power_manager_proxy_->CallMethod(
245 &method_call,
246 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
247 dbus::ObjectProxy::EmptyResponseCallback());
250 virtual void NotifyUserActivity() OVERRIDE {
251 SimpleMethodCallToPowerManager(power_manager::kHandleUserActivityMethod);
254 virtual void NotifyVideoActivity(
255 const base::TimeTicks& last_activity_time,
256 bool is_fullscreen) OVERRIDE {
257 dbus::MethodCall method_call(
258 power_manager::kPowerManagerInterface,
259 power_manager::kHandleVideoActivityMethod);
260 dbus::MessageWriter writer(&method_call);
262 VideoActivityUpdate protobuf;
263 protobuf.set_last_activity_time(last_activity_time.ToInternalValue());
264 protobuf.set_is_fullscreen(is_fullscreen);
266 if (!writer.AppendProtoAsArrayOfBytes(protobuf)) {
267 LOG(ERROR) << "Error calling "
268 << power_manager::kHandleVideoActivityMethod;
269 return;
271 power_manager_proxy_->CallMethod(
272 &method_call,
273 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
274 dbus::ObjectProxy::EmptyResponseCallback());
277 virtual void SetPolicy(
278 const power_manager::PowerManagementPolicy& policy) OVERRIDE {
279 dbus::MethodCall method_call(
280 power_manager::kPowerManagerInterface,
281 power_manager::kSetPolicyMethod);
282 dbus::MessageWriter writer(&method_call);
283 if (!writer.AppendProtoAsArrayOfBytes(policy)) {
284 LOG(ERROR) << "Error calling " << power_manager::kSetPolicyMethod;
285 return;
287 power_manager_proxy_->CallMethod(
288 &method_call,
289 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
290 dbus::ObjectProxy::EmptyResponseCallback());
293 virtual void SetIsProjecting(bool is_projecting) OVERRIDE {
294 dbus::MethodCall method_call(
295 power_manager::kPowerManagerInterface,
296 power_manager::kSetIsProjectingMethod);
297 dbus::MessageWriter writer(&method_call);
298 writer.AppendBool(is_projecting);
299 power_manager_proxy_->CallMethod(
300 &method_call,
301 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
302 dbus::ObjectProxy::EmptyResponseCallback());
303 last_is_projecting_ = is_projecting;
306 virtual base::Closure GetSuspendReadinessCallback() OVERRIDE {
307 DCHECK(OnOriginThread());
308 DCHECK(suspend_is_pending_);
309 num_pending_suspend_readiness_callbacks_++;
310 return base::Bind(&PowerManagerClientImpl::HandleObserverSuspendReadiness,
311 weak_ptr_factory_.GetWeakPtr(), pending_suspend_id_);
314 private:
315 // Returns true if the current thread is the origin thread.
316 bool OnOriginThread() {
317 return base::PlatformThread::CurrentId() == origin_thread_id_;
320 // Called when a dbus signal is initially connected.
321 void SignalConnected(const std::string& interface_name,
322 const std::string& signal_name,
323 bool success) {
324 LOG_IF(WARNING, !success) << "Failed to connect to signal "
325 << signal_name << ".";
328 // Make a method call to power manager with no arguments and no response.
329 void SimpleMethodCallToPowerManager(const std::string& method_name) {
330 dbus::MethodCall method_call(power_manager::kPowerManagerInterface,
331 method_name);
332 power_manager_proxy_->CallMethod(
333 &method_call,
334 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
335 dbus::ObjectProxy::EmptyResponseCallback());
338 void NameOwnerChangedReceived(dbus::Signal* signal) {
339 VLOG(1) << "Power manager restarted";
340 RegisterSuspendDelay();
341 SetIsProjecting(last_is_projecting_);
342 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* unused_signal) {
382 VLOG(1) << "Received power supply poll signal.";
383 RequestStatusUpdate(UPDATE_POLL);
386 void OnGetPowerSupplyPropertiesMethod(dbus::Response* response) {
387 if (!response) {
388 LOG(ERROR) << "Error calling "
389 << power_manager::kGetPowerSupplyPropertiesMethod;
390 return;
393 dbus::MessageReader reader(response);
394 power_manager::PowerSupplyProperties protobuf;
395 if (!reader.PopArrayOfBytesAsProto(&protobuf)) {
396 LOG(ERROR) << "Error calling "
397 << power_manager::kGetPowerSupplyPropertiesMethod
398 << response->ToString();
399 return;
402 // TODO(derat): Update PowerSupplyStatus to keep the ExternalPower and
403 // BatteryState information from PowerSupplyProperties intact.
404 PowerSupplyStatus status;
405 status.line_power_on = protobuf.external_power() !=
406 power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED;
407 status.battery_is_present = protobuf.battery_state() !=
408 power_manager::PowerSupplyProperties_BatteryState_NOT_PRESENT;
409 status.battery_is_full = protobuf.battery_state() ==
410 power_manager::PowerSupplyProperties_BatteryState_FULL;
411 status.battery_seconds_to_empty = protobuf.battery_time_to_empty_sec();
412 status.battery_seconds_to_full = protobuf.battery_time_to_full_sec();
413 status.battery_percentage = protobuf.battery_percent();
414 status.is_calculating_battery_time = protobuf.is_calculating_battery_time();
416 switch (protobuf.external_power()) {
417 case power_manager::PowerSupplyProperties_ExternalPower_AC:
418 status.battery_state = PowerSupplyStatus::CHARGING;
419 break;
420 case power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED:
421 status.battery_state = PowerSupplyStatus::DISCHARGING;
422 break;
423 case power_manager::PowerSupplyProperties_ExternalPower_USB:
424 status.battery_state = PowerSupplyStatus::CONNECTED_TO_USB;
425 break;
426 default:
427 NOTREACHED() << "Unhandled external power state "
428 << protobuf.external_power();
431 // Check power status values are consistent
432 if (!status.is_calculating_battery_time) {
433 int64 battery_seconds_to_goal = status.line_power_on ?
434 status.battery_seconds_to_full : status.battery_seconds_to_empty;
435 if (battery_seconds_to_goal < 0) {
436 LOG(ERROR) << "Received power supply status with negative seconds to "
437 << (status.line_power_on ? "full" : "empty")
438 << ". Assume time is still being calculated.";
439 status.is_calculating_battery_time = true;
443 VLOG(1) << "Power status: " << status.ToString();
444 FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(status));
447 void OnGetScreenBrightnessPercent(
448 const GetScreenBrightnessPercentCallback& callback,
449 dbus::Response* response) {
450 if (!response) {
451 LOG(ERROR) << "Error calling "
452 << power_manager::kGetScreenBrightnessPercent;
453 return;
455 dbus::MessageReader reader(response);
456 double percent = 0.0;
457 if (!reader.PopDouble(&percent))
458 LOG(ERROR) << "Error reading response from powerd: "
459 << response->ToString();
460 callback.Run(percent);
463 void OnRegisterSuspendDelayReply(dbus::Response* response) {
464 if (!response) {
465 LOG(ERROR) << "Error calling "
466 << power_manager::kRegisterSuspendDelayMethod;
467 return;
470 dbus::MessageReader reader(response);
471 power_manager::RegisterSuspendDelayReply protobuf;
472 if (!reader.PopArrayOfBytesAsProto(&protobuf)) {
473 LOG(ERROR) << "Unable to parse reply from "
474 << power_manager::kRegisterSuspendDelayMethod;
475 return;
478 suspend_delay_id_ = protobuf.delay_id();
479 has_suspend_delay_id_ = true;
480 VLOG(1) << "Registered suspend delay " << suspend_delay_id_;
483 void IdleNotifySignalReceived(dbus::Signal* signal) {
484 dbus::MessageReader reader(signal);
485 int64 threshold = 0;
486 if (!reader.PopInt64(&threshold)) {
487 LOG(ERROR) << "Idle Notify signal had incorrect parameters: "
488 << signal->ToString();
489 return;
491 DCHECK_GT(threshold, 0);
493 VLOG(1) << "Idle Notify: " << threshold;
494 FOR_EACH_OBSERVER(Observer, observers_, IdleNotify(threshold));
497 void SuspendImminentReceived(dbus::Signal* signal) {
498 if (!has_suspend_delay_id_) {
499 LOG(ERROR) << "Received unrequested "
500 << power_manager::kSuspendImminentSignal << " signal";
501 return;
504 dbus::MessageReader reader(signal);
505 power_manager::SuspendImminent protobuf_imminent;
506 if (!reader.PopArrayOfBytesAsProto(&protobuf_imminent)) {
507 LOG(ERROR) << "Unable to decode protocol buffer from "
508 << power_manager::kSuspendImminentSignal << " signal";
509 return;
512 if (suspend_is_pending_) {
513 LOG(WARNING) << "Got " << power_manager::kSuspendImminentSignal
514 << " signal about pending suspend attempt "
515 << protobuf_imminent.suspend_id() << " while still waiting "
516 << "on attempt " << pending_suspend_id_;
519 pending_suspend_id_ = protobuf_imminent.suspend_id();
520 suspend_is_pending_ = true;
521 num_pending_suspend_readiness_callbacks_ = 0;
522 FOR_EACH_OBSERVER(Observer, observers_, SuspendImminent());
523 MaybeReportSuspendReadiness();
526 void IdleActionImminentReceived(dbus::Signal* signal) {
527 FOR_EACH_OBSERVER(Observer, observers_, IdleActionImminent());
530 void IdleActionDeferredReceived(dbus::Signal* signal) {
531 FOR_EACH_OBSERVER(Observer, observers_, IdleActionDeferred());
534 void InputEventReceived(dbus::Signal* signal) {
535 dbus::MessageReader reader(signal);
536 power_manager::InputEvent proto;
537 if (!reader.PopArrayOfBytesAsProto(&proto)) {
538 LOG(ERROR) << "Unable to decode protocol buffer from "
539 << power_manager::kInputEventSignal << " signal";
540 return;
543 base::TimeTicks timestamp =
544 base::TimeTicks::FromInternalValue(proto.timestamp());
545 VLOG(1) << "Got " << power_manager::kInputEventSignal << " signal:"
546 << " type=" << proto.type() << " timestamp=" << proto.timestamp();
547 switch (proto.type()) {
548 case power_manager::InputEvent_Type_POWER_BUTTON_DOWN:
549 case power_manager::InputEvent_Type_POWER_BUTTON_UP: {
550 bool down =
551 (proto.type() == power_manager::InputEvent_Type_POWER_BUTTON_DOWN);
552 FOR_EACH_OBSERVER(PowerManagerClient::Observer, observers_,
553 PowerButtonEventReceived(down, timestamp));
554 break;
556 case power_manager::InputEvent_Type_LID_OPEN:
557 case power_manager::InputEvent_Type_LID_CLOSED: {
558 bool open =
559 (proto.type() == power_manager::InputEvent_Type_LID_OPEN);
560 FOR_EACH_OBSERVER(PowerManagerClient::Observer, observers_,
561 LidEventReceived(open, timestamp));
562 break;
567 void SuspendStateChangedReceived(dbus::Signal* signal) {
568 dbus::MessageReader reader(signal);
569 power_manager::SuspendState proto;
570 if (!reader.PopArrayOfBytesAsProto(&proto)) {
571 LOG(ERROR) << "Unable to decode protocol buffer from "
572 << power_manager::kSuspendStateChangedSignal << " signal";
573 return;
576 VLOG(1) << "Got " << power_manager::kSuspendStateChangedSignal << " signal:"
577 << " type=" << proto.type() << " wall_time=" << proto.wall_time();
578 base::Time wall_time =
579 base::Time::FromInternalValue(proto.wall_time());
580 switch (proto.type()) {
581 case power_manager::SuspendState_Type_SUSPEND_TO_MEMORY:
582 last_suspend_wall_time_ = wall_time;
583 break;
584 case power_manager::SuspendState_Type_RESUME:
585 FOR_EACH_OBSERVER(
586 PowerManagerClient::Observer, observers_,
587 SystemResumed(wall_time - last_suspend_wall_time_));
588 break;
592 // Registers a suspend delay with the power manager. This is usually
593 // only called at startup, but if the power manager restarts, we need to
594 // create a new delay.
595 void RegisterSuspendDelay() {
596 // Throw out any old delay that was registered.
597 suspend_delay_id_ = -1;
598 has_suspend_delay_id_ = false;
600 dbus::MethodCall method_call(
601 power_manager::kPowerManagerInterface,
602 power_manager::kRegisterSuspendDelayMethod);
603 dbus::MessageWriter writer(&method_call);
605 power_manager::RegisterSuspendDelayRequest protobuf_request;
606 base::TimeDelta timeout =
607 base::TimeDelta::FromMilliseconds(kSuspendDelayTimeoutMs);
608 protobuf_request.set_timeout(timeout.ToInternalValue());
609 protobuf_request.set_description(kSuspendDelayDescription);
611 if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) {
612 LOG(ERROR) << "Error constructing message for "
613 << power_manager::kRegisterSuspendDelayMethod;
614 return;
616 power_manager_proxy_->CallMethod(
617 &method_call,
618 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
619 base::Bind(
620 &PowerManagerClientImpl::OnRegisterSuspendDelayReply,
621 weak_ptr_factory_.GetWeakPtr()));
624 // Records the fact that an observer has finished doing asynchronous work
625 // that was blocking a pending suspend attempt and possibly reports
626 // suspend readiness to powerd. Called by callbacks returned via
627 // GetSuspendReadinessCallback().
628 void HandleObserverSuspendReadiness(int32 suspend_id) {
629 DCHECK(OnOriginThread());
630 if (!suspend_is_pending_ || suspend_id != pending_suspend_id_)
631 return;
633 num_pending_suspend_readiness_callbacks_--;
634 MaybeReportSuspendReadiness();
637 // Reports suspend readiness to powerd if no observers are still holding
638 // suspend readiness callbacks.
639 void MaybeReportSuspendReadiness() {
640 if (!suspend_is_pending_ || num_pending_suspend_readiness_callbacks_ > 0)
641 return;
643 dbus::MethodCall method_call(
644 power_manager::kPowerManagerInterface,
645 power_manager::kHandleSuspendReadinessMethod);
646 dbus::MessageWriter writer(&method_call);
648 power_manager::SuspendReadinessInfo protobuf_request;
649 protobuf_request.set_delay_id(suspend_delay_id_);
650 protobuf_request.set_suspend_id(pending_suspend_id_);
652 pending_suspend_id_ = -1;
653 suspend_is_pending_ = false;
655 if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) {
656 LOG(ERROR) << "Error constructing message for "
657 << power_manager::kHandleSuspendReadinessMethod;
658 return;
660 power_manager_proxy_->CallMethod(
661 &method_call,
662 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
663 dbus::ObjectProxy::EmptyResponseCallback());
666 // Origin thread (i.e. the UI thread in production).
667 base::PlatformThreadId origin_thread_id_;
669 dbus::ObjectProxy* power_manager_proxy_;
670 ObserverList<Observer> observers_;
672 // The delay_id_ obtained from the RegisterSuspendDelay request.
673 int32 suspend_delay_id_;
674 bool has_suspend_delay_id_;
676 // powerd-supplied ID corresponding to an imminent suspend attempt that is
677 // currently being delayed.
678 int32 pending_suspend_id_;
679 bool suspend_is_pending_;
681 // Number of callbacks that have been returned by
682 // GetSuspendReadinessCallback() during the currently-pending suspend
683 // attempt but have not yet been called.
684 int num_pending_suspend_readiness_callbacks_;
686 // Wall time from the latest signal telling us that the system was about to
687 // suspend to memory.
688 base::Time last_suspend_wall_time_;
690 // Last state passed to SetIsProjecting().
691 bool last_is_projecting_;
693 // Note: This should remain the last member so it'll be destroyed and
694 // invalidate its weak pointers before any other members are destroyed.
695 base::WeakPtrFactory<PowerManagerClientImpl> weak_ptr_factory_;
697 DISALLOW_COPY_AND_ASSIGN(PowerManagerClientImpl);
700 // The PowerManagerClient implementation used on Linux desktop,
701 // which does nothing.
702 class PowerManagerClientStubImpl : public PowerManagerClient {
703 public:
704 PowerManagerClientStubImpl()
705 : discharging_(true),
706 battery_percentage_(40),
707 brightness_(50.0),
708 pause_count_(2),
709 cycle_count_(0) {
712 virtual ~PowerManagerClientStubImpl() {}
714 // PowerManagerClient overrides:
716 virtual void AddObserver(Observer* observer) OVERRIDE {
717 observers_.AddObserver(observer);
720 virtual void RemoveObserver(Observer* observer) OVERRIDE {
721 observers_.RemoveObserver(observer);
724 virtual bool HasObserver(Observer* observer) OVERRIDE {
725 return observers_.HasObserver(observer);
728 virtual void DecreaseScreenBrightness(bool allow_off) OVERRIDE {
729 VLOG(1) << "Requested to descrease screen brightness";
730 SetBrightness(brightness_ - 5.0, true);
733 virtual void IncreaseScreenBrightness() OVERRIDE {
734 VLOG(1) << "Requested to increase screen brightness";
735 SetBrightness(brightness_ + 5.0, true);
738 virtual void SetScreenBrightnessPercent(double percent,
739 bool gradual) OVERRIDE {
740 VLOG(1) << "Requested to set screen brightness to " << percent << "% "
741 << (gradual ? "gradually" : "instantaneously");
742 SetBrightness(percent, false);
745 virtual void GetScreenBrightnessPercent(
746 const GetScreenBrightnessPercentCallback& callback) OVERRIDE {
747 callback.Run(brightness_);
750 virtual void DecreaseKeyboardBrightness() OVERRIDE {
751 VLOG(1) << "Requested to descrease keyboard brightness";
754 virtual void IncreaseKeyboardBrightness() OVERRIDE {
755 VLOG(1) << "Requested to increase keyboard brightness";
758 virtual void RequestStatusUpdate(UpdateRequestType update_type) OVERRIDE {
759 if (update_type == UPDATE_INITIAL) {
760 Update();
761 return;
763 if (!timer_.IsRunning() && update_type == UPDATE_USER) {
764 Update();
765 timer_.Start(
766 FROM_HERE,
767 base::TimeDelta::FromMilliseconds(1000),
768 this,
769 &PowerManagerClientStubImpl::Update);
770 } else {
771 timer_.Stop();
775 virtual void RequestRestart() OVERRIDE {}
776 virtual void RequestShutdown() OVERRIDE {}
778 virtual void RequestIdleNotification(int64 threshold) OVERRIDE {
779 base::MessageLoop::current()->PostDelayedTask(
780 FROM_HERE,
781 base::Bind(&PowerManagerClientStubImpl::TriggerIdleNotify,
782 base::Unretained(this),
783 threshold),
784 base::TimeDelta::FromMilliseconds(threshold));
787 virtual void NotifyUserActivity() OVERRIDE {}
788 virtual void NotifyVideoActivity(
789 const base::TimeTicks& last_activity_time,
790 bool is_fullscreen) OVERRIDE {}
791 virtual void SetPolicy(
792 const power_manager::PowerManagementPolicy& policy) OVERRIDE {}
793 virtual void SetIsProjecting(bool is_projecting) OVERRIDE {}
794 virtual base::Closure GetSuspendReadinessCallback() OVERRIDE {
795 return base::Closure();
798 private:
799 void Update() {
800 if (pause_count_ > 0) {
801 pause_count_--;
802 } else {
803 int discharge_amt = battery_percentage_ <= 10 ? 1 : 10;
804 battery_percentage_ += (discharging_ ? -discharge_amt : discharge_amt);
805 battery_percentage_ = std::min(std::max(battery_percentage_, 0), 100);
806 // We pause at 0 and 100% so that it's easier to check those conditions.
807 if (battery_percentage_ == 0 || battery_percentage_ == 100) {
808 discharging_ = !discharging_;
809 pause_count_ = 4;
810 if (battery_percentage_ == 100)
811 cycle_count_ = (cycle_count_ + 1) % 3;
814 const int kSecondsToEmptyFullBattery(3 * 60 * 60); // 3 hours.
816 status_.is_calculating_battery_time = (pause_count_ > 1);
817 status_.line_power_on = !discharging_;
818 status_.battery_is_present = true;
819 status_.battery_percentage = battery_percentage_;
820 if (cycle_count_ != 2) {
821 status_.battery_state = discharging_ ?
822 PowerSupplyStatus::DISCHARGING : PowerSupplyStatus::CHARGING;
823 } else {
824 // Simulating a non-standard weak power supply.
825 status_.battery_state =
826 PowerSupplyStatus::NEITHER_CHARGING_NOR_DISCHARGING;
829 int64 remaining_battery_time =
830 std::max(1, battery_percentage_ * kSecondsToEmptyFullBattery / 100);
831 status_.battery_seconds_to_empty =
832 status_.battery_state == PowerSupplyStatus::DISCHARGING ?
833 remaining_battery_time : 0;
834 status_.battery_seconds_to_full =
835 status_.battery_state == PowerSupplyStatus::DISCHARGING ?
836 0 : std::max(static_cast<int64>(1),
837 kSecondsToEmptyFullBattery - remaining_battery_time);
838 FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(status_));
841 void SetBrightness(double percent, bool user_initiated) {
842 brightness_ = std::min(std::max(0.0, percent), 100.0);
843 int brightness_level = static_cast<int>(brightness_);
844 FOR_EACH_OBSERVER(Observer, observers_,
845 BrightnessChanged(brightness_level, user_initiated));
848 void TriggerIdleNotify(int64 threshold) {
849 FOR_EACH_OBSERVER(Observer, observers_, IdleNotify(threshold));
852 bool discharging_;
853 int battery_percentage_;
854 double brightness_;
855 int pause_count_;
856 int cycle_count_;
857 ObserverList<Observer> observers_;
858 base::RepeatingTimer<PowerManagerClientStubImpl> timer_;
859 PowerSupplyStatus status_;
862 PowerManagerClient::PowerManagerClient() {
865 PowerManagerClient::~PowerManagerClient() {
868 // static
869 PowerManagerClient* PowerManagerClient::Create(
870 DBusClientImplementationType type,
871 dbus::Bus* bus) {
872 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
873 return new PowerManagerClientImpl(bus);
874 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
875 return new PowerManagerClientStubImpl();
878 } // namespace chromeos