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, ¶ms);
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