1 /*
2 * Copyright (c) 2023-2024 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 "napi_hiappevent_processor.h"
16
17 #include <cinttypes>
18 #include <map>
19 #include <string>
20 #include <unordered_set>
21
22 #include "app_event_observer_mgr.h"
23 #include "hiappevent_base.h"
24 #include "hiappevent_verify.h"
25 #include "hilog/log.h"
26 #include "napi_error.h"
27 #include "napi_util.h"
28
29 #undef LOG_DOMAIN
30 #define LOG_DOMAIN 0xD002D07
31
32 #undef LOG_TAG
33 #define LOG_TAG "NapiProcessor"
34
35 namespace OHOS {
36 namespace HiviewDFX {
37 namespace NapiHiAppEventProcessor {
38 namespace {
39 constexpr int ERR_CODE_SUCC = 0;
40 constexpr int ERR_CODE_PARAM_FORMAT = -1;
41 constexpr int ERR_CODE_PARAM_INVALID = -2;
42
43 const std::string PROCESSOR_NAME = "name";
44 const std::string DEBUG_MODE = "debugMode";
45 const std::string ROUTE_INFO = "routeInfo";
46 const std::string APP_ID = "appId";
47 const std::string START_REPORT = "onStartReport";
48 const std::string BACKGROUND_REPORT = "onBackgroundReport";
49 const std::string PERIOD_REPORT = "periodReport";
50 const std::string BATCH_REPORT = "batchReport";
51 const std::string USER_IDS = "userIds";
52 const std::string USER_PROPERTIES = "userProperties";
53 const std::string EVENT_CONFIGS = "eventConfigs";
54 const std::string EVENT_CONFIG_DOMAIN = "domain";
55 const std::string EVENT_CONFIG_NAME = "name";
56 const std::string EVENT_CONFIG_REALTIME = "isRealTime";
57 const std::string CONFIG_ID = "configId";
58 const std::string CUSTOM_CONFIG = "customConfigs";
59
60 const std::string CONFIG_PROP_TYPE_STR = "string";
61 const std::string CONFIG_PROP_TYPE_STR_ARRAY = "string array";
62 const std::string CONFIG_PROP_TYPE_BOOL = "boolean";
63 const std::string CONFIG_PROP_TYPE_NUM = "number";
64 const std::string CONFIG_PROP_TYPE_EVENT_CONFIG = "AppEventReportConfig array";
65 const std::string CONFIG_PROP_TYPE_RECORD_STRING = "Record string";
66 }
67
GenConfigStrProp(const napi_env env,const napi_value config,const std::string & key,std::string & out,const bool optional=true)68 bool GenConfigStrProp(const napi_env env, const napi_value config, const std::string& key, std::string& out,
69 const bool optional = true)
70 {
71 if (!NapiUtil::HasProperty(env, config, key)) {
72 return optional;
73 }
74 napi_value value = NapiUtil::GetProperty(env, config, key);
75 if (value == nullptr || !NapiUtil::IsString(env, value)) {
76 return false;
77 }
78 out = NapiUtil::GetString(env, value);
79 return true;
80 }
81
GenConfigStrsProp(const napi_env env,const napi_value config,const std::string & key,std::unordered_set<std::string> & out)82 bool GenConfigStrsProp(const napi_env env, const napi_value config, const std::string& key,
83 std::unordered_set<std::string>& out)
84 {
85 if (NapiUtil::HasProperty(env, config, key)) {
86 napi_value value = NapiUtil::GetProperty(env, config, key);
87 if (value == nullptr || !NapiUtil::IsArray(env, value) || !NapiUtil::IsArrayType(env, value, napi_string)) {
88 return false;
89 }
90 NapiUtil::GetStringsToSet(env, value, out);
91 }
92 return true;
93 }
94
GenConfigBoolProp(const napi_env env,const napi_value config,const std::string & key,bool & out)95 bool GenConfigBoolProp(const napi_env env, const napi_value config, const std::string& key, bool& out)
96 {
97 if (NapiUtil::HasProperty(env, config, key)) {
98 napi_value value = NapiUtil::GetProperty(env, config, key);
99 if (value == nullptr || !NapiUtil::IsBoolean(env, value)) {
100 return false;
101 }
102 out = NapiUtil::GetBoolean(env, value);
103 }
104 return true;
105 }
106
GenConfigIntProp(const napi_env env,const napi_value config,const std::string & key,int32_t & out)107 bool GenConfigIntProp(const napi_env env, const napi_value config, const std::string& key, int32_t& out)
108 {
109 if (NapiUtil::HasProperty(env, config, key)) {
110 napi_value value = NapiUtil::GetProperty(env, config, key);
111 if (value == nullptr || !NapiUtil::IsNumber(env, value)) {
112 return false;
113 }
114 out = NapiUtil::GetInt32(env, value);
115 }
116 return true;
117 }
118
GenConfigNameProp(const napi_env env,const napi_value config,const std::string & key,ReportConfig & out)119 int GenConfigNameProp(const napi_env env, const napi_value config, const std::string& key, ReportConfig& out)
120 {
121 std::string name;
122 if (!GenConfigStrProp(env, config, key, name, false)) {
123 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg(key, CONFIG_PROP_TYPE_STR));
124 return ERR_CODE_PARAM_FORMAT;
125 }
126 if (!IsValidProcessorName(name)) {
127 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, "Invalid processor name.");
128 return ERR_CODE_PARAM_FORMAT;
129 }
130 out.name = name;
131 return ERR_CODE_SUCC;
132 }
133
GenConfigRouteInfoProp(const napi_env env,const napi_value config,const std::string & key,ReportConfig & out)134 int GenConfigRouteInfoProp(const napi_env env, const napi_value config, const std::string& key, ReportConfig& out)
135 {
136 std::string routeInfo;
137 if (!GenConfigStrProp(env, config, key, routeInfo) || !IsValidRouteInfo(routeInfo)) {
138 return ERR_CODE_PARAM_INVALID;
139 }
140 out.routeInfo = routeInfo;
141 return ERR_CODE_SUCC;
142 }
143
GenConfigAppIdProp(const napi_env env,const napi_value config,const std::string & key,ReportConfig & out)144 int GenConfigAppIdProp(const napi_env env, const napi_value config, const std::string& key, ReportConfig& out)
145 {
146 std::string appId;
147 if (!GenConfigStrProp(env, config, key, appId) || !IsValidAppId(appId)) {
148 return ERR_CODE_PARAM_INVALID;
149 }
150 out.appId = appId;
151 return ERR_CODE_SUCC;
152 }
153
GenConfigUserIdsProp(const napi_env env,const napi_value config,const std::string & key,ReportConfig & out)154 int GenConfigUserIdsProp(const napi_env env, const napi_value config, const std::string& key, ReportConfig& out)
155 {
156 std::unordered_set<std::string> userIdNames;
157 if (!GenConfigStrsProp(env, config, key, userIdNames)) {
158 return ERR_CODE_PARAM_INVALID;
159 }
160 for (auto userId : userIdNames) {
161 if (!IsValidUserIdName(userId)) {
162 return ERR_CODE_PARAM_INVALID;
163 }
164 }
165 out.userIdNames = userIdNames;
166 return ERR_CODE_SUCC;
167 }
168
GenConfigUserPropertiesProp(const napi_env env,const napi_value config,const std::string & key,ReportConfig & out)169 int GenConfigUserPropertiesProp(const napi_env env, const napi_value config, const std::string& key, ReportConfig& out)
170 {
171 std::unordered_set<std::string> userPropertyNames;
172 if (!GenConfigStrsProp(env, config, key, userPropertyNames)) {
173 return ERR_CODE_PARAM_INVALID;
174 }
175 for (auto userProperty : userPropertyNames) {
176 if (!IsValidUserPropName(userProperty)) {
177 return ERR_CODE_PARAM_INVALID;
178 }
179 }
180 out.userPropertyNames = userPropertyNames;
181 return ERR_CODE_SUCC;
182 }
183
GenConfigDebugModeProp(const napi_env env,const napi_value config,const std::string & key,ReportConfig & out)184 int GenConfigDebugModeProp(const napi_env env, const napi_value config, const std::string& key, ReportConfig& out)
185 {
186 return GenConfigBoolProp(env, config, key, out.debugMode) ? ERR_CODE_SUCC : ERR_CODE_PARAM_INVALID;
187 }
188
GenConfigStartReportProp(const napi_env env,const napi_value config,const std::string & key,ReportConfig & out)189 int GenConfigStartReportProp(const napi_env env, const napi_value config, const std::string& key, ReportConfig& out)
190 {
191 return GenConfigBoolProp(env, config, key, out.triggerCond.onStartup) ? ERR_CODE_SUCC : ERR_CODE_PARAM_INVALID;
192 }
193
GenConfigBackgroundReportProp(const napi_env env,const napi_value config,const std::string & key,ReportConfig & out)194 int GenConfigBackgroundReportProp(const napi_env env, const napi_value config, const std::string& key,
195 ReportConfig& out)
196 {
197 return GenConfigBoolProp(env, config, key, out.triggerCond.onBackground) ? ERR_CODE_SUCC : ERR_CODE_PARAM_INVALID;
198 }
199
GenConfigPeriodReportProp(const napi_env env,const napi_value config,const std::string & key,ReportConfig & out)200 int GenConfigPeriodReportProp(const napi_env env, const napi_value config, const std::string& key, ReportConfig& out)
201 {
202 int timeout = 0;
203 if (!GenConfigIntProp(env, config, key, timeout) || !IsValidPeriodReport(timeout)) {
204 return ERR_CODE_PARAM_INVALID;
205 }
206 out.triggerCond.timeout = timeout;
207 return ERR_CODE_SUCC;
208 }
209
GenConfigBatchReportProp(const napi_env env,const napi_value config,const std::string & key,ReportConfig & out)210 int GenConfigBatchReportProp(const napi_env env, const napi_value config, const std::string& key, ReportConfig& out)
211 {
212 int row = 0;
213 if (!GenConfigIntProp(env, config, key, row) || !IsValidBatchReport(row)) {
214 return ERR_CODE_PARAM_INVALID;
215 }
216 out.triggerCond.row = row;
217 return ERR_CODE_SUCC;
218 }
219
GenConfigReportProp(const napi_env env,const napi_value config,HiAppEvent::EventConfig & out)220 int GenConfigReportProp(const napi_env env, const napi_value config, HiAppEvent::EventConfig& out)
221 {
222 HiAppEvent::EventConfig reportConf;
223 if (!GenConfigStrProp(env, config, EVENT_CONFIG_DOMAIN, reportConf.domain)) {
224 HILOG_WARN(LOG_CORE, "Parameter error. The event domain parameter is invalid.");
225 return ERR_CODE_PARAM_INVALID;
226 }
227 if (!GenConfigStrProp(env, config, EVENT_CONFIG_NAME, reportConf.name)) {
228 HILOG_WARN(LOG_CORE, "Parameter error. The event name parameter is invalid.");
229 return ERR_CODE_PARAM_INVALID;
230 }
231 if (!GenConfigBoolProp(env, config, EVENT_CONFIG_REALTIME, reportConf.isRealTime)) {
232 HILOG_WARN(LOG_CORE, "Parameter error. The event isRealTime parameter is invalid.");
233 return ERR_CODE_PARAM_INVALID;
234 }
235 if (!IsValidEventConfig(reportConf)) {
236 HILOG_WARN(LOG_CORE, "Parameter error. The event config is invalid, domain=%{public}s, name=%{public}s.",
237 reportConf.domain.c_str(), reportConf.name.c_str());
238 return ERR_CODE_PARAM_INVALID;
239 }
240 out = reportConf;
241 return ERR_CODE_SUCC;
242 }
243
GenConfigEventConfigsProp(const napi_env env,const napi_value config,const std::string & key,ReportConfig & out)244 int GenConfigEventConfigsProp(const napi_env env, const napi_value config, const std::string& key, ReportConfig& out)
245 {
246 if (NapiUtil::HasProperty(env, config, key)) {
247 napi_value napiArr = NapiUtil::GetProperty(env, config, key);
248 if (!NapiUtil::IsArray(env, napiArr)) {
249 return ERR_CODE_PARAM_INVALID;
250 }
251 std::vector<HiAppEvent::EventConfig> eventConfigs;
252 uint32_t length = NapiUtil::GetArrayLength(env, napiArr);
253 for (uint32_t i = 0; i < length; i++) {
254 napi_value element = NapiUtil::GetElement(env, napiArr, i);
255 HiAppEvent::EventConfig reportConf;
256 int ret = GenConfigReportProp(env, element, reportConf);
257 if (ret != ERR_CODE_SUCC) {
258 return ret;
259 }
260 eventConfigs.push_back(reportConf);
261 }
262 out.eventConfigs = eventConfigs;
263 }
264 return ERR_CODE_SUCC;
265 }
266
GenConfigIdProp(const napi_env env,const napi_value config,const std::string & key,ReportConfig & out)267 int GenConfigIdProp(const napi_env env, const napi_value config, const std::string& key, ReportConfig& out)
268 {
269 if (!GenConfigIntProp(env, config, key, out.configId) || !IsValidConfigId(out.configId)) {
270 HILOG_WARN(LOG_CORE, "invalid configId");
271 return ERR_CODE_PARAM_INVALID;
272 }
273 return ERR_CODE_SUCC;
274 }
275
GenConfigCustomConfigsProp(const napi_env env,const napi_value config,const std::string & key,ReportConfig & out)276 int GenConfigCustomConfigsProp(const napi_env env, const napi_value config, const std::string& key, ReportConfig& out)
277 {
278 if (!NapiUtil::HasProperty(env, config, key)) {
279 return ERR_CODE_SUCC;
280 }
281 napi_value napiObject = NapiUtil::GetProperty(env, config, key);
282 if (napiObject == nullptr || !NapiUtil::IsObject(env, napiObject)) {
283 HILOG_WARN(LOG_CORE, "invalid customConfigs");
284 return ERR_CODE_PARAM_INVALID;
285 }
286 std::vector<std::string> keys;
287 NapiUtil::GetPropertyNames(env, napiObject, keys);
288 if (!IsValidCustomConfigsNum(keys.size())) {
289 HILOG_WARN(LOG_CORE, "invalid keys size=%{public}zu", keys.size());
290 return ERR_CODE_PARAM_INVALID;
291 }
292 std::unordered_map<std::string, std::string> customConfigs;
293 for (const auto& localKey : keys) {
294 std::string value;
295 if (!GenConfigStrProp(env, napiObject, localKey, value) || !IsValidCustomConfig(localKey, value)) {
296 HILOG_WARN(LOG_CORE, "invalid key");
297 return ERR_CODE_PARAM_INVALID;
298 }
299 customConfigs.insert(std::pair<std::string, std::string>(localKey, value));
300 }
301 out.customConfigs = customConfigs;
302 return ERR_CODE_SUCC;
303 }
304
305 typedef struct ConfigProp {
306 std::string type;
307 std::string key;
308 int (*func)(const napi_env, const napi_value, const std::string&, ReportConfig&);
309 } ConfigProp;
310
311 const ConfigProp CONFIG_PROPS[] = {
312 {
313 .type = CONFIG_PROP_TYPE_STR,
314 .key = PROCESSOR_NAME,
315 .func = GenConfigNameProp
316 },
317 {
318 .type = CONFIG_PROP_TYPE_STR,
319 .key = ROUTE_INFO,
320 .func = GenConfigRouteInfoProp
321 },
322 {
323 .type = CONFIG_PROP_TYPE_STR,
324 .key = APP_ID,
325 .func = GenConfigAppIdProp
326 },
327 {
328 .type = CONFIG_PROP_TYPE_STR_ARRAY,
329 .key = USER_IDS,
330 .func = GenConfigUserIdsProp
331 },
332 {
333 .type = CONFIG_PROP_TYPE_STR_ARRAY,
334 .key = USER_PROPERTIES,
335 .func = GenConfigUserPropertiesProp
336 },
337 {
338 .type = CONFIG_PROP_TYPE_BOOL,
339 .key = DEBUG_MODE,
340 .func = GenConfigDebugModeProp
341 },
342 {
343 .type = CONFIG_PROP_TYPE_BOOL,
344 .key = START_REPORT,
345 .func = GenConfigStartReportProp
346 },
347 {
348 .type = CONFIG_PROP_TYPE_BOOL,
349 .key = BACKGROUND_REPORT,
350 .func = GenConfigBackgroundReportProp
351 },
352 {
353 .type = CONFIG_PROP_TYPE_NUM,
354 .key = PERIOD_REPORT,
355 .func = GenConfigPeriodReportProp
356 },
357 {
358 .type = CONFIG_PROP_TYPE_NUM,
359 .key = BATCH_REPORT,
360 .func = GenConfigBatchReportProp
361 },
362 {
363 .type = CONFIG_PROP_TYPE_EVENT_CONFIG,
364 .key = EVENT_CONFIGS,
365 .func = GenConfigEventConfigsProp
366 },
367 {
368 .type = CONFIG_PROP_TYPE_NUM,
369 .key = CONFIG_ID,
370 .func = GenConfigIdProp
371 },
372 {
373 .type = CONFIG_PROP_TYPE_RECORD_STRING,
374 .key = CUSTOM_CONFIG,
375 .func = GenConfigCustomConfigsProp
376 }
377 };
378
TransConfig(const napi_env env,const napi_value config,ReportConfig & out)379 int TransConfig(const napi_env env, const napi_value config, ReportConfig& out)
380 {
381 if (!NapiUtil::IsObject(env, config)) {
382 HILOG_ERROR(LOG_CORE, "failed to add processor, params format error");
383 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("config", "Processor"));
384 return -1;
385 }
386 for (auto prop : CONFIG_PROPS) {
387 int ret = (prop.func)(env, config, prop.key, out);
388 if (ret == ERR_CODE_PARAM_FORMAT) {
389 HILOG_ERROR(LOG_CORE, "failed to add processor, params format error");
390 return -1;
391 } else if (ret == ERR_CODE_PARAM_INVALID) {
392 HILOG_WARN(LOG_CORE, "Parameter error. The %{public}s parameter is invalid.", prop.key.c_str());
393 }
394 }
395 return 0;
396 }
397
AddProcessor(const napi_env env,const napi_value config,napi_value & out)398 bool AddProcessor(const napi_env env, const napi_value config, napi_value& out)
399 {
400 ReportConfig conf;
401 int ret = TransConfig(env, config, conf);
402 if (ret != 0) {
403 out = NapiUtil::CreateInt64(env, -1);
404 return false;
405 }
406 std::string name = conf.name;
407 if (name.empty()) {
408 HILOG_ERROR(LOG_CORE, "processor name can not be empty.");
409 out = NapiUtil::CreateInt64(env, -1);
410 return false;
411 }
412 if (AppEventObserverMgr::GetInstance().Load(name) != 0) {
413 HILOG_WARN(LOG_CORE, "failed to add processor=%{public}s, name no found", name.c_str());
414 out = NapiUtil::CreateInt64(env, -1);
415 return true;
416 }
417 int64_t processorId = AppEventObserverMgr::GetInstance().RegisterObserver(name, conf);
418 if (processorId <= 0) {
419 HILOG_WARN(LOG_CORE, "failed to add processor=%{public}s, register processor error", name.c_str());
420 out = NapiUtil::CreateInt64(env, -1);
421 return false;
422 }
423 out = NapiUtil::CreateInt64(env, processorId);
424 return true;
425 }
426
RemoveProcessor(const napi_env env,const napi_value id)427 bool RemoveProcessor(const napi_env env, const napi_value id)
428 {
429 if (!NapiUtil::IsNumber(env, id)) {
430 HILOG_WARN(LOG_CORE, "failed to remove processor, params format error");
431 NapiUtil::ThrowError(env, NapiError::ERR_PARAM, NapiUtil::CreateErrMsg("id", "number"));
432 return false;
433 }
434 int64_t processorId = NapiUtil::GetInt64(env, id);
435 if (processorId <= 0) {
436 HILOG_ERROR(LOG_CORE, "failed to remove processor id=%{public}" PRId64, processorId);
437 return true;
438 }
439 if (AppEventObserverMgr::GetInstance().UnregisterObserver(processorId) != 0) {
440 HILOG_WARN(LOG_CORE, "failed to remove processor id=%{public}" PRId64, processorId);
441 return false;
442 }
443 return true;
444 }
445 } // namespace NapiHiAppEventProcessor
446 } // namespace HiviewDFX
447 } // namespace OHOS
448