4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
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>
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #define _BSD_SOURCE /*localtime_r requires */
34 #include"alarm-internal.h"
35 #define DST_TIME_DIFF 1
37 extern __alarm_server_context_t alarm_context;
38 extern GSList *g_scheduled_alarm_list;
39 extern bool is_time_changed;
41 static time_t __alarm_next_duetime_once(__alarm_info_t *__alarm_info);
42 static time_t __alarm_next_duetime_repeat(__alarm_info_t *__alarm_info);
43 static time_t __alarm_next_duetime_annually(__alarm_info_t *__alarm_info);
44 static time_t __alarm_next_duetime_monthly(__alarm_info_t *__alarm_info);
45 static time_t __alarm_next_duetime_weekly(__alarm_info_t *__alarm_info);
46 static bool __find_next_alarm_to_be_scheduled(time_t *min_due_time);
47 bool _alarm_schedule(void);
49 bool _clear_scheduled_alarm_list()
51 g_slist_free_full(g_scheduled_alarm_list, g_free);
52 g_scheduled_alarm_list = NULL;
57 bool _init_scheduled_alarm_list()
59 _clear_scheduled_alarm_list();
64 bool _add_to_scheduled_alarm_list(__alarm_info_t *__alarm_info)
67 * 20080328. Sewook Park(sewook7.park@samsung.com)
68 * When multiple alarms are expired at same time, dbus rpc call for alarm
69 * ui should be invoked first.(Ui conflicting manager cannot manage the
70 * different kinds of alarm popups(wake up alarm/org alarm) correctly,
71 * when they are displayed at same time)So when arranging the schedule
72 * alarm list, wake up alarm element is located ahead.
78 __scheduled_alarm_t *alarm = NULL;
79 __scheduled_alarm_t *entry = NULL;
81 alarm = g_malloc(sizeof(__scheduled_alarm_t));
87 alarm->alarm_id = __alarm_info->alarm_id;
88 alarm->pid = __alarm_info->pid;
89 alarm->__alarm_info = __alarm_info;
91 SECURE_LOGD("%s :alarm->pid =%d, app_service_name=%s(%u)\n",
92 __FUNCTION__, alarm->pid,
93 g_quark_to_string(alarm->__alarm_info->quark_app_service_name),
94 alarm->__alarm_info->quark_app_service_name);
96 SECURE_LOGD("%s :target zone : [%s]\n", __FUNCTION__, g_quark_to_string(alarm->__alarm_info->zone));
97 alarm->__alarm_info->zone = __alarm_info->zone;
99 g_scheduled_alarm_list = g_slist_append(g_scheduled_alarm_list, alarm);
104 bool _remove_from_scheduled_alarm_list(int pid, alarm_id_t alarm_id, const char *zone)
108 __scheduled_alarm_t *alarm = NULL;
110 for (iter = g_scheduled_alarm_list; iter != NULL; iter = g_slist_next(iter)) {
113 if (strcmp(g_quark_to_string(alarm->__alarm_info->zone), zone) != 0)
116 if (alarm->alarm_id == alarm_id) {
117 g_scheduled_alarm_list = g_slist_remove(g_scheduled_alarm_list, iter->data);
124 if (g_slist_length(g_scheduled_alarm_list) == 0) {
125 alarm_context.c_due_time = -1;
131 static time_t __alarm_next_duetime_once(__alarm_info_t *__alarm_info)
134 time_t due_time_tmp = 0;
135 time_t current_time = 0;
136 struct tm duetime_tm;
140 alarm_info_t *alarm_info = &__alarm_info->alarm_info;
141 alarm_date_t *start = &alarm_info->start;
145 localtime_r(¤t_time, &duetime_tm);
146 duetime_tm.tm_hour = start->hour;
147 duetime_tm.tm_min = start->min;
148 duetime_tm.tm_sec = start->sec;
150 current_dst = duetime_tm.tm_isdst;
151 duetime_tm.tm_isdst = -1;
153 if (start->year == 0 && start->month == 0 && start->day == 0)
155 due_time = mktime(&duetime_tm);
156 if (!(due_time > current_time)) {
157 due_time = due_time + 60 * 60 * 24;
159 } else /*specific date*/ {
160 duetime_tm.tm_year = start->year - 1900;
161 duetime_tm.tm_mon = start->month - 1;
162 duetime_tm.tm_mday = start->day;
163 due_time = mktime(&duetime_tm);
166 if (due_time <= current_time) {
167 ALARM_MGR_EXCEPTION_PRINT("duetime is less than or equal to current time. current_dst = %d", current_dst);
168 duetime_tm.tm_isdst = 0; // DST off
170 due_time_tmp = mktime(&duetime_tm);
171 localtime_r(&due_time_tmp, &tmp_tm);
173 ALARM_MGR_LOG_PRINT("%d:%d:%d. duetime = %d", tmp_tm.tm_hour, tmp_tm.tm_min, tmp_tm.tm_sec, due_time);
174 if (tmp_tm.tm_hour == start->hour && tmp_tm.tm_min == start->min && tmp_tm.tm_sec == start->sec ) {
175 due_time = due_time_tmp;
176 ALARM_MGR_EXCEPTION_PRINT("due_time = %d",due_time);
180 localtime_r(&due_time, &tmp_tm);
181 ALARM_MGR_LOG_PRINT("%d:%d:%d. current_dst = %d, duetime_dst = %d", tmp_tm.tm_hour, tmp_tm.tm_min, tmp_tm.tm_sec, current_dst, tmp_tm.tm_isdst);
183 if (current_dst == 1 && tmp_tm.tm_isdst == 1 && tmp_tm.tm_hour == start->hour + 1) {
184 // When the calculated duetime is forwarded 1hour due to DST, Adds 23hours.
185 due_time += 60 * 60 * 23;
186 localtime_r(&due_time, &duetime_tm);
187 ALARM_MGR_EXCEPTION_PRINT("due_time = %d",due_time);
191 ALARM_MGR_EXCEPTION_PRINT("Final due_time = %d, %s",due_time, ctime(&due_time));
195 static time_t __alarm_next_duetime_repeat(__alarm_info_t *__alarm_info)
198 time_t current_time = 0;
199 struct tm duetime_tm;
201 alarm_info_t *alarm_info = &__alarm_info->alarm_info;
202 alarm_date_t *start = &alarm_info->start;
205 /*localtime_r(¤t_time, &duetime_tm); */
207 duetime_tm.tm_hour = start->hour;
208 duetime_tm.tm_min = start->min;
209 duetime_tm.tm_sec = start->sec;
211 duetime_tm.tm_year = start->year - 1900;
212 duetime_tm.tm_mon = start->month - 1;
213 duetime_tm.tm_mday = start->day;
214 duetime_tm.tm_isdst = -1;
216 if (alarm_info->alarm_type & ALARM_TYPE_PERIOD &&
217 alarm_info->mode.u_interval.interval > 0) {
218 /* For minimize 'while loop'
219 * Duetime should be "periodic_standard_time + (interval * x) >= current" */
220 time_t periodic_standard_time = _get_periodic_alarm_standard_time();
222 temp = (current_time - periodic_standard_time) / alarm_info->mode.u_interval.interval;
223 due_time = periodic_standard_time + (temp * alarm_info->mode.u_interval.interval);
225 due_time = mktime(&duetime_tm);
228 if (alarm_info->mode.u_interval.interval <= 0) {
229 ALARM_MGR_ASSERT_PRINT("Error! Despite repeated alarm, interval <= 0.\nalarm_id=%d, pid=%d, app_unique_name=%s, app_service_name=%s, start time=%d",
230 __alarm_info->alarm_id, __alarm_info->pid, g_quark_to_string(__alarm_info->quark_app_unique_name),
231 g_quark_to_string(__alarm_info->quark_app_service_name), __alarm_info->start);
233 while (__alarm_info->start > due_time || current_time > due_time || ((!is_time_changed) && (current_time == due_time))) {
234 due_time += alarm_info->mode.u_interval.interval;
238 if (due_time - current_time < 10)
239 due_time += alarm_info->mode.u_interval.interval;
241 localtime_r(&due_time, &duetime_tm);
243 start->year = duetime_tm.tm_year + 1900;
244 start->month = duetime_tm.tm_mon + 1;
245 start->day = duetime_tm.tm_mday;
246 start->hour = duetime_tm.tm_hour;
247 start->min = duetime_tm.tm_min;
248 start->sec = duetime_tm.tm_sec;
254 static time_t __alarm_next_duetime_annually(__alarm_info_t *__alarm_info)
257 time_t current_time = 0;
258 struct tm duetime_tm;
260 alarm_info_t *alarm_info = &__alarm_info->alarm_info;
261 alarm_date_t *start = &alarm_info->start;
264 localtime_r(¤t_time, &duetime_tm);
265 duetime_tm.tm_hour = start->hour;
266 duetime_tm.tm_min = start->min;
267 duetime_tm.tm_sec = start->sec;
269 if (start->year != 0) {
270 duetime_tm.tm_year = start->year - 1900;
273 duetime_tm.tm_mon = start->month - 1;
274 duetime_tm.tm_mday = start->day;
276 due_time = mktime(&duetime_tm);
278 while (__alarm_info->start > due_time || current_time > due_time || ((!is_time_changed) && (current_time == due_time))) {
279 duetime_tm.tm_year += 1;
280 due_time = mktime(&duetime_tm);
287 static time_t __alarm_next_duetime_monthly(__alarm_info_t *__alarm_info)
290 time_t current_time = 0;
291 struct tm duetime_tm;
293 alarm_info_t *alarm_info = &__alarm_info->alarm_info;
294 alarm_date_t *start = &alarm_info->start;
297 localtime_r(¤t_time, &duetime_tm);
298 duetime_tm.tm_hour = start->hour;
299 duetime_tm.tm_min = start->min;
300 duetime_tm.tm_sec = start->sec;
302 if (start->year != 0) {
303 duetime_tm.tm_year = start->year - 1900;
306 if (start->month != 0) {
307 duetime_tm.tm_mon = start->month - 1;
310 duetime_tm.tm_mday = start->day;
312 due_time = mktime(&duetime_tm);
314 while (__alarm_info->start > due_time || current_time > due_time || ((!is_time_changed) && (current_time == due_time))) {
315 duetime_tm.tm_mon += 1;
316 if (duetime_tm.tm_mon == 12) {
317 duetime_tm.tm_mon = 0;
318 duetime_tm.tm_year += 1;
320 due_time = mktime(&duetime_tm);
327 static time_t __alarm_next_duetime_weekly(__alarm_info_t *__alarm_info)
330 time_t current_time = 0;
331 struct tm duetime_tm;
338 alarm_info_t *alarm_info = &__alarm_info->alarm_info;
339 alarm_date_t *start = &alarm_info->start;
340 alarm_mode_t *mode = &alarm_info->mode;
344 localtime_r(¤t_time, &duetime_tm);
345 wday = duetime_tm.tm_wday;
346 duetime_tm.tm_hour = start->hour;
347 duetime_tm.tm_min = start->min;
348 duetime_tm.tm_sec = start->sec;
349 current_dst = duetime_tm.tm_isdst;
351 duetime_tm.tm_isdst = -1;
353 if (__alarm_info->start != 0) {
354 if (__alarm_info->start >= current_time) {
355 duetime_tm.tm_year = start->year - 1900;
356 duetime_tm.tm_mon = start->month - 1;
357 duetime_tm.tm_mday = start->day;
361 due_time = mktime(&duetime_tm);
362 localtime_r(&due_time, &tmp_tm);
363 ALARM_MGR_EXCEPTION_PRINT("%d:%d:%d. duetime = %d, isdst = %d", tmp_tm.tm_hour, tmp_tm.tm_min, tmp_tm.tm_sec, due_time, tmp_tm.tm_isdst);
365 if (due_time <= current_time) {
366 ALARM_MGR_EXCEPTION_PRINT("duetime is less than or equal to current time. current_dst = %d", current_dst);
367 duetime_tm.tm_isdst = 0;
369 due_time = mktime(&duetime_tm);
370 localtime_r(&due_time, &tmp_tm);
372 SECURE_LOGD("%d:%d:%d. duetime = %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 ALARM_MGR_EXCEPTION_PRINT("due_time = %d",due_time);
383 if (current_dst == 1 && tmp_tm.tm_isdst == 1 && tmp_tm.tm_hour == start->hour + 1) {
384 // When the calculated duetime is forwarded 1hour due to DST, Adds 23hours.
385 due_time += 60 * 60 * 23;
386 localtime_r(&due_time, &duetime_tm);
387 ALARM_MGR_EXCEPTION_PRINT("due_time = %d",due_time);
391 // Gets the dst before calculating the duedate as interval
392 localtime_r(&due_time, &before_tm);
393 SECURE_LOGD("before_dst = %d", before_tm.tm_isdst);
395 wday = duetime_tm.tm_wday;
397 ALARM_MGR_EXCEPTION_PRINT("current_time(%d) due_time(%d)", current_time, due_time);
399 /* CQ defect(72810) : only one time alarm function is not working
400 under all recurrence_disabled. */
401 if (due_time > current_time && mode->u_interval.day_of_week == 0) {
405 if (current_time > due_time || !(mode->u_interval.day_of_week & 1 << wday) || ((!is_time_changed) && (current_time == due_time))) {
414 while (!(mode->u_interval.day_of_week & 1 << day) && interval < 8) {
423 ALARM_MGR_LOG_PRINT("interval : %d\n", interval);
424 due_time += 60 * 60 * 24 * interval;
427 // Gets the dst after calculating the duedate as interval
428 localtime_r(&due_time, &after_tm);
429 SECURE_LOGD("after_dst = %d", after_tm.tm_isdst);
431 // Revise the duetime as difference in tm_isdst
432 if (before_tm.tm_isdst == 1 && after_tm.tm_isdst == 0) {
433 due_time += 60 * 60; // Add an hour
434 } else if (before_tm.tm_isdst == 0 && after_tm.tm_isdst == 1) {
435 due_time -= 60 * 60; // Subtract an hour
438 ALARM_MGR_EXCEPTION_PRINT("Final due_time = %d", due_time);
442 time_t _alarm_next_duetime(__alarm_info_t *__alarm_info)
445 time_t current_time = 0;
447 struct tm *cur_tm = NULL ;
448 struct tm *due_tm = NULL ;
450 alarm_info_t *alarm_info = &__alarm_info->alarm_info;
451 alarm_mode_t *mode = &alarm_info->mode;
454 cur_tm = localtime(¤t_time);
455 if (cur_tm && cur_tm->tm_isdst > 0)
458 ALARM_MGR_LOG_PRINT("mode->repeat is %d\n", mode->repeat);
460 if (mode->repeat == ALARM_REPEAT_MODE_ONCE) {
461 due_time = __alarm_next_duetime_once(__alarm_info);
462 } else if (mode->repeat == ALARM_REPEAT_MODE_REPEAT) {
463 due_time = __alarm_next_duetime_repeat(__alarm_info);
464 } else if (mode->repeat == ALARM_REPEAT_MODE_ANNUALLY) {
465 due_time = __alarm_next_duetime_annually(__alarm_info);
466 } else if (mode->repeat == ALARM_REPEAT_MODE_MONTHLY) {
467 due_time = __alarm_next_duetime_monthly(__alarm_info);
468 } else if (mode->repeat == ALARM_REPEAT_MODE_WEEKLY) {
469 due_time = __alarm_next_duetime_weekly(__alarm_info);
471 ALARM_MGR_EXCEPTION_PRINT("repeat mode(%d) is wrong\n",
476 if (mode->repeat != ALARM_REPEAT_MODE_WEEKLY && mode->repeat != ALARM_REPEAT_MODE_ONCE) {
477 due_tm = localtime(&due_time);
478 if (is_dst==0 && due_tm && due_tm->tm_isdst==1){
479 ALARM_MGR_LOG_PRINT("DST alarm found, enable\n");
480 due_tm->tm_hour = due_tm->tm_hour - DST_TIME_DIFF;
481 } else if (is_dst==1 && due_tm && due_tm->tm_isdst==0){
482 ALARM_MGR_LOG_PRINT("DST alarm found. disable\n");
483 due_tm->tm_hour = due_tm->tm_hour + DST_TIME_DIFF;
487 due_time = mktime(due_tm);
490 ALARM_MGR_EXCEPTION_PRINT("alarm_id: %d, next duetime: %d", __alarm_info->alarm_id, due_time);
492 if (__alarm_info->end != 0 && __alarm_info->end < due_time) {
493 ALARM_MGR_LOG_PRINT("due time > end time");
494 __alarm_info->due_time = 0;
497 __alarm_info->due_time = due_time;
502 static bool __find_next_alarm_to_be_scheduled(time_t *min_due_time)
505 time_t min_time = -1;
508 __alarm_info_t *entry = NULL;
512 for (iter = alarm_context.alarms; iter != NULL;
513 iter = g_slist_next(iter)) {
515 due_time = entry->due_time;
519 SECURE_LOGD("alarm[%d] with duetime(%u) at current(%u) pid: (%d)\n",
520 entry->alarm_id, due_time, current_time, entry->pid);
521 if (due_time == 0) /*0 means this alarm has been disabled*/ {
525 interval = difftime(due_time, current_time);
527 if (interval < 0) /*2008.08.06 when the alarm expires, it may makes an error.*/ {
528 ALARM_MGR_EXCEPTION_PRINT("The duetime of alarm(%d) is OVER.", entry->alarm_id);
532 interval = difftime(due_time, min_time);
534 if ((interval < 0) || min_time == -1) {
540 *min_due_time = min_time;
544 bool _alarm_schedule()
549 __alarm_info_t *entry = NULL;
551 __find_next_alarm_to_be_scheduled(&min_time);
553 if (min_time == -1) {
554 ALARM_MGR_LOG_PRINT("[alarm-server][schedule]: There is no alarm to be scheduled.");
556 for (iter = alarm_context.alarms; iter != NULL; iter = g_slist_next(iter)) {
558 due_time = entry->due_time;
560 if (due_time == min_time) {
561 _add_to_scheduled_alarm_list(entry);
564 _alarm_set_timer(&alarm_context, alarm_context.timer, min_time);