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