blob: 31ca2686cdb397887e3535db4a2d38b1e1e8930c [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/* alarm management servicest
2 * (C) Copyright Marvell 2015
3 * Licensed under the GPLv2
4 *
5 * This service makes sure the alarmtimer & RTC wakeup code is
6 * functioning.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19#include <stdio.h>
20#include <unistd.h>
21#include <time.h>
22#include <string.h>
23#include <signal.h>
24#include <stdlib.h>
25#include <pthread.h>
26#include <assert.h>
27#include <sys/time.h>
28#include <fcntl.h>
29#include <signal.h>
30#include <linux/input.h>
31#include <errno.h>
32#include <asm/ioctl.h>
33
34#include <libubox/blob.h>
35#include <libubox/blobmsg.h>
36#include <libubox/ustream.h>
37#include <libubus.h>
38#include <ubusmsg.h>
39#include "alarmmanager.h"
40#include "aoc.h"
41
42#ifdef CONFIG_ALARM_SERVICE
43
44struct event {
45 struct timeval it_interval;
46 unsigned next_value;
47 int arg;
48 unsigned short flags;
49 char alarm_name[32];
50 struct event *next;
51};
52
53static volatile int alarm_update = 0;
54static pthread_t alarm_tid;
55/* protect access to event list */
56static pthread_mutex_t event_mutex = PTHREAD_MUTEX_INITIALIZER;
57static struct event *event_queue;
58static struct event *event_freelist;
59static int g_maxevents;
60static int g_events;
61static int afd;
62static int dev_opened;
63
64static struct blob_buf alarm_buf;
65static struct ubus_context *alarm_ctx;
66
67static void check_event_queue();
68static void print_event_queue();
69static void thread_alarm(void);
70size_t strlcpy(char *dst, const char *src, size_t size);
71
72size_t strlcpy(char *dst, const char *src, size_t size)
73{
74 size_t srclen; /* Length of source string */
75
76 size --;
77
78 srclen = strlen(src);
79
80 if (srclen > size)
81 srclen = size;
82
83 memcpy(dst, src, srclen);
84 dst[srclen] = '\0';
85
86 return (srclen);
87}
88
89static void alarm_notify_complete_cb(struct ubus_request *req, int ret)
90{
91 (void)(req);
92 (void)(ret);
93 return;
94}
95
96static int alarm_triggered_notify(struct ubus_context *ctx, struct event *event)
97{
98 struct ubus_notify_request nreq;
99
100 if (!event->alarm_name[0])
101 return 0;
102
103 pthread_mutex_lock(&aoc_ubus_mutex);
104 blobmsg_buf_init(&alarm_buf);
105 blobmsg_add_string(&alarm_buf, "alarm_name", event->alarm_name);
106 if (ubus_notify_async(ctx, &aoc_object, "alarm_triggered",
107 alarm_buf.head, &nreq)) {
108 pthread_mutex_unlock(&aoc_ubus_mutex);
109 return 0;
110 }
111 blob_buf_free(&alarm_buf);
112 nreq.complete_cb = (void *)&alarm_notify_complete_cb;
113 ubus_complete_request(ctx, &nreq.req, 2000);
114 pthread_mutex_unlock(&aoc_ubus_mutex);
115 return 0;
116}
117
118static struct event *get_event_from_freelist(char *name, struct timeval *tv)
119{
120 struct event *event;
121 if (!event_freelist)
122 return NULL;
123
124 event = event_freelist;
125 event_freelist = event_freelist->next;
126 event->it_interval = *tv;
127 if (name)
128 strlcpy(event->alarm_name, name, sizeof(event->alarm_name));
129 event->next = NULL;
130 g_events++;
131 return event;
132}
133
134static void put_event_to_freelist(struct event *event)
135{
136 memset(event->alarm_name, 0, sizeof(event->alarm_name));
137 event->next = event_freelist;
138 event_freelist = event;
139 g_events--;
140 return;
141}
142
143static int find_event_and_update(char *name, struct timeval *tv)
144{
145 struct event *event;
146
147 pthread_mutex_lock(&event_mutex);
148 if (event_queue) {
149 event = event_queue;
150 while (event) {
151 if (event->alarm_name[0] &&
152 !strcmp(event->alarm_name, name)) {
153 break;
154 }
155 event = event->next;
156 }
157 if (event) { /* timer already exist */
158 event->it_interval = *tv;
159 if (event == event_queue) {
160 alarm_update = 1;
161 if (pthread_kill(alarm_tid, SIGUSR1))
162 ERROR("%s: pthread_kill failed\n", __func__);
163 }
164 pthread_mutex_unlock(&event_mutex);
165 return 1;
166 }
167 }
168 pthread_mutex_unlock(&event_mutex);
169 return 0;
170}
171
172static int queue_event_to_waitlist(char *name, struct timeval *tv)
173{
174 struct event *event = NULL;
175 struct event *prev_ev, *cur_ev;
176 int ret;
177
178 pthread_mutex_lock(&event_mutex);
179 event = get_event_from_freelist(name, tv);
180 if (!event) {
181 pthread_mutex_unlock(&event_mutex);
182 return 1;
183 }
184
185 if (event_queue) {
186 prev_ev = cur_ev = event_queue;
187 while (cur_ev) {
188 if (timercmp(tv, &(cur_ev->it_interval), <)) {
189 break;
190 }
191 prev_ev = cur_ev;
192 cur_ev = cur_ev->next;
193 }
194 if (cur_ev != event_queue) {
195 DEBUG(2, "New alarm will be inserted into event_queue.\n");
196 event->next = prev_ev->next;
197 prev_ev->next = event;
198 } else {
199 DEBUG(2, "Set new alarm into top of event_queue,\
200 and set new alarm.\n");
201 event->next = event_queue;
202 event_queue = event;
203 alarm_update = 1;
204 if (pthread_kill(alarm_tid, SIGUSR1))
205 ERROR("%s: pthread_kill failed\n", __func__);
206 }
207 print_event_queue();
208 check_event_queue();
209 } else { /* event_queue empty */
210 event_queue = event;
211 event_queue->flags = TFLAG_NONE;
212 event_queue->next = NULL;
213
214 /* if more than 1 event, monitor thread */
215 ret = pthread_create(&alarm_tid, NULL, (void *)thread_alarm, NULL);
216 if (ret) {
217 ERROR("[%s] pthread_create error\n", __FUNCTION__);
218 pthread_mutex_unlock(&event_mutex);
219 return 0;
220 }
221 }
222 pthread_mutex_unlock(&event_mutex);
223 return 0;
224}
225
226static int check_elapsed_event_from_waitlist(struct timeval *tv,
227 struct timespec *ts)
228{
229 struct event *event = NULL;
230 int ret;
231
232 pthread_mutex_lock(&event_mutex);
233 if (!timercmp(tv, &(event_queue->it_interval), >)) {
234 pthread_mutex_unlock(&event_mutex);
235 return 0;
236 }
237
238 event = event_queue;
239 event_queue= event_queue->next;
240 alarm_triggered_notify(alarm_ctx, event);
241 put_event_to_freelist(event);
242 if (event_queue) {
243 print_event_queue();
244 TIMEVAL_TO_TIMESPEC(&(event_queue->it_interval), ts);
245 ret = 2;
246 } else {
247 ret = 1;
248 }
249 pthread_mutex_unlock(&event_mutex);
250 return ret;
251}
252
253static int mmp_timer_settime(int alarm_delay, char *name)
254{
255 struct timespec ts;
256 struct timeval tv;
257 int ret;
258
259 if (!dev_opened) {
260 afd = open("/dev/alarm", O_RDWR);
261 if (afd < 0) {
262 ERROR("Unable to open rtc: %s\n", strerror(errno));
263 return 1;
264 }
265 dev_opened = 1;
266 }
267
268 ret = ioctl(afd, ANDROID_ALARM_GET_TIME(ANDROID_ALARM_RTC_WAKEUP), &ts);
269 if (ret < 0) {
270 ERROR("Unable to get current time: %s\n", strerror(errno));
271 return 1;
272 }
273 ts.tv_sec += alarm_delay;
274 TIMESPEC_TO_TIMEVAL(&tv, &ts);
275
276 if (find_event_and_update(name, &tv))
277 return 0;
278
279 if (queue_event_to_waitlist(name, &tv))
280 return 1;
281
282 return 0;
283}
284
285static int mmp_cancel_timer(char *name)
286{
287 struct event *event = NULL;
288 struct event *prev;
289
290 pthread_mutex_lock(&event_mutex);
291 if (!dev_opened || !event_queue) {
292 pthread_mutex_unlock(&event_mutex);
293 return 0;
294 }
295
296 prev = event = event_queue;
297 while (event) {
298 if (event->alarm_name[0] &&
299 !strcmp(name, event->alarm_name)) {
300 DEBUG(2, "mmp_cancel_timer:find alarm_name=%s\n", name);
301 break;
302 }
303 prev = event;
304 event = event->next;
305 }
306
307 if (!event) {
308 DEBUG(2, "Not found timer: %s\n", name);
309 pthread_mutex_unlock(&event_mutex);
310 return 0;
311 }
312
313 if (event == event_queue) {
314 event_queue = event_queue->next;
315 print_event_queue();
316 if (event_queue)
317 alarm_update = 1;
318 if (pthread_kill(alarm_tid, SIGUSR1))
319 ERROR("%s: pthread_kill failed\n", __func__);
320 } else {
321 prev->next = event->next;
322 }
323
324 put_event_to_freelist(event);
325 pthread_mutex_unlock(&event_mutex);
326 return 0;
327}
328
329static void check_event_queue()
330{
331 struct event *event;
332 int i = 0;
333
334 for (event = event_queue; event; event = event->next) {
335 if (i > g_maxevents) {
336 DEBUG(2, "timer queue is full!");
337 print_event_queue();
338 exit(1);
339 }
340 i++;
341 }
342}
343
344static void print_event_queue()
345{
346 struct event *event;
347 int i = 0;
348
349 for (event = event_queue; event; event = event->next) {
350 DEBUG(2, "#%d %s: (0x%x)->0x%x: \t%d sec %d usec\n",
351 i++, event->alarm_name ? event->alarm_name : "noname",
352 (unsigned int) event, (unsigned int) event->next,
353 (int) event->it_interval.tv_sec,
354 (int) event->it_interval.tv_usec);
355 if (i > g_maxevents) {
356 DEBUG(2, "...(giving up)\n");
357 break;
358 }
359 }
360}
361
362static void alarm_sighandler(int signo)
363{
364 struct timespec ts;
365 int ret;
366
367 DEBUG(2, "alarm_sighandler: signo=%d\n", signo);
368 if (alarm_update) {
369 alarm_update = 0;
370 TIMEVAL_TO_TIMESPEC(&(event_queue->it_interval), &ts);
371 ret = ioctl(afd, ANDROID_ALARM_SET(ANDROID_ALARM_RTC_WAKEUP),
372 &ts);
373 if (ret < 0)
374 ERROR("Unable to set alarm: %s\n", strerror(errno));
375 }
376}
377
378static void thread_alarm(void)
379{
380 struct timespec ts;
381 struct timeval tv;
382 struct sigaction actoins;
383 int ret;
384
385 pthread_detach(pthread_self());
386
387 memset(&actoins, 0, sizeof(actoins));
388 sigemptyset(&actoins.sa_mask);
389 actoins.sa_flags = 0;
390 actoins.sa_handler = alarm_sighandler;
391 sigaction(SIGUSR1, &actoins, NULL);
392 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
393
394 TIMEVAL_TO_TIMESPEC(&(event_queue->it_interval), &ts);
395 ret = ioctl(afd, ANDROID_ALARM_SET(ANDROID_ALARM_RTC_WAKEUP), &ts);
396 if (ret < 0) {
397 ERROR("Unable to set alarm: %s\n", strerror(errno));
398 return;
399 }
400
401 while (true) {
402 ret = ioctl(afd, ANDROID_ALARM_WAIT);
403 if(ret < 0)
404 DEBUG(2, "alarm wait exit due to signal\n");
405 else
406 DEBUG(2, "got alarm %x\n", ret);
407 if (!event_queue)
408 goto out;
409
410 ret = ioctl(afd,
411 ANDROID_ALARM_GET_TIME(ANDROID_ALARM_RTC_WAKEUP), &ts);
412 if (ret < 0)
413 ERROR("Unable to get current time: %s\n",
414 strerror(errno));
415
416 TIMESPEC_TO_TIMEVAL(&tv, &ts);
417 ret = check_elapsed_event_from_waitlist(&tv, &ts);
418 if (ret == 2) {
419 ret = ioctl(afd,
420 ANDROID_ALARM_SET(ANDROID_ALARM_RTC_WAKEUP),
421 &ts);
422 if (ret < 0)
423 ERROR("Unable to set alarm: %s\n",
424 strerror(errno));
425 } else if (ret == 1) {
426 /* only 1 event, thread should kill self.*/
427 goto out;
428 }
429 }
430out:
431 pthread_exit((void *)0);
432}
433
434int alarm_set(struct ubus_context *ctx, struct ubus_object *obj,
435 struct ubus_request_data *req, const char *method,
436 struct blob_attr *msg)
437{
438 struct blob_attr *tb[__ALARM_MAX];
439
440 int alarm_time;
441 int ret;
442 char *alarm_name = NULL;
443
444 (void)obj;
445 (void)method;
446
447 alarm_time = 0;
448 ret = blobmsg_parse(alarm_policy, __ALARM_MAX, tb, blob_data(msg),
449 blob_len(msg));
450 if (ret) {
451 ERROR("[%s] parsing blobmsg failed %d\n",
452 __FUNCTION__, ret);
453 return -UBUS_STATUS_INVALID_ARGUMENT;
454 }
455
456 if (tb[ALARM_TIME])
457 alarm_time = blobmsg_get_u32(tb[ALARM_TIME]);
458 if (tb[ALARM_NAME])
459 alarm_name = blobmsg_get_string(tb[ALARM_NAME]);
460
461 DEBUG(2, "---------[%d]-----------\n", alarm_time);
462 if (alarm_time > 0)
463 ret = mmp_timer_settime(alarm_time, alarm_name);
464 else {
465 DEBUG(2, "----error-----[%d]-----------\n", alarm_time);
466 ret = 1;
467 }
468
469 blobmsg_buf_init(&alarm_buf);
470 blobmsg_add_u32(&alarm_buf, "rc", ret);
471 ubus_send_reply(ctx, req, alarm_buf.head);
472 blob_buf_free(&alarm_buf);
473 return 0;
474}
475
476int alarm_cancel(struct ubus_context *ctx, struct ubus_object *obj,
477 struct ubus_request_data *req, const char *method,
478 struct blob_attr *msg)
479{
480 struct blob_attr *tb[__ALARM_MAX];
481 int ret;
482 char *alarm_name = NULL;
483
484 (void)obj;
485 (void)method;
486
487 ret = blobmsg_parse(alarm_policy, __ALARM_MAX, tb, blob_data(msg),
488 blob_len(msg));
489 if (ret) {
490 ERROR("[%s] parsing blobmsg failed %d\n",
491 __FUNCTION__, ret);
492 return UBUS_STATUS_INVALID_ARGUMENT;
493 }
494
495 if (tb[ALARM_NAME]) {
496 alarm_name = blobmsg_get_string(tb[ALARM_NAME]);
497 ret = mmp_cancel_timer(alarm_name);
498 }
499
500 blobmsg_buf_init(&alarm_buf);
501 blobmsg_add_u32(&alarm_buf, "rc", ret);
502 ubus_send_reply(ctx, req, alarm_buf.head);
503 blob_buf_free(&alarm_buf);
504 return 0;
505}
506
507void alarm_init(struct ubus_context *ctx)
508{
509 int i;
510
511 alarm_ctx = ctx;
512 g_events = 0;
513 dev_opened = 0;
514 g_maxevents = MAX_EVENT;
515 event_freelist = (struct event *) malloc(MAX_EVENT * sizeof(struct event));
516 memset(event_freelist, 0, MAX_EVENT * sizeof(struct event));
517 for (i = 0; i < (MAX_EVENT-1); i++)
518 event_freelist[i].next = &event_freelist[i+1];
519
520 event_freelist[i].next = NULL;
521 event_queue = NULL;
522
523 DEBUG(2, "Alarmmanager service running up ...\n");
524}
525
526#endif //#ifdef CONFIG_ALARM_SERVICE