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 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 struct ErrorInfo *info = NULL;
146 struct BBoxOps *ops = NULL;
147 char dirName[PATH_MAX_LEN] = { 0 };
148
149 info = malloc(sizeof(*info));
150 if (info == NULL) {
151 BBOX_PRINT_ERR("malloc failed!\n");
152 return NULL;
153 }
154
155 GetDirName(dirName, sizeof(dirName), GetFaultLogPath());
156 WaitForLogRootDir(dirName);
157 if (LOS_SemPend(g_opsListSem, LOS_WAIT_FOREVER) != 0) {
158 BBOX_PRINT_ERR("Request g_opsListSem failed!\n");
159 free(info);
160 return NULL;
161 }
162 UTILS_DL_LIST_FOR_EACH_ENTRY(ops, &g_opsList, struct BBoxOps, opsList) {
163 if (ops == NULL) {
164 continue;
165 }
166 if (ops->ops.GetLastLogInfo != NULL && ops->ops.SaveLastLog != NULL) {
167 (void)memset_s(info, sizeof(*info), 0, sizeof(*info));
168 if (ops->ops.GetLastLogInfo(info) != 0) {
169 BBOX_PRINT_ERR("[%s] failed to get log info!\n",
170 ops->ops.module);
171 continue;
172 }
173 BBOX_PRINT_INFO("[%s] starts saving log!\n", ops->ops.module);
174 if (ops->ops.SaveLastLog(dirName, info) != 0) {
175 BBOX_PRINT_ERR("[%s] failed to save log!\n", ops->ops.module);
176 } else {
177 BBOX_PRINT_INFO("[%s] ends saving log!\n", ops->ops.module);
178 BBOX_PRINT_INFO("[%s] starts uploading event [%s]\n", info->module, info->event);
179 (void)UploadEventByFile(GetFaultLogPath());
180 BBOX_PRINT_INFO("[%s] ends uploading event [%s]\n", info->module, info->event);
181 }
182 }
183 }
184 (void)LOS_SemPost(g_opsListSem);
185 free(info);
186
187 return NULL;
188 }
189
190 #ifdef BLACKBOX_DEBUG
PrintModuleOps(void)191 static void PrintModuleOps(void)
192 {
193 struct BBoxOps *temp = NULL;
194
195 BBOX_PRINT_INFO("The following modules have been registered!\n");
196 UTILS_DL_LIST_FOR_EACH_ENTRY(temp, &g_opsList, struct BBoxOps, opsList) {
197 BBOX_PRINT_INFO("module: %s, Dump: %p, Reset: %p, "
198 "GetLastLogInfo: %p, SaveLastLog: %p\n",
199 temp->ops.module, temp->ops.Dump, temp->ops.Reset,
200 temp->ops.GetLastLogInfo, temp->ops.SaveLastLog);
201 }
202 }
203 #endif
204
BBoxRegisterModuleOps(struct ModuleOps * ops)205 int BBoxRegisterModuleOps(struct ModuleOps *ops)
206 {
207 struct BBoxOps *newOps = NULL;
208 struct BBoxOps *temp = NULL;
209
210 if (ops == NULL) {
211 BBOX_PRINT_ERR("ops: %p!\n", ops);
212 return -1;
213 }
214
215 /* Use malloc to avoid the stack overflow */
216 newOps = malloc(sizeof(*newOps));
217 if (newOps == NULL) {
218 BBOX_PRINT_ERR("malloc failed!\n");
219 return -1;
220 }
221 (void)memset_s(newOps, sizeof(*newOps), 0, sizeof(*newOps));
222 (void)memcpy_s(&newOps->ops, sizeof(newOps->ops), ops, sizeof(*ops));
223 if (LOS_SemPend(g_opsListSem, LOS_WAIT_FOREVER) != 0) {
224 BBOX_PRINT_ERR("Request g_opsListSem failed!\n");
225 free(newOps);
226 return -1;
227 }
228 if (UtilsListEmpty(&g_opsList)) {
229 goto __out;
230 }
231 UTILS_DL_LIST_FOR_EACH_ENTRY(temp, &g_opsList, struct BBoxOps, opsList) {
232 if (strcmp(temp->ops.module, ops->module) == 0) {
233 BBOX_PRINT_ERR("[%s] has been registered!\n", ops->module);
234 (void)LOS_SemPost(g_opsListSem);
235 free(newOps);
236 return -1;
237 }
238 }
239
240 __out:
241 BBOX_PRINT_INFO("[%s] is registered successfully!\n", ops->module);
242 UtilsListTailInsert(&g_opsList, &newOps->opsList);
243 (void)LOS_SemPost(g_opsListSem);
244 #ifdef BLACKBOX_DEBUG
245 PrintModuleOps();
246 #endif
247
248 return 0;
249 }
250
BBoxNotifyError(const char event[EVENT_MAX_LEN],const char module[MODULE_MAX_LEN],const char errorDesc[ERROR_DESC_MAX_LEN],int needSysReset)251 int BBoxNotifyError(const char event[EVENT_MAX_LEN],
252 const char module[MODULE_MAX_LEN],
253 const char errorDesc[ERROR_DESC_MAX_LEN],
254 int needSysReset)
255 {
256 int findModule = 0;
257 struct BBoxOps *ops = NULL;
258 struct ErrorInfo *info = NULL;
259 char dirName[PATH_MAX_LEN] = { 0 };
260
261 info = malloc(sizeof(*info));
262 if (info == NULL) {
263 BBOX_PRINT_ERR("malloc failed!\n");
264 return -1;
265 }
266
267 GetDirName(dirName, sizeof(dirName), GetFaultLogPath());
268 if (needSysReset == 0) {
269 WaitForLogRootDir(dirName);
270 if (LOS_SemPend(g_opsListSem, LOS_NO_WAIT) != 0) {
271 BBOX_PRINT_ERR("Request g_opsListSem failed!\n");
272 goto __out;
273 }
274 }
275
276 UTILS_DL_LIST_FOR_EACH_ENTRY(ops, &g_opsList, struct BBoxOps, opsList) {
277 if (ops == NULL) {
278 BBOX_PRINT_ERR("ops: %p!\n", ops);
279 continue;
280 }
281 if (strcmp(ops->ops.module, module) != 0) {
282 continue;
283 }
284 FormatErrorInfo(info, event, module, errorDesc);
285 if (ops->ops.Dump == NULL && ops->ops.Reset == NULL) {
286 SaveBasicErrorInfo(GetFaultLogPath(), info);
287 break;
288 }
289 if (ops->ops.Dump != NULL) {
290 BBOX_PRINT_INFO("[%s] starts dumping data!\n", ops->ops.module);
291 ops->ops.Dump(dirName, info);
292 BBOX_PRINT_INFO("[%s] ends dumping data!\n", ops->ops.module);
293 }
294 if (ops->ops.Reset != NULL) {
295 BBOX_PRINT_INFO("[%s] starts resetting!\n", ops->ops.module);
296 ops->ops.Reset(info);
297 BBOX_PRINT_INFO("[%s] ends resetting!\n", ops->ops.module);
298 }
299 findModule = 1;
300 break;
301 }
302 if (needSysReset == 0) {
303 (void)LOS_SemPost(g_opsListSem);
304 }
305
306 __out:
307 if (info != NULL) {
308 free(info);
309 }
310 if (needSysReset != 0 && findModule != 0) {
311 RebootSystem();
312 }
313
314 return 0;
315 }
316
BBoxInit(void)317 static void BBoxInit(void)
318 {
319 int ret = -1;
320 pthread_t taskId = 0;
321
322 if (LOS_BinarySemCreate(1, &g_opsListSem) != LOS_OK) {
323 BBOX_PRINT_ERR("Create binary semaphore failed!\n");
324 return;
325 }
326 UtilsListInit(&g_opsList);
327 ret = pthread_create(&taskId, NULL, SaveErrorLog, NULL);
328 if (ret != 0) {
329 BBOX_PRINT_ERR("Falied to create SaveErrorLog task, ret: %d\n", ret);
330 }
331 }
332 CORE_INIT_PRI(BBoxInit, 1);