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 "napi_hitrace_meter.h"
24
25 using namespace OHOS::HiviewDFX;
26 namespace {
27 constexpr int FIRST_ARG_INDEX = 0;
28 constexpr int SECOND_ARG_INDEX = 1;
29 constexpr int ARGC_NUMBER_TWO = 2;
30 constexpr int ARGC_NUMBER_THREE = 3;
31
32 #ifdef LOG_DOMAIN
33 #undef LOG_DOMAIN
34 #define LOG_DOMAIN 0xD002D33
35 #endif
36 #ifdef LOG_TAG
37 #undef LOG_TAG
38 #define LOG_TAG "HitraceMeterNapi"
39 #endif
40
41 using STR_NUM_PARAM_FUNC = std::function<bool(std::string, napi_value&)>;
42 std::unordered_map<std::string, uint64_t> g_tagsMap = {
43 {"ohos", HITRACE_TAG_OHOS}, {"ability", HITRACE_TAG_ABILITY_MANAGER}, {"camera", HITRACE_TAG_ZCAMERA},
44 {"media", HITRACE_TAG_ZMEDIA}, {"image", HITRACE_TAG_ZIMAGE}, {"audio", HITRACE_TAG_ZAUDIO},
45 {"distributeddatamgr", HITRACE_TAG_DISTRIBUTEDDATA}, {"graphic", HITRACE_TAG_GRAPHIC_AGP},
46 {"ace", HITRACE_TAG_ACE}, {"notification", HITRACE_TAG_NOTIFICATION}, {"misc", HITRACE_TAG_MISC},
47 {"multimodalinput", HITRACE_TAG_MULTIMODALINPUT}, {"rpc", HITRACE_TAG_RPC}, {"ark", HITRACE_TAG_ARK},
48 {"window", HITRACE_TAG_WINDOW_MANAGER}, {"dscreen", HITRACE_TAG_DISTRIBUTED_SCREEN},
49 {"dcamera", HITRACE_TAG_DISTRIBUTED_CAMERA}, {"dhfwk", HITRACE_TAG_DISTRIBUTED_HARDWARE_FWK},
50 {"gresource", HITRACE_TAG_GLOBAL_RESMGR}, {"devicemanager", HITRACE_TAG_DEVICE_MANAGER},
51 {"samgr", HITRACE_TAG_SAMGR}, {"power", HITRACE_TAG_POWER}, {"dsched", HITRACE_TAG_DISTRIBUTED_SCHEDULE},
52 {"dinput", HITRACE_TAG_DISTRIBUTED_INPUT}, {"bluetooth", HITRACE_TAG_BLUETOOTH}, {"ffrt", HITRACE_TAG_FFRT},
53 {"commonlibrary", HITRACE_TAG_COMMONLIBRARY}, {"hdf", HITRACE_TAG_HDF}, {"net", HITRACE_TAG_NET},
54 {"nweb", HITRACE_TAG_NWEB}, {"daudio", HITRACE_TAG_DISTRIBUTED_AUDIO},
55 {"filemanagement", HITRACE_TAG_FILEMANAGEMENT}, {"app", HITRACE_TAG_APP}
56 };
57
ParseParams(napi_env & env,napi_callback_info & info,size_t & argc,napi_value * argv)58 napi_value ParseParams(napi_env& env, napi_callback_info& info, size_t& argc, napi_value* argv)
59 {
60 napi_value thisVar;
61 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
62 return nullptr;
63 }
64
TypeCheck(const napi_env & env,const napi_value & value,const napi_valuetype expectType)65 bool TypeCheck(const napi_env& env, const napi_value& value, const napi_valuetype expectType)
66 {
67 napi_valuetype valueType;
68 napi_status status = napi_typeof(env, value, &valueType);
69 if (status != napi_ok) {
70 HILOG_ERROR(LOG_CORE, "Failed to get the type of the argument.");
71 return false;
72 }
73 if (valueType != expectType) {
74 HILOG_DEBUG(LOG_CORE, "Type of the parameter is invalid.");
75 return false;
76 }
77 return true;
78 }
79
GetStringParam(const napi_env & env,const napi_value & value,std::string & dest)80 void GetStringParam(const napi_env& env, const napi_value& value, std::string& dest)
81 {
82 constexpr int nameMaxSize = 1024;
83 char buf[nameMaxSize] = {0};
84 size_t len = 0;
85 napi_get_value_string_utf8(env, value, buf, nameMaxSize, &len);
86 dest = std::string {buf};
87 }
88
ParseStringParam(const napi_env & env,const napi_value & value,std::string & dest)89 bool ParseStringParam(const napi_env& env, const napi_value& value, std::string& dest)
90 {
91 if (TypeCheck(env, value, napi_string)) {
92 GetStringParam(env, value, dest);
93 return true;
94 }
95 if (TypeCheck(env, value, napi_number)) {
96 int64_t destI64;
97 napi_get_value_int64(env, value, &destI64);
98 dest = std::to_string(destI64);
99 return true;
100 }
101 if (TypeCheck(env, value, napi_undefined)) {
102 dest = "undefined";
103 return true;
104 }
105 if (TypeCheck(env, value, napi_null)) {
106 dest = "null";
107 return true;
108 }
109 return false;
110 }
111
ParseInt32Param(const napi_env & env,const napi_value & value,int & dest)112 bool ParseInt32Param(const napi_env& env, const napi_value& value, int& dest)
113 {
114 if (!TypeCheck(env, value, napi_number)) {
115 return false;
116 }
117 napi_get_value_int32(env, value, &dest);
118 return true;
119 }
120
ParseInt64Param(const napi_env & env,const napi_value & value,int64_t & dest)121 bool ParseInt64Param(const napi_env& env, const napi_value& value, int64_t& dest)
122 {
123 if (!TypeCheck(env, value, napi_number)) {
124 return false;
125 }
126 napi_get_value_int64(env, value, &dest);
127 return true;
128 }
129
SetTagsParam(const napi_env & env,const napi_value & value,uint64_t & tags)130 void SetTagsParam(const napi_env& env, const napi_value& value, uint64_t& tags)
131 {
132 uint32_t arrayLength;
133 napi_status status = napi_get_array_length(env, value, &arrayLength);
134 if (status != napi_ok) {
135 HILOG_ERROR(LOG_CORE, "Failed to get the length of the array.");
136 return;
137 }
138
139 for (uint32_t i = 0; i < arrayLength; i++) {
140 napi_value tag;
141 status = napi_get_element(env, value, i, &tag);
142 if (status != napi_ok) {
143 HILOG_ERROR(LOG_CORE, "Failed to get element.");
144 return;
145 }
146
147 if (!TypeCheck(env, tag, napi_string)) {
148 HILOG_ERROR(LOG_CORE, "tag is invalid, not a napi_string");
149 return;
150 }
151
152 std::string tagStr = "";
153 GetStringParam(env, tag, tagStr);
154 if (g_tagsMap.count(tagStr) > 0) {
155 tags |= g_tagsMap[tagStr];
156 }
157 }
158 }
159
ParseTagsParam(const napi_env & env,const napi_value & value,uint64_t & tags)160 bool ParseTagsParam(const napi_env& env, const napi_value& value, uint64_t& tags)
161 {
162 bool isArray = false;
163 napi_status status = napi_is_array(env, value, &isArray);
164 if (status != napi_ok) {
165 HILOG_ERROR(LOG_CORE, "Failed to get array type.");
166 return false;
167 }
168
169 if (isArray) {
170 SetTagsParam(env, value, tags);
171 return true;
172 } else {
173 HILOG_ERROR(LOG_CORE, "The argument isn't an array type.");
174 return false;
175 }
176 }
177
JsStrNumParamsFunc(napi_env & env,napi_callback_info & info,STR_NUM_PARAM_FUNC nativeCall)178 bool JsStrNumParamsFunc(napi_env& env, napi_callback_info& info, STR_NUM_PARAM_FUNC nativeCall)
179 {
180 size_t argc = static_cast<size_t>(ARGC_NUMBER_TWO);
181 napi_value argv[ARGC_NUMBER_TWO];
182 ParseParams(env, info, argc, argv);
183 if (argc != ARGC_NUMBER_TWO) {
184 HILOG_ERROR(LOG_CORE, "Wrong number of parameters.");
185 return false;
186 }
187 std::string name;
188 if (!ParseStringParam(env, argv[FIRST_ARG_INDEX], name)) {
189 return false;
190 }
191 if (!nativeCall(name, argv[SECOND_ARG_INDEX])) {
192 return false;
193 }
194 return true;
195 }
196 }
197
JSTraceStart(napi_env env,napi_callback_info info)198 static napi_value JSTraceStart(napi_env env, napi_callback_info info)
199 {
200 size_t argc = ARGC_NUMBER_THREE;
201 napi_value argv[ARGC_NUMBER_THREE];
202 ParseParams(env, info, argc, argv);
203 NAPI_ASSERT(env, argc >= ARGC_NUMBER_TWO, "Wrong number of arguments");
204 std::string name;
205 if (!ParseStringParam(env, argv[FIRST_ARG_INDEX], name)) {
206 return nullptr;
207 }
208 if (name == "null" || name == "undefined") {
209 return nullptr;
210 }
211 int taskId = 0;
212 if (!ParseInt32Param(env, argv[SECOND_ARG_INDEX], taskId)) {
213 return nullptr;
214 }
215 StartAsyncTrace(HITRACE_TAG_APP, name, taskId);
216 return nullptr;
217 }
218
JSTraceFinish(napi_env env,napi_callback_info info)219 static napi_value JSTraceFinish(napi_env env, napi_callback_info info)
220 {
221 size_t argc = ARGC_NUMBER_TWO;
222 napi_value argv[ARGC_NUMBER_TWO];
223 napi_value thisVar;
224 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
225 NAPI_ASSERT(env, argc == ARGC_NUMBER_TWO, "Wrong number of arguments");
226 (void)JsStrNumParamsFunc(env, info, [&env] (std::string name, napi_value& nValue) -> bool {
227 if (name == "null" || name == "undefined") {
228 return false;
229 }
230 int taskId = 0;
231 if (!ParseInt32Param(env, nValue, taskId)) {
232 return false;
233 }
234 FinishAsyncTrace(HITRACE_TAG_APP, name, taskId);
235 return true;
236 });
237 return nullptr;
238 }
239
JSTraceCount(napi_env env,napi_callback_info info)240 static napi_value JSTraceCount(napi_env env, napi_callback_info info)
241 {
242 size_t argc = ARGC_NUMBER_TWO;
243 napi_value argv[ARGC_NUMBER_TWO];
244 napi_value thisVar;
245 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
246 NAPI_ASSERT(env, argc == ARGC_NUMBER_TWO, "Wrong number of arguments");
247 (void)JsStrNumParamsFunc(env, info, [&env] (std::string name, napi_value& nValue) -> bool {
248 if (name == "null" || name == "undefined") {
249 return false;
250 }
251 int64_t count = 0;
252 if (!ParseInt64Param(env, nValue, count)) {
253 return false;
254 }
255 CountTrace(HITRACE_TAG_APP, name, count);
256 return true;
257 });
258 return nullptr;
259 }
260
JSStartCaptureAppTrace(napi_env env,napi_callback_info info)261 static napi_value JSStartCaptureAppTrace(napi_env env, napi_callback_info info)
262 {
263 size_t argc = ARGC_NUMBER_THREE;
264 napi_value argv[ARGC_NUMBER_THREE];
265 ParseParams(env, info, argc, argv);
266 NAPI_ASSERT(env, argc >= ARGC_NUMBER_THREE, "Wrong number of arguments");
267
268 uint64_t tags = HITRACE_TAG_APP;
269 if (!ParseTagsParam(env, argv[FIRST_ARG_INDEX], tags)) {
270 return nullptr;
271 }
272
273 int64_t flag = 0;
274 if (!ParseInt64Param(env, argv[SECOND_ARG_INDEX], flag)) {
275 return nullptr;
276 }
277
278 int64_t limitSize = 0;
279 if (!ParseInt64Param(env, argv[ARGC_NUMBER_TWO], limitSize)) {
280 return nullptr;
281 }
282
283 std::string file = "";
284 if (StartCaptureAppTrace((TraceFlag)flag, tags, limitSize, file) != RET_SUCC) {
285 HILOG_ERROR(LOG_CORE, "StartCaptureAppTrace failed");
286 return nullptr;
287 }
288
289 napi_value napiFile;
290 napi_status status = napi_create_string_utf8(env, file.c_str(), file.length(), &napiFile);
291 if (status != napi_ok) {
292 HILOG_ERROR(LOG_CORE, "create napi string failed: %{public}d(%{public}s)", errno, strerror(errno));
293 return nullptr;
294 }
295
296 return napiFile;
297 }
298
JSStopCaptureAppTrace(napi_env env,napi_callback_info info)299 static napi_value JSStopCaptureAppTrace(napi_env env, napi_callback_info info)
300 {
301 StopCaptureAppTrace();
302 return nullptr;
303 }
304
305 /*
306 * function for module exports
307 */
308 EXTERN_C_START
HiTraceMeterInit(napi_env env,napi_value exports)309 static napi_value HiTraceMeterInit(napi_env env, napi_value exports)
310 {
311 napi_property_descriptor desc[] = {
312 DECLARE_NAPI_FUNCTION("startTrace", JSTraceStart),
313 DECLARE_NAPI_FUNCTION("finishTrace", JSTraceFinish),
314 DECLARE_NAPI_FUNCTION("traceByValue", JSTraceCount),
315 DECLARE_NAPI_FUNCTION("startCaptureAppTrace", JSStartCaptureAppTrace),
316 DECLARE_NAPI_FUNCTION("stopCaptureAppTrace", JSStopCaptureAppTrace),
317 };
318 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
319 return exports;
320 }
321 EXTERN_C_END
322
323 /*
324 * hiTraceMeter module definition
325 */
326 static napi_module hitracemeter_module = {
327 .nm_version = 1,
328 .nm_flags = 0,
329 .nm_filename = nullptr,
330 .nm_register_func = HiTraceMeterInit,
331 .nm_modname = "hiTraceMeter",
332 .nm_priv = ((void *)0),
333 .reserved = {0}
334 };
335
336 /*
337 * Module registration
338 */
RegisterModule(void)339 extern "C" __attribute__((constructor)) void RegisterModule(void)
340 {
341 napi_module_register(&hitracemeter_module);
342 }
343