power_manager_client.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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.
4
5#include "chromeos/dbus/power_manager_client.h"
6
7#include <algorithm>
8
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/strings/stringprintf.h"
17#include "base/threading/platform_thread.h"
18#include "base/time/time.h"
19#include "base/timer/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 "dbus/bus.h"
26#include "dbus/message.h"
27#include "dbus/object_path.h"
28#include "dbus/object_proxy.h"
29#include "third_party/cros_system_api/dbus/service_constants.h"
30
31namespace chromeos {
32
33// Maximum amount of time that the power manager will wait for Chrome to
34// say that it's ready for the system to be suspended, in milliseconds.
35const int kSuspendDelayTimeoutMs = 5000;
36
37// Human-readable description of Chrome's suspend delay.
38const char kSuspendDelayDescription[] = "chrome";
39
40// The PowerManagerClient implementation used in production.
41class PowerManagerClientImpl : public PowerManagerClient {
42 public:
43  explicit PowerManagerClientImpl(dbus::Bus* bus)
44      : origin_thread_id_(base::PlatformThread::CurrentId()),
45        power_manager_proxy_(NULL),
46        suspend_delay_id_(-1),
47        has_suspend_delay_id_(false),
48        pending_suspend_id_(-1),
49        suspend_is_pending_(false),
50        num_pending_suspend_readiness_callbacks_(0),
51        last_is_projecting_(false),
52        weak_ptr_factory_(this) {
53    power_manager_proxy_ = bus->GetObjectProxy(
54        power_manager::kPowerManagerServiceName,
55        dbus::ObjectPath(power_manager::kPowerManagerServicePath));
56
57    power_manager_proxy_->SetNameOwnerChangedCallback(
58        base::Bind(&PowerManagerClientImpl::NameOwnerChangedReceived,
59                   weak_ptr_factory_.GetWeakPtr()));
60
61    // Monitor the D-Bus signal for brightness changes. Only the power
62    // manager knows the actual brightness level. We don't cache the
63    // brightness level in Chrome as it'll make things less reliable.
64    power_manager_proxy_->ConnectToSignal(
65        power_manager::kPowerManagerInterface,
66        power_manager::kBrightnessChangedSignal,
67        base::Bind(&PowerManagerClientImpl::BrightnessChangedReceived,
68                   weak_ptr_factory_.GetWeakPtr()),
69        base::Bind(&PowerManagerClientImpl::SignalConnected,
70                   weak_ptr_factory_.GetWeakPtr()));
71
72    power_manager_proxy_->ConnectToSignal(
73        power_manager::kPowerManagerInterface,
74        power_manager::kPeripheralBatteryStatusSignal,
75        base::Bind(&PowerManagerClientImpl::PeripheralBatteryStatusReceived,
76                   weak_ptr_factory_.GetWeakPtr()),
77        base::Bind(&PowerManagerClientImpl::SignalConnected,
78                   weak_ptr_factory_.GetWeakPtr()));
79
80    power_manager_proxy_->ConnectToSignal(
81        power_manager::kPowerManagerInterface,
82        power_manager::kPowerSupplyPollSignal,
83        base::Bind(&PowerManagerClientImpl::PowerSupplyPollReceived,
84                   weak_ptr_factory_.GetWeakPtr()),
85        base::Bind(&PowerManagerClientImpl::SignalConnected,
86                   weak_ptr_factory_.GetWeakPtr()));
87
88    power_manager_proxy_->ConnectToSignal(
89        power_manager::kPowerManagerInterface,
90        power_manager::kIdleNotifySignal,
91        base::Bind(&PowerManagerClientImpl::IdleNotifySignalReceived,
92                   weak_ptr_factory_.GetWeakPtr()),
93        base::Bind(&PowerManagerClientImpl::SignalConnected,
94                   weak_ptr_factory_.GetWeakPtr()));
95
96    power_manager_proxy_->ConnectToSignal(
97        power_manager::kPowerManagerInterface,
98        power_manager::kInputEventSignal,
99        base::Bind(&PowerManagerClientImpl::InputEventReceived,
100                   weak_ptr_factory_.GetWeakPtr()),
101        base::Bind(&PowerManagerClientImpl::SignalConnected,
102                   weak_ptr_factory_.GetWeakPtr()));
103
104    power_manager_proxy_->ConnectToSignal(
105        power_manager::kPowerManagerInterface,
106        power_manager::kSuspendStateChangedSignal,
107        base::Bind(&PowerManagerClientImpl::SuspendStateChangedReceived,
108                   weak_ptr_factory_.GetWeakPtr()),
109        base::Bind(&PowerManagerClientImpl::SignalConnected,
110                   weak_ptr_factory_.GetWeakPtr()));
111
112    power_manager_proxy_->ConnectToSignal(
113        power_manager::kPowerManagerInterface,
114        power_manager::kSuspendImminentSignal,
115        base::Bind(
116            &PowerManagerClientImpl::SuspendImminentReceived,
117            weak_ptr_factory_.GetWeakPtr()),
118        base::Bind(&PowerManagerClientImpl::SignalConnected,
119                   weak_ptr_factory_.GetWeakPtr()));
120
121    power_manager_proxy_->ConnectToSignal(
122        power_manager::kPowerManagerInterface,
123        power_manager::kIdleActionImminentSignal,
124        base::Bind(
125            &PowerManagerClientImpl::IdleActionImminentReceived,
126            weak_ptr_factory_.GetWeakPtr()),
127        base::Bind(&PowerManagerClientImpl::SignalConnected,
128                   weak_ptr_factory_.GetWeakPtr()));
129
130    power_manager_proxy_->ConnectToSignal(
131        power_manager::kPowerManagerInterface,
132        power_manager::kIdleActionDeferredSignal,
133        base::Bind(
134            &PowerManagerClientImpl::IdleActionDeferredReceived,
135            weak_ptr_factory_.GetWeakPtr()),
136        base::Bind(&PowerManagerClientImpl::SignalConnected,
137                   weak_ptr_factory_.GetWeakPtr()));
138
139    RegisterSuspendDelay();
140  }
141
142  virtual ~PowerManagerClientImpl() {
143    // Here we should unregister suspend notifications from powerd,
144    // however:
145    // - The lifetime of the PowerManagerClientImpl can extend past that of
146    //   the objectproxy,
147    // - power_manager can already detect that the client is gone and
148    //   unregister our suspend delay.
149  }
150
151  // PowerManagerClient overrides:
152
153  virtual void AddObserver(Observer* observer) OVERRIDE {
154    CHECK(observer);  // http://crbug.com/119976
155    observers_.AddObserver(observer);
156  }
157
158  virtual void RemoveObserver(Observer* observer) OVERRIDE {
159    observers_.RemoveObserver(observer);
160  }
161
162  virtual bool HasObserver(Observer* observer) OVERRIDE {
163    return observers_.HasObserver(observer);
164  }
165
166  virtual void DecreaseScreenBrightness(bool allow_off) OVERRIDE {
167    dbus::MethodCall method_call(
168        power_manager::kPowerManagerInterface,
169        power_manager::kDecreaseScreenBrightness);
170    dbus::MessageWriter writer(&method_call);
171    writer.AppendBool(allow_off);
172    power_manager_proxy_->CallMethod(
173        &method_call,
174        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
175        dbus::ObjectProxy::EmptyResponseCallback());
176  }
177
178  virtual void IncreaseScreenBrightness() OVERRIDE {
179    SimpleMethodCallToPowerManager(power_manager::kIncreaseScreenBrightness);
180  }
181
182  virtual void DecreaseKeyboardBrightness() OVERRIDE {
183    SimpleMethodCallToPowerManager(power_manager::kDecreaseKeyboardBrightness);
184  }
185
186  virtual void IncreaseKeyboardBrightness() OVERRIDE {
187    SimpleMethodCallToPowerManager(power_manager::kIncreaseKeyboardBrightness);
188  }
189
190  virtual void SetScreenBrightnessPercent(double percent,
191                                          bool gradual) OVERRIDE {
192    dbus::MethodCall method_call(
193        power_manager::kPowerManagerInterface,
194        power_manager::kSetScreenBrightnessPercent);
195    dbus::MessageWriter writer(&method_call);
196    writer.AppendDouble(percent);
197    writer.AppendInt32(
198        gradual ?
199        power_manager::kBrightnessTransitionGradual :
200        power_manager::kBrightnessTransitionInstant);
201    power_manager_proxy_->CallMethod(
202        &method_call,
203        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
204        dbus::ObjectProxy::EmptyResponseCallback());
205  }
206
207  virtual void GetScreenBrightnessPercent(
208      const GetScreenBrightnessPercentCallback& callback) OVERRIDE {
209    dbus::MethodCall method_call(power_manager::kPowerManagerInterface,
210                                 power_manager::kGetScreenBrightnessPercent);
211    power_manager_proxy_->CallMethod(
212        &method_call,
213        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
214        base::Bind(&PowerManagerClientImpl::OnGetScreenBrightnessPercent,
215                   weak_ptr_factory_.GetWeakPtr(), callback));
216  }
217
218  virtual void RequestStatusUpdate() OVERRIDE {
219    dbus::MethodCall method_call(
220        power_manager::kPowerManagerInterface,
221        power_manager::kGetPowerSupplyPropertiesMethod);
222    power_manager_proxy_->CallMethod(
223        &method_call,
224        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
225        base::Bind(&PowerManagerClientImpl::OnGetPowerSupplyPropertiesMethod,
226                   weak_ptr_factory_.GetWeakPtr()));
227  }
228
229  virtual void RequestRestart() OVERRIDE {
230    SimpleMethodCallToPowerManager(power_manager::kRequestRestartMethod);
231  };
232
233  virtual void RequestShutdown() OVERRIDE {
234    SimpleMethodCallToPowerManager(power_manager::kRequestShutdownMethod);
235  }
236
237  virtual void RequestIdleNotification(int64 threshold) OVERRIDE {
238    dbus::MethodCall method_call(power_manager::kPowerManagerInterface,
239                                 power_manager::kRequestIdleNotification);
240    dbus::MessageWriter writer(&method_call);
241    writer.AppendInt64(threshold);
242
243    power_manager_proxy_->CallMethod(
244        &method_call,
245        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
246        dbus::ObjectProxy::EmptyResponseCallback());
247  }
248
249  virtual void NotifyUserActivity() OVERRIDE {
250    SimpleMethodCallToPowerManager(power_manager::kHandleUserActivityMethod);
251  }
252
253  virtual void NotifyVideoActivity(bool is_fullscreen) OVERRIDE {
254    dbus::MethodCall method_call(
255        power_manager::kPowerManagerInterface,
256        power_manager::kHandleVideoActivityMethod);
257    dbus::MessageWriter writer(&method_call);
258    writer.AppendBool(is_fullscreen);
259
260    power_manager_proxy_->CallMethod(
261        &method_call,
262        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
263        dbus::ObjectProxy::EmptyResponseCallback());
264  }
265
266  virtual void SetPolicy(
267      const power_manager::PowerManagementPolicy& policy) OVERRIDE {
268    dbus::MethodCall method_call(
269        power_manager::kPowerManagerInterface,
270        power_manager::kSetPolicyMethod);
271    dbus::MessageWriter writer(&method_call);
272    if (!writer.AppendProtoAsArrayOfBytes(policy)) {
273      LOG(ERROR) << "Error calling " << power_manager::kSetPolicyMethod;
274      return;
275    }
276    power_manager_proxy_->CallMethod(
277        &method_call,
278        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
279        dbus::ObjectProxy::EmptyResponseCallback());
280  }
281
282  virtual void SetIsProjecting(bool is_projecting) OVERRIDE {
283    dbus::MethodCall method_call(
284        power_manager::kPowerManagerInterface,
285        power_manager::kSetIsProjectingMethod);
286    dbus::MessageWriter writer(&method_call);
287    writer.AppendBool(is_projecting);
288    power_manager_proxy_->CallMethod(
289        &method_call,
290        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
291        dbus::ObjectProxy::EmptyResponseCallback());
292    last_is_projecting_ = is_projecting;
293  }
294
295  virtual base::Closure GetSuspendReadinessCallback() OVERRIDE {
296    DCHECK(OnOriginThread());
297    DCHECK(suspend_is_pending_);
298    num_pending_suspend_readiness_callbacks_++;
299    return base::Bind(&PowerManagerClientImpl::HandleObserverSuspendReadiness,
300                      weak_ptr_factory_.GetWeakPtr(), pending_suspend_id_);
301  }
302
303 private:
304  // Returns true if the current thread is the origin thread.
305  bool OnOriginThread() {
306    return base::PlatformThread::CurrentId() == origin_thread_id_;
307  }
308
309  // Called when a dbus signal is initially connected.
310  void SignalConnected(const std::string& interface_name,
311                       const std::string& signal_name,
312                       bool success) {
313    LOG_IF(WARNING, !success) << "Failed to connect to signal "
314                              << signal_name << ".";
315  }
316
317  // Make a method call to power manager with no arguments and no response.
318  void SimpleMethodCallToPowerManager(const std::string& method_name) {
319    dbus::MethodCall method_call(power_manager::kPowerManagerInterface,
320                                 method_name);
321    power_manager_proxy_->CallMethod(
322        &method_call,
323        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
324        dbus::ObjectProxy::EmptyResponseCallback());
325  }
326
327  void NameOwnerChangedReceived(dbus::Signal* signal) {
328    VLOG(1) << "Power manager restarted";
329    RegisterSuspendDelay();
330    SetIsProjecting(last_is_projecting_);
331    FOR_EACH_OBSERVER(Observer, observers_, PowerManagerRestarted());
332  }
333
334  void BrightnessChangedReceived(dbus::Signal* signal) {
335    dbus::MessageReader reader(signal);
336    int32 brightness_level = 0;
337    bool user_initiated = 0;
338    if (!(reader.PopInt32(&brightness_level) &&
339          reader.PopBool(&user_initiated))) {
340      LOG(ERROR) << "Brightness changed signal had incorrect parameters: "
341                 << signal->ToString();
342      return;
343    }
344    VLOG(1) << "Brightness changed to " << brightness_level
345            << ": user initiated " << user_initiated;
346    FOR_EACH_OBSERVER(Observer, observers_,
347                      BrightnessChanged(brightness_level, user_initiated));
348  }
349
350  void PeripheralBatteryStatusReceived(dbus::Signal* signal) {
351    dbus::MessageReader reader(signal);
352    power_manager::PeripheralBatteryStatus protobuf_status;
353    if (!reader.PopArrayOfBytesAsProto(&protobuf_status)) {
354      LOG(ERROR) << "Unable to decode protocol buffer from "
355                 << power_manager::kPeripheralBatteryStatusSignal << " signal";
356      return;
357    }
358
359    std::string path = protobuf_status.path();
360    std::string name = protobuf_status.name();
361    int level = protobuf_status.has_level() ? protobuf_status.level() : -1;
362
363    VLOG(1) << "Device battery status received " << level
364            << " for " << name << " at " << path;
365
366    FOR_EACH_OBSERVER(Observer, observers_,
367                      PeripheralBatteryStatusReceived(path, name, level));
368  }
369
370  void PowerSupplyPollReceived(dbus::Signal* signal) {
371    VLOG(1) << "Received power supply poll signal.";
372    dbus::MessageReader reader(signal);
373    power_manager::PowerSupplyProperties protobuf;
374    if (reader.PopArrayOfBytesAsProto(&protobuf)) {
375      FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(protobuf));
376    } else {
377      LOG(ERROR) << "Unable to decode "
378                 << power_manager::kPowerSupplyPollSignal << "signal";
379    }
380  }
381
382  void OnGetPowerSupplyPropertiesMethod(dbus::Response* response) {
383    if (!response) {
384      LOG(ERROR) << "Error calling "
385                 << power_manager::kGetPowerSupplyPropertiesMethod;
386      return;
387    }
388
389    dbus::MessageReader reader(response);
390    power_manager::PowerSupplyProperties protobuf;
391    if (reader.PopArrayOfBytesAsProto(&protobuf)) {
392      FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(protobuf));
393    } else {
394      LOG(ERROR) << "Unable to decode "
395                 << power_manager::kGetPowerSupplyPropertiesMethod
396                 << " response";
397    }
398  }
399
400  void OnGetScreenBrightnessPercent(
401      const GetScreenBrightnessPercentCallback& callback,
402      dbus::Response* response) {
403    if (!response) {
404      LOG(ERROR) << "Error calling "
405                 << power_manager::kGetScreenBrightnessPercent;
406      return;
407    }
408    dbus::MessageReader reader(response);
409    double percent = 0.0;
410    if (!reader.PopDouble(&percent))
411      LOG(ERROR) << "Error reading response from powerd: "
412                 << response->ToString();
413    callback.Run(percent);
414  }
415
416  void OnRegisterSuspendDelayReply(dbus::Response* response) {
417    if (!response) {
418      LOG(ERROR) << "Error calling "
419                 << power_manager::kRegisterSuspendDelayMethod;
420      return;
421    }
422
423    dbus::MessageReader reader(response);
424    power_manager::RegisterSuspendDelayReply protobuf;
425    if (!reader.PopArrayOfBytesAsProto(&protobuf)) {
426      LOG(ERROR) << "Unable to parse reply from "
427                 << power_manager::kRegisterSuspendDelayMethod;
428      return;
429    }
430
431    suspend_delay_id_ = protobuf.delay_id();
432    has_suspend_delay_id_ = true;
433    VLOG(1) << "Registered suspend delay " << suspend_delay_id_;
434  }
435
436  void IdleNotifySignalReceived(dbus::Signal* signal) {
437    dbus::MessageReader reader(signal);
438    int64 threshold = 0;
439    if (!reader.PopInt64(&threshold)) {
440      LOG(ERROR) << "Idle Notify signal had incorrect parameters: "
441                 << signal->ToString();
442      return;
443    }
444    DCHECK_GT(threshold, 0);
445
446    VLOG(1) << "Idle Notify: " << threshold;
447    FOR_EACH_OBSERVER(Observer, observers_, IdleNotify(threshold));
448  }
449
450  void SuspendImminentReceived(dbus::Signal* signal) {
451    if (!has_suspend_delay_id_) {
452      LOG(ERROR) << "Received unrequested "
453                 << power_manager::kSuspendImminentSignal << " signal";
454      return;
455    }
456
457    dbus::MessageReader reader(signal);
458    power_manager::SuspendImminent protobuf_imminent;
459    if (!reader.PopArrayOfBytesAsProto(&protobuf_imminent)) {
460      LOG(ERROR) << "Unable to decode protocol buffer from "
461                 << power_manager::kSuspendImminentSignal << " signal";
462      return;
463    }
464
465    if (suspend_is_pending_) {
466      LOG(WARNING) << "Got " << power_manager::kSuspendImminentSignal
467                   << " signal about pending suspend attempt "
468                   << protobuf_imminent.suspend_id() << " while still waiting "
469                   << "on attempt " << pending_suspend_id_;
470    }
471
472    pending_suspend_id_ = protobuf_imminent.suspend_id();
473    suspend_is_pending_ = true;
474    num_pending_suspend_readiness_callbacks_ = 0;
475    FOR_EACH_OBSERVER(Observer, observers_, SuspendImminent());
476    MaybeReportSuspendReadiness();
477  }
478
479  void IdleActionImminentReceived(dbus::Signal* signal) {
480    FOR_EACH_OBSERVER(Observer, observers_, IdleActionImminent());
481  }
482
483  void IdleActionDeferredReceived(dbus::Signal* signal) {
484    FOR_EACH_OBSERVER(Observer, observers_, IdleActionDeferred());
485  }
486
487  void InputEventReceived(dbus::Signal* signal) {
488    dbus::MessageReader reader(signal);
489    power_manager::InputEvent proto;
490    if (!reader.PopArrayOfBytesAsProto(&proto)) {
491      LOG(ERROR) << "Unable to decode protocol buffer from "
492                 << power_manager::kInputEventSignal << " signal";
493      return;
494    }
495
496    base::TimeTicks timestamp =
497        base::TimeTicks::FromInternalValue(proto.timestamp());
498    VLOG(1) << "Got " << power_manager::kInputEventSignal << " signal:"
499            << " type=" << proto.type() << " timestamp=" << proto.timestamp();
500    switch (proto.type()) {
501      case power_manager::InputEvent_Type_POWER_BUTTON_DOWN:
502      case power_manager::InputEvent_Type_POWER_BUTTON_UP: {
503        bool down =
504            (proto.type() == power_manager::InputEvent_Type_POWER_BUTTON_DOWN);
505        FOR_EACH_OBSERVER(PowerManagerClient::Observer, observers_,
506                          PowerButtonEventReceived(down, timestamp));
507        break;
508      }
509      case power_manager::InputEvent_Type_LID_OPEN:
510      case power_manager::InputEvent_Type_LID_CLOSED: {
511        bool open =
512            (proto.type() == power_manager::InputEvent_Type_LID_OPEN);
513        FOR_EACH_OBSERVER(PowerManagerClient::Observer, observers_,
514                          LidEventReceived(open, timestamp));
515        break;
516      }
517    }
518  }
519
520  void SuspendStateChangedReceived(dbus::Signal* signal) {
521    dbus::MessageReader reader(signal);
522    power_manager::SuspendState proto;
523    if (!reader.PopArrayOfBytesAsProto(&proto)) {
524      LOG(ERROR) << "Unable to decode protocol buffer from "
525                 << power_manager::kSuspendStateChangedSignal << " signal";
526      return;
527    }
528
529    VLOG(1) << "Got " << power_manager::kSuspendStateChangedSignal << " signal:"
530            << " type=" << proto.type() << " wall_time=" << proto.wall_time();
531    base::Time wall_time =
532        base::Time::FromInternalValue(proto.wall_time());
533    switch (proto.type()) {
534      case power_manager::SuspendState_Type_SUSPEND_TO_MEMORY:
535        last_suspend_wall_time_ = wall_time;
536        break;
537      case power_manager::SuspendState_Type_RESUME:
538        FOR_EACH_OBSERVER(
539            PowerManagerClient::Observer, observers_,
540            SystemResumed(wall_time - last_suspend_wall_time_));
541        break;
542    }
543  }
544
545  // Registers a suspend delay with the power manager.  This is usually
546  // only called at startup, but if the power manager restarts, we need to
547  // create a new delay.
548  void RegisterSuspendDelay() {
549    // Throw out any old delay that was registered.
550    suspend_delay_id_ = -1;
551    has_suspend_delay_id_ = false;
552
553    dbus::MethodCall method_call(
554        power_manager::kPowerManagerInterface,
555        power_manager::kRegisterSuspendDelayMethod);
556    dbus::MessageWriter writer(&method_call);
557
558    power_manager::RegisterSuspendDelayRequest protobuf_request;
559    base::TimeDelta timeout =
560        base::TimeDelta::FromMilliseconds(kSuspendDelayTimeoutMs);
561    protobuf_request.set_timeout(timeout.ToInternalValue());
562    protobuf_request.set_description(kSuspendDelayDescription);
563
564    if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) {
565      LOG(ERROR) << "Error constructing message for "
566                 << power_manager::kRegisterSuspendDelayMethod;
567      return;
568    }
569    power_manager_proxy_->CallMethod(
570        &method_call,
571        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
572        base::Bind(
573            &PowerManagerClientImpl::OnRegisterSuspendDelayReply,
574            weak_ptr_factory_.GetWeakPtr()));
575  }
576
577  // Records the fact that an observer has finished doing asynchronous work
578  // that was blocking a pending suspend attempt and possibly reports
579  // suspend readiness to powerd.  Called by callbacks returned via
580  // GetSuspendReadinessCallback().
581  void HandleObserverSuspendReadiness(int32 suspend_id) {
582    DCHECK(OnOriginThread());
583    if (!suspend_is_pending_ || suspend_id != pending_suspend_id_)
584      return;
585
586    num_pending_suspend_readiness_callbacks_--;
587    MaybeReportSuspendReadiness();
588  }
589
590  // Reports suspend readiness to powerd if no observers are still holding
591  // suspend readiness callbacks.
592  void MaybeReportSuspendReadiness() {
593    if (!suspend_is_pending_ || num_pending_suspend_readiness_callbacks_ > 0)
594      return;
595
596    dbus::MethodCall method_call(
597        power_manager::kPowerManagerInterface,
598        power_manager::kHandleSuspendReadinessMethod);
599    dbus::MessageWriter writer(&method_call);
600
601    power_manager::SuspendReadinessInfo protobuf_request;
602    protobuf_request.set_delay_id(suspend_delay_id_);
603    protobuf_request.set_suspend_id(pending_suspend_id_);
604
605    pending_suspend_id_ = -1;
606    suspend_is_pending_ = false;
607
608    if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) {
609      LOG(ERROR) << "Error constructing message for "
610                 << power_manager::kHandleSuspendReadinessMethod;
611      return;
612    }
613    power_manager_proxy_->CallMethod(
614        &method_call,
615        dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
616        dbus::ObjectProxy::EmptyResponseCallback());
617  }
618
619  // Origin thread (i.e. the UI thread in production).
620  base::PlatformThreadId origin_thread_id_;
621
622  dbus::ObjectProxy* power_manager_proxy_;
623  ObserverList<Observer> observers_;
624
625  // The delay_id_ obtained from the RegisterSuspendDelay request.
626  int32 suspend_delay_id_;
627  bool has_suspend_delay_id_;
628
629  // powerd-supplied ID corresponding to an imminent suspend attempt that is
630  // currently being delayed.
631  int32 pending_suspend_id_;
632  bool suspend_is_pending_;
633
634  // Number of callbacks that have been returned by
635  // GetSuspendReadinessCallback() during the currently-pending suspend
636  // attempt but have not yet been called.
637  int num_pending_suspend_readiness_callbacks_;
638
639  // Wall time from the latest signal telling us that the system was about to
640  // suspend to memory.
641  base::Time last_suspend_wall_time_;
642
643  // Last state passed to SetIsProjecting().
644  bool last_is_projecting_;
645
646  // Note: This should remain the last member so it'll be destroyed and
647  // invalidate its weak pointers before any other members are destroyed.
648  base::WeakPtrFactory<PowerManagerClientImpl> weak_ptr_factory_;
649
650  DISALLOW_COPY_AND_ASSIGN(PowerManagerClientImpl);
651};
652
653// The PowerManagerClient implementation used on Linux desktop,
654// which does nothing.
655class PowerManagerClientStubImpl : public PowerManagerClient {
656 public:
657  PowerManagerClientStubImpl()
658      : discharging_(true),
659        battery_percentage_(40),
660        brightness_(50.0),
661        pause_count_(2),
662        cycle_count_(0),
663        weak_ptr_factory_(this) {
664    const int kStatusUpdateMs = 1000;
665    update_timer_.Start(FROM_HERE,
666        base::TimeDelta::FromMilliseconds(kStatusUpdateMs), this,
667        &PowerManagerClientStubImpl::UpdateStatus);
668  }
669
670  virtual ~PowerManagerClientStubImpl() {}
671
672  // PowerManagerClient overrides:
673
674  virtual void AddObserver(Observer* observer) OVERRIDE {
675    observers_.AddObserver(observer);
676  }
677
678  virtual void RemoveObserver(Observer* observer) OVERRIDE {
679    observers_.RemoveObserver(observer);
680  }
681
682  virtual bool HasObserver(Observer* observer) OVERRIDE {
683    return observers_.HasObserver(observer);
684  }
685
686  virtual void DecreaseScreenBrightness(bool allow_off) OVERRIDE {
687    VLOG(1) << "Requested to descrease screen brightness";
688    SetBrightness(brightness_ - 5.0, true);
689  }
690
691  virtual void IncreaseScreenBrightness() OVERRIDE {
692    VLOG(1) << "Requested to increase screen brightness";
693    SetBrightness(brightness_ + 5.0, true);
694  }
695
696  virtual void SetScreenBrightnessPercent(double percent,
697                                          bool gradual) OVERRIDE {
698    VLOG(1) << "Requested to set screen brightness to " << percent << "% "
699            << (gradual ? "gradually" : "instantaneously");
700    SetBrightness(percent, false);
701  }
702
703  virtual void GetScreenBrightnessPercent(
704      const GetScreenBrightnessPercentCallback& callback) OVERRIDE {
705    callback.Run(brightness_);
706  }
707
708  virtual void DecreaseKeyboardBrightness() OVERRIDE {
709    VLOG(1) << "Requested to descrease keyboard brightness";
710  }
711
712  virtual void IncreaseKeyboardBrightness() OVERRIDE {
713    VLOG(1) << "Requested to increase keyboard brightness";
714  }
715
716  virtual void RequestStatusUpdate() OVERRIDE {
717    base::MessageLoop::current()->PostTask(FROM_HERE,
718        base::Bind(&PowerManagerClientStubImpl::UpdateStatus,
719                   weak_ptr_factory_.GetWeakPtr()));
720  }
721
722  virtual void RequestRestart() OVERRIDE {}
723  virtual void RequestShutdown() OVERRIDE {}
724
725  virtual void RequestIdleNotification(int64 threshold) OVERRIDE {
726    base::MessageLoop::current()->PostDelayedTask(
727        FROM_HERE,
728        base::Bind(&PowerManagerClientStubImpl::TriggerIdleNotify,
729                   weak_ptr_factory_.GetWeakPtr(), threshold),
730        base::TimeDelta::FromMilliseconds(threshold));
731  }
732
733  virtual void NotifyUserActivity() OVERRIDE {}
734  virtual void NotifyVideoActivity(bool is_fullscreen) OVERRIDE {}
735  virtual void SetPolicy(
736      const power_manager::PowerManagementPolicy& policy) OVERRIDE {}
737  virtual void SetIsProjecting(bool is_projecting) OVERRIDE {}
738  virtual base::Closure GetSuspendReadinessCallback() OVERRIDE {
739    return base::Closure();
740  }
741
742 private:
743  void UpdateStatus() {
744    if (pause_count_ > 0) {
745      pause_count_--;
746      if (pause_count_ == 2)
747        discharging_ = !discharging_;
748    } else {
749      if (discharging_)
750        battery_percentage_ -= (battery_percentage_ <= 10 ? 1 : 10);
751      else
752        battery_percentage_ += (battery_percentage_ >= 10 ? 10 : 1);
753      battery_percentage_ = std::min(std::max(battery_percentage_, 0), 100);
754      // We pause at 0 and 100% so that it's easier to check those conditions.
755      if (battery_percentage_ == 0 || battery_percentage_ == 100) {
756        pause_count_ = 4;
757        if (battery_percentage_ == 100)
758          cycle_count_ = (cycle_count_ + 1) % 3;
759      }
760    }
761
762    const int kSecondsToEmptyFullBattery = 3 * 60 * 60;  // 3 hours.
763    int64 remaining_battery_time =
764        std::max(1, battery_percentage_ * kSecondsToEmptyFullBattery / 100);
765
766    props_.Clear();
767
768    switch (cycle_count_) {
769      case 0:
770        // Say that the system is charging with AC connected and
771        // discharging without any charger connected.
772        props_.set_external_power(discharging_ ?
773            power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED :
774            power_manager::PowerSupplyProperties_ExternalPower_AC);
775        break;
776      case 1:
777        // Say that the system is both charging and discharging on USB
778        // (i.e. a low-power charger).
779        props_.set_external_power(
780            power_manager::PowerSupplyProperties_ExternalPower_USB);
781        break;
782      case 2:
783        // Say that the system is both charging and discharging on AC.
784        props_.set_external_power(
785            power_manager::PowerSupplyProperties_ExternalPower_AC);
786        break;
787      default:
788        NOTREACHED() << "Unhandled cycle " << cycle_count_;
789    }
790
791    if (battery_percentage_ == 100 && !discharging_) {
792      props_.set_battery_state(
793          power_manager::PowerSupplyProperties_BatteryState_FULL);
794    } else if (!discharging_) {
795      props_.set_battery_state(
796          power_manager::PowerSupplyProperties_BatteryState_CHARGING);
797      props_.set_battery_time_to_full_sec(std::max(static_cast<int64>(1),
798          kSecondsToEmptyFullBattery - remaining_battery_time));
799    } else {
800      props_.set_battery_state(
801          power_manager::PowerSupplyProperties_BatteryState_DISCHARGING);
802      props_.set_battery_time_to_empty_sec(remaining_battery_time);
803    }
804
805    props_.set_battery_percent(battery_percentage_);
806    props_.set_is_calculating_battery_time(pause_count_ > 1);
807
808    FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(props_));
809  }
810
811  void SetBrightness(double percent, bool user_initiated) {
812    brightness_ = std::min(std::max(0.0, percent), 100.0);
813    int brightness_level = static_cast<int>(brightness_);
814    FOR_EACH_OBSERVER(Observer, observers_,
815                      BrightnessChanged(brightness_level, user_initiated));
816  }
817
818  void TriggerIdleNotify(int64 threshold) {
819    FOR_EACH_OBSERVER(Observer, observers_, IdleNotify(threshold));
820  }
821
822  bool discharging_;
823  int battery_percentage_;
824  double brightness_;
825  int pause_count_;
826  int cycle_count_;
827  ObserverList<Observer> observers_;
828  base::RepeatingTimer<PowerManagerClientStubImpl> update_timer_;
829  power_manager::PowerSupplyProperties props_;
830
831  // Note: This should remain the last member so it'll be destroyed and
832  // invalidate its weak pointers before any other members are destroyed.
833  base::WeakPtrFactory<PowerManagerClientStubImpl> weak_ptr_factory_;
834};
835
836PowerManagerClient::PowerManagerClient() {
837}
838
839PowerManagerClient::~PowerManagerClient() {
840}
841
842// static
843PowerManagerClient* PowerManagerClient::Create(
844    DBusClientImplementationType type,
845    dbus::Bus* bus) {
846  if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
847    return new PowerManagerClientImpl(bus);
848  DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
849  return new PowerManagerClientStubImpl();
850}
851
852}  // namespace chromeos
853