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"
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"
22 #include "dbus/message.h"
23 #include "dbus/object_path.h"
24 #include "dbus/object_proxy.h"
28 // Used in DebugDaemonClient::EmptySystemStopTracingCallback().
29 void EmptyStopSystemTracingCallbackBody(
30 const scoped_refptr
<base::RefCountedString
>& unused_result
) {
37 // The DebugDaemonClient implementation used in production.
38 class DebugDaemonClientImpl
: public DebugDaemonClient
{
40 DebugDaemonClientImpl() : debugdaemon_proxy_(NULL
), weak_ptr_factory_(this) {}
42 ~DebugDaemonClientImpl() override
{}
44 // DebugDaemonClient override.
45 void DumpDebugLogs(bool is_compressed
,
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(
55 base::Bind(&dbus::FileDescriptor::CheckValidity
,
56 base::Unretained(file_descriptor
)),
57 base::Bind(&DebugDaemonClientImpl::OnCheckValidityGetDebugLogs
,
58 weak_ptr_factory_
.GetWeakPtr(),
60 base::Owned(file_descriptor
),
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(
72 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
73 base::Bind(&DebugDaemonClientImpl::OnSetDebugMode
,
74 weak_ptr_factory_
.GetWeakPtr(),
78 void GetRoutes(bool numeric
,
80 const GetRoutesCallback
& callback
) override
{
81 dbus::MethodCall
method_call(debugd::kDebugdInterface
,
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(
98 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
99 base::Bind(&DebugDaemonClientImpl::OnGetRoutes
,
100 weak_ptr_factory_
.GetWeakPtr(),
104 void GetNetworkStatus(const GetNetworkStatusCallback
& callback
) override
{
105 dbus::MethodCall
method_call(debugd::kDebugdInterface
,
106 debugd::kGetNetworkStatus
);
107 debugdaemon_proxy_
->CallMethod(
109 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
110 base::Bind(&DebugDaemonClientImpl::OnGetNetworkStatus
,
111 weak_ptr_factory_
.GetWeakPtr(),
115 void GetModemStatus(const GetModemStatusCallback
& callback
) override
{
116 dbus::MethodCall
method_call(debugd::kDebugdInterface
,
117 debugd::kGetModemStatus
);
118 debugdaemon_proxy_
->CallMethod(
120 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
121 base::Bind(&DebugDaemonClientImpl::OnGetModemStatus
,
122 weak_ptr_factory_
.GetWeakPtr(),
126 void GetWiMaxStatus(const GetWiMaxStatusCallback
& callback
) override
{
127 dbus::MethodCall
method_call(debugd::kDebugdInterface
,
128 debugd::kGetWiMaxStatus
);
129 debugdaemon_proxy_
->CallMethod(
131 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
132 base::Bind(&DebugDaemonClientImpl::OnGetWiMaxStatus
,
133 weak_ptr_factory_
.GetWeakPtr(),
137 void GetNetworkInterfaces(
138 const GetNetworkInterfacesCallback
& callback
) override
{
139 dbus::MethodCall
method_call(debugd::kDebugdInterface
,
140 debugd::kGetInterfaces
);
141 debugdaemon_proxy_
->CallMethod(
143 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
144 base::Bind(&DebugDaemonClientImpl::OnGetNetworkInterfaces
,
145 weak_ptr_factory_
.GetWeakPtr(),
149 void GetPerfOutput(uint32_t duration
,
150 const GetPerfOutputCallback
& callback
) override
{
151 dbus::MethodCall
method_call(debugd::kDebugdInterface
,
152 debugd::kGetRandomPerfOutput
);
153 dbus::MessageWriter
writer(&method_call
);
154 writer
.AppendUint32(duration
);
156 debugdaemon_proxy_
->CallMethod(
157 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
158 base::Bind(&DebugDaemonClientImpl::OnGetPerfOutput
,
159 weak_ptr_factory_
.GetWeakPtr(), callback
));
162 void GetPerfOutput(uint32_t duration
,
163 const std::vector
<std::string
>& perf_args
,
164 const GetPerfOutputCallback
& callback
) override
{
165 dbus::MethodCall
method_call(debugd::kDebugdInterface
,
166 debugd::kGetPerfOutput
);
167 dbus::MessageWriter
writer(&method_call
);
168 writer
.AppendUint32(duration
);
169 writer
.AppendArrayOfStrings(perf_args
);
171 debugdaemon_proxy_
->CallMethod(
172 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
173 base::Bind(&DebugDaemonClientImpl::OnGetPerfOutput
,
174 weak_ptr_factory_
.GetWeakPtr(), callback
));
177 void GetScrubbedLogs(const GetLogsCallback
& callback
) override
{
178 dbus::MethodCall
method_call(debugd::kDebugdInterface
,
179 debugd::kGetFeedbackLogs
);
180 debugdaemon_proxy_
->CallMethod(
182 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
183 base::Bind(&DebugDaemonClientImpl::OnGetAllLogs
,
184 weak_ptr_factory_
.GetWeakPtr(),
188 void GetAllLogs(const GetLogsCallback
& callback
) override
{
189 dbus::MethodCall
method_call(debugd::kDebugdInterface
,
190 debugd::kGetAllLogs
);
191 debugdaemon_proxy_
->CallMethod(
193 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
194 base::Bind(&DebugDaemonClientImpl::OnGetAllLogs
,
195 weak_ptr_factory_
.GetWeakPtr(),
199 void GetUserLogFiles(const GetLogsCallback
& callback
) override
{
200 dbus::MethodCall
method_call(debugd::kDebugdInterface
,
201 debugd::kGetUserLogFiles
);
202 debugdaemon_proxy_
->CallMethod(
204 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
205 base::Bind(&DebugDaemonClientImpl::OnGetUserLogFiles
,
206 weak_ptr_factory_
.GetWeakPtr(),
210 void StartSystemTracing() override
{
211 dbus::MethodCall
method_call(
212 debugd::kDebugdInterface
,
213 debugd::kSystraceStart
);
214 dbus::MessageWriter
writer(&method_call
);
215 writer
.AppendString("all"); // TODO(sleffler) parameterize category list
217 DVLOG(1) << "Requesting a systrace start";
218 debugdaemon_proxy_
->CallMethod(
220 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
221 base::Bind(&DebugDaemonClientImpl::OnStartMethod
,
222 weak_ptr_factory_
.GetWeakPtr()));
225 bool RequestStopSystemTracing(
226 scoped_refptr
<base::TaskRunner
> task_runner
,
227 const StopSystemTracingCallback
& callback
) override
{
228 if (pipe_reader_
!= NULL
) {
229 LOG(ERROR
) << "Busy doing StopSystemTracing";
233 pipe_reader_
.reset(new PipeReaderForString(
235 base::Bind(&DebugDaemonClientImpl::OnIOComplete
,
236 weak_ptr_factory_
.GetWeakPtr())));
238 base::File pipe_write_end
= pipe_reader_
->StartIO();
239 // Create dbus::FileDescriptor on the worker thread; on return we'll
240 // issue the D-Bus request to stop tracing and collect results.
241 base::PostTaskAndReplyWithResult(
245 &DebugDaemonClientImpl::CreateFileDescriptorToStopSystemTracing
,
246 base::Passed(&pipe_write_end
)),
248 &DebugDaemonClientImpl::OnCreateFileDescriptorRequestStopSystem
,
249 weak_ptr_factory_
.GetWeakPtr(),
254 void TestICMP(const std::string
& ip_address
,
255 const TestICMPCallback
& callback
) override
{
256 dbus::MethodCall
method_call(debugd::kDebugdInterface
,
258 dbus::MessageWriter
writer(&method_call
);
259 writer
.AppendString(ip_address
);
260 debugdaemon_proxy_
->CallMethod(
262 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
263 base::Bind(&DebugDaemonClientImpl::OnTestICMP
,
264 weak_ptr_factory_
.GetWeakPtr(),
268 void TestICMPWithOptions(const std::string
& ip_address
,
269 const std::map
<std::string
, std::string
>& options
,
270 const TestICMPCallback
& callback
) override
{
271 dbus::MethodCall
method_call(debugd::kDebugdInterface
,
272 debugd::kTestICMPWithOptions
);
273 dbus::MessageWriter
writer(&method_call
);
274 dbus::MessageWriter
sub_writer(NULL
);
275 dbus::MessageWriter
elem_writer(NULL
);
278 writer
.AppendString(ip_address
);
280 // Write the options.
281 writer
.OpenArray("{ss}", &sub_writer
);
282 std::map
<std::string
, std::string
>::const_iterator it
;
283 for (it
= options
.begin(); it
!= options
.end(); ++it
) {
284 sub_writer
.OpenDictEntry(&elem_writer
);
285 elem_writer
.AppendString(it
->first
);
286 elem_writer
.AppendString(it
->second
);
287 sub_writer
.CloseContainer(&elem_writer
);
289 writer
.CloseContainer(&sub_writer
);
291 // Call the function.
292 debugdaemon_proxy_
->CallMethod(
294 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
295 base::Bind(&DebugDaemonClientImpl::OnTestICMP
,
296 weak_ptr_factory_
.GetWeakPtr(),
300 void UploadCrashes() override
{
301 dbus::MethodCall
method_call(debugd::kDebugdInterface
,
302 debugd::kUploadCrashes
);
303 debugdaemon_proxy_
->CallMethod(
305 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
306 base::Bind(&DebugDaemonClientImpl::OnStartMethod
,
307 weak_ptr_factory_
.GetWeakPtr()));
310 void EnableDebuggingFeatures(
311 const std::string
& password
,
312 const EnableDebuggingCallback
& callback
) override
{
313 dbus::MethodCall
method_call(debugd::kDebugdInterface
,
314 debugd::kEnableChromeDevFeatures
);
315 dbus::MessageWriter
writer(&method_call
);
316 writer
.AppendString(password
);
317 debugdaemon_proxy_
->CallMethod(
319 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
320 base::Bind(&DebugDaemonClientImpl::OnEnableDebuggingFeatures
,
321 weak_ptr_factory_
.GetWeakPtr(),
325 void QueryDebuggingFeatures(
326 const QueryDevFeaturesCallback
& callback
) override
{
327 dbus::MethodCall
method_call(debugd::kDebugdInterface
,
328 debugd::kQueryDevFeatures
);
329 dbus::MessageWriter
writer(&method_call
);
330 debugdaemon_proxy_
->CallMethod(
332 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
333 base::Bind(&DebugDaemonClientImpl::OnQueryDebuggingFeatures
,
334 weak_ptr_factory_
.GetWeakPtr(),
338 void RemoveRootfsVerification(
339 const EnableDebuggingCallback
& callback
) override
{
340 dbus::MethodCall
method_call(debugd::kDebugdInterface
,
341 debugd::kRemoveRootfsVerification
);
342 dbus::MessageWriter
writer(&method_call
);
343 debugdaemon_proxy_
->CallMethod(
345 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
346 base::Bind(&DebugDaemonClientImpl::OnRemoveRootfsVerification
,
347 weak_ptr_factory_
.GetWeakPtr(),
351 void WaitForServiceToBeAvailable(
352 const WaitForServiceToBeAvailableCallback
& callback
) override
{
353 debugdaemon_proxy_
->WaitForServiceToBeAvailable(callback
);
357 void Init(dbus::Bus
* bus
) override
{
359 bus
->GetObjectProxy(debugd::kDebugdServiceName
,
360 dbus::ObjectPath(debugd::kDebugdServicePath
));
364 // Called when a CheckValidity response is received.
365 void OnCheckValidityGetDebugLogs(bool is_compressed
,
366 dbus::FileDescriptor
* file_descriptor
,
367 const GetDebugLogsCallback
& callback
) {
368 // Issue the dbus request to get debug logs.
369 dbus::MethodCall
method_call(debugd::kDebugdInterface
,
370 debugd::kDumpDebugLogs
);
371 dbus::MessageWriter
writer(&method_call
);
372 writer
.AppendBool(is_compressed
);
373 writer
.AppendFileDescriptor(*file_descriptor
);
375 debugdaemon_proxy_
->CallMethod(
377 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
378 base::Bind(&DebugDaemonClientImpl::OnGetDebugLogs
,
379 weak_ptr_factory_
.GetWeakPtr(),
383 // Called when a response for GetDebugLogs() is received.
384 void OnGetDebugLogs(const GetDebugLogsCallback
& callback
,
385 dbus::Response
* response
) {
387 LOG(ERROR
) << "Failed to get debug logs";
394 // Called when a response for SetDebugMode() is received.
395 void OnSetDebugMode(const SetDebugModeCallback
& callback
,
396 dbus::Response
* response
) {
398 LOG(ERROR
) << "Failed to change debug mode";
405 void OnGetRoutes(const GetRoutesCallback
& callback
,
406 dbus::Response
* response
) {
407 std::vector
<std::string
> routes
;
409 dbus::MessageReader
reader(response
);
410 if (reader
.PopArrayOfStrings(&routes
)) {
411 callback
.Run(true, routes
);
413 LOG(ERROR
) << "Got non-array response from GetRoutes";
414 callback
.Run(false, routes
);
417 callback
.Run(false, routes
);
421 void OnGetNetworkStatus(const GetNetworkStatusCallback
& callback
,
422 dbus::Response
* response
) {
424 if (response
&& dbus::MessageReader(response
).PopString(&status
))
425 callback
.Run(true, status
);
427 callback
.Run(false, "");
430 void OnGetModemStatus(const GetModemStatusCallback
& callback
,
431 dbus::Response
* response
) {
433 if (response
&& dbus::MessageReader(response
).PopString(&status
))
434 callback
.Run(true, status
);
436 callback
.Run(false, "");
439 void OnGetWiMaxStatus(const GetWiMaxStatusCallback
& callback
,
440 dbus::Response
* response
) {
442 if (response
&& dbus::MessageReader(response
).PopString(&status
))
443 callback
.Run(true, status
);
445 callback
.Run(false, "");
448 void OnGetNetworkInterfaces(const GetNetworkInterfacesCallback
& callback
,
449 dbus::Response
* response
) {
451 if (response
&& dbus::MessageReader(response
).PopString(&status
))
452 callback
.Run(true, status
);
454 callback
.Run(false, "");
457 void OnGetPerfOutput(const GetPerfOutputCallback
& callback
,
458 dbus::Response
* response
) {
462 dbus::MessageReader
reader(response
);
465 if (!reader
.PopInt32(&status
))
468 const uint8
* buffer
= nullptr;
471 if (!reader
.PopArrayOfBytes(&buffer
, &buf_size
))
473 std::vector
<uint8
> perf_data
;
475 perf_data
.insert(perf_data
.end(), buffer
, buffer
+ buf_size
);
477 if (!reader
.PopArrayOfBytes(&buffer
, &buf_size
))
479 std::vector
<uint8
> perf_stat
;
481 perf_stat
.insert(perf_stat
.end(), buffer
, buffer
+ buf_size
);
483 callback
.Run(status
, perf_data
, perf_stat
);
486 void OnGetAllLogs(const GetLogsCallback
& callback
,
487 dbus::Response
* response
) {
488 std::map
<std::string
, std::string
> logs
;
489 bool broken
= false; // did we see a broken (k,v) pair?
490 dbus::MessageReader
sub_reader(NULL
);
491 if (!response
|| !dbus::MessageReader(response
).PopArray(&sub_reader
)) {
492 callback
.Run(false, logs
);
495 while (sub_reader
.HasMoreData()) {
496 dbus::MessageReader
sub_sub_reader(NULL
);
497 std::string key
, value
;
498 if (!sub_reader
.PopDictEntry(&sub_sub_reader
)
499 || !sub_sub_reader
.PopString(&key
)
500 || !sub_sub_reader
.PopString(&value
)) {
506 callback
.Run(!sub_reader
.HasMoreData() && !broken
, logs
);
509 void OnGetUserLogFiles(const GetLogsCallback
& callback
,
510 dbus::Response
* response
) {
511 return OnGetAllLogs(callback
, response
);
514 // Called when a response for a simple start is received.
515 void OnStartMethod(dbus::Response
* response
) {
517 LOG(ERROR
) << "Failed to request start";
522 void OnEnableDebuggingFeatures(
523 const EnableDebuggingCallback
& callback
,
524 dbus::Response
* response
) {
525 if (callback
.is_null())
528 callback
.Run(response
!= NULL
);
531 void OnQueryDebuggingFeatures(
532 const QueryDevFeaturesCallback
& callback
,
533 dbus::Response
* response
) {
534 if (callback
.is_null())
537 int32 feature_mask
= DEV_FEATURE_NONE
;
538 if (!response
|| !dbus::MessageReader(response
).PopInt32(&feature_mask
)) {
539 callback
.Run(false, debugd::DevFeatureFlag::DEV_FEATURES_DISABLED
);
543 callback
.Run(true, feature_mask
);
546 void OnRemoveRootfsVerification(
547 const EnableDebuggingCallback
& callback
,
548 dbus::Response
* response
) {
549 if (callback
.is_null())
552 callback
.Run(response
!= NULL
);
555 // Creates dbus::FileDescriptor from base::File.
556 static scoped_ptr
<dbus::FileDescriptor
>
557 CreateFileDescriptorToStopSystemTracing(base::File pipe_write_end
) {
558 if (!pipe_write_end
.IsValid()) {
559 LOG(ERROR
) << "Cannot create pipe reader";
560 // NB: continue anyway to shutdown tracing; toss trace data
561 pipe_write_end
.Initialize(base::FilePath(FILE_PATH_LITERAL("/dev/null")),
562 base::File::FLAG_OPEN
| base::File::FLAG_WRITE
);
563 // TODO(sleffler) if this fails AppendFileDescriptor will abort
565 scoped_ptr
<dbus::FileDescriptor
> file_descriptor(new dbus::FileDescriptor
);
566 file_descriptor
->PutValue(pipe_write_end
.TakePlatformFile());
567 file_descriptor
->CheckValidity();
568 return file_descriptor
.Pass();
571 // Called when a CheckValidity response is received.
572 void OnCreateFileDescriptorRequestStopSystem(
573 const StopSystemTracingCallback
& callback
,
574 scoped_ptr
<dbus::FileDescriptor
> file_descriptor
) {
575 DCHECK(file_descriptor
);
577 // Issue the dbus request to stop system tracing
578 dbus::MethodCall
method_call(
579 debugd::kDebugdInterface
,
580 debugd::kSystraceStop
);
581 dbus::MessageWriter
writer(&method_call
);
582 writer
.AppendFileDescriptor(*file_descriptor
);
584 callback_
= callback
;
586 DVLOG(1) << "Requesting a systrace stop";
587 debugdaemon_proxy_
->CallMethod(
589 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
590 base::Bind(&DebugDaemonClientImpl::OnRequestStopSystemTracing
,
591 weak_ptr_factory_
.GetWeakPtr()));
594 // Called when a response for RequestStopSystemTracing() is received.
595 void OnRequestStopSystemTracing(dbus::Response
* response
) {
597 LOG(ERROR
) << "Failed to request systrace stop";
598 // If debugd crashes or completes I/O before this message is processed
599 // then pipe_reader_ can be NULL, see OnIOComplete().
600 if (pipe_reader_
.get())
601 pipe_reader_
->OnDataReady(-1); // terminate data stream
603 // NB: requester is signaled when i/o completes
606 void OnTestICMP(const TestICMPCallback
& callback
, dbus::Response
* response
) {
608 if (response
&& dbus::MessageReader(response
).PopString(&status
))
609 callback
.Run(true, status
);
611 callback
.Run(false, "");
614 // Called when pipe i/o completes; pass data on and delete the instance.
615 void OnIOComplete() {
616 std::string pipe_data
;
617 pipe_reader_
->GetData(&pipe_data
);
618 callback_
.Run(base::RefCountedString::TakeString(&pipe_data
));
619 pipe_reader_
.reset();
622 dbus::ObjectProxy
* debugdaemon_proxy_
;
623 scoped_ptr
<PipeReaderForString
> pipe_reader_
;
624 StopSystemTracingCallback callback_
;
625 base::WeakPtrFactory
<DebugDaemonClientImpl
> weak_ptr_factory_
;
627 DISALLOW_COPY_AND_ASSIGN(DebugDaemonClientImpl
);
630 DebugDaemonClient::DebugDaemonClient() {
633 DebugDaemonClient::~DebugDaemonClient() {
637 DebugDaemonClient::StopSystemTracingCallback
638 DebugDaemonClient::EmptyStopSystemTracingCallback() {
639 return base::Bind(&EmptyStopSystemTracingCallbackBody
);
643 DebugDaemonClient
* DebugDaemonClient::Create() {
644 return new DebugDaemonClientImpl();
647 } // namespace chromeos