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.
SerializeProtocolBuffer(const google::protobuf::MessageLite & protobuf,vector<uint8_t> * out)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.
DeserializeProtocolBuffer(const vector<uint8_t> & serialized_protobuf,google::protobuf::MessageLite * protobuf_out)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 
ChromeosPowerManagerProxy(EventDispatcher * dispatcher,const scoped_refptr<dbus::Bus> & bus,PowerManagerProxyDelegate * delegate,const base::Closure & service_appeared_callback,const base::Closure & service_vanished_callback)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 
~ChromeosPowerManagerProxy()92 ChromeosPowerManagerProxy::~ChromeosPowerManagerProxy() {}
93 
RegisterSuspendDelay(base::TimeDelta timeout,const string & description,int * delay_id_out)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 
UnregisterSuspendDelay(int delay_id)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 
ReportSuspendReadiness(int delay_id,int suspend_id)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 
RegisterDarkSuspendDelay(base::TimeDelta timeout,const string & description,int * delay_id_out)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 
UnregisterDarkSuspendDelay(int delay_id)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 
ReportDarkSuspendReadiness(int delay_id,int suspend_id)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 
RecordDarkResumeWakeReason(const string & wake_reason)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 
RegisterSuspendDelayInternal(bool is_dark,base::TimeDelta timeout,const string & description,int * delay_id_out)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 
UnregisterSuspendDelayInternal(bool is_dark,int delay_id)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 
ReportSuspendReadinessInternal(bool is_dark,int delay_id,int suspend_id)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 
SuspendImminent(const vector<uint8_t> & serialized_proto)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 
SuspendDone(const vector<uint8_t> & serialized_proto)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 
DarkSuspendImminent(const vector<uint8_t> & serialized_proto)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 
OnServiceAvailable(bool available)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 
OnServiceOwnerChanged(const string & old_owner,const string & new_owner)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 
OnSignalConnected(const string & interface_name,const string & signal_name,bool success)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