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