1 /*
2 * Copyright (C) 2018 Knowles Electronics
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <poll.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <time.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <cutils/properties.h>
28
29 #define LOG_TAG "ia_crash_event_logger"
30 #include <cutils/log.h>
31 #include <cutils/uevent.h>
32 #include "crash_analyzer.h"
33
34 #define UEVENT_MSG_LEN (1024)
35 #define BUF_SIZE (4096)
36 #define CRASH_LOGGER_DEV "/dev/crashdump"
37 #define REGDUMP_LOGGER_DEV "/dev/regdump"
38 #define CRASH_DUMP_FILE_PREFIX "/data/data/dump_crash_"
39 #define REG_ACCESS_FILE_PREFIX "/data/data/dump_reg_access_history_"
40 #define CRASH_REASON_FILE_PREFIX "/data/data/dump_crash_reason_"
41 #define SSR_CRASH_REASON_PREFIX "ia_dump_crash_reason_"
42 #define BIN_EXTN ".bin"
43 #define TXT_EXTN ".txt"
44 #define MAX_FILENAME_LEN 512
45 #define MAX_TIMESTR_LEN 64
46 #define CRASH_DUMP_ANALYZER_MAX_STR_LEN 512
47
48 #define SSR_RAMDUMP_PREFIX "ramdump_audio_codec_"
49 #define SSR_CRASH_FILE_PREFIX "ia_crash_dump_"
50 #define SSR_REG_FILE_PREFIX "ia_reg_access_history_"
51 #define SSR_DUMP_PATH "/data/vendor/ssrdump/"
52
53 int g_exit_socket[2];
54
sigint_handler(int sig __unused)55 void sigint_handler(int sig __unused) {
56 ALOGE("Interrupted, setting the exit condition");
57 if (g_exit_socket[0] >= 0)
58 write(g_exit_socket[0], "T", 1);
59 }
60
61 char *crash_dump_split_file_names[] =
62 {"/data/data/dump_debug_CM4_",
63 "/data/data/dump_debug_HMD_",
64 "/data/data/dump_debug_DMX_",
65 "/data/data/dump_crash_CM4_",
66 "/data/data/dump_crash_HMD_",
67 "/data/data/dump_crash_DMX_",
68 "/data/data/dump_crash_SSP_RAM0_",
69 "/data/data/dump_crash_SSP_RAM1_",
70 "/data/data/dump_crash_SSP_ROM0_",
71 CRASH_REASON_FILE_PREFIX
72 };
73
74 char *ssr_crash_dump_split_file_names[] = {
75 "ia_dump_debug_CM4_",
76 "ia_dump_debug_HMD_",
77 "ia_dump_debug_DMX_",
78 "ia_dump_crash_CM4_",
79 "ia_dump_crash_HMD_",
80 "ia_dump_crash_DMX_",
81 "ia_dump_crash_SSP_RAM0_",
82 "ia_dump_crash_SSP_RAM1_",
83 "ia_dump_crash_SSP_ROM0_",
84 SSR_CRASH_REASON_PREFIX
85 };
86
dump_crash_reason(const unsigned char * crash_dump_buf,const int crash_dump_len,const unsigned char * crash_reason_buf,const int crash_reason_len,const char * time_stamp,bool is_ssr)87 void dump_crash_reason(const unsigned char *crash_dump_buf,
88 const int crash_dump_len,
89 const unsigned char *crash_reason_buf,
90 const int crash_reason_len,
91 const char *time_stamp, bool is_ssr)
92 {
93
94 FILE *out_fp = NULL;
95 char file_name[MAX_FILENAME_LEN] = {0};
96 char crash_dump_analyzer_str[CRASH_DUMP_ANALYZER_MAX_STR_LEN] = {0};
97 int len = 0;
98 const char *crash_dump_title = " crash_analysis:";
99
100 if (is_ssr) {
101 snprintf(file_name, MAX_FILENAME_LEN, "%s%s%s%s%s",
102 SSR_DUMP_PATH, SSR_RAMDUMP_PREFIX,
103 SSR_CRASH_REASON_PREFIX,
104 time_stamp, BIN_EXTN);
105 } else {
106 snprintf(file_name, MAX_FILENAME_LEN, "%s%s%s",
107 CRASH_REASON_FILE_PREFIX, time_stamp,
108 TXT_EXTN);
109 }
110
111 out_fp = fopen(file_name, "w");
112 if (out_fp == NULL) {
113 ALOGE("Failed to open %s for writting", file_name);
114 goto exit;
115 }
116
117 len = strnlen((const char *)crash_reason_buf, crash_reason_len);
118
119 if (fwrite(crash_reason_buf, 1, len, out_fp) != len) {
120 ALOGE("%s: ERROR writing to CRASH REASON FILE", __func__);
121 goto exit;
122 }
123
124 len = analyse_crash_info(
125 crash_dump_buf, crash_dump_len, crash_dump_analyzer_str,
126 CRASH_DUMP_ANALYZER_MAX_STR_LEN);
127 if (len > 0) {
128 fwrite(crash_dump_title, 1, strlen(crash_dump_title), out_fp);
129 fwrite(crash_dump_analyzer_str, 1,
130 strlen(crash_dump_analyzer_str), out_fp);
131 }
132 ALOGI("Crash logs saved to %s", file_name);
133 exit:
134 if (out_fp != NULL) {
135 fclose(out_fp);
136 }
137
138 }
139
split_crash_dump_buffer(unsigned char * buf,const int len,const char * time_stamp)140 int split_crash_dump_buffer(unsigned char *buf, const int len,
141 const char* time_stamp)
142 {
143
144 unsigned int file_index = 0, size = 0, tot_len = 0, flen = 0;
145 int fcount = 0;
146 unsigned char *ptr = NULL;
147 FILE *fp = NULL;
148 char file_name[MAX_FILENAME_LEN] = {0};
149 int number_crashdump_files = sizeof(crash_dump_split_file_names) /
150 sizeof(crash_dump_split_file_names[0]);
151
152 if (buf == NULL || time_stamp == NULL || len <= 0) {
153 ALOGE("%s: Bad parameters", __func__);
154 return -1;
155 }
156
157 while ((tot_len + STEP_LENGTH - 1 < len) &&
158 (fcount++ < number_crashdump_files)) {
159 file_index = buf[tot_len];
160
161 size = buf[tot_len + 8] |
162 buf[tot_len + 9] << 8 |
163 buf[tot_len + 10] << 16 |
164 buf[tot_len + 11] << 24;
165
166 tot_len += STEP_LENGTH;
167
168 if (file_index >= number_crashdump_files || size > len - tot_len) {
169 continue;
170 }
171
172 /* Some special handling is needed for crash reason file */
173 if (!strcmp(crash_dump_split_file_names[file_index],
174 CRASH_REASON_FILE_PREFIX)) {
175 dump_crash_reason(buf, len, buf + tot_len, size, time_stamp,
176 false);
177 }
178 else {
179 snprintf(file_name, MAX_FILENAME_LEN, "%s%s%s",
180 crash_dump_split_file_names[file_index],
181 time_stamp, BIN_EXTN);
182
183 fp = fopen(file_name, "w+");
184
185 ptr = buf + tot_len;
186
187 flen = fwrite(ptr , 1, size, fp);
188 tot_len += size;
189 fclose(fp);
190 ALOGI("Crash logs saved to %s", file_name);
191 }
192 }
193 return 0;
194 }
195
split_crash_dump_file(const char * crash_dump_filename,const char * time_stamp)196 int split_crash_dump_file (const char* crash_dump_filename,
197 const char* time_stamp)
198 {
199 int fd, fil_len;
200 FILE *fp;
201 struct stat st;
202 unsigned char *buf;
203 int len,ret ;
204
205 fp = fopen(crash_dump_filename, "r");
206 if (!fp)
207 {
208 ALOGE("File open error %s \n", crash_dump_filename);
209 return -1;
210 }
211
212 fd = fileno(fp);
213 fstat(fd, &st);
214 fil_len = st.st_size;
215 buf = (unsigned char*) malloc(fil_len);
216
217 if (NULL == buf) {
218 ALOGE("Failed to allocate buffer exiting");
219 ret = -1;
220 goto exit;
221 }
222
223 len = fread(buf,1, fil_len, fp);
224 if (len <=0) {
225 ALOGE("file reading error %s\n", crash_dump_filename);
226 ret = -1;
227 goto exit;
228 }
229 ret = split_crash_dump_buffer(buf, len, time_stamp);
230
231 exit:
232 if (fp)
233 fclose (fp);
234 if (buf)
235 free(buf);
236 return ret;
237 }
238
dump_crash_log()239 void dump_crash_log() {
240 void *buf = NULL;
241 int inp_fp = -1, out_fp = -1;
242 int bytes_read = 0;
243 int err = 0;
244 time_t t;
245 struct tm *tm;
246 char file_name[MAX_FILENAME_LEN];
247 char curr_time[MAX_TIMESTR_LEN];
248
249 buf = malloc(BUF_SIZE);
250 if (NULL == buf) {
251 ALOGE("Failed to allocate buffer exiting");
252 err = -1;
253 goto exit;
254 }
255
256 inp_fp = open(CRASH_LOGGER_DEV, O_RDONLY);
257 if (inp_fp == -1) {
258 ALOGE("Failed to open %s with error %d(%s)",
259 CRASH_LOGGER_DEV, errno, strerror(errno));
260 goto exit;
261 }
262
263 strcpy(file_name, CRASH_DUMP_FILE_PREFIX);
264 t = time(NULL);
265 tm = localtime(&t);
266 strftime(curr_time, 64, "%F_%H_%M_%S", tm);
267 strcat(file_name, curr_time);
268 strcat(file_name, BIN_EXTN);
269
270 out_fp = open(file_name, O_WRONLY | O_CREAT, 0644);
271 if (out_fp == -1) {
272 ALOGE("Failed to open %s for writing", file_name);
273 goto exit;
274 }
275
276 do {
277 bytes_read = read(inp_fp, buf, BUF_SIZE);
278 if (bytes_read > 0)
279 write(out_fp, buf, bytes_read);
280 } while (bytes_read > 0);
281
282 ALOGI("Crash logs has been dumped to %s", file_name);
283 close(out_fp);
284 out_fp = -1;
285 close(inp_fp);
286 inp_fp = -1;
287 free(buf);
288 buf = NULL;
289 split_crash_dump_file(file_name, curr_time);
290
291 exit:
292 if (out_fp != -1) {
293 close(out_fp);
294 }
295
296 if (inp_fp != -1) {
297 close(inp_fp);
298 }
299
300 if (buf) {
301 free(buf);
302 }
303 }
304
dump_reg_access_hist_log()305 void dump_reg_access_hist_log() {
306 void *buf = NULL;
307 int inp_fp = -1, out_fp = -1;
308 int bytes_read = 0;
309 int err = 0;
310 time_t t;
311 struct tm *tm;
312 char file_name[MAX_FILENAME_LEN];
313 char curr_time[MAX_TIMESTR_LEN];
314
315 buf = malloc(BUF_SIZE);
316 if (!buf) {
317 ALOGE("Failed to allocate buffer exiting");
318 err = -1;
319 goto exit;
320 }
321
322 inp_fp = open(REGDUMP_LOGGER_DEV, O_RDONLY);
323 if (inp_fp == -1) {
324 ALOGE("Failed to open %s with error %d(%s)",
325 REGDUMP_LOGGER_DEV, errno, strerror(errno));
326 goto exit;
327 }
328
329 strcpy(file_name, REG_ACCESS_FILE_PREFIX);
330 t = time(NULL);
331 tm = localtime(&t);
332 strftime(curr_time, 64, "%F_%H_%M_%S", tm);
333 strcat(file_name, curr_time);
334 strcat(file_name, TXT_EXTN);
335
336 out_fp = open(file_name, O_WRONLY | O_CREAT, 0644);
337 if (out_fp == -1) {
338 ALOGE("Failed to open %s for writing", file_name);
339 goto exit;
340 }
341
342 do {
343 bytes_read = read(inp_fp, buf, BUF_SIZE);
344 if (bytes_read > 0)
345 write(out_fp, buf, bytes_read);
346 } while (bytes_read > 0);
347
348 ALOGI("Register access history has been dumped to %s", file_name);
349
350 exit:
351 if (out_fp != -1) {
352 close(out_fp);
353 }
354
355 if (inp_fp != -1) {
356 close(inp_fp);
357 }
358
359 if (buf) {
360 free(buf);
361 }
362 }
363
364 /* --- functions for SSR detector ---*/
ssr_split_bin(unsigned char * buf,int len,const char * time_stamp)365 int ssr_split_bin(unsigned char *buf, int len, const char* time_stamp) {
366 unsigned int file_index = 0, size = 0, tot_len = 0, flen = 0;
367 unsigned char *ptr = NULL;
368 char file_name[MAX_FILENAME_LEN] = {0};
369 FILE *fp = NULL;
370 int fcount = 0;
371 int number_crashdump_files = sizeof(ssr_crash_dump_split_file_names) /
372 sizeof(ssr_crash_dump_split_file_names[0]);
373
374 if (buf == NULL || time_stamp == NULL || len <= 0) {
375 ALOGE("%s: Bad parameters", __func__);
376 return -1;
377 }
378
379 while ((tot_len + STEP_LENGTH - 1 < len) &&
380 (fcount++ < number_crashdump_files)) {
381
382 file_index = buf[tot_len];
383
384 size = buf[tot_len + 8] |
385 buf[tot_len + 9] << 8 |
386 buf[tot_len + 10] << 16 |
387 buf[tot_len + 11] << 24 ;
388
389 tot_len += STEP_LENGTH;
390
391 if (file_index >= number_crashdump_files || size > len - tot_len) {
392 continue;
393 }
394
395 /* Some special handling is needed for crash reason file */
396 if (!strcmp(ssr_crash_dump_split_file_names[file_index],
397 SSR_CRASH_REASON_PREFIX)) {
398 dump_crash_reason(buf, len, buf + tot_len, size, time_stamp, true);
399 continue;
400 }
401
402 snprintf(file_name, MAX_FILENAME_LEN, "%s%s%s%s%s",
403 SSR_DUMP_PATH, SSR_RAMDUMP_PREFIX,
404 ssr_crash_dump_split_file_names[file_index],
405 time_stamp, BIN_EXTN);
406
407 fp = fopen(file_name, "w+");
408
409 ptr = buf + tot_len;
410 flen = fwrite(ptr, 1, size, fp);
411 tot_len += size;
412 fclose(fp);
413 ALOGI("SSR Crash logs saved to %s", file_name);
414 }
415 return 0;
416 }
417
ssr_split_crash_dump_file(const char * crash_dump_filename,const char * time_stamp)418 int ssr_split_crash_dump_file(const char* crash_dump_filename,
419 const char* time_stamp) {
420 int fd = -1, fil_len = 0;
421 FILE *fp = NULL;
422 struct stat st;
423 unsigned char *buf = NULL;
424 int len = 0, ret = 0;
425
426 fp = fopen(crash_dump_filename, "r");
427 if (!fp) {
428 ALOGE("File open error %s \n", crash_dump_filename);
429 return -1;
430 }
431
432 fd = fileno(fp);
433 fstat(fd, &st);
434 fil_len = st.st_size;
435 buf = (unsigned char *)malloc(fil_len);
436
437 if (NULL == buf) {
438 ALOGE("Failed to allocate buffer exiting");
439 ret = -1;
440 goto exit;
441 }
442
443 len = fread(buf, 1, fil_len, fp);
444 if (len <= 0) {
445 ALOGE("file reading error %s\n", crash_dump_filename);
446 ret = -1;
447 goto exit;
448 }
449 ret = ssr_split_bin(buf, len, time_stamp);
450
451 exit:
452 if (fp) {
453 fclose(fp);
454 }
455
456 if (buf) {
457 free(buf);
458 }
459 return ret;
460 }
461
ssr_copy_log(const char * src_path,const char * dis_path)462 void ssr_copy_log(const char* src_path, const char* dis_path) {
463 int src_fp = -1, dis_fp = -1;
464 int bytes_read = 0;
465 void *temp_buf = NULL;
466
467 // allocate temp buf
468 temp_buf = malloc(BUF_SIZE);
469 if (!temp_buf) {
470 ALOGE("Failed to allocate buffer exiting");
471 goto exit;
472 }
473
474 // open src file
475 src_fp = open(src_path, O_RDONLY);
476 if (src_fp == -1) {
477 ALOGE("Failed to open %s with error %d(%s)",
478 src_path, errno, strerror(errno));
479 goto exit;
480 }
481
482 // open dis file and append
483 dis_fp = open(dis_path, O_CREAT | O_SYNC | O_WRONLY,
484 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
485 if (dis_fp == -1) {
486 ALOGE("Failed to open %s with error %d(%s)",
487 dis_path, errno, strerror(errno));
488 goto exit;
489 }
490
491 // copy data
492 do {
493 bytes_read = read(src_fp, temp_buf, BUF_SIZE);
494 if (bytes_read > 0)
495 write(dis_fp, temp_buf, bytes_read);
496 } while (bytes_read > 0);
497
498 ALOGI("Write data successfully from %s to %s", src_path, dis_path);
499
500 exit:
501 if (src_fp != -1) {
502 close(src_fp);
503 }
504
505 if (dis_fp != -1) {
506 close(dis_fp);
507 }
508
509 if (temp_buf) {
510 free(temp_buf);
511 }
512 return;
513 }
514
check_crash_reason_file(const char * time_stamp)515 void check_crash_reason_file(const char *time_stamp)
516 {
517 FILE *out_fp = NULL;
518 char file_name[MAX_FILENAME_LEN] = {0};
519 const char *default_crash_reason = "Iaxxx Firmware Crashed";
520
521 snprintf(file_name, MAX_FILENAME_LEN, "%s%s%s%s%s",
522 SSR_DUMP_PATH, SSR_RAMDUMP_PREFIX,
523 SSR_CRASH_REASON_PREFIX,
524 time_stamp, BIN_EXTN);
525
526 if (access(file_name, F_OK) == -1) {
527 ALOGE("Write default crash reason into the crash reason file");
528
529 out_fp = fopen(file_name, "w");
530
531 if (out_fp == NULL) {
532 ALOGE("%s: Failed to open: %s , errno: %s", __func__,
533 file_name, strerror(errno));
534 return;
535 }
536
537 fwrite(default_crash_reason, 1,
538 strlen(default_crash_reason), out_fp);
539
540 fclose(out_fp);
541 }
542 }
543
ssr_dump_log()544 void ssr_dump_log() {
545 time_t t;
546 struct tm *tm = NULL;
547 char curr_time_for_property[MAX_TIMESTR_LEN] = {0};
548 char curr_time_for_dump[MAX_TIMESTR_LEN] = {0};
549 char out_crash_file_name[MAX_FILENAME_LEN] = {0};
550 char out_reg_file_name[MAX_FILENAME_LEN] = {0};
551
552 // get current time
553 t = time(NULL);
554 tm = localtime(&t);
555 snprintf(curr_time_for_property, MAX_TIMESTR_LEN,
556 "%.4d-%.2d-%.2d %.2d-%.2d-%.2d",
557 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
558 tm->tm_hour, tm->tm_min, tm->tm_sec);
559 snprintf(curr_time_for_dump, MAX_TIMESTR_LEN,
560 "%.02d-%.02d-%.02d_%.02d-%.02d-%.02d",
561 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
562 tm->tm_hour, tm->tm_min, tm->tm_sec);
563 // strftime(curr_time_for_dump, MAX_TIMESTR_LEN, "%F_%H_%M_%S", tm);
564
565 // set property
566 property_set("vendor.debug.ssrdump.subsys", "audio_codec");
567 property_set("vendor.debug.ssrdump.timestamp", curr_time_for_property);
568
569 // copy crash log only
570 snprintf(out_crash_file_name, MAX_FILENAME_LEN, "%s%s%s%s%s",
571 SSR_DUMP_PATH, SSR_RAMDUMP_PREFIX, SSR_CRASH_FILE_PREFIX,
572 curr_time_for_dump, BIN_EXTN);
573 ssr_copy_log(CRASH_LOGGER_DEV, out_crash_file_name);
574 ssr_split_crash_dump_file(out_crash_file_name, curr_time_for_dump);
575 ALOGI("Crash logs has been dumped to %s", out_crash_file_name);
576
577 // copy reg
578 snprintf(out_reg_file_name, MAX_FILENAME_LEN, "%s%s%s%s%s",
579 SSR_DUMP_PATH, SSR_RAMDUMP_PREFIX, SSR_REG_FILE_PREFIX,
580 curr_time_for_dump, TXT_EXTN);
581 ssr_copy_log(REGDUMP_LOGGER_DEV, out_reg_file_name);
582 ALOGI("Register access history has been dumped %s", out_reg_file_name);
583
584 // Check the crash reason file
585 check_crash_reason_file(curr_time_for_dump);
586 }
587
588 /* --- main function --- */
main(int argc,char ** argv)589 int main(int argc, char** argv) {
590 int err = 0;
591 int timeout = -1; // Wait for event indefinitely
592 struct pollfd fds[2];
593 char msg[UEVENT_MSG_LEN];
594 int i, n;
595 bool ssr_monitor = false;
596
597 if ((argc == 2) && !strcmp(argv[1], "-m")) {
598 ALOGD("Monitor the crash logs");
599 (void)umask(S_IWGRP | S_IWOTH);
600 ssr_monitor = true;
601 }
602
603 signal(SIGINT, sigint_handler);
604
605 if ( (argc == 2) && !strcmp(argv[1], "-f")) {
606 ALOGD("Read to get the crash logs");
607 dump_reg_access_hist_log();
608 dump_crash_log();
609 return 0;
610 }
611
612 if (socketpair(AF_UNIX, SOCK_STREAM, 0, g_exit_socket) == -1) {
613 ALOGE("%s: Failed to create termination socket", __func__);
614 err = -1;
615 goto exit;
616 }
617
618
619 fds[0].events = POLLIN;
620 fds[0].fd = uevent_open_socket(64*1024, true);
621 if (fds[0].fd == -1) {
622 ALOGE("Error opening socket for hotplug uevent errno %d(%s)",
623 errno, strerror(errno));
624 goto exit;
625 }
626 fds[1].events = POLLIN;
627 fds[1].fd = g_exit_socket[1];
628
629 while (1) {
630 err = poll (fds, 2, timeout);
631
632 if (fds[0].revents & POLLIN) {
633 n = uevent_kernel_multicast_recv(fds[0].fd, msg, UEVENT_MSG_LEN);
634 if (n <= 0) {
635 continue;
636 }
637
638 for (i = 0; i < n;) {
639 if (strstr(msg + i, "IAXXX_CRASH_EVENT")) {
640 ALOGD("IAXXX_CRASH_EVENT received trying to get the crash logs");
641 if (ssr_monitor) {
642 ssr_dump_log();
643 } else {
644 dump_reg_access_hist_log();
645 dump_crash_log();
646 }
647 }
648
649 i += strlen(msg + i) + 1;
650 }
651 } else if (fds[1].revents & POLLIN) {
652 read(fds[1].fd, &n, sizeof(n)); /* clear the socket */
653 ALOGE("Interrupt received, exiting");
654 break;
655 } else {
656 ALOGI("Message ignored");
657 }
658 }
659
660 exit:
661 if (g_exit_socket[0] >= 0) {
662 close(g_exit_socket[0]);
663 }
664
665 if (g_exit_socket[1] >= 0) {
666 close(g_exit_socket[1]);
667 }
668
669 return err;
670 }
671