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