Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chromeos / dbus / debug_daemon_client.cc
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.
4
5 #include "chromeos/dbus/debug_daemon_client.h"
6
7 #include <fcntl.h>
8 #include <unistd.h>
9 #include <string>
10 #include <vector>
11
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"
28
29 namespace {
30
31 // Used in DebugDaemonClient::EmptySystemStopTracingCallback().
32 void EmptyStopSystemTracingCallbackBody(
33   const scoped_refptr<base::RefCountedString>& unused_result) {
34 }
35
36 }  // namespace
37
38 namespace chromeos {
39
40 // The DebugDaemonClient implementation used in production.
41 class DebugDaemonClientImpl : public DebugDaemonClient {
42  public:
43   DebugDaemonClientImpl() : debugdaemon_proxy_(NULL), weak_ptr_factory_(this) {}
44
45   virtual ~DebugDaemonClientImpl() {}
46
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));
65   }
66
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));
79   }
80
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));
104   }
105
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));
116   }
117
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));
128   }
129
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));
140   }
141
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));
152   }
153
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);
160
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));
167   }
168
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));
178   }
179
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));
190   }
191
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));
202   }
203
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
210
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()));
217   }
218
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;
225     }
226
227     pipe_reader_.reset(new PipeReaderForString(
228         task_runner,
229         base::Bind(&DebugDaemonClientImpl::OnIOComplete,
230                    weak_ptr_factory_.GetWeakPtr())));
231
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,
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;
246   }
247
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));
260   }
261
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);
271
272     // Write the host.
273     writer.AppendString(ip_address);
274
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);
283     }
284     writer.CloseContainer(&sub_writer);
285
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));
293   }
294
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()));
303   }
304
305  protected:
306   virtual void Init(dbus::Bus* bus) OVERRIDE {
307     debugdaemon_proxy_ =
308         bus->GetObjectProxy(debugd::kDebugdServiceName,
309                             dbus::ObjectPath(debugd::kDebugdServicePath));
310   }
311
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);
323
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));
330   }
331
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;
339     }
340     callback.Run(true);
341   }
342
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);
351     }
352   }
353
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);
364       }
365     } else {
366       callback.Run(false, routes);
367     }
368   }
369
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, "");
377   }
378
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, "");
386   }
387
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, "");
395   }
396
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, "");
404   }
405
406   void OnGetPerfData(const GetPerfDataCallback& callback,
407                      dbus::Response* response) {
408     std::vector<uint8> data;
409
410     if (!response) {
411       return;
412     }
413
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;
419
420     // TODO(asharif): Figure out a way to avoid this copy.
421     data.insert(data.end(), buffer, buffer + buf_size);
422
423     callback.Run(data);
424   }
425
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;
434     }
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;
443       }
444       logs[key] = value;
445     }
446     callback.Run(!sub_reader.HasMoreData() && !broken, logs);
447   }
448
449   void OnGetUserLogFiles(const GetLogsCallback& callback,
450                          dbus::Response* response) {
451     return OnGetAllLogs(callback, response);
452   }
453
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;
459     }
460   }
461
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
471     }
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();
476   }
477
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);
483
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);
490
491     callback_ = callback;
492
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()));
499   }
500
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
509     }
510     // NB: requester is signaled when i/o completes
511   }
512
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, "");
519   }
520
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();
527   }
528
529   dbus::ObjectProxy* debugdaemon_proxy_;
530   scoped_ptr<PipeReaderForString> pipe_reader_;
531   StopSystemTracingCallback callback_;
532   base::WeakPtrFactory<DebugDaemonClientImpl> weak_ptr_factory_;
533
534   DISALLOW_COPY_AND_ASSIGN(DebugDaemonClientImpl);
535 };
536
537 DebugDaemonClient::DebugDaemonClient() {
538 }
539
540 DebugDaemonClient::~DebugDaemonClient() {
541 }
542
543 // static
544 DebugDaemonClient::StopSystemTracingCallback
545 DebugDaemonClient::EmptyStopSystemTracingCallback() {
546   return base::Bind(&EmptyStopSystemTracingCallbackBody);
547 }
548
549 // static
550 DebugDaemonClient* DebugDaemonClient::Create() {
551   return new DebugDaemonClientImpl();
552 }
553
554 }  // namespace chromeos