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