| // Copyright 2021 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 "rmad/dbus_service.h" |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include <base/bind.h> |
| #include <base/logging.h> |
| #include <base/process/launch.h> |
| #include <brillo/dbus/data_serialization.h> |
| #include <dbus/bus.h> |
| #include <dbus/object_path.h> |
| #include <dbus/rmad/dbus-constants.h> |
| |
| namespace brillo { |
| namespace dbus_utils { |
| |
| using rmad::CalibrationComponentStatus; |
| using rmad::CalibrationOverallStatus; |
| using rmad::HardwareVerificationResult; |
| using rmad::ProvisionDeviceState; |
| using rmad::RmadComponent; |
| using rmad::RmadErrorCode; |
| |
| // Overload AppendValueToWriter() for |HardwareVerificationResult| and |
| // |CalibrationComponentStatus| structures. |
| void AppendValueToWriter(dbus::MessageWriter* writer, |
| const HardwareVerificationResult& value) { |
| dbus::MessageWriter struct_writer(nullptr); |
| writer->OpenStruct(&struct_writer); |
| AppendValueToWriter(&struct_writer, value.is_compliant()); |
| AppendValueToWriter(&struct_writer, value.error_str()); |
| writer->CloseContainer(&struct_writer); |
| } |
| |
| void AppendValueToWriter(dbus::MessageWriter* writer, |
| const CalibrationComponentStatus& value) { |
| dbus::MessageWriter struct_writer(nullptr); |
| writer->OpenStruct(&struct_writer); |
| AppendValueToWriter(&struct_writer, static_cast<int>(value.component())); |
| AppendValueToWriter(&struct_writer, static_cast<int>(value.status())); |
| AppendValueToWriter(&struct_writer, value.progress()); |
| writer->CloseContainer(&struct_writer); |
| } |
| |
| // Overload PopValueFromReader() for |HardwareVerificationResult| and |
| // |CalibrationComponentStatus| structures. |
| bool PopValueFromReader(dbus::MessageReader* reader, |
| HardwareVerificationResult* value) { |
| dbus::MessageReader struct_reader(nullptr); |
| if (!reader->PopStruct(&struct_reader)) { |
| return false; |
| } |
| |
| bool is_compliant; |
| std::string error_str; |
| if (!PopValueFromReader(&struct_reader, &is_compliant) || |
| !PopValueFromReader(&struct_reader, &error_str)) { |
| return false; |
| } |
| value->set_is_compliant(is_compliant); |
| value->set_error_str(error_str); |
| return true; |
| } |
| |
| bool PopValueFromReader(dbus::MessageReader* reader, |
| CalibrationComponentStatus* value) { |
| dbus::MessageReader struct_reader(nullptr); |
| if (!reader->PopStruct(&struct_reader)) { |
| return false; |
| } |
| |
| int component, status; |
| double progress; |
| if (!PopValueFromReader(&struct_reader, &component) || |
| !PopValueFromReader(&struct_reader, &status) || |
| !PopValueFromReader(&struct_reader, &progress)) { |
| return false; |
| } |
| value->set_component(static_cast<RmadComponent>(component)); |
| value->set_status( |
| static_cast<CalibrationComponentStatus::CalibrationStatus>(status)); |
| value->set_progress(progress); |
| return true; |
| } |
| |
| // DBusType definition for signals. |
| template <> |
| struct DBusType<RmadErrorCode> { |
| inline static std::string GetSignature() { |
| return DBusType<int>::GetSignature(); |
| } |
| inline static void Write(dbus::MessageWriter* writer, |
| const RmadErrorCode value) { |
| DBusType<int>::Write(writer, static_cast<int>(value)); |
| } |
| inline static bool Read(dbus::MessageReader* reader, RmadErrorCode* value) { |
| int v; |
| if (DBusType<int>::Read(reader, &v)) { |
| *value = static_cast<rmad::RmadErrorCode>(v); |
| return true; |
| } else { |
| return false; |
| } |
| } |
| }; |
| |
| template <> |
| struct DBusType<HardwareVerificationResult> { |
| inline static std::string GetSignature() { |
| return GetStructDBusSignature<bool, std::string>(); |
| } |
| inline static void Write(dbus::MessageWriter* writer, |
| const HardwareVerificationResult& value) { |
| AppendValueToWriter(writer, value); |
| } |
| inline static bool Read(dbus::MessageReader* reader, |
| HardwareVerificationResult* value) { |
| return PopValueFromReader(reader, value); |
| } |
| }; |
| |
| template <> |
| struct DBusType<CalibrationOverallStatus> { |
| inline static std::string GetSignature() { |
| return DBusType<int>::GetSignature(); |
| } |
| inline static void Write(dbus::MessageWriter* writer, |
| const CalibrationOverallStatus value) { |
| DBusType<int>::Write(writer, static_cast<int>(value)); |
| } |
| inline static bool Read(dbus::MessageReader* reader, |
| CalibrationOverallStatus* value) { |
| int v; |
| if (DBusType<int>::Read(reader, &v)) { |
| *value = static_cast<CalibrationOverallStatus>(v); |
| return true; |
| } else { |
| return false; |
| } |
| } |
| }; |
| |
| template <> |
| struct DBusType<CalibrationComponentStatus> { |
| inline static std::string GetSignature() { |
| return GetStructDBusSignature<int, int, double>(); |
| } |
| inline static void Write(dbus::MessageWriter* writer, |
| const CalibrationComponentStatus& value) { |
| AppendValueToWriter(writer, value); |
| } |
| inline static bool Read(dbus::MessageReader* reader, |
| CalibrationComponentStatus* value) { |
| return PopValueFromReader(reader, value); |
| } |
| }; |
| |
| template <> |
| struct DBusType<ProvisionDeviceState::ProvisioningStep> { |
| inline static std::string GetSignature() { |
| return DBusType<int>::GetSignature(); |
| } |
| inline static void Write(dbus::MessageWriter* writer, |
| const ProvisionDeviceState::ProvisioningStep value) { |
| DBusType<int>::Write(writer, static_cast<int>(value)); |
| } |
| inline static bool Read(dbus::MessageReader* reader, |
| ProvisionDeviceState::ProvisioningStep* value) { |
| int v; |
| if (DBusType<int>::Read(reader, &v)) { |
| *value = static_cast<ProvisionDeviceState::ProvisioningStep>(v); |
| return true; |
| } else { |
| return false; |
| } |
| } |
| }; |
| |
| } // namespace dbus_utils |
| } // namespace brillo |
| |
| namespace rmad { |
| |
| namespace { |
| |
| const char kCroslogCmd[] = "/usr/sbin/croslog"; |
| |
| } // namespace |
| |
| using brillo::dbus_utils::AsyncEventSequencer; |
| using brillo::dbus_utils::DBusObject; |
| |
| DBusService::DBusService(RmadInterface* rmad_interface) |
| : brillo::DBusServiceDaemon(kRmadServiceName), |
| rmad_interface_(rmad_interface) {} |
| |
| DBusService::DBusService(const scoped_refptr<dbus::Bus>& bus, |
| RmadInterface* rmad_interface) |
| : brillo::DBusServiceDaemon(kRmadServiceName), |
| rmad_interface_(rmad_interface) { |
| dbus_object_ = std::make_unique<DBusObject>( |
| nullptr, bus, dbus::ObjectPath(kRmadServicePath)); |
| } |
| |
| int DBusService::OnInit() { |
| VLOG(1) << "Starting DBus service"; |
| const int exit_code = DBusServiceDaemon::OnInit(); |
| // Try a state transition after initialization. |
| rmad_interface_->TryTransitionNextStateFromCurrentState(); |
| return exit_code; |
| } |
| |
| void DBusService::RegisterDBusObjectsAsync(AsyncEventSequencer* sequencer) { |
| if (!dbus_object_.get()) { |
| CHECK(bus_.get()); |
| dbus_object_ = std::make_unique<DBusObject>( |
| nullptr, bus_, dbus::ObjectPath(kRmadServicePath)); |
| } |
| brillo::dbus_utils::DBusInterface* dbus_interface = |
| dbus_object_->AddOrGetInterface(kRmadInterfaceName); |
| |
| dbus_interface->AddMethodHandler( |
| kGetCurrentStateMethod, base::Unretained(this), |
| &DBusService::HandleMethod<GetStateReply, |
| &RmadInterface::GetCurrentState>); |
| dbus_interface->AddMethodHandler( |
| kTransitionNextStateMethod, base::Unretained(this), |
| &DBusService::HandleMethod<TransitionNextStateRequest, GetStateReply, |
| &RmadInterface::TransitionNextState>); |
| dbus_interface->AddMethodHandler( |
| kTransitionPreviousStateMethod, base::Unretained(this), |
| &DBusService::HandleMethod<GetStateReply, |
| &RmadInterface::TransitionPreviousState>); |
| dbus_interface->AddMethodHandler( |
| kAbortRmaMethod, base::Unretained(this), |
| &DBusService::HandleMethod<AbortRmaReply, &RmadInterface::AbortRma>); |
| |
| dbus_interface->AddSimpleMethodHandler(kGetLogPathMethod, |
| base::Unretained(this), |
| &DBusService::HandleGetLogPathMethod); |
| dbus_interface->AddSimpleMethodHandler(kGetLogMethod, base::Unretained(this), |
| &DBusService::HandleGetLogMethod); |
| |
| error_signal_ = dbus_interface->RegisterSignal<RmadErrorCode>(kErrorSignal); |
| hardware_verification_signal_ = |
| dbus_interface->RegisterSignal<HardwareVerificationResult>( |
| kHardwareVerificationResultSignal); |
| calibration_overall_signal_ = |
| dbus_interface->RegisterSignal<CalibrationOverallStatus>( |
| kCalibrationOverallSignal); |
| calibration_component_signal_ = |
| dbus_interface->RegisterSignal<CalibrationComponentStatus>( |
| kCalibrationProgressSignal); |
| provisioning_signal_ = |
| dbus_interface |
| ->RegisterSignal<ProvisionDeviceState::ProvisioningStep, double>( |
| kProvisioningProgressSignal); |
| hwwp_signal_ = |
| dbus_interface->RegisterSignal<bool>(kHardwareWriteProtectionStateSignal); |
| power_cable_signal_ = |
| dbus_interface->RegisterSignal<bool>(kPowerCableStateSignal); |
| |
| RegisterSignalSenders(); |
| |
| dbus_object_->RegisterAsync( |
| sequencer->GetHandler("Failed to register D-Bus objects.", true)); |
| } |
| |
| void DBusService::RegisterSignalSenders() { |
| rmad_interface_->RegisterSignalSender( |
| RmadState::StateCase::kWpDisablePhysical, |
| std::make_unique<base::RepeatingCallback<bool(bool)>>(base::BindRepeating( |
| &DBusService::SendHardwareWriteProtectionStateSignal, |
| base::Unretained(this)))); |
| rmad_interface_->RegisterSignalSender( |
| RmadState::StateCase::kWpEnablePhysical, |
| std::make_unique<base::RepeatingCallback<bool(bool)>>(base::BindRepeating( |
| &DBusService::SendHardwareWriteProtectionStateSignal, |
| base::Unretained(this)))); |
| rmad_interface_->RegisterSignalSender( |
| RmadState::StateCase::kWelcome, |
| std::make_unique< |
| base::RepeatingCallback<bool(const HardwareVerificationResult&)>>( |
| base::BindRepeating( |
| &DBusService::SendHardwareVerificationResultSignal, |
| base::Unretained(this)))); |
| rmad_interface_->RegisterSignalSender( |
| RmadState::StateCase::kRunCalibration, |
| std::make_unique<base::RepeatingCallback<bool(CalibrationOverallStatus)>>( |
| base::BindRepeating(&DBusService::SendCalibrationOverallSignal, |
| base::Unretained(this)))); |
| rmad_interface_->RegisterSignalSender( |
| RmadState::StateCase::kRunCalibration, |
| std::make_unique< |
| base::RepeatingCallback<bool(CalibrationComponentStatus)>>( |
| base::BindRepeating(&DBusService::SendCalibrationProgressSignal, |
| base::Unretained(this)))); |
| } |
| |
| std::string DBusService::HandleGetLogPathMethod() { |
| return "not_supported"; |
| } |
| |
| GetLogReply DBusService::HandleGetLogMethod() { |
| GetLogReply reply; |
| std::string log_string; |
| if (base::GetAppOutput({kCroslogCmd, "--identifier=rmad"}, &log_string)) { |
| reply.set_log(log_string); |
| } else { |
| LOG(ERROR) << "Failed to generate logs from croslog"; |
| reply.set_error(RMAD_ERROR_CANNOT_GET_LOG); |
| } |
| return reply; |
| } |
| |
| bool DBusService::SendErrorSignal(RmadErrorCode error) { |
| auto signal = error_signal_.lock(); |
| return (signal.get() == nullptr) ? false : signal->Send(error); |
| } |
| |
| bool DBusService::SendHardwareVerificationResultSignal( |
| const HardwareVerificationResult& result) { |
| auto signal = hardware_verification_signal_.lock(); |
| return (signal.get() == nullptr) ? false : signal->Send(result); |
| } |
| |
| bool DBusService::SendCalibrationOverallSignal( |
| CalibrationOverallStatus status) { |
| auto signal = calibration_overall_signal_.lock(); |
| return (signal.get() == nullptr) ? false : signal->Send(status); |
| } |
| |
| bool DBusService::SendCalibrationProgressSignal( |
| CalibrationComponentStatus status) { |
| auto signal = calibration_component_signal_.lock(); |
| return (signal.get() == nullptr) ? false : signal->Send(status); |
| } |
| |
| bool DBusService::SendProvisioningProgressSignal( |
| ProvisionDeviceState::ProvisioningStep step, double progress) { |
| auto signal = provisioning_signal_.lock(); |
| return (signal.get() == nullptr) ? false : signal->Send(step, progress); |
| } |
| |
| bool DBusService::SendHardwareWriteProtectionStateSignal(bool enabled) { |
| auto signal = hwwp_signal_.lock(); |
| return (signal.get() == nullptr) ? false : signal->Send(enabled); |
| } |
| |
| bool DBusService::SendPowerCableStateSignal(bool plugged_in) { |
| auto signal = power_cable_signal_.lock(); |
| return (signal.get() == nullptr) ? false : signal->Send(plugged_in); |
| } |
| |
| void DBusService::ConditionallyQuit() { |
| const RmadState::StateCase current_state_case = |
| rmad_interface_->GetCurrentStateCase(); |
| if (current_state_case == RmadState::STATE_NOT_SET || |
| current_state_case == RmadState::kWpDisableComplete) { |
| PostQuitTask(); |
| } |
| } |
| |
| void DBusService::PostQuitTask() { |
| if (bus_) { |
| VLOG(1) << "Stopping DBus service"; |
| bus_->GetOriginTaskRunner()->PostTask( |
| FROM_HERE, base::BindOnce(&Daemon::Quit, base::Unretained(this))); |
| } |
| } |
| |
| } // namespace rmad |