4th attempt to land change to remove NativeViewportService and
[chromium-blink-merge.git] / chromeos / dbus / debug_daemon_client.cc
blobec6a6790524ba52bbeefbc655593ab736b01474c
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 virtual ~DebugDaemonClientImpl() {}
47 // DebugDaemonClient override.
48 virtual 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 virtual 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 virtual void GetRoutes(bool numeric, bool ipv6,
82 const GetRoutesCallback& callback) OVERRIDE {
83 dbus::MethodCall method_call(debugd::kDebugdInterface,
84 debugd::kGetRoutes);
85 dbus::MessageWriter writer(&method_call);
86 dbus::MessageWriter sub_writer(NULL);
87 writer.OpenArray("{sv}", &sub_writer);
88 dbus::MessageWriter elem_writer(NULL);
89 sub_writer.OpenDictEntry(&elem_writer);
90 elem_writer.AppendString("numeric");
91 elem_writer.AppendVariantOfBool(numeric);
92 sub_writer.CloseContainer(&elem_writer);
93 sub_writer.OpenDictEntry(&elem_writer);
94 elem_writer.AppendString("v6");
95 elem_writer.AppendVariantOfBool(ipv6);
96 sub_writer.CloseContainer(&elem_writer);
97 writer.CloseContainer(&sub_writer);
98 debugdaemon_proxy_->CallMethod(
99 &method_call,
100 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
101 base::Bind(&DebugDaemonClientImpl::OnGetRoutes,
102 weak_ptr_factory_.GetWeakPtr(),
103 callback));
106 virtual void GetNetworkStatus(const GetNetworkStatusCallback& callback)
107 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 virtual void GetModemStatus(const GetModemStatusCallback& callback)
119 OVERRIDE {
120 dbus::MethodCall method_call(debugd::kDebugdInterface,
121 debugd::kGetModemStatus);
122 debugdaemon_proxy_->CallMethod(
123 &method_call,
124 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
125 base::Bind(&DebugDaemonClientImpl::OnGetModemStatus,
126 weak_ptr_factory_.GetWeakPtr(),
127 callback));
130 virtual void GetWiMaxStatus(const GetWiMaxStatusCallback& callback)
131 OVERRIDE {
132 dbus::MethodCall method_call(debugd::kDebugdInterface,
133 debugd::kGetWiMaxStatus);
134 debugdaemon_proxy_->CallMethod(
135 &method_call,
136 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
137 base::Bind(&DebugDaemonClientImpl::OnGetWiMaxStatus,
138 weak_ptr_factory_.GetWeakPtr(),
139 callback));
142 virtual void GetNetworkInterfaces(
143 const GetNetworkInterfacesCallback& callback) OVERRIDE {
144 dbus::MethodCall method_call(debugd::kDebugdInterface,
145 debugd::kGetInterfaces);
146 debugdaemon_proxy_->CallMethod(
147 &method_call,
148 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
149 base::Bind(&DebugDaemonClientImpl::OnGetNetworkInterfaces,
150 weak_ptr_factory_.GetWeakPtr(),
151 callback));
154 virtual void GetPerfData(uint32_t duration,
155 const GetPerfDataCallback& callback) OVERRIDE {
156 dbus::MethodCall method_call(debugd::kDebugdInterface,
157 debugd::kGetRichPerfData);
158 dbus::MessageWriter writer(&method_call);
159 writer.AppendUint32(duration);
161 debugdaemon_proxy_->CallMethod(
162 &method_call,
163 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
164 base::Bind(&DebugDaemonClientImpl::OnGetPerfData,
165 weak_ptr_factory_.GetWeakPtr(),
166 callback));
169 virtual void GetScrubbedLogs(const GetLogsCallback& callback) OVERRIDE {
170 dbus::MethodCall method_call(debugd::kDebugdInterface,
171 debugd::kGetFeedbackLogs);
172 debugdaemon_proxy_->CallMethod(
173 &method_call,
174 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
175 base::Bind(&DebugDaemonClientImpl::OnGetAllLogs,
176 weak_ptr_factory_.GetWeakPtr(),
177 callback));
180 virtual void GetAllLogs(const GetLogsCallback& callback)
181 OVERRIDE {
182 dbus::MethodCall method_call(debugd::kDebugdInterface,
183 debugd::kGetAllLogs);
184 debugdaemon_proxy_->CallMethod(
185 &method_call,
186 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
187 base::Bind(&DebugDaemonClientImpl::OnGetAllLogs,
188 weak_ptr_factory_.GetWeakPtr(),
189 callback));
192 virtual void GetUserLogFiles(
193 const GetLogsCallback& callback) OVERRIDE {
194 dbus::MethodCall method_call(debugd::kDebugdInterface,
195 debugd::kGetUserLogFiles);
196 debugdaemon_proxy_->CallMethod(
197 &method_call,
198 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
199 base::Bind(&DebugDaemonClientImpl::OnGetUserLogFiles,
200 weak_ptr_factory_.GetWeakPtr(),
201 callback));
204 virtual void StartSystemTracing() OVERRIDE {
205 dbus::MethodCall method_call(
206 debugd::kDebugdInterface,
207 debugd::kSystraceStart);
208 dbus::MessageWriter writer(&method_call);
209 writer.AppendString("all"); // TODO(sleffler) parameterize category list
211 DVLOG(1) << "Requesting a systrace start";
212 debugdaemon_proxy_->CallMethod(
213 &method_call,
214 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
215 base::Bind(&DebugDaemonClientImpl::OnStartMethod,
216 weak_ptr_factory_.GetWeakPtr()));
219 virtual bool RequestStopSystemTracing(
220 scoped_refptr<base::TaskRunner> task_runner,
221 const StopSystemTracingCallback& callback) OVERRIDE {
222 if (pipe_reader_ != NULL) {
223 LOG(ERROR) << "Busy doing StopSystemTracing";
224 return false;
227 pipe_reader_.reset(new PipeReaderForString(
228 task_runner,
229 base::Bind(&DebugDaemonClientImpl::OnIOComplete,
230 weak_ptr_factory_.GetWeakPtr())));
232 base::File pipe_write_end = pipe_reader_->StartIO();
233 // Create dbus::FileDescriptor on the worker thread; on return we'll
234 // issue the D-Bus request to stop tracing and collect results.
235 base::PostTaskAndReplyWithResult(
236 task_runner.get(),
237 FROM_HERE,
238 base::Bind(
239 &DebugDaemonClientImpl::CreateFileDescriptorToStopSystemTracing,
240 base::Passed(&pipe_write_end)),
241 base::Bind(
242 &DebugDaemonClientImpl::OnCreateFileDescriptorRequestStopSystem,
243 weak_ptr_factory_.GetWeakPtr(),
244 callback));
245 return true;
248 virtual void TestICMP(const std::string& ip_address,
249 const TestICMPCallback& callback) OVERRIDE {
250 dbus::MethodCall method_call(debugd::kDebugdInterface,
251 debugd::kTestICMP);
252 dbus::MessageWriter writer(&method_call);
253 writer.AppendString(ip_address);
254 debugdaemon_proxy_->CallMethod(
255 &method_call,
256 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
257 base::Bind(&DebugDaemonClientImpl::OnTestICMP,
258 weak_ptr_factory_.GetWeakPtr(),
259 callback));
262 virtual void TestICMPWithOptions(
263 const std::string& ip_address,
264 const std::map<std::string, std::string>& options,
265 const TestICMPCallback& callback) OVERRIDE {
266 dbus::MethodCall method_call(debugd::kDebugdInterface,
267 debugd::kTestICMPWithOptions);
268 dbus::MessageWriter writer(&method_call);
269 dbus::MessageWriter sub_writer(NULL);
270 dbus::MessageWriter elem_writer(NULL);
272 // Write the host.
273 writer.AppendString(ip_address);
275 // Write the options.
276 writer.OpenArray("{ss}", &sub_writer);
277 std::map<std::string, std::string>::const_iterator it;
278 for (it = options.begin(); it != options.end(); ++it) {
279 sub_writer.OpenDictEntry(&elem_writer);
280 elem_writer.AppendString(it->first);
281 elem_writer.AppendString(it->second);
282 sub_writer.CloseContainer(&elem_writer);
284 writer.CloseContainer(&sub_writer);
286 // Call the function.
287 debugdaemon_proxy_->CallMethod(
288 &method_call,
289 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
290 base::Bind(&DebugDaemonClientImpl::OnTestICMP,
291 weak_ptr_factory_.GetWeakPtr(),
292 callback));
295 virtual void UploadCrashes() OVERRIDE {
296 dbus::MethodCall method_call(debugd::kDebugdInterface,
297 debugd::kUploadCrashes);
298 debugdaemon_proxy_->CallMethod(
299 &method_call,
300 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
301 base::Bind(&DebugDaemonClientImpl::OnStartMethod,
302 weak_ptr_factory_.GetWeakPtr()));
305 protected:
306 virtual void Init(dbus::Bus* bus) OVERRIDE {
307 debugdaemon_proxy_ =
308 bus->GetObjectProxy(debugd::kDebugdServiceName,
309 dbus::ObjectPath(debugd::kDebugdServicePath));
312 private:
313 // Called when a CheckValidity response is received.
314 void OnCheckValidityGetDebugLogs(bool is_compressed,
315 dbus::FileDescriptor* file_descriptor,
316 const GetDebugLogsCallback& callback) {
317 // Issue the dbus request to get debug logs.
318 dbus::MethodCall method_call(debugd::kDebugdInterface,
319 debugd::kDumpDebugLogs);
320 dbus::MessageWriter writer(&method_call);
321 writer.AppendBool(is_compressed);
322 writer.AppendFileDescriptor(*file_descriptor);
324 debugdaemon_proxy_->CallMethod(
325 &method_call,
326 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
327 base::Bind(&DebugDaemonClientImpl::OnGetDebugLogs,
328 weak_ptr_factory_.GetWeakPtr(),
329 callback));
332 // Called when a response for GetDebugLogs() is received.
333 void OnGetDebugLogs(const GetDebugLogsCallback& callback,
334 dbus::Response* response) {
335 if (!response) {
336 LOG(ERROR) << "Failed to get debug logs";
337 callback.Run(false);
338 return;
340 callback.Run(true);
343 // Called when a response for SetDebugMode() is received.
344 void OnSetDebugMode(const SetDebugModeCallback& callback,
345 dbus::Response* response) {
346 if (!response) {
347 LOG(ERROR) << "Failed to change debug mode";
348 callback.Run(false);
349 } else {
350 callback.Run(true);
354 void OnGetRoutes(const GetRoutesCallback& callback,
355 dbus::Response* response) {
356 std::vector<std::string> routes;
357 if (response) {
358 dbus::MessageReader reader(response);
359 if (reader.PopArrayOfStrings(&routes)) {
360 callback.Run(true, routes);
361 } else {
362 LOG(ERROR) << "Got non-array response from GetRoutes";
363 callback.Run(false, routes);
365 } else {
366 callback.Run(false, routes);
370 void OnGetNetworkStatus(const GetNetworkStatusCallback& callback,
371 dbus::Response* response) {
372 std::string status;
373 if (response && dbus::MessageReader(response).PopString(&status))
374 callback.Run(true, status);
375 else
376 callback.Run(false, "");
379 void OnGetModemStatus(const GetModemStatusCallback& callback,
380 dbus::Response* response) {
381 std::string status;
382 if (response && dbus::MessageReader(response).PopString(&status))
383 callback.Run(true, status);
384 else
385 callback.Run(false, "");
388 void OnGetWiMaxStatus(const GetWiMaxStatusCallback& callback,
389 dbus::Response* response) {
390 std::string status;
391 if (response && dbus::MessageReader(response).PopString(&status))
392 callback.Run(true, status);
393 else
394 callback.Run(false, "");
397 void OnGetNetworkInterfaces(const GetNetworkInterfacesCallback& callback,
398 dbus::Response* response) {
399 std::string status;
400 if (response && dbus::MessageReader(response).PopString(&status))
401 callback.Run(true, status);
402 else
403 callback.Run(false, "");
406 void OnGetPerfData(const GetPerfDataCallback& callback,
407 dbus::Response* response) {
408 std::vector<uint8> data;
410 if (!response) {
411 return;
414 dbus::MessageReader reader(response);
415 const uint8* buffer = NULL;
416 size_t buf_size = 0;
417 if (!reader.PopArrayOfBytes(&buffer, &buf_size))
418 return;
420 // TODO(asharif): Figure out a way to avoid this copy.
421 data.insert(data.end(), buffer, buffer + buf_size);
423 callback.Run(data);
426 void OnGetAllLogs(const GetLogsCallback& callback,
427 dbus::Response* response) {
428 std::map<std::string, std::string> logs;
429 bool broken = false; // did we see a broken (k,v) pair?
430 dbus::MessageReader sub_reader(NULL);
431 if (!response || !dbus::MessageReader(response).PopArray(&sub_reader)) {
432 callback.Run(false, logs);
433 return;
435 while (sub_reader.HasMoreData()) {
436 dbus::MessageReader sub_sub_reader(NULL);
437 std::string key, value;
438 if (!sub_reader.PopDictEntry(&sub_sub_reader)
439 || !sub_sub_reader.PopString(&key)
440 || !sub_sub_reader.PopString(&value)) {
441 broken = true;
442 break;
444 logs[key] = value;
446 callback.Run(!sub_reader.HasMoreData() && !broken, logs);
449 void OnGetUserLogFiles(const GetLogsCallback& callback,
450 dbus::Response* response) {
451 return OnGetAllLogs(callback, response);
454 // Called when a response for a simple start is received.
455 void OnStartMethod(dbus::Response* response) {
456 if (!response) {
457 LOG(ERROR) << "Failed to request start";
458 return;
462 // Creates dbus::FileDescriptor from base::File.
463 static scoped_ptr<dbus::FileDescriptor>
464 CreateFileDescriptorToStopSystemTracing(base::File pipe_write_end) {
465 if (!pipe_write_end.IsValid()) {
466 LOG(ERROR) << "Cannot create pipe reader";
467 // NB: continue anyway to shutdown tracing; toss trace data
468 pipe_write_end.Initialize(base::FilePath(FILE_PATH_LITERAL("/dev/null")),
469 base::File::FLAG_OPEN | base::File::FLAG_WRITE);
470 // TODO(sleffler) if this fails AppendFileDescriptor will abort
472 scoped_ptr<dbus::FileDescriptor> file_descriptor(new dbus::FileDescriptor);
473 file_descriptor->PutValue(pipe_write_end.TakePlatformFile());
474 file_descriptor->CheckValidity();
475 return file_descriptor.Pass();
478 // Called when a CheckValidity response is received.
479 void OnCreateFileDescriptorRequestStopSystem(
480 const StopSystemTracingCallback& callback,
481 scoped_ptr<dbus::FileDescriptor> file_descriptor) {
482 DCHECK(file_descriptor);
484 // Issue the dbus request to stop system tracing
485 dbus::MethodCall method_call(
486 debugd::kDebugdInterface,
487 debugd::kSystraceStop);
488 dbus::MessageWriter writer(&method_call);
489 writer.AppendFileDescriptor(*file_descriptor);
491 callback_ = callback;
493 DVLOG(1) << "Requesting a systrace stop";
494 debugdaemon_proxy_->CallMethod(
495 &method_call,
496 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
497 base::Bind(&DebugDaemonClientImpl::OnRequestStopSystemTracing,
498 weak_ptr_factory_.GetWeakPtr()));
501 // Called when a response for RequestStopSystemTracing() is received.
502 void OnRequestStopSystemTracing(dbus::Response* response) {
503 if (!response) {
504 LOG(ERROR) << "Failed to request systrace stop";
505 // If debugd crashes or completes I/O before this message is processed
506 // then pipe_reader_ can be NULL, see OnIOComplete().
507 if (pipe_reader_.get())
508 pipe_reader_->OnDataReady(-1); // terminate data stream
510 // NB: requester is signaled when i/o completes
513 void OnTestICMP(const TestICMPCallback& callback, dbus::Response* response) {
514 std::string status;
515 if (response && dbus::MessageReader(response).PopString(&status))
516 callback.Run(true, status);
517 else
518 callback.Run(false, "");
521 // Called when pipe i/o completes; pass data on and delete the instance.
522 void OnIOComplete() {
523 std::string pipe_data;
524 pipe_reader_->GetData(&pipe_data);
525 callback_.Run(base::RefCountedString::TakeString(&pipe_data));
526 pipe_reader_.reset();
529 dbus::ObjectProxy* debugdaemon_proxy_;
530 scoped_ptr<PipeReaderForString> pipe_reader_;
531 StopSystemTracingCallback callback_;
532 base::WeakPtrFactory<DebugDaemonClientImpl> weak_ptr_factory_;
534 DISALLOW_COPY_AND_ASSIGN(DebugDaemonClientImpl);
537 DebugDaemonClient::DebugDaemonClient() {
540 DebugDaemonClient::~DebugDaemonClient() {
543 // static
544 DebugDaemonClient::StopSystemTracingCallback
545 DebugDaemonClient::EmptyStopSystemTracingCallback() {
546 return base::Bind(&EmptyStopSystemTracingCallbackBody);
549 // static
550 DebugDaemonClient* DebugDaemonClient::Create() {
551 return new DebugDaemonClientImpl();
554 } // namespace chromeos