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