1 /*
2 * Copyright (c) 2021 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
16 #include "blackbox.h"
17 #include "blackbox_adapter.h"
18 #include "blackbox_detector.h"
19 #include "ohos_init.h"
20 #include "ohos_types.h"
21 #include "pthread.h"
22 #include "securec.h"
23 #include "utils_list.h"
24
25 /******************local macroes*********************/
26 #define LOG_ROOT_DIR_WAIT_TIME 1000
27 #define LOG_ROOT_DIR_WAIT_COUNT 1
28 #ifndef LOS_WAIT_FOREVER
29 #define LOS_WAIT_FOREVER 0xFFFFFFFF
30 #endif
31 #ifndef LOS_NO_WAIT
32 #define LOS_NO_WAIT 0
33 #endif
34 #ifndef LOS_OK
35 #define LOS_OK 0
36 #endif
37
38 /******************local prototypes******************/
39 struct BBoxOps {
40 UTILS_DL_LIST opsList;
41 struct ModuleOps ops;
42 };
43
44 /******************global functions*******************/
45 /******************local variables*******************/
46 static UTILS_DL_LIST_HEAD(g_opsList);
47 static unsigned int g_opsListSem;
48
49 /******************function definitions*******************/
GetDirName(char * dirBuf,unsigned int dirBufSize,const char * path)50 static void GetDirName(char *dirBuf, unsigned int dirBufSize, const char *path)
51 {
52 if (dirBuf == NULL || dirBufSize == 0 || path == NULL) {
53 BBOX_PRINT_ERR("dirBuf: %p, dirBufSize: %u, path: %p!\n", dirBuf, dirBufSize, path);
54 return;
55 }
56
57 const char *end = path + strlen(path);
58 while (*end != '/' && end >= path) {
59 end--;
60 }
61 if (end >= path) {
62 (void)memset_s(dirBuf, dirBufSize, 0, dirBufSize);
63 if (strncpy_s(dirBuf, dirBufSize - 1, path, end - path + strlen("/")) != EOK) {
64 BBOX_PRINT_ERR("strncpy_s failed or the dirBuf is not enough!\n");
65 }
66 } else {
67 BBOX_PRINT_ERR("no / has been found!\n");
68 }
69 }
70
FormatErrorInfo(struct ErrorInfo * info,const char event[EVENT_MAX_LEN],const char module[MODULE_MAX_LEN],const char errorDesc[ERROR_DESC_MAX_LEN])71 static void FormatErrorInfo(struct ErrorInfo *info,
72 const char event[EVENT_MAX_LEN],
73 const char module[MODULE_MAX_LEN],
74 const char errorDesc[ERROR_DESC_MAX_LEN])
75 {
76 if (info == NULL || event == NULL || module == NULL || errorDesc == NULL) {
77 BBOX_PRINT_ERR("info: %p, event: %p, module: %p, errorDesc: %p\n",
78 info, event, module, errorDesc);
79 return;
80 }
81
82 (void)memset_s(info, sizeof(*info), 0, sizeof(*info));
83 if (strncpy_s(info->event, sizeof(info->event), event,
84 Min(strlen(event), sizeof(info->event) - 1)) != EOK) {
85 BBOX_PRINT_ERR("strncpy_s failed or the info->event is not enough!\n");
86 }
87 if (strncpy_s(info->module, sizeof(info->module), module,
88 Min(strlen(module), sizeof(info->module) - 1)) != EOK) {
89 BBOX_PRINT_ERR("strncpy_s failed or the info->module is not enough!\n");
90 }
91 if (strncpy_s(info->errorDesc, sizeof(info->errorDesc), errorDesc,
92 Min(strlen(errorDesc), sizeof(info->errorDesc) - 1)) != EOK) {
93 BBOX_PRINT_ERR("strncpy_s failed or the info->errorDesc is not enough!\n");
94 }
95 }
96
WaitForLogRootDir(const char * rootDir)97 static void WaitForLogRootDir(const char *rootDir)
98 {
99 int i = 0;
100
101 if (rootDir == NULL) {
102 BBOX_PRINT_ERR("rootDir: %p\n", rootDir);
103 return;
104 }
105 BBOX_PRINT_INFO("wait for log root dir [%s] begin!\n", rootDir);
106 while (i++ < LOG_ROOT_DIR_WAIT_COUNT) {
107 LOS_Msleep(LOG_ROOT_DIR_WAIT_TIME);
108 }
109 BBOX_PRINT_INFO("wait for log root dir [%s] end!\n", rootDir);
110 }
111
SaveBasicErrorInfo(const char * filePath,struct ErrorInfo * info)112 static void SaveBasicErrorInfo(const char *filePath, struct ErrorInfo *info)
113 {
114 char *buf = NULL;
115
116 if (filePath == NULL || info == NULL) {
117 BBOX_PRINT_ERR("filePath: %p, info: %p!\n", filePath, info);
118 return;
119 }
120
121 buf = malloc(ERROR_INFO_MAX_LEN);
122 if (buf == NULL) {
123 BBOX_PRINT_ERR("malloc failed!\n");
124 return;
125 }
126 (void)memset_s(buf, ERROR_INFO_MAX_LEN, 0, ERROR_INFO_MAX_LEN);
127 if (snprintf_s(buf, ERROR_INFO_MAX_LEN, ERROR_INFO_MAX_LEN - 1,
128 ERROR_INFO_HEADER ERROR_INFO_HEADER_FORMAT,
129 info->event, info->module, info->errorDesc) != -1) {
130 *(buf + ERROR_INFO_MAX_LEN - 1) = '\0';
131 (void)FullWriteFile(filePath, buf, strlen(buf), 0);
132 } else {
133 PRINT_ERR("buf is not enough or snprintf_s failed\n");
134 }
135 free(buf);
136 BBOX_PRINT_INFO("[%s] starts uploading event [%s]\n",
137 info->module, info->event);
138 (void)UploadEventByFile(filePath);
139 BBOX_PRINT_INFO("[%s] ends uploading event [%s]\n",
140 info->module, info->event);
141 }
142
SaveErrorLog(void * param)143 static void* SaveErrorLog(void *param)
144 {
145 (void)param;
146 struct ErrorInfo *info = NULL;
147 struct BBoxOps *ops = NULL;
148 char dirName[PATH_MAX_LEN] = { 0 };
149
150 info = malloc(sizeof(*info));
151 if (info == NULL) {
152 BBOX_PRINT_ERR("malloc failed!\n");
153 return NULL;
154 }
155
156 GetDirName(dirName, sizeof(dirName), GetFaultLogPath());
157 WaitForLogRootDir(dirName);
158 if (LOS_SemPend(g_opsListSem, LOS_WAIT_FOREVER) != 0) {
159 BBOX_PRINT_ERR("Request g_opsListSem failed!\n");
160 free(info);
161 return NULL;
162 }
163 UTILS_DL_LIST_FOR_EACH_ENTRY(ops, &g_opsList, struct BBoxOps, opsList) {
164 if (ops == NULL) {
165 continue;
166 }
167 if (ops->ops.GetLastLogInfo != NULL && ops->ops.SaveLastLog != NULL) {
168 (void)memset_s(info, sizeof(*info), 0, sizeof(*info));
169 if (ops->ops.GetLastLogInfo(info) != 0) {
170 BBOX_PRINT_ERR("[%s] failed to get log info!\n",
171 ops->ops.module);
172 continue;
173 }
174 BBOX_PRINT_INFO("[%s] starts saving log!\n", ops->ops.module);
175 if (ops->ops.SaveLastLog(dirName, info) != 0) {
176 BBOX_PRINT_ERR("[%s] failed to save log!\n", ops->ops.module);
177 } else {
178 BBOX_PRINT_INFO("[%s] ends saving log!\n", ops->ops.module);
179 BBOX_PRINT_INFO("[%s] starts uploading event [%s]\n", info->module, info->event);
180 (void)UploadEventByFile(GetFaultLogPath());
181 BBOX_PRINT_INFO("[%s] ends uploading event [%s]\n", info->module, info->event);
182 }
183 }
184 }
185 (void)LOS_SemPost(g_opsListSem);
186 free(info);
187
188 return NULL;
189 }
190
191 #ifdef BLACKBOX_DEBUG
PrintModuleOps(void)192 static void PrintModuleOps(void)
193 {
194 struct BBoxOps *temp = NULL;
195
196 BBOX_PRINT_INFO("The following modules have been registered!\n");
197 UTILS_DL_LIST_FOR_EACH_ENTRY(temp, &g_opsList, struct BBoxOps, opsList) {
198 BBOX_PRINT_INFO("module: %s, Dump: %p, Reset: %p, "
199 "GetLastLogInfo: %p, SaveLastLog: %p\n",
200 temp->ops.module, temp->ops.Dump, temp->ops.Reset,
201 temp->ops.GetLastLogInfo, temp->ops.SaveLastLog);
202 }
203 }
204 #endif
205
BBoxRegisterModuleOps(struct ModuleOps * ops)206 int BBoxRegisterModuleOps(struct ModuleOps *ops)
207 {
208 struct BBoxOps *newOps = NULL;
209 struct BBoxOps *temp = NULL;
210
211 if (ops == NULL) {
212 BBOX_PRINT_ERR("ops: %p!\n", ops);
213 return -1;
214 }
215
216 /* Use malloc to avoid the stack overflow */
217 newOps = malloc(sizeof(*newOps));
218 if (newOps == NULL) {
219 BBOX_PRINT_ERR("malloc failed!\n");
220 return -1;
221 }
222 (void)memset_s(newOps, sizeof(*newOps), 0, sizeof(*newOps));
223 (void)memcpy_s(&newOps->ops, sizeof(newOps->ops), ops, sizeof(*ops));
224 if (LOS_SemPend(g_opsListSem, LOS_WAIT_FOREVER) != 0) {
225 BBOX_PRINT_ERR("Request g_opsListSem failed!\n");
226 free(newOps);
227 return -1;
228 }
229 if (UtilsListEmpty(&g_opsList)) {
230 goto __out;
231 }
232 UTILS_DL_LIST_FOR_EACH_ENTRY(temp, &g_opsList, struct BBoxOps, opsList) {
233 if (strcmp(temp->ops.module, ops->module) == 0) {
234 BBOX_PRINT_ERR("[%s] has been registered!\n", ops->module);
235 (void)LOS_SemPost(g_opsListSem);
236 free(newOps);
237 return -1;
238 }
239 }
240
241 __out:
242 BBOX_PRINT_INFO("[%s] is registered successfully!\n", ops->module);
243 UtilsListTailInsert(&g_opsList, &newOps->opsList);
244 (void)LOS_SemPost(g_opsListSem);
245 #ifdef BLACKBOX_DEBUG
246 PrintModuleOps();
247 #endif
248
249 return 0;
250 }
251
BBoxNotifyError(const char event[EVENT_MAX_LEN],const char module[MODULE_MAX_LEN],const char errorDesc[ERROR_DESC_MAX_LEN],int needSysReset)252 int BBoxNotifyError(const char event[EVENT_MAX_LEN],
253 const char module[MODULE_MAX_LEN],
254 const char errorDesc[ERROR_DESC_MAX_LEN],
255 int needSysReset)
256 {
257 int findModule = 0;
258 struct BBoxOps *ops = NULL;
259 struct ErrorInfo *info = NULL;
260 char dirName[PATH_MAX_LEN] = { 0 };
261
262 info = malloc(sizeof(*info));
263 if (info == NULL) {
264 BBOX_PRINT_ERR("malloc failed!\n");
265 return -1;
266 }
267
268 GetDirName(dirName, sizeof(dirName), GetFaultLogPath());
269 if (needSysReset == 0) {
270 WaitForLogRootDir(dirName);
271 if (LOS_SemPend(g_opsListSem, LOS_NO_WAIT) != 0) {
272 BBOX_PRINT_ERR("Request g_opsListSem failed!\n");
273 goto __out;
274 }
275 }
276
277 UTILS_DL_LIST_FOR_EACH_ENTRY(ops, &g_opsList, struct BBoxOps, opsList) {
278 if (ops == NULL) {
279 BBOX_PRINT_ERR("ops: %p!\n", ops);
280 continue;
281 }
282 if (strcmp(ops->ops.module, module) != 0) {
283 continue;
284 }
285 FormatErrorInfo(info, event, module, errorDesc);
286 if (ops->ops.Dump == NULL && ops->ops.Reset == NULL) {
287 SaveBasicErrorInfo(GetFaultLogPath(), info);
288 break;
289 }
290 if (ops->ops.Dump != NULL) {
291 BBOX_PRINT_INFO("[%s] starts dumping data!\n", ops->ops.module);
292 ops->ops.Dump(dirName, info);
293 BBOX_PRINT_INFO("[%s] ends dumping data!\n", ops->ops.module);
294 }
295 if (ops->ops.Reset != NULL) {
296 BBOX_PRINT_INFO("[%s] starts resetting!\n", ops->ops.module);
297 ops->ops.Reset(info);
298 BBOX_PRINT_INFO("[%s] ends resetting!\n", ops->ops.module);
299 }
300 findModule = 1;
301 break;
302 }
303 if (needSysReset == 0) {
304 (void)LOS_SemPost(g_opsListSem);
305 }
306
307 __out:
308 if (info != NULL) {
309 free(info);
310 }
311 if (needSysReset != 0 && findModule != 0) {
312 RebootSystem();
313 }
314
315 return 0;
316 }
317
BBoxInit(void)318 static void BBoxInit(void)
319 {
320 int ret = -1;
321 pthread_t taskId = 0;
322
323 if (LOS_BinarySemCreate(1, &g_opsListSem) != LOS_OK) {
324 BBOX_PRINT_ERR("Create binary semaphore failed!\n");
325 return;
326 }
327 UtilsListInit(&g_opsList);
328 ret = pthread_create(&taskId, NULL, SaveErrorLog, NULL);
329 if (ret != 0) {
330 BBOX_PRINT_ERR("Falied to create SaveErrorLog task, ret: %d\n", ret);
331 }
332 }
333 CORE_INIT_PRI(BBoxInit, 1);