1 /*
2 * Copyright (C) 2018-2022 Intel Corporation.
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5
6 #include <stdio.h>
7 #include <signal.h>
8 #include <string.h>
9 #include <sys/time.h>
10 #include <malloc.h>
11 #include <stdlib.h>
12 #include "event_queue.h"
13 #include "load_conf.h"
14 #include "channels.h"
15 #include "fsutils.h"
16 #include "cmdutils.h"
17 #include "log_sys.h"
18 #include "event_handler.h"
19 #include "startupreason.h"
20 #include "android_events.h"
21
22 /* Watchdog timeout in second*/
23 #define WDT_TIMEOUT 300
24
25 static struct event_t *last_e;
26 static int event_processing;
27
28 /**
29 * Handle watchdog expire.
30 *
31 * @param signal Signal which triggered this function.
32 */
wdt_timeout(int signal)33 static void wdt_timeout(int signal)
34 {
35 struct event_t *e;
36 struct crash_t *crash;
37 struct info_t *info;
38 int count;
39
40 if (signal == SIGALRM) {
41 LOGE("haven't received heart beat(%ds) for %ds, killing self\n",
42 HEART_BEAT, WDT_TIMEOUT);
43
44 if (event_processing) {
45 LOGE("event (%d, %s) processing...\n",
46 last_e->event_type, last_e->path);
47 free(last_e);
48 }
49
50 count = events_count();
51 LOGE("total %d unhandled events :\n", count);
52
53 while (count-- && (e = event_dequeue())) {
54 switch (e->event_type) {
55 case CRASH:
56 crash = (struct crash_t *)e->private;
57 LOGE("CRASH (%s, %s)\n", (char *)crash->name,
58 e->path);
59 break;
60 case INFO:
61 info = (struct info_t *)e->private;
62 LOGE("INFO (%s)\n", (char *)info->name);
63 break;
64 case UPTIME:
65 LOGE("UPTIME\n");
66 break;
67 case HEART_BEAT:
68 LOGE("HEART_BEAT\n");
69 break;
70 case REBOOT:
71 LOGE("REBOOT\n");
72 break;
73 default:
74 LOGE("error event type %d\n", e->event_type);
75 }
76 free(e);
77 }
78
79 raise(SIGKILL);
80 }
81 }
82
83 /**
84 * Fed watchdog.
85 *
86 * @param timeout in second When the watchdog expire next time.
87 */
watchdog_fed(int timeout)88 static void watchdog_fed(int timeout)
89 {
90 struct itimerval new_value;
91 int ret;
92
93 memset(&new_value, 0, sizeof(new_value));
94
95 new_value.it_value.tv_sec = timeout;
96 ret = setitimer(ITIMER_REAL, &new_value, NULL);
97 if (ret < 0) {
98 LOGE("setitimer failed, error (%s)\n", strerror(errno));
99 exit(EXIT_FAILURE);
100 }
101 }
102
103 /**
104 * Initialize watchdog. This watchdog is used to monitor event handler.
105 *
106 * @param timeout in second When the watchdog expire next time.
107 */
watchdog_init(int timeout)108 static void watchdog_init(int timeout)
109 {
110 struct itimerval new_value;
111 int ret;
112 sighandler_t ohdlr;
113
114 ohdlr = signal(SIGALRM, wdt_timeout);
115 if (ohdlr == SIG_ERR) {
116 LOGE("signal failed, error (%s)\n", strerror(errno));
117 exit(EXIT_FAILURE);
118 }
119
120 memset(&new_value, 0, sizeof(new_value));
121
122 new_value.it_value.tv_sec = timeout;
123 ret = setitimer(ITIMER_REAL, &new_value, NULL);
124 if (ret < 0) {
125 LOGE("setitimer failed, error (%s)\n", strerror(errno));
126 exit(EXIT_FAILURE);
127 }
128 }
129
130 /**
131 * Process each event in event queue.
132 * Note that currently event handler is single threaded.
133 */
event_handle(void * unused)134 static void *event_handle(void *unused __attribute__((unused)))
135 {
136 int id;
137 struct sender_t *sender;
138 struct event_t *e;
139 struct vm_event_t *vme;
140
141 while ((e = event_dequeue())) {
142 /* here we only handle internal event */
143 if (e->event_type == HEART_BEAT) {
144 watchdog_fed(WDT_TIMEOUT);
145 free(e);
146 continue;
147 }
148
149 /* last_e is allocated for debug purpose, the information
150 * will be dumped if watchdog expire.
151 */
152 last_e = malloc(sizeof(*e) + e->len);
153 if (last_e == NULL) {
154 LOGE("malloc failed, error (%s)\n", strerror(errno));
155 exit(EXIT_FAILURE);
156 }
157 event_processing = 1;
158 memcpy(last_e, e, sizeof(*e) + e->len);
159
160 for_each_sender(id, sender, conf) {
161 if (!sender)
162 continue;
163
164 if (sender->send)
165 sender->send(e);
166 }
167
168 if (e->event_type == REBOOT) {
169 char reason[REBOOT_REASON_SIZE];
170
171 read_startupreason(reason, sizeof(reason));
172 if (!strcmp(reason, "WARM") ||
173 !strcmp(reason, "WATCHDOG"))
174 if (exec_out2file(NULL, "reboot") == -1)
175 break;
176 }
177
178 if (e->event_type == VM) {
179 vme = (struct vm_event_t *)e->private;
180 if (vme && vme->vm_msg)
181 free(vme->vm_msg);
182 if (vme)
183 free(vme);
184 }
185 if ((e->dir))
186 free(e->dir);
187 free(e);
188 event_processing = 0;
189 free(last_e);
190
191 }
192
193 LOGE("failed to reboot system, %s exit\n", __func__);
194 return NULL;
195 }
196
197 /**
198 * Initialize event handler.
199 */
init_event_handler(void)200 int init_event_handler(void)
201 {
202 int ret;
203 pthread_t pid;
204
205 watchdog_init(WDT_TIMEOUT);
206 ret = create_detached_thread(&pid, &event_handle, NULL);
207 if (ret) {
208 LOGE("create event handler failed (%s)\n", strerror(errno));
209 return -1;
210 }
211 return 0;
212 }
213