• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "napi_hisysevent_adapter.h"
17 
18 #include <cctype>
19 #include <memory>
20 
21 #include "def.h"
22 #include "hilog/log.h"
23 #include "napi_hisysevent_util.h"
24 #include "native_engine/native_engine.h"
25 
26 #undef LOG_DOMAIN
27 #define LOG_DOMAIN 0xD002D08
28 
29 #undef LOG_TAG
30 #define LOG_TAG "NAPI_HISYSEVENT_ADAPTER"
31 
32 namespace OHOS {
33 namespace HiviewDFX {
34 namespace {
35 constexpr size_t ERR_INDEX = 0;
36 constexpr size_t VAL_INDEX = 1;
37 constexpr size_t RET_SIZE = 2;
38 constexpr int64_t DEFAULT_LINE_NUM = -1;
39 constexpr char FUNC_SOURCE_NAME[] = "JSHiSysEventWrite";
40 constexpr int FUNC_NAME_INDEX = 1;
41 constexpr int LINE_INFO_INDEX = 2;
42 constexpr int LINE_INDEX = 1;
43 constexpr char CALL_FUNC_INFO_DELIMITER = ' ';
44 constexpr char CALL_LINE_INFO_DELIMITER = ':';
45 constexpr char PATH_DELIMITER = '/';
46 
Split(const std::string & origin,char delimiter,std::vector<std::string> & ret)47 void Split(const std::string& origin, char delimiter, std::vector<std::string>& ret)
48 {
49     std::string::size_type start = 0;
50     std::string::size_type end = origin.find(delimiter);
51     while (end != std::string::npos) {
52         if (end == start) {
53             start++;
54             end = origin.find(delimiter, start);
55             continue;
56         }
57         ret.emplace_back(origin.substr(start, end - start));
58         start = end + 1;
59         end = origin.find(delimiter, start);
60     }
61     if (start != origin.length()) {
62         ret.emplace_back(origin.substr(start));
63     }
64 }
65 
ParseCallerInfoFromStackTrace(const std::string & stackTrace,JsCallerInfo & callerInfo)66 void ParseCallerInfoFromStackTrace(const std::string& stackTrace, JsCallerInfo& callerInfo)
67 {
68     if (stackTrace.empty()) {
69         HILOG_ERROR(LOG_CORE, "js stack trace is invalid.");
70         return;
71     }
72     std::vector<std::string> callInfos;
73     Split(stackTrace, CALL_FUNC_INFO_DELIMITER, callInfos);
74     if (callInfos.size() <= FUNC_NAME_INDEX) {
75         HILOG_ERROR(LOG_CORE, "js function name parsed failed.");
76         return;
77     }
78     callerInfo.first = callInfos[FUNC_NAME_INDEX];
79     if (callInfos.size() <= LINE_INFO_INDEX) {
80         HILOG_ERROR(LOG_CORE, "js function line info parsed failed.");
81         return;
82     }
83     std::string callInfo = callInfos[LINE_INFO_INDEX];
84     std::vector<std::string> lineInfos;
85     Split(callInfo, CALL_LINE_INFO_DELIMITER, lineInfos);
86     if (lineInfos.size() <= LINE_INDEX) {
87         HILOG_ERROR(LOG_CORE, "js function line number parsed failed.");
88         return;
89     }
90     if (callerInfo.first == "anonymous") {
91         auto fileName = lineInfos[LINE_INDEX - 1];
92         auto pos = fileName.find_last_of(PATH_DELIMITER);
93         callerInfo.first = (pos == std::string::npos) ? fileName : fileName.substr(++pos);
94     }
95     auto lineInfo = lineInfos[LINE_INDEX];
96     if (std::any_of(lineInfo.begin(), lineInfo.end(), [] (auto& c) {
97         return !isdigit(c);
98     })) {
99         callerInfo.second = DEFAULT_LINE_NUM;
100         return;
101     }
102     callerInfo.second = static_cast<int64_t>(std::stoll(lineInfos[LINE_INDEX]));
103 }
104 }
105 
ParseJsCallerInfo(const napi_env env,JsCallerInfo & callerInfo)106 void NapiHiSysEventAdapter::ParseJsCallerInfo(const napi_env env, JsCallerInfo& callerInfo)
107 {
108     NativeEngine* engine = reinterpret_cast<NativeEngine*>(env);
109     std::string stackTrace;
110     if (!engine->BuildJsStackTrace(stackTrace)) {
111         HILOG_ERROR(LOG_CORE, "js stack trace build failed.");
112         return;
113     }
114     ParseCallerInfoFromStackTrace(stackTrace, callerInfo);
115 }
116 
CheckThenWriteSysEvent(HiSysEventAsyncContext * eventAsyncContext)117 void NapiHiSysEventAdapter::CheckThenWriteSysEvent(HiSysEventAsyncContext* eventAsyncContext)
118 {
119     if (eventAsyncContext == nullptr) {
120         return;
121     }
122     if (eventAsyncContext->eventWroteResult != SUCCESS) {
123         return;
124     }
125     auto eventInfo = eventAsyncContext->eventInfo;
126     auto jsCallerInfo = eventAsyncContext->jsCallerInfo;
127     ControlParam param {
128         .period = HISYSEVENT_DEFAULT_PERIOD,
129         .threshold = HISYSEVENT_DEFAULT_THRESHOLD,
130     };
131     CallerInfo info = {
132         .func = jsCallerInfo.first.c_str(),
133         .line = jsCallerInfo.second,
134         .timeStamp = eventAsyncContext->timeStamp,
135     };
136     uint64_t timeStamp = HiSysEvent::controller.CheckLimitWritingEvent(param, eventInfo.domain.c_str(),
137         eventInfo.name.c_str(), info);
138     if (timeStamp == INVALID_TIME_STAMP) {
139         eventAsyncContext->eventWroteResult = ERR_WRITE_IN_HIGH_FREQ;
140         return;
141     }
142     eventAsyncContext->eventWroteResult = Write(eventInfo, timeStamp);
143 }
144 
Write(const napi_env env,HiSysEventAsyncContext * eventAsyncContext)145 void NapiHiSysEventAdapter::Write(const napi_env env, HiSysEventAsyncContext* eventAsyncContext)
146 {
147     napi_value resource = nullptr;
148     NapiHiSysEventUtil::CreateStringValue(env, FUNC_SOURCE_NAME, resource);
149     eventAsyncContext->timeStamp = HiSysEvent::controller.GetCurrentTimeMills();
150     napi_create_async_work(
151         env, nullptr, resource,
152         [] (napi_env env, void* data) {
153             HiSysEventAsyncContext* eventAsyncContext = reinterpret_cast<HiSysEventAsyncContext*>(data);
154             CheckThenWriteSysEvent(eventAsyncContext);
155         },
156         [] (napi_env env, napi_status status, void* data) {
157             HiSysEventAsyncContext* eventAsyncContext = reinterpret_cast<HiSysEventAsyncContext*>(data);
158             napi_value results[RET_SIZE] = {0};
159             auto isNormalWrote = eventAsyncContext->eventWroteResult == SUCCESS &&
160                 !NapiHiSysEventUtil::HasStrParamLenOverLimit(eventAsyncContext->eventInfo);
161             if (isNormalWrote) {
162                 NapiHiSysEventUtil::CreateNull(env, results[ERR_INDEX]);
163                 NapiHiSysEventUtil::CreateInt32Value(env, eventAsyncContext->eventWroteResult, results[VAL_INDEX]);
164             } else {
165                 NapiHiSysEventUtil::CreateNull(env, results[VAL_INDEX]);
166                 auto errorCode = eventAsyncContext->eventWroteResult == SUCCESS ? ERR_VALUE_LENGTH_TOO_LONG :
167                     eventAsyncContext->eventWroteResult;
168                 results[ERR_INDEX] = NapiHiSysEventUtil::CreateErrorByRet(env, errorCode);
169             }
170             if (eventAsyncContext->deferred != nullptr) { // promise
171                 isNormalWrote ? napi_resolve_deferred(env, eventAsyncContext->deferred, results[VAL_INDEX]) :
172                     napi_reject_deferred(env, eventAsyncContext->deferred, results[ERR_INDEX]);
173             } else {
174                 napi_value callback = nullptr;
175                 napi_get_reference_value(env, eventAsyncContext->callback, &callback);
176                 napi_value retValue = nullptr;
177                 napi_call_function(env, nullptr, callback, RET_SIZE, results, &retValue);
178                 napi_delete_reference(env, eventAsyncContext->callback);
179             }
180             napi_delete_async_work(env, eventAsyncContext->asyncWork);
181             delete eventAsyncContext;
182         }, reinterpret_cast<void*>(eventAsyncContext), &eventAsyncContext->asyncWork);
183     napi_queue_async_work_with_qos(env, eventAsyncContext->asyncWork, napi_qos_default);
184 }
185 
InnerWrite(HiSysEvent::EventBase & eventBase,const HiSysEventInfo & eventInfo)186 void NapiHiSysEventAdapter::InnerWrite(HiSysEvent::EventBase& eventBase,
187     const HiSysEventInfo& eventInfo)
188 {
189     AppendParams(eventBase, eventInfo.params);
190 }
191 
Write(const HiSysEventInfo & eventInfo,uint64_t timeStamp)192 int NapiHiSysEventAdapter::Write(const HiSysEventInfo& eventInfo, uint64_t timeStamp)
193 {
194     if (!StringFilter::GetInstance().IsValidName(eventInfo.domain, MAX_DOMAIN_LENGTH)) {
195         return HiSysEvent::ExplainThenReturnRetCode(ERR_DOMAIN_NAME_INVALID);
196     }
197     if (!StringFilter::GetInstance().IsValidName(eventInfo.name, MAX_EVENT_NAME_LENGTH)) {
198         return HiSysEvent::ExplainThenReturnRetCode(ERR_EVENT_NAME_INVALID);
199     }
200     HiSysEvent::EventBase eventBase(eventInfo.domain, eventInfo.name, eventInfo.eventType, timeStamp);
201     HiSysEvent::WritebaseInfo(eventBase);
202     if (HiSysEvent::IsError(eventBase)) {
203         return HiSysEvent::ExplainThenReturnRetCode(eventBase.GetRetCode());
204     }
205 
206     InnerWrite(eventBase, eventInfo);
207     HiSysEvent::InnerWrite(eventBase);
208     if (HiSysEvent::IsError(eventBase)) {
209         return HiSysEvent::ExplainThenReturnRetCode(eventBase.GetRetCode());
210     }
211 
212     HiSysEvent::SendSysEvent(eventBase);
213     return eventBase.GetRetCode();
214 }
215 } // namespace HiviewDFX
216 } // namespace OHOS
217