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/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         pending_suspend_id_(-1),
     52         suspend_is_pending_(false),
     53         num_pending_suspend_readiness_callbacks_(0),
     54         last_is_projecting_(false),
     55         weak_ptr_factory_(this) {}
     56 
     57   virtual ~PowerManagerClientImpl() {
     58     // Here we should unregister suspend notifications from powerd,
     59     // however:
     60     // - The lifetime of the PowerManagerClientImpl can extend past that of
     61     //   the objectproxy,
     62     // - power_manager can already detect that the client is gone and
     63     //   unregister our suspend delay.
     64   }
     65 
     66   // PowerManagerClient overrides:
     67 
     68   virtual void AddObserver(Observer* observer) OVERRIDE {
     69     CHECK(observer);  // http://crbug.com/119976
     70     observers_.AddObserver(observer);
     71   }
     72 
     73   virtual void RemoveObserver(Observer* observer) OVERRIDE {
     74     observers_.RemoveObserver(observer);
     75   }
     76 
     77   virtual bool HasObserver(Observer* observer) OVERRIDE {
     78     return observers_.HasObserver(observer);
     79   }
     80 
     81   virtual void DecreaseScreenBrightness(bool allow_off) OVERRIDE {
     82     dbus::MethodCall method_call(
     83         power_manager::kPowerManagerInterface,
     84         power_manager::kDecreaseScreenBrightnessMethod);
     85     dbus::MessageWriter writer(&method_call);
     86     writer.AppendBool(allow_off);
     87     power_manager_proxy_->CallMethod(
     88         &method_call,
     89         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
     90         dbus::ObjectProxy::EmptyResponseCallback());
     91   }
     92 
     93   virtual void IncreaseScreenBrightness() OVERRIDE {
     94     SimpleMethodCallToPowerManager(
     95         power_manager::kIncreaseScreenBrightnessMethod);
     96   }
     97 
     98   virtual void DecreaseKeyboardBrightness() OVERRIDE {
     99     SimpleMethodCallToPowerManager(
    100         power_manager::kDecreaseKeyboardBrightnessMethod);
    101   }
    102 
    103   virtual void IncreaseKeyboardBrightness() OVERRIDE {
    104     SimpleMethodCallToPowerManager(
    105         power_manager::kIncreaseKeyboardBrightnessMethod);
    106   }
    107 
    108   virtual void SetScreenBrightnessPercent(double percent,
    109                                           bool gradual) OVERRIDE {
    110     dbus::MethodCall method_call(
    111         power_manager::kPowerManagerInterface,
    112         power_manager::kSetScreenBrightnessPercentMethod);
    113     dbus::MessageWriter writer(&method_call);
    114     writer.AppendDouble(percent);
    115     writer.AppendInt32(
    116         gradual ?
    117         power_manager::kBrightnessTransitionGradual :
    118         power_manager::kBrightnessTransitionInstant);
    119     power_manager_proxy_->CallMethod(
    120         &method_call,
    121         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    122         dbus::ObjectProxy::EmptyResponseCallback());
    123   }
    124 
    125   virtual void GetScreenBrightnessPercent(
    126       const GetScreenBrightnessPercentCallback& callback) OVERRIDE {
    127     dbus::MethodCall method_call(
    128         power_manager::kPowerManagerInterface,
    129         power_manager::kGetScreenBrightnessPercentMethod);
    130     power_manager_proxy_->CallMethod(
    131         &method_call,
    132         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    133         base::Bind(&PowerManagerClientImpl::OnGetScreenBrightnessPercent,
    134                    weak_ptr_factory_.GetWeakPtr(), callback));
    135   }
    136 
    137   virtual void RequestStatusUpdate() OVERRIDE {
    138     dbus::MethodCall method_call(
    139         power_manager::kPowerManagerInterface,
    140         power_manager::kGetPowerSupplyPropertiesMethod);
    141     power_manager_proxy_->CallMethod(
    142         &method_call,
    143         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    144         base::Bind(&PowerManagerClientImpl::OnGetPowerSupplyPropertiesMethod,
    145                    weak_ptr_factory_.GetWeakPtr()));
    146   }
    147 
    148   virtual void RequestRestart() OVERRIDE {
    149     SimpleMethodCallToPowerManager(power_manager::kRequestRestartMethod);
    150   };
    151 
    152   virtual void RequestShutdown() OVERRIDE {
    153     SimpleMethodCallToPowerManager(power_manager::kRequestShutdownMethod);
    154   }
    155 
    156   virtual void NotifyUserActivity(
    157       power_manager::UserActivityType type) OVERRIDE {
    158     dbus::MethodCall method_call(
    159         power_manager::kPowerManagerInterface,
    160         power_manager::kHandleUserActivityMethod);
    161     dbus::MessageWriter writer(&method_call);
    162     writer.AppendInt32(type);
    163 
    164     power_manager_proxy_->CallMethod(
    165         &method_call,
    166         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    167         dbus::ObjectProxy::EmptyResponseCallback());
    168   }
    169 
    170   virtual void NotifyVideoActivity(bool is_fullscreen) OVERRIDE {
    171     dbus::MethodCall method_call(
    172         power_manager::kPowerManagerInterface,
    173         power_manager::kHandleVideoActivityMethod);
    174     dbus::MessageWriter writer(&method_call);
    175     writer.AppendBool(is_fullscreen);
    176 
    177     power_manager_proxy_->CallMethod(
    178         &method_call,
    179         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    180         dbus::ObjectProxy::EmptyResponseCallback());
    181   }
    182 
    183   virtual void SetPolicy(
    184       const power_manager::PowerManagementPolicy& policy) OVERRIDE {
    185     dbus::MethodCall method_call(
    186         power_manager::kPowerManagerInterface,
    187         power_manager::kSetPolicyMethod);
    188     dbus::MessageWriter writer(&method_call);
    189     if (!writer.AppendProtoAsArrayOfBytes(policy)) {
    190       LOG(ERROR) << "Error calling " << power_manager::kSetPolicyMethod;
    191       return;
    192     }
    193     power_manager_proxy_->CallMethod(
    194         &method_call,
    195         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    196         dbus::ObjectProxy::EmptyResponseCallback());
    197   }
    198 
    199   virtual void SetIsProjecting(bool is_projecting) OVERRIDE {
    200     dbus::MethodCall method_call(
    201         power_manager::kPowerManagerInterface,
    202         power_manager::kSetIsProjectingMethod);
    203     dbus::MessageWriter writer(&method_call);
    204     writer.AppendBool(is_projecting);
    205     power_manager_proxy_->CallMethod(
    206         &method_call,
    207         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    208         dbus::ObjectProxy::EmptyResponseCallback());
    209     last_is_projecting_ = is_projecting;
    210   }
    211 
    212   virtual base::Closure GetSuspendReadinessCallback() OVERRIDE {
    213     DCHECK(OnOriginThread());
    214     DCHECK(suspend_is_pending_);
    215     num_pending_suspend_readiness_callbacks_++;
    216     return base::Bind(&PowerManagerClientImpl::HandleObserverSuspendReadiness,
    217                       weak_ptr_factory_.GetWeakPtr(), pending_suspend_id_);
    218   }
    219 
    220   virtual int GetNumPendingSuspendReadinessCallbacks() OVERRIDE {
    221     return num_pending_suspend_readiness_callbacks_;
    222   }
    223 
    224  protected:
    225   virtual void Init(dbus::Bus* bus) OVERRIDE {
    226     power_manager_proxy_ = bus->GetObjectProxy(
    227         power_manager::kPowerManagerServiceName,
    228         dbus::ObjectPath(power_manager::kPowerManagerServicePath));
    229 
    230     power_manager_proxy_->SetNameOwnerChangedCallback(
    231         base::Bind(&PowerManagerClientImpl::NameOwnerChangedReceived,
    232                    weak_ptr_factory_.GetWeakPtr()));
    233 
    234     // Monitor the D-Bus signal for brightness changes. Only the power
    235     // manager knows the actual brightness level. We don't cache the
    236     // brightness level in Chrome as it'll make things less reliable.
    237     power_manager_proxy_->ConnectToSignal(
    238         power_manager::kPowerManagerInterface,
    239         power_manager::kBrightnessChangedSignal,
    240         base::Bind(&PowerManagerClientImpl::BrightnessChangedReceived,
    241                    weak_ptr_factory_.GetWeakPtr()),
    242         base::Bind(&PowerManagerClientImpl::SignalConnected,
    243                    weak_ptr_factory_.GetWeakPtr()));
    244 
    245     power_manager_proxy_->ConnectToSignal(
    246         power_manager::kPowerManagerInterface,
    247         power_manager::kPeripheralBatteryStatusSignal,
    248         base::Bind(&PowerManagerClientImpl::PeripheralBatteryStatusReceived,
    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::kPowerSupplyPollSignal,
    256         base::Bind(&PowerManagerClientImpl::PowerSupplyPollReceived,
    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::kInputEventSignal,
    264         base::Bind(&PowerManagerClientImpl::InputEventReceived,
    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::kSuspendImminentSignal,
    272         base::Bind(
    273             &PowerManagerClientImpl::SuspendImminentReceived,
    274             weak_ptr_factory_.GetWeakPtr()),
    275         base::Bind(&PowerManagerClientImpl::SignalConnected,
    276                    weak_ptr_factory_.GetWeakPtr()));
    277 
    278     power_manager_proxy_->ConnectToSignal(
    279         power_manager::kPowerManagerInterface,
    280         power_manager::kSuspendDoneSignal,
    281         base::Bind(&PowerManagerClientImpl::SuspendDoneReceived,
    282                    weak_ptr_factory_.GetWeakPtr()),
    283         base::Bind(&PowerManagerClientImpl::SignalConnected,
    284                    weak_ptr_factory_.GetWeakPtr()));
    285 
    286     power_manager_proxy_->ConnectToSignal(
    287         power_manager::kPowerManagerInterface,
    288         power_manager::kIdleActionImminentSignal,
    289         base::Bind(
    290             &PowerManagerClientImpl::IdleActionImminentReceived,
    291             weak_ptr_factory_.GetWeakPtr()),
    292         base::Bind(&PowerManagerClientImpl::SignalConnected,
    293                    weak_ptr_factory_.GetWeakPtr()));
    294 
    295     power_manager_proxy_->ConnectToSignal(
    296         power_manager::kPowerManagerInterface,
    297         power_manager::kIdleActionDeferredSignal,
    298         base::Bind(
    299             &PowerManagerClientImpl::IdleActionDeferredReceived,
    300             weak_ptr_factory_.GetWeakPtr()),
    301         base::Bind(&PowerManagerClientImpl::SignalConnected,
    302                    weak_ptr_factory_.GetWeakPtr()));
    303 
    304     RegisterSuspendDelay();
    305   }
    306 
    307  private:
    308   // Returns true if the current thread is the origin thread.
    309   bool OnOriginThread() {
    310     return base::PlatformThread::CurrentId() == origin_thread_id_;
    311   }
    312 
    313   // Called when a dbus signal is initially connected.
    314   void SignalConnected(const std::string& interface_name,
    315                        const std::string& signal_name,
    316                        bool success) {
    317     LOG_IF(WARNING, !success) << "Failed to connect to signal "
    318                               << signal_name << ".";
    319   }
    320 
    321   // Makes a method call to power manager with no arguments and no response.
    322   void SimpleMethodCallToPowerManager(const std::string& method_name) {
    323     dbus::MethodCall method_call(power_manager::kPowerManagerInterface,
    324                                  method_name);
    325     power_manager_proxy_->CallMethod(
    326         &method_call,
    327         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    328         dbus::ObjectProxy::EmptyResponseCallback());
    329   }
    330 
    331   void NameOwnerChangedReceived(const std::string& old_owner,
    332                                 const std::string& new_owner) {
    333     VLOG(1) << "Power manager restarted (old owner was "
    334             << (old_owner.empty() ? "[none]" : old_owner.c_str())
    335             << ", new owner is "
    336             << (new_owner.empty() ? "[none]" : new_owner.c_str()) << ")";
    337     if (!new_owner.empty()) {
    338       VLOG(1) << "Sending initial state to power manager";
    339       RegisterSuspendDelay();
    340       SetIsProjecting(last_is_projecting_);
    341       FOR_EACH_OBSERVER(Observer, observers_, PowerManagerRestarted());
    342     }
    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::kGetScreenBrightnessPercentMethod;
    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 SuspendImminentReceived(dbus::Signal* signal) {
    448     if (!has_suspend_delay_id_) {
    449       LOG(ERROR) << "Received unrequested "
    450                  << power_manager::kSuspendImminentSignal << " signal";
    451       return;
    452     }
    453 
    454     dbus::MessageReader reader(signal);
    455     power_manager::SuspendImminent proto;
    456     if (!reader.PopArrayOfBytesAsProto(&proto)) {
    457       LOG(ERROR) << "Unable to decode protocol buffer from "
    458                  << power_manager::kSuspendImminentSignal << " signal";
    459       return;
    460     }
    461 
    462     VLOG(1) << "Got " << power_manager::kSuspendImminentSignal << " signal "
    463             << "announcing suspend attempt " << proto.suspend_id();
    464     if (suspend_is_pending_) {
    465       LOG(WARNING) << "Got " << power_manager::kSuspendImminentSignal
    466                    << " signal about pending suspend attempt "
    467                    << proto.suspend_id() << " while still waiting "
    468                    << "on attempt " << pending_suspend_id_;
    469     }
    470 
    471     pending_suspend_id_ = proto.suspend_id();
    472     suspend_is_pending_ = true;
    473     num_pending_suspend_readiness_callbacks_ = 0;
    474     FOR_EACH_OBSERVER(Observer, observers_, SuspendImminent());
    475     MaybeReportSuspendReadiness();
    476   }
    477 
    478   void SuspendDoneReceived(dbus::Signal* signal) {
    479     dbus::MessageReader reader(signal);
    480     power_manager::SuspendDone proto;
    481     if (!reader.PopArrayOfBytesAsProto(&proto)) {
    482       LOG(ERROR) << "Unable to decode protocol buffer from "
    483                  << power_manager::kSuspendDoneSignal << " signal";
    484       return;
    485     }
    486 
    487     const base::TimeDelta duration =
    488         base::TimeDelta::FromInternalValue(proto.suspend_duration());
    489     VLOG(1) << "Got " << power_manager::kSuspendDoneSignal << " signal:"
    490             << " suspend_id=" << proto.suspend_id()
    491             << " duration=" << duration.InSeconds() << " sec";
    492     FOR_EACH_OBSERVER(
    493         PowerManagerClient::Observer, observers_, SuspendDone(duration));
    494   }
    495 
    496   void IdleActionImminentReceived(dbus::Signal* signal) {
    497     dbus::MessageReader reader(signal);
    498     power_manager::IdleActionImminent proto;
    499     if (!reader.PopArrayOfBytesAsProto(&proto)) {
    500       LOG(ERROR) << "Unable to decode protocol buffer from "
    501                  << power_manager::kIdleActionImminentSignal << " signal";
    502       return;
    503     }
    504     FOR_EACH_OBSERVER(Observer, observers_,
    505         IdleActionImminent(base::TimeDelta::FromInternalValue(
    506             proto.time_until_idle_action())));
    507   }
    508 
    509   void IdleActionDeferredReceived(dbus::Signal* signal) {
    510     FOR_EACH_OBSERVER(Observer, observers_, IdleActionDeferred());
    511   }
    512 
    513   void InputEventReceived(dbus::Signal* signal) {
    514     dbus::MessageReader reader(signal);
    515     power_manager::InputEvent proto;
    516     if (!reader.PopArrayOfBytesAsProto(&proto)) {
    517       LOG(ERROR) << "Unable to decode protocol buffer from "
    518                  << power_manager::kInputEventSignal << " signal";
    519       return;
    520     }
    521 
    522     base::TimeTicks timestamp =
    523         base::TimeTicks::FromInternalValue(proto.timestamp());
    524     VLOG(1) << "Got " << power_manager::kInputEventSignal << " signal:"
    525             << " type=" << proto.type() << " timestamp=" << proto.timestamp();
    526     switch (proto.type()) {
    527       case power_manager::InputEvent_Type_POWER_BUTTON_DOWN:
    528       case power_manager::InputEvent_Type_POWER_BUTTON_UP: {
    529         const bool down =
    530             (proto.type() == power_manager::InputEvent_Type_POWER_BUTTON_DOWN);
    531         FOR_EACH_OBSERVER(PowerManagerClient::Observer, observers_,
    532                           PowerButtonEventReceived(down, timestamp));
    533 
    534         // Tell powerd that Chrome has handled power button presses.
    535         if (down) {
    536           dbus::MethodCall method_call(
    537               power_manager::kPowerManagerInterface,
    538               power_manager::kHandlePowerButtonAcknowledgmentMethod);
    539           dbus::MessageWriter writer(&method_call);
    540           writer.AppendInt64(proto.timestamp());
    541           power_manager_proxy_->CallMethod(
    542               &method_call,
    543               dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    544               dbus::ObjectProxy::EmptyResponseCallback());
    545         }
    546         break;
    547       }
    548       case power_manager::InputEvent_Type_LID_OPEN:
    549       case power_manager::InputEvent_Type_LID_CLOSED: {
    550         bool open =
    551             (proto.type() == power_manager::InputEvent_Type_LID_OPEN);
    552         FOR_EACH_OBSERVER(PowerManagerClient::Observer, observers_,
    553                           LidEventReceived(open, timestamp));
    554         break;
    555       }
    556     }
    557   }
    558 
    559   // Registers a suspend delay with the power manager.  This is usually
    560   // only called at startup, but if the power manager restarts, we need to
    561   // create a new delay.
    562   void RegisterSuspendDelay() {
    563     // Throw out any old delay that was registered.
    564     suspend_delay_id_ = -1;
    565     has_suspend_delay_id_ = false;
    566 
    567     dbus::MethodCall method_call(
    568         power_manager::kPowerManagerInterface,
    569         power_manager::kRegisterSuspendDelayMethod);
    570     dbus::MessageWriter writer(&method_call);
    571 
    572     power_manager::RegisterSuspendDelayRequest protobuf_request;
    573     base::TimeDelta timeout =
    574         base::TimeDelta::FromMilliseconds(kSuspendDelayTimeoutMs);
    575     protobuf_request.set_timeout(timeout.ToInternalValue());
    576     protobuf_request.set_description(kSuspendDelayDescription);
    577 
    578     if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) {
    579       LOG(ERROR) << "Error constructing message for "
    580                  << power_manager::kRegisterSuspendDelayMethod;
    581       return;
    582     }
    583     power_manager_proxy_->CallMethod(
    584         &method_call,
    585         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    586         base::Bind(
    587             &PowerManagerClientImpl::OnRegisterSuspendDelayReply,
    588             weak_ptr_factory_.GetWeakPtr()));
    589   }
    590 
    591   // Records the fact that an observer has finished doing asynchronous work
    592   // that was blocking a pending suspend attempt and possibly reports
    593   // suspend readiness to powerd.  Called by callbacks returned via
    594   // GetSuspendReadinessCallback().
    595   void HandleObserverSuspendReadiness(int32 suspend_id) {
    596     DCHECK(OnOriginThread());
    597     if (!suspend_is_pending_ || suspend_id != pending_suspend_id_)
    598       return;
    599 
    600     num_pending_suspend_readiness_callbacks_--;
    601     MaybeReportSuspendReadiness();
    602   }
    603 
    604   // Reports suspend readiness to powerd if no observers are still holding
    605   // suspend readiness callbacks.
    606   void MaybeReportSuspendReadiness() {
    607     if (!suspend_is_pending_ || num_pending_suspend_readiness_callbacks_ > 0)
    608       return;
    609 
    610     dbus::MethodCall method_call(
    611         power_manager::kPowerManagerInterface,
    612         power_manager::kHandleSuspendReadinessMethod);
    613     dbus::MessageWriter writer(&method_call);
    614 
    615     VLOG(1) << "Announcing readiness of suspend delay " << suspend_delay_id_
    616             << " for suspend attempt " << pending_suspend_id_;
    617     power_manager::SuspendReadinessInfo protobuf_request;
    618     protobuf_request.set_delay_id(suspend_delay_id_);
    619     protobuf_request.set_suspend_id(pending_suspend_id_);
    620 
    621     pending_suspend_id_ = -1;
    622     suspend_is_pending_ = false;
    623 
    624     if (!writer.AppendProtoAsArrayOfBytes(protobuf_request)) {
    625       LOG(ERROR) << "Error constructing message for "
    626                  << power_manager::kHandleSuspendReadinessMethod;
    627       return;
    628     }
    629     power_manager_proxy_->CallMethod(
    630         &method_call,
    631         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    632         dbus::ObjectProxy::EmptyResponseCallback());
    633   }
    634 
    635   // Origin thread (i.e. the UI thread in production).
    636   base::PlatformThreadId origin_thread_id_;
    637 
    638   dbus::ObjectProxy* power_manager_proxy_;
    639   ObserverList<Observer> observers_;
    640 
    641   // The delay_id_ obtained from the RegisterSuspendDelay request.
    642   int32 suspend_delay_id_;
    643   bool has_suspend_delay_id_;
    644 
    645   // powerd-supplied ID corresponding to an imminent suspend attempt that is
    646   // currently being delayed.
    647   int32 pending_suspend_id_;
    648   bool suspend_is_pending_;
    649 
    650   // Number of callbacks that have been returned by
    651   // GetSuspendReadinessCallback() during the currently-pending suspend
    652   // attempt but have not yet been called.
    653   int num_pending_suspend_readiness_callbacks_;
    654 
    655   // Last state passed to SetIsProjecting().
    656   bool last_is_projecting_;
    657 
    658   // Note: This should remain the last member so it'll be destroyed and
    659   // invalidate its weak pointers before any other members are destroyed.
    660   base::WeakPtrFactory<PowerManagerClientImpl> weak_ptr_factory_;
    661 
    662   DISALLOW_COPY_AND_ASSIGN(PowerManagerClientImpl);
    663 };
    664 
    665 // The PowerManagerClient implementation used on Linux desktop,
    666 // which does nothing.
    667 class PowerManagerClientStubImpl : public PowerManagerClient {
    668  public:
    669   PowerManagerClientStubImpl()
    670       : discharging_(true),
    671         battery_percentage_(40),
    672         brightness_(50.0),
    673         pause_count_(2),
    674         cycle_count_(0),
    675         num_pending_suspend_readiness_callbacks_(0),
    676         weak_ptr_factory_(this) {}
    677 
    678   virtual ~PowerManagerClientStubImpl() {}
    679 
    680   int num_pending_suspend_readiness_callbacks() const {
    681     return num_pending_suspend_readiness_callbacks_;
    682   }
    683 
    684   // PowerManagerClient overrides:
    685   virtual void Init(dbus::Bus* bus) OVERRIDE {
    686     ParseCommandLineSwitch();
    687     if (power_cycle_delay_ != base::TimeDelta()) {
    688       update_timer_.Start(FROM_HERE,
    689                           power_cycle_delay_,
    690                           this,
    691                           &PowerManagerClientStubImpl::UpdateStatus);
    692     }
    693   }
    694 
    695   virtual void AddObserver(Observer* observer) OVERRIDE {
    696     observers_.AddObserver(observer);
    697   }
    698 
    699   virtual void RemoveObserver(Observer* observer) OVERRIDE {
    700     observers_.RemoveObserver(observer);
    701   }
    702 
    703   virtual bool HasObserver(Observer* observer) OVERRIDE {
    704     return observers_.HasObserver(observer);
    705   }
    706 
    707   virtual void DecreaseScreenBrightness(bool allow_off) OVERRIDE {
    708     VLOG(1) << "Requested to descrease screen brightness";
    709     SetBrightness(brightness_ - 5.0, true);
    710   }
    711 
    712   virtual void IncreaseScreenBrightness() OVERRIDE {
    713     VLOG(1) << "Requested to increase screen brightness";
    714     SetBrightness(brightness_ + 5.0, true);
    715   }
    716 
    717   virtual void SetScreenBrightnessPercent(double percent,
    718                                           bool gradual) OVERRIDE {
    719     VLOG(1) << "Requested to set screen brightness to " << percent << "% "
    720             << (gradual ? "gradually" : "instantaneously");
    721     SetBrightness(percent, false);
    722   }
    723 
    724   virtual void GetScreenBrightnessPercent(
    725       const GetScreenBrightnessPercentCallback& callback) OVERRIDE {
    726     callback.Run(brightness_);
    727   }
    728 
    729   virtual void DecreaseKeyboardBrightness() OVERRIDE {
    730     VLOG(1) << "Requested to descrease keyboard brightness";
    731   }
    732 
    733   virtual void IncreaseKeyboardBrightness() OVERRIDE {
    734     VLOG(1) << "Requested to increase keyboard brightness";
    735   }
    736 
    737   virtual void RequestStatusUpdate() OVERRIDE {
    738     base::MessageLoop::current()->PostTask(FROM_HERE,
    739         base::Bind(&PowerManagerClientStubImpl::UpdateStatus,
    740                    weak_ptr_factory_.GetWeakPtr()));
    741   }
    742 
    743   virtual void RequestRestart() OVERRIDE {}
    744   virtual void RequestShutdown() OVERRIDE {}
    745 
    746   virtual void NotifyUserActivity(
    747       power_manager::UserActivityType type) OVERRIDE {}
    748   virtual void NotifyVideoActivity(bool is_fullscreen) OVERRIDE {}
    749   virtual void SetPolicy(
    750       const power_manager::PowerManagementPolicy& policy) OVERRIDE {}
    751   virtual void SetIsProjecting(bool is_projecting) OVERRIDE {}
    752   virtual base::Closure GetSuspendReadinessCallback() OVERRIDE {
    753     num_pending_suspend_readiness_callbacks_++;
    754     return base::Bind(&PowerManagerClientStubImpl::HandleSuspendReadiness,
    755                       weak_ptr_factory_.GetWeakPtr());
    756   }
    757   virtual int GetNumPendingSuspendReadinessCallbacks() OVERRIDE {
    758     return num_pending_suspend_readiness_callbacks_;
    759   }
    760 
    761  private:
    762   void HandleSuspendReadiness() {
    763     num_pending_suspend_readiness_callbacks_--;
    764   }
    765 
    766   void UpdateStatus() {
    767     if (pause_count_ > 0) {
    768       pause_count_--;
    769       if (pause_count_ == 2)
    770         discharging_ = !discharging_;
    771     } else {
    772       if (discharging_)
    773         battery_percentage_ -= (battery_percentage_ <= 10 ? 1 : 10);
    774       else
    775         battery_percentage_ += (battery_percentage_ >= 10 ? 10 : 1);
    776       battery_percentage_ = std::min(std::max(battery_percentage_, 0), 100);
    777       // We pause at 0 and 100% so that it's easier to check those conditions.
    778       if (battery_percentage_ == 0 || battery_percentage_ == 100) {
    779         pause_count_ = 4;
    780         if (battery_percentage_ == 100)
    781           cycle_count_ = (cycle_count_ + 1) % 3;
    782       }
    783     }
    784 
    785     const int kSecondsToEmptyFullBattery = 3 * 60 * 60;  // 3 hours.
    786     int64 remaining_battery_time =
    787         std::max(1, battery_percentage_ * kSecondsToEmptyFullBattery / 100);
    788 
    789     props_.Clear();
    790 
    791     switch (cycle_count_) {
    792       case 0:
    793         // Say that the system is charging with AC connected and
    794         // discharging without any charger connected.
    795         props_.set_external_power(discharging_ ?
    796             power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED :
    797             power_manager::PowerSupplyProperties_ExternalPower_AC);
    798         break;
    799       case 1:
    800         // Say that the system is both charging and discharging on USB
    801         // (i.e. a low-power charger).
    802         props_.set_external_power(
    803             power_manager::PowerSupplyProperties_ExternalPower_USB);
    804         break;
    805       case 2:
    806         // Say that the system is both charging and discharging on AC.
    807         props_.set_external_power(
    808             power_manager::PowerSupplyProperties_ExternalPower_AC);
    809         break;
    810       default:
    811         NOTREACHED() << "Unhandled cycle " << cycle_count_;
    812     }
    813 
    814     if (battery_percentage_ == 100 && !discharging_) {
    815       props_.set_battery_state(
    816           power_manager::PowerSupplyProperties_BatteryState_FULL);
    817     } else if (!discharging_) {
    818       props_.set_battery_state(
    819           power_manager::PowerSupplyProperties_BatteryState_CHARGING);
    820       props_.set_battery_time_to_full_sec(std::max(static_cast<int64>(1),
    821           kSecondsToEmptyFullBattery - remaining_battery_time));
    822     } else {
    823       props_.set_battery_state(
    824           power_manager::PowerSupplyProperties_BatteryState_DISCHARGING);
    825       props_.set_battery_time_to_empty_sec(remaining_battery_time);
    826     }
    827 
    828     props_.set_battery_percent(battery_percentage_);
    829     props_.set_is_calculating_battery_time(pause_count_ > 1);
    830 
    831     FOR_EACH_OBSERVER(Observer, observers_, PowerChanged(props_));
    832   }
    833 
    834   void SetBrightness(double percent, bool user_initiated) {
    835     brightness_ = std::min(std::max(0.0, percent), 100.0);
    836     int brightness_level = static_cast<int>(brightness_);
    837     FOR_EACH_OBSERVER(Observer, observers_,
    838                       BrightnessChanged(brightness_level, user_initiated));
    839   }
    840 
    841   void ParseCommandLineSwitch() {
    842     CommandLine* command_line = CommandLine::ForCurrentProcess();
    843     if (!command_line || !command_line->HasSwitch(switches::kPowerStub))
    844       return;
    845     std::string option_str =
    846         command_line->GetSwitchValueASCII(switches::kPowerStub);
    847     base::StringPairs string_pairs;
    848     base::SplitStringIntoKeyValuePairs(option_str, '=', ',', &string_pairs);
    849     for (base::StringPairs::iterator iter = string_pairs.begin();
    850          iter != string_pairs.end(); ++iter) {
    851       ParseOption((*iter).first, (*iter).second);
    852     }
    853   }
    854 
    855   void ParseOption(const std::string& arg0, const std::string& arg1) {
    856     if (arg0 == "cycle" || arg0 == "interactive") {
    857       int seconds = 1;
    858       if (!arg1.empty())
    859         base::StringToInt(arg1, &seconds);
    860       power_cycle_delay_ = base::TimeDelta::FromSeconds(seconds);
    861     }
    862   }
    863 
    864   base::TimeDelta power_cycle_delay_;  // Time over which to cycle power state
    865   bool discharging_;
    866   int battery_percentage_;
    867   double brightness_;
    868   int pause_count_;
    869   int cycle_count_;
    870   ObserverList<Observer> observers_;
    871   base::RepeatingTimer<PowerManagerClientStubImpl> update_timer_;
    872   power_manager::PowerSupplyProperties props_;
    873 
    874   // Number of callbacks returned by GetSuspendReadinessCallback() but not yet
    875   // invoked.
    876   int num_pending_suspend_readiness_callbacks_;
    877 
    878   // Note: This should remain the last member so it'll be destroyed and
    879   // invalidate its weak pointers before any other members are destroyed.
    880   base::WeakPtrFactory<PowerManagerClientStubImpl> weak_ptr_factory_;
    881 };
    882 
    883 PowerManagerClient::PowerManagerClient() {
    884 }
    885 
    886 PowerManagerClient::~PowerManagerClient() {
    887 }
    888 
    889 // static
    890 PowerManagerClient* PowerManagerClient::Create(
    891     DBusClientImplementationType type) {
    892   if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
    893     return new PowerManagerClientImpl();
    894   DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
    895   return new PowerManagerClientStubImpl();
    896 }
    897 
    898 }  // namespace chromeos
    899