Files
2026-04-28 22:15:10 +08:00

333 lines
10 KiB
C

/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "blackbox.h"
#include "blackbox_adapter.h"
#include "blackbox_detector.h"
#include "ohos_init.h"
#include "ohos_types.h"
#include "pthread.h"
#include "securec.h"
#include "utils_list.h"
/******************local macroes*********************/
#define LOG_ROOT_DIR_WAIT_TIME 1000
#define LOG_ROOT_DIR_WAIT_COUNT 1
#ifndef LOS_WAIT_FOREVER
#define LOS_WAIT_FOREVER 0xFFFFFFFF
#endif
#ifndef LOS_NO_WAIT
#define LOS_NO_WAIT 0
#endif
#ifndef LOS_OK
#define LOS_OK 0
#endif
/******************local prototypes******************/
struct BBoxOps {
UTILS_DL_LIST opsList;
struct ModuleOps ops;
};
/******************global functions*******************/
/******************local variables*******************/
static UTILS_DL_LIST_HEAD(g_opsList);
static unsigned int g_opsListSem;
/******************function definitions*******************/
static void GetDirName(char *dirBuf, unsigned int dirBufSize, const char *path)
{
if (dirBuf == NULL || dirBufSize == 0 || path == NULL) {
BBOX_PRINT_ERR("dirBuf: %p, dirBufSize: %u, path: %p!\n", dirBuf, dirBufSize, path);
return;
}
const char *end = path + strlen(path);
while (end >= path && *end != '/') {
end--;
}
if (end >= path) {
(void)memset_s(dirBuf, dirBufSize, 0, dirBufSize);
if (strncpy_s(dirBuf, dirBufSize - 1, path, end - path + strlen("/")) != EOK) {
BBOX_PRINT_ERR("strncpy_s failed or the dirBuf is not enough!\n");
}
} else {
BBOX_PRINT_ERR("no / has been found!\n");
}
}
static void FormatErrorInfo(struct ErrorInfo *info,
const char event[EVENT_MAX_LEN],
const char module[MODULE_MAX_LEN],
const char errorDesc[ERROR_DESC_MAX_LEN])
{
if (info == NULL || event == NULL || module == NULL || errorDesc == NULL) {
BBOX_PRINT_ERR("info: %p, event: %p, module: %p, errorDesc: %p\n",
info, event, module, errorDesc);
return;
}
(void)memset_s(info, sizeof(*info), 0, sizeof(*info));
if (strncpy_s(info->event, sizeof(info->event), event,
Min(strlen(event), sizeof(info->event) - 1)) != EOK) {
BBOX_PRINT_ERR("strncpy_s failed or the info->event is not enough!\n");
}
if (strncpy_s(info->module, sizeof(info->module), module,
Min(strlen(module), sizeof(info->module) - 1)) != EOK) {
BBOX_PRINT_ERR("strncpy_s failed or the info->module is not enough!\n");
}
if (strncpy_s(info->errorDesc, sizeof(info->errorDesc), errorDesc,
Min(strlen(errorDesc), sizeof(info->errorDesc) - 1)) != EOK) {
BBOX_PRINT_ERR("strncpy_s failed or the info->errorDesc is not enough!\n");
}
}
static void WaitForLogRootDir(const char *rootDir)
{
int i = 0;
if (rootDir == NULL) {
BBOX_PRINT_ERR("rootDir: %p\n", rootDir);
return;
}
BBOX_PRINT_INFO("wait for log root dir [%s] begin!\n", rootDir);
while (i++ < LOG_ROOT_DIR_WAIT_COUNT) {
LOS_Msleep(LOG_ROOT_DIR_WAIT_TIME);
}
BBOX_PRINT_INFO("wait for log root dir [%s] end!\n", rootDir);
}
static void SaveBasicErrorInfo(const char *filePath, struct ErrorInfo *info)
{
char *buf = NULL;
if (filePath == NULL || info == NULL) {
BBOX_PRINT_ERR("filePath: %p, info: %p!\n", filePath, info);
return;
}
buf = malloc(ERROR_INFO_MAX_LEN);
if (buf == NULL) {
BBOX_PRINT_ERR("malloc failed!\n");
return;
}
(void)memset_s(buf, ERROR_INFO_MAX_LEN, 0, ERROR_INFO_MAX_LEN);
if (snprintf_s(buf, ERROR_INFO_MAX_LEN, ERROR_INFO_MAX_LEN - 1,
ERROR_INFO_HEADER ERROR_INFO_HEADER_FORMAT,
info->event, info->module, info->errorDesc) != -1) {
*(buf + ERROR_INFO_MAX_LEN - 1) = '\0';
(void)FullWriteFile(filePath, buf, strlen(buf), 0);
} else {
PRINT_ERR("buf is not enough or snprintf_s failed\n");
}
free(buf);
BBOX_PRINT_INFO("[%s] starts uploading event [%s]\n",
info->module, info->event);
(void)UploadEventByFile(filePath);
BBOX_PRINT_INFO("[%s] ends uploading event [%s]\n",
info->module, info->event);
}
static void* SaveErrorLog(void *param)
{
(void)param;
struct ErrorInfo *info = NULL;
struct BBoxOps *ops = NULL;
char dirName[PATH_MAX_LEN] = { 0 };
info = malloc(sizeof(*info));
if (info == NULL) {
BBOX_PRINT_ERR("malloc failed!\n");
return NULL;
}
GetDirName(dirName, sizeof(dirName), GetFaultLogPath());
WaitForLogRootDir(dirName);
if (LOS_SemPend(g_opsListSem, LOS_WAIT_FOREVER) != 0) {
BBOX_PRINT_ERR("Request g_opsListSem failed!\n");
free(info);
return NULL;
}
UTILS_DL_LIST_FOR_EACH_ENTRY(ops, &g_opsList, struct BBoxOps, opsList) {
if (ops == NULL) {
continue;
}
if (ops->ops.GetLastLogInfo != NULL && ops->ops.SaveLastLog != NULL) {
(void)memset_s(info, sizeof(*info), 0, sizeof(*info));
if (ops->ops.GetLastLogInfo(info) != 0) {
BBOX_PRINT_ERR("[%s] failed to get log info!\n",
ops->ops.module);
continue;
}
BBOX_PRINT_INFO("[%s] starts saving log!\n", ops->ops.module);
if (ops->ops.SaveLastLog(dirName, info) != 0) {
BBOX_PRINT_ERR("[%s] failed to save log!\n", ops->ops.module);
} else {
BBOX_PRINT_INFO("[%s] ends saving log!\n", ops->ops.module);
BBOX_PRINT_INFO("[%s] starts uploading event [%s]\n", info->module, info->event);
(void)UploadEventByFile(GetFaultLogPath());
BBOX_PRINT_INFO("[%s] ends uploading event [%s]\n", info->module, info->event);
}
}
}
(void)LOS_SemPost(g_opsListSem);
free(info);
return NULL;
}
#ifdef BLACKBOX_DEBUG
static void PrintModuleOps(void)
{
struct BBoxOps *temp = NULL;
BBOX_PRINT_INFO("The following modules have been registered!\n");
UTILS_DL_LIST_FOR_EACH_ENTRY(temp, &g_opsList, struct BBoxOps, opsList) {
BBOX_PRINT_INFO("module: %s, Dump: %p, Reset: %p, "
"GetLastLogInfo: %p, SaveLastLog: %p\n",
temp->ops.module, temp->ops.Dump, temp->ops.Reset,
temp->ops.GetLastLogInfo, temp->ops.SaveLastLog);
}
}
#endif
int BBoxRegisterModuleOps(struct ModuleOps *ops)
{
struct BBoxOps *newOps = NULL;
struct BBoxOps *temp = NULL;
if (ops == NULL) {
BBOX_PRINT_ERR("ops: %p!\n", ops);
return -1;
}
/* Use malloc to avoid the stack overflow */
newOps = malloc(sizeof(*newOps));
if (newOps == NULL) {
BBOX_PRINT_ERR("malloc failed!\n");
return -1;
}
(void)memset_s(newOps, sizeof(*newOps), 0, sizeof(*newOps));
(void)memcpy_s(&newOps->ops, sizeof(newOps->ops), ops, sizeof(*ops));
if (LOS_SemPend(g_opsListSem, LOS_WAIT_FOREVER) != 0) {
BBOX_PRINT_ERR("Request g_opsListSem failed!\n");
free(newOps);
return -1;
}
if (UtilsListEmpty(&g_opsList)) {
goto __out;
}
UTILS_DL_LIST_FOR_EACH_ENTRY(temp, &g_opsList, struct BBoxOps, opsList) {
if (strcmp(temp->ops.module, ops->module) == 0) {
BBOX_PRINT_ERR("[%s] has been registered!\n", ops->module);
(void)LOS_SemPost(g_opsListSem);
free(newOps);
return -1;
}
}
__out:
BBOX_PRINT_INFO("[%s] is registered successfully!\n", ops->module);
UtilsListTailInsert(&g_opsList, &newOps->opsList);
(void)LOS_SemPost(g_opsListSem);
#ifdef BLACKBOX_DEBUG
PrintModuleOps();
#endif
return 0;
}
int BBoxNotifyError(const char event[EVENT_MAX_LEN],
const char module[MODULE_MAX_LEN],
const char errorDesc[ERROR_DESC_MAX_LEN],
int needSysReset)
{
int findModule = 0;
struct BBoxOps *ops = NULL;
struct ErrorInfo *info = NULL;
char dirName[PATH_MAX_LEN] = { 0 };
info = malloc(sizeof(*info));
if (info == NULL) {
BBOX_PRINT_ERR("malloc failed!\n");
return -1;
}
GetDirName(dirName, sizeof(dirName), GetFaultLogPath());
if (needSysReset == 0) {
WaitForLogRootDir(dirName);
if (LOS_SemPend(g_opsListSem, LOS_NO_WAIT) != 0) {
BBOX_PRINT_ERR("Request g_opsListSem failed!\n");
goto __out;
}
}
UTILS_DL_LIST_FOR_EACH_ENTRY(ops, &g_opsList, struct BBoxOps, opsList) {
if (ops == NULL) {
BBOX_PRINT_ERR("ops: %p!\n", ops);
continue;
}
if (strcmp(ops->ops.module, module) != 0) {
continue;
}
FormatErrorInfo(info, event, module, errorDesc);
if (ops->ops.Dump == NULL && ops->ops.Reset == NULL) {
SaveBasicErrorInfo(GetFaultLogPath(), info);
break;
}
if (ops->ops.Dump != NULL) {
BBOX_PRINT_INFO("[%s] starts dumping data!\n", ops->ops.module);
ops->ops.Dump(dirName, info);
BBOX_PRINT_INFO("[%s] ends dumping data!\n", ops->ops.module);
}
if (ops->ops.Reset != NULL) {
BBOX_PRINT_INFO("[%s] starts resetting!\n", ops->ops.module);
ops->ops.Reset(info);
BBOX_PRINT_INFO("[%s] ends resetting!\n", ops->ops.module);
}
findModule = 1;
break;
}
if (needSysReset == 0) {
(void)LOS_SemPost(g_opsListSem);
}
__out:
if (info != NULL) {
free(info);
}
if (needSysReset != 0 && findModule != 0) {
RebootSystem();
}
return 0;
}
static void BBoxInit(void)
{
int ret = -1;
pthread_t taskId = 0;
if (LOS_BinarySemCreate(1, &g_opsListSem) != LOS_OK) {
BBOX_PRINT_ERR("Create binary semaphore failed!\n");
return;
}
UtilsListInit(&g_opsList);
ret = pthread_create(&taskId, NULL, SaveErrorLog, NULL);
if (ret != 0) {
BBOX_PRINT_ERR("Falied to create SaveErrorLog task, ret: %d\n", ret);
}
}
CORE_INIT_PRI(BBoxInit, 1);