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