58aef2f960493afaf4aaaf313829576f33a5903a
[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 "appcore_base.h"
39 #include "appcore_base_private.h"
40
41 #define PATH_LOCALE "locale"
42 #define RESOURCED_FREEZER_PATH "/Org/Tizen/Resourced/Freezer"
43 #define RESOURCED_FREEZER_INTERFACE "org.tizen.resourced.freezer"
44 #define RESOURCED_FREEZER_SIGNAL "FreezerState"
45
46 typedef struct _appcore_base_context {
47         appcore_base_ops ops;
48         void *data;
49         int argc;
50         char **argv;
51         unsigned int tid;
52         bool suspended_state;
53         bool allowed_bg;
54         bool dirty;
55 } appcore_base_context;
56
57 typedef struct _appcore_base_event_node {
58         int type;
59         appcore_base_event_cb cb;
60         void *data;
61 } appcore_base_event_node;
62
63 struct lang_info_s {
64         char *parent;
65         GList *list;
66 };
67
68 static appcore_base_context __context;
69 static GList *__events;
70 static GDBusConnection *__bus;
71 static guint __suspend_dbus_handler_initialized;
72 static char *__locale_dir;
73
74 static void __invoke_callback(void *event, int type)
75 {
76         GList *iter = __events;
77
78         while (iter) {
79                 appcore_base_event_node *node = iter->data;
80
81                 if (node->type == type)
82                         node->cb(event, node->data);
83                 iter = g_list_next(iter);
84         }
85 }
86
87 static bool __exist_callback(int type)
88 {
89         GList *iter = __events;
90
91         while (iter) {
92                 appcore_base_event_node *node = iter->data;
93
94                 if (node->type == type)
95                         return true;
96
97                 iter = g_list_next(iter);
98         }
99
100         return false;
101 }
102
103 static void __on_low_memory(keynode_t *key, void *data)
104 {
105         int val;
106
107         val = vconf_keynode_get_int(key);
108
109         if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) {
110                 __invoke_callback(key, APPCORE_BASE_EVENT_LOW_MEMORY);
111                 malloc_trim(0);
112         }
113 }
114
115 static void __on_low_battery(keynode_t *key, void *data)
116 {
117         int val;
118
119         val = vconf_keynode_get_int(key);
120
121         if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
122                 __invoke_callback(key, APPCORE_BASE_EVENT_LOW_BATTERY);
123 }
124
125 static void __destroy_lang_info(gpointer data)
126 {
127         struct lang_info_s *info = (struct lang_info_s *)data;
128
129         if (info == NULL)
130                 return;
131
132         if (info->list)
133                 g_list_free_full(info->list, free);
134         if (info->parent)
135                 free(info->parent);
136         free(info);
137 }
138
139 static struct lang_info_s *__create_lang_info(const char *lang)
140 {
141         struct lang_info_s *info;
142
143         info = calloc(1, sizeof(struct lang_info_s));
144         if (info == NULL) {
145                 _ERR("Out of memory");
146                 return NULL;
147         }
148
149         info->parent = strdup(lang);
150         if (info->parent == NULL) {
151                 _ERR("Out of memory");
152                 free(info);
153                 return NULL;
154         }
155
156         return info;
157 }
158
159 static gint __compare_langs(gconstpointer a, gconstpointer b)
160 {
161         if (!a || !b)
162                 return -1;
163
164         return strcmp(a, b);
165 }
166
167 static char *__get_string_before(const char *str, const char *delim)
168 {
169         char *new_str;
170         char *dup_str;
171         char *token;
172
173         dup_str = strdup(str);
174         if (dup_str == NULL)
175                 return NULL;
176
177         token = strtok(dup_str, delim);
178         if (token == NULL) {
179                 free(dup_str);
180                 return NULL;
181         }
182
183         new_str = strdup(token);
184         free(dup_str);
185
186         return new_str;
187 }
188
189 static GHashTable *__get_lang_table(void)
190 {
191         GHashTable *table;
192         DIR *dp;
193         struct dirent *dentry;
194         char buf[PATH_MAX];
195         struct stat stat_buf;
196         int ret;
197         char *parent_lang;
198         struct lang_info_s *info;
199
200         if (__locale_dir == NULL || __locale_dir[0] == '\0')
201                 return NULL;
202
203         table = g_hash_table_new_full(g_str_hash, g_str_equal,
204                         NULL, __destroy_lang_info);
205         if (table == NULL) {
206                 _ERR("Out of memory");
207                 return NULL;
208         }
209
210         dp = opendir(__locale_dir);
211         if (dp == NULL) {
212                 g_hash_table_destroy(table);
213                 return NULL;
214         }
215
216         while ((dentry = readdir(dp)) != NULL) {
217                 if (!strcmp(dentry->d_name, ".") ||
218                                 !strcmp(dentry->d_name, ".."))
219                         continue;
220
221                 snprintf(buf, sizeof(buf), "%s/%s",
222                                 __locale_dir, dentry->d_name);
223                 ret = stat(buf, &stat_buf);
224                 if (ret != 0 || !S_ISDIR(stat_buf.st_mode))
225                         continue;
226
227                 parent_lang = __get_string_before(dentry->d_name, "_");
228                 if (parent_lang == NULL) {
229                         _ERR("Out of memory");
230                         break;
231                 }
232
233                 info = g_hash_table_lookup(table, parent_lang);
234                 if (info == NULL) {
235                         info = __create_lang_info(parent_lang);
236                         if (info == NULL) {
237                                 free(parent_lang);
238                                 break;
239                         }
240                         g_hash_table_insert(table, info->parent, info);
241                 }
242                 info->list = g_list_append(info->list, strdup(dentry->d_name));
243                 free(parent_lang);
244         }
245         closedir(dp);
246
247         return table;
248 }
249
250 static GList *__append_langs(const char *lang, GList *list, GHashTable *table)
251 {
252         struct lang_info_s *info;
253         GList *found;
254         char *parent_lang = NULL;
255         char *extract_lang;
256
257         if (lang == NULL)
258                 return list;
259
260         extract_lang = __get_string_before(lang, ".");
261         if (extract_lang == NULL)
262                 return list;
263
264         found = g_list_find_custom(list, extract_lang, __compare_langs);
265         if (found) {
266                 list = g_list_remove_link(list, found);
267                 list = g_list_concat(list, found);
268                 goto end;
269         }
270
271         parent_lang = __get_string_before(extract_lang, "_");
272         if (parent_lang == NULL)
273                 goto end;
274
275         info = g_hash_table_lookup(table, parent_lang);
276         if (info == NULL)
277                 goto end;
278
279         found = g_list_find_custom(info->list, extract_lang, __compare_langs);
280         if (found) {
281                 info->list = g_list_remove_link(info->list, found);
282                 list = g_list_concat(list, found);
283                 goto end;
284         }
285
286         found = g_list_find_custom(info->list, parent_lang, __compare_langs);
287         if (found) {
288                 info->list = g_list_remove_link(info->list, found);
289                 list = g_list_concat(list, found);
290                 goto end;
291         }
292
293         found = g_list_first(info->list);
294         if (found) {
295                 info->list = g_list_remove_link(info->list, found);
296                 list = g_list_concat(list, found);
297         }
298
299 end:
300         if (extract_lang)
301                 free(extract_lang);
302         if (parent_lang)
303                 free(parent_lang);
304
305         return list;
306 }
307
308 static GList *__split_language(const char *lang)
309 {
310         GList *list = NULL;
311         char *dup_lang;
312         char *token;
313
314         dup_lang = strdup(lang);
315         if (dup_lang == NULL) {
316                 _ERR("Out of memory");
317                 return NULL;
318         }
319
320         token = strtok(dup_lang, ":");
321         while (token != NULL) {
322                 list = g_list_append(list, strdup(token));
323                 token = strtok(NULL, ":");
324         }
325         free(dup_lang);
326
327         return list;
328 }
329
330 static GList *__append_default_langs(GList *list)
331 {
332         const char *langs[] = {"en_US", "en_GB", "en"};
333         unsigned int i;
334         GList *found;
335
336         for (i = 0; i < (sizeof(langs) / sizeof(langs[0])); i++) {
337                 found = g_list_find_custom(list, langs[i], __compare_langs);
338                 if (found == NULL)
339                         list = g_list_append(list, strdup(langs[i]));
340         }
341
342         return list;
343 }
344
345 static char *__get_language(const char *lang)
346 {
347         GHashTable *table;
348         GList *list;
349         GList *lang_list = NULL;
350         GList *iter;
351         char *language;
352         char buf[LINE_MAX] = {'\0'};
353         size_t n;
354
355         list = __split_language(lang);
356         if (list == NULL)
357                 return NULL;
358
359         table = __get_lang_table();
360         if (table == NULL) {
361                 g_list_free_full(list, free);
362                 return NULL;
363         }
364
365         iter = g_list_first(list);
366         while (iter) {
367                 language = (char *)iter->data;
368                 lang_list = __append_langs(language, lang_list, table);
369                 iter = g_list_next(iter);
370         }
371         g_list_free_full(list, free);
372         g_hash_table_destroy(table);
373
374         lang_list = __append_default_langs(lang_list);
375         iter = g_list_first(lang_list);
376         while (iter) {
377                 language = (char *)iter->data;
378                 if (language) {
379                         if (buf[0] == '\0') {
380                                 snprintf(buf, sizeof(buf), "%s", language);
381                         } else {
382                                 n = sizeof(buf) - strlen(buf) - 1;
383                                 strncat(buf, ":", n);
384                                 n = sizeof(buf) - strlen(buf) - 1;
385                                 strncat(buf, language, n);
386                         }
387                 }
388                 iter = g_list_next(iter);
389         }
390         g_list_free_full(lang_list, free);
391
392         return strdup(buf);
393 }
394
395 static void __update_lang(void)
396 {
397         char *language;
398         char *lang;
399         char *r;
400
401         lang = vconf_get_str(VCONFKEY_LANGSET);
402         if (lang) {
403                 /* TODO: Use VCONFKEY_SETAPPL_LANGUAGES key */
404                 language = __get_language(lang);
405                 if (language) {
406                         _DBG("*****language(%s)", language);
407                         setenv("LANGUAGE", language, 1);
408                         free(language);
409                 } else {
410                         setenv("LANGUAGE", lang, 1);
411                 }
412                 setenv("LANG", lang, 1);
413                 setenv("LC_MESSAGES", lang, 1);
414                 r = setlocale(LC_ALL, "");
415                 if (r == NULL) {
416                         r = setlocale(LC_ALL, lang);
417                         if (r != NULL)
418                                 _DBG("*****appcore setlocale=%s\n", r);
419                 }
420                 free(lang);
421         }
422 }
423
424 static void __update_region(void)
425 {
426         char *region;
427         char *r;
428
429         region = vconf_get_str(VCONFKEY_REGIONFORMAT);
430         if (region) {
431                 setenv("LC_CTYPE", region, 1);
432                 setenv("LC_NUMERIC", region, 1);
433                 setenv("LC_TIME", region, 1);
434                 setenv("LC_COLLATE", region, 1);
435                 setenv("LC_MONETARY", region, 1);
436                 setenv("LC_PAPER", region, 1);
437                 setenv("LC_NAME", region, 1);
438                 setenv("LC_ADDRESS", region, 1);
439                 setenv("LC_TELEPHONE", region, 1);
440                 setenv("LC_MEASUREMENT", region, 1);
441                 setenv("LC_IDENTIFICATION", region, 1);
442                 r = setlocale(LC_ALL, "");
443                 if (r != NULL)
444                         _DBG("*****appcore setlocale=%s\n", r);
445
446                 free(region);
447         }
448 }
449
450 static void __on_language_change(keynode_t *key, void *data)
451 {
452         char *val;
453
454         val = vconf_keynode_get_str(key);
455
456         __update_lang();
457         __invoke_callback((void *)val, APPCORE_BASE_EVENT_LANG_CHANGE);
458 }
459
460 static void __on_region_change(keynode_t *key, void *data)
461 {
462         char *val = NULL;
463         const char *name;
464
465         name = vconf_keynode_get_name(key);
466         if (!strcmp(name, VCONFKEY_REGIONFORMAT))
467                 val = vconf_keynode_get_str(key);
468
469         __update_region();
470         __invoke_callback((void *)val, APPCORE_BASE_EVENT_REGION_CHANGE);
471 }
472
473 static gboolean __flush_memory(gpointer data)
474 {
475         int suspend = APPCORE_BASE_SUSPENDED_STATE_WILL_ENTER_SUSPEND;
476
477         appcore_base_flush_memory();
478         __context.tid = 0;
479
480         if (!__context.allowed_bg && !__context.suspended_state) {
481                 _DBG("[__SUSPEND__] flush case");
482                 __invoke_callback((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
483                 __context.suspended_state = true;
484         }
485
486         return FALSE;
487 }
488
489 static void __add_suspend_timer(void)
490 {
491         __context.tid = g_timeout_add_seconds(5, __flush_memory, NULL);
492 }
493
494 static void __remove_suspend_timer(void)
495 {
496         if (__context.tid > 0) {
497                 g_source_remove(__context.tid);
498                 __context.tid = 0;
499         }
500 }
501
502 static void __on_receive_suspend_signal(GDBusConnection *connection,
503                                         const gchar *sender_name,
504                                         const gchar *object_path,
505                                         const gchar *interface_name,
506                                         const gchar *signal_name,
507                                         GVariant *parameters,
508                                         gpointer user_data)
509 {
510         gint suspend = APPCORE_BASE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
511         gint pid;
512         gint status;
513
514         if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
515                 g_variant_get(parameters, "(ii)", &status, &pid);
516                 if (pid == getpid() && status == 0) {
517                         if (!__context.allowed_bg && __context.suspended_state) {
518                                 __remove_suspend_timer();
519                                 __invoke_callback((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
520                                 __context.suspended_state = false;
521                                 __add_suspend_timer();
522                         }
523                 }
524         }
525 }
526
527 static int __init_suspend_dbus_handler(void)
528 {
529         GError *err = NULL;
530
531         if (__suspend_dbus_handler_initialized)
532                 return 0;
533
534         if (!__bus) {
535                 __bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
536                 if (!__bus) {
537                         _ERR("Failed to connect to the D-BUS daemon: %s",
538                                                 err->message);
539                         g_error_free(err);
540                         return -1;
541                 }
542         }
543
544         __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
545                                                 __bus,
546                                                 NULL,
547                                                 RESOURCED_FREEZER_INTERFACE,
548                                                 RESOURCED_FREEZER_SIGNAL,
549                                                 RESOURCED_FREEZER_PATH,
550                                                 NULL,
551                                                 G_DBUS_SIGNAL_FLAGS_NONE,
552                                                 __on_receive_suspend_signal,
553                                                 NULL,
554                                                 NULL);
555         if (__suspend_dbus_handler_initialized == 0) {
556                 _ERR("g_dbus_connection_signal_subscribe() is failed.");
557                 return -1;
558         }
559
560         _DBG("[__SUSPEND__] suspend signal initialized");
561
562         return 0;
563 }
564
565 static void __fini_suspend_dbus_handler(void)
566 {
567         if (__bus == NULL)
568                 return;
569
570         if (__suspend_dbus_handler_initialized) {
571                 g_dbus_connection_signal_unsubscribe(__bus,
572                                 __suspend_dbus_handler_initialized);
573                 __suspend_dbus_handler_initialized = 0;
574         }
575
576         g_object_unref(__bus);
577         __bus = NULL;
578 }
579
580 static int __get_locale_resource_dir(char *locale_dir, int size)
581 {
582         const char *res_path;
583
584         res_path = aul_get_app_resource_path();
585         if (res_path == NULL) {
586                 _ERR("Failed to get resource path");
587                 return -1;
588         }
589
590         snprintf(locale_dir, size, "%s" PATH_LOCALE, res_path);
591         if (access(locale_dir, R_OK) != 0)
592                 _DBG("%s does not exist", locale_dir);
593
594         return 0;
595 }
596
597 static int __get_app_name(const char *appid, char **name)
598 {
599         char *name_token = NULL;
600
601         if (appid == NULL)
602                 return -1;
603
604         /* com.vendor.name -> name */
605         name_token = strrchr(appid, '.');
606         if (name_token == NULL)
607                 return -1;
608
609         name_token++;
610
611         *name = strdup(name_token);
612         if (*name == NULL)
613                 return -1;
614
615         return 0;
616 }
617
618 static int __set_i18n(const char *domain, const char *dir)
619 {
620         char *r;
621         char *lan;
622
623         if (domain == NULL) {
624                 errno = EINVAL;
625                 return -1;
626         }
627
628         if (dir) {
629                 if (__locale_dir)
630                         free(__locale_dir);
631                 __locale_dir = strdup(dir);
632         }
633
634         __update_lang();
635         __update_region();
636
637         r = setlocale(LC_ALL, "");
638         /* if locale is not set properly, try again to set as language base */
639         if (r == NULL) {
640                 lan = vconf_get_str(VCONFKEY_LANGSET);
641                 if (lan != NULL) {
642                         r = setlocale(LC_ALL, lan);
643                         _DBG("*****appcore setlocale=%s\n", r);
644                         free(lan);
645                 }
646         }
647         if (r == NULL)
648                 _ERR("appcore: setlocale() error");
649
650         r = bindtextdomain(domain, dir);
651         if (r == NULL)
652                 _ERR("appcore: bindtextdomain() error");
653
654         r = textdomain(domain);
655         if (r == NULL)
656                 _ERR("appcore: textdomain() error");
657
658         return 0;
659 }
660
661 EXPORT_API int appcore_base_on_set_i18n(void)
662 {
663         int r;
664         char locale_dir[PATH_MAX];
665         char appid[PATH_MAX];
666         char *name = NULL;
667
668         r = aul_app_get_appid_bypid(getpid(), appid, PATH_MAX);
669         if (r < 0)
670                 return -1;
671
672         r = __get_app_name(appid, &name);
673         if (r < 0)
674                 return -1;
675
676         r = __get_locale_resource_dir(locale_dir, sizeof(locale_dir));
677         if (r < 0) {
678                 free(name);
679                 return -1;
680         }
681
682         r = __set_i18n(name, locale_dir);
683         if (r < 0) {
684                 free(name);
685                 return -1;
686         }
687
688         free(name);
689
690         return 0;
691 }
692
693 EXPORT_API int appcore_base_init(appcore_base_ops ops, int argc, char **argv, void *data)
694 {
695         int i;
696
697         __context.ops = ops;
698         __context.argc = argc;
699         __context.argv = argv;
700         __context.data = data;
701         __context.tid = 0;
702         __context.suspended_state = false;
703         __context.allowed_bg = false;
704
705         if (__context.ops.set_i18n)
706                 __context.ops.set_i18n(__context.data);
707
708         __init_suspend_dbus_handler();
709
710         if (!__context.dirty) {
711                 __context.dirty = true;
712
713                 for (i = APPCORE_BASE_EVENT_START + 1; i < APPCORE_BASE_EVENT_MAX; i++) {
714                         if (__exist_callback(i)) {
715                                 if (__context.ops.set_event)
716                                         __context.ops.set_event(i, __context.data);
717                         }
718                 }
719         }
720
721         if (__context.ops.create && __context.ops.create(__context.data) < 0) {
722                 aul_status_update(STATUS_DYING);
723                 return 0;
724         }
725
726         if (__context.ops.run)
727                 __context.ops.run(__context.data);
728
729         return 0;
730 }
731
732 EXPORT_API void appcore_base_fini(void)
733 {
734         int i;
735
736         aul_status_update(STATUS_DYING);
737         if (__context.ops.terminate)
738                 __context.ops.terminate(__context.data);
739
740         for (i = APPCORE_BASE_EVENT_START + 1; i < APPCORE_BASE_EVENT_MAX; i++) {
741                 if (__exist_callback(i)) {
742                         if (__context.ops.unset_event)
743                                 __context.ops.unset_event(i, __context.data);
744                 }
745         }
746
747         g_list_free_full(__events, free);
748         __events = NULL;
749         __fini_suspend_dbus_handler();
750
751         if (__locale_dir) {
752                 free(__locale_dir);
753                 __locale_dir = NULL;
754         }
755
756         __context.dirty = false;
757 }
758
759 EXPORT_API int appcore_base_flush_memory(void)
760 {
761         malloc_trim(0);
762         return 0;
763 }
764
765 EXPORT_API int appcore_base_on_receive(aul_type type, bundle *b)
766 {
767         int ret;
768         const char **tep_path;
769         int len = 0;
770         int i;
771         const char *bg;
772         int dummy = 0;
773
774         switch (type) {
775         case AUL_START:
776                 _DBG("[APP %d]     AUL event: AUL_START", getpid());
777                 tep_path = bundle_get_str_array(b, AUL_TEP_PATH, &len);
778                 if (tep_path) {
779                         for (i = 0; i < len; i++) {
780                                 ret = aul_check_tep_mount(tep_path[i]);
781                                 if (ret == -1) {
782                                         _ERR("mount request not completed within 1 sec");
783                                         exit(-1);
784                                 }
785                         }
786                 }
787
788                 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
789                 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
790                         _DBG("[__SUSPEND__] allowed background");
791                         __context.allowed_bg = true;
792                         __remove_suspend_timer();
793                 }
794
795                 if (__context.ops.control)
796                        __context.ops.control(b, __context.data);
797                 break;
798         case AUL_RESUME:
799                 _DBG("[APP %d]     AUL event: AUL_RESUME", getpid());
800                 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
801                 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
802                         _DBG("[__SUSPEND__] allowed background");
803                         __context.allowed_bg = true;
804                         __remove_suspend_timer();
805                 }
806                 break;
807         case AUL_TERMINATE:
808                 _DBG("[APP %d]     AUL event: AUL_TERMINATE", getpid());
809                 aul_status_update(STATUS_DYING);
810                 if (!__context.allowed_bg)
811                         __remove_suspend_timer();
812
813                 if (__context.ops.exit)
814                         __context.ops.exit(__context.data);
815                 break;
816         case AUL_TERMINATE_BGAPP:
817                 _DBG("[APP %d]     AUL event: AUL_TERMINATE_BGAPP", getpid());
818                 if (!__context.allowed_bg)
819                         __remove_suspend_timer();
820                 break;
821         case AUL_WAKE:
822                 _DBG("[APP %d]     AUL event: AUL_WAKE", getpid());
823                 if (!__context.allowed_bg && __context.suspended_state) {
824                         int suspend = APPCORE_BASE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
825                         __remove_suspend_timer();
826                         __invoke_callback((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
827                         __context.suspended_state = false;
828                 }
829                 break;
830         case AUL_SUSPEND:
831                 _DBG("[APP %d]     AUL event: AUL_SUSPEND", getpid());
832                 if (!__context.allowed_bg && !__context.suspended_state) {
833                         __remove_suspend_timer();
834                         __flush_memory(NULL);
835                 }
836                 break;
837         case AUL_UPDATE_REQUESTED:
838                 _DBG("[APP %d]     AUL event: AUL_UPDATE_REQUESTED", getpid());
839                 __invoke_callback((void *)&dummy, APPCORE_BASE_EVENT_UPDATE_REQUESTED);
840                 break;
841         default:
842                 _DBG("[APP %d]     AUL event: %d", getpid(), type);
843                 /* do nothing */
844                 break;
845         }
846
847         return 0;
848 }
849
850 EXPORT_API int appcore_base_on_create(void)
851 {
852         int r;
853         r = aul_launch_init(__context.ops.receive, NULL);
854         if (r < 0) {
855                 _ERR("Aul init failed: %d", r);
856                 return -1;
857         }
858
859         r = aul_launch_argv_handler(__context.argc, __context.argv);
860         if (r < 0) {
861                 _ERR("Aul argv handler failed: %d", r);
862                 return -1;
863         }
864
865         return 0;
866 }
867
868 EXPORT_API int appcore_base_on_control(bundle *b)
869 {
870         return 0;
871 }
872
873 EXPORT_API int appcore_base_on_terminate()
874 {
875         aul_finalize();
876         if (__context.ops.exit)
877                 __context.ops.exit(__context.data);
878
879         return 0;
880 }
881
882 EXPORT_API void appcore_base_on_set_event(enum appcore_base_event event)
883 {
884         int r;
885
886         switch (event) {
887         case APPCORE_BASE_EVENT_LOW_MEMORY:
888                 vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory, NULL);
889                 break;
890         case APPCORE_BASE_EVENT_LOW_BATTERY:
891                 vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery, NULL);
892                 break;
893         case APPCORE_BASE_EVENT_LANG_CHANGE:
894                 vconf_notify_key_changed(VCONFKEY_LANGSET, __on_language_change, NULL);
895                 break;
896         case APPCORE_BASE_EVENT_REGION_CHANGE:
897                 r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, __on_region_change, NULL);
898                 if (r < 0)
899                         break;
900
901                 vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __on_region_change, NULL);
902                 break;
903         case APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE:
904                 break;
905
906         default:
907                 break;
908         }
909
910 }
911
912 EXPORT_API void appcore_base_on_unset_event(enum appcore_base_event event)
913 {
914         int r;
915
916         switch (event) {
917         case APPCORE_BASE_EVENT_LOW_MEMORY:
918                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory);
919                 break;
920         case APPCORE_BASE_EVENT_LOW_BATTERY:
921                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery);
922                 break;
923         case APPCORE_BASE_EVENT_LANG_CHANGE:
924                 vconf_ignore_key_changed(VCONFKEY_LANGSET, __on_language_change);
925                 break;
926         case APPCORE_BASE_EVENT_REGION_CHANGE:
927                 r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __on_region_change);
928                 if (r < 0)
929                         break;
930                 vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __on_region_change);
931                 break;
932         case APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE:
933                 break;
934         default:
935                 break;
936         }
937 }
938
939 EXPORT_API appcore_base_event_h appcore_base_add_event(enum appcore_base_event event,
940                 appcore_base_event_cb cb, void *data)
941 {
942         appcore_base_event_node *node;
943
944         if (__context.dirty && !__exist_callback(event)) {
945                 if (__context.ops.set_event)
946                         __context.ops.set_event(event, __context.data);
947         }
948
949         node = malloc(sizeof(appcore_base_event_node));
950
951         if (node == NULL)
952                 return NULL;
953
954         node->cb = cb;
955         node->type = event;
956         node->data = data;
957         __events = g_list_append(__events, node);
958
959         return node;
960 }
961
962 EXPORT_API int appcore_base_remove_event(appcore_base_event_h handle)
963 {
964         appcore_base_event_node *node = handle;
965         enum appcore_base_event event;
966
967         event = node->type;
968         __events = g_list_remove(__events, node);
969         free(node);
970         if (__context.dirty && !__exist_callback(event)) {
971                 if (__context.ops.unset_event)
972                         __context.ops.unset_event(event, __context.data);
973         }
974
975         return 0;
976 }
977
978 EXPORT_API int appcore_base_raise_event(void *event, enum appcore_base_event type)
979 {
980         __invoke_callback(event, type);
981         return 0;
982 }
983
984 EXPORT_API int appcore_base_get_rotation_state(enum appcore_base_rm *curr)
985 {
986         return 0;
987 }
988
989 EXPORT_API bool appcore_base_is_bg_allowed(void)
990 {
991         return __context.allowed_bg;
992 }
993
994 EXPORT_API bool appcore_base_is_suspended(void)
995 {
996         return __context.suspended_state;
997 }
998
999 EXPORT_API void appcore_base_toggle_suspended_state(void)
1000 {
1001         __context.suspended_state ^= __context.suspended_state;
1002 }
1003
1004 static int __on_receive(aul_type type, bundle *b, void *data)
1005 {
1006         return appcore_base_on_receive(type, b);
1007 }
1008
1009 static int __on_create(void *data)
1010 {
1011         return appcore_base_on_create();
1012 }
1013
1014 static int __on_control(bundle *b, void *data)
1015 {
1016         return appcore_base_on_control(b);
1017 }
1018
1019 static int __on_terminate(void *data)
1020 {
1021         return appcore_base_on_terminate();
1022 }
1023
1024 static int __on_set_i18n(void *data)
1025 {
1026         return appcore_base_on_set_i18n();
1027 }
1028
1029 static void __on_set_event(enum appcore_base_event event, void *data)
1030 {
1031         return appcore_base_on_set_event(event);
1032 }
1033
1034 static void __on_unset_event(enum appcore_base_event event, void *data)
1035 {
1036         return appcore_base_on_unset_event(event);
1037 }
1038
1039 EXPORT_API appcore_base_ops appcore_base_get_default_ops(void)
1040 {
1041         appcore_base_ops ops;
1042
1043         ops.create = __on_create;
1044         ops.control = __on_control;
1045         ops.terminate = __on_terminate;
1046         ops.receive = __on_receive;
1047         ops.set_i18n = __on_set_i18n;
1048         ops.run = NULL;
1049         ops.exit = NULL;
1050         ops.set_event = __on_set_event;
1051         ops.unset_event = __on_unset_event;
1052
1053         return ops;
1054 }
1055
1056