Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / chromeos / dbus / debug_daemon_client.cc
blob480494fc2aead5a3eeaf0d9ecd9e0fb0c5633605
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 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(
181 &method_call,
182 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
183 base::Bind(&DebugDaemonClientImpl::OnGetAllLogs,
184 weak_ptr_factory_.GetWeakPtr(),
185 callback));
188 void GetAllLogs(const GetLogsCallback& callback) override {
189 dbus::MethodCall method_call(debugd::kDebugdInterface,
190 debugd::kGetAllLogs);
191 debugdaemon_proxy_->CallMethod(
192 &method_call,
193 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
194 base::Bind(&DebugDaemonClientImpl::OnGetAllLogs,
195 weak_ptr_factory_.GetWeakPtr(),
196 callback));
199 void GetUserLogFiles(const GetLogsCallback& callback) override {
200 dbus::MethodCall method_call(debugd::kDebugdInterface,
201 debugd::kGetUserLogFiles);
202 debugdaemon_proxy_->CallMethod(
203 &method_call,
204 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
205 base::Bind(&DebugDaemonClientImpl::OnGetUserLogFiles,
206 weak_ptr_factory_.GetWeakPtr(),
207 callback));
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(
219 &method_call,
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";
230 return false;
233 pipe_reader_.reset(new PipeReaderForString(
234 task_runner,
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(
242 task_runner.get(),
243 FROM_HERE,
244 base::Bind(
245 &DebugDaemonClientImpl::CreateFileDescriptorToStopSystemTracing,
246 base::Passed(&pipe_write_end)),
247 base::Bind(
248 &DebugDaemonClientImpl::OnCreateFileDescriptorRequestStopSystem,
249 weak_ptr_factory_.GetWeakPtr(),
250 callback));
251 return true;
254 void TestICMP(const std::string& ip_address,
255 const TestICMPCallback& callback) override {
256 dbus::MethodCall method_call(debugd::kDebugdInterface,
257 debugd::kTestICMP);
258 dbus::MessageWriter writer(&method_call);
259 writer.AppendString(ip_address);
260 debugdaemon_proxy_->CallMethod(
261 &method_call,
262 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
263 base::Bind(&DebugDaemonClientImpl::OnTestICMP,
264 weak_ptr_factory_.GetWeakPtr(),
265 callback));
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);
277 // Write the host.
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(
293 &method_call,
294 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
295 base::Bind(&DebugDaemonClientImpl::OnTestICMP,
296 weak_ptr_factory_.GetWeakPtr(),
297 callback));
300 void UploadCrashes() override {
301 dbus::MethodCall method_call(debugd::kDebugdInterface,
302 debugd::kUploadCrashes);
303 debugdaemon_proxy_->CallMethod(
304 &method_call,
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(
318 &method_call,
319 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
320 base::Bind(&DebugDaemonClientImpl::OnEnableDebuggingFeatures,
321 weak_ptr_factory_.GetWeakPtr(),
322 callback));
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(
331 &method_call,
332 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
333 base::Bind(&DebugDaemonClientImpl::OnQueryDebuggingFeatures,
334 weak_ptr_factory_.GetWeakPtr(),
335 callback));
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(
344 &method_call,
345 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
346 base::Bind(&DebugDaemonClientImpl::OnRemoveRootfsVerification,
347 weak_ptr_factory_.GetWeakPtr(),
348 callback));
351 void WaitForServiceToBeAvailable(
352 const WaitForServiceToBeAvailableCallback& callback) override {
353 debugdaemon_proxy_->WaitForServiceToBeAvailable(callback);
356 protected:
357 void Init(dbus::Bus* bus) override {
358 debugdaemon_proxy_ =
359 bus->GetObjectProxy(debugd::kDebugdServiceName,
360 dbus::ObjectPath(debugd::kDebugdServicePath));
363 private:
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(
376 &method_call,
377 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
378 base::Bind(&DebugDaemonClientImpl::OnGetDebugLogs,
379 weak_ptr_factory_.GetWeakPtr(),
380 callback));
383 // Called when a response for GetDebugLogs() is received.
384 void OnGetDebugLogs(const GetDebugLogsCallback& callback,
385 dbus::Response* response) {
386 if (!response) {
387 LOG(ERROR) << "Failed to get debug logs";
388 callback.Run(false);
389 return;
391 callback.Run(true);
394 // Called when a response for SetDebugMode() is received.
395 void OnSetDebugMode(const SetDebugModeCallback& callback,
396 dbus::Response* response) {
397 if (!response) {
398 LOG(ERROR) << "Failed to change debug mode";
399 callback.Run(false);
400 } else {
401 callback.Run(true);
405 void OnGetRoutes(const GetRoutesCallback& callback,
406 dbus::Response* response) {
407 std::vector<std::string> routes;
408 if (response) {
409 dbus::MessageReader reader(response);
410 if (reader.PopArrayOfStrings(&routes)) {
411 callback.Run(true, routes);
412 } else {
413 LOG(ERROR) << "Got non-array response from GetRoutes";
414 callback.Run(false, routes);
416 } else {
417 callback.Run(false, routes);
421 void OnGetNetworkStatus(const GetNetworkStatusCallback& callback,
422 dbus::Response* response) {
423 std::string status;
424 if (response && dbus::MessageReader(response).PopString(&status))
425 callback.Run(true, status);
426 else
427 callback.Run(false, "");
430 void OnGetModemStatus(const GetModemStatusCallback& callback,
431 dbus::Response* response) {
432 std::string status;
433 if (response && dbus::MessageReader(response).PopString(&status))
434 callback.Run(true, status);
435 else
436 callback.Run(false, "");
439 void OnGetWiMaxStatus(const GetWiMaxStatusCallback& callback,
440 dbus::Response* response) {
441 std::string status;
442 if (response && dbus::MessageReader(response).PopString(&status))
443 callback.Run(true, status);
444 else
445 callback.Run(false, "");
448 void OnGetNetworkInterfaces(const GetNetworkInterfacesCallback& callback,
449 dbus::Response* response) {
450 std::string status;
451 if (response && dbus::MessageReader(response).PopString(&status))
452 callback.Run(true, status);
453 else
454 callback.Run(false, "");
457 void OnGetPerfOutput(const GetPerfOutputCallback& callback,
458 dbus::Response* response) {
459 if (!response)
460 return;
462 dbus::MessageReader reader(response);
464 int status = 0;
465 if (!reader.PopInt32(&status))
466 return;
468 const uint8* buffer = nullptr;
469 size_t buf_size = 0;
471 if (!reader.PopArrayOfBytes(&buffer, &buf_size))
472 return;
473 std::vector<uint8> perf_data;
474 if (buf_size > 0)
475 perf_data.insert(perf_data.end(), buffer, buffer + buf_size);
477 if (!reader.PopArrayOfBytes(&buffer, &buf_size))
478 return;
479 std::vector<uint8> perf_stat;
480 if (buf_size > 0)
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);
493 return;
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)) {
501 broken = true;
502 break;
504 logs[key] = 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) {
516 if (!response) {
517 LOG(ERROR) << "Failed to request start";
518 return;
522 void OnEnableDebuggingFeatures(
523 const EnableDebuggingCallback& callback,
524 dbus::Response* response) {
525 if (callback.is_null())
526 return;
528 callback.Run(response != NULL);
531 void OnQueryDebuggingFeatures(
532 const QueryDevFeaturesCallback& callback,
533 dbus::Response* response) {
534 if (callback.is_null())
535 return;
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);
540 return;
543 callback.Run(true, feature_mask);
546 void OnRemoveRootfsVerification(
547 const EnableDebuggingCallback& callback,
548 dbus::Response* response) {
549 if (callback.is_null())
550 return;
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(
588 &method_call,
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) {
596 if (!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) {
607 std::string status;
608 if (response && dbus::MessageReader(response).PopString(&status))
609 callback.Run(true, status);
610 else
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() {
636 // static
637 DebugDaemonClient::StopSystemTracingCallback
638 DebugDaemonClient::EmptyStopSystemTracingCallback() {
639 return base::Bind(&EmptyStopSystemTracingCallbackBody);
642 // static
643 DebugDaemonClient* DebugDaemonClient::Create() {
644 return new DebugDaemonClientImpl();
647 } // namespace chromeos