• 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 <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