| // Copyright 2018 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include <memory> | |
| #include <string> | |
| #include <utility> | |
| #include <vector> | |
| #include <base/functional/bind.h> | |
| #include <base/json/json_writer.h> | |
| #include <base/logging.h> | |
| #include <base/task/single_thread_task_runner.h> | |
| #include <base/values.h> | |
| #include <dbus/runtime_probe/dbus-constants.h> | |
| #include <google/protobuf/util/json_util.h> | |
| #include <mojo/core/embedder/embedder.h> | |
| #include <mojo/core/embedder/scoped_ipc_support.h> | |
| #include "runtime_probe/avl_probe_config_loader.h" | |
| #include "runtime_probe/daemon.h" | |
| #include "runtime_probe/probe_config.h" | |
| #include "runtime_probe/proto_bindings/runtime_probe.pb.h" | |
| #include "runtime_probe/ssfc_probe_config_loader.h" | |
| namespace runtime_probe { | |
| namespace { | |
| using brillo::dbus_utils::AsyncEventSequencer; | |
| using brillo::dbus_utils::DBusObject; | |
| } // namespace | |
| Daemon::Daemon() | |
| : brillo::DBusServiceDaemon(kRuntimeProbeServiceName), | |
| org::chromium::RuntimeProbeAdaptor(this) {} | |
| int Daemon::OnInit() { | |
| VLOG(1) << "Starting D-Bus service"; | |
| const auto exit_code = brillo::DBusServiceDaemon::OnInit(); | |
| // Required by mojo | |
| mojo::core::Init(); | |
| ipc_support_ = std::make_unique<mojo::core::ScopedIPCSupport>( | |
| base::SingleThreadTaskRunner::GetCurrentDefault(), | |
| mojo::core::ScopedIPCSupport::ShutdownPolicy::CLEAN); | |
| return exit_code; | |
| } | |
| void Daemon::RegisterDBusObjectsAsync(AsyncEventSequencer* sequencer) { | |
| DCHECK(!dbus_object_); | |
| dbus_object_ = std::make_unique<brillo::dbus_utils::DBusObject>( | |
| nullptr, bus_, dbus::ObjectPath(kRuntimeProbeServicePath)); | |
| RegisterWithDBusObject(dbus_object_.get()); | |
| dbus_object_->RegisterAsync( | |
| sequencer->GetHandler("RegisterAsync() failed", true)); | |
| } | |
| void Daemon::ProbeCategories(Daemon::DBusCallback<ProbeResult> cb, | |
| const ProbeRequest& request) { | |
| AvlProbeConfigLoader config_loader; | |
| auto probe_config = config_loader.Load(); | |
| if (!probe_config) { | |
| ProbeResult reply; | |
| reply.set_error(RUNTIME_PROBE_ERROR_PROBE_CONFIG_INVALID); | |
| cb->Return(reply); | |
| return Quit(); | |
| } | |
| auto* probe_config_ptr = probe_config.get(); | |
| if (request.probe_default_category()) { | |
| probe_config_ptr->Eval(base::BindOnce(&Daemon::ProbeCallback<ProbeResult>, | |
| base::Unretained(this), std::move(cb), | |
| std::move(probe_config))); | |
| } else { | |
| // Convert the ProbeReuslt from enum into array of string. | |
| std::vector<std::string> categories_to_probe; | |
| const google::protobuf::EnumDescriptor* descriptor = | |
| ProbeRequest_SupportCategory_descriptor(); | |
| for (int j = 0; j < request.categories_size(); j++) | |
| categories_to_probe.push_back( | |
| descriptor->FindValueByNumber(request.categories(j))->name()); | |
| probe_config_ptr->Eval(categories_to_probe, | |
| base::BindOnce(&Daemon::ProbeCallback<ProbeResult>, | |
| base::Unretained(this), std::move(cb), | |
| std::move(probe_config))); | |
| } | |
| } | |
| void Daemon::GetKnownComponents( | |
| Daemon::DBusCallback<GetKnownComponentsResult> cb, | |
| const GetKnownComponentsRequest& request) { | |
| GetKnownComponentsResult reply; | |
| AvlProbeConfigLoader config_loader; | |
| const auto probe_config = config_loader.Load(); | |
| if (!probe_config) { | |
| reply.set_error(RUNTIME_PROBE_ERROR_PROBE_CONFIG_INVALID); | |
| cb->Return(reply); | |
| return Quit(); | |
| } | |
| std::string category_name = | |
| ProbeRequest_SupportCategory_Name(request.category()); | |
| if (auto category = probe_config->GetComponentCategory(category_name); | |
| category != nullptr) { | |
| for (const auto& name : category->GetComponentNames()) { | |
| reply.add_component_names(name); | |
| } | |
| } | |
| cb->Return(reply); | |
| return Quit(); | |
| } | |
| void Daemon::ProbeSsfcComponents( | |
| Daemon::DBusCallback<ProbeSsfcComponentsResponse> cb, | |
| const ProbeSsfcComponentsRequest& request) { | |
| SsfcProbeConfigLoader config_loader; | |
| auto probe_config = config_loader.Load(); | |
| if (!probe_config) { | |
| ProbeSsfcComponentsResponse reply; | |
| reply.set_error(RUNTIME_PROBE_ERROR_PROBE_CONFIG_INVALID); | |
| cb->Return(reply); | |
| return Quit(); | |
| } | |
| auto* probe_config_ptr = probe_config.get(); | |
| probe_config_ptr->Eval(base::BindOnce( | |
| &Daemon::ProbeCallback<ProbeSsfcComponentsResponse>, | |
| base::Unretained(this), std::move(cb), std::move(probe_config))); | |
| } | |
| template <typename MessageType> | |
| void Daemon::ProbeCallback(Daemon::DBusCallback<MessageType> cb, | |
| std::unique_ptr<ProbeConfig> probe_config, | |
| base::Value::Dict probe_result) { | |
| std::string output_json; | |
| base::JSONWriter::Write(probe_result, &output_json); | |
| DVLOG(3) << "Raw JSON probe result\n" << output_json; | |
| // Convert JSON to Protocol Buffer. | |
| MessageType reply; | |
| auto options = google::protobuf::util::JsonParseOptions(); | |
| options.ignore_unknown_fields = true; | |
| const auto json_parse_status = | |
| google::protobuf::util::JsonStringToMessage(output_json, &reply, options); | |
| VLOG(3) << "serialize JSON to Protobuf status: " << json_parse_status; | |
| if (!json_parse_status.ok()) { | |
| reply.set_error(RUNTIME_PROBE_ERROR_PROBE_RESULT_INVALID); | |
| } | |
| cb->Return(reply); | |
| return Quit(); | |
| } | |
| } // namespace runtime_probe |