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