34475c8bc491b24e1434a2b259e90047f17fabc1
[framework/appfw/alarm-manager.git] / alarm-manager-schedule.c
1 /*
2  *  alarm-manager
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Venkatesha Sarpangala <sarpangala.v@samsung.com>, Jayoun Lee <airjany@samsung.com>,
7  * Sewook Park <sewook7.park@samsung.com>, Jaeho Lee <jaeho81.lee@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23
24
25
26 #define _BSD_SOURCE             /*localtime_r requires */
27 #include<stdio.h>
28 #include<stdlib.h>
29 #include<time.h>
30 #include<signal.h>
31 #include<string.h>
32 #include<sys/types.h>
33
34 #include<dbus/dbus.h>
35 #include<glib.h>
36
37 #include"alarm.h"
38 #include"alarm-internal.h"
39 #define WAKEUP_ALARM_APP_ID "com.samsung.alarm.ALARM"   /*alarm ui
40                                                            application's alarm's dbus_service name instead of 21 value */
41 #define DST_TIME_DIFF 1
42
43 extern __alarm_server_context_t alarm_context;
44 extern GSList *g_scheduled_alarm_list;
45
46 #ifdef __ALARM_BOOT
47 extern bool enable_power_on_alarm;
48 #endif
49
50 static void __free_scheduled_alarm(gpointer data, gpointer user_data);
51 static time_t __alarm_next_duetime_once(__alarm_info_t *__alarm_info);
52 static time_t __alarm_next_duetime_repeat(__alarm_info_t *__alarm_info);
53 static time_t __alarm_next_duetime_annually(__alarm_info_t *__alarm_info);
54 static time_t __alarm_next_duetime_monthly(__alarm_info_t *__alarm_info);
55 static time_t __alarm_next_duetime_weekly(__alarm_info_t *__alarm_info);
56 static bool __find_next_alarm_to_be_scheduled(time_t *min_due_time);
57 #ifdef __ALARM_BOOT
58 /*alarm boot*/
59 static bool __find_next_alarm_to_be_scheduled_power_on(time_t *min_due_time);
60 bool _alarm_find_mintime_power_on(time_t *min_time);
61 #endif
62 bool _alarm_schedule(void);
63
64 static void __free_scheduled_alarm(gpointer data, gpointer user_data)
65 {
66         if (data != NULL) {
67                 g_free(data);
68         }
69 }
70
71 bool _clear_scheduled_alarm_list()
72 {
73
74         g_slist_foreach(g_scheduled_alarm_list, __free_scheduled_alarm, NULL);
75         g_slist_free(g_scheduled_alarm_list);
76
77         g_scheduled_alarm_list = NULL;
78
79         return true;
80 }
81
82 bool _init_scheduled_alarm_list()
83 {
84         _clear_scheduled_alarm_list();
85
86         return true;
87 }
88
89 bool _add_to_scheduled_alarm_list(__alarm_info_t *__alarm_info)
90 {
91 /*
92  *      20080328. Sewook Park(sewook7.park@samsung.com)
93  *      When multiple alarms are expired at same time, dbus rpc call for alarm
94  *      ui should be invoked first.(Ui conflicting manager cannot manage the 
95  *      different kinds of alarm popups(wake up alarm/org alarm) correctly, 
96  *      when they are displayed at same time)So when arranging the schedule 
97  *      alarm list, wake up alarm element is located ahead.
98  */
99
100         bool prior = false;
101         gint count = 0;
102         GSList *iter = NULL;
103         __scheduled_alarm_t *alarm = NULL;
104         __scheduled_alarm_t *entry = NULL;
105
106         alarm = g_malloc(sizeof(__scheduled_alarm_t));
107         if (alarm == NULL) {
108                 return false;
109         }
110
111         alarm->used = true;
112         alarm->alarm_id = __alarm_info->alarm_id;
113         alarm->pid = __alarm_info->pid;
114         alarm->__alarm_info = __alarm_info;
115
116         SECURE_LOGD("%s :alarm->pid =%d, app_service_name=%s(%u)\n",
117                             __FUNCTION__, alarm->pid,
118                         g_quark_to_string(alarm->
119                         __alarm_info->quark_app_service_name),
120                             alarm->__alarm_info->quark_app_service_name);
121
122         if (alarm->__alarm_info->quark_app_service_name !=
123             g_quark_from_string(WAKEUP_ALARM_APP_ID)) {
124                 g_scheduled_alarm_list =
125                     g_slist_append(g_scheduled_alarm_list, alarm);
126                 return true;
127         } else {
128                 for (iter = g_scheduled_alarm_list; iter != NULL;
129                      iter = g_slist_next(iter)) {
130                         count++;
131                         entry = iter->data;
132                         if (entry->__alarm_info->quark_app_service_name !=
133                             g_quark_from_string(WAKEUP_ALARM_APP_ID)) {
134                                 prior = true;
135                                 break;
136                         }
137                 }
138
139                 if (!prior) {
140                         g_scheduled_alarm_list =
141                             g_slist_append(g_scheduled_alarm_list, alarm);
142                         ALARM_MGR_LOG_PRINT(
143                             "appended : prior is %d\tcount is %d\n", prior,
144                              count);
145                 } else {
146                         g_scheduled_alarm_list =
147                             g_slist_insert(g_scheduled_alarm_list, alarm,
148                                            count - 1);
149                         ALARM_MGR_LOG_PRINT(
150                             "appended : prior is %d\tcount is %d\n", prior,
151                              count);
152                 }
153         }
154
155         return true;
156 }
157
158 bool _remove_from_scheduled_alarm_list(int pid, alarm_id_t alarm_id)
159 {
160         bool result = false;
161         GSList *iter = NULL;
162         __scheduled_alarm_t *alarm = NULL;
163
164         for (iter = g_scheduled_alarm_list; iter != NULL;
165              iter = g_slist_next(iter)) {
166                 alarm = iter->data;
167                 if (alarm->alarm_id == alarm_id) {
168                         g_scheduled_alarm_list =
169                             g_slist_remove(g_scheduled_alarm_list, iter->data);
170                         /*g_free(iter->data); */
171                         result = true;
172                         break;
173                 }
174
175         }
176
177         if (g_slist_length(g_scheduled_alarm_list) == 0) {
178                 alarm_context.c_due_time = -1;
179         }
180
181         return result;
182 }
183
184 static time_t __alarm_next_duetime_once(__alarm_info_t *__alarm_info)
185 {
186         time_t due_time = 0;
187         time_t current_time = 0;
188         struct tm duetime_tm;
189
190         alarm_info_t *alarm_info = &__alarm_info->alarm_info;
191         alarm_date_t *start = &alarm_info->start;
192
193         time(&current_time);
194         localtime_r(&current_time, &duetime_tm);
195         duetime_tm.tm_hour = start->hour;
196         duetime_tm.tm_min = start->min;
197         duetime_tm.tm_sec = start->sec;
198
199         if (start->year == 0 && start->month == 0 && start->day == 0)
200                 /*any date */  {
201                 due_time = mktime(&duetime_tm);
202                 if (!(due_time > current_time)) {
203                         due_time = due_time + 60 * 60 * 24;
204                 }
205         } else  /*specific date*/ {
206                 duetime_tm.tm_year = start->year - 1900;
207                 duetime_tm.tm_mon = start->month - 1;
208                 duetime_tm.tm_mday = start->day;
209                 due_time = mktime(&duetime_tm);
210         }
211
212         return due_time;
213
214 }
215
216 static time_t __alarm_next_duetime_repeat(__alarm_info_t *__alarm_info)
217 {
218         time_t due_time = 0;
219         time_t current_time = 0;
220         struct tm duetime_tm;
221
222         alarm_info_t *alarm_info = &__alarm_info->alarm_info;
223         alarm_date_t *start = &alarm_info->start;
224
225         time(&current_time);
226         /*localtime_r(&current_time, &duetime_tm); */
227
228         duetime_tm.tm_hour = start->hour;
229         duetime_tm.tm_min = start->min;
230         duetime_tm.tm_sec = start->sec;
231
232         duetime_tm.tm_year = start->year - 1900;
233         duetime_tm.tm_mon = start->month - 1;
234         duetime_tm.tm_mday = start->day;
235         duetime_tm.tm_isdst = -1;
236
237         due_time = mktime(&duetime_tm);
238
239         while (__alarm_info->start > due_time || current_time >= due_time) {
240                 due_time += alarm_info->mode.u_interval.interval;
241
242                 /* due_time = mktime(&duetime_tm); */
243         }
244         localtime_r(&due_time, &duetime_tm);
245
246         start->year = duetime_tm.tm_year + 1900;
247         start->month = duetime_tm.tm_mon + 1;
248         start->day = duetime_tm.tm_mday;
249         start->hour = duetime_tm.tm_hour;
250         start->min = duetime_tm.tm_min;
251         start->sec = duetime_tm.tm_sec;
252
253         return due_time;
254
255 }
256
257 static time_t __alarm_next_duetime_annually(__alarm_info_t *__alarm_info)
258 {
259         time_t due_time = 0;
260         time_t current_time = 0;
261         struct tm duetime_tm;
262
263         alarm_info_t *alarm_info = &__alarm_info->alarm_info;
264         alarm_date_t *start = &alarm_info->start;
265
266         time(&current_time);
267         localtime_r(&current_time, &duetime_tm);
268         duetime_tm.tm_hour = start->hour;
269         duetime_tm.tm_min = start->min;
270         duetime_tm.tm_sec = start->sec;
271
272         if (start->year != 0) {
273                 duetime_tm.tm_year = start->year - 1900;
274         }
275
276         duetime_tm.tm_mon = start->month - 1;
277         duetime_tm.tm_mday = start->day;
278
279         due_time = mktime(&duetime_tm);
280
281         while (__alarm_info->start > due_time || current_time > due_time) {
282                 duetime_tm.tm_year += 1;
283                 due_time = mktime(&duetime_tm);
284         }
285
286         return due_time;
287
288 }
289
290 static time_t __alarm_next_duetime_monthly(__alarm_info_t *__alarm_info)
291 {
292         time_t due_time = 0;
293         time_t current_time = 0;
294         struct tm duetime_tm;
295
296         alarm_info_t *alarm_info = &__alarm_info->alarm_info;
297         alarm_date_t *start = &alarm_info->start;
298
299         time(&current_time);
300         localtime_r(&current_time, &duetime_tm);
301         duetime_tm.tm_hour = start->hour;
302         duetime_tm.tm_min = start->min;
303         duetime_tm.tm_sec = start->sec;
304
305         if (start->year != 0) {
306                 duetime_tm.tm_year = start->year - 1900;
307         }
308
309         if (start->month != 0) {
310
311                 duetime_tm.tm_mon = start->month - 1;
312         }
313
314         duetime_tm.tm_mday = start->day;
315
316         due_time = mktime(&duetime_tm);
317
318         while (__alarm_info->start > due_time || current_time > due_time) {
319                 duetime_tm.tm_mon += 1;
320                 if (duetime_tm.tm_mon == 12) {
321                         duetime_tm.tm_mon = 0;
322                         duetime_tm.tm_year += 1;
323                 }
324                 due_time = mktime(&duetime_tm);
325         }
326
327         return due_time;
328
329 }
330
331 static time_t __alarm_next_duetime_weekly(__alarm_info_t *__alarm_info)
332 {
333         time_t due_time = 0;
334         time_t current_time = 0;
335         struct tm duetime_tm;
336         struct tm tmp_tm;
337         int wday;
338         int current_dst = 0;
339
340         alarm_info_t *alarm_info = &__alarm_info->alarm_info;
341         alarm_date_t *start = &alarm_info->start;
342
343         alarm_mode_t *mode = &alarm_info->mode;
344
345         time(&current_time);
346         localtime_r(&current_time, &duetime_tm);
347         wday = duetime_tm.tm_wday;
348         duetime_tm.tm_hour = start->hour;
349         duetime_tm.tm_min = start->min;
350         duetime_tm.tm_sec = start->sec;
351         current_dst = duetime_tm.tm_isdst;
352         duetime_tm.tm_isdst = -1;
353
354         if (__alarm_info->start != 0) {
355
356                 if (__alarm_info->start >= current_time)        /*case 1*/ {
357                         duetime_tm.tm_year = start->year - 1900;
358                         duetime_tm.tm_mon = start->month - 1;
359                         duetime_tm.tm_mday = start->day;
360                 } else  /*case 3*/ {
361                         /*don't need to be set */
362                 }
363         }
364         /*case 4 */
365
366         due_time = mktime(&duetime_tm);
367
368         if( current_dst == 1 && due_time < current_time) {
369                 duetime_tm.tm_isdst = 0;
370                 due_time = mktime(&duetime_tm);
371                 localtime_r(&due_time, &tmp_tm);
372                 SECURE_LOGD("%d %d %d : %d", tmp_tm.tm_hour, tmp_tm.tm_min, tmp_tm.tm_sec, due_time);
373                 if( tmp_tm.tm_hour != start->hour || tmp_tm.tm_min != start->min || tmp_tm.tm_sec != start->sec ) {
374                         duetime_tm.tm_hour = start->hour;
375                         duetime_tm.tm_min = start->min;
376                         duetime_tm.tm_sec = start->sec;
377                         duetime_tm.tm_isdst = -1;
378                         due_time = mktime(&duetime_tm);
379                         SECURE_LOGD("%d",due_time); 
380                 }
381         }
382         wday = duetime_tm.tm_wday;
383         SECURE_LOGD("current_time(%d) due_time(%d)", current_time, due_time);
384
385         /* CQ defect(72810) : only one time alarm function is not working 
386            under all recurrence_disabled. */
387         if (due_time > current_time && mode->u_interval.day_of_week == 0)
388                 return due_time;
389
390         if (current_time >= due_time
391             || !(mode->u_interval.day_of_week & 1 << wday)) {
392                 int day = wday + 1;
393                 int interval = 1;
394                 /*this week */
395
396                 if (day == 7) {
397                         day = 0;
398                 }
399
400                 while (!(mode->u_interval.day_of_week & 1 << day)
401                        && interval < 8) {
402                         day += 1;
403                         interval += 1;
404
405                         if (day == 7) {
406                                 day = 0;
407                         }
408
409                 }
410                 ALARM_MGR_LOG_PRINT("interval : %d\n", interval);
411                 due_time += 60 * 60 * 24 * interval;
412         }
413
414         return due_time;
415
416 }
417
418 time_t _alarm_next_duetime(__alarm_info_t *__alarm_info)
419 {
420         int is_dst=0;
421         time_t current_time = 0;
422         time_t due_time = 0;
423         struct tm *cur_tm = NULL ;
424         struct tm *due_tm = NULL ;
425
426         alarm_info_t *alarm_info = &__alarm_info->alarm_info;
427         alarm_mode_t *mode = &alarm_info->mode;
428
429         time(&current_time);
430         cur_tm = localtime(&current_time);
431         if (cur_tm->tm_isdst > 0)
432                 is_dst = 1;
433
434         ALARM_MGR_LOG_PRINT("mode->repeat is %d\n", mode->repeat);
435
436         if (mode->repeat == ALARM_REPEAT_MODE_ONCE) {
437                 due_time = __alarm_next_duetime_once(__alarm_info);
438         } else if (mode->repeat == ALARM_REPEAT_MODE_REPEAT) {
439                 due_time = __alarm_next_duetime_repeat(__alarm_info);
440         } else if (mode->repeat == ALARM_REPEAT_MODE_ANNUALLY) {
441                 due_time = __alarm_next_duetime_annually(__alarm_info);
442         } else if (mode->repeat == ALARM_REPEAT_MODE_MONTHLY) {
443                 due_time = __alarm_next_duetime_monthly(__alarm_info);
444         } else if (mode->repeat == ALARM_REPEAT_MODE_WEEKLY) {
445                 due_time = __alarm_next_duetime_weekly(__alarm_info);
446         } else {
447                 ALARM_MGR_EXCEPTION_PRINT("repeat mode(%d) is wrong\n",
448                                           mode->repeat);
449                 return 0;
450         }
451
452         if (mode->repeat != ALARM_REPEAT_MODE_WEEKLY) {
453                 due_tm = localtime(&due_time);
454                 if (is_dst==0 && due_tm->tm_isdst==1){
455                                 ALARM_MGR_LOG_PRINT("DST alarm found, enable\n");
456                                 due_tm->tm_hour = due_tm->tm_hour - DST_TIME_DIFF;
457                 } else if (is_dst==1 && due_tm->tm_isdst==0){
458                                 ALARM_MGR_LOG_PRINT("DST alarm found. disable\n");
459                                 due_tm->tm_hour = due_tm->tm_hour + DST_TIME_DIFF;
460                 }
461                 due_time = mktime(due_tm);
462         }
463
464         ALARM_MGR_LOG_PRINT("due_time %d\n", due_time);
465
466         if (__alarm_info->end != 0 && __alarm_info->end < due_time) {
467                 ALARM_MGR_LOG_PRINT("due time > end time");
468                 __alarm_info->due_time = 0;
469                 return 0;
470         }
471         __alarm_info->due_time = due_time;
472
473         return due_time;
474
475 }
476
477 static bool __find_next_alarm_to_be_scheduled(time_t *min_due_time)
478 {
479         time_t current_time;
480         time_t min_time = -1;
481         time_t due_time;
482         GSList *iter = NULL;
483         __alarm_info_t *entry = NULL;
484
485         time(&current_time);
486
487         for (iter = alarm_context.alarms; iter != NULL;
488              iter = g_slist_next(iter)) {
489                 entry = iter->data;
490                 due_time = entry->due_time;
491
492                 double interval = 0;
493
494                 SECURE_LOGD("alarm[%d] with duetime(%u) at current(%u) pid: (%d)\n",
495                         entry->alarm_id, due_time, current_time, entry->pid);
496                 if (due_time == 0)      /*0 means this alarm 
497                         has been disabled*/ {
498                         continue;
499                 }
500
501                 interval = difftime(due_time, current_time);
502
503                 if (interval <= 0)      /*2008.08.06 when the alarm expires, 
504                         it may makes an error.*/ {
505                         ALARM_MGR_LOG_PRINT("this may be error.. alarm[%d]\n",
506                                             entry->alarm_id);
507                         continue;
508                 }
509
510                 interval = difftime(due_time, min_time);
511
512                 if ((interval < 0) || min_time == -1) {
513                         min_time = due_time;
514                 }
515
516         }
517
518         *min_due_time = min_time;
519         return true;
520 }
521
522 #ifdef __ALARM_BOOT
523 /*alarm boot*/
524 static bool __find_next_alarm_to_be_scheduled_power_on(time_t *min_due_time)
525 {
526         time_t current_time;
527         time_t min_time = -1;
528         time_t due_time;
529         struct tm duetime_tm;
530         __alarm_info_t *entry = NULL;
531         struct tm *temp_info;
532         GSList *iter = NULL;
533
534         time(&current_time);
535
536         tzset();                /*for portability tzset() need to be called
537                                 before locatime_r,refer manpage localtime_r*/
538         temp_info = localtime_r(&current_time, &duetime_tm);
539
540         if (temp_info != NULL)
541                 ALARM_MGR_LOG_PRINT
542                     ("__find_next_alarm_to_be_scheduled_power_on "
543                      ": %d %d %d %d %d\n", temp_info->tm_year,
544                      temp_info->tm_mon, temp_info->tm_mday, temp_info->tm_hour,
545                      temp_info->tm_min);
546
547         for (iter = alarm_context.alarms; iter != NULL;
548              iter = g_slist_next(iter)) {
549                 entry = iter->data;
550                 due_time = entry->due_time;
551
552                 double interval = 0;
553
554                 SECURE_LOGD("%s\n", g_quark_to_string(
555                         entry->quark_dst_service_name));
556
557                 /*if(entry->quark_dst_service_name  != g_quark_from_string
558                    (WAKEUP_ALARM_APP_ID)) continue; */
559
560                 if (strcmp
561                     (g_quark_to_string(entry->quark_dst_service_name),
562                      WAKEUP_ALARM_APP_ID) != 0)
563                         continue;
564
565                 ALARM_MGR_LOG_PRINT(
566                     "alarm[%d] with duetime(%u) at current(%u)\n",
567                      entry->alarm_id, due_time, current_time);
568                 if (due_time == 0)      /* 0 means this alarm has 
569                         been disabled*/ {
570                         continue;
571                 }
572
573                 interval = difftime(due_time, current_time);
574
575                 if (interval <= 0)      /*2008.08.06 when the alarm expires, 
576                 it may makes an error.*/ {
577                         ALARM_MGR_LOG_PRINT("this may be error.. alarm[%d]\n",
578                                             entry->alarm_id);
579                         continue;
580                 }
581
582                 interval = difftime(due_time, min_time);
583
584                 if ((interval < 0) || min_time == -1) {
585                         min_time = due_time;
586                 }
587
588         }
589
590         *min_due_time = min_time;
591         return true;
592 }
593 #endif
594
595 bool _alarm_schedule()
596 {
597         time_t current_time;
598         time_t due_time;
599         time_t min_time;
600         GSList *iter;
601         __alarm_info_t *entry = NULL;
602
603         int min = -1;
604
605         time(&current_time);
606
607         min_time = 0;
608
609         __find_next_alarm_to_be_scheduled(&min_time);
610
611         if (min_time == -1) {
612                 ALARM_MGR_LOG_PRINT("[alarm-server][schedule]: There is no "
613                                     "alarm to be scheduled..\n");
614         } else {
615                 for (iter = alarm_context.alarms; iter != NULL;
616                      iter = g_slist_next(iter)) {
617                         entry = iter->data;
618                         due_time = entry->due_time;
619
620                         if (due_time == min_time) {
621                                 _add_to_scheduled_alarm_list(entry);
622                         }
623
624         }
625
626                 _alarm_set_timer(&alarm_context, alarm_context.timer, min_time,
627                                  min);
628
629         }
630
631         return true;
632 }
633
634 #ifdef __ALARM_BOOT
635 /*alarm boot*/
636 bool _alarm_find_mintime_power_on(time_t *min_time)
637 {
638
639         __find_next_alarm_to_be_scheduled_power_on(min_time);
640
641         if ((*min_time) == -1) {
642                 ALARM_MGR_LOG_PRINT("[alarm-server][schedule]: There is no "
643                                     "alarm boot to be scheduled..\n");
644                 return false;
645         }
646
647         return true;
648 }
649 #endif