1 /*
2 * Copyright (C) 2021-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 #include "napi_faultlogger.h"
16
17 #include <cinttypes>
18 #include <sstream>
19 #include <unistd.h>
20
21 #include "napi/native_api.h"
22 #include "napi/native_node_api.h"
23
24 #include "hiview_logger.h"
25
26 #include "faultlog_query_result.h"
27 #include "napi_error.h"
28 #include "napi_util.h"
29
30 namespace OHOS {
31 namespace HiviewDFX {
32 DEFINE_LOG_LABEL(0xD002D11, "Faultlogger-napi");
33 namespace {
34 constexpr size_t ONE_PARAMETER = 1;
35 constexpr size_t TWO_PARAMETER = 2;
36 constexpr size_t THREE_PARAMETER = 3;
37 constexpr size_t FOUR_PARAMETER = 4;
38 constexpr uint32_t BUF_SIZE_64 = 64;
39 constexpr uint32_t BUF_SIZE_512 = 512;
40 std::mutex g_mutex;
41 }
ConversionInform(std::unique_ptr<FaultLogInfo> faultLogInfo)42 static FaultLogNapiInfo ConversionInform(std::unique_ptr<FaultLogInfo> faultLogInfo)
43 {
44 FaultLogNapiInfo ret = {
45 .pid = faultLogInfo->GetProcessId(),
46 .uid = faultLogInfo->GetId(),
47 .type = faultLogInfo->GetFaultType(),
48 .ts = faultLogInfo->GetTimeStamp(),
49 .reason = faultLogInfo->GetFaultReason(),
50 .module = faultLogInfo->GetModuleName(),
51 .summary = faultLogInfo->GetFaultSummary(),
52 };
53 int fd = faultLogInfo->GetRawFileDescriptor();
54 if (fd < 0) {
55 HIVIEW_LOGE("pid %{public}d Fail to get fd:%{public}d\n", faultLogInfo->GetProcessId(), fd);
56 ret.fullLog = "Fail to get log, fd is " + std::to_string(fd);
57 return ret;
58 }
59 while (true) {
60 char buf[BUF_SIZE_512] = {0};
61 int nread = TEMP_FAILURE_RETRY(read((fd), buf, BUF_SIZE_512 - 1));
62 if (nread == -1) {
63 if (errno == EAGAIN) {
64 continue;
65 } else {
66 break;
67 }
68 } else if (nread == 0) {
69 break;
70 }
71 ret.fullLog += buf;
72 }
73
74 return ret;
75 }
76
FaultLogExecuteCallback(napi_env env,void * data)77 static void FaultLogExecuteCallback(napi_env env, void *data)
78 {
79 std::lock_guard<std::mutex> lock(g_mutex);
80 FaultLogInfoContext* faultLogInfoContext = static_cast<FaultLogInfoContext *>(data);
81 const int maxQueryCount = 10;
82 int currentCount = 0;
83 auto faultLogResult = QuerySelfFaultLog((FaultLogType)faultLogInfoContext->faultType,
84 maxQueryCount);
85 if (faultLogResult == nullptr) {
86 faultLogInfoContext->resolved = true;
87 return;
88 }
89
90 while (faultLogResult->HasNext()) {
91 if (currentCount >= maxQueryCount) {
92 break;
93 }
94 auto faultLogInfo = faultLogResult->Next();
95 if (faultLogInfo == nullptr) {
96 break;
97 }
98 currentCount++;
99 faultLogInfoContext->infoVector.push_back(ConversionInform(std::move(faultLogInfo)));
100 }
101 faultLogInfoContext->resolved = true;
102 }
103
FaultLogCompleteCallback(napi_env env,napi_status status,void * data)104 static void FaultLogCompleteCallback(napi_env env, napi_status status, void *data)
105 {
106 FaultLogInfoContext* faultLogInfoContext = static_cast<FaultLogInfoContext *>(data);
107 if (faultLogInfoContext == nullptr) {
108 return;
109 }
110 napi_value callbackValue = nullptr;
111 if (faultLogInfoContext->resolved) {
112 napi_create_array(env, &callbackValue);
113 int i = 0;
114 for (auto& infoItem : faultLogInfoContext->infoVector) {
115 napi_value info = nullptr;
116 napi_create_object(env, &info);
117 NapiUtil::SetPropertyInt32(env, info, "pid", infoItem.pid);
118 NapiUtil::SetPropertyInt32(env, info, "uid", infoItem.uid);
119 NapiUtil::SetPropertyInt32(env, info, "type", infoItem.type);
120 NapiUtil::SetPropertyInt64(env, info, "timestamp", infoItem.ts);
121 NapiUtil::SetPropertyStringUtf8(env, info, "reason", infoItem.reason);
122 NapiUtil::SetPropertyStringUtf8(env, info, "module", infoItem.module);
123 NapiUtil::SetPropertyStringUtf8(env, info, "summary", infoItem.summary);
124 NapiUtil::SetPropertyStringUtf8(env, info, "fullLog", infoItem.fullLog);
125 napi_set_element(env, callbackValue, i, info);
126 ++i;
127 HIVIEW_LOGI("add element when resovled pid = %{public}d, uid = %{public}d, ts = %{public}" PRId64,
128 infoItem.pid, infoItem.uid, infoItem.ts);
129 }
130 } else {
131 callbackValue = NapiUtil::CreateErrorMessage(env, "get signal info list failed");
132 }
133
134 if (faultLogInfoContext->callbackRef != nullptr) {
135 napi_value callbackFunc = nullptr;
136 napi_get_reference_value(env, faultLogInfoContext->callbackRef, &callbackFunc);
137 napi_value callbackValues[] = {nullptr, nullptr};
138 callbackValues[0] = faultLogInfoContext->resolved ? NapiUtil::CreateUndefined(env) : callbackValue;
139 callbackValues[1] = faultLogInfoContext->resolved ? callbackValue : NapiUtil::CreateUndefined(env);
140 napi_value recv = NapiUtil::CreateUndefined(env);
141 napi_value result = nullptr;
142 napi_call_function(env, recv, callbackFunc, std::size(callbackValues), callbackValues, &result);
143 napi_delete_reference(env, faultLogInfoContext->callbackRef);
144 } else if (faultLogInfoContext->deferred != nullptr) {
145 if (faultLogInfoContext->resolved) {
146 napi_resolve_deferred(env, faultLogInfoContext->deferred, callbackValue);
147 } else {
148 napi_reject_deferred(env, faultLogInfoContext->deferred, callbackValue);
149 }
150 }
151
152 napi_delete_async_work(env, faultLogInfoContext->work);
153 delete faultLogInfoContext;
154 }
155
QuerySelfFaultLog(napi_env env,napi_callback_info info)156 static napi_value QuerySelfFaultLog(napi_env env, napi_callback_info info)
157 {
158 size_t parameterCount = 2;
159 napi_value parameters[2] = {0};
160 napi_value thisVar = nullptr;
161 void *data = nullptr;
162 NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data));
163
164 napi_value result = NapiUtil::CreateUndefined(env);
165 if (parameterCount < ONE_PARAMETER || parameterCount > TWO_PARAMETER) {
166 HIVIEW_LOGE("parameterCount Incorrect %{public}zu", parameterCount);
167 return result;
168 }
169
170 if (!NapiUtil::IsMatchType(env, parameters[ONE_PARAMETER - 1], napi_number)) {
171 HIVIEW_LOGE("parameters[0] type isn't number");
172 return result;
173 }
174
175 auto faultLogInfoContext = std::make_unique<FaultLogInfoContext>().release();
176 if (faultLogInfoContext == nullptr) {
177 HIVIEW_LOGE("faultLogInfoContext == nullptr");
178 return result;
179 }
180
181 napi_get_value_int32(env, parameters[ONE_PARAMETER - 1], &faultLogInfoContext->faultType);
182 if (parameterCount == ONE_PARAMETER) {
183 napi_create_promise(env, &faultLogInfoContext->deferred, &result);
184 } else if (parameterCount == TWO_PARAMETER) {
185 if (!NapiUtil::IsMatchType(env, parameters[TWO_PARAMETER - 1], napi_function)) {
186 HIVIEW_LOGE("parameters[1] type isn't function");
187 delete faultLogInfoContext;
188 return result;
189 }
190 NAPI_CALL(env, napi_create_reference(env, parameters[TWO_PARAMETER - 1], 1, &faultLogInfoContext->callbackRef));
191 }
192
193 napi_value resource = NapiUtil::CreateUndefined(env);
194 napi_value resourceName = nullptr;
195 napi_create_string_utf8(env, "QuerySelfFaultLog", NAPI_AUTO_LENGTH, &resourceName);
196 napi_create_async_work(env, resource, resourceName, FaultLogExecuteCallback,
197 FaultLogCompleteCallback, (void *)faultLogInfoContext, &faultLogInfoContext->work);
198 napi_queue_async_work_with_qos(env, faultLogInfoContext->work, napi_qos_default);
199 return result;
200 }
201
AddFaultLog(napi_env env,napi_callback_info info)202 static napi_value AddFaultLog(napi_env env, napi_callback_info info)
203 {
204 size_t parameterCount = 4;
205 napi_value parameters[4] = {0};
206 napi_value thisVar = nullptr;
207 void *data = nullptr;
208 NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data));
209
210 napi_value result = NapiUtil::CreateUndefined(env);
211 if (parameterCount != FOUR_PARAMETER) {
212 return result;
213 }
214 if (!NapiUtil::IsMatchType(env, parameters[ONE_PARAMETER - 1], napi_number)) {
215 HIVIEW_LOGE("parameters[0] type isn't number");
216 return result;
217 }
218 if (!NapiUtil::IsMatchType(env, parameters[TWO_PARAMETER - 1], napi_number)) {
219 HIVIEW_LOGE("parameters[1] type isn't number");
220 return result;
221 }
222 if (!NapiUtil::IsMatchType(env, parameters[THREE_PARAMETER - 1], napi_string)) {
223 HIVIEW_LOGE("parameters[2] type isn't napi_string");
224 return result;
225 }
226 if (!NapiUtil::IsMatchType(env, parameters[FOUR_PARAMETER - 1], napi_string)) {
227 HIVIEW_LOGE("parameters[3] type isn't napi_string");
228 return result;
229 }
230 int32_t nowTmp;
231 size_t resultString;
232 napi_get_value_int32(env, parameters[ONE_PARAMETER - 1], &nowTmp);
233 int64_t now = time(nullptr) + nowTmp;
234 int32_t logType;
235 napi_get_value_int32(env, parameters[TWO_PARAMETER - 1], &logType);
236
237 char module[BUF_SIZE_64];
238 napi_get_value_string_utf8(env, parameters[THREE_PARAMETER - 1], module, BUF_SIZE_64, &resultString);
239 char summary[BUF_SIZE_64];
240 napi_get_value_string_utf8(env, parameters[FOUR_PARAMETER - 1], summary, BUF_SIZE_64, &resultString);
241 constexpr int64_t SEC_TO_MILLISEC = 1000;
242 AddFaultLog(now * SEC_TO_MILLISEC, logType, module, summary);
243 return result;
244 }
245
Query(napi_env env,napi_callback_info info)246 static napi_value Query(napi_env env, napi_callback_info info)
247 {
248 size_t parameterCount = 2;
249 napi_value parameters[2] = {0};
250 napi_value thisVar = nullptr;
251 void *data = nullptr;
252 NAPI_CALL(env, napi_get_cb_info(env, info, ¶meterCount, parameters, &thisVar, &data));
253
254 napi_value result = NapiUtil::CreateUndefined(env);
255 if (parameterCount < ONE_PARAMETER || parameterCount > TWO_PARAMETER) {
256 HIVIEW_LOGE("parameterCount Incorrect %{public}zu", parameterCount);
257 NapiUtil::ThrowError(env, NapiError::ERR_INPUT_PARAM, NapiUtil::CreateParamCntErrMsg());
258 return result;
259 }
260
261 if (!NapiUtil::IsMatchType(env, parameters[ONE_PARAMETER - 1], napi_number)) {
262 HIVIEW_LOGE("parameters[0] type isn't number");
263 NapiUtil::ThrowError(env, NapiError::ERR_INPUT_PARAM, NapiUtil::CreateErrMsg("type", napi_number));
264 return result;
265 }
266 if (!CheckFaultloggerStatus()) {
267 NapiUtil::ThrowError(env, NapiError::ERR_SERVICE_STATUS, NapiUtil::CreateServiceErrMsg());
268 return result;
269 }
270
271 auto faultLogInfoContext = std::make_unique<FaultLogInfoContext>().release();
272 if (faultLogInfoContext == nullptr) {
273 HIVIEW_LOGE("faultLogInfoContext == nullptr");
274 return result;
275 }
276
277 napi_get_value_int32(env, parameters[ONE_PARAMETER - 1], &faultLogInfoContext->faultType);
278 if (parameterCount == ONE_PARAMETER) {
279 napi_create_promise(env, &faultLogInfoContext->deferred, &result);
280 } else if (parameterCount == TWO_PARAMETER) {
281 if (!NapiUtil::IsMatchType(env, parameters[TWO_PARAMETER - 1], napi_function)) {
282 HIVIEW_LOGE("parameters[1] type isn't function");
283 delete faultLogInfoContext;
284 NapiUtil::ThrowError(env, NapiError::ERR_INPUT_PARAM,
285 NapiUtil::CreateErrMsg("callback", napi_function), true);
286 return result;
287 }
288 NAPI_CALL(env, napi_create_reference(env, parameters[TWO_PARAMETER - 1], 1, &faultLogInfoContext->callbackRef));
289 }
290
291 napi_value resource = NapiUtil::CreateUndefined(env);
292 napi_value resourceName = nullptr;
293 napi_create_string_utf8(env, "QuerySelfFaultLog", NAPI_AUTO_LENGTH, &resourceName);
294 napi_create_async_work(env, resource, resourceName, FaultLogExecuteCallback,
295 FaultLogCompleteCallback, (void *)faultLogInfoContext, &faultLogInfoContext->work);
296 napi_queue_async_work_with_qos(env, faultLogInfoContext->work, napi_qos_default);
297 return result;
298 }
299
FaultLogTypeConstructor(napi_env env,napi_callback_info info)300 napi_value FaultLogTypeConstructor(napi_env env, napi_callback_info info)
301 {
302 napi_value thisArg = nullptr;
303 void* data = nullptr;
304
305 napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, &data);
306
307 napi_value global = nullptr;
308 napi_get_global(env, &global);
309
310 return thisArg;
311 }
312
FaultLogTypeEnumInit(napi_env env,napi_value exports)313 static void FaultLogTypeEnumInit(napi_env env, napi_value exports)
314 {
315 napi_value noSpecific = nullptr;
316 napi_value cppCrash = nullptr;
317 napi_value jsCrash = nullptr;
318 napi_value appCrash = nullptr;
319
320 napi_create_int32(env, FaultLogType::NO_SPECIFIC, &noSpecific);
321 napi_create_int32(env, FaultLogType::CPP_CRASH, &cppCrash);
322 napi_create_int32(env, FaultLogType::JS_CRASH, &jsCrash);
323 napi_create_int32(env, FaultLogType::APP_FREEZE, &appCrash);
324
325 napi_property_descriptor descriptors[] = {
326 DECLARE_NAPI_STATIC_PROPERTY("NO_SPECIFIC", noSpecific),
327 DECLARE_NAPI_STATIC_PROPERTY("CPP_CRASH", cppCrash),
328 DECLARE_NAPI_STATIC_PROPERTY("JS_CRASH", jsCrash),
329 DECLARE_NAPI_STATIC_PROPERTY("APP_FREEZE", appCrash),
330 };
331
332 napi_value result = nullptr;
333 napi_define_class(env, "FaultType", NAPI_AUTO_LENGTH, FaultLogTypeConstructor, nullptr,
334 sizeof(descriptors) / sizeof(*descriptors), descriptors, &result);
335
336 napi_set_named_property(env, exports, "FaultType", result);
337 }
338
FaultLogInfoConstructor(napi_env env,napi_callback_info info)339 napi_value FaultLogInfoConstructor(napi_env env, napi_callback_info info)
340 {
341 napi_value thisArg = nullptr;
342 void* data = nullptr;
343
344 napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, &data);
345
346 napi_value global = nullptr;
347 napi_get_global(env, &global);
348
349 return thisArg;
350 }
351
FaultLogInfoClassInit(napi_env env,napi_value exports)352 static void FaultLogInfoClassInit(napi_env env, napi_value exports)
353 {
354 napi_value pid = nullptr;
355 napi_value uid = nullptr;
356 napi_value type = nullptr;
357 napi_value ts = nullptr;
358 napi_value reason = nullptr;
359 napi_value module = nullptr;
360 napi_value summary = nullptr;
361 napi_value fullLog = nullptr;
362
363 napi_create_int32(env, 0, &pid);
364 napi_create_int32(env, 0, &uid);
365 napi_create_int32(env, FaultLogType::NO_SPECIFIC, &type);
366 napi_create_int64(env, 0, &ts);
367 napi_create_string_latin1(env, "reason", NAPI_AUTO_LENGTH, &reason);
368 napi_create_string_latin1(env, "module", NAPI_AUTO_LENGTH, &module);
369 napi_create_string_latin1(env, "summary", NAPI_AUTO_LENGTH, &summary);
370 napi_create_string_latin1(env, "fullLog", NAPI_AUTO_LENGTH, &fullLog);
371
372 napi_property_descriptor descriptors[] = {
373 DECLARE_NAPI_PROPERTY("pid", pid),
374 DECLARE_NAPI_PROPERTY("uid", uid),
375 DECLARE_NAPI_PROPERTY("type", type),
376 DECLARE_NAPI_PROPERTY("timestamp", ts),
377 DECLARE_NAPI_PROPERTY("reason", reason),
378 DECLARE_NAPI_PROPERTY("module", module),
379 DECLARE_NAPI_PROPERTY("summary", summary),
380 DECLARE_NAPI_PROPERTY("fullLog", fullLog),
381 };
382
383 napi_value result = nullptr;
384 napi_define_class(env, "FaultLogInfo", NAPI_AUTO_LENGTH, FaultLogInfoConstructor, nullptr,
385 sizeof(descriptors) / sizeof(*descriptors), descriptors, &result);
386
387 napi_set_named_property(env, exports, "FaultLogInfo", result);
388 }
389
390 EXTERN_C_START
InitNapiRegistry(napi_env env,napi_value exports)391 napi_value InitNapiRegistry(napi_env env, napi_value exports)
392 {
393 napi_property_descriptor desc[] = {
394 DECLARE_NAPI_FUNCTION("querySelfFaultLog", QuerySelfFaultLog),
395 DECLARE_NAPI_FUNCTION("addFaultLog", AddFaultLog),
396 DECLARE_NAPI_FUNCTION("query", Query),
397 };
398 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
399 FaultLogTypeEnumInit(env, exports);
400 FaultLogInfoClassInit(env, exports);
401 return exports;
402 }
403 EXTERN_C_END
404
405 static napi_module _stateRegistryModule = {
406 .nm_version = 1,
407 .nm_flags = 0,
408 .nm_filename = NULL,
409 .nm_register_func = InitNapiRegistry,
410 .nm_modname = "faultLogger",
411 .nm_priv = ((void *)0),
412 .reserved = {(void *)0},
413 };
414
RegisterFaultLoggerModule(void)415 extern "C" __attribute__((constructor)) void RegisterFaultLoggerModule(void)
416 {
417 napi_module_register(&_stateRegistryModule);
418 }
419 } // namespace HiviewDFX
420 } // namespace OHOS
421