Adding Peter Thatcher to the owners file.
[chromium-blink-merge.git] / chromeos / dbus / debug_daemon_client.cc
blob59e98405b866f82255ae0e6953d0cdcbd4c13640
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/files/file_path.h"
15 #include "base/location.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/posix/eintr_wrapper.h"
18 #include "base/strings/string_util.h"
19 #include "base/task_runner_util.h"
20 #include "chromeos/dbus/pipe_reader.h"
21 #include "dbus/bus.h"
22 #include "dbus/message.h"
23 #include "dbus/object_path.h"
24 #include "dbus/object_proxy.h"
26 namespace {
28 // Used in DebugDaemonClient::EmptySystemStopTracingCallback().
29 void EmptyStopSystemTracingCallbackBody(
30 const scoped_refptr<base::RefCountedString>& unused_result) {
33 } // namespace
35 namespace chromeos {
37 // The DebugDaemonClient implementation used in production.
38 class DebugDaemonClientImpl : public DebugDaemonClient {
39 public:
40 DebugDaemonClientImpl() : debugdaemon_proxy_(NULL), weak_ptr_factory_(this) {}
42 ~DebugDaemonClientImpl() override {}
44 // DebugDaemonClient override.
45 void DumpDebugLogs(bool is_compressed,
46 base::File file,
47 scoped_refptr<base::TaskRunner> task_runner,
48 const GetDebugLogsCallback& callback) override {
49 dbus::FileDescriptor* file_descriptor = new dbus::FileDescriptor;
50 file_descriptor->PutValue(file.TakePlatformFile());
51 // Punt descriptor validity check to a worker thread; on return we'll
52 // issue the D-Bus request to stop tracing and collect results.
53 task_runner->PostTaskAndReply(
54 FROM_HERE,
55 base::Bind(&dbus::FileDescriptor::CheckValidity,
56 base::Unretained(file_descriptor)),
57 base::Bind(&DebugDaemonClientImpl::OnCheckValidityGetDebugLogs,
58 weak_ptr_factory_.GetWeakPtr(),
59 is_compressed,
60 base::Owned(file_descriptor),
61 callback));
64 void SetDebugMode(const std::string& subsystem,
65 const SetDebugModeCallback& callback) override {
66 dbus::MethodCall method_call(debugd::kDebugdInterface,
67 debugd::kSetDebugMode);
68 dbus::MessageWriter writer(&method_call);
69 writer.AppendString(subsystem);
70 debugdaemon_proxy_->CallMethod(
71 &method_call,
72 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
73 base::Bind(&DebugDaemonClientImpl::OnSetDebugMode,
74 weak_ptr_factory_.GetWeakPtr(),
75 callback));
78 void GetRoutes(bool numeric,
79 bool ipv6,
80 const GetRoutesCallback& callback) override {
81 dbus::MethodCall method_call(debugd::kDebugdInterface,
82 debugd::kGetRoutes);
83 dbus::MessageWriter writer(&method_call);
84 dbus::MessageWriter sub_writer(NULL);
85 writer.OpenArray("{sv}", &sub_writer);
86 dbus::MessageWriter elem_writer(NULL);
87 sub_writer.OpenDictEntry(&elem_writer);
88 elem_writer.AppendString("numeric");
89 elem_writer.AppendVariantOfBool(numeric);
90 sub_writer.CloseContainer(&elem_writer);
91 sub_writer.OpenDictEntry(&elem_writer);
92 elem_writer.AppendString("v6");
93 elem_writer.AppendVariantOfBool(ipv6);
94 sub_writer.CloseContainer(&elem_writer);
95 writer.CloseContainer(&sub_writer);
96 debugdaemon_proxy_->CallMethod(
97 &method_call,
98 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
99 base::Bind(&DebugDaemonClientImpl::OnGetRoutes,
100 weak_ptr_factory_.GetWeakPtr(),
101 callback));
104 void GetNetworkStatus(const GetNetworkStatusCallback& callback) override {
105 dbus::MethodCall method_call(debugd::kDebugdInterface,
106 debugd::kGetNetworkStatus);
107 debugdaemon_proxy_->CallMethod(
108 &method_call,
109 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
110 base::Bind(&DebugDaemonClientImpl::OnGetNetworkStatus,
111 weak_ptr_factory_.GetWeakPtr(),
112 callback));
115 void GetModemStatus(const GetModemStatusCallback& callback) override {
116 dbus::MethodCall method_call(debugd::kDebugdInterface,
117 debugd::kGetModemStatus);
118 debugdaemon_proxy_->CallMethod(
119 &method_call,
120 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
121 base::Bind(&DebugDaemonClientImpl::OnGetModemStatus,
122 weak_ptr_factory_.GetWeakPtr(),
123 callback));
126 void GetWiMaxStatus(const GetWiMaxStatusCallback& callback) override {
127 dbus::MethodCall method_call(debugd::kDebugdInterface,
128 debugd::kGetWiMaxStatus);
129 debugdaemon_proxy_->CallMethod(
130 &method_call,
131 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
132 base::Bind(&DebugDaemonClientImpl::OnGetWiMaxStatus,
133 weak_ptr_factory_.GetWeakPtr(),
134 callback));
137 void GetNetworkInterfaces(
138 const GetNetworkInterfacesCallback& callback) override {
139 dbus::MethodCall method_call(debugd::kDebugdInterface,
140 debugd::kGetInterfaces);
141 debugdaemon_proxy_->CallMethod(
142 &method_call,
143 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
144 base::Bind(&DebugDaemonClientImpl::OnGetNetworkInterfaces,
145 weak_ptr_factory_.GetWeakPtr(),
146 callback));
149 void GetPerfData(uint32_t duration,
150 const GetPerfDataCallback& callback) override {
151 dbus::MethodCall method_call(debugd::kDebugdInterface,
152 debugd::kGetRichPerfData);
153 dbus::MessageWriter writer(&method_call);
154 writer.AppendUint32(duration);
156 debugdaemon_proxy_->CallMethod(
157 &method_call,
158 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
159 base::Bind(&DebugDaemonClientImpl::OnGetPerfData,
160 weak_ptr_factory_.GetWeakPtr(),
161 callback));
164 void GetScrubbedLogs(const GetLogsCallback& callback) override {
165 dbus::MethodCall method_call(debugd::kDebugdInterface,
166 debugd::kGetFeedbackLogs);
167 debugdaemon_proxy_->CallMethod(
168 &method_call,
169 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
170 base::Bind(&DebugDaemonClientImpl::OnGetAllLogs,
171 weak_ptr_factory_.GetWeakPtr(),
172 callback));
175 void GetAllLogs(const GetLogsCallback& callback) override {
176 dbus::MethodCall method_call(debugd::kDebugdInterface,
177 debugd::kGetAllLogs);
178 debugdaemon_proxy_->CallMethod(
179 &method_call,
180 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
181 base::Bind(&DebugDaemonClientImpl::OnGetAllLogs,
182 weak_ptr_factory_.GetWeakPtr(),
183 callback));
186 void GetUserLogFiles(const GetLogsCallback& callback) override {
187 dbus::MethodCall method_call(debugd::kDebugdInterface,
188 debugd::kGetUserLogFiles);
189 debugdaemon_proxy_->CallMethod(
190 &method_call,
191 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
192 base::Bind(&DebugDaemonClientImpl::OnGetUserLogFiles,
193 weak_ptr_factory_.GetWeakPtr(),
194 callback));
197 void StartSystemTracing() override {
198 dbus::MethodCall method_call(
199 debugd::kDebugdInterface,
200 debugd::kSystraceStart);
201 dbus::MessageWriter writer(&method_call);
202 writer.AppendString("all"); // TODO(sleffler) parameterize category list
204 DVLOG(1) << "Requesting a systrace start";
205 debugdaemon_proxy_->CallMethod(
206 &method_call,
207 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
208 base::Bind(&DebugDaemonClientImpl::OnStartMethod,
209 weak_ptr_factory_.GetWeakPtr()));
212 bool RequestStopSystemTracing(
213 scoped_refptr<base::TaskRunner> task_runner,
214 const StopSystemTracingCallback& callback) override {
215 if (pipe_reader_ != NULL) {
216 LOG(ERROR) << "Busy doing StopSystemTracing";
217 return false;
220 pipe_reader_.reset(new PipeReaderForString(
221 task_runner,
222 base::Bind(&DebugDaemonClientImpl::OnIOComplete,
223 weak_ptr_factory_.GetWeakPtr())));
225 base::File pipe_write_end = pipe_reader_->StartIO();
226 // Create dbus::FileDescriptor on the worker thread; on return we'll
227 // issue the D-Bus request to stop tracing and collect results.
228 base::PostTaskAndReplyWithResult(
229 task_runner.get(),
230 FROM_HERE,
231 base::Bind(
232 &DebugDaemonClientImpl::CreateFileDescriptorToStopSystemTracing,
233 base::Passed(&pipe_write_end)),
234 base::Bind(
235 &DebugDaemonClientImpl::OnCreateFileDescriptorRequestStopSystem,
236 weak_ptr_factory_.GetWeakPtr(),
237 callback));
238 return true;
241 void TestICMP(const std::string& ip_address,
242 const TestICMPCallback& callback) override {
243 dbus::MethodCall method_call(debugd::kDebugdInterface,
244 debugd::kTestICMP);
245 dbus::MessageWriter writer(&method_call);
246 writer.AppendString(ip_address);
247 debugdaemon_proxy_->CallMethod(
248 &method_call,
249 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
250 base::Bind(&DebugDaemonClientImpl::OnTestICMP,
251 weak_ptr_factory_.GetWeakPtr(),
252 callback));
255 void TestICMPWithOptions(const std::string& ip_address,
256 const std::map<std::string, std::string>& options,
257 const TestICMPCallback& callback) override {
258 dbus::MethodCall method_call(debugd::kDebugdInterface,
259 debugd::kTestICMPWithOptions);
260 dbus::MessageWriter writer(&method_call);
261 dbus::MessageWriter sub_writer(NULL);
262 dbus::MessageWriter elem_writer(NULL);
264 // Write the host.
265 writer.AppendString(ip_address);
267 // Write the options.
268 writer.OpenArray("{ss}", &sub_writer);
269 std::map<std::string, std::string>::const_iterator it;
270 for (it = options.begin(); it != options.end(); ++it) {
271 sub_writer.OpenDictEntry(&elem_writer);
272 elem_writer.AppendString(it->first);
273 elem_writer.AppendString(it->second);
274 sub_writer.CloseContainer(&elem_writer);
276 writer.CloseContainer(&sub_writer);
278 // Call the function.
279 debugdaemon_proxy_->CallMethod(
280 &method_call,
281 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
282 base::Bind(&DebugDaemonClientImpl::OnTestICMP,
283 weak_ptr_factory_.GetWeakPtr(),
284 callback));
287 void UploadCrashes() override {
288 dbus::MethodCall method_call(debugd::kDebugdInterface,
289 debugd::kUploadCrashes);
290 debugdaemon_proxy_->CallMethod(
291 &method_call,
292 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
293 base::Bind(&DebugDaemonClientImpl::OnStartMethod,
294 weak_ptr_factory_.GetWeakPtr()));
297 void EnableDebuggingFeatures(
298 const std::string& password,
299 const EnableDebuggingCallback& callback) override {
300 dbus::MethodCall method_call(debugd::kDebugdInterface,
301 debugd::kEnableChromeDevFeatures);
302 dbus::MessageWriter writer(&method_call);
303 writer.AppendString(password);
304 debugdaemon_proxy_->CallMethod(
305 &method_call,
306 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
307 base::Bind(&DebugDaemonClientImpl::OnEnableDebuggingFeatures,
308 weak_ptr_factory_.GetWeakPtr(),
309 callback));
312 void QueryDebuggingFeatures(
313 const QueryDevFeaturesCallback& callback) override {
314 dbus::MethodCall method_call(debugd::kDebugdInterface,
315 debugd::kQueryDevFeatures);
316 dbus::MessageWriter writer(&method_call);
317 debugdaemon_proxy_->CallMethod(
318 &method_call,
319 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
320 base::Bind(&DebugDaemonClientImpl::OnQueryDebuggingFeatures,
321 weak_ptr_factory_.GetWeakPtr(),
322 callback));
325 void RemoveRootfsVerification(
326 const EnableDebuggingCallback& callback) override {
327 dbus::MethodCall method_call(debugd::kDebugdInterface,
328 debugd::kRemoveRootfsVerification);
329 dbus::MessageWriter writer(&method_call);
330 debugdaemon_proxy_->CallMethod(
331 &method_call,
332 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
333 base::Bind(&DebugDaemonClientImpl::OnRemoveRootfsVerification,
334 weak_ptr_factory_.GetWeakPtr(),
335 callback));
338 void WaitForServiceToBeAvailable(
339 const WaitForServiceToBeAvailableCallback& callback) override {
340 debugdaemon_proxy_->WaitForServiceToBeAvailable(callback);
343 protected:
344 void Init(dbus::Bus* bus) override {
345 debugdaemon_proxy_ =
346 bus->GetObjectProxy(debugd::kDebugdServiceName,
347 dbus::ObjectPath(debugd::kDebugdServicePath));
350 private:
351 // Called when a CheckValidity response is received.
352 void OnCheckValidityGetDebugLogs(bool is_compressed,
353 dbus::FileDescriptor* file_descriptor,
354 const GetDebugLogsCallback& callback) {
355 // Issue the dbus request to get debug logs.
356 dbus::MethodCall method_call(debugd::kDebugdInterface,
357 debugd::kDumpDebugLogs);
358 dbus::MessageWriter writer(&method_call);
359 writer.AppendBool(is_compressed);
360 writer.AppendFileDescriptor(*file_descriptor);
362 debugdaemon_proxy_->CallMethod(
363 &method_call,
364 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
365 base::Bind(&DebugDaemonClientImpl::OnGetDebugLogs,
366 weak_ptr_factory_.GetWeakPtr(),
367 callback));
370 // Called when a response for GetDebugLogs() is received.
371 void OnGetDebugLogs(const GetDebugLogsCallback& callback,
372 dbus::Response* response) {
373 if (!response) {
374 LOG(ERROR) << "Failed to get debug logs";
375 callback.Run(false);
376 return;
378 callback.Run(true);
381 // Called when a response for SetDebugMode() is received.
382 void OnSetDebugMode(const SetDebugModeCallback& callback,
383 dbus::Response* response) {
384 if (!response) {
385 LOG(ERROR) << "Failed to change debug mode";
386 callback.Run(false);
387 } else {
388 callback.Run(true);
392 void OnGetRoutes(const GetRoutesCallback& callback,
393 dbus::Response* response) {
394 std::vector<std::string> routes;
395 if (response) {
396 dbus::MessageReader reader(response);
397 if (reader.PopArrayOfStrings(&routes)) {
398 callback.Run(true, routes);
399 } else {
400 LOG(ERROR) << "Got non-array response from GetRoutes";
401 callback.Run(false, routes);
403 } else {
404 callback.Run(false, routes);
408 void OnGetNetworkStatus(const GetNetworkStatusCallback& callback,
409 dbus::Response* response) {
410 std::string status;
411 if (response && dbus::MessageReader(response).PopString(&status))
412 callback.Run(true, status);
413 else
414 callback.Run(false, "");
417 void OnGetModemStatus(const GetModemStatusCallback& callback,
418 dbus::Response* response) {
419 std::string status;
420 if (response && dbus::MessageReader(response).PopString(&status))
421 callback.Run(true, status);
422 else
423 callback.Run(false, "");
426 void OnGetWiMaxStatus(const GetWiMaxStatusCallback& callback,
427 dbus::Response* response) {
428 std::string status;
429 if (response && dbus::MessageReader(response).PopString(&status))
430 callback.Run(true, status);
431 else
432 callback.Run(false, "");
435 void OnGetNetworkInterfaces(const GetNetworkInterfacesCallback& callback,
436 dbus::Response* response) {
437 std::string status;
438 if (response && dbus::MessageReader(response).PopString(&status))
439 callback.Run(true, status);
440 else
441 callback.Run(false, "");
444 void OnGetPerfData(const GetPerfDataCallback& callback,
445 dbus::Response* response) {
446 std::vector<uint8> data;
448 if (!response) {
449 return;
452 dbus::MessageReader reader(response);
453 const uint8* buffer = NULL;
454 size_t buf_size = 0;
455 if (!reader.PopArrayOfBytes(&buffer, &buf_size))
456 return;
458 // TODO(asharif): Figure out a way to avoid this copy.
459 data.insert(data.end(), buffer, buffer + buf_size);
461 callback.Run(data);
464 void OnGetAllLogs(const GetLogsCallback& callback,
465 dbus::Response* response) {
466 std::map<std::string, std::string> logs;
467 bool broken = false; // did we see a broken (k,v) pair?
468 dbus::MessageReader sub_reader(NULL);
469 if (!response || !dbus::MessageReader(response).PopArray(&sub_reader)) {
470 callback.Run(false, logs);
471 return;
473 while (sub_reader.HasMoreData()) {
474 dbus::MessageReader sub_sub_reader(NULL);
475 std::string key, value;
476 if (!sub_reader.PopDictEntry(&sub_sub_reader)
477 || !sub_sub_reader.PopString(&key)
478 || !sub_sub_reader.PopString(&value)) {
479 broken = true;
480 break;
482 logs[key] = value;
484 callback.Run(!sub_reader.HasMoreData() && !broken, logs);
487 void OnGetUserLogFiles(const GetLogsCallback& callback,
488 dbus::Response* response) {
489 return OnGetAllLogs(callback, response);
492 // Called when a response for a simple start is received.
493 void OnStartMethod(dbus::Response* response) {
494 if (!response) {
495 LOG(ERROR) << "Failed to request start";
496 return;
500 void OnEnableDebuggingFeatures(
501 const EnableDebuggingCallback& callback,
502 dbus::Response* response) {
503 if (callback.is_null())
504 return;
506 callback.Run(response != NULL);
509 void OnQueryDebuggingFeatures(
510 const QueryDevFeaturesCallback& callback,
511 dbus::Response* response) {
512 if (callback.is_null())
513 return;
515 int32 feature_mask = DEV_FEATURE_NONE;
516 if (!response || !dbus::MessageReader(response).PopInt32(&feature_mask)) {
517 callback.Run(false, debugd::DevFeatureFlag::DEV_FEATURES_DISABLED);
518 return;
521 callback.Run(true, feature_mask);
524 void OnRemoveRootfsVerification(
525 const EnableDebuggingCallback& callback,
526 dbus::Response* response) {
527 if (callback.is_null())
528 return;
530 callback.Run(response != NULL);
533 // Creates dbus::FileDescriptor from base::File.
534 static scoped_ptr<dbus::FileDescriptor>
535 CreateFileDescriptorToStopSystemTracing(base::File pipe_write_end) {
536 if (!pipe_write_end.IsValid()) {
537 LOG(ERROR) << "Cannot create pipe reader";
538 // NB: continue anyway to shutdown tracing; toss trace data
539 pipe_write_end.Initialize(base::FilePath(FILE_PATH_LITERAL("/dev/null")),
540 base::File::FLAG_OPEN | base::File::FLAG_WRITE);
541 // TODO(sleffler) if this fails AppendFileDescriptor will abort
543 scoped_ptr<dbus::FileDescriptor> file_descriptor(new dbus::FileDescriptor);
544 file_descriptor->PutValue(pipe_write_end.TakePlatformFile());
545 file_descriptor->CheckValidity();
546 return file_descriptor.Pass();
549 // Called when a CheckValidity response is received.
550 void OnCreateFileDescriptorRequestStopSystem(
551 const StopSystemTracingCallback& callback,
552 scoped_ptr<dbus::FileDescriptor> file_descriptor) {
553 DCHECK(file_descriptor);
555 // Issue the dbus request to stop system tracing
556 dbus::MethodCall method_call(
557 debugd::kDebugdInterface,
558 debugd::kSystraceStop);
559 dbus::MessageWriter writer(&method_call);
560 writer.AppendFileDescriptor(*file_descriptor);
562 callback_ = callback;
564 DVLOG(1) << "Requesting a systrace stop";
565 debugdaemon_proxy_->CallMethod(
566 &method_call,
567 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
568 base::Bind(&DebugDaemonClientImpl::OnRequestStopSystemTracing,
569 weak_ptr_factory_.GetWeakPtr()));
572 // Called when a response for RequestStopSystemTracing() is received.
573 void OnRequestStopSystemTracing(dbus::Response* response) {
574 if (!response) {
575 LOG(ERROR) << "Failed to request systrace stop";
576 // If debugd crashes or completes I/O before this message is processed
577 // then pipe_reader_ can be NULL, see OnIOComplete().
578 if (pipe_reader_.get())
579 pipe_reader_->OnDataReady(-1); // terminate data stream
581 // NB: requester is signaled when i/o completes
584 void OnTestICMP(const TestICMPCallback& callback, dbus::Response* response) {
585 std::string status;
586 if (response && dbus::MessageReader(response).PopString(&status))
587 callback.Run(true, status);
588 else
589 callback.Run(false, "");
592 // Called when pipe i/o completes; pass data on and delete the instance.
593 void OnIOComplete() {
594 std::string pipe_data;
595 pipe_reader_->GetData(&pipe_data);
596 callback_.Run(base::RefCountedString::TakeString(&pipe_data));
597 pipe_reader_.reset();
600 dbus::ObjectProxy* debugdaemon_proxy_;
601 scoped_ptr<PipeReaderForString> pipe_reader_;
602 StopSystemTracingCallback callback_;
603 base::WeakPtrFactory<DebugDaemonClientImpl> weak_ptr_factory_;
605 DISALLOW_COPY_AND_ASSIGN(DebugDaemonClientImpl);
608 DebugDaemonClient::DebugDaemonClient() {
611 DebugDaemonClient::~DebugDaemonClient() {
614 // static
615 DebugDaemonClient::StopSystemTracingCallback
616 DebugDaemonClient::EmptyStopSystemTracingCallback() {
617 return base::Bind(&EmptyStopSystemTracingCallbackBody);
620 // static
621 DebugDaemonClient* DebugDaemonClient::Create() {
622 return new DebugDaemonClientImpl();
625 } // namespace chromeos