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