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