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