1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "processor_config_loader.h"
16
17 #include <fstream>
18 #include <map>
19 #include <unordered_set>
20
21 #include "hiappevent_verify.h"
22 #include "hilog/log.h"
23 #include "json/json.h"
24
25 #undef LOG_DOMAIN
26 #define LOG_DOMAIN 0xD002D07
27
28 #undef LOG_TAG
29 #define LOG_TAG "ProcessorConfigLoader"
30
31 namespace OHOS {
32 namespace HiviewDFX {
33 namespace HiAppEvent {
34 namespace {
35 constexpr int ERR_CODE_SUCC = 0;
36 constexpr int ERR_CODE_PARAM_INVALID = -2;
37
38 const char* const DEBUG_MODE = "debugMode";
39 const char* const ROUTE_INFO = "routeInfo";
40 const char* const APP_ID = "appId";
41 const char* const START_REPORT = "onStartReport";
42 const char* const BACKGROUND_REPORT = "onBackgroundReport";
43 const char* const PERIOD_REPORT = "periodReport";
44 const char* const BATCH_REPORT = "batchReport";
45 const char* const USER_IDS = "userIds";
46 const char* const USER_PROPERTIES = "userProperties";
47 const char* const EVENT_CONFIGS = "eventConfigs";
48 const char* const EVENT_CONFIG_DOMAIN = "domain";
49 const char* const EVENT_CONFIG_NAME = "name";
50 const char* const EVENT_CONFIG_REALTIME = "isRealTime";
51 const char* const CONFIG_ID = "configId";
52 const char* const CUSTOM_CONFIG = "customConfigs";
53
54 const char* const PROCESSOR_CONFIG_PATH = "/system/etc/hiappevent/processor.json";
55
56 struct ConfigProp {
57 const char* const key;
58 std::function<int()> func;
59 };
60 }
61
62 class ProcessorConfigLoader::Impl {
63 public:
64 bool LoadProcessorConfig(const std::string& processorName, const std::string& configName);
65 const ReportConfig& GetReportConfig() const;
66
67 private:
68 int ParseRouteInfoProp();
69 int ParseAppIdProp();
70 int ParseUserIdsProp();
71 int ParseUserPropertiesProp();
72 int ParseDebugModeProp();
73 int ParseStartReportProp();
74 int ParseBackgroundReportProp();
75 int ParsePeriodReportProp();
76 int ParseBatchReportProp();
77 int ParseEventConfigsProp();
78 int ParseConfigIdProp();
79 int ParseCustomConfigsProp();
80
81 bool ParseProcessorConfig();
82 int ParseStringProp(const std::string& key, std::string& out,
83 const std::function<bool(std::string)>& validationFunc);
84 int ParseBoolProp(const std::string& key, bool& out);
85 int ParseIntProp(const std::string& key, int& out, const std::function<bool(int)>& validationFunc);
86 int ParseUnorderedSetProp(const std::string& key, std::unordered_set<std::string>& out,
87 const std::function<bool(std::string)>& validationFunc);
88 int ParseConfigReportProp(const Json::Value& eventConfig, HiAppEvent::EventConfig& reportConf);
89
90 private:
91 ReportConfig conf_;
92 Json::Value jsonConfig_;
93 };
94
ProcessorConfigLoader()95 ProcessorConfigLoader::ProcessorConfigLoader()
96 : impl_(std::make_unique<Impl>())
97 {}
98
99 ProcessorConfigLoader::~ProcessorConfigLoader() = default;
100
GetReportConfig() const101 const ReportConfig& ProcessorConfigLoader::GetReportConfig() const
102 {
103 return impl_->GetReportConfig();
104 }
105
LoadProcessorConfig(const std::string & processorName,const std::string & configName)106 bool ProcessorConfigLoader::LoadProcessorConfig(const std::string& processorName, const std::string& configName)
107 {
108 return impl_->LoadProcessorConfig(processorName, configName);
109 }
110
ParseStringProp(const std::string & key,std::string & out,const std::function<bool (std::string)> & validationFunc)111 int ProcessorConfigLoader::Impl::ParseStringProp(const std::string& key, std::string& out,
112 const std::function<bool(std::string)>& validationFunc)
113 {
114 if (!jsonConfig_.isMember(key)) {
115 out = "";
116 return ERR_CODE_SUCC;
117 }
118 if (!jsonConfig_[key].isString() || !validationFunc(jsonConfig_[key].asString())) {
119 return ERR_CODE_PARAM_INVALID;
120 }
121 out = jsonConfig_[key].asString();
122 return ERR_CODE_SUCC;
123 }
124
ParseBoolProp(const std::string & key,bool & out)125 int ProcessorConfigLoader::Impl::ParseBoolProp(const std::string& key, bool& out)
126 {
127 if (!jsonConfig_.isMember(key)) {
128 out = false;
129 return ERR_CODE_SUCC;
130 }
131 if (!jsonConfig_[key].isBool()) {
132 return ERR_CODE_PARAM_INVALID;
133 }
134 out = jsonConfig_[key].asBool();
135 return ERR_CODE_SUCC;
136 }
137
ParseIntProp(const std::string & key,int & out,const std::function<bool (int)> & validationFunc)138 int ProcessorConfigLoader::Impl::ParseIntProp(const std::string& key, int& out,
139 const std::function<bool(int)>& validationFunc)
140 {
141 if (!jsonConfig_.isMember(key)) {
142 out = 0;
143 return ERR_CODE_SUCC;
144 }
145 if (!jsonConfig_[key].isIntegral() || !validationFunc(jsonConfig_[key].asInt())) {
146 return ERR_CODE_PARAM_INVALID;
147 }
148 out = jsonConfig_[key].asInt();
149 return ERR_CODE_SUCC;
150 }
151
ParseUnorderedSetProp(const std::string & key,std::unordered_set<std::string> & out,const std::function<bool (std::string)> & validationFunc)152 int ProcessorConfigLoader::Impl::ParseUnorderedSetProp(const std::string& key, std::unordered_set<std::string>& out,
153 const std::function<bool(std::string)>& validationFunc)
154 {
155 std::unordered_set<std::string> curSet;
156 if (!jsonConfig_.isMember(key)) {
157 out = std::move(curSet);
158 return ERR_CODE_SUCC;
159 }
160 if (!jsonConfig_[key].isArray()) {
161 return ERR_CODE_PARAM_INVALID;
162 }
163 for (const auto& userId : jsonConfig_[key]) {
164 if (!userId.isString() || !validationFunc(userId.asString())) {
165 return ERR_CODE_PARAM_INVALID;
166 }
167 curSet.insert(userId.asString());
168 }
169 out = std::move(curSet);
170 return ERR_CODE_SUCC;
171 }
172
ParseConfigReportProp(const Json::Value & eventConfig,HiAppEvent::EventConfig & reportConf)173 int ProcessorConfigLoader::Impl::ParseConfigReportProp(const Json::Value& eventConfig,
174 HiAppEvent::EventConfig& reportConf)
175 {
176 if (eventConfig.isMember(EVENT_CONFIG_DOMAIN)) {
177 if (!eventConfig[EVENT_CONFIG_DOMAIN].isString()) {
178 HILOG_WARN(LOG_CORE, "Parameter error. The event domain parameter is invalid.");
179 return ERR_CODE_PARAM_INVALID;
180 }
181 reportConf.domain = eventConfig[EVENT_CONFIG_DOMAIN].asString();
182 }
183 if (eventConfig.isMember(EVENT_CONFIG_NAME)) {
184 if (!eventConfig[EVENT_CONFIG_NAME].isString()) {
185 HILOG_WARN(LOG_CORE, "Parameter error. The event name parameter is invalid.");
186 return ERR_CODE_PARAM_INVALID;
187 }
188 reportConf.name = eventConfig[EVENT_CONFIG_NAME].asString();
189 }
190 if (eventConfig.isMember(EVENT_CONFIG_REALTIME)) {
191 if (!eventConfig[EVENT_CONFIG_REALTIME].isBool()) {
192 HILOG_WARN(LOG_CORE, "Parameter error. The event isRealTime parameter is invalid.");
193 return ERR_CODE_PARAM_INVALID;
194 }
195 reportConf.isRealTime = eventConfig[EVENT_CONFIG_REALTIME].asBool();
196 }
197 if (!IsValidEventConfig(reportConf)) {
198 HILOG_WARN(LOG_CORE, "Parameter error. The event config is invalid, domain=%{public}s, name=%{public}s.",
199 reportConf.domain.c_str(), reportConf.name.c_str());
200 return ERR_CODE_PARAM_INVALID;
201 }
202 return ERR_CODE_SUCC;
203 }
204
ParseRouteInfoProp()205 int ProcessorConfigLoader::Impl::ParseRouteInfoProp()
206 {
207 return ParseStringProp(ROUTE_INFO, conf_.routeInfo, IsValidRouteInfo);
208 }
209
ParseAppIdProp()210 int ProcessorConfigLoader::Impl::ParseAppIdProp()
211 {
212 return ParseStringProp(APP_ID, conf_.appId, IsValidAppId);
213 }
214
ParseUserIdsProp()215 int ProcessorConfigLoader::Impl::ParseUserIdsProp()
216 {
217 return ParseUnorderedSetProp(USER_IDS, conf_.userIdNames, IsValidUserIdName);
218 }
219
ParseUserPropertiesProp()220 int ProcessorConfigLoader::Impl::ParseUserPropertiesProp()
221 {
222 return ParseUnorderedSetProp(USER_PROPERTIES, conf_.userPropertyNames, IsValidUserPropName);
223 }
224
ParseDebugModeProp()225 int ProcessorConfigLoader::Impl::ParseDebugModeProp()
226 {
227 return ParseBoolProp(DEBUG_MODE, conf_.debugMode);
228 }
229
ParseStartReportProp()230 int ProcessorConfigLoader::Impl::ParseStartReportProp()
231 {
232 return ParseBoolProp(START_REPORT, conf_.triggerCond.onStartup);
233 }
234
ParseBackgroundReportProp()235 int ProcessorConfigLoader::Impl::ParseBackgroundReportProp()
236 {
237 return ParseBoolProp(BACKGROUND_REPORT, conf_.triggerCond.onBackground);
238 }
239
ParsePeriodReportProp()240 int ProcessorConfigLoader::Impl::ParsePeriodReportProp()
241 {
242 return ParseIntProp(PERIOD_REPORT, conf_.triggerCond.timeout, IsValidPeriodReport);
243 }
244
ParseBatchReportProp()245 int ProcessorConfigLoader::Impl::ParseBatchReportProp()
246 {
247 return ParseIntProp(BATCH_REPORT, conf_.triggerCond.row, IsValidBatchReport);
248 }
249
ParseConfigIdProp()250 int ProcessorConfigLoader::Impl::ParseConfigIdProp()
251 {
252 return ParseIntProp(CONFIG_ID, conf_.configId, IsValidConfigId);
253 }
254
ParseEventConfigsProp()255 int ProcessorConfigLoader::Impl::ParseEventConfigsProp()
256 {
257 std::vector<HiAppEvent::EventConfig> eventConfigs;
258 if (!jsonConfig_.isMember(EVENT_CONFIGS)) {
259 conf_.eventConfigs = std::move(eventConfigs);
260 return ERR_CODE_SUCC;
261 }
262 if (!jsonConfig_[EVENT_CONFIGS].isArray()) {
263 return ERR_CODE_PARAM_INVALID;
264 }
265 for (const auto& eventConfig : jsonConfig_[EVENT_CONFIGS]) {
266 if (!eventConfig.isObject()) {
267 return ERR_CODE_PARAM_INVALID;
268 }
269 HiAppEvent::EventConfig reportConf;
270 if (ParseConfigReportProp(eventConfig, reportConf) != ERR_CODE_SUCC) {
271 return ERR_CODE_PARAM_INVALID;
272 }
273 eventConfigs.push_back(reportConf);
274 }
275 conf_.eventConfigs = std::move(eventConfigs);
276 return ERR_CODE_SUCC;
277 }
278
ParseCustomConfigsProp()279 int ProcessorConfigLoader::Impl::ParseCustomConfigsProp()
280 {
281 std::unordered_map<std::string, std::string> customConfigs;
282 if (!jsonConfig_.isMember(CUSTOM_CONFIG)) {
283 conf_.customConfigs = std::move(customConfigs);
284 return ERR_CODE_SUCC;
285 }
286 if (!jsonConfig_[CUSTOM_CONFIG].isObject()) {
287 return ERR_CODE_PARAM_INVALID;
288 }
289 const Json::Value::Members& members = jsonConfig_[CUSTOM_CONFIG].getMemberNames();
290 for (const auto& name : members) {
291 if (!jsonConfig_[CUSTOM_CONFIG][name].isString() ||
292 !IsValidCustomConfig(name, jsonConfig_[CUSTOM_CONFIG][name].asString())) {
293 return ERR_CODE_PARAM_INVALID;
294 }
295 customConfigs.insert(std::pair<std::string, std::string>(name, jsonConfig_[CUSTOM_CONFIG][name].asString()));
296 }
297 conf_.customConfigs = std::move(customConfigs);
298 return ERR_CODE_SUCC;
299 }
300
ParseProcessorConfig()301 bool ProcessorConfigLoader::Impl::ParseProcessorConfig()
302 {
303 const ConfigProp CONFIG_PROPS[] = {
304 { .key = ROUTE_INFO, .func = [this]() -> int { return this->ParseRouteInfoProp(); } },
305 { .key = APP_ID, .func = [this]() -> int { return this->ParseAppIdProp(); } },
306 { .key = USER_IDS, .func = [this]() -> int { return this->ParseUserIdsProp(); } },
307 { .key = USER_PROPERTIES, .func = [this]() -> int { return this->ParseUserPropertiesProp(); } },
308 { .key = DEBUG_MODE, .func = [this]() -> int { return this->ParseDebugModeProp(); } },
309 { .key = START_REPORT, .func = [this]() -> int { return this->ParseStartReportProp(); } },
310 { .key = BACKGROUND_REPORT, .func = [this]() -> int { return this->ParseBackgroundReportProp(); } },
311 { .key = PERIOD_REPORT, .func = [this]() -> int { return this->ParsePeriodReportProp(); } },
312 { .key = BATCH_REPORT, .func = [this]() -> int { return this->ParseBatchReportProp(); } },
313 { .key = EVENT_CONFIGS, .func = [this]() -> int { return this->ParseEventConfigsProp(); } },
314 { .key = CONFIG_ID, .func = [this]() -> int { return this->ParseConfigIdProp(); } },
315 { .key = CUSTOM_CONFIG, .func = [this]() -> int { return this->ParseCustomConfigsProp(); } }
316 };
317
318 for (const auto& prop : CONFIG_PROPS) {
319 if (prop.func() != ERR_CODE_SUCC) {
320 HILOG_ERROR(LOG_CORE, "failed to load processor config item:%{public}s", prop.key);
321 return false;
322 }
323 }
324 return true;
325 }
326
LoadProcessorConfig(const std::string & processorName,const std::string & configName)327 bool ProcessorConfigLoader::Impl::LoadProcessorConfig(const std::string& processorName, const std::string& configName)
328 {
329 std::ifstream file(PROCESSOR_CONFIG_PATH);
330 if (!file.is_open()) {
331 HILOG_ERROR(LOG_CORE, "failed to open the processor config file, path:%{public}s.", PROCESSOR_CONFIG_PATH);
332 return false;
333 }
334
335 Json::Value jsonConfig;
336 Json::CharReaderBuilder builder;
337 Json::CharReaderBuilder::strictMode(&builder.settings_);
338 JSONCPP_STRING errs;
339 if (!parseFromStream(builder, file, &jsonConfig, &errs)) {
340 HILOG_ERROR(LOG_CORE, "failed to parse the processor config file, path:%{public}s.", PROCESSOR_CONFIG_PATH);
341 return false;
342 }
343 if (jsonConfig.empty() || !jsonConfig.isObject()) {
344 HILOG_ERROR(LOG_CORE, "the processor config file is invalid.");
345 return false;
346 }
347 if (!jsonConfig.isMember(configName) || !jsonConfig[configName].isObject()) {
348 HILOG_ERROR(LOG_CORE, "the configName=%{public}s is invalid in config file.", configName.c_str());
349 return false;
350 }
351 conf_.name = processorName;
352 conf_.configName = configName;
353 jsonConfig_ = jsonConfig[configName];
354
355 return ParseProcessorConfig();
356 }
357
GetReportConfig() const358 const ReportConfig& ProcessorConfigLoader::Impl::GetReportConfig() const
359 {
360 return conf_;
361 }
362 } // namespace HiAppEvent
363 } // namespace HiviewDFX
364 } // namespace OHOS