1 /*
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "napi_hitrace_init.h"
17 
18 #include "hilog/log.h"
19 #include "napi_hitrace_param.h"
20 #include "napi_hitrace_util.h"
21 
22 using namespace OHOS::HiviewDFX;
23 
24 namespace {
25 #undef LOG_DOMAIN
26 #define LOG_DOMAIN 0xD002D33
27 
28 #undef LOG_TAG
29 #define LOG_TAG "HITRACE_JS_NAPI"
30 constexpr uint32_t BUF_SIZE_64 = 64;
31 
ParseInt32Param(const napi_env & env,const napi_value & origin,int & dest)32 bool ParseInt32Param(const napi_env& env, const napi_value& origin, int& dest)
33 {
34     if (!NapiHitraceUtil::CheckValueTypeValidity(env, origin, napi_valuetype::napi_number)) {
35         return false;
36     }
37     napi_get_value_int32(env, origin, &dest);
38     return true;
39 }
40 
ParseStringParam(const napi_env & env,const napi_value & origin,std::string & dest)41 bool ParseStringParam(const napi_env& env, const napi_value& origin, std::string& dest)
42 {
43     if (!NapiHitraceUtil::CheckValueTypeValidity(env, origin, napi_valuetype::napi_string)) {
44         return false;
45     }
46     char buf[BUF_SIZE_64] = {0};
47     size_t bufLength = 0;
48     napi_get_value_string_utf8(env, origin, buf, BUF_SIZE_64, &bufLength);
49     dest = std::string {buf};
50     return true;
51 }
52 
ParseTraceIdObject(const napi_env & env,const napi_value & origin,HiTraceId & traceId)53 bool ParseTraceIdObject(const napi_env& env, const napi_value& origin, HiTraceId& traceId)
54 {
55     if (!NapiHitraceUtil::CheckValueTypeValidity(env, origin, napi_valuetype::napi_object)) {
56         return false;
57     }
58     NapiHitraceUtil::TransHiTraceIdJsObjectToNative(env, traceId, origin);
59     return true;
60 }
61 
IsNullOrUndefinedType(const napi_env & env,const napi_value & origin)62 bool IsNullOrUndefinedType(const napi_env& env, const napi_value& origin)
63 {
64     return NapiHitraceUtil::CheckValueTypeValidity(env, origin, napi_valuetype::napi_null) ||
65         NapiHitraceUtil::CheckValueTypeValidity(env, origin, napi_valuetype::napi_undefined);
66 }
67 }
68 
Begin(napi_env env,napi_callback_info info)69 static napi_value Begin(napi_env env, napi_callback_info info)
70 {
71     size_t paramNum = ParamNum::TOTAL_TWO;
72     napi_value params[ParamNum::TOTAL_TWO] = {0};
73     napi_value thisArg = nullptr;
74     void* data = nullptr;
75     NAPI_CALL(env, napi_get_cb_info(env, info, &paramNum, params, &thisArg, &data));
76     HiTraceId traceId;
77     napi_value val = nullptr;
78     NapiHitraceUtil::CreateHiTraceIdJsObject(env, traceId, val);
79     if (paramNum != ParamNum::TOTAL_ONE && paramNum != ParamNum::TOTAL_TWO) {
80         HILOG_ERROR(LOG_CORE,
81             "failed to begin a new trace, count of parameters is not equal to 1 or 2");
82         return val;
83     }
84     std::string name;
85     if (!ParseStringParam(env, params[ParamIndex::PARAM_FIRST], name)) {
86         HILOG_ERROR(LOG_CORE, "name type must be string.");
87         return val;
88     }
89     int flag = HiTraceFlag::HITRACE_FLAG_DEFAULT;
90     if (paramNum == ParamNum::TOTAL_TWO &&
91         !ParseInt32Param(env, params[ParamIndex::PARAM_SECOND], flag) &&
92         !IsNullOrUndefinedType(env, params[ParamIndex::PARAM_SECOND])) {
93         HILOG_ERROR(LOG_CORE, "flag type must be number, null or undefined.");
94         return val;
95     }
96     traceId = HiTraceChain::Begin(name, flag);
97     NapiHitraceUtil::CreateHiTraceIdJsObject(env, traceId, val);
98     return val;
99 }
100 
End(napi_env env,napi_callback_info info)101 static napi_value End(napi_env env, napi_callback_info info)
102 {
103     size_t paramNum = ParamNum::TOTAL_ONE;
104     napi_value params[ParamNum::TOTAL_ONE] = {0};
105     napi_value thisArg = nullptr;
106     void* data = nullptr;
107     NAPI_CALL(env, napi_get_cb_info(env, info, &paramNum, params, &thisArg, &data));
108     if (paramNum != ParamNum::TOTAL_ONE) {
109         HILOG_ERROR(LOG_CORE,
110             "failed to end trace by trace id, count of parameters is not equal to 1.");
111         return nullptr;
112     }
113     HiTraceId traceId;
114     if (!ParseTraceIdObject(env, params[ParamIndex::PARAM_FIRST], traceId)) {
115         HILOG_ERROR(LOG_CORE, "hitarce id type must be object.");
116         return nullptr;
117     }
118     HiTraceChain::End(traceId);
119     return nullptr;
120 }
121 
GetId(napi_env env,napi_callback_info info)122 static napi_value GetId(napi_env env, napi_callback_info info)
123 {
124     HiTraceId traceId = HiTraceChain::GetId();
125     napi_value val = nullptr;
126     NapiHitraceUtil::CreateHiTraceIdJsObject(env, traceId, val);
127     return val;
128 }
129 
SetId(napi_env env,napi_callback_info info)130 static napi_value SetId(napi_env env, napi_callback_info info)
131 {
132     size_t paramNum = ParamNum::TOTAL_ONE;
133     napi_value params[ParamNum::TOTAL_ONE] = {0};
134     napi_value thisArg = nullptr;
135     void* data = nullptr;
136     NAPI_CALL(env, napi_get_cb_info(env, info, &paramNum, params, &thisArg, &data));
137     if (paramNum != ParamNum::TOTAL_ONE) {
138         HILOG_ERROR(LOG_CORE,
139             "failed to set a new id for a trace, count of parameters is not equal to 1.");
140         return nullptr;
141     }
142     HiTraceId traceId;
143     if (!ParseTraceIdObject(env, params[ParamIndex::PARAM_FIRST], traceId)) {
144         HILOG_ERROR(LOG_CORE, "hitarce id type must be object.");
145         return nullptr;
146     }
147     HiTraceChain::SetId(traceId);
148     return nullptr;
149 }
150 
ClearId(napi_env env,napi_callback_info info)151 static napi_value ClearId(napi_env env, napi_callback_info info)
152 {
153     HiTraceChain::ClearId();
154     return nullptr;
155 }
156 
CreateSpan(napi_env env,napi_callback_info info)157 static napi_value CreateSpan(napi_env env, napi_callback_info info)
158 {
159     HiTraceId traceId = HiTraceChain::CreateSpan();
160     napi_value val = nullptr;
161     NapiHitraceUtil::CreateHiTraceIdJsObject(env, traceId, val);
162     return val;
163 }
164 
Tracepoint(napi_env env,napi_callback_info info)165 static napi_value Tracepoint(napi_env env, napi_callback_info info)
166 {
167     size_t paramNum = ParamNum::TOTAL_FOUR;
168     napi_value params[ParamNum::TOTAL_FOUR] = {0};
169     napi_value thisArg = nullptr;
170     void* data = nullptr;
171     NAPI_CALL(env, napi_get_cb_info(env, info, &paramNum, params, &thisArg, &data));
172     if (paramNum != ParamNum::TOTAL_THREE && paramNum != ParamNum::TOTAL_FOUR) {
173         HILOG_ERROR(LOG_CORE,
174             "failed to trace point, count of parameters is not equal to 3 or 4.");
175         return nullptr;
176     }
177     int communicationModeInt = 0;
178     if (!ParseInt32Param(env, params[ParamIndex::PARAM_FIRST], communicationModeInt)) {
179         HILOG_ERROR(LOG_CORE, "HiTraceCommunicationMode type must be number.");
180         return nullptr;
181     }
182     HiTraceCommunicationMode communicationMode = HiTraceCommunicationMode(communicationModeInt);
183     int tracePointTypeInt = 0;
184     if (!ParseInt32Param(env, params[ParamIndex::PARAM_SECOND], tracePointTypeInt)) {
185         HILOG_ERROR(LOG_CORE, "HiTraceTracePointType type must be number.");
186         return nullptr;
187     }
188     HiTraceTracepointType tracePointType = HiTraceTracepointType(tracePointTypeInt);
189     HiTraceId traceId;
190     if (!ParseTraceIdObject(env, params[ParamIndex::PARAM_THIRD], traceId)) {
191         HILOG_ERROR(LOG_CORE, "hitarce id type must be object.");
192         return nullptr;
193     }
194     std::string description;
195     if (paramNum == ParamNum::TOTAL_FOUR &&
196         !ParseStringParam(env, params[ParamIndex::PARAM_FORTH], description) &&
197         !IsNullOrUndefinedType(env, params[ParamIndex::PARAM_FORTH])) {
198         HILOG_ERROR(LOG_CORE, "description type must be string, null or undefined.");
199         return nullptr;
200     }
201     HiTraceChain::Tracepoint(communicationMode, tracePointType, traceId, "%s", description.c_str());
202     return nullptr;
203 }
204 
IsValid(napi_env env,napi_callback_info info)205 static napi_value IsValid(napi_env env, napi_callback_info info)
206 {
207     size_t paramNum = ParamNum::TOTAL_ONE;
208     napi_value params[ParamNum::TOTAL_ONE] = {0};
209     napi_value thisArg = nullptr;
210     void* data = nullptr;
211     NAPI_CALL(env, napi_get_cb_info(env, info, &paramNum, params, &thisArg, &data));
212     bool isValid = false;
213     napi_value val = nullptr;
214     napi_get_boolean(env, isValid, &val);
215     if (paramNum != ParamNum::TOTAL_ONE) {
216         HILOG_ERROR(LOG_CORE,
217             "failed to check whether a id is valid or not, count of parameters is not equal to 1.");
218         return val;
219     }
220     HiTraceId traceId;
221     if (!ParseTraceIdObject(env, params[ParamIndex::PARAM_FIRST], traceId)) {
222         HILOG_ERROR(LOG_CORE, "hitarce id type must be object.");
223         return val;
224     }
225     isValid = traceId.IsValid();
226     napi_get_boolean(env, isValid, &val);
227     return val;
228 }
229 
IsFlagEnabled(napi_env env,napi_callback_info info)230 static napi_value IsFlagEnabled(napi_env env, napi_callback_info info)
231 {
232     size_t paramNum = ParamNum::TOTAL_TWO;
233     napi_value params[ParamNum::TOTAL_TWO] = {0};
234     napi_value thisArg = nullptr;
235     void* data = nullptr;
236     NAPI_CALL(env, napi_get_cb_info(env, info, &paramNum, params, &thisArg, &data));
237     bool isFalgEnabled = false;
238     napi_value val = nullptr;
239     napi_get_boolean(env, isFalgEnabled, &val);
240     if (paramNum != ParamNum::TOTAL_TWO) {
241         HILOG_ERROR(LOG_CORE,
242             "failed to check whether a flag is enabled in a trace id, count of parameters is not equal to 2.");
243         return val;
244     }
245     HiTraceId traceId;
246     if (!ParseTraceIdObject(env, params[ParamIndex::PARAM_FIRST], traceId)) {
247         HILOG_ERROR(LOG_CORE, "hitarce id type must be object.");
248         return val;
249     }
250     int traceFlagInt = 0;
251     if (!ParseInt32Param(env, params[ParamIndex::PARAM_SECOND], traceFlagInt)) {
252         HILOG_ERROR(LOG_CORE, "HiTraceFlag type must be number.");
253         return val;
254     }
255     HiTraceFlag traceFlag = HiTraceFlag(traceFlagInt);
256     isFalgEnabled = traceId.IsFlagEnabled(traceFlag);
257     napi_get_boolean(env, isFalgEnabled, &val);
258     return val;
259 }
260 
EnableFlag(napi_env env,napi_callback_info info)261 static napi_value EnableFlag(napi_env env, napi_callback_info info)
262 {
263     size_t paramNum = ParamNum::TOTAL_TWO;
264     napi_value params[ParamNum::TOTAL_TWO] = {0};
265     napi_value thisArg = nullptr;
266     void* data = nullptr;
267     NAPI_CALL(env, napi_get_cb_info(env, info, &paramNum, params, &thisArg, &data));
268     if (paramNum != ParamNum::TOTAL_TWO) {
269         HILOG_ERROR(LOG_CORE,
270             "failed to enable a flag for a trace id, count of parameters is not equal to 2.");
271         return nullptr;
272     }
273     HiTraceId traceId;
274     if (!ParseTraceIdObject(env, params[ParamIndex::PARAM_FIRST], traceId)) {
275         HILOG_ERROR(LOG_CORE, "hitarce id type must be object.");
276         return nullptr;
277     }
278     int traceFlagInt = 0;
279     if (!ParseInt32Param(env, params[ParamIndex::PARAM_SECOND], traceFlagInt)) {
280         HILOG_ERROR(LOG_CORE, "HiTraceFlag type must be number.");
281         return nullptr;
282     }
283     HiTraceFlag traceFlag = HiTraceFlag(traceFlagInt);
284     traceId.EnableFlag(traceFlag);
285     NapiHitraceUtil::EnableTraceIdObjectFlag(env, traceId, params[ParamIndex::PARAM_FIRST]);
286     return nullptr;
287 }
288 
289 EXTERN_C_START
TraceNapiInit(napi_env env,napi_value exports)290 static napi_value TraceNapiInit(napi_env env, napi_value exports)
291 {
292     napi_property_descriptor desc[] = {
293         DECLARE_NAPI_FUNCTION("begin", Begin),
294         DECLARE_NAPI_FUNCTION("end", End),
295         DECLARE_NAPI_FUNCTION("getId", GetId),
296         DECLARE_NAPI_FUNCTION("setId", SetId),
297         DECLARE_NAPI_FUNCTION("clearId", ClearId),
298         DECLARE_NAPI_FUNCTION("createSpan", CreateSpan),
299         DECLARE_NAPI_FUNCTION("tracepoint", Tracepoint),
300         DECLARE_NAPI_FUNCTION("isValid", IsValid),
301         DECLARE_NAPI_FUNCTION("isFlagEnabled", IsFlagEnabled),
302         DECLARE_NAPI_FUNCTION("enableFlag", EnableFlag),
303     };
304     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(napi_property_descriptor), desc));
305 
306     // init HiTraceFlag class, HiTraceTracePointType class and HiTraceCommunicationMode class
307     InitNapiClass(env, exports);
308     return exports;
309 }
310 EXTERN_C_END
311 
312 static napi_module hitrace_module = {
313     .nm_version = 1,
314     .nm_flags = 0,
315     .nm_filename = nullptr,
316     .nm_register_func = TraceNapiInit,
317     .nm_modname = "hiTraceChain",
318     .nm_priv = (reinterpret_cast<void *>(0)),
319     .reserved = {0}
320 };
321 
RegisterModule(void)322 extern "C" __attribute__((constructor)) void RegisterModule(void)
323 {
324     napi_module_register(&hitrace_module);
325 }
326