diff options
author | sleffler@chromium.org <sleffler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-05 07:27:34 +0000 |
---|---|---|
committer | sleffler@chromium.org <sleffler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-05 07:27:34 +0000 |
commit | 3629fd7b8bbec105c5819aba93f7931e62443461 (patch) | |
tree | e1127a18a0cd5cc736eefe0147f1b6ec200783ee /chrome/browser/chromeos/dbus | |
parent | 32dfbe4c74fb99ccef54c9006c143ea9e538c656 (diff) | |
download | chromium_src-3629fd7b8bbec105c5819aba93f7931e62443461.zip chromium_src-3629fd7b8bbec105c5819aba93f7931e62443461.tar.gz chromium_src-3629fd7b8bbec105c5819aba93f7931e62443461.tar.bz2 |
chromeos: add client support for debugd systrace support
Add support for communicating with the debugd service and enable access
to use systrace methods.
BUG=chromium-os:27809
TEST=use new about:tracing support to collect system event data
Change-Id: I1b6ed75f3ece960c77527e7b9d3a34e5cb76401e
Review URL: http://codereview.chromium.org/9700073
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@130860 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/chromeos/dbus')
8 files changed, 393 insertions, 0 deletions
diff --git a/chrome/browser/chromeos/dbus/dbus_thread_manager.cc b/chrome/browser/chromeos/dbus/dbus_thread_manager.cc index fc169cc..9cbd6ab 100644 --- a/chrome/browser/chromeos/dbus/dbus_thread_manager.cc +++ b/chrome/browser/chromeos/dbus/dbus_thread_manager.cc @@ -15,6 +15,7 @@ #include "chrome/browser/chromeos/dbus/dbus_client_implementation_type.h" #include "chrome/browser/chromeos/dbus/cros_disks_client.h" #include "chrome/browser/chromeos/dbus/cryptohome_client.h" +#include "chrome/browser/chromeos/dbus/debug_daemon_client.h" #include "chrome/browser/chromeos/dbus/flimflam_ipconfig_client.h" #include "chrome/browser/chromeos/dbus/flimflam_network_client.h" #include "chrome/browser/chromeos/dbus/flimflam_profile_client.h" @@ -72,6 +73,9 @@ class DBusThreadManagerImpl : public DBusThreadManager { // Create the Cryptohome client. cryptohome_client_.reset( CryptohomeClient::Create(client_type, system_bus_.get())); + // Create the debugdaemon client. + debugdaemon_client_.reset( + DebugDaemonClient::Create(client_type, system_bus_.get())); // Create the Flimflam IPConfig client. flimflam_ipconfig_client_.reset( FlimflamIPConfigClient::Create(client_type, system_bus_.get())); @@ -156,6 +160,11 @@ class DBusThreadManagerImpl : public DBusThreadManager { } // DBusThreadManager override. + virtual DebugDaemonClient* GetDebugDaemonClient() OVERRIDE { + return debugdaemon_client_.get(); + } + + // DBusThreadManager override. virtual FlimflamIPConfigClient* GetFlimflamIPConfigClient() OVERRIDE { return flimflam_ipconfig_client_.get(); } @@ -209,6 +218,7 @@ class DBusThreadManagerImpl : public DBusThreadManager { scoped_ptr<CashewClient> cashew_client_; scoped_ptr<CrosDisksClient> cros_disks_client_; scoped_ptr<CryptohomeClient> cryptohome_client_; + scoped_ptr<DebugDaemonClient> debugdaemon_client_; scoped_ptr<FlimflamIPConfigClient> flimflam_ipconfig_client_; scoped_ptr<FlimflamNetworkClient> flimflam_network_client_; scoped_ptr<FlimflamProfileClient> flimflam_profile_client_; diff --git a/chrome/browser/chromeos/dbus/dbus_thread_manager.h b/chrome/browser/chromeos/dbus/dbus_thread_manager.h index cbcf371..f2caffa 100644 --- a/chrome/browser/chromeos/dbus/dbus_thread_manager.h +++ b/chrome/browser/chromeos/dbus/dbus_thread_manager.h @@ -28,6 +28,7 @@ class BluetoothNodeClient; class CashewClient; class CrosDisksClient; class CryptohomeClient; +class DebugDaemonClient; class FlimflamIPConfigClient; class FlimflamNetworkClient; class FlimflamProfileClient; @@ -118,6 +119,11 @@ class DBusThreadManager { // down. virtual CryptohomeClient* GetCryptohomeClient() = 0; + // Returns the DebugDaemon client, owned by DBusThreadManager. + // Do not cache this pointer and use it after DBusThreadManager is shut + // down. + virtual DebugDaemonClient* GetDebugDaemonClient() = 0; + // Returns the Flimflam IPConfig client, owned by DBusThreadManager. // Do not cache this pointer and use it after DBusThreadManager is shut // down. diff --git a/chrome/browser/chromeos/dbus/debug_daemon_client.cc b/chrome/browser/chromeos/dbus/debug_daemon_client.cc new file mode 100644 index 0000000..1fec37d --- /dev/null +++ b/chrome/browser/chromeos/dbus/debug_daemon_client.cc @@ -0,0 +1,277 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <fcntl.h> +#include <unistd.h> + +#include "chrome/browser/chromeos/dbus/debug_daemon_client.h" + +#include "base/bind.h" +#include "base/callback.h" +#include "base/chromeos/chromeos_version.h" +#include "base/eintr_wrapper.h" +#include "base/memory/ref_counted_memory.h" +#include "base/platform_file.h" +#include "base/string_util.h" +#include "content/public/browser/browser_thread.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" + +using content::BrowserThread; + +namespace { + +// Used in DebugDaemonClient::EmptySystemStopTracingCallback(). +void EmptyStopSystemTracingCallbackBody( + 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) + : data_stream_(NULL), + io_buffer_(new net::IOBufferWithSize(4096)), + weak_ptr_factory_(this), + callback_(callback) { + pipe_fd_[0] = pipe_fd_[1] = -1; + } + + virtual ~PipeReader() { + if (pipe_fd_[0] != -1) + HANDLE_EINTR(close(pipe_fd_[0])); + if (pipe_fd_[1] != -1) + HANDLE_EINTR(close(pipe_fd_[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) { + HANDLE_EINTR(close(pipe_fd_[1])); + 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_; + base::WeakPtrFactory<PipeReader> weak_ptr_factory_; + std::string data_; + IOCompleteCallback callback_; + + DISALLOW_COPY_AND_ASSIGN(PipeReader); +}; + +} // namespace + +namespace chromeos { + +// The DebugDaemonClient implementation used in production. +class DebugDaemonClientImpl : public DebugDaemonClient { + public: + explicit DebugDaemonClientImpl(dbus::Bus* bus) + : debugdaemon_proxy_(NULL), + weak_ptr_factory_(this), + pipe_reader_(NULL) { + debugdaemon_proxy_ = bus->GetObjectProxy( + debugd::kDebugdServiceName, + dbus::ObjectPath(debugd::kDebugdServicePath)); + } + + virtual ~DebugDaemonClientImpl() {} + + // DebugDaemonClient override. + virtual void StartSystemTracing() OVERRIDE { + dbus::MethodCall method_call( + debugd::kDebugdInterface, + debugd::kSystraceStart); + dbus::MessageWriter writer(&method_call); + writer.AppendString("all"); // TODO(sleffler) parameterize category list + + DVLOG(1) << "Requesting a systrace start"; + debugdaemon_proxy_->CallMethod( + &method_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::Bind(&DebugDaemonClientImpl::OnStartSystemTracing, + weak_ptr_factory_.GetWeakPtr())); + } + + virtual bool RequestStopSystemTracing(const StopSystemTracingCallback& + callback) OVERRIDE { + if (pipe_reader_ != NULL) { + LOG(ERROR) << "Busy doing StopSystemTracing"; + return false; + } + + pipe_reader_.reset(new PipeReader( + 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(); + } + + DCHECK(callback.is_null()); + callback_ = callback; + + // Issue the dbus request to stop system tracing + dbus::MethodCall method_call( + debugd::kDebugdInterface, + debugd::kSystraceStop); + dbus::MessageWriter writer(&method_call); + dbus::FileDescriptor temp(write_fd); // NB: explicit temp for C++98 + writer.AppendFileDescriptor(temp); + + DVLOG(1) << "Requesting a systrace stop"; + debugdaemon_proxy_->CallMethod( + &method_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, + base::Bind(&DebugDaemonClientImpl::OnRequestStopSystemTracing, + weak_ptr_factory_.GetWeakPtr())); + + pipe_reader_->CloseWriteFD(); // close our copy of fd after send + + return true; + } + + private: + // Called when a response for StartSystemTracing() is received. + void OnStartSystemTracing(dbus::Response* response) { + if (!response) { + LOG(ERROR) << "Failed to request systrace start"; + return; + } + } + + // Called when a response for RequestStopSystemTracing() is received. + void OnRequestStopSystemTracing(dbus::Response* response) { + if (!response) { + LOG(ERROR) << "Failed to request systrace stop"; + pipe_reader_->OnDataReady(-1); // terminate data stream + } + // NB: requester is signaled when i/o completes + } + + // Called when pipe i/o completes; pass data on and delete the instance. + void OnIOComplete() { + callback_.Run(base::RefCountedString::TakeString(pipe_reader_->data())); + pipe_reader_.reset(); + } + + dbus::ObjectProxy* debugdaemon_proxy_; + base::WeakPtrFactory<DebugDaemonClientImpl> weak_ptr_factory_; + scoped_ptr<PipeReader> pipe_reader_; + StopSystemTracingCallback callback_; + + DISALLOW_COPY_AND_ASSIGN(DebugDaemonClientImpl); +}; + +// The DebugDaemonClient implementation used on Linux desktop, +// which does nothing. +class DebugDaemonClientStubImpl : public DebugDaemonClient { + // DebugDaemonClient overrides. + virtual void StartSystemTracing() OVERRIDE {} + virtual bool RequestStopSystemTracing(const StopSystemTracingCallback& + callback) OVERRIDE { + std::string no_data; + callback.Run(base::RefCountedString::TakeString(&no_data)); + return true; + } +}; + +DebugDaemonClient::DebugDaemonClient() { +} + +DebugDaemonClient::~DebugDaemonClient() { +} + +// static +DebugDaemonClient::StopSystemTracingCallback +DebugDaemonClient::EmptyStopSystemTracingCallback() { + return base::Bind(&EmptyStopSystemTracingCallbackBody); +} + +// static +DebugDaemonClient* DebugDaemonClient::Create(DBusClientImplementationType type, + dbus::Bus* bus) { + if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) + return new DebugDaemonClientImpl(bus); + DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type); + return new DebugDaemonClientStubImpl(); +} + +} // namespace chromeos diff --git a/chrome/browser/chromeos/dbus/debug_daemon_client.h b/chrome/browser/chromeos/dbus/debug_daemon_client.h new file mode 100644 index 0000000..843a059 --- /dev/null +++ b/chrome/browser/chromeos/dbus/debug_daemon_client.h @@ -0,0 +1,52 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_DBUS_DEBUG_DAEMON_CLIENT_H_ +#define CHROME_BROWSER_CHROMEOS_DBUS_DEBUG_DAEMON_CLIENT_H_ + +#include "base/callback.h" +#include "base/memory/ref_counted_memory.h" +#include "chrome/browser/chromeos/dbus/dbus_client_implementation_type.h" + +namespace dbus { +class Bus; +} // namespace dbus + +namespace chromeos { + +// DebugDaemonClient is used to communicate with the debug daemon. +class DebugDaemonClient { + public: + virtual ~DebugDaemonClient(); + + // Requests to start system/kernel tracing. + virtual void StartSystemTracing() = 0; + + // Called once RequestStopSystemTracing() is complete. Takes one parameter: + // - result: the data collected while tracing was active + typedef base::Callback<void(const scoped_refptr<base::RefCountedString>& + result)> StopSystemTracingCallback; + + // Requests to stop system tracing and calls |callback| when completed. + virtual bool RequestStopSystemTracing(const StopSystemTracingCallback& + callback) = 0; + + // Returns an empty SystemTracingCallback that does nothing. + static StopSystemTracingCallback EmptyStopSystemTracingCallback(); + + // Factory function, creates a new instance and returns ownership. + // For normal usage, access the singleton via DBusThreadManager::Get(). + static DebugDaemonClient* Create(DBusClientImplementationType type, + dbus::Bus* bus); + protected: + // Create() should be used instead. + DebugDaemonClient(); + + private: + DISALLOW_COPY_AND_ASSIGN(DebugDaemonClient); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_DBUS_DEBUG_DAEMON_CLIENT_H_ diff --git a/chrome/browser/chromeos/dbus/mock_dbus_thread_manager.cc b/chrome/browser/chromeos/dbus/mock_dbus_thread_manager.cc index 1e1a4c0..843bb4f 100644 --- a/chrome/browser/chromeos/dbus/mock_dbus_thread_manager.cc +++ b/chrome/browser/chromeos/dbus/mock_dbus_thread_manager.cc @@ -12,6 +12,7 @@ #include "chrome/browser/chromeos/dbus/mock_cashew_client.h" #include "chrome/browser/chromeos/dbus/mock_cros_disks_client.h" #include "chrome/browser/chromeos/dbus/mock_cryptohome_client.h" +#include "chrome/browser/chromeos/dbus/mock_debug_daemon_client.h" #include "chrome/browser/chromeos/dbus/mock_flimflam_ipconfig_client.h" #include "chrome/browser/chromeos/dbus/mock_flimflam_network_client.h" #include "chrome/browser/chromeos/dbus/mock_flimflam_profile_client.h" @@ -37,6 +38,7 @@ MockDBusThreadManager::MockDBusThreadManager() mock_cashew_client_(new MockCashewClient), mock_cros_disks_client_(new MockCrosDisksClient), mock_cryptohome_client_(new MockCryptohomeClient), + mock_debugdaemon_client_(new MockDebugDaemonClient), mock_flimflam_ipconfig_client_(new MockFlimflamIPConfigClient), mock_flimflam_network_client_(new MockFlimflamNetworkClient), mock_flimflam_profile_client_(new MockFlimflamProfileClient), @@ -62,6 +64,8 @@ MockDBusThreadManager::MockDBusThreadManager() .WillRepeatedly(Return(mock_cros_disks_client())); EXPECT_CALL(*this, GetCryptohomeClient()) .WillRepeatedly(Return(mock_cryptohome_client())); + EXPECT_CALL(*this, GetDebugDaemonClient()) + .WillRepeatedly(Return(mock_debugdaemon_client())); EXPECT_CALL(*this, GetFlimflamIPConfigClient()) .WillRepeatedly(Return(mock_flimflam_ipconfig_client())); EXPECT_CALL(*this, GetFlimflamNetworkClient()) diff --git a/chrome/browser/chromeos/dbus/mock_dbus_thread_manager.h b/chrome/browser/chromeos/dbus/mock_dbus_thread_manager.h index 05ea0da..3402fcb 100644 --- a/chrome/browser/chromeos/dbus/mock_dbus_thread_manager.h +++ b/chrome/browser/chromeos/dbus/mock_dbus_thread_manager.h @@ -26,6 +26,7 @@ class MockBluetoothNodeClient; class MockCashewClient; class MockCrosDisksClient; class MockCryptohomeClient; +class MockDebugDaemonClient; class MockFlimflamIPConfigClient; class MockFlimflamNetworkClient; class MockFlimflamProfileClient; @@ -53,6 +54,7 @@ class MockDBusThreadManager : public DBusThreadManager { MOCK_METHOD0(GetCashewClient, CashewClient*(void)); MOCK_METHOD0(GetCrosDisksClient, CrosDisksClient*(void)); MOCK_METHOD0(GetCryptohomeClient, CryptohomeClient*(void)); + MOCK_METHOD0(GetDebugDaemonClient, DebugDaemonClient*(void)); MOCK_METHOD0(GetFlimflamIPConfigClient, FlimflamIPConfigClient*(void)); MOCK_METHOD0(GetFlimflamNetworkClient, FlimflamNetworkClient*(void)); MOCK_METHOD0(GetFlimflamProfileClient, FlimflamProfileClient*(void)); @@ -87,6 +89,9 @@ class MockDBusThreadManager : public DBusThreadManager { MockCryptohomeClient* mock_cryptohome_client() { return mock_cryptohome_client_.get(); } + MockDebugDaemonClient* mock_debugdaemon_client() { + return mock_debugdaemon_client_.get(); + } MockFlimflamIPConfigClient* mock_flimflam_ipconfig_client() { return mock_flimflam_ipconfig_client_.get(); } @@ -124,6 +129,7 @@ class MockDBusThreadManager : public DBusThreadManager { scoped_ptr<MockCashewClient> mock_cashew_client_; scoped_ptr<MockCrosDisksClient> mock_cros_disks_client_; scoped_ptr<MockCryptohomeClient> mock_cryptohome_client_; + scoped_ptr<MockDebugDaemonClient> mock_debugdaemon_client_; scoped_ptr<MockFlimflamIPConfigClient> mock_flimflam_ipconfig_client_; scoped_ptr<MockFlimflamNetworkClient> mock_flimflam_network_client_; scoped_ptr<MockFlimflamProfileClient> mock_flimflam_profile_client_; diff --git a/chrome/browser/chromeos/dbus/mock_debug_daemon_client.cc b/chrome/browser/chromeos/dbus/mock_debug_daemon_client.cc new file mode 100644 index 0000000..4d1e5b6 --- /dev/null +++ b/chrome/browser/chromeos/dbus/mock_debug_daemon_client.cc @@ -0,0 +1,13 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/dbus/mock_debug_daemon_client.h" + +namespace chromeos { + +MockDebugDaemonClient::MockDebugDaemonClient() {} + +MockDebugDaemonClient::~MockDebugDaemonClient() {} + +} // namespace chromeos diff --git a/chrome/browser/chromeos/dbus/mock_debug_daemon_client.h b/chrome/browser/chromeos/dbus/mock_debug_daemon_client.h new file mode 100644 index 0000000..9d825c3 --- /dev/null +++ b/chrome/browser/chromeos/dbus/mock_debug_daemon_client.h @@ -0,0 +1,25 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_DBUS_MOCK_DEBUG_DAEMON_CLIENT_H_ +#define CHROME_BROWSER_CHROMEOS_DBUS_MOCK_DEBUG_DAEMON_CLIENT_H_ + +#include "chrome/browser/chromeos/dbus/debug_daemon_client.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace chromeos { + +class MockDebugDaemonClient : public DebugDaemonClient { + public: + MockDebugDaemonClient(); + virtual ~MockDebugDaemonClient(); + + MOCK_METHOD1(RequestStopSystemTracing, + bool(const StopSystemTracingCallback&)); + MOCK_METHOD0(StartSystemTracing, void()); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_DBUS_MOCK_DEBUG_DAEMON_CLIENT_H_ |