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