Home | History | Annotate | Download | only in dbus
      1 //
      2 // Copyright (C) 2015 The Android Open Source Project
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 //
     16 
     17 #include "shill/dbus/chromeos_power_manager_proxy.h"
     18 
     19 #include <base/bind.h>
     20 #include <google/protobuf/message_lite.h>
     21 
     22 #include "power_manager/proto_bindings/suspend.pb.h"
     23 #include "shill/event_dispatcher.h"
     24 #include "shill/logging.h"
     25 
     26 using std::string;
     27 using std::vector;
     28 
     29 namespace shill {
     30 
     31 namespace {
     32 
     33 // Serializes |protobuf| to |out| and returns true on success.
     34 bool SerializeProtocolBuffer(const google::protobuf::MessageLite& protobuf,
     35                              vector<uint8_t>* out) {
     36   CHECK(out);
     37   out->clear();
     38   string serialized_protobuf;
     39   if (!protobuf.SerializeToString(&serialized_protobuf))
     40     return false;
     41   out->assign(serialized_protobuf.begin(), serialized_protobuf.end());
     42   return true;
     43 }
     44 
     45 // Deserializes |serialized_protobuf| to |protobuf_out| and returns true on
     46 // success.
     47 bool DeserializeProtocolBuffer(const vector<uint8_t>& serialized_protobuf,
     48                                google::protobuf::MessageLite* protobuf_out) {
     49   CHECK(protobuf_out);
     50   if (serialized_protobuf.empty())
     51     return false;
     52   return protobuf_out->ParseFromArray(&serialized_protobuf.front(),
     53                                       serialized_protobuf.size());
     54 }
     55 
     56 }  // namespace
     57 
     58 ChromeosPowerManagerProxy::ChromeosPowerManagerProxy(
     59       EventDispatcher* dispatcher,
     60       const scoped_refptr<dbus::Bus>& bus,
     61       PowerManagerProxyDelegate* delegate,
     62       const base::Closure& service_appeared_callback,
     63       const base::Closure& service_vanished_callback)
     64     : proxy_(new org::chromium::PowerManagerProxy(bus)),
     65       dispatcher_(dispatcher),
     66       delegate_(delegate),
     67       service_appeared_callback_(service_appeared_callback),
     68       service_vanished_callback_(service_vanished_callback) {
     69   // Register signal handlers.
     70   proxy_->RegisterSuspendImminentSignalHandler(
     71       base::Bind(&ChromeosPowerManagerProxy::SuspendImminent,
     72                  weak_factory_.GetWeakPtr()),
     73       base::Bind(&ChromeosPowerManagerProxy::OnSignalConnected,
     74                  weak_factory_.GetWeakPtr()));
     75   proxy_->RegisterSuspendDoneSignalHandler(
     76       base::Bind(&ChromeosPowerManagerProxy::SuspendDone,
     77                  weak_factory_.GetWeakPtr()),
     78       base::Bind(&ChromeosPowerManagerProxy::OnSignalConnected,
     79                  weak_factory_.GetWeakPtr()));
     80   proxy_->RegisterDarkSuspendImminentSignalHandler(
     81       base::Bind(&ChromeosPowerManagerProxy::DarkSuspendImminent,
     82                  weak_factory_.GetWeakPtr()),
     83       base::Bind(&ChromeosPowerManagerProxy::OnSignalConnected,
     84                  weak_factory_.GetWeakPtr()));
     85 
     86   // One time callback when service becomes available.
     87   proxy_->GetObjectProxy()->WaitForServiceToBeAvailable(
     88       base::Bind(&ChromeosPowerManagerProxy::OnServiceAvailable,
     89                  weak_factory_.GetWeakPtr()));
     90 }
     91 
     92 ChromeosPowerManagerProxy::~ChromeosPowerManagerProxy() {}
     93 
     94 bool ChromeosPowerManagerProxy::RegisterSuspendDelay(
     95     base::TimeDelta timeout,
     96     const string& description,
     97     int* delay_id_out) {
     98   if (!service_available_) {
     99     LOG(ERROR) << "PowerManager service not available";
    100     return false;
    101   }
    102   return RegisterSuspendDelayInternal(false,
    103                                       timeout,
    104                                       description,
    105                                       delay_id_out);
    106 }
    107 
    108 bool ChromeosPowerManagerProxy::UnregisterSuspendDelay(int delay_id) {
    109   if (!service_available_) {
    110     LOG(ERROR) << "PowerManager service not available";
    111     return false;
    112   }
    113   return UnregisterSuspendDelayInternal(false, delay_id);
    114 }
    115 
    116 bool ChromeosPowerManagerProxy::ReportSuspendReadiness(int delay_id,
    117                                                        int suspend_id) {
    118   if (!service_available_) {
    119     LOG(ERROR) << "PowerManager service not available";
    120     return false;
    121   }
    122   return ReportSuspendReadinessInternal(false, delay_id, suspend_id);
    123 }
    124 
    125 bool ChromeosPowerManagerProxy::RegisterDarkSuspendDelay(
    126     base::TimeDelta timeout,
    127     const string& description,
    128     int* delay_id_out) {
    129   if (!service_available_) {
    130     LOG(ERROR) << "PowerManager service not available";
    131     return false;
    132   }
    133   return RegisterSuspendDelayInternal(true,
    134                                       timeout,
    135                                       description,
    136                                       delay_id_out);
    137 }
    138 
    139 bool ChromeosPowerManagerProxy::UnregisterDarkSuspendDelay(int delay_id) {
    140   if (!service_available_) {
    141     LOG(ERROR) << "PowerManager service not available";
    142     return false;
    143   }
    144   return UnregisterSuspendDelayInternal(true, delay_id);
    145 }
    146 
    147 bool ChromeosPowerManagerProxy::ReportDarkSuspendReadiness(int delay_id,
    148                                                            int suspend_id ) {
    149   if (!service_available_) {
    150     LOG(ERROR) << "PowerManager service not available";
    151     return false;
    152   }
    153   return ReportSuspendReadinessInternal(true, delay_id, suspend_id);
    154 }
    155 
    156 bool ChromeosPowerManagerProxy::RecordDarkResumeWakeReason(
    157     const string& wake_reason) {
    158   LOG(INFO) << __func__;
    159 
    160   if (!service_available_) {
    161     LOG(ERROR) << "PowerManager service not available";
    162     return false;
    163   }
    164 
    165   power_manager::DarkResumeWakeReason proto;
    166   proto.set_wake_reason(wake_reason);
    167   vector<uint8_t> serialized_proto;
    168   CHECK(SerializeProtocolBuffer(proto, &serialized_proto));
    169 
    170   brillo::ErrorPtr error;
    171   if (!proxy_->RecordDarkResumeWakeReason(serialized_proto, &error)) {
    172     LOG(ERROR) << "Failed tp record dark resume wake reason: "
    173                << error->GetCode() << " " << error->GetMessage();
    174     return false;
    175   }
    176   return true;
    177 }
    178 
    179 bool ChromeosPowerManagerProxy::RegisterSuspendDelayInternal(
    180     bool is_dark,
    181     base::TimeDelta timeout,
    182     const string& description,
    183     int* delay_id_out) {
    184   const string is_dark_arg = (is_dark ? "dark=true" : "dark=false");
    185   LOG(INFO) << __func__ << "(" << timeout.InMilliseconds()
    186             << ", " << is_dark_arg <<")";
    187 
    188   power_manager::RegisterSuspendDelayRequest request_proto;
    189   request_proto.set_timeout(timeout.ToInternalValue());
    190   request_proto.set_description(description);
    191   vector<uint8_t> serialized_request;
    192   CHECK(SerializeProtocolBuffer(request_proto, &serialized_request));
    193 
    194   vector<uint8_t> serialized_reply;
    195   brillo::ErrorPtr error;
    196   if (is_dark) {
    197     proxy_->RegisterDarkSuspendDelay(serialized_request,
    198                                      &serialized_reply,
    199                                      &error);
    200   } else {
    201     proxy_->RegisterSuspendDelay(serialized_request, &serialized_reply, &error);
    202   }
    203   if (error) {
    204     LOG(ERROR) << "Failed to register suspend delay: "
    205                << error->GetCode() << " " << error->GetMessage();
    206     return false;
    207   }
    208 
    209   power_manager::RegisterSuspendDelayReply reply_proto;
    210   if (!DeserializeProtocolBuffer(serialized_reply, &reply_proto)) {
    211     LOG(ERROR) << "Failed to register "
    212                << (is_dark ? "dark " : "")
    213                << "suspend delay.  Couldn't parse response.";
    214     return false;
    215   }
    216   *delay_id_out = reply_proto.delay_id();
    217   return true;
    218 }
    219 
    220 bool ChromeosPowerManagerProxy::UnregisterSuspendDelayInternal(bool is_dark,
    221                                                                int delay_id) {
    222   const string is_dark_arg = (is_dark ? "dark=true" : "dark=false");
    223   LOG(INFO) << __func__ << "(" << delay_id << ", " << is_dark_arg << ")";
    224 
    225   power_manager::UnregisterSuspendDelayRequest request_proto;
    226   request_proto.set_delay_id(delay_id);
    227   vector<uint8_t> serialized_request;
    228   CHECK(SerializeProtocolBuffer(request_proto, &serialized_request));
    229 
    230   brillo::ErrorPtr error;
    231   if (is_dark) {
    232     proxy_->UnregisterDarkSuspendDelay(serialized_request, &error);
    233   } else {
    234     proxy_->UnregisterSuspendDelay(serialized_request, &error);
    235   }
    236   if (error) {
    237     LOG(ERROR) << "Failed to unregister suspend delay: "
    238                << error->GetCode() << " " << error->GetMessage();
    239     return false;
    240   }
    241   return true;
    242 }
    243 
    244 bool ChromeosPowerManagerProxy::ReportSuspendReadinessInternal(
    245     bool is_dark, int delay_id, int suspend_id) {
    246   const string is_dark_arg = (is_dark ? "dark=true" : "dark=false");
    247   LOG(INFO) << __func__
    248             << "(" << delay_id
    249             << ", " << suspend_id
    250             << ", " << is_dark_arg << ")";
    251 
    252   power_manager::SuspendReadinessInfo proto;
    253   proto.set_delay_id(delay_id);
    254   proto.set_suspend_id(suspend_id);
    255   vector<uint8_t> serialized_proto;
    256   CHECK(SerializeProtocolBuffer(proto, &serialized_proto));
    257 
    258   brillo::ErrorPtr error;
    259   if (is_dark) {
    260     proxy_->HandleDarkSuspendReadiness(serialized_proto, &error);
    261   } else {
    262     proxy_->HandleSuspendReadiness(serialized_proto, &error);
    263   }
    264   if (error) {
    265     LOG(ERROR) << "Failed to report suspend readiness: "
    266                << error->GetCode() << " " << error->GetMessage();
    267     return false;
    268   }
    269   return true;
    270 }
    271 
    272 void ChromeosPowerManagerProxy::SuspendImminent(
    273     const vector<uint8_t>& serialized_proto) {
    274   LOG(INFO) << __func__;
    275   power_manager::SuspendImminent proto;
    276   if (!DeserializeProtocolBuffer(serialized_proto, &proto)) {
    277     LOG(ERROR) << "Failed to parse SuspendImminent signal.";
    278     return;
    279   }
    280   delegate_->OnSuspendImminent(proto.suspend_id());
    281 }
    282 
    283 void ChromeosPowerManagerProxy::SuspendDone(
    284     const vector<uint8_t>& serialized_proto) {
    285   LOG(INFO) << __func__;
    286   power_manager::SuspendDone proto;
    287   if (!DeserializeProtocolBuffer(serialized_proto, &proto)) {
    288     LOG(ERROR) << "Failed to parse SuspendDone signal.";
    289     return;
    290   }
    291   delegate_->OnSuspendDone(proto.suspend_id());
    292 }
    293 
    294 void ChromeosPowerManagerProxy::DarkSuspendImminent(
    295     const vector<uint8_t>& serialized_proto) {
    296   LOG(INFO) << __func__;
    297   power_manager::SuspendImminent proto;
    298   if (!DeserializeProtocolBuffer(serialized_proto, &proto)) {
    299     LOG(ERROR) << "Failed to parse DarkSuspendImminent signal.";
    300     return;
    301   }
    302   delegate_->OnDarkSuspendImminent(proto.suspend_id());
    303 }
    304 
    305 void ChromeosPowerManagerProxy::OnServiceAvailable(bool available) {
    306   // The only time this function will ever be invoked with |available| set to
    307   // false is when we failed to connect the signals, either bus is not setup
    308   // yet or we failed to add match rules, and both of these errors are
    309   // considered fatal.
    310   CHECK(available);
    311 
    312   // Service is available now, continuously monitor the service owner changes.
    313   proxy_->GetObjectProxy()->SetNameOwnerChangedCallback(
    314       base::Bind(&ChromeosPowerManagerProxy::OnServiceOwnerChanged,
    315                  weak_factory_.GetWeakPtr()));
    316 
    317   // The callback might invoke calls to the ObjectProxy, so defer the callback
    318   // to event loop.
    319   if (!service_appeared_callback_.is_null()) {
    320     dispatcher_->PostTask(service_appeared_callback_);
    321   }
    322 
    323   service_available_ = true;
    324 }
    325 
    326 void ChromeosPowerManagerProxy::OnServiceOwnerChanged(
    327     const string& old_owner, const string& new_owner) {
    328   LOG(INFO) << __func__ << "old: " << old_owner << " new: " << new_owner;
    329 
    330   if (new_owner.empty()) {
    331     // The callback might invoke calls to the ObjectProxy, so defer the
    332     // callback to event loop.
    333     if (!service_vanished_callback_.is_null()) {
    334         dispatcher_->PostTask(service_vanished_callback_);
    335     }
    336     service_available_ = false;
    337   } else {
    338     // The callback might invoke calls to the ObjectProxy, so defer the
    339     // callback to event loop.
    340     if (!service_appeared_callback_.is_null()) {
    341       dispatcher_->PostTask(service_appeared_callback_);
    342     }
    343     service_available_ = true;
    344   }
    345 }
    346 
    347 void ChromeosPowerManagerProxy::OnSignalConnected(
    348     const string& interface_name, const string& signal_name, bool success) {
    349   LOG(INFO) << __func__ << " interface: " << interface_name
    350             << " signal: " << signal_name << "success: " << success;
    351   if (!success) {
    352     LOG(ERROR) << "Failed to connect signal " << signal_name
    353         << " to interface " << interface_name;
    354   }
    355 }
    356 
    357 }  // namespace shill
    358