blob: ed83a06bb46bb75156ff82794f26142e0dcd0887 [file] [log] [blame]
// 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 "chromeos/dbus/debug_daemon_client.h"
#include <fcntl.h>
#include <stddef.h>
#include <stdint.h>
#include <unistd.h>
#include <memory>
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/files/file_path.h"
#include "base/json/json_string_value_serializer.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/posix/eintr_wrapper.h"
#include "base/strings/string_util.h"
#include "base/task_runner_util.h"
#include "base/threading/thread_task_runner_handle.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"
namespace chromeos {
namespace {
const char kCrOSTracingAgentName[] = "cros";
const char kCrOSTraceLabel[] = "systemTraceEvents";
// Because the cheets logs are very huge, we set the D-Bus timeout to 2 minutes.
const int kBigLogsDBusTimeoutMS = 120 * 1000;
// Used in DebugDaemonClient::EmptyStopAgentTracingCallback().
void EmptyStopAgentTracingCallbackBody(
const std::string& agent_name,
const std::string& events_label,
const scoped_refptr<base::RefCountedString>& unused_result) {}
// A self-deleting object that wraps the pipe reader operations for reading the
// big feedback logs. It will delete itself once the pipe stream has been
// terminated. Once the data has been completely read from the pipe, it invokes
// the GetLogsCallback |callback| passing the deserialized logs data back to
// the requester.
class PipeReaderWrapper : public base::SupportsWeakPtr<PipeReaderWrapper> {
public:
explicit PipeReaderWrapper(const DebugDaemonClient::GetLogsCallback& callback)
: task_runner_(
base::WorkerPool::GetTaskRunner(true /** tasks_are_slow */)),
pipe_reader_(task_runner_,
base::Bind(&PipeReaderWrapper::OnIOComplete, AsWeakPtr())),
callback_(callback) {}
base::ScopedFD Initialize() { return pipe_reader_.StartIO(); }
void OnIOComplete() {
std::string pipe_data;
pipe_reader_.GetData(&pipe_data);
JSONStringValueDeserializer json_reader(pipe_data);
std::map<std::string, std::string> data;
const base::DictionaryValue* dictionary = nullptr;
std::unique_ptr<base::Value> logs_value =
json_reader.Deserialize(nullptr, nullptr);
if (!logs_value.get() || !logs_value->GetAsDictionary(&dictionary)) {
VLOG(1) << "Failed to deserialize the JSON logs.";
callback_.Run(false, data);
delete this;
return;
}
base::DictionaryValue::Iterator itr(*dictionary);
for (; !itr.IsAtEnd(); itr.Advance()) {
std::string value;
itr.value().GetAsString(&value);
data[itr.key()] = value;
}
callback_.Run(true, data);
delete this;
}
void TerminateStream() { pipe_reader_.OnDataReady(-1); }
private:
scoped_refptr<base::TaskRunner> task_runner_;
PipeReaderForString pipe_reader_;
DebugDaemonClient::GetLogsCallback callback_;
DISALLOW_COPY_AND_ASSIGN(PipeReaderWrapper);
};
} // namespace
// The DebugDaemonClient implementation used in production.
class DebugDaemonClientImpl : public DebugDaemonClient {
public:
DebugDaemonClientImpl() : debugdaemon_proxy_(NULL), weak_ptr_factory_(this) {}
~DebugDaemonClientImpl() override {}
// DebugDaemonClient override.
void DumpDebugLogs(bool is_compressed,
int file_descriptor,
const GetDebugLogsCallback& callback) override {
// Issue the dbus request to get debug logs.
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kDumpDebugLogs);
dbus::MessageWriter writer(&method_call);
writer.AppendBool(is_compressed);
writer.AppendFileDescriptor(file_descriptor);
debugdaemon_proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnGetDebugLogs,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void SetDebugMode(const std::string& subsystem,
const SetDebugModeCallback& callback) override {
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kSetDebugMode);
dbus::MessageWriter writer(&method_call);
writer.AppendString(subsystem);
debugdaemon_proxy_->CallMethod(
&method_call,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnSetDebugMode,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
void GetRoutes(bool numeric,
bool ipv6,
const GetRoutesCallback& callback) override {
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kGetRoutes);
dbus::MessageWriter writer(&method_call);
dbus::MessageWriter sub_writer(NULL);
writer.OpenArray("{sv}", &sub_writer);
dbus::MessageWriter elem_writer(NULL);
sub_writer.OpenDictEntry(&elem_writer);
elem_writer.AppendString("numeric");
elem_writer.AppendVariantOfBool(numeric);
sub_writer.CloseContainer(&elem_writer);
sub_writer.OpenDictEntry(&elem_writer);
elem_writer.AppendString("v6");
elem_writer.AppendVariantOfBool(ipv6);
sub_writer.CloseContainer(&elem_writer);
writer.CloseContainer(&sub_writer);
debugdaemon_proxy_->CallMethod(
&method_call,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnGetRoutes,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
void GetNetworkStatus(const GetNetworkStatusCallback& callback) override {
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kGetNetworkStatus);
debugdaemon_proxy_->CallMethod(
&method_call,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnGetNetworkStatus,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
void GetModemStatus(const GetModemStatusCallback& callback) override {
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kGetModemStatus);
debugdaemon_proxy_->CallMethod(
&method_call,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnGetModemStatus,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
void GetWiMaxStatus(const GetWiMaxStatusCallback& callback) override {
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kGetWiMaxStatus);
debugdaemon_proxy_->CallMethod(
&method_call,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnGetWiMaxStatus,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
void GetNetworkInterfaces(
const GetNetworkInterfacesCallback& callback) override {
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kGetInterfaces);
debugdaemon_proxy_->CallMethod(
&method_call,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnGetNetworkInterfaces,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
void GetPerfOutput(base::TimeDelta duration,
const std::vector<std::string>& perf_args,
int file_descriptor,
const DBusMethodErrorCallback& error_callback) override {
DCHECK(file_descriptor);
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kGetPerfOutputFd);
dbus::MessageWriter writer(&method_call);
writer.AppendUint32(duration.InSeconds());
writer.AppendArrayOfStrings(perf_args);
writer.AppendFileDescriptor(file_descriptor);
debugdaemon_proxy_->CallMethodWithErrorCallback(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
dbus::ObjectProxy::EmptyResponseCallback(),
base::Bind(&DebugDaemonClientImpl::OnDBusMethodError,
weak_ptr_factory_.GetWeakPtr(), error_callback));
}
void GetScrubbedLogs(const GetLogsCallback& callback) override {
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kGetFeedbackLogs);
debugdaemon_proxy_->CallMethod(
&method_call,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnGetAllLogs,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
void GetScrubbedBigLogs(const GetLogsCallback& callback) override {
// The PipeReaderWrapper is a self-deleting object; we don't have to worry
// about ownership or lifetime. We need to create a new one for each Big
// Logs requests in order to queue these requests. One request can take a
// long time to be processed and a new request should never be ignored nor
// cancels the on-going one.
PipeReaderWrapper* pipe_reader = new PipeReaderWrapper(callback);
base::ScopedFD pipe_write_end = pipe_reader->Initialize();
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kGetBigFeedbackLogs);
dbus::MessageWriter writer(&method_call);
writer.AppendFileDescriptor(pipe_write_end.get());
DVLOG(1) << "Requesting big feedback logs";
debugdaemon_proxy_->CallMethod(
&method_call, kBigLogsDBusTimeoutMS,
base::Bind(&DebugDaemonClientImpl::OnBigFeedbackLogsResponse,
weak_ptr_factory_.GetWeakPtr(), pipe_reader->AsWeakPtr()));
}
void GetAllLogs(const GetLogsCallback& callback) override {
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kGetAllLogs);
debugdaemon_proxy_->CallMethod(
&method_call,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnGetAllLogs,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
void GetUserLogFiles(const GetLogsCallback& callback) override {
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kGetUserLogFiles);
debugdaemon_proxy_->CallMethod(
&method_call,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnGetUserLogFiles,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
// base::trace_event::TracingAgent implementation.
std::string GetTracingAgentName() override { return kCrOSTracingAgentName; }
std::string GetTraceEventLabel() override { return kCrOSTraceLabel; }
void StartAgentTracing(const base::trace_event::TraceConfig& trace_config,
const StartAgentTracingCallback& callback) 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::OnStartMethod,
weak_ptr_factory_.GetWeakPtr()));
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(callback, GetTracingAgentName(), true /* success */));
}
void StopAgentTracing(const StopAgentTracingCallback& callback) override {
DCHECK(stop_agent_tracing_task_runner_);
if (pipe_reader_ != NULL) {
LOG(ERROR) << "Busy doing StopSystemTracing";
return;
}
pipe_reader_.reset(
new PipeReaderForString(stop_agent_tracing_task_runner_,
base::Bind(&DebugDaemonClientImpl::OnIOComplete,
weak_ptr_factory_.GetWeakPtr())));
base::ScopedFD pipe_write_end = pipe_reader_->StartIO();
DCHECK(pipe_write_end.is_valid());
// Issue the dbus request to stop system tracing
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kSystraceStop);
dbus::MessageWriter writer(&method_call);
writer.AppendFileDescriptor(pipe_write_end.get());
callback_ = callback;
DVLOG(1) << "Requesting a systrace stop";
debugdaemon_proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnStopAgentTracing,
weak_ptr_factory_.GetWeakPtr()));
}
void SetStopAgentTracingTaskRunner(
scoped_refptr<base::TaskRunner> task_runner) override {
stop_agent_tracing_task_runner_ = task_runner;
}
void TestICMP(const std::string& ip_address,
const TestICMPCallback& callback) override {
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kTestICMP);
dbus::MessageWriter writer(&method_call);
writer.AppendString(ip_address);
debugdaemon_proxy_->CallMethod(
&method_call,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnTestICMP,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
void TestICMPWithOptions(const std::string& ip_address,
const std::map<std::string, std::string>& options,
const TestICMPCallback& callback) override {
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kTestICMPWithOptions);
dbus::MessageWriter writer(&method_call);
dbus::MessageWriter sub_writer(NULL);
dbus::MessageWriter elem_writer(NULL);
// Write the host.
writer.AppendString(ip_address);
// Write the options.
writer.OpenArray("{ss}", &sub_writer);
std::map<std::string, std::string>::const_iterator it;
for (it = options.begin(); it != options.end(); ++it) {
sub_writer.OpenDictEntry(&elem_writer);
elem_writer.AppendString(it->first);
elem_writer.AppendString(it->second);
sub_writer.CloseContainer(&elem_writer);
}
writer.CloseContainer(&sub_writer);
// Call the function.
debugdaemon_proxy_->CallMethod(
&method_call,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnTestICMP,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
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()));
}
void EnableDebuggingFeatures(
const std::string& password,
const EnableDebuggingCallback& callback) override {
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kEnableChromeDevFeatures);
dbus::MessageWriter writer(&method_call);
writer.AppendString(password);
debugdaemon_proxy_->CallMethod(
&method_call,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnEnableDebuggingFeatures,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
void QueryDebuggingFeatures(
const QueryDevFeaturesCallback& callback) override {
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kQueryDevFeatures);
dbus::MessageWriter writer(&method_call);
debugdaemon_proxy_->CallMethod(
&method_call,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnQueryDebuggingFeatures,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
void RemoveRootfsVerification(
const EnableDebuggingCallback& callback) override {
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kRemoveRootfsVerification);
dbus::MessageWriter writer(&method_call);
debugdaemon_proxy_->CallMethod(
&method_call,
dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnRemoveRootfsVerification,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
void WaitForServiceToBeAvailable(
const WaitForServiceToBeAvailableCallback& callback) override {
debugdaemon_proxy_->WaitForServiceToBeAvailable(callback);
}
void SetOomScoreAdj(const std::map<pid_t, int32_t>& pid_to_oom_score_adj,
const SetOomScoreAdjCallback& callback) override {
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kSetOomScoreAdj);
dbus::MessageWriter writer(&method_call);
dbus::MessageWriter sub_writer(nullptr);
writer.OpenArray("{ii}", &sub_writer);
dbus::MessageWriter elem_writer(nullptr);
for (const auto& entry : pid_to_oom_score_adj) {
sub_writer.OpenDictEntry(&elem_writer);
elem_writer.AppendInt32(entry.first);
elem_writer.AppendInt32(entry.second);
sub_writer.CloseContainer(&elem_writer);
}
writer.CloseContainer(&sub_writer);
debugdaemon_proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnSetOomScoreAdj,
weak_ptr_factory_.GetWeakPtr(), callback));
}
void CupsAddPrinter(const std::string& name,
const std::string& uri,
const std::string& ppd_path,
bool ipp_everywhere,
const DebugDaemonClient::CupsAddPrinterCallback& callback,
const base::Closure& error_callback) override {
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kCupsAddPrinter);
dbus::MessageWriter writer(&method_call);
writer.AppendString(name);
writer.AppendString(uri);
writer.AppendString(ppd_path);
writer.AppendBool(ipp_everywhere);
debugdaemon_proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnPrinterAdded,
weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
}
void CupsRemovePrinter(
const std::string& name,
const DebugDaemonClient::CupsRemovePrinterCallback& callback,
const base::Closure& error_callback) override {
dbus::MethodCall method_call(debugd::kDebugdInterface,
debugd::kCupsRemovePrinter);
dbus::MessageWriter writer(&method_call);
writer.AppendString(name);
debugdaemon_proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&DebugDaemonClientImpl::OnPrinterRemoved,
weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
}
protected:
void Init(dbus::Bus* bus) override {
debugdaemon_proxy_ =
bus->GetObjectProxy(debugd::kDebugdServiceName,
dbus::ObjectPath(debugd::kDebugdServicePath));
}
private:
// Called when a response for GetDebugLogs() is received.
void OnGetDebugLogs(const GetDebugLogsCallback& callback,
dbus::Response* response) {
if (!response) {
LOG(ERROR) << "Failed to get debug logs";
callback.Run(false);
return;
}
callback.Run(true);
}
// Called when a response for SetDebugMode() is received.
void OnSetDebugMode(const SetDebugModeCallback& callback,
dbus::Response* response) {
if (!response) {
LOG(ERROR) << "Failed to change debug mode";
callback.Run(false);
} else {
callback.Run(true);
}
}
void OnGetRoutes(const GetRoutesCallback& callback,
dbus::Response* response) {
std::vector<std::string> routes;
if (response) {
dbus::MessageReader reader(response);
if (reader.PopArrayOfStrings(&routes)) {
callback.Run(true, routes);
} else {
LOG(ERROR) << "Got non-array response from GetRoutes";
callback.Run(false, routes);
}
} else {
callback.Run(false, routes);
}
}
void OnGetNetworkStatus(const GetNetworkStatusCallback& callback,
dbus::Response* response) {
std::string status;
if (response && dbus::MessageReader(response).PopString(&status))
callback.Run(true, status);
else
callback.Run(false, "");
}
void OnGetModemStatus(const GetModemStatusCallback& callback,
dbus::Response* response) {
std::string status;
if (response && dbus::MessageReader(response).PopString(&status))
callback.Run(true, status);
else
callback.Run(false, "");
}
void OnGetWiMaxStatus(const GetWiMaxStatusCallback& callback,
dbus::Response* response) {
std::string status;
if (response && dbus::MessageReader(response).PopString(&status))
callback.Run(true, status);
else
callback.Run(false, "");
}
void OnGetNetworkInterfaces(const GetNetworkInterfacesCallback& callback,
dbus::Response* response) {
std::string status;
if (response && dbus::MessageReader(response).PopString(&status))
callback.Run(true, status);
else
callback.Run(false, "");
}
void OnGetAllLogs(const GetLogsCallback& callback,
dbus::Response* response) {
std::map<std::string, std::string> logs;
bool broken = false; // did we see a broken (k,v) pair?
dbus::MessageReader sub_reader(NULL);
if (!response || !dbus::MessageReader(response).PopArray(&sub_reader)) {
callback.Run(false, logs);
return;
}
while (sub_reader.HasMoreData()) {
dbus::MessageReader sub_sub_reader(NULL);
std::string key, value;
if (!sub_reader.PopDictEntry(&sub_sub_reader)
|| !sub_sub_reader.PopString(&key)
|| !sub_sub_reader.PopString(&value)) {
broken = true;
break;
}
logs[key] = value;
}
callback.Run(!sub_reader.HasMoreData() && !broken, logs);
}
void OnGetUserLogFiles(const GetLogsCallback& callback,
dbus::Response* response) {
return OnGetAllLogs(callback, response);
}
void OnBigFeedbackLogsResponse(base::WeakPtr<PipeReaderWrapper> pipe_reader,
dbus::Response* response) {
if (!response && pipe_reader.get()) {
// We need to terminate the data stream if an error occurred while the
// pipe reader is still waiting on read.
pipe_reader->TerminateStream();
}
}
// Called when a response for a simple start is received.
void OnStartMethod(dbus::Response* response) {
if (!response) {
LOG(ERROR) << "Failed to request start";
return;
}
}
void OnDBusMethodError(DBusMethodErrorCallback error_callback,
dbus::ErrorResponse* response) {
// Error response has optional error message argument.
std::string error_name = "<unknown>";
std::string error_message = "<empty>";
if (response) {
dbus::MessageReader reader(response);
error_name = response->GetErrorName();
reader.PopString(&error_message);
}
VLOG(1) << "DBus method error: " << error_name << ": " << error_message;
error_callback.Run(error_name, error_message);
}
void OnEnableDebuggingFeatures(
const EnableDebuggingCallback& callback,
dbus::Response* response) {
if (callback.is_null())
return;
callback.Run(response != NULL);
}
void OnQueryDebuggingFeatures(
const QueryDevFeaturesCallback& callback,
dbus::Response* response) {
if (callback.is_null())
return;
int32_t feature_mask = DEV_FEATURE_NONE;
if (!response || !dbus::MessageReader(response).PopInt32(&feature_mask)) {
callback.Run(false, debugd::DevFeatureFlag::DEV_FEATURES_DISABLED);
return;
}
callback.Run(true, feature_mask);
}
void OnRemoveRootfsVerification(
const EnableDebuggingCallback& callback,
dbus::Response* response) {
if (callback.is_null())
return;
callback.Run(response != NULL);
}
// Called when a response for StopAgentTracing() is received.
void OnStopAgentTracing(dbus::Response* response) {
if (!response) {
LOG(ERROR) << "Failed to request systrace stop";
// If debugd crashes or completes I/O before this message is processed
// then pipe_reader_ can be NULL, see OnIOComplete().
if (pipe_reader_.get())
pipe_reader_->OnDataReady(-1); // terminate data stream
}
// NB: requester is signaled when i/o completes
}
void OnTestICMP(const TestICMPCallback& callback, dbus::Response* response) {
std::string status;
if (response && dbus::MessageReader(response).PopString(&status))
callback.Run(true, status);
else
callback.Run(false, "");
}
// Called when pipe i/o completes; pass data on and delete the instance.
void OnIOComplete() {
std::string pipe_data;
pipe_reader_->GetData(&pipe_data);
callback_.Run(GetTracingAgentName(), GetTraceEventLabel(),
base::RefCountedString::TakeString(&pipe_data));
pipe_reader_.reset();
}
void OnSetOomScoreAdj(const SetOomScoreAdjCallback& callback,
dbus::Response* response) {
std::string output;
if (response && dbus::MessageReader(response).PopString(&output))
callback.Run(true, output);
else
callback.Run(false, "");
}
void OnPrinterAdded(const CupsAddPrinterCallback& callback,
const base::Closure& error_callback,
dbus::Response* response) {
bool result = false;
dbus::MessageReader reader(response);
if (response && reader.PopBool(&result)) {
callback.Run(result);
} else {
error_callback.Run();
}
}
void OnPrinterRemoved(const CupsRemovePrinterCallback& callback,
const base::Closure& error_callback,
dbus::Response* response) {
bool result = false;
dbus::MessageReader reader(response);
if (response && reader.PopBool(&result)) {
callback.Run(result);
} else {
error_callback.Run();
}
}
dbus::ObjectProxy* debugdaemon_proxy_;
std::unique_ptr<PipeReaderForString> pipe_reader_;
StopAgentTracingCallback callback_;
scoped_refptr<base::TaskRunner> stop_agent_tracing_task_runner_;
base::WeakPtrFactory<DebugDaemonClientImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(DebugDaemonClientImpl);
};
DebugDaemonClient::DebugDaemonClient() {
}
DebugDaemonClient::~DebugDaemonClient() {
}
// static
DebugDaemonClient::StopAgentTracingCallback
DebugDaemonClient::EmptyStopAgentTracingCallback() {
return base::Bind(&EmptyStopAgentTracingCallbackBody);
}
// static
DebugDaemonClient* DebugDaemonClient::Create() {
return new DebugDaemonClientImpl();
}
} // namespace chromeos