• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &parameterCount, 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, &parameterCount, 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, &parameterCount, 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