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