blob: c80986ab0517b505b5b0a5dab92075305eb2ecd0 [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS 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 "debugd/src/debugd_dbus_adaptor.h"
#include <memory>
#include <utility>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/memory/ref_counted.h>
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
#include <brillo/variant_dictionary.h>
#include <chromeos/dbus/service_constants.h>
#include <dbus/object_path.h>
#include "debugd/src/constants.h"
#include "debugd/src/error_utils.h"
#include "debugd/src/process_with_output.h"
namespace debugd {
namespace {
const char kDevCoredumpDBusErrorString[] =
"org.chromium.debugd.error.DevCoreDump";
const char kShouldSendRlzPingKey[] = "should_send_rlz_ping";
const char kRlzEmbargoEndDateKey[] = "rlz_embargo_end_date";
} // namespace
DebugdDBusAdaptor::DebugdDBusAdaptor(scoped_refptr<dbus::Bus> bus)
: org::chromium::debugdAdaptor(this),
dbus_object_(nullptr, bus, dbus::ObjectPath(kDebugdServicePath)) {
battery_tool_ = std::make_unique<BatteryTool>();
container_tool_ = std::make_unique<ContainerTool>();
crash_sender_tool_ = std::make_unique<CrashSenderTool>();
cups_tool_ = std::make_unique<CupsTool>();
cros_healthd_tool_ = std::make_unique<CrosHealthdTool>();
debug_logs_tool_ = std::make_unique<DebugLogsTool>(bus);
debug_mode_tool_ = std::make_unique<DebugModeTool>(bus);
dev_features_tool_wrapper_ =
std::make_unique<RestrictedToolWrapper<DevFeaturesTool>>(bus);
dmesg_tool_ = std::make_unique<DmesgTool>();
ec_typec_tool_ = std::make_unique<EcTypeCTool>();
example_tool_ = std::make_unique<ExampleTool>();
icmp_tool_ = std::make_unique<ICMPTool>();
ipaddrs_tool_ = std::make_unique<IpAddrsTool>();
log_tool_ = std::make_unique<LogTool>(bus);
memory_tool_ = std::make_unique<MemtesterTool>();
netif_tool_ = std::make_unique<NetifTool>();
network_status_tool_ = std::make_unique<NetworkStatusTool>();
oom_adj_tool_ = std::make_unique<OomAdjTool>();
packet_capture_tool_ = std::make_unique<PacketCaptureTool>();
perf_tool_ = std::make_unique<PerfTool>();
ping_tool_ = std::make_unique<PingTool>();
probe_tool_ = std::make_unique<ProbeTool>();
route_tool_ = std::make_unique<RouteTool>();
shill_scripts_tool_ = std::make_unique<ShillScriptsTool>();
storage_tool_ = std::make_unique<StorageTool>();
swap_tool_ = std::make_unique<SwapTool>();
sysrq_tool_ = std::make_unique<SysrqTool>();
systrace_tool_ = std::make_unique<SystraceTool>();
tracepath_tool_ = std::make_unique<TracePathTool>();
u2f_tool_ = std::make_unique<U2fTool>();
verify_ro_tool_ = std::make_unique<VerifyRoTool>();
vm_plugin_dispatcher_tool_ = std::make_unique<SimpleServiceTool>(
"vmplugin_dispatcher", bus,
vm_tools::plugin_dispatcher::kVmPluginDispatcherServiceName,
vm_tools::plugin_dispatcher::kVmPluginDispatcherServicePath);
wifi_fw_dump_tool_ = std::make_unique<WifiFWDumpTool>();
wifi_power_tool_ = std::make_unique<WifiPowerTool>();
session_manager_proxy_ = std::make_unique<SessionManagerProxy>(bus);
scheduler_configuration_tool_ =
std::make_unique<SchedulerConfigurationTool>();
if (dev_features_tool_wrapper_->restriction().InDevMode() &&
base::PathExists(
base::FilePath(debugd::kDevFeaturesChromeRemoteDebuggingFlagPath))) {
session_manager_proxy_->EnableChromeRemoteDebugging();
}
}
void DebugdDBusAdaptor::RegisterAsync(
const brillo::dbus_utils::AsyncEventSequencer::CompletionAction& cb) {
auto* my_interface = dbus_object_.AddOrGetInterface(kDebugdInterface);
DCHECK(my_interface);
my_interface->AddProperty(kCrashSenderTestMode, &crash_sender_test_mode_);
crash_sender_test_mode_.SetUpdateCallback(
base::Bind(&CrashSenderTool::OnTestModeChanged,
base::Unretained(crash_sender_tool_.get())));
crash_sender_test_mode_.SetValue(false);
crash_sender_test_mode_.SetAccessMode(
brillo::dbus_utils::ExportedPropertyBase::Access::kReadWrite);
RegisterWithDBusObject(&dbus_object_);
dbus_object_.RegisterAsync(cb);
}
std::string DebugdDBusAdaptor::SetOomScoreAdj(
const std::map<pid_t, int32_t>& scores) {
return oom_adj_tool_->Set(scores);
}
bool DebugdDBusAdaptor::PingStart(brillo::ErrorPtr* error,
const base::ScopedFD& outfd,
const std::string& destination,
const brillo::VariantDictionary& options,
std::string* handle) {
return ping_tool_->Start(outfd, destination, options, handle, error);
}
bool DebugdDBusAdaptor::PingStop(brillo::ErrorPtr* error,
const std::string& handle) {
return ping_tool_->Stop(handle, error);
}
std::string DebugdDBusAdaptor::TracePathStart(
const base::ScopedFD& outfd,
const std::string& destination,
const brillo::VariantDictionary& options) {
return tracepath_tool_->Start(outfd, destination, options);
}
bool DebugdDBusAdaptor::TracePathStop(brillo::ErrorPtr* error,
const std::string& handle) {
return tracepath_tool_->Stop(handle, error);
}
void DebugdDBusAdaptor::SystraceStart(const std::string& categories) {
(void)systrace_tool_->Start(categories);
}
void DebugdDBusAdaptor::SystraceStop(const base::ScopedFD& outfd) {
systrace_tool_->Stop(outfd);
}
std::string DebugdDBusAdaptor::SystraceStatus() {
return systrace_tool_->Status();
}
std::vector<std::string> DebugdDBusAdaptor::GetIpAddresses(
const brillo::VariantDictionary& options) {
return ipaddrs_tool_->GetIpAddresses(options);
}
std::vector<std::string> DebugdDBusAdaptor::GetRoutes(
const brillo::VariantDictionary& options) {
return route_tool_->GetRoutes(options);
}
std::string DebugdDBusAdaptor::GetNetworkStatus() {
return network_status_tool_->GetNetworkStatus();
}
bool DebugdDBusAdaptor::GetPerfOutput(brillo::ErrorPtr* error,
uint32_t duration_sec,
const std::vector<std::string>& perf_args,
int32_t* status,
std::vector<uint8_t>* perf_data,
std::vector<uint8_t>* perf_stat) {
return perf_tool_->GetPerfOutput(duration_sec, perf_args, perf_data,
perf_stat, status, error);
}
bool DebugdDBusAdaptor::GetPerfOutputFd(
brillo::ErrorPtr* error,
uint32_t duration_sec,
const std::vector<std::string>& perf_args,
const base::ScopedFD& stdout_fd,
uint64_t* session_id) {
return perf_tool_->GetPerfOutputFd(duration_sec, perf_args, stdout_fd,
session_id, error);
}
bool DebugdDBusAdaptor::StopPerf(brillo::ErrorPtr* error, uint64_t session_id) {
return perf_tool_->StopPerf(session_id, error);
}
void DebugdDBusAdaptor::DumpDebugLogs(bool is_compressed,
const base::ScopedFD& fd) {
debug_logs_tool_->GetDebugLogs(is_compressed, fd);
}
void DebugdDBusAdaptor::SetDebugMode(const std::string& subsystem) {
debug_mode_tool_->SetDebugMode(subsystem);
}
std::string DebugdDBusAdaptor::GetLog(const std::string& name) {
return log_tool_->GetLog(name);
}
std::map<std::string, std::string> DebugdDBusAdaptor::GetAllLogs() {
return log_tool_->GetAllLogs();
}
void DebugdDBusAdaptor::GetBigFeedbackLogs(const base::ScopedFD& fd,
const std::string& username) {
log_tool_->GetBigFeedbackLogs(fd, username);
}
void DebugdDBusAdaptor::BackupArcBugReport(const std::string& username) {
log_tool_->BackupArcBugReport(username);
}
void DebugdDBusAdaptor::DeleteArcBugReportBackup(const std::string& username) {
log_tool_->DeleteArcBugReportBackup(username);
}
void DebugdDBusAdaptor::GetJournalLog(const base::ScopedFD& fd) {
log_tool_->GetJournalLog(fd);
}
std::string DebugdDBusAdaptor::GetExample() {
return example_tool_->GetExample();
}
int32_t DebugdDBusAdaptor::CupsAddAutoConfiguredPrinter(
const std::string& name, const std::string& uri) {
return cups_tool_->AddAutoConfiguredPrinter(name, uri);
}
int32_t DebugdDBusAdaptor::CupsAddManuallyConfiguredPrinter(
const std::string& name,
const std::string& uri,
const std::vector<uint8_t>& ppd_contents) {
return cups_tool_->AddManuallyConfiguredPrinter(name, uri, ppd_contents);
}
bool DebugdDBusAdaptor::CupsRemovePrinter(const std::string& name) {
return cups_tool_->RemovePrinter(name);
}
std::string DebugdDBusAdaptor::GetInterfaces() {
return netif_tool_->GetInterfaces();
}
std::string DebugdDBusAdaptor::TestICMP(const std::string& host) {
return icmp_tool_->TestICMP(host);
}
std::string DebugdDBusAdaptor::TestICMPWithOptions(
const std::string& host,
const std::map<std::string, std::string>& options) {
return icmp_tool_->TestICMPWithOptions(host, options);
}
std::string DebugdDBusAdaptor::BatteryFirmware(const std::string& option) {
return battery_tool_->BatteryFirmware(option);
}
std::string DebugdDBusAdaptor::Smartctl(const std::string& option) {
return storage_tool_->Smartctl(option);
}
std::string DebugdDBusAdaptor::Mmc(const std::string& option) {
return storage_tool_->Mmc(option);
}
std::string DebugdDBusAdaptor::Nvme(const std::string& option) {
return storage_tool_->Nvme(option);
}
std::string DebugdDBusAdaptor::NvmeLog(const uint32_t page_id,
const uint32_t length,
bool raw_binary) {
return storage_tool_->NvmeLog(page_id, length, raw_binary);
}
std::string DebugdDBusAdaptor::MemtesterStart(const base::ScopedFD& outfd,
uint32_t memory) {
return memory_tool_->Start(outfd, memory);
}
bool DebugdDBusAdaptor::MemtesterStop(brillo::ErrorPtr* error,
const std::string& handle) {
return memory_tool_->Stop(handle, error);
}
std::string DebugdDBusAdaptor::BadblocksStart(const base::ScopedFD& outfd) {
return storage_tool_->Start(outfd);
}
bool DebugdDBusAdaptor::BadblocksStop(brillo::ErrorPtr* error,
const std::string& handle) {
return storage_tool_->Stop(handle, error);
}
bool DebugdDBusAdaptor::PacketCaptureStart(
brillo::ErrorPtr* error,
const base::ScopedFD& statfd,
const base::ScopedFD& outfd,
const brillo::VariantDictionary& options,
std::string* handle) {
return packet_capture_tool_->Start(statfd, outfd, options, handle, error);
}
bool DebugdDBusAdaptor::PacketCaptureStop(brillo::ErrorPtr* error,
const std::string& handle) {
return packet_capture_tool_->Stop(handle, error);
}
bool DebugdDBusAdaptor::LogKernelTaskStates(brillo::ErrorPtr* error) {
return sysrq_tool_->LogKernelTaskStates(error);
}
void DebugdDBusAdaptor::UploadCrashes() {
crash_sender_tool_->UploadCrashes();
}
bool DebugdDBusAdaptor::UploadSingleCrash(
brillo::ErrorPtr* error,
const std::vector<std::tuple<std::string, base::ScopedFD>>& in_files) {
return crash_sender_tool_->UploadSingleCrash(in_files, error);
}
bool DebugdDBusAdaptor::RemoveRootfsVerification(brillo::ErrorPtr* error) {
auto tool = dev_features_tool_wrapper_->GetTool(error);
return tool && tool->RemoveRootfsVerification(error);
}
bool DebugdDBusAdaptor::EnableBootFromUsb(brillo::ErrorPtr* error) {
auto tool = dev_features_tool_wrapper_->GetTool(error);
return tool && tool->EnableBootFromUsb(error);
}
bool DebugdDBusAdaptor::EnableChromeRemoteDebugging(brillo::ErrorPtr* error) {
auto tool = dev_features_tool_wrapper_->GetTool(error);
return tool && tool->EnableChromeRemoteDebugging(error);
}
bool DebugdDBusAdaptor::ConfigureSshServer(brillo::ErrorPtr* error) {
auto tool = dev_features_tool_wrapper_->GetTool(error);
return tool && tool->ConfigureSshServer(error);
}
bool DebugdDBusAdaptor::SetUserPassword(brillo::ErrorPtr* error,
const std::string& username,
const std::string& password) {
auto tool = dev_features_tool_wrapper_->GetTool(error);
return tool && tool->SetUserPassword(username, password, error);
}
bool DebugdDBusAdaptor::EnableChromeDevFeatures(
brillo::ErrorPtr* error, const std::string& root_password) {
auto tool = dev_features_tool_wrapper_->GetTool(error);
return tool && tool->EnableChromeDevFeatures(root_password, error);
}
bool DebugdDBusAdaptor::QueryDevFeatures(brillo::ErrorPtr* error,
int32_t* features) {
// Special case: if access fails here, we return DEV_FEATURES_DISABLED rather
// than a D-Bus error. However, we still want to return an error if we can
// access the tool but the tool execution fails.
auto tool = dev_features_tool_wrapper_->GetTool(nullptr);
if (!tool) {
*features = DEV_FEATURES_DISABLED;
return true;
}
return tool && tool->QueryDevFeatures(features, error);
}
bool DebugdDBusAdaptor::EnableDevCoredumpUpload(brillo::ErrorPtr* error) {
if (base::PathExists(base::FilePath(debugd::kDeviceCoredumpUploadFlagPath))) {
VLOG(1) << "Device coredump upload already enabled";
return true;
}
if (base::WriteFile(base::FilePath(debugd::kDeviceCoredumpUploadFlagPath), "",
0) < 0) {
DEBUGD_ADD_ERROR(error, kDevCoredumpDBusErrorString,
"Failed to write flag file.");
PLOG(ERROR) << "Failed to write flag file.";
return false;
}
return true;
}
bool DebugdDBusAdaptor::DisableDevCoredumpUpload(brillo::ErrorPtr* error) {
if (!base::PathExists(
base::FilePath(debugd::kDeviceCoredumpUploadFlagPath))) {
VLOG(1) << "Device coredump upload already disabled";
return true;
}
if (!base::DeleteFile(
base::FilePath(debugd::kDeviceCoredumpUploadFlagPath))) {
DEBUGD_ADD_ERROR(error, kDevCoredumpDBusErrorString,
"Failed to delete flag file.");
PLOG(ERROR) << "Failed to delete flag file.";
return false;
}
return true;
}
bool DebugdDBusAdaptor::KstaledSetRatio(brillo::ErrorPtr* error,
uint8_t kstaled_ratio,
bool* out_result) {
*out_result = swap_tool_->KstaledSetRatio(error, kstaled_ratio);
return *out_result;
}
std::string DebugdDBusAdaptor::SwapEnable(int32_t size, bool change_now) {
return swap_tool_->SwapEnable(size, change_now);
}
std::string DebugdDBusAdaptor::SwapDisable(bool change_now) {
return swap_tool_->SwapDisable(change_now);
}
std::string DebugdDBusAdaptor::SwapStartStop(bool on) {
return swap_tool_->SwapStartStop(on);
}
std::string DebugdDBusAdaptor::SwapStatus() {
return swap_tool_->SwapStatus();
}
std::string DebugdDBusAdaptor::SwapSetParameter(
const std::string& parameter_name, int32_t parameter_value) {
return swap_tool_->SwapSetParameter(parameter_name, parameter_value);
}
std::string DebugdDBusAdaptor::SetU2fFlags(const std::string& flags) {
return u2f_tool_->SetFlags(flags);
}
std::string DebugdDBusAdaptor::GetU2fFlags() {
return u2f_tool_->GetFlags();
}
void DebugdDBusAdaptor::ContainerStarted() {
container_tool_->ContainerStarted();
}
void DebugdDBusAdaptor::ContainerStopped() {
container_tool_->ContainerStopped();
}
std::string DebugdDBusAdaptor::WifiFWDump() {
return wifi_fw_dump_tool_->WifiFWDump();
}
std::string DebugdDBusAdaptor::SetWifiPowerSave(bool enable) {
return wifi_power_tool_->SetWifiPowerSave(enable);
}
std::string DebugdDBusAdaptor::GetWifiPowerSave() {
return wifi_power_tool_->GetWifiPowerSave();
}
bool DebugdDBusAdaptor::RunShillScriptStart(
brillo::ErrorPtr* error,
const base::ScopedFD& outfd,
const std::string& script,
const std::vector<std::string>& script_args,
std::string* handle) {
return shill_scripts_tool_->Run(outfd, script, script_args, handle, error);
}
bool DebugdDBusAdaptor::RunShillScriptStop(brillo::ErrorPtr* error,
const std::string& handle) {
return shill_scripts_tool_->Stop(handle, error);
}
void DebugdDBusAdaptor::StartVmPluginDispatcher(
std::unique_ptr<brillo::dbus_utils::DBusMethodResponse<bool>> response,
const std::string& in_user_id_hash,
const std::string& in_lang) {
// Perform basic validation of user ID hash.
if (in_user_id_hash.length() != 40) {
LOG(ERROR) << "Incorrect length of the user_id_hash (" << in_user_id_hash
<< ")";
response->Return(false);
return;
}
if (!base::ContainsOnlyChars(in_user_id_hash, "abcdef0123456789")) {
LOG(ERROR) << "user_id_hash should only contain lower case hex digits ("
<< in_user_id_hash << ")";
response->Return(false);
return;
}
// Perform basic validation of the language string. We expect it to be
// <language>[-<territory>].
std::vector<base::StringPiece> chunks = base::SplitStringPiece(
in_lang, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
if (chunks.size() < 1 || chunks.size() > 2 || chunks[0].empty()) {
LOG(ERROR) << "malformed language argument (" << in_lang << ")";
response->Return(false);
return;
}
vm_plugin_dispatcher_tool_->StartService(
{{"CROS_USER_ID_HASH", in_user_id_hash}, {"CROS_USER_UI_LANG", in_lang}},
std::move(response));
}
void DebugdDBusAdaptor::StopVmPluginDispatcher() {
vm_plugin_dispatcher_tool_->StopService();
}
bool DebugdDBusAdaptor::SetRlzPingSent(brillo::ErrorPtr* error) {
std::string stderr;
int result = ProcessWithOutput::RunProcess(
"/usr/sbin/vpd",
{"-i", "RW_VPD", "-s", std::string(kShouldSendRlzPingKey) + "=0"},
true, // requires root
false, // disable_sandbox
nullptr, // stdin
nullptr, // stdout
&stderr, error);
if (result != EXIT_SUCCESS) {
std::string error_string =
"Failed to set vpd key: " + std::string(kShouldSendRlzPingKey) +
" with exit code: " + std::to_string(result) + " with error: " + stderr;
DEBUGD_ADD_ERROR(error, kDevCoredumpDBusErrorString, error_string);
PLOG(ERROR) << error_string;
return false;
}
// Remove |kRlzEmbargoEndDateKey|, which is no longer useful after
// |kShouldSendRlzPingKey| is updated.
result = ProcessWithOutput::RunProcess(
"/usr/sbin/vpd",
{"-i", "RW_VPD", "-d", std::string(kRlzEmbargoEndDateKey)},
true, // requires root
false, // disable_sandbox
nullptr, // stdin
nullptr, // stdout
&stderr, error);
if (result != EXIT_SUCCESS) {
std::string error_string =
"Failed to delete vpd key: " + std::string(kRlzEmbargoEndDateKey) +
" with exit code: " + std::to_string(result) + " with error: " + stderr;
DEBUGD_ADD_ERROR(error, kDevCoredumpDBusErrorString, error_string);
PLOG(ERROR) << error_string;
}
// Regenerate the vpd cache log.
result = ProcessWithOutput::RunProcess("/usr/sbin/dump_vpd_log", {"--force"},
true, // requires root
false, // disable_sandbox
nullptr, // stdin
nullptr, // stdout
&stderr, error);
if (result != EXIT_SUCCESS) {
std::string error_string =
"Failed to dump vpd log with exit code: " + std::to_string(result) +
" with error: " + stderr;
DEBUGD_ADD_ERROR(error, kDevCoredumpDBusErrorString, error_string);
PLOG(ERROR) << error_string;
}
// The client only cares if updating |kShouldSendRlzPingKey| is successful, so
// returns true regardless of the result of removing |kRlzEmbargoEndDateKey|
// or the cache log update.
return true;
}
bool DebugdDBusAdaptor::UpdateAndVerifyFWOnUsbStart(
brillo::ErrorPtr* error,
const base::ScopedFD& outfd,
const std::string& image_file,
const std::string& ro_db_dir,
std::string* handle) {
return verify_ro_tool_->UpdateAndVerifyFWOnUsb(error, outfd, image_file,
ro_db_dir, handle);
}
bool DebugdDBusAdaptor::UpdateAndVerifyFWOnUsbStop(brillo::ErrorPtr* error,
const std::string& handle) {
return verify_ro_tool_->Stop(handle, error);
}
bool DebugdDBusAdaptor::SetSchedulerConfiguration(brillo::ErrorPtr* error,
const std::string& policy,
bool* result) {
uint32_t num_cores_disabled;
return SetSchedulerConfigurationV2(error, policy, false /* lock_policy */,
result, &num_cores_disabled);
}
bool DebugdDBusAdaptor::SetSchedulerConfigurationV2(
brillo::ErrorPtr* error,
const std::string& policy,
bool lock_policy,
bool* result,
uint32_t* num_cores_disabled) {
*result = scheduler_configuration_tool_->SetPolicy(policy, lock_policy, error,
num_cores_disabled);
return *result;
}
bool DebugdDBusAdaptor::EvaluateProbeFunction(
brillo::ErrorPtr* error,
const std::string& probe_statement,
brillo::dbus_utils::FileDescriptor* outfd) {
return probe_tool_->EvaluateProbeFunction(error, probe_statement, outfd);
}
bool DebugdDBusAdaptor::CollectSmartBatteryMetric(
brillo::ErrorPtr* error,
const std::string& metric_name,
std::string* output) {
return cros_healthd_tool_->CollectSmartBatteryMetric(error, metric_name,
output);
}
std::string DebugdDBusAdaptor::EcGetInventory() {
return ec_typec_tool_->GetInventory();
}
bool DebugdDBusAdaptor::CallDmesg(brillo::ErrorPtr* error,
const brillo::VariantDictionary& options,
std::string* output) {
return dmesg_tool_->CallDmesg(options, error, output);
}
} // namespace debugd