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