• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/threading/worker_pool.h"
23 #include "chromeos/dbus/pipe_reader.h"
24 #include "dbus/bus.h"
25 #include "dbus/message.h"
26 #include "dbus/object_path.h"
27 #include "dbus/object_proxy.h"
28 #include "third_party/cros_system_api/dbus/service_constants.h"
29 
30 namespace {
31 
32 // Used in DebugDaemonClient::EmptySystemStopTracingCallback().
EmptyStopSystemTracingCallbackBody(const scoped_refptr<base::RefCountedString> & unused_result)33 void EmptyStopSystemTracingCallbackBody(
34   const scoped_refptr<base::RefCountedString>& unused_result) {
35 }
36 
37 }  // namespace
38 
39 namespace chromeos {
40 
41 // The DebugDaemonClient implementation used in production.
42 class DebugDaemonClientImpl : public DebugDaemonClient {
43  public:
DebugDaemonClientImpl()44   DebugDaemonClientImpl() : debugdaemon_proxy_(NULL), weak_ptr_factory_(this) {}
45 
~DebugDaemonClientImpl()46   virtual ~DebugDaemonClientImpl() {}
47 
48   // DebugDaemonClient override.
GetDebugLogs(base::File file,const GetDebugLogsCallback & callback)49   virtual void GetDebugLogs(base::File file,
50                             const GetDebugLogsCallback& callback) OVERRIDE {
51 
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     base::WorkerPool::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                    base::Owned(file_descriptor),
63                    callback),
64         false);
65   }
66 
SetDebugMode(const std::string & subsystem,const SetDebugModeCallback & 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));
79   }
80 
GetRoutes(bool numeric,bool ipv6,const GetRoutesCallback & 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));
104   }
105 
GetNetworkStatus(const GetNetworkStatusCallback & 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));
116   }
117 
GetModemStatus(const GetModemStatusCallback & 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));
128   }
129 
GetWiMaxStatus(const GetWiMaxStatusCallback & 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));
140   }
141 
GetNetworkInterfaces(const GetNetworkInterfacesCallback & 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));
152   }
153 
GetPerfData(uint32_t duration,const GetPerfDataCallback & 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);
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 
GetScrubbedLogs(const GetLogsCallback & 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));
178   }
179 
GetAllLogs(const GetLogsCallback & 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));
190   }
191 
GetUserLogFiles(const GetLogsCallback & 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));
202   }
203 
StartSystemTracing()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 
RequestStopSystemTracing(const StopSystemTracingCallback & callback)219   virtual bool RequestStopSystemTracing(const StopSystemTracingCallback&
220       callback) OVERRIDE {
221     if (pipe_reader_ != NULL) {
222       LOG(ERROR) << "Busy doing StopSystemTracing";
223       return false;
224     }
225 
226     scoped_refptr<base::TaskRunner> task_runner =
227         base::WorkerPool::GetTaskRunner(true /* task_is_slow */);
228 
229     pipe_reader_.reset(new PipeReaderForString(
230         task_runner,
231         base::Bind(&DebugDaemonClientImpl::OnIOComplete,
232                    weak_ptr_factory_.GetWeakPtr())));
233 
234     base::File pipe_write_end = pipe_reader_->StartIO();
235     // Create dbus::FileDescriptor on the worker thread; on return we'll
236     // issue the D-Bus request to stop tracing and collect results.
237     base::PostTaskAndReplyWithResult(
238         task_runner,
239         FROM_HERE,
240         base::Bind(
241             &DebugDaemonClientImpl::CreateFileDescriptorToStopSystemTracing,
242             base::Passed(&pipe_write_end)),
243         base::Bind(
244             &DebugDaemonClientImpl::OnCreateFileDescriptorRequestStopSystem,
245             weak_ptr_factory_.GetWeakPtr(),
246             callback));
247     return true;
248   }
249 
TestICMP(const std::string & ip_address,const TestICMPCallback & callback)250   virtual void TestICMP(const std::string& ip_address,
251                         const TestICMPCallback& callback) OVERRIDE {
252     dbus::MethodCall method_call(debugd::kDebugdInterface,
253                                  debugd::kTestICMP);
254     dbus::MessageWriter writer(&method_call);
255     writer.AppendString(ip_address);
256     debugdaemon_proxy_->CallMethod(
257         &method_call,
258         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
259         base::Bind(&DebugDaemonClientImpl::OnTestICMP,
260                    weak_ptr_factory_.GetWeakPtr(),
261                    callback));
262   }
263 
TestICMPWithOptions(const std::string & ip_address,const std::map<std::string,std::string> & options,const TestICMPCallback & callback)264   virtual void TestICMPWithOptions(
265       const std::string& ip_address,
266       const std::map<std::string, std::string>& options,
267       const TestICMPCallback& callback) OVERRIDE {
268     dbus::MethodCall method_call(debugd::kDebugdInterface,
269                                  debugd::kTestICMPWithOptions);
270     dbus::MessageWriter writer(&method_call);
271     dbus::MessageWriter sub_writer(NULL);
272     dbus::MessageWriter elem_writer(NULL);
273 
274     // Write the host.
275     writer.AppendString(ip_address);
276 
277     // Write the options.
278     writer.OpenArray("{ss}", &sub_writer);
279     std::map<std::string, std::string>::const_iterator it;
280     for (it = options.begin(); it != options.end(); ++it) {
281       sub_writer.OpenDictEntry(&elem_writer);
282       elem_writer.AppendString(it->first);
283       elem_writer.AppendString(it->second);
284       sub_writer.CloseContainer(&elem_writer);
285     }
286     writer.CloseContainer(&sub_writer);
287 
288     // Call the function.
289     debugdaemon_proxy_->CallMethod(
290         &method_call,
291         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
292         base::Bind(&DebugDaemonClientImpl::OnTestICMP,
293                    weak_ptr_factory_.GetWeakPtr(),
294                    callback));
295   }
296 
UploadCrashes()297   virtual void UploadCrashes() OVERRIDE {
298     dbus::MethodCall method_call(debugd::kDebugdInterface,
299                                  debugd::kUploadCrashes);
300     debugdaemon_proxy_->CallMethod(
301         &method_call,
302         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
303         base::Bind(&DebugDaemonClientImpl::OnStartMethod,
304                    weak_ptr_factory_.GetWeakPtr()));
305   }
306 
307  protected:
Init(dbus::Bus * bus)308   virtual void Init(dbus::Bus* bus) OVERRIDE {
309     debugdaemon_proxy_ =
310         bus->GetObjectProxy(debugd::kDebugdServiceName,
311                             dbus::ObjectPath(debugd::kDebugdServicePath));
312   }
313 
314  private:
315   // Called when a CheckValidity response is received.
OnCheckValidityGetDebugLogs(dbus::FileDescriptor * file_descriptor,const GetDebugLogsCallback & callback)316   void OnCheckValidityGetDebugLogs(dbus::FileDescriptor* file_descriptor,
317                                    const GetDebugLogsCallback& callback) {
318     // Issue the dbus request to get debug logs.
319     dbus::MethodCall method_call(
320         debugd::kDebugdInterface,
321         debugd::kGetDebugLogs);
322     dbus::MessageWriter writer(&method_call);
323     writer.AppendFileDescriptor(*file_descriptor);
324 
325     debugdaemon_proxy_->CallMethod(
326         &method_call,
327         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
328         base::Bind(&DebugDaemonClientImpl::OnGetDebugLogs,
329                    weak_ptr_factory_.GetWeakPtr(),
330                    callback));
331   }
332 
333   // Called when a response for GetDebugLogs() is received.
OnGetDebugLogs(const GetDebugLogsCallback & callback,dbus::Response * response)334   void OnGetDebugLogs(const GetDebugLogsCallback& callback,
335                       dbus::Response* response) {
336     if (!response) {
337       LOG(ERROR) << "Failed to get debug logs";
338       callback.Run(false);
339       return;
340     }
341     callback.Run(true);
342   }
343 
344   // Called when a response for SetDebugMode() is received.
OnSetDebugMode(const SetDebugModeCallback & callback,dbus::Response * response)345   void OnSetDebugMode(const SetDebugModeCallback& callback,
346                       dbus::Response* response) {
347     if (!response) {
348       LOG(ERROR) << "Failed to change debug mode";
349       callback.Run(false);
350     } else {
351       callback.Run(true);
352     }
353   }
354 
OnGetRoutes(const GetRoutesCallback & callback,dbus::Response * response)355   void OnGetRoutes(const GetRoutesCallback& callback,
356                    dbus::Response* response) {
357     std::vector<std::string> routes;
358     if (response) {
359       dbus::MessageReader reader(response);
360       if (reader.PopArrayOfStrings(&routes)) {
361         callback.Run(true, routes);
362       } else {
363         LOG(ERROR) << "Got non-array response from GetRoutes";
364         callback.Run(false, routes);
365       }
366     } else {
367       callback.Run(false, routes);
368     }
369   }
370 
OnGetNetworkStatus(const GetNetworkStatusCallback & callback,dbus::Response * response)371   void OnGetNetworkStatus(const GetNetworkStatusCallback& callback,
372                           dbus::Response* response) {
373     std::string status;
374     if (response && dbus::MessageReader(response).PopString(&status))
375       callback.Run(true, status);
376     else
377       callback.Run(false, "");
378   }
379 
OnGetModemStatus(const GetModemStatusCallback & callback,dbus::Response * response)380   void OnGetModemStatus(const GetModemStatusCallback& callback,
381                         dbus::Response* response) {
382     std::string status;
383     if (response && dbus::MessageReader(response).PopString(&status))
384       callback.Run(true, status);
385     else
386       callback.Run(false, "");
387   }
388 
OnGetWiMaxStatus(const GetWiMaxStatusCallback & callback,dbus::Response * response)389   void OnGetWiMaxStatus(const GetWiMaxStatusCallback& callback,
390                         dbus::Response* response) {
391     std::string status;
392     if (response && dbus::MessageReader(response).PopString(&status))
393       callback.Run(true, status);
394     else
395       callback.Run(false, "");
396   }
397 
OnGetNetworkInterfaces(const GetNetworkInterfacesCallback & callback,dbus::Response * response)398   void OnGetNetworkInterfaces(const GetNetworkInterfacesCallback& callback,
399                               dbus::Response* response) {
400     std::string status;
401     if (response && dbus::MessageReader(response).PopString(&status))
402       callback.Run(true, status);
403     else
404       callback.Run(false, "");
405   }
406 
OnGetPerfData(const GetPerfDataCallback & callback,dbus::Response * response)407   void OnGetPerfData(const GetPerfDataCallback& callback,
408                      dbus::Response* response) {
409     std::vector<uint8> data;
410 
411     if (!response) {
412       return;
413     }
414 
415     dbus::MessageReader reader(response);
416     const uint8* buffer = NULL;
417     size_t buf_size = 0;
418     if (!reader.PopArrayOfBytes(&buffer, &buf_size))
419       return;
420 
421     // TODO(asharif): Figure out a way to avoid this copy.
422     data.insert(data.end(), buffer, buffer + buf_size);
423 
424     callback.Run(data);
425   }
426 
OnGetAllLogs(const GetLogsCallback & callback,dbus::Response * response)427   void OnGetAllLogs(const GetLogsCallback& callback,
428                     dbus::Response* response) {
429     std::map<std::string, std::string> logs;
430     bool broken = false; // did we see a broken (k,v) pair?
431     dbus::MessageReader sub_reader(NULL);
432     if (!response || !dbus::MessageReader(response).PopArray(&sub_reader)) {
433       callback.Run(false, logs);
434       return;
435     }
436     while (sub_reader.HasMoreData()) {
437       dbus::MessageReader sub_sub_reader(NULL);
438       std::string key, value;
439       if (!sub_reader.PopDictEntry(&sub_sub_reader)
440           || !sub_sub_reader.PopString(&key)
441           || !sub_sub_reader.PopString(&value)) {
442         broken = true;
443         break;
444       }
445       logs[key] = value;
446     }
447     callback.Run(!sub_reader.HasMoreData() && !broken, logs);
448   }
449 
OnGetUserLogFiles(const GetLogsCallback & callback,dbus::Response * response)450   void OnGetUserLogFiles(const GetLogsCallback& callback,
451                          dbus::Response* response) {
452     return OnGetAllLogs(callback, response);
453   }
454 
455   // Called when a response for a simple start is received.
OnStartMethod(dbus::Response * response)456   void OnStartMethod(dbus::Response* response) {
457     if (!response) {
458       LOG(ERROR) << "Failed to request start";
459       return;
460     }
461   }
462 
463   // Creates dbus::FileDescriptor from base::File.
464   static scoped_ptr<dbus::FileDescriptor>
CreateFileDescriptorToStopSystemTracing(base::File pipe_write_end)465   CreateFileDescriptorToStopSystemTracing(base::File pipe_write_end) {
466     if (!pipe_write_end.IsValid()) {
467       LOG(ERROR) << "Cannot create pipe reader";
468       // NB: continue anyway to shutdown tracing; toss trace data
469       pipe_write_end.Initialize(base::FilePath(FILE_PATH_LITERAL("/dev/null")),
470                                 base::File::FLAG_OPEN | base::File::FLAG_WRITE);
471       // TODO(sleffler) if this fails AppendFileDescriptor will abort
472     }
473     scoped_ptr<dbus::FileDescriptor> file_descriptor(new dbus::FileDescriptor);
474     file_descriptor->PutValue(pipe_write_end.TakePlatformFile());
475     file_descriptor->CheckValidity();
476     return file_descriptor.Pass();
477   }
478 
479   // Called when a CheckValidity response is received.
OnCreateFileDescriptorRequestStopSystem(const StopSystemTracingCallback & callback,scoped_ptr<dbus::FileDescriptor> file_descriptor)480   void OnCreateFileDescriptorRequestStopSystem(
481       const StopSystemTracingCallback& callback,
482       scoped_ptr<dbus::FileDescriptor> file_descriptor) {
483     DCHECK(file_descriptor);
484 
485     // Issue the dbus request to stop system tracing
486     dbus::MethodCall method_call(
487         debugd::kDebugdInterface,
488         debugd::kSystraceStop);
489     dbus::MessageWriter writer(&method_call);
490     writer.AppendFileDescriptor(*file_descriptor);
491 
492     callback_ = callback;
493 
494     DVLOG(1) << "Requesting a systrace stop";
495     debugdaemon_proxy_->CallMethod(
496         &method_call,
497         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
498         base::Bind(&DebugDaemonClientImpl::OnRequestStopSystemTracing,
499                    weak_ptr_factory_.GetWeakPtr()));
500   }
501 
502   // Called when a response for RequestStopSystemTracing() is received.
OnRequestStopSystemTracing(dbus::Response * response)503   void OnRequestStopSystemTracing(dbus::Response* response) {
504     if (!response) {
505       LOG(ERROR) << "Failed to request systrace stop";
506       // If debugd crashes or completes I/O before this message is processed
507       // then pipe_reader_ can be NULL, see OnIOComplete().
508       if (pipe_reader_.get())
509         pipe_reader_->OnDataReady(-1); // terminate data stream
510     }
511     // NB: requester is signaled when i/o completes
512   }
513 
OnTestICMP(const TestICMPCallback & callback,dbus::Response * response)514   void OnTestICMP(const TestICMPCallback& callback, dbus::Response* response) {
515     std::string status;
516     if (response && dbus::MessageReader(response).PopString(&status))
517       callback.Run(true, status);
518     else
519       callback.Run(false, "");
520   }
521 
522   // Called when pipe i/o completes; pass data on and delete the instance.
OnIOComplete()523   void OnIOComplete() {
524     std::string pipe_data;
525     pipe_reader_->GetData(&pipe_data);
526     callback_.Run(base::RefCountedString::TakeString(&pipe_data));
527     pipe_reader_.reset();
528   }
529 
530   dbus::ObjectProxy* debugdaemon_proxy_;
531   scoped_ptr<PipeReaderForString> pipe_reader_;
532   StopSystemTracingCallback callback_;
533   base::WeakPtrFactory<DebugDaemonClientImpl> weak_ptr_factory_;
534 
535   DISALLOW_COPY_AND_ASSIGN(DebugDaemonClientImpl);
536 };
537 
DebugDaemonClient()538 DebugDaemonClient::DebugDaemonClient() {
539 }
540 
~DebugDaemonClient()541 DebugDaemonClient::~DebugDaemonClient() {
542 }
543 
544 // static
545 DebugDaemonClient::StopSystemTracingCallback
EmptyStopSystemTracingCallback()546 DebugDaemonClient::EmptyStopSystemTracingCallback() {
547   return base::Bind(&EmptyStopSystemTracingCallbackBody);
548 }
549 
550 // static
Create()551 DebugDaemonClient* DebugDaemonClient::Create() {
552   return new DebugDaemonClientImpl();
553 }
554 
555 }  // namespace chromeos
556