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