2 // Power savings by syncronizing start points of periodic network activitiy
3 // frequently triggered by applications during sleep and/or active state.
8 #include"alarm-internal.h"
10 static bool g_white_list = true;
11 static bool g_white_list_plus_auto_add = false;
12 static bool g_app_sync_on = false;
14 #define SYNC_COPRIME_VALUE 60 // [s] 1 min
15 #define SYNC_MIN_VALUE (5*60) // [s] 5 min
16 #define SYNC_MAX_VALUE (4*60*60) // [s] 4 hr
17 #define INTERVAL_HOUR (60*60)
18 #define INTERVAL_HALF_DAY (12*60*60)
20 #define MAX_INT_VALUE 2147483647
21 #define APP_SYNC_LOG 1
23 #define CSC_BUFFER_SIZE 256
25 // [ms] global unit interval; Greatest Common Divisor of RepeatIntervals interested
26 static int g_interval_gcd = SYNC_MAX_VALUE;
28 static GSList* g_adjustable_repeating_alarms = NULL;
29 static GSList* g_target_packages = NULL;
30 //static GSList* g_csc_packages = NULL;
32 static int __gcd(int first_value, int second_value)
34 if (second_value == 0)
37 return __gcd(second_value, first_value % second_value);
40 void __convert_time_to_alarm_date_t(time_t time, alarm_date_t* alarm_date)
43 localtime_r(&time, &time_tm);
45 alarm_date->year = time_tm.tm_year + 1900;
46 alarm_date->month = time_tm.tm_mon + 1;
47 alarm_date->day = time_tm.tm_mday;
48 alarm_date->hour = time_tm.tm_hour;
49 alarm_date->min = time_tm.tm_min;
50 alarm_date->sec = time_tm.tm_sec;
53 void __convert_alarm_date_t_to_time(alarm_date_t* alarm_date, time_t* time)
55 struct tm alarm_tm = {0, };
57 alarm_tm.tm_year = alarm_date->year - 1900;
58 alarm_tm.tm_mon = alarm_date->month - 1;
59 alarm_tm.tm_mday = alarm_date->day;
61 alarm_tm.tm_hour = alarm_date->hour;
62 alarm_tm.tm_min = alarm_date->min;
63 alarm_tm.tm_sec = alarm_date->sec;
65 *time = mktime(&alarm_tm);
68 static int __compare_func(const char* a, const char* b)
70 if (0 == g_strcmp0(a, b)) {
77 static bool __sync_scheduler_look_for_non_adjustable_alarm(GSList* alarmList, __alarm_info_t* __alarm_info)
79 // ±âÁ¸ alarm ¸®½ºÆ®¿¡¼ µ¿ÀÏÇÑ alarm ÀÇ original alarm ½Ã°£ÀÌ ÇöÀç ¿äû½Ã°£°ú °°À¸¸é return ture;
81 GSList *gs_iter = NULL;
82 __alarm_info_t *entry = NULL;
84 for (gs_iter = alarmList; gs_iter != NULL;
85 gs_iter = g_slist_next(gs_iter)) {
87 entry = gs_iter->data;
89 if (__alarm_info->start == entry->start) {
90 if (!g_strcmp0(g_quark_to_string(__alarm_info->quark_app_unique_name), g_quark_to_string(entry->quark_app_unique_name)) &&
91 !g_strcmp0(g_quark_to_string(__alarm_info->quark_app_service_name), g_quark_to_string(entry->quark_app_service_name)) &&
92 !g_strcmp0(g_quark_to_string(__alarm_info->quark_dst_service_name), g_quark_to_string(entry->quark_dst_service_name)) &&
93 !g_strcmp0(g_quark_to_string(__alarm_info->quark_bundle), g_quark_to_string(entry->quark_bundle))) {
94 ALARM_MGR_LOG_PRINT("This is non adjustable alarm");
103 static int __sync_scheduler_calculate_gcd_of_repeat_intervals(int interval_old, int interval_new)
105 int new_interval_gcd = interval_old;
106 int temp_interval_gcd = __gcd(interval_old, interval_new);
108 if (temp_interval_gcd > SYNC_COPRIME_VALUE) {
109 if ((temp_interval_gcd % SYNC_MIN_VALUE) == 0) {
110 new_interval_gcd = temp_interval_gcd;
114 return new_interval_gcd;
117 // list Áß¿¡¼ interval ÀÌ °°Àº °¡Àå ÃÖ½ÅÀÇ alarm À» ¸®ÅÏ , °°Àº °ÍÀÌ ¾øÀ¸¸é ¹è¼ö interval À» °¡Áø alarm ÀÌ ¸®ÅÏ
118 static __alarm_info_t* __sync_scheduler_time_to_next_repeating_alarm(int interval)
120 int next_alarm = MAX_INT_VALUE;
121 int next_alarm_with_same_interval = MAX_INT_VALUE;
122 __alarm_info_t* alarm_result = NULL;
123 __alarm_info_t* alarm_result_with_same_interval = NULL;
124 GSList *gs_iter = NULL;
125 __alarm_info_t *entry = NULL;
127 bool is_int_same_as_gcd = (interval == g_interval_gcd);
131 for (gs_iter = g_adjustable_repeating_alarms; gs_iter != NULL;
132 gs_iter = g_slist_next(gs_iter)) {
134 entry = gs_iter->data;
136 __convert_alarm_date_t_to_time(&entry->alarm_info.start, &when);
138 if (now_rtc < (when + g_interval_gcd)) { // Accept ealier time of one GCD interval
139 // Look for the alarm with same interval as GCD
140 if (is_int_same_as_gcd) {
141 if (when < next_alarm) {
143 alarm_result = entry;
146 // Look for the alarm with same interval or multiples of interval
148 if (entry->alarm_info.mode.u_interval.interval != 0) {
149 if (entry->alarm_info.mode.u_interval.interval == interval) {
150 if (when < next_alarm_with_same_interval) {
151 next_alarm_with_same_interval = when;
152 alarm_result_with_same_interval = entry;
155 else if (((entry->alarm_info.mode.u_interval.interval > interval) && (entry->alarm_info.mode.u_interval.interval % interval == 0)) ||
156 ((entry->alarm_info.mode.u_interval.interval < interval) && (interval % entry->alarm_info.mode.u_interval.interval == 0))) {
157 if (when < next_alarm) {
159 alarm_result = entry;
166 // Old alarms eventually left must be removed.
167 if ((when + INTERVAL_HALF_DAY) < now_rtc) {
168 g_adjustable_repeating_alarms =
169 g_slist_remove(g_adjustable_repeating_alarms, gs_iter->data);
176 // Next alarm with same interval value goes first.
177 if (alarm_result_with_same_interval != NULL)
178 alarm_result = alarm_result_with_same_interval;
184 //inputDistance = gcd or alarm's repeated interval
185 static void __sync_scheduler_adjust_alarm_time(__alarm_info_t* __alarm_info, int input_distance)
187 int next_alarm_when = MAX_INT_VALUE;
188 int distance = input_distance;
191 // Retreve the nearest alarm with same RepeatInterval or multiples of RepeatInterval
192 if (__alarm_info->alarm_info.mode.u_interval.interval != g_interval_gcd) {
193 __alarm_info_t* a = __sync_scheduler_time_to_next_repeating_alarm(__alarm_info->alarm_info.mode.u_interval.interval);
195 __convert_alarm_date_t_to_time(&a->alarm_info.start, (time_t*)&next_alarm_when);
196 // Same RepeatInterval or co-prime RepeatInterval with GCD
197 if ((a->alarm_info.mode.u_interval.interval == __alarm_info->alarm_info.mode.u_interval.interval) ||
198 (__alarm_info->alarm_info.mode.u_interval.interval % g_interval_gcd != 0)) {
199 distance = __alarm_info->alarm_info.mode.u_interval.interval;
201 // Multiples of RepeatInterval
203 distance = __gcd(__alarm_info->alarm_info.mode.u_interval.interval, a->alarm_info.mode.u_interval.interval);
207 // Retreve the nearest alarm using GCD based RepeatInterval
208 if (next_alarm_when == MAX_INT_VALUE) {
209 __alarm_info_t* a = __sync_scheduler_time_to_next_repeating_alarm(g_interval_gcd);
211 __convert_alarm_date_t_to_time(&a->alarm_info.start, (time_t*)&next_alarm_when);
215 if (next_alarm_when != MAX_INT_VALUE) {
216 ALARM_MGR_LOG_PRINT("next: %d", next_alarm_when);
218 // If the requested alarm is after the very next alarm to be triggered,
219 // place it somewhere aligned with the point that is one of multiples of
220 // requested distance and nearest to the very next alarm.
221 if (next_alarm_when <= __alarm_info->start) {
222 int count = (__alarm_info->start - next_alarm_when) / distance;
223 new_time = next_alarm_when + distance * count;
225 // If the requested alarm is before the very next alarm to be triggered,
226 // find the earlier aligned point around the requested alarm
228 int count = (next_alarm_when - __alarm_info->start) / distance;
229 count++; // move to one more earlier point
230 new_time = next_alarm_when - distance * count;
233 __convert_time_to_alarm_date_t(new_time, &__alarm_info->alarm_info.start);
234 ALARM_MGR_EXCEPTION_PRINT("AppSync original time : %s", ctime(&__alarm_info->start));
235 ALARM_MGR_EXCEPTION_PRINT("AppSync change time : %s", ctime(&new_time));
238 ALARM_MGR_LOG_PRINT("next: MAX_INT_VALUE");
242 //csc ¿¡ ÀÇÇØ targetPackageList °¡ ±¸¼ºµÈ »óÅ¿¡¼ white list ¿¡ ÇØ´ç package Á¸Àç È®ÀÎ
243 // target_package_list ¿¡¼ appid °¡ Á¸ÀçÇϸé return true;
244 static bool __sync_scheduler_look_for_target_package(GSList* target_package_list, char* appid)
246 GSList* list = g_slist_find_custom(target_package_list, appid, (GCompareFunc)__compare_func);
253 SECURE_LOGD("%s is NOT found in the app sync white list", appid);
256 SECURE_LOGD("%s is found in the app sync white list", appid);
261 bool _sync_scheduler_app_sync_on()
263 return g_app_sync_on;
266 // CSC ¿Í Account ·Î ºÎÅÍ g_target_packages ±¸¼º
267 void _sync_scheduler_init()
271 char cscAppData[CSC_BUFFER_SIZE] = {0,};
272 char** cscAppSyncList = NULL;
274 g_target_packages = g_slist_alloc();
276 // Check the AppSync feature frm CSC
278 if (csc_feature_get_bool(CSC_FEATURE_DEF_BOOL_FRAMEWORK_APP_SYNC_DISABLE) == CSC_FEATURE_BOOL_FALSE) {
282 g_app_sync_on = true;
284 // TODO: Get app sync data from csc file (cscAppData)
285 //ret = csc_feature_get_str(CSC_FEATURE_DEF_STR_ALARM_MANAGER_APP_SYNC, cscAppData, CSC_BUFFER_SIZE);
287 cscAppSyncList = g_strsplit(cscAppData, ",", 0);
289 // Check the whitelist mode
290 if (0 == g_strcmp0(*cscAppSyncList, "whitelist")) {
292 // Load Whitelist of target packages
293 for (cscAppSyncList++; NULL != *cscAppSyncList; cscAppSyncList++) {
294 ALARM_MGR_LOG_PRINT("CSC data, %s", *cscAppSyncList);
295 g_target_packages = g_slist_append(g_target_packages, g_strdup(*cscAppSyncList));
297 } else if (0 == g_strcmp0(*cscAppSyncList, "blacklist")) {
299 // Disable Whitelist depending on Blacklist selection.
300 g_white_list = false;
301 g_white_list_plus_auto_add = false;
303 // Load Blacklist of target packages
304 for (cscAppSyncList++; NULL != *cscAppSyncList; cscAppSyncList++) {
305 ALARM_MGR_LOG_PRINT("CSC data, %s", *cscAppSyncList);
306 g_target_packages = g_slist_append(g_target_packages, g_strdup(*cscAppSyncList));
308 } else { // default lists
309 //g_target_packages = g_slist_append(g_target_packages, "com.samsung.helloworld");
313 g_strfreev(cscAppSyncList);
316 GSList *gs_iter = NULL;
318 for (gs_iter = g_target_packages; gs_iter != NULL;
319 gs_iter = g_slist_next(gs_iter), i++) {
320 SECURE_LOGD("target package [%d] : %s",
325 ALARM_MGR_EXCEPTION_PRINT("App sync is disabled", *cscAppSyncList);
329 void _sync_scheduler_repeating_alarms(__alarm_info_t* __alarm_info)
333 // true ¸é ±âÁ¸°ú µ¿ÀÏÇÑ alarm ¿äûÀ̹ǷÎ, ¹«½Ã
334 bool is_non_adjustable_alarm = __sync_scheduler_look_for_non_adjustable_alarm(
335 g_adjustable_repeating_alarms, __alarm_info);
337 // Remove this alarm if already scheduled.
338 // replace pre existed alarm and remove from the appsync list
339 //removeLocked(alarm.operation);
341 char appid[255] = {0,};
342 ret = aul_app_get_appid_bypid(__alarm_info->pid, appid, sizeof(appid));
344 ALARM_MGR_LOG_PRINT("Cannot get the appid");
346 if ( (is_non_adjustable_alarm == false) &&
347 (__sync_scheduler_look_for_target_package(g_target_packages, appid) == g_white_list)) {
349 if ((__alarm_info->alarm_info.mode.repeat == ALARM_REPEAT_MODE_REPEAT) &&
350 (__alarm_info->alarm_info.mode.u_interval.interval >= SYNC_MIN_VALUE) &&
351 (__alarm_info->alarm_info.mode.u_interval.interval <= SYNC_MAX_VALUE)) {
352 g_interval_gcd = __sync_scheduler_calculate_gcd_of_repeat_intervals(g_interval_gcd,
353 __alarm_info->alarm_info.mode.u_interval.interval);
355 // If new RepeatInterval belongs to multiples of gIntervalGcd,
356 // the alarm will start at the nearest scheduling point
357 // around the requested alarm time. The scheduling points are
358 // calculated on the unit of gIntervalGcd from the next repeating alarm
360 if (__alarm_info->alarm_info.mode.u_interval.interval % g_interval_gcd == 0) {
361 __sync_scheduler_adjust_alarm_time(__alarm_info, g_interval_gcd);
362 g_adjustable_repeating_alarms = g_slist_append(g_adjustable_repeating_alarms, __alarm_info);
364 // If not, the alarm will start at the nearest scheduling point around
365 // the requested alarm time. The scheduling points are calculated on
366 // the unit of alarm.repeatInterval from the next repeating alarm to be triggered.
368 __sync_scheduler_adjust_alarm_time(__alarm_info, __alarm_info->alarm_info.mode.u_interval.interval);
371 else if (__alarm_info->alarm_info.mode.repeat == ALARM_REPEAT_MODE_ONCE) {
373 // The package of the alarms registered to account manager could be adjusted
376 int distance_to_alarm = __alarm_info->start - now;
377 int sync_tolerance_value = (distance_to_alarm >= (INTERVAL_HOUR - SYNC_MIN_VALUE)) ? 60 : 10; // [s] 30s or 5s
378 int distance_to_alarm_rounded = (int) round((double)distance_to_alarm/(double)sync_tolerance_value) * sync_tolerance_value;
380 // Optimize code for com.android.email is omitted.
381 // Optimize code for com.google.android.gsf is omitted.
383 // Adjust the alarm that occurs periodically in the range
384 // between SYNC_MIN_VALUE and SYNC_MAX_VALUE
385 if ((distance_to_alarm_rounded <= SYNC_MAX_VALUE) &&
386 (distance_to_alarm_rounded >= SYNC_MIN_VALUE) &&
387 (distance_to_alarm_rounded % SYNC_MIN_VALUE == 0)) {
388 __alarm_info_t* new_alarm;
389 g_interval_gcd = __sync_scheduler_calculate_gcd_of_repeat_intervals(g_interval_gcd, distance_to_alarm_rounded);
390 new_alarm = malloc(sizeof(__alarm_info_t));
392 memcpy(new_alarm, __alarm_info, sizeof(__alarm_info_t));
393 new_alarm->alarm_info.mode.u_interval.interval = distance_to_alarm_rounded;
394 __sync_scheduler_adjust_alarm_time(new_alarm, g_interval_gcd);
395 g_adjustable_repeating_alarms = g_slist_append(g_adjustable_repeating_alarms, new_alarm);
396 memcpy(&(__alarm_info->alarm_info.start), &(new_alarm->alarm_info.start), sizeof(alarm_date_t));
400 GSList *gs_iter = NULL;
401 __alarm_info_t *entry = NULL;
404 struct tm duetime_tm;
407 for (gs_iter = g_adjustable_repeating_alarms; gs_iter != NULL;
408 gs_iter = g_slist_next(gs_iter), i++) {
410 entry = gs_iter->data;
411 start = &entry->alarm_info.start;
413 duetime_tm.tm_hour = start->hour;
414 duetime_tm.tm_min = start->min;
415 duetime_tm.tm_sec = start->sec;
417 duetime_tm.tm_year = start->year - 1900;
418 duetime_tm.tm_mon = start->month - 1;
419 duetime_tm.tm_mday = start->day;
421 due_time = mktime(&duetime_tm);
423 ALARM_MGR_LOG_PRINT("List[%d] : Interval %d Start %s",
424 i, entry->alarm_info.mode.u_interval.interval, ctime(&due_time));
427 ALARM_MGR_LOG_PRINT("Interval GCD : %d", g_interval_gcd);
431 void _sync_scheduler_remove_repeating_alarm(alarm_id_t alarm_id)
433 // __alarm_delete ÇÔ¼ö¿¡¼ È£Ãâ
434 //g_adjustable_repeating_alarms ¿¡¼ alarm »èÁ¦
435 GSList *gs_iter = NULL;
436 __alarm_info_t *entry = NULL;
438 for (gs_iter = g_adjustable_repeating_alarms; gs_iter != NULL;
439 gs_iter = g_slist_next(gs_iter)) {
440 entry = gs_iter->data;
442 if (entry->alarm_id == alarm_id) {
443 g_adjustable_repeating_alarms =
444 g_slist_remove(g_adjustable_repeating_alarms, gs_iter->data);