blob: 88ecae2e08456d0824e95a4ae28c20ad28f99424 [file] [log] [blame]
Chun-Ta Linb6b59b52018-11-08 10:13:57 +08001// Copyright 2018 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <sysexits.h>
6
Hong-Min Chu9caafda2018-11-27 16:51:52 +08007#include <memory>
8#include <string>
9#include <utility>
10#include <vector>
Chun-Ta Linb6b59b52018-11-08 10:13:57 +080011
12#include <base/bind.h>
Qijiang Fan713061e2021-03-08 15:45:12 +090013#include <base/check.h>
Chun-Ta Lin49a91df2018-12-31 02:42:48 +080014#include <base/json/json_writer.h>
Chun-Ta Linb6b59b52018-11-08 10:13:57 +080015#include <base/memory/ptr_util.h>
16#include <chromeos/dbus/service_constants.h>
17
18#include <google/protobuf/util/json_util.h>
19
20#include "runtime_probe/daemon.h"
Wei-Han Chen27670102018-12-25 19:57:03 +080021#include "runtime_probe/probe_config.h"
Kevin Linc6615ae2020-11-11 19:36:59 +080022#include "runtime_probe/probe_config_loader_impl.h"
Chun-Ta Linb6b59b52018-11-08 10:13:57 +080023
24namespace runtime_probe {
25
Kevin Linc6615ae2020-11-11 19:36:59 +080026const char kErrorMsgFailedToPackProtobuf[] = "Failed to serialize the protobuf";
Chun-Ta Linb6b59b52018-11-08 10:13:57 +080027
28namespace {
29
Chun-Ta Linb6b59b52018-11-08 10:13:57 +080030void DumpProtocolBuffer(const google::protobuf::Message& protobuf,
31 std::string message_name) {
Hong-Min Chua03de9c2019-05-21 11:46:46 +080032 VLOG(3) << "---> Protobuf dump of " << message_name;
33 VLOG(3) << " DebugString():\n\n" << protobuf.DebugString();
Chun-Ta Linb6b59b52018-11-08 10:13:57 +080034 std::string json_string;
35 google::protobuf::util::JsonPrintOptions options;
36 MessageToJsonString(protobuf, &json_string, options);
Hong-Min Chua03de9c2019-05-21 11:46:46 +080037 VLOG(3) << " JSON output:\n\n" << json_string << "\n";
38 VLOG(3) << "<--- Finished Protobuf dump\n";
Hong-Min Chu9caafda2018-11-27 16:51:52 +080039}
40
Chun-Ta Linb6b59b52018-11-08 10:13:57 +080041} // namespace
42
43Daemon::Daemon() {}
44
45Daemon::~Daemon() {}
46
Chun-Ta Linb6b59b52018-11-08 10:13:57 +080047int Daemon::OnInit() {
48 int exit_code = DBusDaemon::OnInit();
49 if (exit_code != EX_OK)
50 return exit_code;
51
52 InitDBus();
53 return 0;
54}
55
56void Daemon::InitDBus() {
57 LOG(INFO) << "Init DBus for Runtime Probe";
58 // Get or create the ExportedObject for the Runtime Probe service.
59 auto const runtime_probe_exported_object =
60 bus_->GetExportedObject(dbus::ObjectPath(kRuntimeProbeServicePath));
61 CHECK(runtime_probe_exported_object);
62
63 // Register a handler of the ProbeCategories method.
64 CHECK(runtime_probe_exported_object->ExportMethodAndBlock(
65 kRuntimeProbeInterfaceName, kProbeCategoriesMethod,
66 base::Bind(&Daemon::ProbeCategories, weak_ptr_factory_.GetWeakPtr())));
67
Kevin Lin66adcf82021-03-30 21:36:27 +080068 // Register a handler of the GetKnownComponents method.
69 CHECK(runtime_probe_exported_object->ExportMethodAndBlock(
70 kRuntimeProbeInterfaceName, kGetKnownComponentsMethod,
71 base::Bind(&Daemon::GetKnownComponents, weak_ptr_factory_.GetWeakPtr())));
72
Chun-Ta Linb6b59b52018-11-08 10:13:57 +080073 // Take ownership of the RuntimeProbe service.
74 CHECK(bus_->RequestOwnershipAndBlock(kRuntimeProbeServiceName,
75 dbus::Bus::REQUIRE_PRIMARY));
76 LOG(INFO) << kRuntimeProbeServicePath << " DBus initialized.";
77}
78
Chun-Ta Line6c61b42018-11-26 14:22:29 +080079void Daemon::PostQuitTask() {
80 bus_->GetOriginTaskRunner()->PostTask(
81 FROM_HERE,
82 base::Bind(&Daemon::QuitDaemonInternal, base::Unretained(this)));
83}
84
85void Daemon::QuitDaemonInternal() {
86 bus_->ShutdownAndBlock();
87 Quit();
88}
89
Kevin Lin66adcf82021-03-30 21:36:27 +080090void Daemon::SendMessage(const google::protobuf::Message& reply,
91 dbus::MethodCall* method_call,
92 dbus::ExportedObject::ResponseSender response_sender) {
Wei-Han Chen27670102018-12-25 19:57:03 +080093 DumpProtocolBuffer(reply, "ProbeResult");
Chun-Ta Linb6b59b52018-11-08 10:13:57 +080094
95 std::unique_ptr<dbus::Response> message(
96 dbus::Response::FromMethodCall(method_call));
97 dbus::MessageWriter writer(message.get());
98 if (!writer.AppendProtoAsArrayOfBytes(reply)) {
99 LOG(ERROR) << kErrorMsgFailedToPackProtobuf;
hscham829c1582020-09-09 10:13:36 +0900100 std::move(response_sender)
101 .Run(dbus::ErrorResponse::FromMethodCall(
102 method_call, DBUS_ERROR_INVALID_ARGS,
103 kErrorMsgFailedToPackProtobuf));
Chun-Ta Linb6b59b52018-11-08 10:13:57 +0800104 } else {
105 // TODO(itspeter): b/119939408, PII filter before return.
hscham829c1582020-09-09 10:13:36 +0900106 std::move(response_sender).Run(std::move(message));
Chun-Ta Linb6b59b52018-11-08 10:13:57 +0800107 }
Chun-Ta Line6c61b42018-11-26 14:22:29 +0800108 PostQuitTask();
Chun-Ta Linb6b59b52018-11-08 10:13:57 +0800109}
110
111void Daemon::ProbeCategories(
112 dbus::MethodCall* method_call,
113 dbus::ExportedObject::ResponseSender response_sender) {
Chun-Ta Linb6b59b52018-11-08 10:13:57 +0800114 std::unique_ptr<dbus::Response> message(
115 dbus::Response::FromMethodCall(method_call));
116 dbus::MessageReader reader(method_call);
117 dbus::MessageWriter writer(message.get());
118 ProbeRequest request;
119 ProbeResult reply;
120
121 if (!reader.PopArrayOfBytesAsProto(&request)) {
122 reply.set_error(RUNTIME_PROBE_ERROR_PROBE_REQUEST_INVALID);
Kevin Lin66adcf82021-03-30 21:36:27 +0800123 return SendMessage(reply, method_call, std::move(response_sender));
Chun-Ta Linb6b59b52018-11-08 10:13:57 +0800124 }
125
Wei-Han Chen27670102018-12-25 19:57:03 +0800126 DumpProtocolBuffer(request, "ProbeRequest");
127
Kevin Linc6615ae2020-11-11 19:36:59 +0800128 const auto probe_config_loader =
129 std::make_unique<runtime_probe::ProbeConfigLoaderImpl>();
130 const auto probe_config_data = probe_config_loader->LoadDefault();
Hong-Min Chubd3c2972019-05-29 12:53:29 +0800131 if (!probe_config_data) {
Kevin Linc6615ae2020-11-11 19:36:59 +0800132 reply.set_error(RUNTIME_PROBE_ERROR_PROBE_CONFIG_INVALID);
Kevin Lin66adcf82021-03-30 21:36:27 +0800133 return SendMessage(reply, method_call, std::move(response_sender));
Chun-Ta Lin49a91df2018-12-31 02:42:48 +0800134 }
Kevin Linc6615ae2020-11-11 19:36:59 +0800135 LOG(INFO) << "Load probe config from: " << probe_config_data->path
136 << " (checksum: " << probe_config_data->sha1_hash << ")";
Chun-Ta Linb6b59b52018-11-08 10:13:57 +0800137
Kevin Linc6615ae2020-11-11 19:36:59 +0800138 reply.set_probe_config_checksum(probe_config_data->sha1_hash);
Hong-Min Chubd3c2972019-05-29 12:53:29 +0800139
Kevin Linaf1ee812020-06-23 16:53:53 +0800140 const auto probe_config =
Kevin Linc6615ae2020-11-11 19:36:59 +0800141 runtime_probe::ProbeConfig::FromValue(probe_config_data->config);
Chun-Ta Lin49a91df2018-12-31 02:42:48 +0800142 if (!probe_config) {
143 reply.set_error(RUNTIME_PROBE_ERROR_PROBE_CONFIG_INCOMPLETE_PROBE_FUNCTION);
Kevin Lin66adcf82021-03-30 21:36:27 +0800144 return SendMessage(reply, method_call, std::move(response_sender));
Chun-Ta Lin49a91df2018-12-31 02:42:48 +0800145 }
146
Kevin Linaf1ee812020-06-23 16:53:53 +0800147 base::Value probe_result;
Hong-Min Chufc94ece2019-05-22 14:18:16 +0800148 if (request.probe_default_category()) {
149 probe_result = probe_config->Eval();
150 } else {
151 // Convert the ProbeReuslt from enum into array of string.
152 std::vector<std::string> categories_to_probe;
153 const google::protobuf::EnumDescriptor* descriptor =
154 ProbeRequest_SupportCategory_descriptor();
Chun-Ta Lin49a91df2018-12-31 02:42:48 +0800155
Hong-Min Chufc94ece2019-05-22 14:18:16 +0800156 for (int j = 0; j < request.categories_size(); j++)
157 categories_to_probe.push_back(
158 descriptor->FindValueByNumber(request.categories(j))->name());
Chun-Ta Lin49a91df2018-12-31 02:42:48 +0800159
Hong-Min Chufc94ece2019-05-22 14:18:16 +0800160 probe_result = probe_config->Eval(categories_to_probe);
161 }
162
Chun-Ta Lin49a91df2018-12-31 02:42:48 +0800163 // TODO(itspeter): Report assigned but not in the probe config's category.
164 std::string output_js;
Kevin Linaf1ee812020-06-23 16:53:53 +0800165 base::JSONWriter::Write(probe_result, &output_js);
Kevin Linc6615ae2020-11-11 19:36:59 +0800166 DVLOG(3) << "Raw JSON probe result\n" << output_js;
Chun-Ta Lin49a91df2018-12-31 02:42:48 +0800167
168 // Convert JSON to Protocol Buffer.
169 auto options = google::protobuf::util::JsonParseOptions();
170 options.ignore_unknown_fields = true;
Yong Hong200a80c2019-06-17 16:23:27 +0800171 ProbeResult placeholder;
Hong-Min Chufc94ece2019-05-22 14:18:16 +0800172 const auto json_parse_status = google::protobuf::util::JsonStringToMessage(
Yong Hong200a80c2019-06-17 16:23:27 +0800173 output_js, &placeholder, options);
174 reply.MergeFrom(placeholder);
Hong-Min Chua03de9c2019-05-21 11:46:46 +0800175 VLOG(3) << "serialize JSON to Protobuf status: " << json_parse_status;
Kevin Linc999d1e2020-10-05 20:11:01 +0800176 if (!json_parse_status.ok()) {
177 reply.set_error(RUNTIME_PROBE_ERROR_PROBE_RESULT_INVALID);
178 }
Chun-Ta Lin49a91df2018-12-31 02:42:48 +0800179
Kevin Lin66adcf82021-03-30 21:36:27 +0800180 return SendMessage(reply, method_call, std::move(response_sender));
181}
182
183void Daemon::GetKnownComponents(
184 dbus::MethodCall* method_call,
185 dbus::ExportedObject::ResponseSender response_sender) {
186 std::unique_ptr<dbus::Response> message(
187 dbus::Response::FromMethodCall(method_call));
188 dbus::MessageReader reader(method_call);
189 dbus::MessageWriter writer(message.get());
190 GetKnownComponentsRequest request;
191 GetKnownComponentsResult reply;
192
193 if (!reader.PopArrayOfBytesAsProto(&request)) {
194 reply.set_error(RUNTIME_PROBE_ERROR_PROBE_REQUEST_INVALID);
195 return SendMessage(reply, method_call, std::move(response_sender));
196 }
197
198 const auto probe_config_loader =
199 std::make_unique<runtime_probe::ProbeConfigLoaderImpl>();
200 const auto probe_config_data = probe_config_loader->LoadDefault();
201 if (!probe_config_data) {
202 reply.set_error(RUNTIME_PROBE_ERROR_PROBE_CONFIG_INVALID);
203 return SendMessage(reply, method_call, std::move(response_sender));
204 }
205
206 const auto probe_config =
207 runtime_probe::ProbeConfig::FromValue(probe_config_data->config);
208 if (!probe_config) {
209 reply.set_error(RUNTIME_PROBE_ERROR_PROBE_CONFIG_INCOMPLETE_PROBE_FUNCTION);
210 return SendMessage(reply, method_call, std::move(response_sender));
211 }
212
213 std::string category_name =
214 ProbeRequest_SupportCategory_Name(request.category());
215 if (auto category = probe_config->GetComponentCategory(category_name);
216 category != nullptr) {
217 for (const auto& name : category->GetComponentNames()) {
218 reply.add_component_names(name);
219 }
220 }
221
222 return SendMessage(reply, method_call, std::move(response_sender));
Chun-Ta Linb6b59b52018-11-08 10:13:57 +0800223}
224
225} // namespace runtime_probe