| // 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 |