Home | History | Annotate | Download | only in dbus
      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/location.h"
     16 #include "base/memory/ref_counted_memory.h"
     17 #include "base/message_loop/message_loop.h"
     18 #include "base/platform_file.h"
     19 #include "base/posix/eintr_wrapper.h"
     20 #include "base/strings/string_util.h"
     21 #include "base/threading/worker_pool.h"
     22 #include "dbus/bus.h"
     23 #include "dbus/message.h"
     24 #include "dbus/object_path.h"
     25 #include "dbus/object_proxy.h"
     26 #include "net/base/file_stream.h"
     27 #include "net/base/io_buffer.h"
     28 #include "net/base/net_errors.h"
     29 #include "third_party/cros_system_api/dbus/service_constants.h"
     30 
     31 namespace {
     32 
     33 // Used in DebugDaemonClient::EmptySystemStopTracingCallback().
     34 void EmptyStopSystemTracingCallbackBody(
     35   const scoped_refptr<base::RefCountedString>& unused_result) {
     36 }
     37 
     38 // Simple class to encapsulate collecting data from a pipe into a
     39 // string.  To use, instantiate the class, start i/o, and then delete
     40 // the instance on callback.  The data should be retrieved before
     41 // delete and extracted or copied.
     42 //
     43 // TODO(sleffler) move data collection to a sub-class so this
     44 // can be reused to process data as it is received
     45 class PipeReader {
     46  public:
     47   typedef base::Callback<void(void)>IOCompleteCallback;
     48 
     49   explicit PipeReader(IOCompleteCallback callback)
     50       : io_buffer_(new net::IOBufferWithSize(4096)),
     51         callback_(callback),
     52         weak_ptr_factory_(this) {
     53     pipe_fd_[0] = pipe_fd_[1] = -1;
     54   }
     55 
     56   virtual ~PipeReader() {
     57     // Don't close pipe_fd_[0] as it's closed by data_stream_.
     58     if (pipe_fd_[1] != -1)
     59       if (IGNORE_EINTR(close(pipe_fd_[1])) < 0)
     60         PLOG(ERROR) << "close[1]";
     61   }
     62 
     63   // Returns descriptor for the writeable side of the pipe.
     64   int GetWriteFD() { return pipe_fd_[1]; }
     65 
     66   // Closes writeable descriptor; normally used in parent process after fork.
     67   void CloseWriteFD() {
     68     if (pipe_fd_[1] != -1) {
     69       if (IGNORE_EINTR(close(pipe_fd_[1])) < 0)
     70         PLOG(ERROR) << "close";
     71       pipe_fd_[1] = -1;
     72     }
     73   }
     74 
     75   // Returns collected data.
     76   std::string* data() { return &data_; }
     77 
     78   // Starts data collection.  Returns true if stream was setup correctly.
     79   // On success data will automatically be accumulated into a string that
     80   // can be retrieved with PipeReader::data().  To shutdown collection delete
     81   // the instance and/or use PipeReader::OnDataReady(-1).
     82   bool StartIO() {
     83     // Use a pipe to collect data
     84     const int status = HANDLE_EINTR(pipe(pipe_fd_));
     85     if (status < 0) {
     86       PLOG(ERROR) << "pipe";
     87       return false;
     88     }
     89     base::PlatformFile data_file_ = pipe_fd_[0];  // read side
     90     data_stream_.reset(new net::FileStream(data_file_,
     91         base::PLATFORM_FILE_READ | base::PLATFORM_FILE_ASYNC,
     92         NULL));
     93 
     94     // Post an initial async read to setup data collection
     95     int rv = data_stream_->Read(io_buffer_.get(), io_buffer_->size(),
     96         base::Bind(&PipeReader::OnDataReady, weak_ptr_factory_.GetWeakPtr()));
     97     if (rv != net::ERR_IO_PENDING) {
     98       LOG(ERROR) << "Unable to post initial read";
     99       return false;
    100     }
    101     return true;
    102   }
    103 
    104   // Called when pipe data are available.  Can also be used to shutdown
    105   // data collection by passing -1 for |byte_count|.
    106   void OnDataReady(int byte_count) {
    107     DVLOG(1) << "OnDataReady byte_count " << byte_count;
    108     if (byte_count <= 0) {
    109       callback_.Run();  // signal creator to take data and delete us
    110       return;
    111     }
    112     data_.append(io_buffer_->data(), byte_count);
    113 
    114     // Post another read
    115     int rv = data_stream_->Read(io_buffer_.get(), io_buffer_->size(),
    116         base::Bind(&PipeReader::OnDataReady, weak_ptr_factory_.GetWeakPtr()));
    117     if (rv != net::ERR_IO_PENDING) {
    118       LOG(ERROR) << "Unable to post another read";
    119       // TODO(sleffler) do something more intelligent?
    120     }
    121   }
    122 
    123  private:
    124   friend class base::RefCounted<PipeReader>;
    125 
    126   int pipe_fd_[2];
    127   scoped_ptr<net::FileStream> data_stream_;
    128   scoped_refptr<net::IOBufferWithSize> io_buffer_;
    129   std::string data_;
    130   IOCompleteCallback callback_;
    131 
    132   // Note: This should remain the last member so it'll be destroyed and
    133   // invalidate its weak pointers before any other members are destroyed.
    134   base::WeakPtrFactory<PipeReader> weak_ptr_factory_;
    135 
    136   DISALLOW_COPY_AND_ASSIGN(PipeReader);
    137 };
    138 
    139 }  // namespace
    140 
    141 namespace chromeos {
    142 
    143 // The DebugDaemonClient implementation used in production.
    144 class DebugDaemonClientImpl : public DebugDaemonClient {
    145  public:
    146   DebugDaemonClientImpl() : debugdaemon_proxy_(NULL), weak_ptr_factory_(this) {}
    147 
    148   virtual ~DebugDaemonClientImpl() {}
    149 
    150   // DebugDaemonClient override.
    151   virtual void GetDebugLogs(base::PlatformFile file,
    152                             const GetDebugLogsCallback& callback) OVERRIDE {
    153 
    154     dbus::FileDescriptor* file_descriptor = new dbus::FileDescriptor(file);
    155     // Punt descriptor validity check to a worker thread; on return we'll
    156     // issue the D-Bus request to stop tracing and collect results.
    157     base::WorkerPool::PostTaskAndReply(
    158         FROM_HERE,
    159         base::Bind(&DebugDaemonClientImpl::CheckValidity,
    160                    file_descriptor),
    161         base::Bind(&DebugDaemonClientImpl::OnCheckValidityGetDebugLogs,
    162                    weak_ptr_factory_.GetWeakPtr(),
    163                    base::Owned(file_descriptor),
    164                    callback),
    165         false);
    166   }
    167 
    168   virtual void SetDebugMode(const std::string& subsystem,
    169                             const SetDebugModeCallback& callback) OVERRIDE {
    170     dbus::MethodCall method_call(debugd::kDebugdInterface,
    171                                  debugd::kSetDebugMode);
    172     dbus::MessageWriter writer(&method_call);
    173     writer.AppendString(subsystem);
    174     debugdaemon_proxy_->CallMethod(
    175         &method_call,
    176         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    177         base::Bind(&DebugDaemonClientImpl::OnSetDebugMode,
    178                    weak_ptr_factory_.GetWeakPtr(),
    179                    callback));
    180   }
    181 
    182   virtual void GetRoutes(bool numeric, bool ipv6,
    183                          const GetRoutesCallback& callback) OVERRIDE {
    184     dbus::MethodCall method_call(debugd::kDebugdInterface,
    185                                  debugd::kGetRoutes);
    186     dbus::MessageWriter writer(&method_call);
    187     dbus::MessageWriter sub_writer(NULL);
    188     writer.OpenArray("{sv}", &sub_writer);
    189     dbus::MessageWriter elem_writer(NULL);
    190     sub_writer.OpenDictEntry(&elem_writer);
    191     elem_writer.AppendString("numeric");
    192     elem_writer.AppendVariantOfBool(numeric);
    193     sub_writer.CloseContainer(&elem_writer);
    194     sub_writer.OpenDictEntry(&elem_writer);
    195     elem_writer.AppendString("v6");
    196     elem_writer.AppendVariantOfBool(ipv6);
    197     sub_writer.CloseContainer(&elem_writer);
    198     writer.CloseContainer(&sub_writer);
    199     debugdaemon_proxy_->CallMethod(
    200         &method_call,
    201         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    202         base::Bind(&DebugDaemonClientImpl::OnGetRoutes,
    203                    weak_ptr_factory_.GetWeakPtr(),
    204                    callback));
    205   }
    206 
    207   virtual void GetNetworkStatus(const GetNetworkStatusCallback& callback)
    208       OVERRIDE {
    209     dbus::MethodCall method_call(debugd::kDebugdInterface,
    210                                  debugd::kGetNetworkStatus);
    211     debugdaemon_proxy_->CallMethod(
    212         &method_call,
    213         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    214         base::Bind(&DebugDaemonClientImpl::OnGetNetworkStatus,
    215                    weak_ptr_factory_.GetWeakPtr(),
    216                    callback));
    217   }
    218 
    219   virtual void GetModemStatus(const GetModemStatusCallback& callback)
    220       OVERRIDE {
    221     dbus::MethodCall method_call(debugd::kDebugdInterface,
    222                                  debugd::kGetModemStatus);
    223     debugdaemon_proxy_->CallMethod(
    224         &method_call,
    225         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    226         base::Bind(&DebugDaemonClientImpl::OnGetModemStatus,
    227                    weak_ptr_factory_.GetWeakPtr(),
    228                    callback));
    229   }
    230 
    231   virtual void GetWiMaxStatus(const GetWiMaxStatusCallback& callback)
    232       OVERRIDE {
    233     dbus::MethodCall method_call(debugd::kDebugdInterface,
    234                                  debugd::kGetWiMaxStatus);
    235     debugdaemon_proxy_->CallMethod(
    236         &method_call,
    237         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    238         base::Bind(&DebugDaemonClientImpl::OnGetWiMaxStatus,
    239                    weak_ptr_factory_.GetWeakPtr(),
    240                    callback));
    241   }
    242 
    243   virtual void GetNetworkInterfaces(
    244       const GetNetworkInterfacesCallback& callback) OVERRIDE {
    245     dbus::MethodCall method_call(debugd::kDebugdInterface,
    246                                  debugd::kGetInterfaces);
    247     debugdaemon_proxy_->CallMethod(
    248         &method_call,
    249         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    250         base::Bind(&DebugDaemonClientImpl::OnGetNetworkInterfaces,
    251                    weak_ptr_factory_.GetWeakPtr(),
    252                    callback));
    253   }
    254 
    255   virtual void GetPerfData(uint32_t duration,
    256                            const GetPerfDataCallback& callback) OVERRIDE {
    257     dbus::MethodCall method_call(debugd::kDebugdInterface,
    258                                  debugd::kGetRichPerfData);
    259     dbus::MessageWriter writer(&method_call);
    260     writer.AppendUint32(duration);
    261 
    262     debugdaemon_proxy_->CallMethod(
    263         &method_call,
    264         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    265         base::Bind(&DebugDaemonClientImpl::OnGetPerfData,
    266                    weak_ptr_factory_.GetWeakPtr(),
    267                    callback));
    268   }
    269 
    270   virtual void GetScrubbedLogs(const GetLogsCallback& callback) OVERRIDE {
    271     dbus::MethodCall method_call(debugd::kDebugdInterface,
    272                                  debugd::kGetFeedbackLogs);
    273     debugdaemon_proxy_->CallMethod(
    274         &method_call,
    275         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    276         base::Bind(&DebugDaemonClientImpl::OnGetAllLogs,
    277                    weak_ptr_factory_.GetWeakPtr(),
    278                    callback));
    279   }
    280 
    281   virtual void GetAllLogs(const GetLogsCallback& callback)
    282       OVERRIDE {
    283     dbus::MethodCall method_call(debugd::kDebugdInterface,
    284                                  debugd::kGetAllLogs);
    285     debugdaemon_proxy_->CallMethod(
    286         &method_call,
    287         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    288         base::Bind(&DebugDaemonClientImpl::OnGetAllLogs,
    289                    weak_ptr_factory_.GetWeakPtr(),
    290                    callback));
    291   }
    292 
    293   virtual void GetUserLogFiles(
    294       const GetLogsCallback& callback) OVERRIDE {
    295     dbus::MethodCall method_call(debugd::kDebugdInterface,
    296                                  debugd::kGetUserLogFiles);
    297     debugdaemon_proxy_->CallMethod(
    298         &method_call,
    299         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    300         base::Bind(&DebugDaemonClientImpl::OnGetUserLogFiles,
    301                    weak_ptr_factory_.GetWeakPtr(),
    302                    callback));
    303   }
    304 
    305   virtual void StartSystemTracing() OVERRIDE {
    306     dbus::MethodCall method_call(
    307         debugd::kDebugdInterface,
    308         debugd::kSystraceStart);
    309     dbus::MessageWriter writer(&method_call);
    310     writer.AppendString("all"); // TODO(sleffler) parameterize category list
    311 
    312     DVLOG(1) << "Requesting a systrace start";
    313     debugdaemon_proxy_->CallMethod(
    314         &method_call,
    315         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    316         base::Bind(&DebugDaemonClientImpl::OnStartSystemTracing,
    317                    weak_ptr_factory_.GetWeakPtr()));
    318   }
    319 
    320   virtual bool RequestStopSystemTracing(const StopSystemTracingCallback&
    321       callback) OVERRIDE {
    322     if (pipe_reader_ != NULL) {
    323       LOG(ERROR) << "Busy doing StopSystemTracing";
    324       return false;
    325     }
    326 
    327     pipe_reader_.reset(new PipeReader(
    328         base::Bind(&DebugDaemonClientImpl::OnIOComplete,
    329                    weak_ptr_factory_.GetWeakPtr())));
    330     int write_fd = -1;
    331     if (!pipe_reader_->StartIO()) {
    332       LOG(ERROR) << "Cannot create pipe reader";
    333       // NB: continue anyway to shutdown tracing; toss trace data
    334       write_fd = HANDLE_EINTR(open("/dev/null", O_WRONLY));
    335       // TODO(sleffler) if this fails AppendFileDescriptor will abort
    336     } else {
    337       write_fd = pipe_reader_->GetWriteFD();
    338     }
    339 
    340     dbus::FileDescriptor* file_descriptor = new dbus::FileDescriptor(write_fd);
    341     // Punt descriptor validity check to a worker thread; on return we'll
    342     // issue the D-Bus request to stop tracing and collect results.
    343     base::WorkerPool::PostTaskAndReply(
    344         FROM_HERE,
    345         base::Bind(&DebugDaemonClientImpl::CheckValidity,
    346                    file_descriptor),
    347         base::Bind(&DebugDaemonClientImpl::OnCheckValidityRequestStopSystem,
    348                    weak_ptr_factory_.GetWeakPtr(),
    349                    base::Owned(file_descriptor),
    350                    callback),
    351         false);
    352 
    353     return true;
    354   }
    355 
    356   virtual void TestICMP(const std::string& ip_address,
    357                         const TestICMPCallback& callback) OVERRIDE {
    358     dbus::MethodCall method_call(debugd::kDebugdInterface,
    359                                  debugd::kTestICMP);
    360     dbus::MessageWriter writer(&method_call);
    361     writer.AppendString(ip_address);
    362     debugdaemon_proxy_->CallMethod(
    363         &method_call,
    364         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    365         base::Bind(&DebugDaemonClientImpl::OnTestICMP,
    366                    weak_ptr_factory_.GetWeakPtr(),
    367                    callback));
    368   }
    369 
    370   virtual void TestICMPWithOptions(
    371       const std::string& ip_address,
    372       const std::map<std::string, std::string>& options,
    373       const TestICMPCallback& callback) OVERRIDE {
    374     dbus::MethodCall method_call(debugd::kDebugdInterface,
    375                                  debugd::kTestICMPWithOptions);
    376     dbus::MessageWriter writer(&method_call);
    377     dbus::MessageWriter sub_writer(NULL);
    378     dbus::MessageWriter elem_writer(NULL);
    379 
    380     // Write the host.
    381     writer.AppendString(ip_address);
    382 
    383     // Write the options.
    384     writer.OpenArray("{ss}", &sub_writer);
    385     std::map<std::string, std::string>::const_iterator it;
    386     for (it = options.begin(); it != options.end(); ++it) {
    387       sub_writer.OpenDictEntry(&elem_writer);
    388       elem_writer.AppendString(it->first);
    389       elem_writer.AppendString(it->second);
    390       sub_writer.CloseContainer(&elem_writer);
    391     }
    392     writer.CloseContainer(&sub_writer);
    393 
    394     // Call the function.
    395     debugdaemon_proxy_->CallMethod(
    396         &method_call,
    397         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    398         base::Bind(&DebugDaemonClientImpl::OnTestICMP,
    399                    weak_ptr_factory_.GetWeakPtr(),
    400                    callback));
    401   }
    402 
    403  protected:
    404   virtual void Init(dbus::Bus* bus) OVERRIDE {
    405     debugdaemon_proxy_ =
    406         bus->GetObjectProxy(debugd::kDebugdServiceName,
    407                             dbus::ObjectPath(debugd::kDebugdServicePath));
    408   }
    409 
    410  private:
    411   // Called to check descriptor validity on a thread where i/o is permitted.
    412   static void CheckValidity(dbus::FileDescriptor* file_descriptor) {
    413     file_descriptor->CheckValidity();
    414   }
    415 
    416   // Called when a CheckValidity response is received.
    417   void OnCheckValidityGetDebugLogs(dbus::FileDescriptor* file_descriptor,
    418                                    const GetDebugLogsCallback& callback) {
    419     // Issue the dbus request to get debug logs.
    420     dbus::MethodCall method_call(
    421         debugd::kDebugdInterface,
    422         debugd::kGetDebugLogs);
    423     dbus::MessageWriter writer(&method_call);
    424     writer.AppendFileDescriptor(*file_descriptor);
    425 
    426     debugdaemon_proxy_->CallMethod(
    427         &method_call,
    428         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    429         base::Bind(&DebugDaemonClientImpl::OnGetDebugLogs,
    430                    weak_ptr_factory_.GetWeakPtr(),
    431                    callback));
    432   }
    433 
    434   // Called when a response for GetDebugLogs() is received.
    435   void OnGetDebugLogs(const GetDebugLogsCallback& callback,
    436                       dbus::Response* response) {
    437     if (!response) {
    438       LOG(ERROR) << "Failed to get debug logs";
    439       callback.Run(false);
    440       return;
    441     }
    442     callback.Run(true);
    443   }
    444 
    445   // Called when a response for SetDebugMode() is received.
    446   void OnSetDebugMode(const SetDebugModeCallback& callback,
    447                       dbus::Response* response) {
    448     if (!response) {
    449       LOG(ERROR) << "Failed to change debug mode";
    450       callback.Run(false);
    451     } else {
    452       callback.Run(true);
    453     }
    454   }
    455 
    456   void OnGetRoutes(const GetRoutesCallback& callback,
    457                    dbus::Response* response) {
    458     std::vector<std::string> routes;
    459     if (response) {
    460       dbus::MessageReader reader(response);
    461       if (reader.PopArrayOfStrings(&routes)) {
    462         callback.Run(true, routes);
    463       } else {
    464         LOG(ERROR) << "Got non-array response from GetRoutes";
    465         callback.Run(false, routes);
    466       }
    467     } else {
    468       callback.Run(false, routes);
    469     }
    470   }
    471 
    472   void OnGetNetworkStatus(const GetNetworkStatusCallback& callback,
    473                           dbus::Response* response) {
    474     std::string status;
    475     if (response && dbus::MessageReader(response).PopString(&status))
    476       callback.Run(true, status);
    477     else
    478       callback.Run(false, "");
    479   }
    480 
    481   void OnGetModemStatus(const GetModemStatusCallback& callback,
    482                         dbus::Response* response) {
    483     std::string status;
    484     if (response && dbus::MessageReader(response).PopString(&status))
    485       callback.Run(true, status);
    486     else
    487       callback.Run(false, "");
    488   }
    489 
    490   void OnGetWiMaxStatus(const GetWiMaxStatusCallback& callback,
    491                         dbus::Response* response) {
    492     std::string status;
    493     if (response && dbus::MessageReader(response).PopString(&status))
    494       callback.Run(true, status);
    495     else
    496       callback.Run(false, "");
    497   }
    498 
    499   void OnGetNetworkInterfaces(const GetNetworkInterfacesCallback& callback,
    500                               dbus::Response* response) {
    501     std::string status;
    502     if (response && dbus::MessageReader(response).PopString(&status))
    503       callback.Run(true, status);
    504     else
    505       callback.Run(false, "");
    506   }
    507 
    508   void OnGetPerfData(const GetPerfDataCallback& callback,
    509                      dbus::Response* response) {
    510     std::vector<uint8> data;
    511 
    512     if (!response) {
    513       return;
    514     }
    515 
    516     dbus::MessageReader reader(response);
    517     uint8* buffer = NULL;
    518     size_t buf_size = 0;
    519     if (!reader.PopArrayOfBytes(reinterpret_cast<uint8**>(
    520         &buffer), &buf_size)) {
    521       return;
    522     }
    523 
    524     // TODO(asharif): Figure out a way to avoid this copy.
    525     data.insert(data.end(), buffer, buffer + buf_size);
    526 
    527     callback.Run(data);
    528   }
    529 
    530   void OnGetAllLogs(const GetLogsCallback& callback,
    531                     dbus::Response* response) {
    532     std::map<std::string, std::string> logs;
    533     bool broken = false; // did we see a broken (k,v) pair?
    534     dbus::MessageReader sub_reader(NULL);
    535     if (!response || !dbus::MessageReader(response).PopArray(&sub_reader)) {
    536       callback.Run(false, logs);
    537       return;
    538     }
    539     while (sub_reader.HasMoreData()) {
    540       dbus::MessageReader sub_sub_reader(NULL);
    541       std::string key, value;
    542       if (!sub_reader.PopDictEntry(&sub_sub_reader)
    543           || !sub_sub_reader.PopString(&key)
    544           || !sub_sub_reader.PopString(&value)) {
    545         broken = true;
    546         break;
    547       }
    548       logs[key] = value;
    549     }
    550     callback.Run(!sub_reader.HasMoreData() && !broken, logs);
    551   }
    552 
    553   void OnGetUserLogFiles(const GetLogsCallback& callback,
    554                          dbus::Response* response) {
    555     return OnGetAllLogs(callback, response);
    556   }
    557 
    558   // Called when a response for StartSystemTracing() is received.
    559   void OnStartSystemTracing(dbus::Response* response) {
    560     if (!response) {
    561       LOG(ERROR) << "Failed to request systrace start";
    562       return;
    563     }
    564   }
    565 
    566   // Called when a CheckValidity response is received.
    567   void OnCheckValidityRequestStopSystem(
    568       dbus::FileDescriptor* file_descriptor,
    569       const StopSystemTracingCallback& callback) {
    570     // Issue the dbus request to stop system tracing
    571     dbus::MethodCall method_call(
    572         debugd::kDebugdInterface,
    573         debugd::kSystraceStop);
    574     dbus::MessageWriter writer(&method_call);
    575     writer.AppendFileDescriptor(*file_descriptor);
    576 
    577     callback_ = callback;
    578 
    579     DVLOG(1) << "Requesting a systrace stop";
    580     debugdaemon_proxy_->CallMethod(
    581         &method_call,
    582         dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
    583         base::Bind(&DebugDaemonClientImpl::OnRequestStopSystemTracing,
    584                    weak_ptr_factory_.GetWeakPtr()));
    585 
    586     pipe_reader_->CloseWriteFD();  // close our copy of fd after send
    587   }
    588 
    589   // Called when a response for RequestStopSystemTracing() is received.
    590   void OnRequestStopSystemTracing(dbus::Response* response) {
    591     if (!response) {
    592       LOG(ERROR) << "Failed to request systrace stop";
    593       // If debugd crashes or completes I/O before this message is processed
    594       // then pipe_reader_ can be NULL, see OnIOComplete().
    595       if (pipe_reader_.get())
    596         pipe_reader_->OnDataReady(-1); // terminate data stream
    597     }
    598     // NB: requester is signaled when i/o completes
    599   }
    600 
    601   void OnTestICMP(const TestICMPCallback& callback, dbus::Response* response) {
    602     std::string status;
    603     if (response && dbus::MessageReader(response).PopString(&status))
    604       callback.Run(true, status);
    605     else
    606       callback.Run(false, "");
    607   }
    608 
    609   // Called when pipe i/o completes; pass data on and delete the instance.
    610   void OnIOComplete() {
    611     callback_.Run(base::RefCountedString::TakeString(pipe_reader_->data()));
    612     pipe_reader_.reset();
    613   }
    614 
    615   dbus::ObjectProxy* debugdaemon_proxy_;
    616   scoped_ptr<PipeReader> pipe_reader_;
    617   StopSystemTracingCallback callback_;
    618   base::WeakPtrFactory<DebugDaemonClientImpl> weak_ptr_factory_;
    619 
    620   DISALLOW_COPY_AND_ASSIGN(DebugDaemonClientImpl);
    621 };
    622 
    623 DebugDaemonClient::DebugDaemonClient() {
    624 }
    625 
    626 DebugDaemonClient::~DebugDaemonClient() {
    627 }
    628 
    629 // static
    630 DebugDaemonClient::StopSystemTracingCallback
    631 DebugDaemonClient::EmptyStopSystemTracingCallback() {
    632   return base::Bind(&EmptyStopSystemTracingCallbackBody);
    633 }
    634 
    635 // static
    636 DebugDaemonClient* DebugDaemonClient::Create() {
    637   return new DebugDaemonClientImpl();
    638 }
    639 
    640 }  // namespace chromeos
    641