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 <cstdio>
17 #include <functional>
18 #include <hilog/log.h>
19 #include <map>
20 #include <string>
21
22 #include "hitrace_meter.h"
23 #include "hitrace_meter_c.h"
24 #include "napi_hitrace_meter.h"
25
26 using namespace OHOS::HiviewDFX;
27 namespace {
28 enum ArgcNum {
29 ARGC_ONE = 1,
30 ARGC_TWO = 2,
31 ARGC_THREE = 3,
32 ARGC_FOURTH = 4,
33 ARGC_FIVE = 5,
34 };
35
36 enum ArgIndex {
37 ARG_FIRST = 0,
38 ARG_SECOND = 1,
39 ARG_THIRD = 2,
40 ARG_FOURTH = 3,
41 ARG_FIFTH = 4,
42 };
43
44 const char* const HITRACE_OUTPUT_LEVEL = "HiTraceOutputLevel";
45
46 #ifdef LOG_DOMAIN
47 #undef LOG_DOMAIN
48 #define LOG_DOMAIN 0xD002D33
49 #endif
50 #ifdef LOG_TAG
51 #undef LOG_TAG
52 #define LOG_TAG "HitraceMeterNapi"
53 #endif
54
55 using STR_NUM_PARAM_FUNC = std::function<bool(std::string, napi_value&)>;
56
TypeCheck(const napi_env & env,const napi_value & value,const napi_valuetype expectType)57 bool TypeCheck(const napi_env& env, const napi_value& value, const napi_valuetype expectType)
58 {
59 napi_valuetype valueType;
60 napi_status status = napi_typeof(env, value, &valueType);
61 if (status != napi_ok) {
62 HILOG_ERROR(LOG_CORE, "Failed to get the type of the argument.");
63 return false;
64 }
65 if (valueType != expectType) {
66 HILOG_DEBUG(LOG_CORE, "Type of the parameter is invalid.");
67 return false;
68 }
69 return true;
70 }
71
GetStringParam(const napi_env & env,const napi_value & value,std::string & dest)72 bool GetStringParam(const napi_env& env, const napi_value& value, std::string& dest)
73 {
74 constexpr int nameMaxSize = 1024;
75 char buf[nameMaxSize] = {0};
76 size_t len = 0;
77 napi_status status = napi_get_value_string_utf8(env, value, buf, nameMaxSize, &len);
78 if (status != napi_ok) {
79 HILOG_ERROR(LOG_CORE, "Failed to get string argument.");
80 return false;
81 }
82 dest = std::string {buf};
83 return true;
84 }
85
ParseStringParam(const napi_env & env,const napi_value & value,std::string & dest)86 bool ParseStringParam(const napi_env& env, const napi_value& value, std::string& dest)
87 {
88 if (TypeCheck(env, value, napi_string)) {
89 if (GetStringParam(env, value, dest)) {
90 return true;
91 }
92 } else if (TypeCheck(env, value, napi_undefined) || TypeCheck(env, value, napi_null)) {
93 dest = "";
94 return true;
95 }
96 return false;
97 }
98
ParseInt32Param(const napi_env & env,const napi_value & value,int & dest)99 bool ParseInt32Param(const napi_env& env, const napi_value& value, int& dest)
100 {
101 if (!TypeCheck(env, value, napi_number)) {
102 return false;
103 }
104 napi_status status = napi_get_value_int32(env, value, &dest);
105 if (status != napi_ok) {
106 HILOG_ERROR(LOG_CORE, "Failed to get int32 argument.");
107 return false;
108 }
109 return true;
110 }
111
ParseInt64Param(const napi_env & env,const napi_value & value,int64_t & dest)112 bool ParseInt64Param(const napi_env& env, const napi_value& value, int64_t& dest)
113 {
114 if (!TypeCheck(env, value, napi_number)) {
115 return false;
116 }
117 napi_status status = napi_get_value_int64(env, value, &dest);
118 if (status != napi_ok) {
119 HILOG_ERROR(LOG_CORE, "Failed to get int64 argument.");
120 return false;
121 }
122 return true;
123 }
124
JsStrNumParamsFunc(napi_env & env,napi_callback_info & info,STR_NUM_PARAM_FUNC nativeCall)125 bool JsStrNumParamsFunc(napi_env& env, napi_callback_info& info, STR_NUM_PARAM_FUNC nativeCall)
126 {
127 size_t argc = static_cast<size_t>(ARGC_TWO);
128 napi_value argv[ARGC_TWO];
129 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
130 if (status != napi_ok) {
131 HILOG_ERROR(LOG_CORE, "napi_get_cb_info failed.");
132 return false;
133 }
134 if (argc != ARGC_TWO) {
135 HILOG_ERROR(LOG_CORE, "Wrong number of parameters.");
136 return false;
137 }
138 std::string name;
139 if (!ParseStringParam(env, argv[ARG_FIRST], name)) {
140 return false;
141 }
142 if (!nativeCall(name, argv[ARG_SECOND])) {
143 return false;
144 }
145 return true;
146 }
147 }
148
JSTraceStart(napi_env env,napi_callback_info info)149 static napi_value JSTraceStart(napi_env env, napi_callback_info info)
150 {
151 size_t argc = ARGC_THREE;
152 napi_value argv[ARGC_THREE];
153 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
154 if (status != napi_ok) {
155 HILOG_ERROR(LOG_CORE, "napi_get_cb_info failed.");
156 return nullptr;
157 }
158 std::string name;
159 if (!ParseStringParam(env, argv[ARG_FIRST], name)) {
160 return nullptr;
161 }
162 int taskId = 0;
163 if (!ParseInt32Param(env, argv[ARG_SECOND], taskId)) {
164 return nullptr;
165 }
166 StartAsyncTraceEx(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_APP, name.c_str(), taskId, "", "");
167 return nullptr;
168 }
169
JSTraceFinish(napi_env env,napi_callback_info info)170 static napi_value JSTraceFinish(napi_env env, napi_callback_info info)
171 {
172 size_t argc = ARGC_TWO;
173 napi_value argv[ARGC_TWO];
174 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
175 if (status != napi_ok) {
176 HILOG_ERROR(LOG_CORE, "napi_get_cb_info failed.");
177 return nullptr;
178 }
179 (void)JsStrNumParamsFunc(env, info, [&env] (std::string name, napi_value& nValue) -> bool {
180 int taskId = 0;
181 if (!ParseInt32Param(env, nValue, taskId)) {
182 return false;
183 }
184 FinishAsyncTraceEx(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_APP, name.c_str(), taskId);
185 return true;
186 });
187 return nullptr;
188 }
189
JSCountTrace(napi_env env,napi_callback_info info)190 static napi_value JSCountTrace(napi_env env, napi_callback_info info)
191 {
192 size_t argc = ARGC_THREE;
193 napi_value argv[ARGC_THREE];
194 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
195 if (status != napi_ok) {
196 HILOG_ERROR(LOG_CORE, "napi_get_cb_info failed.");
197 return nullptr;
198 }
199 int32_t level;
200 if (!ParseInt32Param(env, argv[ARG_FIRST], level)) {
201 return nullptr;
202 }
203
204 std::string name;
205 if (!ParseStringParam(env, argv[ARG_SECOND], name)) {
206 return nullptr;
207 }
208
209 int64_t count;
210 if (!ParseInt64Param(env, argv[ARG_THIRD], count)) {
211 return nullptr;
212 }
213
214 CountTraceEx(static_cast<HiTraceOutputLevel>(level), HITRACE_TAG_APP, name.c_str(), count);
215 return nullptr;
216 }
217
JSTraceCount(napi_env env,napi_callback_info info)218 static napi_value JSTraceCount(napi_env env, napi_callback_info info)
219 {
220 size_t argc = ARGC_TWO;
221 napi_value argv[ARGC_TWO];
222 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
223 if (status != napi_ok) {
224 HILOG_ERROR(LOG_CORE, "napi_get_cb_info failed.");
225 return nullptr;
226 }
227 if (argc == ARGC_TWO) {
228 (void)JsStrNumParamsFunc(env, info, [&env] (std::string name, napi_value& nValue) -> bool {
229 int64_t count = 0;
230 if (!ParseInt64Param(env, nValue, count)) {
231 return false;
232 }
233 CountTraceEx(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_APP, name.c_str(), count);
234 return true;
235 });
236 } else {
237 JSCountTrace(env, info);
238 }
239 return nullptr;
240 }
241
JSStartSyncTrace(napi_env env,napi_callback_info info)242 static napi_value JSStartSyncTrace(napi_env env, napi_callback_info info)
243 {
244 size_t argc = ARGC_THREE;
245 napi_value argv[ARGC_THREE];
246 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
247 if (status != napi_ok) {
248 HILOG_ERROR(LOG_CORE, "napi_get_cb_info failed.");
249 return nullptr;
250 }
251 int32_t level;
252 if (!ParseInt32Param(env, argv[ARG_FIRST], level)) {
253 return nullptr;
254 }
255
256 std::string name;
257 if (!ParseStringParam(env, argv[ARG_SECOND], name)) {
258 return nullptr;
259 }
260
261 std::string customArgs;
262 if (!ParseStringParam(env, argv[ARG_THIRD], customArgs)) {
263 return nullptr;
264 }
265
266 StartTraceEx(static_cast<HiTraceOutputLevel>(level), HITRACE_TAG_APP, name.c_str(), customArgs.c_str());
267 return nullptr;
268 }
269
JSFinishSyncTrace(napi_env env,napi_callback_info info)270 static napi_value JSFinishSyncTrace(napi_env env, napi_callback_info info)
271 {
272 size_t argc = ARGC_THREE;
273 napi_value argv[ARGC_THREE];
274 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
275 if (status != napi_ok) {
276 HILOG_ERROR(LOG_CORE, "napi_get_cb_info failed.");
277 return nullptr;
278 }
279 int32_t level;
280 if (!ParseInt32Param(env, argv[ARG_FIRST], level)) {
281 return nullptr;
282 }
283
284 FinishTraceEx(static_cast<HiTraceOutputLevel>(level), HITRACE_TAG_APP);
285 return nullptr;
286 }
287
JSStartAsyncTrace(napi_env env,napi_callback_info info)288 static napi_value JSStartAsyncTrace(napi_env env, napi_callback_info info)
289 {
290 size_t argc = ARGC_FIVE;
291 napi_value argv[ARGC_FIVE];
292 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
293 if (status != napi_ok) {
294 HILOG_ERROR(LOG_CORE, "napi_get_cb_info failed.");
295 return nullptr;
296 }
297 int32_t level;
298 if (!ParseInt32Param(env, argv[ARG_FIRST], level)) {
299 return nullptr;
300 }
301
302 std::string name;
303 if (!ParseStringParam(env, argv[ARG_SECOND], name)) {
304 return nullptr;
305 }
306
307 int32_t taskId;
308 if (!ParseInt32Param(env, argv[ARG_THIRD], taskId)) {
309 return nullptr;
310 }
311
312 std::string customCategory;
313 if (!ParseStringParam(env, argv[ARG_FOURTH], customCategory)) {
314 return nullptr;
315 }
316
317 std::string customArgs;
318 if (!ParseStringParam(env, argv[ARG_FIFTH], customArgs)) {
319 return nullptr;
320 }
321
322 StartAsyncTraceEx(static_cast<HiTraceOutputLevel>(level), HITRACE_TAG_APP, name.c_str(),
323 taskId, customCategory.c_str(), customArgs.c_str());
324 return nullptr;
325 }
326
JSFinishAsyncTrace(napi_env env,napi_callback_info info)327 static napi_value JSFinishAsyncTrace(napi_env env, napi_callback_info info)
328 {
329 size_t argc = ARGC_THREE;
330 napi_value argv[ARGC_THREE];
331 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
332 if (status != napi_ok) {
333 HILOG_ERROR(LOG_CORE, "napi_get_cb_info failed.");
334 return nullptr;
335 }
336 int32_t level;
337 if (!ParseInt32Param(env, argv[ARG_FIRST], level)) {
338 return nullptr;
339 }
340
341 std::string name;
342 if (!ParseStringParam(env, argv[ARG_SECOND], name)) {
343 return nullptr;
344 }
345
346 int32_t taskId;
347 if (!ParseInt32Param(env, argv[ARG_THIRD], taskId)) {
348 return nullptr;
349 }
350
351 FinishAsyncTraceEx(static_cast<HiTraceOutputLevel>(level), HITRACE_TAG_APP, name.c_str(), taskId);
352 return nullptr;
353 }
354
JSIsTraceEnabled(napi_env env,napi_callback_info info)355 static napi_value JSIsTraceEnabled(napi_env env, napi_callback_info info)
356 {
357 bool isTagEnable = IsTagEnabled(HITRACE_TAG_APP);
358 napi_value val = nullptr;
359 napi_get_boolean(env, isTagEnable, &val);
360 return val;
361 }
362
TraceLevelConstructor(napi_env env,napi_callback_info info)363 static napi_value TraceLevelConstructor(napi_env env, napi_callback_info info)
364 {
365 napi_value thisArg = nullptr;
366 napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr);
367 if (status != napi_ok) {
368 HILOG_ERROR(LOG_CORE, "napi_get_cb_info failed.");
369 return nullptr;
370 }
371 napi_get_global(env, nullptr);
372 return thisArg;
373 }
374
InitTraceLevelEnum(napi_env env,napi_value exports)375 static void InitTraceLevelEnum(napi_env env, napi_value exports)
376 {
377 napi_value debug = nullptr;
378 napi_value info = nullptr;
379 napi_value critical = nullptr;
380 napi_value commercial = nullptr;
381
382 napi_create_int32(env, HITRACE_LEVEL_DEBUG, &debug);
383 napi_create_int32(env, HITRACE_LEVEL_INFO, &info);
384 napi_create_int32(env, HITRACE_LEVEL_CRITICAL, &critical);
385 napi_create_int32(env, HITRACE_LEVEL_COMMERCIAL, &commercial);
386
387 napi_property_descriptor descriptors[] = {
388 DECLARE_NAPI_STATIC_PROPERTY("DEBUG", debug),
389 DECLARE_NAPI_STATIC_PROPERTY("INFO", info),
390 DECLARE_NAPI_STATIC_PROPERTY("CRITICAL", critical),
391 DECLARE_NAPI_STATIC_PROPERTY("COMMERCIAL", commercial),
392 DECLARE_NAPI_STATIC_PROPERTY("MAX", commercial),
393 };
394
395 napi_value result = nullptr;
396 napi_define_class(env, HITRACE_OUTPUT_LEVEL, NAPI_AUTO_LENGTH, TraceLevelConstructor,
397 nullptr, sizeof(descriptors) / sizeof(*descriptors), descriptors, &result);
398 napi_set_named_property(env, exports, HITRACE_OUTPUT_LEVEL, result);
399 }
400
401 /*
402 * function for module exports
403 */
404 EXTERN_C_START
HiTraceMeterInit(napi_env env,napi_value exports)405 static napi_value HiTraceMeterInit(napi_env env, napi_value exports)
406 {
407 napi_property_descriptor desc[] = {
408 DECLARE_NAPI_FUNCTION("startTrace", JSTraceStart),
409 DECLARE_NAPI_FUNCTION("finishTrace", JSTraceFinish),
410 DECLARE_NAPI_FUNCTION("traceByValue", JSTraceCount),
411 DECLARE_NAPI_FUNCTION("startSyncTrace", JSStartSyncTrace),
412 DECLARE_NAPI_FUNCTION("finishSyncTrace", JSFinishSyncTrace),
413 DECLARE_NAPI_FUNCTION("startAsyncTrace", JSStartAsyncTrace),
414 DECLARE_NAPI_FUNCTION("finishAsyncTrace", JSFinishAsyncTrace),
415 DECLARE_NAPI_FUNCTION("isTraceEnabled", JSIsTraceEnabled),
416 };
417 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
418 InitTraceLevelEnum(env, exports);
419 return exports;
420 }
421 EXTERN_C_END
422
423 /*
424 * hiTraceMeter module definition
425 */
426 static napi_module hitracemeter_module = {
427 .nm_version = 1,
428 .nm_flags = 0,
429 .nm_filename = nullptr,
430 .nm_register_func = HiTraceMeterInit,
431 .nm_modname = "hiTraceMeter",
432 .nm_priv = ((void *)0),
433 .reserved = {0}
434 };
435
436 /*
437 * Module registration
438 */
RegisterModule(void)439 extern "C" __attribute__((constructor)) void RegisterModule(void)
440 {
441 napi_module_register(&hitracemeter_module);
442 }
443