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 <cstdio>
17 #include <functional>
18 #include <string>
19 #include <hilog/log.h>
20 #include "hitrace_meter.h"
21 #include "bytrace_napi_common.h"
22
23 using namespace OHOS::HiviewDFX;
24 namespace {
25 constexpr int FIRST_ARGC_INDEX = 0;
26 constexpr int SECOND_ARGC_INDEX = 1;
27 constexpr int THIRD_ARGC_INDEX = 2;
28 constexpr int ARGC_NUMBER_TWICE = 2;
29 constexpr int ARGC_NUMBER_TRIPLE = 3;
30 constexpr uint64_t HITRACE_METER_LABEL = 0xD002D33;
31 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HITRACE_METER_LABEL, "HITRACE_METER_JS"};
32 using STR_NUM_PARAM_FUNC = std::function<bool(std::string, napi_value&)>;
33
ParseParams(napi_env & env,napi_callback_info & info,size_t & argc,napi_value * argv)34 napi_value ParseParams(napi_env& env, napi_callback_info& info, size_t& argc, napi_value* argv)
35 {
36 napi_value thisVar;
37 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
38 return nullptr;
39 }
40
TypeCheck(const napi_env & env,const napi_value & value,const napi_valuetype expectType)41 bool TypeCheck(const napi_env& env, const napi_value& value, const napi_valuetype expectType)
42 {
43 napi_valuetype valueType;
44 napi_status status = napi_typeof(env, value, &valueType);
45 if (status != napi_ok) {
46 HiLog::Error(LABEL, "Failed to get the type of the argument");
47 return false;
48 }
49 if (valueType != expectType) {
50 HiLog::Error(LABEL, "Type of the parameter is invalid");
51 return false;
52 }
53 return true;
54 }
55
GetStringParam(const napi_env & env,const napi_value & value,std::string & dest)56 void GetStringParam(const napi_env& env, const napi_value& value, std::string& dest)
57 {
58 // parsing the value of string type into dest
59 constexpr int maxNameSize = 1024;
60 char buf[maxNameSize] = {0};
61 size_t len = 0;
62 napi_get_value_string_utf8(env, value, buf, maxNameSize, &len);
63 dest = std::string {buf};
64 }
65
ParseStringParam(const napi_env & env,const napi_value & value,std::string & dest)66 bool ParseStringParam(const napi_env& env, const napi_value& value, std::string& dest)
67 {
68 // if it is not a string, convert the corresponding type to a string
69 if (TypeCheck(env, value, napi_string)) {
70 GetStringParam(env, value, dest);
71 return true;
72 }
73 if (TypeCheck(env, value, napi_number)) {
74 int64_t destI64;
75 napi_get_value_int64(env, value, &destI64);
76 dest = std::to_string(destI64);
77 return true;
78 }
79 // if it's napi_null, then handle it as 'null'
80 if (TypeCheck(env, value, napi_null)) {
81 dest = "null";
82 return true;
83 }
84 if (TypeCheck(env, value, napi_undefined)) {
85 dest = "undefined";
86 return true;
87 }
88 return false;
89 }
90
ParseInt32Param(const napi_env & env,const napi_value & value,int & dest)91 bool ParseInt32Param(const napi_env& env, const napi_value& value, int& dest)
92 {
93 if (!TypeCheck(env, value, napi_number)) {
94 return false;
95 }
96 napi_get_value_int32(env, value, &dest);
97 return true;
98 }
99
ParseInt64Param(const napi_env & env,const napi_value & value,int64_t & dest)100 bool ParseInt64Param(const napi_env& env, const napi_value& value, int64_t& dest)
101 {
102 if (!TypeCheck(env, value, napi_number)) {
103 return false;
104 }
105 napi_get_value_int64(env, value, &dest);
106 return true;
107 }
108
ParseDoubleParam(const napi_env & env,const napi_value & value,double & dest)109 bool ParseDoubleParam(const napi_env& env, const napi_value& value, double& dest)
110 {
111 if (!TypeCheck(env, value, napi_number)) {
112 return false;
113 }
114 napi_get_value_double(env, value, &dest);
115 return true;
116 }
117
ParseUndefinedParam(const napi_env & env,const napi_value & value)118 bool ParseUndefinedParam(const napi_env& env, const napi_value& value)
119 {
120 return TypeCheck(env, value, napi_undefined);
121 }
122
ParseNullParam(const napi_env & env,const napi_value & value)123 bool ParseNullParam(const napi_env& env, const napi_value& value)
124 {
125 return TypeCheck(env, value, napi_null);
126 }
127
JsStrNumParamsFunc(napi_env & env,napi_callback_info & info,STR_NUM_PARAM_FUNC nativeCall)128 bool JsStrNumParamsFunc(napi_env& env, napi_callback_info& info, STR_NUM_PARAM_FUNC nativeCall)
129 {
130 size_t argc = ARGC_NUMBER_TWICE;
131 napi_value argv[ARGC_NUMBER_TWICE];
132 ParseParams(env, info, argc, argv);
133 if (argc != ARGC_NUMBER_TWICE) {
134 HiLog::Error(LABEL, "Wrong number of parameters.");
135 return false;
136 }
137 std::string name;
138 if (!ParseStringParam(env, argv[FIRST_ARGC_INDEX], name)) {
139 return false;
140 }
141 if (!nativeCall(name, argv[SECOND_ARGC_INDEX])) {
142 return false;
143 }
144 return true;
145 }
146 }
147
JSTraceStart(napi_env env,napi_callback_info info)148 static napi_value JSTraceStart(napi_env env, napi_callback_info info)
149 {
150 size_t argc = ARGC_NUMBER_TRIPLE;
151 napi_value argv[ARGC_NUMBER_TRIPLE];
152 ParseParams(env, info, argc, argv);
153 NAPI_ASSERT(env, argc >= ARGC_NUMBER_TWICE, "Wrong number of arguments");
154 if (argc < ARGC_NUMBER_TWICE) {
155 HiLog::Error(LABEL, "Wrong number of parameters.");
156 }
157 std::string name;
158 if (!ParseStringParam(env, argv[FIRST_ARGC_INDEX], name)) {
159 return nullptr;
160 }
161 int taskId = 0;
162 if (!ParseInt32Param(env, argv[SECOND_ARGC_INDEX], taskId)) {
163 return nullptr;
164 }
165 if (argc == ARGC_NUMBER_TWICE) {
166 StartAsyncTrace(HITRACE_TAG_APP, name, taskId);
167 } else {
168 double limit = 0.0;
169 if (!ParseDoubleParam(env, argv[THIRD_ARGC_INDEX], limit) &&
170 !ParseUndefinedParam(env, argv[THIRD_ARGC_INDEX]) && !ParseNullParam(env, argv[THIRD_ARGC_INDEX])) {
171 HiLog::Error(LABEL, "the third param is not number, not undefined, not null.");
172 return nullptr;
173 }
174 StartAsyncTrace(HITRACE_TAG_APP, name, taskId, limit);
175 }
176 return nullptr;
177 }
178
JSTraceFinish(napi_env env,napi_callback_info info)179 static napi_value JSTraceFinish(napi_env env, napi_callback_info info)
180 {
181 size_t argc = ARGC_NUMBER_TWICE;
182 napi_value argv[ARGC_NUMBER_TWICE];
183 napi_value thisVar;
184 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
185 NAPI_ASSERT(env, argc >= ARGC_NUMBER_TWICE, "Wrong number of arguments");
186 (void)JsStrNumParamsFunc(env, info, [&env] (std::string name, const napi_value& nValue) -> bool {
187 int taskId = 0;
188 if (!ParseInt32Param(env, nValue, taskId)) {
189 return false;
190 }
191 FinishAsyncTrace(HITRACE_TAG_APP, name, taskId);
192 return true;
193 });
194 return nullptr;
195 }
196
JSTraceCount(napi_env env,napi_callback_info info)197 static napi_value JSTraceCount(napi_env env, napi_callback_info info)
198 {
199 size_t argc = ARGC_NUMBER_TWICE;
200 napi_value argv[ARGC_NUMBER_TWICE];
201 napi_value thisVar;
202 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
203 NAPI_ASSERT(env, argc == ARGC_NUMBER_TWICE, "Wrong number of arguments");
204 (void)JsStrNumParamsFunc(env, info, [&env] (std::string name, const napi_value& nValue) -> bool {
205 int64_t count = 0;
206 if (!ParseInt64Param(env, nValue, count)) {
207 return false;
208 }
209 CountTrace(HITRACE_TAG_APP, name, count);
210 return true;
211 });
212 return nullptr;
213 }
214
215 /*
216 * function for module exports
217 */
218 EXTERN_C_START
BytraceInit(napi_env env,napi_value exports)219 static napi_value BytraceInit(napi_env env, napi_value exports)
220 {
221 static napi_property_descriptor desc[] = {
222 DECLARE_NAPI_FUNCTION("startTrace", JSTraceStart),
223 DECLARE_NAPI_FUNCTION("finishTrace", JSTraceFinish),
224 DECLARE_NAPI_FUNCTION("traceByValue", JSTraceCount),
225 };
226 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
227 return exports;
228 }
229 EXTERN_C_END
230
231 /*
232 * bytrace module definition
233 */
234 static napi_module bytrace_module = {
235 .nm_version = 1,
236 .nm_flags = 0,
237 .nm_filename = "bytrace",
238 .nm_register_func = BytraceInit,
239 .nm_modname = "bytrace",
240 .nm_priv = ((void *)0),
241 .reserved = {0}
242 };
243
244 /*
245 * Module registration
246 */
RegisterModule(void)247 extern "C" __attribute__((constructor)) void RegisterModule(void)
248 {
249 napi_module_register(&bytrace_module);
250 }
251