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