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         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
    969