bluetooth: Shutdown BluetoothAdapter before DBus on ChromeOS.
[chromium-blink-merge.git] / chromeos / dbus / debug_daemon_client.cc
blob3e723849138c284e84589c5221c5b559b509eefd
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.
5 #include "chromeos/dbus/debug_daemon_client.h"
7 #include <fcntl.h>
8 #include <unistd.h>
9 #include <string>
10 #include <vector>
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/callback.h"
15 #include "base/files/file_path.h"
16 #include "base/location.h"
17 #include "base/memory/ref_counted_memory.h"
18 #include "base/message_loop/message_loop.h"
19 #include "base/posix/eintr_wrapper.h"
20 #include "base/strings/string_util.h"
21 #include "base/task_runner_util.h"
22 #include "chromeos/dbus/pipe_reader.h"
23 #include "dbus/bus.h"
24 #include "dbus/message.h"
25 #include "dbus/object_path.h"
26 #include "dbus/object_proxy.h"
27 #include "third_party/cros_system_api/dbus/service_constants.h"
29 namespace {
31 // Used in DebugDaemonClient::EmptySystemStopTracingCallback().
32 void EmptyStopSystemTracingCallbackBody(
33 const scoped_refptr<base::RefCountedString>& unused_result) {
36 } // namespace
38 namespace chromeos {
40 // The DebugDaemonClient implementation used in production.
41 class DebugDaemonClientImpl : public DebugDaemonClient {
42 public:
43 DebugDaemonClientImpl() : debugdaemon_proxy_(NULL), weak_ptr_factory_(this) {}
45 ~DebugDaemonClientImpl() override {}
47 // DebugDaemonClient override.
48 void DumpDebugLogs(bool is_compressed,
49 base::File file,
50 scoped_refptr<base::TaskRunner> task_runner,
51 const GetDebugLogsCallback& callback) override {
52 dbus::FileDescriptor* file_descriptor = new dbus::FileDescriptor;
53 file_descriptor->PutValue(file.TakePlatformFile());
54 // Punt descriptor validity check to a worker thread; on return we'll
55 // issue the D-Bus request to stop tracing and collect results.
56 task_runner->PostTaskAndReply(
57 FROM_HERE,
58 base::Bind(&dbus::FileDescriptor::CheckValidity,
59 base::Unretained(file_descriptor)),
60 base::Bind(&DebugDaemonClientImpl::OnCheckValidityGetDebugLogs,
61 weak_ptr_factory_.GetWeakPtr(),
62 is_compressed,
63 base::Owned(file_descriptor),
64 callback));
67 void SetDebugMode(const std::string& subsystem,
68 const SetDebugModeCallback& callback) override {
69 dbus::MethodCall method_call(debugd::kDebugdInterface,
70 debugd::kSetDebugMode);
71 dbus::MessageWriter writer(&method_call);
72 writer.AppendString(subsystem);
73 debugdaemon_proxy_->CallMethod(
74 &method_call,
75 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
76 base::Bind(&DebugDaemonClientImpl::OnSetDebugMode,
77 weak_ptr_factory_.GetWeakPtr(),
78 callback));
81 void GetRoutes(bool numeric,
82 bool ipv6,
83 const GetRoutesCallback& callback) override {
84 dbus::MethodCall method_call(debugd::kDebugdInterface,
85 debugd::kGetRoutes);
86 dbus::MessageWriter writer(&method_call);
87 dbus::MessageWriter sub_writer(NULL);
88 writer.OpenArray("{sv}", &sub_writer);
89 dbus::MessageWriter elem_writer(NULL);
90 sub_writer.OpenDictEntry(&elem_writer);
91 elem_writer.AppendString("numeric");
92 elem_writer.AppendVariantOfBool(numeric);
93 sub_writer.CloseContainer(&elem_writer);
94 sub_writer.OpenDictEntry(&elem_writer);
95 elem_writer.AppendString("v6");
96 elem_writer.AppendVariantOfBool(ipv6);
97 sub_writer.CloseContainer(&elem_writer);
98 writer.CloseContainer(&sub_writer);
99 debugdaemon_proxy_->CallMethod(
100 &method_call,
101 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
102 base::Bind(&DebugDaemonClientImpl::OnGetRoutes,
103 weak_ptr_factory_.GetWeakPtr(),
104 callback));
107 void GetNetworkStatus(const GetNetworkStatusCallback& callback) override {
108 dbus::MethodCall method_call(debugd::kDebugdInterface,
109 debugd::kGetNetworkStatus);
110 debugdaemon_proxy_->CallMethod(
111 &method_call,
112 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
113 base::Bind(&DebugDaemonClientImpl::OnGetNetworkStatus,
114 weak_ptr_factory_.GetWeakPtr(),
115 callback));
118 void GetModemStatus(const GetModemStatusCallback& callback) override {
119 dbus::MethodCall method_call(debugd::kDebugdInterface,
120 debugd::kGetModemStatus);
121 debugdaemon_proxy_->CallMethod(
122 &method_call,
123 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
124 base::Bind(&DebugDaemonClientImpl::OnGetModemStatus,
125 weak_ptr_factory_.GetWeakPtr(),
126 callback));
129 void GetWiMaxStatus(const GetWiMaxStatusCallback& callback) override {
130 dbus::MethodCall method_call(debugd::kDebugdInterface,
131 debugd::kGetWiMaxStatus);
132 debugdaemon_proxy_->CallMethod(
133 &method_call,
134 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
135 base::Bind(&DebugDaemonClientImpl::OnGetWiMaxStatus,
136 weak_ptr_factory_.GetWeakPtr(),
137 callback));
140 void GetNetworkInterfaces(
141 const GetNetworkInterfacesCallback& callback) override {
142 dbus::MethodCall method_call(debugd::kDebugdInterface,
143 debugd::kGetInterfaces);
144 debugdaemon_proxy_->CallMethod(
145 &method_call,
146 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
147 base::Bind(&DebugDaemonClientImpl::OnGetNetworkInterfaces,
148 weak_ptr_factory_.GetWeakPtr(),
149 callback));
152 void GetPerfData(uint32_t duration,
153 const GetPerfDataCallback& callback) override {
154 dbus::MethodCall method_call(debugd::kDebugdInterface,
155 debugd::kGetRichPerfData);
156 dbus::MessageWriter writer(&method_call);
157 writer.AppendUint32(duration);
159 debugdaemon_proxy_->CallMethod(
160 &method_call,
161 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
162 base::Bind(&DebugDaemonClientImpl::OnGetPerfData,
163 weak_ptr_factory_.GetWeakPtr(),
164 callback));
167 void GetScrubbedLogs(const GetLogsCallback& callback) override {
168 dbus::MethodCall method_call(debugd::kDebugdInterface,
169 debugd::kGetFeedbackLogs);
170 debugdaemon_proxy_->CallMethod(
171 &method_call,
172 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
173 base::Bind(&DebugDaemonClientImpl::OnGetAllLogs,
174 weak_ptr_factory_.GetWeakPtr(),
175 callback));
178 void GetAllLogs(const GetLogsCallback& callback) override {
179 dbus::MethodCall method_call(debugd::kDebugdInterface,
180 debugd::kGetAllLogs);
181 debugdaemon_proxy_->CallMethod(
182 &method_call,
183 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
184 base::Bind(&DebugDaemonClientImpl::OnGetAllLogs,
185 weak_ptr_factory_.GetWeakPtr(),
186 callback));
189 void GetUserLogFiles(const GetLogsCallback& callback) override {
190 dbus::MethodCall method_call(debugd::kDebugdInterface,
191 debugd::kGetUserLogFiles);
192 debugdaemon_proxy_->CallMethod(
193 &method_call,
194 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
195 base::Bind(&DebugDaemonClientImpl::OnGetUserLogFiles,
196 weak_ptr_factory_.GetWeakPtr(),
197 callback));
200 void StartSystemTracing() override {
201 dbus::MethodCall method_call(
202 debugd::kDebugdInterface,
203 debugd::kSystraceStart);
204 dbus::MessageWriter writer(&method_call);
205 writer.AppendString("all"); // TODO(sleffler) parameterize category list
207 DVLOG(1) << "Requesting a systrace start";
208 debugdaemon_proxy_->CallMethod(
209 &method_call,
210 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
211 base::Bind(&DebugDaemonClientImpl::OnStartMethod,
212 weak_ptr_factory_.GetWeakPtr()));
215 bool RequestStopSystemTracing(
216 scoped_refptr<base::TaskRunner> task_runner,
217 const StopSystemTracingCallback& callback) override {
218 if (pipe_reader_ != NULL) {
219 LOG(ERROR) << "Busy doing StopSystemTracing";
220 return false;
223 pipe_reader_.reset(new PipeReaderForString(
224 task_runner,
225 base::Bind(&DebugDaemonClientImpl::OnIOComplete,
226 weak_ptr_factory_.GetWeakPtr())));
228 base::File pipe_write_end = pipe_reader_->StartIO();
229 // Create dbus::FileDescriptor on the worker thread; on return we'll
230 // issue the D-Bus request to stop tracing and collect results.
231 base::PostTaskAndReplyWithResult(
232 task_runner.get(),
233 FROM_HERE,
234 base::Bind(
235 &DebugDaemonClientImpl::CreateFileDescriptorToStopSystemTracing,
236 base::Passed(&pipe_write_end)),
237 base::Bind(
238 &DebugDaemonClientImpl::OnCreateFileDescriptorRequestStopSystem,
239 weak_ptr_factory_.GetWeakPtr(),
240 callback));
241 return true;
244 void TestICMP(const std::string& ip_address,
245 const TestICMPCallback& callback) override {
246 dbus::MethodCall method_call(debugd::kDebugdInterface,
247 debugd::kTestICMP);
248 dbus::MessageWriter writer(&method_call);
249 writer.AppendString(ip_address);
250 debugdaemon_proxy_->CallMethod(
251 &method_call,
252 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
253 base::Bind(&DebugDaemonClientImpl::OnTestICMP,
254 weak_ptr_factory_.GetWeakPtr(),
255 callback));
258 void TestICMPWithOptions(const std::string& ip_address,
259 const std::map<std::string, std::string>& options,
260 const TestICMPCallback& callback) override {
261 dbus::MethodCall method_call(debugd::kDebugdInterface,
262 debugd::kTestICMPWithOptions);
263 dbus::MessageWriter writer(&method_call);
264 dbus::MessageWriter sub_writer(NULL);
265 dbus::MessageWriter elem_writer(NULL);
267 // Write the host.
268 writer.AppendString(ip_address);
270 // Write the options.
271 writer.OpenArray("{ss}", &sub_writer);
272 std::map<std::string, std::string>::const_iterator it;
273 for (it = options.begin(); it != options.end(); ++it) {
274 sub_writer.OpenDictEntry(&elem_writer);
275 elem_writer.AppendString(it->first);
276 elem_writer.AppendString(it->second);
277 sub_writer.CloseContainer(&elem_writer);
279 writer.CloseContainer(&sub_writer);
281 // Call the function.
282 debugdaemon_proxy_->CallMethod(
283 &method_call,
284 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
285 base::Bind(&DebugDaemonClientImpl::OnTestICMP,
286 weak_ptr_factory_.GetWeakPtr(),
287 callback));
290 void UploadCrashes() override {
291 dbus::MethodCall method_call(debugd::kDebugdInterface,
292 debugd::kUploadCrashes);
293 debugdaemon_proxy_->CallMethod(
294 &method_call,
295 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
296 base::Bind(&DebugDaemonClientImpl::OnStartMethod,
297 weak_ptr_factory_.GetWeakPtr()));
300 void EnableDebuggingFeatures(
301 const std::string& password,
302 const EnableDebuggingCallback& callback) override {
303 dbus::MethodCall method_call(debugd::kDebugdInterface,
304 debugd::kEnableChromeDevFeatures);
305 dbus::MessageWriter writer(&method_call);
306 writer.AppendString(password);
307 debugdaemon_proxy_->CallMethod(
308 &method_call,
309 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
310 base::Bind(&DebugDaemonClientImpl::OnEnableDebuggingFeatures,
311 weak_ptr_factory_.GetWeakPtr(),
312 callback));
315 void QueryDebuggingFeatures(
316 const QueryDevFeaturesCallback& callback) override {
317 dbus::MethodCall method_call(debugd::kDebugdInterface,
318 debugd::kQueryDevFeatures);
319 dbus::MessageWriter writer(&method_call);
320 debugdaemon_proxy_->CallMethod(
321 &method_call,
322 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
323 base::Bind(&DebugDaemonClientImpl::OnQueryDebuggingFeatures,
324 weak_ptr_factory_.GetWeakPtr(),
325 callback));
328 void RemoveRootfsVerification(
329 const EnableDebuggingCallback& callback) override {
330 dbus::MethodCall method_call(debugd::kDebugdInterface,
331 debugd::kRemoveRootfsVerification);
332 dbus::MessageWriter writer(&method_call);
333 debugdaemon_proxy_->CallMethod(
334 &method_call,
335 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
336 base::Bind(&DebugDaemonClientImpl::OnRemoveRootfsVerification,
337 weak_ptr_factory_.GetWeakPtr(),
338 callback));
341 void WaitForServiceToBeAvailable(
342 const WaitForServiceToBeAvailableCallback& callback) override {
343 debugdaemon_proxy_->WaitForServiceToBeAvailable(callback);
346 protected:
347 void Init(dbus::Bus* bus) override {
348 debugdaemon_proxy_ =
349 bus->GetObjectProxy(debugd::kDebugdServiceName,
350 dbus::ObjectPath(debugd::kDebugdServicePath));
353 private:
354 // Called when a CheckValidity response is received.
355 void OnCheckValidityGetDebugLogs(bool is_compressed,
356 dbus::FileDescriptor* file_descriptor,
357 const GetDebugLogsCallback& callback) {
358 // Issue the dbus request to get debug logs.
359 dbus::MethodCall method_call(debugd::kDebugdInterface,
360 debugd::kDumpDebugLogs);
361 dbus::MessageWriter writer(&method_call);
362 writer.AppendBool(is_compressed);
363 writer.AppendFileDescriptor(*file_descriptor);
365 debugdaemon_proxy_->CallMethod(
366 &method_call,
367 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
368 base::Bind(&DebugDaemonClientImpl::OnGetDebugLogs,
369 weak_ptr_factory_.GetWeakPtr(),
370 callback));
373 // Called when a response for GetDebugLogs() is received.
374 void OnGetDebugLogs(const GetDebugLogsCallback& callback,
375 dbus::Response* response) {
376 if (!response) {
377 LOG(ERROR) << "Failed to get debug logs";
378 callback.Run(false);
379 return;
381 callback.Run(true);
384 // Called when a response for SetDebugMode() is received.
385 void OnSetDebugMode(const SetDebugModeCallback& callback,
386 dbus::Response* response) {
387 if (!response) {
388 LOG(ERROR) << "Failed to change debug mode";
389 callback.Run(false);
390 } else {
391 callback.Run(true);
395 void OnGetRoutes(const GetRoutesCallback& callback,
396 dbus::Response* response) {
397 std::vector<std::string> routes;
398 if (response) {
399 dbus::MessageReader reader(response);
400 if (reader.PopArrayOfStrings(&routes)) {
401 callback.Run(true, routes);
402 } else {
403 LOG(ERROR) << "Got non-array response from GetRoutes";
404 callback.Run(false, routes);
406 } else {
407 callback.Run(false, routes);
411 void OnGetNetworkStatus(const GetNetworkStatusCallback& callback,
412 dbus::Response* response) {
413 std::string status;
414 if (response && dbus::MessageReader(response).PopString(&status))
415 callback.Run(true, status);
416 else
417 callback.Run(false, "");
420 void OnGetModemStatus(const GetModemStatusCallback& callback,
421 dbus::Response* response) {
422 std::string status;
423 if (response && dbus::MessageReader(response).PopString(&status))
424 callback.Run(true, status);
425 else
426 callback.Run(false, "");
429 void OnGetWiMaxStatus(const GetWiMaxStatusCallback& callback,
430 dbus::Response* response) {
431 std::string status;
432 if (response && dbus::MessageReader(response).PopString(&status))
433 callback.Run(true, status);
434 else
435 callback.Run(false, "");
438 void OnGetNetworkInterfaces(const GetNetworkInterfacesCallback& callback,
439 dbus::Response* response) {
440 std::string status;
441 if (response && dbus::MessageReader(response).PopString(&status))
442 callback.Run(true, status);
443 else
444 callback.Run(false, "");
447 void OnGetPerfData(const GetPerfDataCallback& callback,
448 dbus::Response* response) {
449 std::vector<uint8> data;
451 if (!response) {
452 return;
455 dbus::MessageReader reader(response);
456 const uint8* buffer = NULL;
457 size_t buf_size = 0;
458 if (!reader.PopArrayOfBytes(&buffer, &buf_size))
459 return;
461 // TODO(asharif): Figure out a way to avoid this copy.
462 data.insert(data.end(), buffer, buffer + buf_size);
464 callback.Run(data);
467 void OnGetAllLogs(const GetLogsCallback& callback,
468 dbus::Response* response) {
469 std::map<std::string, std::string> logs;
470 bool broken = false; // did we see a broken (k,v) pair?
471 dbus::MessageReader sub_reader(NULL);
472 if (!response || !dbus::MessageReader(response).PopArray(&sub_reader)) {
473 callback.Run(false, logs);
474 return;
476 while (sub_reader.HasMoreData()) {
477 dbus::MessageReader sub_sub_reader(NULL);
478 std::string key, value;
479 if (!sub_reader.PopDictEntry(&sub_sub_reader)
480 || !sub_sub_reader.PopString(&key)
481 || !sub_sub_reader.PopString(&value)) {
482 broken = true;
483 break;
485 logs[key] = value;
487 callback.Run(!sub_reader.HasMoreData() && !broken, logs);
490 void OnGetUserLogFiles(const GetLogsCallback& callback,
491 dbus::Response* response) {
492 return OnGetAllLogs(callback, response);
495 // Called when a response for a simple start is received.
496 void OnStartMethod(dbus::Response* response) {
497 if (!response) {
498 LOG(ERROR) << "Failed to request start";
499 return;
503 void OnEnableDebuggingFeatures(
504 const EnableDebuggingCallback& callback,
505 dbus::Response* response) {
506 if (callback.is_null())
507 return;
509 callback.Run(response != NULL);
512 void OnQueryDebuggingFeatures(
513 const QueryDevFeaturesCallback& callback,
514 dbus::Response* response) {
515 if (callback.is_null())
516 return;
518 int32 feature_mask = DEV_FEATURE_NONE;
519 if (!response || !dbus::MessageReader(response).PopInt32(&feature_mask)) {
520 callback.Run(false, DEV_FEATURES_DISABLED);
521 return;
524 callback.Run(true, feature_mask);
527 void OnRemoveRootfsVerification(
528 const EnableDebuggingCallback& callback,
529 dbus::Response* response) {
530 if (callback.is_null())
531 return;
533 callback.Run(response != NULL);
536 // Creates dbus::FileDescriptor from base::File.
537 static scoped_ptr<dbus::FileDescriptor>
538 CreateFileDescriptorToStopSystemTracing(base::File pipe_write_end) {
539 if (!pipe_write_end.IsValid()) {
540 LOG(ERROR) << "Cannot create pipe reader";
541 // NB: continue anyway to shutdown tracing; toss trace data
542 pipe_write_end.Initialize(base::FilePath(FILE_PATH_LITERAL("/dev/null")),
543 base::File::FLAG_OPEN | base::File::FLAG_WRITE);
544 // TODO(sleffler) if this fails AppendFileDescriptor will abort
546 scoped_ptr<dbus::FileDescriptor> file_descriptor(new dbus::FileDescriptor);
547 file_descriptor->PutValue(pipe_write_end.TakePlatformFile());
548 file_descriptor->CheckValidity();
549 return file_descriptor.Pass();
552 // Called when a CheckValidity response is received.
553 void OnCreateFileDescriptorRequestStopSystem(
554 const StopSystemTracingCallback& callback,
555 scoped_ptr<dbus::FileDescriptor> file_descriptor) {
556 DCHECK(file_descriptor);
558 // Issue the dbus request to stop system tracing
559 dbus::MethodCall method_call(
560 debugd::kDebugdInterface,
561 debugd::kSystraceStop);
562 dbus::MessageWriter writer(&method_call);
563 writer.AppendFileDescriptor(*file_descriptor);
565 callback_ = callback;
567 DVLOG(1) << "Requesting a systrace stop";
568 debugdaemon_proxy_->CallMethod(
569 &method_call,
570 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
571 base::Bind(&DebugDaemonClientImpl::OnRequestStopSystemTracing,
572 weak_ptr_factory_.GetWeakPtr()));
575 // Called when a response for RequestStopSystemTracing() is received.
576 void OnRequestStopSystemTracing(dbus::Response* response) {
577 if (!response) {
578 LOG(ERROR) << "Failed to request systrace stop";
579 // If debugd crashes or completes I/O before this message is processed
580 // then pipe_reader_ can be NULL, see OnIOComplete().
581 if (pipe_reader_.get())
582 pipe_reader_->OnDataReady(-1); // terminate data stream
584 // NB: requester is signaled when i/o completes
587 void OnTestICMP(const TestICMPCallback& callback, dbus::Response* response) {
588 std::string status;
589 if (response && dbus::MessageReader(response).PopString(&status))
590 callback.Run(true, status);
591 else
592 callback.Run(false, "");
595 // Called when pipe i/o completes; pass data on and delete the instance.
596 void OnIOComplete() {
597 std::string pipe_data;
598 pipe_reader_->GetData(&pipe_data);
599 callback_.Run(base::RefCountedString::TakeString(&pipe_data));
600 pipe_reader_.reset();
603 dbus::ObjectProxy* debugdaemon_proxy_;
604 scoped_ptr<PipeReaderForString> pipe_reader_;
605 StopSystemTracingCallback callback_;
606 base::WeakPtrFactory<DebugDaemonClientImpl> weak_ptr_factory_;
608 DISALLOW_COPY_AND_ASSIGN(DebugDaemonClientImpl);
611 DebugDaemonClient::DebugDaemonClient() {
614 DebugDaemonClient::~DebugDaemonClient() {
617 // static
618 DebugDaemonClient::StopSystemTracingCallback
619 DebugDaemonClient::EmptyStopSystemTracingCallback() {
620 return base::Bind(&EmptyStopSystemTracingCallbackBody);
623 // static
624 DebugDaemonClient* DebugDaemonClient::Create() {
625 return new DebugDaemonClientImpl();
628 } // namespace chromeos