Support watchdog timer
[platform/core/appfw/app-core.git] / src / base / appcore_base.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #define _GNU_SOURCE
19
20 #include <stdbool.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <malloc.h>
28 #include <locale.h>
29 #include <libintl.h>
30 #include <linux/limits.h>
31 #include <glib.h>
32 #include <gio/gio.h>
33 #include <sys/time.h>
34 #include <dlfcn.h>
35 #include <vconf.h>
36 #include <aul.h>
37 #include <bundle_internal.h>
38 #include <sensor_internal.h>
39 #include <ttrace.h>
40 #include <system_info.h>
41
42 #include "appcore_base.h"
43 #include "appcore_base_private.h"
44 #include "appcore_watchdog.h"
45
46 #define PATH_LOCALE "locale"
47 #define RESOURCED_FREEZER_PATH "/Org/Tizen/ResourceD/Freezer"
48 #define RESOURCED_FREEZER_INTERFACE "org.tizen.resourced.freezer"
49 #define RESOURCED_FREEZER_SIGNAL "FreezerState"
50 #define SQLITE_FLUSH_MAX (1024 * 1024)
51
52 typedef struct _appcore_base_context {
53         appcore_base_ops ops;
54         void *data;
55         int argc;
56         char **argv;
57         unsigned int tid;
58         bool suspended_state;
59         bool allowed_bg;
60         bool dirty;
61         guint sid;
62 } appcore_base_context;
63
64 typedef struct _appcore_base_event_node {
65         int type;
66         appcore_base_event_cb cb;
67         void *data;
68 } appcore_base_event_node;
69
70 typedef struct _appcore_base_rotation {
71         int conn;
72         int lock;
73         int ref;
74         enum appcore_base_rm rm;
75         int charger_status;
76         bool initialized;
77 } appcore_base_rotation;
78
79 struct lang_info_s {
80         char *parent;
81         GList *list;
82 };
83
84 static appcore_base_context __context;
85 static GList *__events;
86 static GDBusConnection *__bus;
87 static guint __suspend_dbus_handler_initialized;
88 static char *__locale_dir;
89 static appcore_base_rotation __rotation;
90
91 appcore_base_tizen_profile_t appcore_base_get_tizen_profile(void)
92 {
93         static appcore_base_tizen_profile_t profile = TIZEN_PROFILE_UNKNOWN;
94         char *profile_name = NULL;
95
96         if (__builtin_expect(profile != TIZEN_PROFILE_UNKNOWN, 1))
97                 return profile;
98
99         system_info_get_platform_string("http://tizen.org/feature/profile",
100                         &profile_name);
101         if (profile_name == NULL)
102                 return profile;
103
104         switch (*profile_name) {
105         case 'm':
106         case 'M':
107                 profile = TIZEN_PROFILE_MOBILE;
108                 break;
109         case 'w':
110         case 'W':
111                 profile = TIZEN_PROFILE_WEARABLE;
112                 break;
113         case 't':
114         case 'T':
115                 profile = TIZEN_PROFILE_TV;
116                 break;
117         case 'i':
118         case 'I':
119                 profile = TIZEN_PROFILE_IVI;
120                 break;
121         default:
122                 profile = TIZEN_PROFILE_COMMON;
123                 break;
124         }
125         free(profile_name);
126
127         return profile;
128 }
129
130
131 static void __invoke_callback(void *event, int type)
132 {
133         GList *iter = __events;
134
135         while (iter) {
136                 appcore_base_event_node *node = iter->data;
137
138                 if (node->type == type)
139                         node->cb(event, node->data);
140                 iter = g_list_next(iter);
141         }
142 }
143
144 static bool __exist_callback(int type)
145 {
146         GList *iter = __events;
147
148         while (iter) {
149                 appcore_base_event_node *node = iter->data;
150
151                 if (node->type == type)
152                         return true;
153
154                 iter = g_list_next(iter);
155         }
156
157         return false;
158 }
159
160 static enum appcore_base_rm __get_rm(sensor_data_t data)
161 {
162         int event;
163         enum appcore_base_rm rm;
164
165         if (data.value_count <= 0) {
166                 _ERR("Failed to get sensor data");
167                 return APPCORE_BASE_RM_UNKNOWN;
168         }
169
170         event = data.values[0];
171         switch (event) {
172         case AUTO_ROTATION_DEGREE_0:
173                 rm = APPCORE_BASE_RM_PORTRAIT_NORMAL;
174                 break;
175         case AUTO_ROTATION_DEGREE_90:
176                 rm = APPCORE_BASE_RM_LANDSCAPE_NORMAL;
177                 break;
178         case AUTO_ROTATION_DEGREE_180:
179                 rm = APPCORE_BASE_RM_PORTRAIT_REVERSE;
180                 break;
181         case AUTO_ROTATION_DEGREE_270:
182                 rm = APPCORE_BASE_RM_LANDSCAPE_REVERSE;
183                 break;
184         default:
185                 rm = APPCORE_BASE_RM_UNKNOWN;
186                 break;
187         }
188
189         return rm;
190 }
191
192 static void __lock_cb(keynode_t *node, void *user_data)
193 {
194         bool r;
195         sensor_data_t data;
196         enum appcore_base_rm rm;
197
198         __rotation.lock = !vconf_keynode_get_bool(node);
199         if (__rotation.lock) {
200                 _DBG("Rotation locked");
201                 rm = APPCORE_BASE_RM_PORTRAIT_NORMAL;
202         } else {
203                 _DBG("Rotation unlocked");
204                 r = sensord_get_data(__rotation.conn, AUTO_ROTATION_SENSOR, &data);
205                 if (!r) {
206                         _ERR("Failed to get sensor data");
207                         return;
208                 }
209
210                 rm = __get_rm(data);
211                 if (rm == APPCORE_BASE_RM_UNKNOWN) {
212                         _ERR("Unknown mode");
213                         return;
214                 }
215         }
216
217         if (__rotation.rm == rm)
218                 return;
219
220         _DBG("Rotation: %d -> %d", __rotation.rm, rm);
221         __rotation.rm = rm;
222         __invoke_callback((void *)&__rotation.rm, APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED);
223 }
224
225 static void __auto_rotation_changed_cb(sensor_t sensor, unsigned int event_type,
226                 sensor_data_t *data, void *user_data)
227 {
228         enum appcore_base_rm rm;
229
230         if (data == NULL)
231                 return;
232
233         if (__rotation.lock)
234                 return;
235
236         if (event_type != AUTO_ROTATION_CHANGE_STATE_EVENT)
237                 return;
238
239         rm = __get_rm(*data);
240         if (rm == APPCORE_BASE_RM_UNKNOWN) {
241                 _ERR("Unknown mode");
242                 return;
243         }
244
245         _DBG("Rotation: %d -> %d", __rotation.rm, rm);
246         __rotation.rm = rm;
247         __invoke_callback((void *)&__rotation.rm, APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED);
248 }
249
250 static void __fini_rotation(void)
251 {
252         if (!__rotation.initialized)
253                 return;
254
255         vconf_ignore_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, __lock_cb);
256         sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
257         sensord_stop(__rotation.conn);
258         sensord_disconnect(__rotation.conn);
259
260         __rotation.lock = 0;
261         __rotation.initialized = false;
262 }
263
264 static void __init_rotation(void)
265 {
266         sensor_t sensor;
267         int lock;
268         bool r;
269
270         if (__rotation.initialized)
271                 return;
272
273         sensor = sensord_get_sensor(AUTO_ROTATION_SENSOR);
274         __rotation.conn = sensord_connect(sensor);
275         if (__rotation.conn < 0) {
276                 _ERR("Failed to connect sensord");
277                 return;
278         }
279
280         r = sensord_register_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT,
281                         SENSOR_INTERVAL_NORMAL, 0, __auto_rotation_changed_cb, NULL);
282         if (!r) {
283                 _ERR("Failed to register auto rotation change event");
284                 sensord_disconnect(__rotation.conn);
285                 return;
286         }
287
288         r = sensord_start(__rotation.conn, 0);
289         if (!r) {
290                 _ERR("Failed to start sensord");
291                 sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT);
292                 sensord_disconnect(__rotation.conn);
293                 return;
294         }
295
296         lock = 0;
297         vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, &lock);
298         vconf_notify_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, __lock_cb, NULL);
299
300         __rotation.lock = !lock;
301         __rotation.initialized = true;
302 }
303
304 static void __charger_status_changed_cb(keynode_t *keynode, void *user_data)
305 {
306         if (TIZEN_FEATURE_CHARGER_STATUS) {
307                 __rotation.charger_status = vconf_keynode_get_int(keynode);
308                 if (__rotation.charger_status) {
309                         if (__rotation.ref)
310                                 __init_rotation();
311                 } else {
312                         if (__rotation.ref)
313                                 __fini_rotation();
314                 }
315                 _DBG("charger status(%d)", __rotation.charger_status);
316         }
317 }
318
319 static void __unregister_rotation_changed_event(void)
320 {
321         if (!__rotation.ref)
322                 return;
323
324         __rotation.ref--;
325         if (__rotation.ref > 1)
326                 return;
327
328         __fini_rotation();
329         if (TIZEN_FEATURE_CHARGER_STATUS) {
330                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
331                                 __charger_status_changed_cb);
332         }
333
334         __rotation.ref = 0;
335 }
336
337 static void __register_rotation_changed_event(void)
338 {
339         if (__rotation.ref) {
340                 __rotation.ref++;
341                 return;
342         }
343
344         if (TIZEN_FEATURE_CHARGER_STATUS) {
345                 vconf_get_int(VCONFKEY_SYSMAN_CHARGER_STATUS,
346                                 &__rotation.charger_status);
347                 vconf_notify_key_changed(VCONFKEY_SYSMAN_CHARGER_STATUS,
348                                 __charger_status_changed_cb, NULL);
349                 if (__rotation.charger_status)
350                         __init_rotation();
351         } else {
352                 __init_rotation();
353         }
354
355         __rotation.ref++;
356 }
357
358 static void __on_low_memory(keynode_t *key, void *data)
359 {
360         int val;
361
362         val = vconf_keynode_get_int(key);
363
364         if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) {
365                 __invoke_callback(&val, APPCORE_BASE_EVENT_LOW_MEMORY);
366                 malloc_trim(0);
367         }
368 }
369
370 static void __on_low_battery(keynode_t *key, void *data)
371 {
372         int val;
373
374         val = vconf_keynode_get_int(key);
375
376         if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
377                 __invoke_callback(&val, APPCORE_BASE_EVENT_LOW_BATTERY);
378 }
379
380 static void __destroy_lang_info(gpointer data)
381 {
382         struct lang_info_s *info = (struct lang_info_s *)data;
383
384         if (info == NULL)
385                 return;
386
387         if (info->list)
388                 g_list_free_full(info->list, free);
389         if (info->parent)
390                 free(info->parent);
391         free(info);
392 }
393
394 static struct lang_info_s *__create_lang_info(const char *lang)
395 {
396         struct lang_info_s *info;
397
398         info = calloc(1, sizeof(struct lang_info_s));
399         if (info == NULL) {
400                 _ERR("Out of memory");
401                 return NULL;
402         }
403
404         info->parent = strdup(lang);
405         if (info->parent == NULL) {
406                 _ERR("Out of memory");
407                 free(info);
408                 return NULL;
409         }
410
411         return info;
412 }
413
414 static gint __compare_langs(gconstpointer a, gconstpointer b)
415 {
416         if (!a || !b)
417                 return -1;
418
419         return strcmp(a, b);
420 }
421
422 static char *__get_string_before(const char *str, const char *delim)
423 {
424         char *new_str;
425         char *dup_str;
426         char *token;
427
428         dup_str = strdup(str);
429         if (dup_str == NULL)
430                 return NULL;
431
432         token = strtok(dup_str, delim);
433         if (token == NULL) {
434                 free(dup_str);
435                 return NULL;
436         }
437
438         new_str = strdup(token);
439         free(dup_str);
440
441         return new_str;
442 }
443
444 static GHashTable *__get_lang_table(void)
445 {
446         GHashTable *table;
447         DIR *dp;
448         struct dirent *dentry;
449         char buf[PATH_MAX];
450         struct stat stat_buf;
451         int ret;
452         char *parent_lang;
453         struct lang_info_s *info;
454
455         if (__locale_dir == NULL || __locale_dir[0] == '\0')
456                 return NULL;
457
458         table = g_hash_table_new_full(g_str_hash, g_str_equal,
459                         NULL, __destroy_lang_info);
460         if (table == NULL) {
461                 _ERR("Out of memory");
462                 return NULL;
463         }
464
465         dp = opendir(__locale_dir);
466         if (dp == NULL) {
467                 g_hash_table_destroy(table);
468                 return NULL;
469         }
470
471         while ((dentry = readdir(dp)) != NULL) {
472                 if (!strcmp(dentry->d_name, ".") ||
473                                 !strcmp(dentry->d_name, ".."))
474                         continue;
475
476                 snprintf(buf, sizeof(buf), "%s/%s",
477                                 __locale_dir, dentry->d_name);
478                 ret = stat(buf, &stat_buf);
479                 if (ret != 0 || !S_ISDIR(stat_buf.st_mode))
480                         continue;
481
482                 parent_lang = __get_string_before(dentry->d_name, "_");
483                 if (parent_lang == NULL) {
484                         _ERR("Out of memory");
485                         break;
486                 }
487
488                 info = g_hash_table_lookup(table, parent_lang);
489                 if (info == NULL) {
490                         info = __create_lang_info(parent_lang);
491                         if (info == NULL) {
492                                 free(parent_lang);
493                                 break;
494                         }
495                         g_hash_table_insert(table, info->parent, info);
496                 }
497                 info->list = g_list_append(info->list, strdup(dentry->d_name));
498                 free(parent_lang);
499         }
500         closedir(dp);
501
502         return table;
503 }
504
505 static GList *__append_langs(const char *lang, GList *list, GHashTable *table)
506 {
507         struct lang_info_s *info;
508         GList *found;
509         char *parent_lang = NULL;
510         char *extract_lang;
511
512         if (lang == NULL)
513                 return list;
514
515         list = g_list_append(list, strdup(lang));
516
517         extract_lang = __get_string_before(lang, ".");
518         if (extract_lang == NULL)
519                 return list;
520
521         found = g_list_find_custom(list, extract_lang, __compare_langs);
522         if (found) {
523                 list = g_list_remove_link(list, found);
524                 list = g_list_concat(list, found);
525                 goto end;
526         }
527
528         parent_lang = __get_string_before(extract_lang, "_");
529         if (parent_lang == NULL)
530                 goto end;
531
532         info = g_hash_table_lookup(table, parent_lang);
533         if (info == NULL)
534                 goto end;
535
536         found = g_list_find_custom(info->list, extract_lang, __compare_langs);
537         if (found) {
538                 info->list = g_list_remove_link(info->list, found);
539                 list = g_list_concat(list, found);
540                 goto end;
541         }
542
543         found = g_list_find_custom(info->list, parent_lang, __compare_langs);
544         if (found) {
545                 info->list = g_list_remove_link(info->list, found);
546                 list = g_list_concat(list, found);
547                 goto end;
548         }
549
550         found = g_list_first(info->list);
551         if (found) {
552                 info->list = g_list_remove_link(info->list, found);
553                 list = g_list_concat(list, found);
554         }
555
556 end:
557         if (extract_lang)
558                 free(extract_lang);
559         if (parent_lang)
560                 free(parent_lang);
561
562         return list;
563 }
564
565 static GList *__split_language(const char *lang)
566 {
567         GList *list = NULL;
568         char *dup_lang;
569         char *token;
570
571         dup_lang = strdup(lang);
572         if (dup_lang == NULL) {
573                 _ERR("Out of memory");
574                 return NULL;
575         }
576
577         token = strtok(dup_lang, ":");
578         while (token != NULL) {
579                 list = g_list_append(list, strdup(token));
580                 token = strtok(NULL, ":");
581         }
582         free(dup_lang);
583
584         return list;
585 }
586
587 static GList *__append_default_langs(GList *list)
588 {
589         const char *langs[] = {"en_US", "en_GB", "en"};
590         unsigned int i;
591         GList *found;
592
593         for (i = 0; i < (sizeof(langs) / sizeof(langs[0])); i++) {
594                 found = g_list_find_custom(list, langs[i], __compare_langs);
595                 if (found == NULL)
596                         list = g_list_append(list, strdup(langs[i]));
597         }
598
599         return list;
600 }
601
602 static char *__get_language(const char *lang)
603 {
604         GHashTable *table;
605         GList *list;
606         GList *lang_list = NULL;
607         GList *iter;
608         char *language;
609         char buf[LINE_MAX] = {'\0'};
610         size_t n;
611
612         list = __split_language(lang);
613         if (list == NULL)
614                 return NULL;
615
616         table = __get_lang_table();
617         if (table == NULL) {
618                 g_list_free_full(list, free);
619                 return NULL;
620         }
621
622         iter = g_list_first(list);
623         while (iter) {
624                 language = (char *)iter->data;
625                 lang_list = __append_langs(language, lang_list, table);
626                 iter = g_list_next(iter);
627         }
628         g_list_free_full(list, free);
629         g_hash_table_destroy(table);
630
631         lang_list = __append_default_langs(lang_list);
632         iter = g_list_first(lang_list);
633         while (iter) {
634                 language = (char *)iter->data;
635                 if (language) {
636                         if (buf[0] == '\0') {
637                                 snprintf(buf, sizeof(buf), "%s", language);
638                         } else {
639                                 n = sizeof(buf) - strlen(buf) - 1;
640                                 strncat(buf, ":", n);
641                                 n = sizeof(buf) - strlen(buf) - 1;
642                                 strncat(buf, language, n);
643                         }
644                 }
645                 iter = g_list_next(iter);
646         }
647         g_list_free_full(lang_list, free);
648
649         return strdup(buf);
650 }
651
652 static void __update_lang(void)
653 {
654         char *language;
655         char *lang;
656         char *r;
657
658         lang = vconf_get_str(VCONFKEY_LANGSET);
659         if (lang) {
660                 /* TODO: Use VCONFKEY_SETAPPL_LANGUAGES key */
661                 language = __get_language(lang);
662                 if (language) {
663                         _DBG("*****language(%s)", language);
664                         setenv("LANGUAGE", language, 1);
665                         free(language);
666                 } else {
667                         setenv("LANGUAGE", lang, 1);
668                 }
669                 setenv("LANG", lang, 1);
670                 setenv("LC_MESSAGES", lang, 1);
671                 r = setlocale(LC_ALL, "");
672                 if (r == NULL) {
673                         r = setlocale(LC_ALL, "en_US.UTF-8");
674                         if (r != NULL) {
675                                 _DBG("*****appcore setlocale=%s\n", r);
676                         } else {
677                                 _DBG("*****appcore setlocale=\"C\"");
678                                 setenv("LC_ALL", "C", 1);
679                                 r = setlocale(LC_ALL, "");
680                                 if (r == NULL)
681                                         _ERR("failed to setlocale");
682                         }
683                 }
684                 free(lang);
685         }
686 }
687
688 static void __update_region(void)
689 {
690         char *region;
691         char *r;
692
693         region = vconf_get_str(VCONFKEY_REGIONFORMAT);
694         if (region) {
695                 setenv("LC_CTYPE", region, 1);
696                 setenv("LC_NUMERIC", region, 1);
697                 setenv("LC_TIME", region, 1);
698                 setenv("LC_COLLATE", region, 1);
699                 setenv("LC_MONETARY", region, 1);
700                 setenv("LC_PAPER", region, 1);
701                 setenv("LC_NAME", region, 1);
702                 setenv("LC_ADDRESS", region, 1);
703                 setenv("LC_TELEPHONE", region, 1);
704                 setenv("LC_MEASUREMENT", region, 1);
705                 setenv("LC_IDENTIFICATION", region, 1);
706                 r = setlocale(LC_ALL, "");
707                 if (r != NULL) {
708                         _DBG("*****appcore setlocale=%s\n", r);
709                 } else {
710                         _DBG("*****appcore setlocale=\"C\"");
711                         setenv("LC_ALL", "C", 1);
712                         r = setlocale(LC_ALL, "");
713                         if (r == NULL)
714                                 _ERR("failed to setlocale");
715                 }
716
717                 free(region);
718         }
719 }
720
721 static void __on_language_change(keynode_t *key, void *data)
722 {
723         char *val;
724
725         if (__context.sid) {
726                 g_source_remove(__context.sid);
727                 __context.sid = 0;
728         }
729
730         val = vconf_keynode_get_str(key);
731
732         __update_lang();
733         __invoke_callback((void *)val, APPCORE_BASE_EVENT_LANG_CHANGE);
734 }
735
736 static void __on_region_change(keynode_t *key, void *data)
737 {
738         char *val;
739         const char *name;
740
741         name = vconf_keynode_get_name(key);
742         if (name == NULL)
743                 return;
744
745         if (strcmp(name, VCONFKEY_REGIONFORMAT) &&
746                         strcmp(name, VCONFKEY_REGIONFORMAT_TIME1224))
747                 return;
748
749         val = vconf_get_str(VCONFKEY_REGIONFORMAT);
750
751         __update_region();
752         __invoke_callback((void *)val, APPCORE_BASE_EVENT_REGION_CHANGE);
753         free(val);
754 }
755
756 static gboolean __invoke_lang_change(gpointer data)
757 {
758         const char *lang;
759
760         __context.sid = 0;
761
762         lang = getenv("LANG");
763         if (!lang)
764                 return G_SOURCE_REMOVE;
765
766         __invoke_callback((void *)lang, APPCORE_BASE_EVENT_LANG_CHANGE);
767
768         return G_SOURCE_REMOVE;
769 }
770
771 static void __verify_language(void)
772 {
773         char *lang;
774         const char *env_lang;
775
776         env_lang = getenv("LANG");
777         if (!env_lang)
778                 return;
779
780         lang = vconf_get_str(VCONFKEY_LANGSET);
781         if (!lang)
782                 return;
783
784         if (strcmp(env_lang, lang) != 0) {
785                 _INFO("LANG(%s), LANGSET(%s)", env_lang, lang);
786                 __context.sid = g_idle_add(__invoke_lang_change, NULL);
787         }
788
789         free(lang);
790 }
791
792 static gboolean __flush_memory(gpointer data)
793 {
794         int suspend = APPCORE_BASE_SUSPENDED_STATE_WILL_ENTER_SUSPEND;
795
796         if (__context.ops.trim_memory)
797                 __context.ops.trim_memory(__context.data);
798
799         __context.tid = 0;
800
801         if (!__context.allowed_bg && !__context.suspended_state) {
802                 _DBG("[__SUSPEND__] flush case");
803                 __invoke_callback((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
804                 __context.suspended_state = true;
805         }
806
807         return FALSE;
808 }
809
810 static void __add_suspend_timer(void)
811 {
812         __context.tid = g_timeout_add_seconds(5, __flush_memory, NULL);
813 }
814
815 static void __remove_suspend_timer(void)
816 {
817         if (__context.tid > 0) {
818                 g_source_remove(__context.tid);
819                 __context.tid = 0;
820         }
821 }
822
823 static void __on_receive_suspend_signal(GDBusConnection *connection,
824                                         const gchar *sender_name,
825                                         const gchar *object_path,
826                                         const gchar *interface_name,
827                                         const gchar *signal_name,
828                                         GVariant *parameters,
829                                         gpointer user_data)
830 {
831         gint suspend = APPCORE_BASE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
832         gint pid;
833         gint status;
834
835         if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
836                 g_variant_get(parameters, "(ii)", &status, &pid);
837                 if (pid == getpid() && status == 0) {
838                         if (!__context.allowed_bg && __context.suspended_state) {
839                                 __remove_suspend_timer();
840                                 __invoke_callback((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
841                                 __context.suspended_state = false;
842                                 __add_suspend_timer();
843                         }
844                 }
845         }
846 }
847
848 static int __init_suspend_dbus_handler(void)
849 {
850         GError *err = NULL;
851
852         if (__suspend_dbus_handler_initialized)
853                 return 0;
854
855         if (!__bus) {
856                 __bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
857                 if (!__bus) {
858                         _ERR("Failed to connect to the D-BUS daemon: %s",
859                                                 err->message);
860                         g_error_free(err);
861                         return -1;
862                 }
863         }
864
865         __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
866                                                 __bus,
867                                                 NULL,
868                                                 RESOURCED_FREEZER_INTERFACE,
869                                                 RESOURCED_FREEZER_SIGNAL,
870                                                 RESOURCED_FREEZER_PATH,
871                                                 NULL,
872                                                 G_DBUS_SIGNAL_FLAGS_NONE,
873                                                 __on_receive_suspend_signal,
874                                                 NULL,
875                                                 NULL);
876         if (__suspend_dbus_handler_initialized == 0) {
877                 _ERR("g_dbus_connection_signal_subscribe() is failed.");
878                 return -1;
879         }
880
881         _DBG("[__SUSPEND__] suspend signal initialized");
882
883         return 0;
884 }
885
886 static void __fini_suspend_dbus_handler(void)
887 {
888         if (__bus == NULL)
889                 return;
890
891         if (__suspend_dbus_handler_initialized) {
892                 g_dbus_connection_signal_unsubscribe(__bus,
893                                 __suspend_dbus_handler_initialized);
894                 __suspend_dbus_handler_initialized = 0;
895         }
896
897         g_object_unref(__bus);
898         __bus = NULL;
899 }
900
901 static gboolean __init_suspend(gpointer data)
902 {
903         __init_suspend_dbus_handler();
904         return G_SOURCE_REMOVE;
905 }
906
907 static int __get_locale_resource_dir(char *locale_dir, int size)
908 {
909         const char *res_path;
910
911         res_path = aul_get_app_resource_path();
912         if (res_path == NULL) {
913                 _ERR("Failed to get resource path");
914                 return -1;
915         }
916
917         snprintf(locale_dir, size, "%s" PATH_LOCALE, res_path);
918         if (access(locale_dir, R_OK) != 0)
919                 _DBG("%s does not exist", locale_dir);
920
921         return 0;
922 }
923
924 static int __get_app_name(const char *appid, char **name)
925 {
926         char *name_token = NULL;
927
928         if (appid == NULL)
929                 return -1;
930
931         /* com.vendor.name -> name */
932         name_token = strrchr(appid, '.');
933         if (name_token == NULL)
934                 return -1;
935
936         name_token++;
937
938         *name = strdup(name_token);
939         if (*name == NULL)
940                 return -1;
941
942         return 0;
943 }
944
945 static int __set_i18n(const char *domain, const char *dir)
946 {
947         char *r;
948
949         if (domain == NULL) {
950                 errno = EINVAL;
951                 return -1;
952         }
953
954         if (dir) {
955                 if (__locale_dir)
956                         free(__locale_dir);
957                 __locale_dir = strdup(dir);
958         }
959
960         __update_lang();
961         __update_region();
962
963         r = setlocale(LC_ALL, "");
964         /* if locale is not set properly, try to set "en_US" again */
965         if (r == NULL) {
966                 r = setlocale(LC_ALL, "en_US.UTF-8");
967                 if (r != NULL)
968                         _DBG("*****appcore setlocale=%s\n", r);
969         }
970         if (r == NULL) {
971                 _ERR("appcore: setlocale() error");
972                 _DBG("*****appcore setlocale=\"C\"");
973                 setenv("LC_ALL", "C", 1);
974                 r = setlocale(LC_ALL, "");
975                 if (r == NULL)
976                         _ERR("failed to setlocale");
977         }
978
979         r = bindtextdomain(domain, dir);
980         if (r == NULL)
981                 _ERR("appcore: bindtextdomain() error");
982
983         r = textdomain(domain);
984         if (r == NULL)
985                 _ERR("appcore: textdomain() error");
986
987         return 0;
988 }
989
990 EXPORT_API int appcore_base_on_set_i18n(void)
991 {
992         int r;
993         char locale_dir[PATH_MAX];
994         char appid[PATH_MAX];
995         char *name = NULL;
996
997         r = aul_app_get_appid_bypid(getpid(), appid, PATH_MAX);
998         if (r < 0) {
999                 _ERR("Failed to get application ID - pid(%d)", getpid());
1000                 return -1;
1001         }
1002
1003         r = __get_app_name(appid, &name);
1004         if (r < 0)
1005                 return -1;
1006
1007         r = __get_locale_resource_dir(locale_dir, sizeof(locale_dir));
1008         if (r < 0) {
1009                 free(name);
1010                 return -1;
1011         }
1012
1013         r = __set_i18n(name, locale_dir);
1014         if (r < 0) {
1015                 free(name);
1016                 return -1;
1017         }
1018
1019         free(name);
1020
1021         return 0;
1022 }
1023
1024 EXPORT_API int appcore_base_set_i18n(const char *domain_name, const char *dir_name)
1025 {
1026         return __set_i18n(domain_name, dir_name);
1027 }
1028
1029 static void __set_default_events(void)
1030 {
1031         int r;
1032
1033         vconf_notify_key_changed(VCONFKEY_LANGSET, __on_language_change, NULL);
1034         r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, __on_region_change, NULL);
1035         if (r == 0)
1036                 vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __on_region_change, NULL);
1037         vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory, NULL);
1038 }
1039
1040 static void __unset_default_events(void)
1041 {
1042         int r;
1043
1044         vconf_ignore_key_changed(VCONFKEY_LANGSET, __on_language_change);
1045         r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __on_region_change);
1046         if (r == 0)
1047                 vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __on_region_change);
1048         vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory);
1049 }
1050
1051 EXPORT_API int appcore_base_init(appcore_base_ops ops, int argc, char **argv, void *data)
1052 {
1053         int i;
1054         int r;
1055
1056         __context.ops = ops;
1057         __context.argc = argc;
1058         __context.argv = argv;
1059         __context.data = data;
1060         __context.tid = 0;
1061         __context.suspended_state = false;
1062         __context.allowed_bg = false;
1063
1064         if (__context.ops.init)
1065                 __context.ops.init(argc, argv, data);
1066
1067         if (TIZEN_FEATURE_BACKGROUND_MANAGEMENT)
1068                 g_idle_add(__init_suspend, NULL);
1069
1070         if (!__context.dirty) {
1071                 __context.dirty = true;
1072
1073                 for (i = APPCORE_BASE_EVENT_START + 1; i < APPCORE_BASE_EVENT_MAX; i++) {
1074                         if (__exist_callback(i)) {
1075                                 if (__context.ops.set_event)
1076                                         __context.ops.set_event(i, __context.data);
1077                         }
1078                 }
1079         }
1080
1081         __verify_language();
1082         __set_default_events();
1083         if (__context.ops.set_i18n)
1084                 __context.ops.set_i18n(__context.data);
1085
1086         appcore_watchdog_enable();
1087
1088         if (__context.ops.create) {
1089                 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:CREATE");
1090                 r = __context.ops.create(__context.data);
1091                 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1092                 if (r < 0) {
1093                         aul_status_update(STATUS_DYING);
1094                         return 0;
1095                 }
1096         }
1097
1098         if (__context.ops.run)
1099                 __context.ops.run(__context.data);
1100
1101         return 0;
1102 }
1103
1104 EXPORT_API void appcore_base_fini(void)
1105 {
1106         int i;
1107
1108         aul_status_update(STATUS_DYING);
1109         appcore_watchdog_disable();
1110         if (__context.ops.terminate) {
1111                 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:TERMINATE");
1112                 __context.ops.terminate(__context.data);
1113                 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1114         }
1115
1116         for (i = APPCORE_BASE_EVENT_START + 1; i < APPCORE_BASE_EVENT_MAX; i++) {
1117                 if (__exist_callback(i)) {
1118                         if (__context.ops.unset_event)
1119                                 __context.ops.unset_event(i, __context.data);
1120                 }
1121         }
1122
1123         __unset_default_events();
1124
1125         if (__context.sid) {
1126                 g_source_remove(__context.sid);
1127                 __context.sid = 0;
1128         }
1129
1130         g_list_free_full(__events, free);
1131         __events = NULL;
1132
1133         if (TIZEN_FEATURE_BACKGROUND_MANAGEMENT)
1134                 __fini_suspend_dbus_handler();
1135
1136         if (__locale_dir) {
1137                 free(__locale_dir);
1138                 __locale_dir = NULL;
1139         }
1140
1141         __context.dirty = false;
1142
1143         if (__context.ops.finish)
1144                 __context.ops.finish();
1145 }
1146
1147 EXPORT_API int appcore_base_flush_memory(void)
1148 {
1149         if (__context.ops.trim_memory)
1150                 __context.ops.trim_memory(__context.data);
1151
1152         return 0;
1153 }
1154
1155 EXPORT_API int appcore_base_on_receive(aul_type type, bundle *b)
1156 {
1157         const char *bg;
1158         int dummy = 0;
1159
1160         switch (type) {
1161         case AUL_START:
1162                 _DBG("[APP %d]     AUL event: AUL_START", getpid());
1163                 if (TIZEN_FEATURE_BACKGROUND_MANAGEMENT) {
1164                         bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
1165                         if (bg && !strcmp(bg, "ALLOWED_BG")) {
1166                                 _DBG("[__SUSPEND__] allowed background");
1167                                 __context.allowed_bg = true;
1168                                 __remove_suspend_timer();
1169                         }
1170                 }
1171
1172                 if (__context.ops.control) {
1173                         traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:RESET");
1174                         __context.ops.control(b, __context.data);
1175                         traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1176                 }
1177                 break;
1178         case AUL_RESUME:
1179                 _DBG("[APP %d]     AUL event: AUL_RESUME", getpid());
1180                 if (TIZEN_FEATURE_BACKGROUND_MANAGEMENT) {
1181                         bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
1182                         if (bg && !strcmp(bg, "ALLOWED_BG")) {
1183                                 _DBG("[__SUSPEND__] allowed background");
1184                                 __context.allowed_bg = true;
1185                                 __remove_suspend_timer();
1186                         }
1187                 }
1188                 break;
1189         case AUL_TERMINATE:
1190                 _DBG("[APP %d]     AUL event: AUL_TERMINATE", getpid());
1191                 aul_status_update(STATUS_DYING);
1192                 if (!__context.allowed_bg)
1193                         __remove_suspend_timer();
1194
1195                 if (__context.ops.exit)
1196                         __context.ops.exit(__context.data);
1197                 break;
1198         case AUL_TERMINATE_BGAPP:
1199                 _DBG("[APP %d]     AUL event: AUL_TERMINATE_BGAPP", getpid());
1200                 if (!__context.allowed_bg)
1201                         __remove_suspend_timer();
1202                 break;
1203         case AUL_WAKE:
1204                 _DBG("[APP %d]     AUL event: AUL_WAKE", getpid());
1205                 if (TIZEN_FEATURE_BACKGROUND_MANAGEMENT) {
1206                         if (!__context.allowed_bg &&
1207                                         __context.suspended_state) {
1208                                 int suspend = APPCORE_BASE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
1209                                 __remove_suspend_timer();
1210                                 __invoke_callback((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
1211                                 __context.suspended_state = false;
1212                         }
1213                 }
1214                 break;
1215         case AUL_SUSPEND:
1216                 _DBG("[APP %d]     AUL event: AUL_SUSPEND", getpid());
1217                 if (TIZEN_FEATURE_BACKGROUND_MANAGEMENT) {
1218                         if (!__context.allowed_bg &&
1219                                         !__context.suspended_state) {
1220                                 __remove_suspend_timer();
1221                                 __flush_memory(NULL);
1222                         }
1223                 }
1224                 break;
1225         case AUL_UPDATE_REQUESTED:
1226                 _DBG("[APP %d]     AUL event: AUL_UPDATE_REQUESTED", getpid());
1227                 __invoke_callback((void *)&dummy, APPCORE_BASE_EVENT_UPDATE_REQUESTED);
1228                 break;
1229         default:
1230                 _DBG("[APP %d]     AUL event: %d", getpid(), type);
1231                 /* do nothing */
1232                 break;
1233         }
1234
1235         return 0;
1236 }
1237
1238 EXPORT_API int appcore_base_on_create(void)
1239 {
1240         int r;
1241
1242         r = aul_launch_init(__context.ops.receive, NULL);
1243         if (r < 0) {
1244                 _ERR("Aul init failed: %d", r);
1245                 return -1;
1246         }
1247
1248         r = aul_launch_argv_handler(__context.argc, __context.argv);
1249         if (r < 0) {
1250                 _ERR("Aul argv handler failed: %d", r);
1251                 return -1;
1252         }
1253
1254         return 0;
1255 }
1256
1257 EXPORT_API int appcore_base_on_control(bundle *b)
1258 {
1259         return 0;
1260 }
1261
1262 EXPORT_API int appcore_base_on_terminate()
1263 {
1264         aul_finalize();
1265
1266         return 0;
1267 }
1268
1269 EXPORT_API void appcore_base_on_set_event(enum appcore_base_event event)
1270 {
1271         switch (event) {
1272         case APPCORE_BASE_EVENT_LOW_BATTERY:
1273                 vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery, NULL);
1274                 break;
1275         case APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED:
1276                 __register_rotation_changed_event();
1277                 break;
1278         case APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE:
1279                 break;
1280
1281         default:
1282                 break;
1283         }
1284
1285 }
1286
1287 EXPORT_API void appcore_base_on_unset_event(enum appcore_base_event event)
1288 {
1289         switch (event) {
1290         case APPCORE_BASE_EVENT_LOW_BATTERY:
1291                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery);
1292                 break;
1293         case APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED:
1294                 __unregister_rotation_changed_event();
1295                 break;
1296         case APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE:
1297                 break;
1298         default:
1299                 break;
1300         }
1301 }
1302
1303 EXPORT_API int appcore_base_on_trim_memory(void)
1304 {
1305         int (*sqlite3_free_heap_memory)(int);
1306
1307         sqlite3_free_heap_memory = dlsym(RTLD_DEFAULT,
1308                         "sqlite3_release_memory");
1309         if (sqlite3_free_heap_memory)
1310                 sqlite3_free_heap_memory(SQLITE_FLUSH_MAX);
1311
1312         malloc_trim(0);
1313
1314         return 0;
1315 }
1316
1317 EXPORT_API appcore_base_event_h appcore_base_add_event(enum appcore_base_event event,
1318                 appcore_base_event_cb cb, void *data)
1319 {
1320         appcore_base_event_node *node;
1321
1322         if (__context.dirty && !__exist_callback(event)) {
1323                 if (__context.ops.set_event)
1324                         __context.ops.set_event(event, __context.data);
1325         }
1326
1327         node = malloc(sizeof(appcore_base_event_node));
1328
1329         if (node == NULL)
1330                 return NULL;
1331
1332         node->cb = cb;
1333         node->type = event;
1334         node->data = data;
1335         __events = g_list_append(__events, node);
1336
1337         return node;
1338 }
1339
1340 EXPORT_API int appcore_base_remove_event(appcore_base_event_h handle)
1341 {
1342         appcore_base_event_node *node = handle;
1343         enum appcore_base_event event;
1344
1345         if (!node || !g_list_find(__events, node))
1346                 return -1;
1347
1348         event = node->type;
1349         __events = g_list_remove(__events, node);
1350         free(node);
1351         if (__context.dirty && !__exist_callback(event)) {
1352                 if (__context.ops.unset_event)
1353                         __context.ops.unset_event(event, __context.data);
1354         }
1355
1356         return 0;
1357 }
1358
1359 EXPORT_API int appcore_base_raise_event(void *event, enum appcore_base_event type)
1360 {
1361         __invoke_callback(event, type);
1362         return 0;
1363 }
1364
1365 EXPORT_API int appcore_base_get_rotation_state(enum appcore_base_rm *curr)
1366 {
1367         if (curr == NULL)
1368                 return -1;
1369
1370         if (!__rotation.ref)
1371                 return -1;
1372
1373         *curr = __rotation.rm;
1374         return 0;
1375 }
1376
1377 EXPORT_API bool appcore_base_is_bg_allowed(void)
1378 {
1379         return __context.allowed_bg;
1380 }
1381
1382 EXPORT_API bool appcore_base_is_suspended(void)
1383 {
1384         return __context.suspended_state;
1385 }
1386
1387 EXPORT_API void appcore_base_toggle_suspended_state(void)
1388 {
1389         __context.suspended_state ^= __context.suspended_state;
1390 }
1391
1392 EXPORT_API void appcore_base_exit(void)
1393 {
1394         if (__context.ops.exit)
1395                 __context.ops.exit(__context.data);
1396 }
1397
1398 EXPORT_API void appcore_base_add_suspend_timer(void)
1399 {
1400         __add_suspend_timer();
1401 }
1402
1403 EXPORT_API void appcore_base_remove_suspend_timer(void)
1404 {
1405         __remove_suspend_timer();
1406 }
1407
1408 static int __on_receive(aul_type type, bundle *b, void *data)
1409 {
1410         return appcore_base_on_receive(type, b);
1411 }
1412
1413 static int __on_create(void *data)
1414 {
1415         return appcore_base_on_create();
1416 }
1417
1418 static int __on_control(bundle *b, void *data)
1419 {
1420         return appcore_base_on_control(b);
1421 }
1422
1423 static int __on_terminate(void *data)
1424 {
1425         return appcore_base_on_terminate();
1426 }
1427
1428 static int __on_set_i18n(void *data)
1429 {
1430         return appcore_base_on_set_i18n();
1431 }
1432
1433 static void __on_set_event(enum appcore_base_event event, void *data)
1434 {
1435         appcore_base_on_set_event(event);
1436 }
1437
1438 static void __on_unset_event(enum appcore_base_event event, void *data)
1439 {
1440         appcore_base_on_unset_event(event);
1441 }
1442
1443 static void __on_trim_memory(void *data)
1444 {
1445         appcore_base_on_trim_memory();
1446 }
1447
1448 EXPORT_API appcore_base_ops appcore_base_get_default_ops(void)
1449 {
1450         appcore_base_ops ops;
1451
1452         ops.create = __on_create;
1453         ops.control = __on_control;
1454         ops.terminate = __on_terminate;
1455         ops.receive = __on_receive;
1456         ops.set_i18n = __on_set_i18n;
1457         ops.init = NULL;
1458         ops.finish = NULL;
1459         ops.run = NULL;
1460         ops.exit = NULL;
1461         ops.set_event = __on_set_event;
1462         ops.unset_event = __on_unset_event;
1463         ops.trim_memory = __on_trim_memory;
1464
1465         return ops;
1466 }