#include "base/platform_file.h"
#include "base/posix/eintr_wrapper.h"
#include "base/strings/string_util.h"
+#include "base/task_runner_util.h"
#include "base/threading/worker_pool.h"
+#include "chromeos/dbus/pipe_reader.h"
#include "dbus/bus.h"
#include "dbus/message.h"
#include "dbus/object_path.h"
#include "dbus/object_proxy.h"
-#include "net/base/file_stream.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace {
const scoped_refptr<base::RefCountedString>& unused_result) {
}
-// Simple class to encapsulate collecting data from a pipe into a
-// string. To use, instantiate the class, start i/o, and then delete
-// the instance on callback. The data should be retrieved before
-// delete and extracted or copied.
-//
-// TODO(sleffler) move data collection to a sub-class so this
-// can be reused to process data as it is received
-class PipeReader {
- public:
- typedef base::Callback<void(void)>IOCompleteCallback;
-
- explicit PipeReader(IOCompleteCallback callback)
- : io_buffer_(new net::IOBufferWithSize(4096)),
- callback_(callback),
- weak_ptr_factory_(this) {
- pipe_fd_[0] = pipe_fd_[1] = -1;
- }
-
- virtual ~PipeReader() {
- // Don't close pipe_fd_[0] as it's closed by data_stream_.
- if (pipe_fd_[1] != -1)
- if (IGNORE_EINTR(close(pipe_fd_[1])) < 0)
- PLOG(ERROR) << "close[1]";
- }
-
- // Returns descriptor for the writeable side of the pipe.
- int GetWriteFD() { return pipe_fd_[1]; }
-
- // Closes writeable descriptor; normally used in parent process after fork.
- void CloseWriteFD() {
- if (pipe_fd_[1] != -1) {
- if (IGNORE_EINTR(close(pipe_fd_[1])) < 0)
- PLOG(ERROR) << "close";
- pipe_fd_[1] = -1;
- }
- }
-
- // Returns collected data.
- std::string* data() { return &data_; }
-
- // Starts data collection. Returns true if stream was setup correctly.
- // On success data will automatically be accumulated into a string that
- // can be retrieved with PipeReader::data(). To shutdown collection delete
- // the instance and/or use PipeReader::OnDataReady(-1).
- bool StartIO() {
- // Use a pipe to collect data
- const int status = HANDLE_EINTR(pipe(pipe_fd_));
- if (status < 0) {
- PLOG(ERROR) << "pipe";
- return false;
- }
- base::PlatformFile data_file_ = pipe_fd_[0]; // read side
- data_stream_.reset(new net::FileStream(data_file_,
- base::PLATFORM_FILE_READ | base::PLATFORM_FILE_ASYNC,
- NULL));
-
- // Post an initial async read to setup data collection
- int rv = data_stream_->Read(io_buffer_.get(), io_buffer_->size(),
- base::Bind(&PipeReader::OnDataReady, weak_ptr_factory_.GetWeakPtr()));
- if (rv != net::ERR_IO_PENDING) {
- LOG(ERROR) << "Unable to post initial read";
- return false;
- }
- return true;
- }
-
- // Called when pipe data are available. Can also be used to shutdown
- // data collection by passing -1 for |byte_count|.
- void OnDataReady(int byte_count) {
- DVLOG(1) << "OnDataReady byte_count " << byte_count;
- if (byte_count <= 0) {
- callback_.Run(); // signal creator to take data and delete us
- return;
- }
- data_.append(io_buffer_->data(), byte_count);
-
- // Post another read
- int rv = data_stream_->Read(io_buffer_.get(), io_buffer_->size(),
- base::Bind(&PipeReader::OnDataReady, weak_ptr_factory_.GetWeakPtr()));
- if (rv != net::ERR_IO_PENDING) {
- LOG(ERROR) << "Unable to post another read";
- // TODO(sleffler) do something more intelligent?
- }
- }
-
- private:
- friend class base::RefCounted<PipeReader>;
-
- int pipe_fd_[2];
- scoped_ptr<net::FileStream> data_stream_;
- scoped_refptr<net::IOBufferWithSize> io_buffer_;
- std::string data_;
- IOCompleteCallback callback_;
-
- // Note: This should remain the last member so it'll be destroyed and
- // invalidate its weak pointers before any other members are destroyed.
- base::WeakPtrFactory<PipeReader> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(PipeReader);
-};
-
} // namespace
namespace chromeos {
// issue the D-Bus request to stop tracing and collect results.
base::WorkerPool::PostTaskAndReply(
FROM_HERE,
- base::Bind(&DebugDaemonClientImpl::CheckValidity,
- file_descriptor),
+ base::Bind(&dbus::FileDescriptor::CheckValidity,
+ base::Unretained(file_descriptor)),
base::Bind(&DebugDaemonClientImpl::OnCheckValidityGetDebugLogs,
weak_ptr_factory_.GetWeakPtr(),
base::Owned(file_descriptor),
debugdaemon_proxy_->CallMethod(
&method_call,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
- base::Bind(&DebugDaemonClientImpl::OnStartSystemTracing,
+ base::Bind(&DebugDaemonClientImpl::OnStartMethod,
weak_ptr_factory_.GetWeakPtr()));
}
return false;
}
- pipe_reader_.reset(new PipeReader(
+ scoped_refptr<base::TaskRunner> task_runner =
+ base::WorkerPool::GetTaskRunner(true /* task_is_slow */);
+
+ pipe_reader_.reset(new PipeReaderForString(
+ task_runner,
base::Bind(&DebugDaemonClientImpl::OnIOComplete,
weak_ptr_factory_.GetWeakPtr())));
- int write_fd = -1;
- if (!pipe_reader_->StartIO()) {
- LOG(ERROR) << "Cannot create pipe reader";
- // NB: continue anyway to shutdown tracing; toss trace data
- write_fd = HANDLE_EINTR(open("/dev/null", O_WRONLY));
- // TODO(sleffler) if this fails AppendFileDescriptor will abort
- } else {
- write_fd = pipe_reader_->GetWriteFD();
- }
- dbus::FileDescriptor* file_descriptor = new dbus::FileDescriptor(write_fd);
- // Punt descriptor validity check to a worker thread; on return we'll
+ base::File pipe_write_end = pipe_reader_->StartIO();
+ // Create dbus::FileDescriptor on the worker thread; on return we'll
// issue the D-Bus request to stop tracing and collect results.
- base::WorkerPool::PostTaskAndReply(
+ base::PostTaskAndReplyWithResult(
+ task_runner,
FROM_HERE,
- base::Bind(&DebugDaemonClientImpl::CheckValidity,
- file_descriptor),
- base::Bind(&DebugDaemonClientImpl::OnCheckValidityRequestStopSystem,
- weak_ptr_factory_.GetWeakPtr(),
- base::Owned(file_descriptor),
- callback),
- false);
-
+ base::Bind(
+ &DebugDaemonClientImpl::CreateFileDescriptorToStopSystemTracing,
+ base::Passed(&pipe_write_end)),
+ base::Bind(
+ &DebugDaemonClientImpl::OnCreateFileDescriptorRequestStopSystem,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback));
return true;
}
callback));
}
+ virtual void UploadCrashes() OVERRIDE {
+ dbus::MethodCall method_call(debugd::kDebugdInterface,
+ debugd::kUploadCrashes);
+ debugdaemon_proxy_->CallMethod(
+ &method_call,
+ dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&DebugDaemonClientImpl::OnStartMethod,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
protected:
virtual void Init(dbus::Bus* bus) OVERRIDE {
debugdaemon_proxy_ =
}
private:
- // Called to check descriptor validity on a thread where i/o is permitted.
- static void CheckValidity(dbus::FileDescriptor* file_descriptor) {
- file_descriptor->CheckValidity();
- }
-
// Called when a CheckValidity response is received.
void OnCheckValidityGetDebugLogs(dbus::FileDescriptor* file_descriptor,
const GetDebugLogsCallback& callback) {
return OnGetAllLogs(callback, response);
}
- // Called when a response for StartSystemTracing() is received.
- void OnStartSystemTracing(dbus::Response* response) {
+ // Called when a response for a simple start is received.
+ void OnStartMethod(dbus::Response* response) {
if (!response) {
- LOG(ERROR) << "Failed to request systrace start";
+ LOG(ERROR) << "Failed to request start";
return;
}
}
+ // Creates dbus::FileDescriptor from base::File.
+ static scoped_ptr<dbus::FileDescriptor>
+ CreateFileDescriptorToStopSystemTracing(base::File pipe_write_end) {
+ if (!pipe_write_end.IsValid()) {
+ LOG(ERROR) << "Cannot create pipe reader";
+ // NB: continue anyway to shutdown tracing; toss trace data
+ pipe_write_end.Initialize(base::FilePath(FILE_PATH_LITERAL("/dev/null")),
+ base::File::FLAG_OPEN | base::File::FLAG_WRITE);
+ // TODO(sleffler) if this fails AppendFileDescriptor will abort
+ }
+ scoped_ptr<dbus::FileDescriptor> file_descriptor(new dbus::FileDescriptor);
+ file_descriptor->PutValue(pipe_write_end.TakePlatformFile());
+ file_descriptor->CheckValidity();
+ return file_descriptor.Pass();
+ }
+
// Called when a CheckValidity response is received.
- void OnCheckValidityRequestStopSystem(
- dbus::FileDescriptor* file_descriptor,
- const StopSystemTracingCallback& callback) {
+ void OnCreateFileDescriptorRequestStopSystem(
+ const StopSystemTracingCallback& callback,
+ scoped_ptr<dbus::FileDescriptor> file_descriptor) {
+ DCHECK(file_descriptor);
+
// Issue the dbus request to stop system tracing
dbus::MethodCall method_call(
debugd::kDebugdInterface,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnRequestStopSystemTracing,
weak_ptr_factory_.GetWeakPtr()));
-
- pipe_reader_->CloseWriteFD(); // close our copy of fd after send
}
// Called when a response for RequestStopSystemTracing() is received.
// Called when pipe i/o completes; pass data on and delete the instance.
void OnIOComplete() {
- callback_.Run(base::RefCountedString::TakeString(pipe_reader_->data()));
+ std::string pipe_data;
+ pipe_reader_->GetData(&pipe_data);
+ callback_.Run(base::RefCountedString::TakeString(&pipe_data));
pipe_reader_.reset();
}
dbus::ObjectProxy* debugdaemon_proxy_;
- scoped_ptr<PipeReader> pipe_reader_;
+ scoped_ptr<PipeReaderForString> pipe_reader_;
StopSystemTracingCallback callback_;
base::WeakPtrFactory<DebugDaemonClientImpl> weak_ptr_factory_;