• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 
16 #include "napi_hisysevent_util.h"
17 
18 #include <cinttypes>
19 
20 #include "def.h"
21 #include "hilog/log.h"
22 #include "json/json.h"
23 #include "ret_code.h"
24 #include "ret_def.h"
25 #include "stringfilter.h"
26 
27 namespace OHOS {
28 namespace HiviewDFX {
29 namespace {
30 constexpr HiLogLabel LABEL = { LOG_CORE, 0xD002D08, "NAPI_HISYSEVENT_UTIL" };
31 constexpr uint32_t JS_STR_PARM_LEN_LIMIT = 1024 * 10; // 10k
32 constexpr uint32_t BUF_SIZE = 1024 * 11; // 11k
33 constexpr int SYS_EVENT_INFO_PARAM_INDEX = 0;
34 constexpr long long DEFAULT_TIME_STAMP = -1;
35 constexpr long long DEFAULT_SEQ = 0;
36 constexpr int32_t DEFAULT_MAX_EVENTS = 1000;
37 constexpr char PARAMS_ATTR[] = "params";
38 constexpr char TAG_ATTR[] = "tag";
39 constexpr char RULE_TYPE_ATTR[] = "ruleType";
40 constexpr char BEGIN_TIME_ATTR[] = "beginTime";
41 constexpr char END_TIME_ATTR[] = "endTime";
42 constexpr char MAX_EVENTS_ATTR[] = "maxEvents";
43 constexpr char BEGIN_SEQ_ATTR[] = "fromSeq";
44 constexpr char END_SEQ_ATTR[] = "toSeq";
45 constexpr char NAMES_ATTR[] = "names";
46 constexpr char DOMAIN__KEY[] = "domain_";
47 constexpr char NAME__KEY[] = "name_";
48 constexpr char TYPE__KEY[] = "type_";
49 const std::string INVALID_KEY_TYPE_ARR[] = {
50     "[object Object]",
51     "null",
52     "()",
53     ","
54 };
55 
CheckKeyTypeString(const std::string & str)56 bool CheckKeyTypeString(const std::string& str)
57 {
58     bool ret = true;
59     for (auto invalidType : INVALID_KEY_TYPE_ARR) {
60         if (str.find(invalidType) != std::string::npos) {
61             ret = false;
62             break;
63         }
64     }
65     return ret;
66 }
67 
GetValueType(const napi_env env,const napi_value & value)68 napi_valuetype GetValueType(const napi_env env, const napi_value& value)
69 {
70     napi_valuetype valueType = napi_undefined;
71     napi_status ret = napi_typeof(env, value, &valueType);
72     if (ret != napi_ok) {
73         HiLog::Error(LABEL, "failed to parse the type of napi value.");
74     }
75     return valueType;
76 }
77 
IsValueTypeValid(const napi_env env,const napi_value & jsObj,const napi_valuetype typeName)78 bool IsValueTypeValid(const napi_env env, const napi_value& jsObj,
79     const napi_valuetype typeName)
80 {
81     napi_valuetype valueType = GetValueType(env, jsObj);
82     if (valueType != typeName) {
83         HiLog::Error(LABEL, "napi value type not match: valueType=%{public}d, typeName=%{public}d.",
84             valueType, typeName);
85         return false;
86     }
87     return true;
88 }
89 
CheckValueIsArray(const napi_env env,const napi_value & jsObj)90 bool CheckValueIsArray(const napi_env env, const napi_value& jsObj)
91 {
92     if (!IsValueTypeValid(env, jsObj, napi_valuetype::napi_object)) {
93         return false;
94     }
95     bool isArray = false;
96     napi_status ret = napi_is_array(env, jsObj, &isArray);
97     if (ret != napi_ok) {
98         HiLog::Error(LABEL, "failed to check array napi value.");
99     }
100     return isArray;
101 }
102 
ParseBoolValue(const napi_env env,const napi_value & value,bool defalutValue=false)103 bool ParseBoolValue(const napi_env env, const napi_value& value, bool defalutValue = false)
104 {
105     bool boolValue = defalutValue;
106     napi_status ret = napi_get_value_bool(env, value, &boolValue);
107     if (ret != napi_ok) {
108         HiLog::Error(LABEL, "failed to parse napi value of boolean type.");
109     }
110     return boolValue;
111 }
112 
ParseNumberValue(const napi_env env,const napi_value & value,double defaultValue=0.0)113 double ParseNumberValue(const napi_env env, const napi_value& value, double defaultValue = 0.0)
114 {
115     double numValue = defaultValue;
116     napi_status ret = napi_get_value_double(env, value, &numValue);
117     if (ret != napi_ok) {
118         HiLog::Error(LABEL, "failed to parse napi value of number type.");
119     }
120     return numValue;
121 }
122 
ParseBigIntValue(const napi_env env,const napi_value & value,uint64_t defaultValue=0)123 double ParseBigIntValue(const napi_env env, const napi_value& value, uint64_t defaultValue = 0)
124 {
125     uint64_t bigIntValue = defaultValue;
126     bool lossless = true;
127     napi_status ret = napi_get_value_bigint_uint64(env, value, &bigIntValue, &lossless);
128     if (ret != napi_ok) {
129         HiLog::Error(LABEL, "failed to parse napi value of big int type.");
130     }
131     return static_cast<double>(bigIntValue);
132 }
133 
ParseStringValue(const napi_env env,const napi_value & value,std::string defaultValue="")134 std::string ParseStringValue(const napi_env env, const napi_value& value, std::string defaultValue = "")
135 {
136     char buf[BUF_SIZE] = {0};
137     size_t bufLength = 0;
138     napi_status status = napi_get_value_string_utf8(env, value, buf, BUF_SIZE - 1, &bufLength);
139     if (status != napi_ok) {
140         HiLog::Error(LABEL, "failed to parse napi value of string type.");
141         return defaultValue;
142     }
143     std::string dest = std::string {buf};
144     return dest;
145 }
146 
GetTagAttribute(const napi_env env,const napi_value & object,std::string defaultValue="")147 std::string GetTagAttribute(const napi_env env, const napi_value& object, std::string defaultValue = "")
148 {
149     napi_value propertyValue = NapiHiSysEventUtil::GetPropertyByName(env, object, TAG_ATTR);
150     if (IsValueTypeValid(env, propertyValue, napi_valuetype::napi_null) ||
151         IsValueTypeValid(env, propertyValue, napi_valuetype::napi_undefined)) {
152         return defaultValue;
153     }
154     if (IsValueTypeValid(env, propertyValue, napi_valuetype::napi_string)) {
155         return ParseStringValue(env, propertyValue, defaultValue);
156     }
157     NapiHiSysEventUtil::ThrowParamTypeError(env, TAG_ATTR, "string");
158     HiLog::Error(LABEL, "type of listener tag is not napi_string.");
159     return defaultValue;
160 }
161 
GetStringTypeAttribute(const napi_env env,const napi_value & object,const std::string & propertyName,std::string defaultValue="")162 std::string GetStringTypeAttribute(const napi_env env, const napi_value& object,
163     const std::string& propertyName, std::string defaultValue = "")
164 {
165     napi_value propertyValue = NapiHiSysEventUtil::GetPropertyByName(env, object, propertyName);
166     if (!IsValueTypeValid(env, propertyValue, napi_valuetype::napi_string)) {
167         NapiHiSysEventUtil::ThrowParamTypeError(env, propertyName, "string");
168         HiLog::Error(LABEL, "type is not napi_string.");
169         return defaultValue;
170     }
171     return ParseStringValue(env, propertyValue, defaultValue);
172 }
173 
GetLonglongTypeAttribute(const napi_env env,const napi_value & object,const std::string & propertyName,long long defaultValue=0)174 long long GetLonglongTypeAttribute(const napi_env env, const napi_value& object,
175     const std::string& propertyName, long long defaultValue = 0)
176 {
177     napi_value propertyValue = NapiHiSysEventUtil::GetPropertyByName(env, object, propertyName);
178     bool isNumberType = IsValueTypeValid(env, propertyValue, napi_valuetype::napi_number);
179     bool isBigIntType = IsValueTypeValid(env, propertyValue, napi_valuetype::napi_bigint);
180     if (!isNumberType && !isBigIntType) {
181         HiLog::Error(LABEL, "type is not napi_number or napi_bigint.");
182         return defaultValue;
183     }
184     if (isBigIntType) {
185         return static_cast<long long>(ParseBigIntValue(env, propertyValue));
186     }
187     return static_cast<long long>(ParseNumberValue(env, propertyValue, defaultValue));
188 }
189 
ParseInt32Value(const napi_env env,const napi_value & value,int32_t defaultValue=0)190 int32_t ParseInt32Value(const napi_env env, const napi_value& value, int32_t defaultValue = 0)
191 {
192     int32_t int32Value = 0;
193     napi_status ret = napi_get_value_int32(env, value, &int32Value);
194     if (ret != napi_ok) {
195         HiLog::Error(LABEL, "failed to parse napi value of number type.");
196         return defaultValue;
197     }
198     return int32Value;
199 }
200 
GetInt32TypeAttribute(const napi_env env,const napi_value & object,const std::string & propertyName,int32_t defaultValue=0)201 int32_t GetInt32TypeAttribute(const napi_env env, const napi_value& object,
202     const std::string& propertyName, int32_t defaultValue = 0)
203 {
204     napi_value propertyValue = NapiHiSysEventUtil::GetPropertyByName(env, object, propertyName);
205     if (!IsValueTypeValid(env, propertyValue, napi_valuetype::napi_number)) {
206         NapiHiSysEventUtil::ThrowParamTypeError(env, propertyName, "number");
207         HiLog::Error(LABEL, "type is not napi_number.");
208         return defaultValue;
209     }
210     return ParseInt32Value(env, propertyValue);
211 }
212 
AppendBoolArrayData(const napi_env env,HiSysEventInfo & info,const std::string & key,const napi_value array,size_t len)213 void AppendBoolArrayData(const napi_env env, HiSysEventInfo& info, const std::string& key,
214     const napi_value array, size_t len)
215 {
216     std::vector<bool> values;
217     napi_value element;
218     napi_status status;
219     for (uint32_t i = 0; i < len; i++) {
220         status = napi_get_element(env, array, i, &element);
221         if (status != napi_ok) {
222             HiLog::Error(LABEL, "failed to get the element of bool array.");
223             continue;
224         }
225         if (IsValueTypeValid(env, element, napi_valuetype::napi_boolean)) {
226             values.emplace_back(ParseBoolValue(env, element));
227         }
228     }
229     info.boolArrayParams[key] = values;
230 }
231 
AppendNumberArrayData(const napi_env env,HiSysEventInfo & info,const std::string & key,const napi_value array,size_t len)232 void AppendNumberArrayData(const napi_env env, HiSysEventInfo& info, const std::string& key,
233     const napi_value array, size_t len)
234 {
235     std::vector<double> values;
236     napi_value element;
237     napi_status status;
238     for (uint32_t i = 0; i < len; i++) {
239         status = napi_get_element(env, array, i, &element);
240         if (status != napi_ok) {
241             HiLog::Error(LABEL, "failed to get the element of number array.");
242             continue;
243         }
244         if (IsValueTypeValid(env, element, napi_valuetype::napi_number)) {
245             values.emplace_back(ParseNumberValue(env, element));
246         }
247     }
248     info.doubleArrayParams[key] = values;
249 }
250 
AppendBigIntArrayData(const napi_env env,HiSysEventInfo & info,const std::string & key,const napi_value array,size_t len)251 void AppendBigIntArrayData(const napi_env env, HiSysEventInfo& info, const std::string& key,
252     const napi_value array, size_t len)
253 {
254     std::vector<double> values;
255     napi_value element;
256     napi_status status;
257     for (uint32_t i = 0; i < len; i++) {
258         status = napi_get_element(env, array, i, &element);
259         if (status != napi_ok) {
260             HiLog::Error(LABEL, "failed to get the element of big int array.");
261             continue;
262         }
263         if (IsValueTypeValid(env, element, napi_valuetype::napi_bigint)) {
264             values.emplace_back(ParseBigIntValue(env, element));
265         }
266     }
267     info.doubleArrayParams[key] = values;
268 }
269 
AppendStringArrayData(const napi_env env,HiSysEventInfo & info,const std::string & key,const napi_value array,size_t len)270 void AppendStringArrayData(const napi_env env, HiSysEventInfo& info, const std::string& key,
271     const napi_value array, size_t len)
272 {
273     std::vector<std::string> values;
274     napi_value element;
275     napi_status status;
276     for (uint32_t i = 0; i < len; i++) {
277         status = napi_get_element(env, array, i, &element);
278         if (status != napi_ok) {
279             HiLog::Error(LABEL, "failed to get the element of string array.");
280             continue;
281         }
282         if (IsValueTypeValid(env, element, napi_valuetype::napi_string)) {
283             values.emplace_back(ParseStringValue(env, element));
284         }
285     }
286     info.stringArrayParams[key] = values;
287 }
288 
AddArrayParamToEventInfo(const napi_env env,HiSysEventInfo & info,const std::string & key,napi_value & array)289 void AddArrayParamToEventInfo(const napi_env env, HiSysEventInfo& info, const std::string& key, napi_value& array)
290 {
291     uint32_t len = 0;
292     napi_status status = napi_get_array_length(env, array, &len);
293     if (status != napi_ok) {
294         HiLog::Error(LABEL, "failed to get the length of param array.");
295         return;
296     }
297     if (len == 0) {
298         HiLog::Warn(LABEL, "array is empty.");
299         return;
300     }
301     napi_value firstItem;
302     status = napi_get_element(env, array, 0, &firstItem);
303     if (status != napi_ok) {
304         HiLog::Error(LABEL, "failed to get the first element in array.");
305         return;
306     }
307     napi_valuetype type;
308     status = napi_typeof(env, firstItem, &type);
309     if (status != napi_ok) {
310         HiLog::Error(LABEL, "failed to get the type of the first element in array.");
311         return;
312     }
313     switch (type) {
314         case napi_valuetype::napi_boolean:
315             AppendBoolArrayData(env, info, key, array, len);
316             HiLog::Debug(LABEL, "AppendBoolArrayData: %{public}s.", key.c_str());
317             break;
318         case napi_valuetype::napi_number:
319             AppendNumberArrayData(env, info, key, array, len);
320             HiLog::Debug(LABEL, "AppendNumberArrayData: %{public}s.", key.c_str());
321             break;
322         case napi_valuetype::napi_bigint:
323             AppendBigIntArrayData(env, info, key, array, len);
324             HiLog::Debug(LABEL, "AppendBigIntArrayData: %{public}s.", key.c_str());
325             break;
326         case napi_valuetype::napi_string:
327             AppendStringArrayData(env, info, key, array, len);
328             HiLog::Debug(LABEL, "AppendStringArrayData: %{public}s.", key.c_str());
329             break;
330         default:
331             break;
332     }
333 }
334 
AddParamToEventInfo(const napi_env env,HiSysEventInfo & info,const std::string & key,napi_value & value)335 void AddParamToEventInfo(const napi_env env, HiSysEventInfo& info, const std::string& key, napi_value& value)
336 {
337     if (CheckValueIsArray(env, value)) {
338         AddArrayParamToEventInfo(env, info, key, value);
339         return;
340     }
341     napi_valuetype type = GetValueType(env, value);
342     switch (type) {
343         case napi_valuetype::napi_boolean:
344             info.boolParams[key] = ParseBoolValue(env, value);
345             break;
346         case napi_valuetype::napi_number:
347             info.doubleParams[key] = ParseNumberValue(env, value);
348             break;
349         case napi_valuetype::napi_string:
350             info.stringParams[key] = ParseStringValue(env, value);
351             break;
352         case napi_valuetype::napi_bigint:
353             info.boolParams[key] = ParseBigIntValue(env, value);
354             break;
355         default:
356             break;
357     }
358 }
359 
GetObjectTypeAttribute(const napi_env env,const napi_value & object,const std::string & propertyName,HiSysEventInfo & info)360 void GetObjectTypeAttribute(const napi_env env, const napi_value& object,
361     const std::string& propertyName, HiSysEventInfo& info)
362 {
363     napi_value propertyValue = NapiHiSysEventUtil::GetPropertyByName(env, object, propertyName);
364     if (!IsValueTypeValid(env, propertyValue, napi_valuetype::napi_object)) {
365         HiLog::Error(LABEL, "type is not napi_object.");
366         return;
367     }
368     napi_value keyArr = nullptr;
369     napi_status status = napi_get_property_names(env, propertyValue, &keyArr);
370     if (status != napi_ok) {
371         HiLog::Error(LABEL, "failed to parse property names of a js object.");
372         return;
373     }
374     uint32_t len = 0;
375     status = napi_get_array_length(env, keyArr, &len);
376     if (status != napi_ok) {
377         HiLog::Error(LABEL, "failed to get the length of the key-value pairs.");
378         return;
379     }
380     for (uint32_t i = 0; i < len; i++) {
381         napi_value key = nullptr;
382         napi_get_element(env, keyArr, i, &key);
383         if (!IsValueTypeValid(env, key, napi_valuetype::napi_string)) {
384             HiLog::Warn(LABEL, "this param would be discarded because of invalid type of the key.");
385             continue;
386         }
387         char buf[BUF_SIZE] = {0};
388         size_t valueLen = 0;
389         napi_get_value_string_utf8(env, key, buf, BUF_SIZE - 1, &valueLen);
390         if (!CheckKeyTypeString(buf)) {
391             HiLog::Warn(LABEL, "this param would be discarded because of invalid format of the key.");
392             continue;
393         }
394         napi_value val = NapiHiSysEventUtil::GetPropertyByName(env, propertyValue, buf);
395         AddParamToEventInfo(env, info, buf, val);
396     }
397 }
398 
ParseStringArray(const napi_env env,napi_value & arrayValue,std::vector<std::string> & arrayDest)399 void ParseStringArray(const napi_env env, napi_value& arrayValue, std::vector<std::string>& arrayDest)
400 {
401     if (!CheckValueIsArray(env, arrayValue)) {
402         HiLog::Error(LABEL, "try to parse a array from a napi value without array type");
403         return;
404     }
405     uint32_t len = 0;
406     napi_status status = napi_get_array_length(env, arrayValue, &len);
407     if (status != napi_ok) {
408         return;
409     }
410     napi_value element;
411     for (uint32_t i = 0; i < len; i++) {
412         status = napi_get_element(env, arrayValue, i, &element);
413         if (status != napi_ok) {
414             return;
415         }
416         if (IsValueTypeValid(env, element, napi_valuetype::napi_string)) {
417             std::string str = ParseStringValue(env, element);
418             HiLog::Debug(LABEL, "parse string: %{public}s.", str.c_str());
419             arrayDest.emplace_back(str);
420         }
421     }
422 }
423 
ParseListenerRule(const napi_env env,const napi_value & jsObj)424 ListenerRule ParseListenerRule(const napi_env env, const napi_value& jsObj)
425 {
426     if (!IsValueTypeValid(env, jsObj, napi_valuetype::napi_object)) {
427         return ListenerRule("", RuleType::WHOLE_WORD);
428     }
429     std::string domain = GetStringTypeAttribute(env, jsObj, NapiHiSysEventUtil::DOMAIN_ATTR);
430     HiLog::Debug(LABEL, "domain is %{public}s.", domain.c_str());
431     std::string name = GetStringTypeAttribute(env, jsObj, NapiHiSysEventUtil::NAME_ATTR);
432     HiLog::Debug(LABEL, "name is %{public}s.", name.c_str());
433     int32_t ruleType = GetInt32TypeAttribute(env, jsObj, RULE_TYPE_ATTR, RuleType::WHOLE_WORD);
434     HiLog::Debug(LABEL, "ruleType is %{public}d.", ruleType);
435     std::string tag = GetTagAttribute(env, jsObj);
436     HiLog::Debug(LABEL, "tag is %{public}s.", tag.c_str());
437     return ListenerRule(domain, name, tag, RuleType(ruleType));
438 }
439 
IsQueryRuleValid(const napi_env env,const QueryRule & rule)440 bool IsQueryRuleValid(const napi_env env, const QueryRule& rule)
441 {
442     auto domain = rule.GetDomain();
443     if (!StringFilter::GetInstance().IsValidName(domain, MAX_DOMAIN_LENGTH)) {
444         NapiHiSysEventUtil::ThrowErrorByRet(env, NapiInnerError::ERR_INVALID_DOMAIN_IN_QUERY_RULE);
445         return false;
446     }
447     auto names = rule.GetEventList();
448     if (std::any_of(names.begin(), names.end(), [] (auto& name) {
449         return !StringFilter::GetInstance().IsValidName(name, MAX_EVENT_NAME_LENGTH);
450     })) {
451         NapiHiSysEventUtil::ThrowErrorByRet(env, NapiInnerError::ERR_INVALID_EVENT_NAME_IN_QUERY_RULE);
452         return false;
453     }
454     return true;
455 }
456 
ParseQueryRule(const napi_env env,napi_value & jsObj)457 QueryRule ParseQueryRule(const napi_env env, napi_value& jsObj)
458 {
459     std::vector<std::string> names;
460     if (!IsValueTypeValid(env, jsObj, napi_valuetype::napi_object)) {
461         return QueryRule("", names);
462     }
463     std::string domain = GetStringTypeAttribute(env, jsObj, NapiHiSysEventUtil::DOMAIN_ATTR);
464     HiLog::Debug(LABEL, "domain is %{public}s.", domain.c_str());
465     napi_value propertyValue = NapiHiSysEventUtil::GetPropertyByName(env, jsObj, NAMES_ATTR);
466     ParseStringArray(env, propertyValue, names);
467     for (auto& name : names) {
468         HiLog::Debug(LABEL, "    event name is %{public}s.", name.c_str());
469     }
470     return QueryRule(domain, names);
471 }
472 
SetNamedProperty(const napi_env env,napi_value & object,const std::string & propertyName,napi_value & propertyValue)473 void SetNamedProperty(const napi_env env, napi_value& object, const std::string& propertyName,
474     napi_value& propertyValue)
475 {
476     napi_status status = napi_set_named_property(env, object, propertyName.c_str(), propertyValue);
477     if (status != napi_ok) {
478         HiLog::Error(LABEL, "set property %{public}s failed.", propertyName.c_str());
479     }
480 }
481 
IsBaseInfoKey(const std::string & propertyName)482 bool IsBaseInfoKey(const std::string& propertyName)
483 {
484     return propertyName == DOMAIN__KEY || propertyName == NAME__KEY || propertyName == TYPE__KEY;
485 }
486 
translateKeyToAttrName(const std::string & key)487 std::string translateKeyToAttrName(const std::string& key)
488 {
489     if (key == DOMAIN__KEY) {
490         return NapiHiSysEventUtil::DOMAIN_ATTR;
491     }
492     if (key == NAME__KEY) {
493         return NapiHiSysEventUtil::NAME_ATTR;
494     }
495     if (key == TYPE__KEY) {
496         return NapiHiSysEventUtil::EVENT_TYPE_ATTR;
497     }
498     return "";
499 }
500 
AppendBaseInfo(const napi_env env,napi_value & sysEventInfo,const std::string & key,Json::Value & value)501 void AppendBaseInfo(const napi_env env, napi_value& sysEventInfo, const std::string& key, Json::Value& value)
502 {
503     if ((key == DOMAIN__KEY || key == NAME__KEY) && value.isString()) {
504         NapiHiSysEventUtil::AppendStringPropertyToJsObject(env, translateKeyToAttrName(key),
505             value.asString(), sysEventInfo);
506     }
507     if (key == TYPE__KEY && value.isInt()) {
508         NapiHiSysEventUtil::AppendInt32PropertyToJsObject(env, translateKeyToAttrName(key),
509             static_cast<int32_t>(value.asInt()), sysEventInfo);
510     }
511 }
512 
CreateBoolValue(const napi_env env,bool value,napi_value & val)513 void CreateBoolValue(const napi_env env, bool value, napi_value& val)
514 {
515     napi_status status = napi_get_boolean(env, value, &val);
516     HiLog::Debug(LABEL, "create napi value of bool type, value is %{public}d.", value);
517     if (status != napi_ok) {
518         HiLog::Error(LABEL, "failed to get create napi value of bool type.");
519     }
520 }
521 
CreateDoubleValue(const napi_env env,double value,napi_value & val)522 void CreateDoubleValue(const napi_env env, double value, napi_value& val)
523 {
524     napi_status status = napi_create_double(env, value, &val);
525     HiLog::Debug(LABEL, "create napi value of double type, value is %{public}f.", value);
526     if (status != napi_ok) {
527         HiLog::Error(LABEL, "failed to get create napi value of double type.");
528     }
529 }
530 
CreateUint32Value(const napi_env env,uint32_t value,napi_value & val)531 void CreateUint32Value(const napi_env env, uint32_t value, napi_value& val)
532 {
533     napi_status status = napi_create_uint32(env, value, &val);
534     HiLog::Debug(LABEL, "create napi value of uint32 type, value is %{public}u.", value);
535     if (status != napi_ok) {
536         HiLog::Error(LABEL, "failed to get create napi value of uint32 type.");
537     }
538 }
539 
CreateParamItemTypeValue(const napi_env env,Json::Value & jsonValue,napi_value & value)540 void CreateParamItemTypeValue(const napi_env env, Json::Value& jsonValue, napi_value& value)
541 {
542     if (jsonValue.isBool()) {
543         CreateBoolValue(env, jsonValue.asBool(), value);
544         return;
545     }
546     if (jsonValue.isInt()) {
547         NapiHiSysEventUtil::CreateInt32Value(env, static_cast<int32_t>(jsonValue.asInt()), value);
548         return;
549     }
550     if (jsonValue.isUInt()) {
551         CreateUint32Value(env, static_cast<uint32_t>(jsonValue.asUInt()), value);
552         return;
553     }
554 #ifdef JSON_HAS_INT64
555     if (jsonValue.isInt64() && jsonValue.type() != Json::ValueType::uintValue) {
556         NapiHiSysEventUtil::CreateInt64Value(env, jsonValue.asInt64(), value);
557         return;
558     }
559     if (jsonValue.isUInt64() && jsonValue.type() != Json::ValueType::intValue) {
560         NapiHiSysEventUtil::CreateUInt64Value(env, jsonValue.asUInt64(), value);
561         return;
562     }
563 #endif
564     if (jsonValue.isDouble()) {
565         CreateDoubleValue(env, jsonValue.asDouble(), value);
566         return;
567     }
568     if (jsonValue.isString()) {
569         NapiHiSysEventUtil::CreateStringValue(env, jsonValue.asString(), value);
570         return;
571     }
572 }
573 
AppendArrayParams(const napi_env env,napi_value & params,const std::string & key,Json::Value & value)574 void AppendArrayParams(const napi_env env, napi_value& params, const std::string& key, Json::Value& value)
575 {
576     size_t len = value.size();
577     napi_value array = nullptr;
578     napi_create_array_with_length(env, len, &array);
579     for (size_t i = 0; i < len; i++) {
580         napi_value item;
581         CreateParamItemTypeValue(env, value[static_cast<int>(i)], item);
582         napi_set_element(env, array, i, item);
583     }
584     SetNamedProperty(env, params, key, array);
585 }
586 
AppendParamsInfo(const napi_env env,napi_value & params,const std::string & key,Json::Value & jsonValue)587 void AppendParamsInfo(const napi_env env, napi_value& params, const std::string& key, Json::Value& jsonValue)
588 {
589     if (jsonValue.isArray()) {
590         AppendArrayParams(env, params, key, jsonValue);
591         return;
592     }
593     napi_value property = nullptr;
594     CreateParamItemTypeValue(env, jsonValue, property);
595     SetNamedProperty(env, params, key, property);
596 }
597 }
598 
GetPropertyByName(const napi_env env,const napi_value & object,const std::string & propertyName)599 napi_value NapiHiSysEventUtil::GetPropertyByName(const napi_env env, const napi_value& object,
600     const std::string& propertyName)
601 {
602     napi_value result = nullptr;
603     napi_status status = napi_get_named_property(env, object, propertyName.c_str(), &result);
604     if (status != napi_ok) {
605         HiLog::Debug(LABEL, "failed to parse property named %{public}s from JS object.", propertyName.c_str());
606     }
607     return result;
608 }
609 
ParseHiSysEventInfo(const napi_env env,napi_value * param,size_t paramNum,HiSysEventInfo & info)610 void NapiHiSysEventUtil::ParseHiSysEventInfo(const napi_env env, napi_value* param,
611     size_t paramNum, HiSysEventInfo& info)
612 {
613     if (paramNum <= SYS_EVENT_INFO_PARAM_INDEX) {
614         return;
615     }
616     if (!IsValueTypeValid(env, param[SYS_EVENT_INFO_PARAM_INDEX], napi_valuetype::napi_object)) {
617         NapiHiSysEventUtil::ThrowParamTypeError(env, "info", "object");
618         return;
619     }
620     info.domain = GetStringTypeAttribute(env, param[SYS_EVENT_INFO_PARAM_INDEX], NapiHiSysEventUtil::DOMAIN_ATTR);
621     HiLog::Debug(LABEL, "domain is %{public}s.", info.domain.c_str());
622     info.name = GetStringTypeAttribute(env, param[SYS_EVENT_INFO_PARAM_INDEX], NapiHiSysEventUtil::NAME_ATTR);
623     HiLog::Debug(LABEL, "name is %{public}s.", info.name.c_str());
624     info.eventType = HiSysEvent::EventType(GetInt32TypeAttribute(env,
625         param[SYS_EVENT_INFO_PARAM_INDEX], EVENT_TYPE_ATTR, HiSysEvent::EventType::FAULT));
626     HiLog::Debug(LABEL, "eventType is %{public}d.", info.eventType);
627     GetObjectTypeAttribute(env, param[SYS_EVENT_INFO_PARAM_INDEX], PARAMS_ATTR, info);
628 }
629 
HasStrParamLenOverLimit(HiSysEventInfo & info)630 bool NapiHiSysEventUtil::HasStrParamLenOverLimit(HiSysEventInfo& info)
631 {
632     return any_of(info.stringParams.begin(), info.stringParams.end(), [] (auto& item) {
633         return item.second.size() > JS_STR_PARM_LEN_LIMIT;
634     }) || any_of(info.stringArrayParams.begin(), info.stringArrayParams.end(), [] (auto& item) {
635         auto allStr = item.second;
636         return any_of(allStr.begin(), allStr.end(), [] (auto& item) {
637             return item.size() > JS_STR_PARM_LEN_LIMIT;
638         });
639     });
640 }
641 
CreateHiSysEventInfoJsObject(const napi_env env,const std::string & jsonStr,napi_value & sysEventInfo)642 void NapiHiSysEventUtil::CreateHiSysEventInfoJsObject(const napi_env env, const std::string& jsonStr,
643     napi_value& sysEventInfo)
644 {
645     Json::Value eventJson;
646 #ifdef JSONCPP_VERSION_STRING
647     Json::CharReaderBuilder jsonRBuilder;
648     Json::CharReaderBuilder::strictMode(&jsonRBuilder.settings_);
649     std::unique_ptr<Json::CharReader> const reader(jsonRBuilder.newCharReader());
650     JSONCPP_STRING errs;
651     if (!reader->parse(jsonStr.data(), jsonStr.data() + jsonStr.size(), &eventJson, &errs)) {
652 #else
653     Json::Reader reader(Json::Features::strictMode());
654     if (!reader.parse(jsonStr, eventJson)) {
655 #endif
656         HiLog::Error(LABEL, "parse event detail info failed, please check the style of json infomation: %{public}s",
657             jsonStr.c_str());
658         return;
659     }
660     napi_create_object(env, &sysEventInfo);
661     napi_value params = nullptr;
662     napi_create_object(env, &params);
663     auto eventNameList = eventJson.getMemberNames();
664     for (auto it = eventNameList.cbegin(); it != eventNameList.cend(); it++) {
665         auto propertyName = *it;
666         if (IsBaseInfoKey(propertyName)) {
667             AppendBaseInfo(env, sysEventInfo, propertyName, eventJson[propertyName]);
668         } else {
669             AppendParamsInfo(env, params, propertyName, eventJson[propertyName]);
670         }
671     }
672     SetNamedProperty(env, sysEventInfo, PARAMS_ATTR, params);
673 }
674 
675 void NapiHiSysEventUtil::CreateJsSysEventInfoArray(const napi_env env, const std::vector<std::string>& originValues,
676     napi_value& array)
677 {
678     auto len = originValues.size();
679     for (size_t i = 0; i < len; i++) {
680         napi_value item;
681         CreateHiSysEventInfoJsObject(env, originValues[i], item);
682         napi_status status = napi_set_element(env, array, i, item);
683         if (status != napi_ok) {
684             HiLog::Error(LABEL, "napi_set_element failed");
685         }
686     }
687 }
688 
689 void NapiHiSysEventUtil::AppendStringPropertyToJsObject(const napi_env env, const std::string& key,
690     const std::string& value, napi_value& jsObj)
691 {
692     napi_value property = nullptr;
693     NapiHiSysEventUtil::CreateStringValue(env, value, property);
694     SetNamedProperty(env, jsObj, key, property);
695 }
696 
697 void NapiHiSysEventUtil::AppendInt32PropertyToJsObject(const napi_env env, const std::string& key,
698     const int32_t& value, napi_value& jsObj)
699 {
700     napi_value property = nullptr;
701     NapiHiSysEventUtil::CreateInt32Value(env, value, property);
702     SetNamedProperty(env, jsObj, key, property);
703 }
704 
705 int32_t NapiHiSysEventUtil::ParseListenerRules(const napi_env env, napi_value& array,
706     std::vector<ListenerRule>& listenerRules)
707 {
708     if (!CheckValueIsArray(env, array)) {
709         ThrowParamTypeError(env, "rules", "array");
710         return ERR_LISTENER_RULES_TYPE_NOT_ARRAY;
711     }
712     uint32_t len = 0;
713     napi_status status = napi_get_array_length(env, array, &len);
714     if (status != napi_ok) {
715         return ERR_NAPI_PARSED_FAILED;
716     }
717     napi_value firstItem;
718     status = napi_get_element(env, array, 0, &firstItem);
719     if (status != napi_ok) {
720         return ERR_NAPI_PARSED_FAILED;
721     }
722     napi_valuetype type;
723     status = napi_typeof(env, firstItem, &type);
724     if (status != napi_ok) {
725         return ERR_NAPI_PARSED_FAILED;
726     }
727     napi_value element;
728     for (uint32_t i = 0; i < len; i++) {
729         status = napi_get_element(env, array, i, &element);
730         if (status != napi_ok) {
731             return ERR_NAPI_PARSED_FAILED;
732         }
733         if (IsValueTypeValid(env, element, napi_valuetype::napi_object)) {
734             listenerRules.emplace_back(ParseListenerRule(env, element));
735         }
736     }
737     return NAPI_SUCCESS;
738 }
739 
740 int32_t NapiHiSysEventUtil::ParseQueryRules(const napi_env env, napi_value& array, std::vector<QueryRule>& queryRules)
741 {
742     if (!CheckValueIsArray(env, array)) {
743         ThrowParamTypeError(env, "rules", "array");
744         return ERR_QUERY_RULES_TYPE_NOT_ARRAY;
745     }
746     uint32_t len = 0;
747     napi_status status = napi_get_array_length(env, array, &len);
748     if (status != napi_ok) {
749         return ERR_NAPI_PARSED_FAILED;
750     }
751     napi_value firstItem;
752     status = napi_get_element(env, array, 0, &firstItem);
753     if (status != napi_ok) {
754         return ERR_NAPI_PARSED_FAILED;
755     }
756     napi_valuetype type;
757     status = napi_typeof(env, firstItem, &type);
758     if (status != napi_ok) {
759         return ERR_NAPI_PARSED_FAILED;
760     }
761     napi_value element;
762     for (uint32_t i = 0; i < len; i++) {
763         status = napi_get_element(env, array, i, &element);
764         if (status != napi_ok) {
765             return ERR_NAPI_PARSED_FAILED;
766         }
767         if (IsValueTypeValid(env, element, napi_valuetype::napi_object)) {
768             auto queryRule = ParseQueryRule(env, element);
769             if (IsQueryRuleValid(env, queryRule)) {
770                 queryRules.emplace_back(queryRule);
771             }
772         }
773     }
774     return NAPI_SUCCESS;
775 }
776 
777 int32_t NapiHiSysEventUtil::ParseQueryArg(const napi_env env, napi_value& jsObj, QueryArg& queryArg)
778 {
779     if (!IsValueTypeValid(env, jsObj, napi_valuetype::napi_object)) {
780         ThrowParamTypeError(env, "queryArg", "object");
781         return ERR_QUERY_ARG_TYPE_INVALID;
782     }
783     queryArg.beginTime = GetLonglongTypeAttribute(env, jsObj, BEGIN_TIME_ATTR, DEFAULT_TIME_STAMP);
784     HiLog::Debug(LABEL, "queryArg.beginTime is %{public}lld.", queryArg.beginTime);
785     queryArg.endTime = GetLonglongTypeAttribute(env, jsObj, END_TIME_ATTR, DEFAULT_TIME_STAMP);
786     HiLog::Debug(LABEL, "queryArg.endTime is %{public}lld.", queryArg.endTime);
787     queryArg.maxEvents = GetInt32TypeAttribute(env, jsObj, MAX_EVENTS_ATTR, DEFAULT_MAX_EVENTS);
788     HiLog::Debug(LABEL, "queryArg.maxEvents is %{public}d.", queryArg.maxEvents);
789     queryArg.fromSeq = GetLonglongTypeAttribute(env, jsObj, BEGIN_SEQ_ATTR, DEFAULT_SEQ);
790     HiLog::Debug(LABEL, "queryArg.fromSeq is %{public}lld.", queryArg.fromSeq);
791     queryArg.toSeq = GetLonglongTypeAttribute(env, jsObj, END_SEQ_ATTR, DEFAULT_SEQ);
792     HiLog::Debug(LABEL, "queryArg.endSeq is %{public}lld.", queryArg.toSeq);
793     return NAPI_SUCCESS;
794 }
795 
796 void NapiHiSysEventUtil::CreateNull(const napi_env env, napi_value& ret)
797 {
798     napi_status status = napi_get_null(env, &ret);
799     if (status != napi_ok) {
800         HiLog::Error(LABEL, "failed to create napi value of null.");
801     }
802 }
803 
804 void NapiHiSysEventUtil::CreateInt32Value(const napi_env env, int32_t value, napi_value& ret)
805 {
806     napi_status status = napi_create_int32(env, value, &ret);
807     HiLog::Debug(LABEL, "create napi value of int32 type, value is %{public}d.", value);
808     if (status != napi_ok) {
809         HiLog::Error(LABEL, "failed to create napi value of int32 type.");
810     }
811 }
812 
813 void NapiHiSysEventUtil::CreateInt64Value(const napi_env env, int64_t value, napi_value& ret)
814 {
815     napi_status status = napi_create_bigint_int64(env, value, &ret);
816     HiLog::Debug(LABEL, "create napi value of int64_t type, value is %{public}" PRId64 ".", value);
817     if (status != napi_ok) {
818         HiLog::Error(LABEL, "failed to create napi value of int64_t type.");
819     }
820 }
821 
822 void NapiHiSysEventUtil::CreateUInt64Value(const napi_env env, uint64_t value, napi_value& ret)
823 {
824     napi_status status = napi_create_bigint_uint64(env, value, &ret);
825     HiLog::Debug(LABEL, "create napi value of uint64_t type, value is %{public}" PRIu64 ".", value);
826     if (status != napi_ok) {
827         HiLog::Error(LABEL, "failed to create napi value of uint64_t type.");
828     }
829 }
830 
831 void NapiHiSysEventUtil::CreateStringValue(const napi_env env, std::string value, napi_value& ret)
832 {
833     napi_status status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &ret);
834     HiLog::Debug(LABEL, "create napi value of string type, value is %{public}s.", value.c_str());
835     if (status != napi_ok) {
836         HiLog::Error(LABEL, "failed to create napi value of string type.");
837     }
838 }
839 
840 void NapiHiSysEventUtil::ThrowParamMandatoryError(napi_env env, const std::string paramName)
841 {
842     ThrowError(env, NapiError::ERR_PARAM_CHECK, "Parameter error. The " + paramName + " parameter is mandatory.");
843 }
844 
845 void NapiHiSysEventUtil::ThrowParamTypeError(napi_env env, const std::string paramName, std::string paramType)
846 {
847     ThrowError(env, NapiError::ERR_PARAM_CHECK, "Parameter error. The type of " + paramName + " must be "
848         + paramType + ".");
849 }
850 
851 napi_value NapiHiSysEventUtil::CreateError(napi_env env, int32_t code, const std::string& msg)
852 {
853     napi_value err = nullptr;
854     napi_value napiCode = nullptr;
855     NapiHiSysEventUtil::CreateStringValue(env, std::to_string(code), napiCode);
856     napi_value napiStr = nullptr;
857     NapiHiSysEventUtil::CreateStringValue(env, msg, napiStr);
858     if (napi_create_error(env, napiCode, napiStr, &err) != napi_ok) {
859         HiLog::Error(LABEL, "failed to create napi error");
860     }
861     return err;
862 }
863 
864 void NapiHiSysEventUtil::ThrowError(napi_env env, const int32_t code, const std::string& msg)
865 {
866     if (napi_throw_error(env, std::to_string(code).c_str(), msg.c_str()) != napi_ok) {
867         HiLog::Error(LABEL, "failed to throw err, code=%{public}d, msg=%{public}s.", code, msg.c_str());
868     }
869 }
870 
871 std::pair<int32_t, std::string> NapiHiSysEventUtil::GetErrorDetailByRet(napi_env env, const int32_t retCode)
872 {
873     HiLog::Info(LABEL, "origin result code is %{public}d.", retCode);
874     const std::unordered_map<int32_t, std::pair<int32_t, std::string>> errMap = {
875         // common
876         {ERR_NO_PERMISSION, {NapiError::ERR_PERMISSION_CHECK,
877             "Permission denied. An attempt was made to read sysevent forbidden"
878             " by permission: ohos.permission.READ_DFX_SYSEVENT."}},
879         // write refer
880         {ERR_DOMAIN_NAME_INVALID, {NapiError::ERR_INVALID_DOMAIN, "Domain is invalid"}},
881         {ERR_EVENT_NAME_INVALID, {NapiError::ERR_INVALID_EVENT_NAME, "Event name is invalid"}},
882         {ERR_DOES_NOT_INIT, {NapiError::ERR_ENV_ABNORMAL, "Environment is abnormal"}},
883         {ERR_OVER_SIZE, {NapiError::ERR_CONTENT_OVER_LIMIT, "Size of event content is over limit"}},
884         {ERR_KEY_NAME_INVALID, {NapiError::ERR_INVALID_PARAM_NAME, "Name of param is invalid"}},
885         {ERR_VALUE_LENGTH_TOO_LONG, {NapiError::ERR_STR_LEN_OVER_LIMIT,
886             "Size of string type param is over limit"}},
887         {ERR_KEY_NUMBER_TOO_MUCH, {NapiError::ERR_PARAM_COUNT_OVER_LIMIT, "Count of params is over limit"}},
888         {ERR_ARRAY_TOO_MUCH, {NapiError::ERR_ARRAY_SIZE_OVER_LIMIT, "Size of array type param is over limit"}},
889         // ipc common
890         {ERR_SYS_EVENT_SERVICE_NOT_FOUND, {NapiError::ERR_ENV_ABNORMAL, "Environment is abnormal"}},
891         {ERR_CAN_NOT_WRITE_DESCRIPTOR, {NapiError::ERR_ENV_ABNORMAL, "Environment is abnormal"}},
892         {ERR_CAN_NOT_WRITE_PARCEL, {NapiError::ERR_ENV_ABNORMAL, "Environment is abnormal"}},
893         {ERR_CAN_NOT_WRITE_REMOTE_OBJECT, {NapiError::ERR_ENV_ABNORMAL, "Environment is abnormal"}},
894         {ERR_CAN_NOT_SEND_REQ, {NapiError::ERR_ENV_ABNORMAL, "Environment is abnormal"}},
895         {ERR_CAN_NOT_READ_PARCEL, {NapiError::ERR_ENV_ABNORMAL, "Environment is abnormal"}},
896         {ERR_SEND_FAIL, {NapiError::ERR_ENV_ABNORMAL, "Environment is abnormal"}},
897         // add watcher
898         {ERR_TOO_MANY_WATCHERS, {NapiError::ERR_WATCHER_COUNT_OVER_LIMIT, "Count of watchers is over limit"}},
899         {ERR_TOO_MANY_WATCH_RULES, {NapiError::ERR_WATCH_RULE_COUNT_OVER_LIMIT,
900             "Count of watch rules is over limit"}},
901         // remove watcher
902         {ERR_LISTENER_NOT_EXIST, {NapiError::ERR_WATCHER_NOT_EXIST, "Watcher is not exist"}},
903         {ERR_NAPI_LISTENER_NOT_FOUND, {NapiError::ERR_WATCHER_NOT_EXIST, "Watcher is not exist"}},
904         // query refer
905         {ERR_TOO_MANY_QUERY_RULES, {NapiError::ERR_QUERY_RULE_COUNT_OVER_LIMIT,
906             "Count of query rules is over limit"}},
907         {ERR_TOO_MANY_CONCURRENT_QUERIES, {NapiError::ERR_CONCURRENT_QUERY_COUNT_OVER_LIMIT,
908             "cCount of concurrent queries is over limit"}},
909         {ERR_QUERY_TOO_FREQUENTLY, {NapiError::ERR_QUERY_TOO_FREQUENTLY, "Frequency of event query is over limit"}},
910         {NapiInnerError::ERR_INVALID_DOMAIN_IN_QUERY_RULE,
911             {NapiError::ERR_INVALID_QUERY_RULE, "Query rule is invalid"}},
912         {ERR_QUERY_RULE_INVALID, {NapiError::ERR_INVALID_QUERY_RULE, "Query rule is invalid"}},
913         {NapiInnerError::ERR_INVALID_EVENT_NAME_IN_QUERY_RULE,
914             {NapiError::ERR_INVALID_QUERY_RULE, "Query rule is invalid"}},
915     };
916     return errMap.find(retCode) == errMap.end() ?
917         std::make_pair(NapiError::ERR_ENV_ABNORMAL, "environment is abnormal") : errMap.at(retCode);
918 }
919 
920 napi_value NapiHiSysEventUtil::CreateErrorByRet(napi_env env, const int32_t retCode)
921 {
922     auto detail = GetErrorDetailByRet(env, retCode);
923     return CreateError(env, detail.first, detail.second);
924 }
925 
926 void NapiHiSysEventUtil::ThrowErrorByRet(napi_env env, const int32_t retCode)
927 {
928     auto detail = GetErrorDetailByRet(env, retCode);
929     ThrowError(env, detail.first, detail.second);
930 }
931 } // namespace HiviewDFX
932 } // namespace OHOS