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