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