• 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 <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, &parameterCount, 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, &parameterCount, 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, &parameterCount, 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