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