Fix getting locale resource path
[platform/core/appfw/app-core.git] / src / appcore.c
1 /*
2  * Copyright (c) 2000 - 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 <errno.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25 #include <malloc.h>
26 #include <locale.h>
27 #include <linux/limits.h>
28 #include <glib.h>
29 #include <sys/time.h>
30 #include <dlfcn.h>
31 #include <vconf.h>
32 #include <aul.h>
33 #include <bundle_internal.h>
34 #include "appcore-internal.h"
35
36 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
37 #include <gio/gio.h>
38
39 #define RESOURCED_FREEZER_PATH "/Org/Tizen/Resourced/Freezer"
40 #define RESOURCED_FREEZER_INTERFACE "org.tizen.resourced.freezer"
41 #define RESOURCED_FREEZER_SIGNAL "FreezerState"
42 #endif
43
44 #define SQLITE_FLUSH_MAX                (1024*1024)
45
46 #define PATH_LOCALE "locale"
47
48 static struct appcore core;
49 static pid_t _pid;
50
51 static enum appcore_event to_ae[SE_MAX] = {
52         APPCORE_EVENT_UNKNOWN,  /* SE_UNKNOWN */
53         APPCORE_EVENT_LOW_MEMORY,       /* SE_LOWMEM */
54         APPCORE_EVENT_LOW_BATTERY,      /* SE_LOWBAT */
55         APPCORE_EVENT_LANG_CHANGE,      /* SE_LANGCGH */
56         APPCORE_EVENT_REGION_CHANGE,
57         APPCORE_EVENT_SUSPENDED_STATE_CHANGE,
58 };
59
60 static int appcore_event_initialized[SE_MAX] = {0,};
61
62 enum cb_type {                  /* callback */
63         _CB_NONE,
64         _CB_SYSNOTI,
65         _CB_APPNOTI,
66         _CB_VCONF,
67 };
68
69 struct evt_ops {
70         enum cb_type type;
71         union {
72                 enum appcore_event sys;
73                 enum app_event app;
74                 const char *vkey;
75         } key;
76
77         int (*cb_pre) (void *);
78         int (*cb) (void *);
79         int (*cb_post) (void *);
80
81         int (*vcb_pre) (void *, void *);
82         int (*vcb) (void *, void *);
83         int (*vcb_post) (void *, void *);
84 };
85
86 struct open_s {
87         int (*callback) (void *);
88         void *cbdata;
89 };
90
91 static struct open_s open;
92
93 static int __app_terminate(void *data);
94 static int __app_resume(void *data);
95 static int __app_reset(void *data, bundle *k);
96
97 static int __sys_lowmem_post(void *data, void *evt);
98 static int __sys_lowmem(void *data, void *evt);
99 static int __sys_lowbatt(void *data, void *evt);
100 static int __sys_langchg_pre(void *data, void *evt);
101 static int __sys_langchg(void *data, void *evt);
102 static int __sys_regionchg_pre(void *data, void *evt);
103 static int __sys_regionchg(void *data, void *evt);
104 extern void aul_finalize();
105
106
107 static struct evt_ops evtops[] = {
108         {
109          .type = _CB_VCONF,
110          .key.vkey = VCONFKEY_SYSMAN_LOW_MEMORY,
111          .vcb_post = __sys_lowmem_post,
112          .vcb = __sys_lowmem,
113          },
114         {
115          .type = _CB_VCONF,
116          .key.vkey = VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
117          .vcb = __sys_lowbatt,
118          },
119         {
120          .type = _CB_VCONF,
121          .key.vkey = VCONFKEY_LANGSET,
122          .vcb_pre = __sys_langchg_pre,
123          .vcb = __sys_langchg,
124          },
125         {
126          .type = _CB_VCONF,
127          .key.vkey = VCONFKEY_REGIONFORMAT,
128          .vcb_pre = __sys_regionchg_pre,
129          .vcb = __sys_regionchg,
130          },
131         {
132          .type = _CB_VCONF,
133          .key.vkey = VCONFKEY_REGIONFORMAT_TIME1224,
134          .vcb = __sys_regionchg,
135          },
136 };
137
138 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
139 static GDBusConnection *bus = NULL;
140 static guint __suspend_dbus_handler_initialized = 0;
141 #endif
142
143 static int __get_locale_resource_dir(char *locale_dir, int size)
144 {
145         const char *res_path;
146
147         res_path = aul_get_app_resource_path();
148         if (res_path == NULL) {
149                 _ERR("Failed to get resource path");
150                 return -1;
151         }
152
153         snprintf(locale_dir, size, "%s" PATH_LOCALE, res_path);
154         if (access(locale_dir, R_OK) != 0)
155                 return -1;
156
157         return 0;
158 }
159
160 static int __app_terminate(void *data)
161 {
162         struct appcore *ac = data;
163
164         _retv_if(ac == NULL || ac->ops == NULL, -1);
165         _retv_if(ac->ops->cb_app == NULL, 0);
166
167         ac->ops->cb_app(AE_TERMINATE, ac->ops->data, NULL);
168
169         return 0;
170 }
171
172 static int __bgapp_terminate(void *data)
173 {
174         struct appcore *ac = data;
175
176         _retv_if(ac == NULL || ac->ops == NULL, -1);
177         _retv_if(ac->ops->cb_app == NULL, 0);
178
179         ac->ops->cb_app(AE_TERMINATE_BGAPP, ac->ops->data, NULL);
180
181         return 0;
182 }
183
184 static gboolean __prt_ltime(gpointer data)
185 {
186         int msec;
187
188         msec = appcore_measure_time_from(NULL);
189         if (msec)
190                 _DBG("[APP %d] first idle after reset: %d msec", _pid, msec);
191
192         return FALSE;
193 }
194
195 static int __app_reset(void *data, bundle * k)
196 {
197         struct appcore *ac = data;
198         _retv_if(ac == NULL || ac->ops == NULL, -1);
199         _retv_if(ac->ops->cb_app == NULL, 0);
200
201         g_idle_add(__prt_ltime, ac);
202
203         ac->ops->cb_app(AE_RESET, ac->ops->data, k);
204
205         return 0;
206 }
207
208 static int __app_resume(void *data)
209 {
210         struct appcore *ac = data;
211         _retv_if(ac == NULL || ac->ops == NULL, -1);
212         _retv_if(ac->ops->cb_app == NULL, 0);
213
214         ac->ops->cb_app(AE_RAISE, ac->ops->data, NULL);
215         return 0;
216 }
217
218 static int __app_pause(void *data)
219 {
220         struct appcore *ac = data;
221         _retv_if(ac == NULL || ac->ops == NULL, -1);
222         _retv_if(ac->ops->cb_app == NULL, 0);
223
224         ac->ops->cb_app(AE_LOWER, ac->ops->data, NULL);
225         return 0;
226 }
227
228 static int __sys_do_default(struct appcore *ac, enum sys_event event)
229 {
230         int r;
231
232         switch (event) {
233         case SE_LOWBAT:
234                 /*r = __def_lowbatt(ac);*/
235                 r = 0;
236                 break;
237         default:
238                 r = 0;
239                 break;
240         };
241
242         return r;
243 }
244
245 static int __sys_do(struct appcore *ac, void *event_info, enum sys_event event)
246 {
247         struct sys_op *op;
248
249         _retv_if(ac == NULL || event >= SE_MAX, -1);
250
251         op = &ac->sops[event];
252
253         if (op->func == NULL)
254                 return __sys_do_default(ac, event);
255
256         return op->func(event_info, op->data);
257 }
258
259 static int __sys_lowmem_post(void *data, void *evt)
260 {
261         keynode_t *key = evt;
262         int val;
263
264         val = vconf_keynode_get_int(key);
265
266         if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)     {
267 #if defined(MEMORY_FLUSH_ACTIVATE)
268                 struct appcore *ac = data;
269                 ac->ops->cb_app(AE_LOWMEM_POST, ac->ops->data, NULL);
270 #else
271                 malloc_trim(0);
272 #endif
273         }
274         return 0;
275 }
276
277 static int __sys_lowmem(void *data, void *evt)
278 {
279         keynode_t *key = evt;
280         int val;
281
282         val = vconf_keynode_get_int(key);
283
284         if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)
285                 return __sys_do(data, (void *)&val, SE_LOWMEM);
286
287         return 0;
288 }
289
290 static int __sys_lowbatt(void *data, void *evt)
291 {
292         keynode_t *key = evt;
293         int val;
294
295         val = vconf_keynode_get_int(key);
296
297         /* VCONFKEY_SYSMAN_BAT_CRITICAL_LOW or VCONFKEY_SYSMAN_POWER_OFF */
298         if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
299                 return __sys_do(data, (void *)&val, SE_LOWBAT);
300
301         return 0;
302 }
303
304 static int __sys_langchg_pre(void *data, void *evt)
305 {
306         update_lang();
307         return 0;
308 }
309
310 static int __sys_langchg(void *data, void *evt)
311 {
312         keynode_t *key = evt;
313         char *val;
314
315         val = vconf_keynode_get_str(key);
316
317         return __sys_do(data, (void *)val, SE_LANGCHG);
318 }
319
320 static int __sys_regionchg_pre(void *data, void *evt)
321 {
322         update_region();
323         return 0;
324 }
325
326 static int __sys_regionchg(void *data, void *evt)
327 {
328         keynode_t *key = evt;
329         char *val = NULL;
330         const char *name;
331
332         name = vconf_keynode_get_name(key);
333         if (!strcmp(name, VCONFKEY_REGIONFORMAT))
334                 val = vconf_keynode_get_str(key);
335
336         return __sys_do(data, (void *)val, SE_REGIONCHG);
337 }
338
339 static void __vconf_do(struct evt_ops *eo, keynode_t * key, void *data)
340 {
341         _ret_if(eo == NULL);
342
343         if (eo->vcb_pre)
344                 eo->vcb_pre(data, key);
345
346         if (eo->vcb)
347                 eo->vcb(data, key);
348
349         if (eo->vcb_post)
350                 eo->vcb_post(data, key);
351 }
352
353 static void __vconf_cb(keynode_t *key, void *data)
354 {
355         int i;
356         const char *name;
357
358         name = vconf_keynode_get_name(key);
359         _ret_if(name == NULL);
360
361         _DBG("[APP %d] vconf changed: %s", _pid, name);
362
363         for (i = 0; i < sizeof(evtops) / sizeof(evtops[0]); i++) {
364                 struct evt_ops *eo = &evtops[i];
365
366                 switch (eo->type) {
367                 case _CB_VCONF:
368                         if (!strcmp(name, eo->key.vkey))
369                                 __vconf_do(eo, key, data);
370                         break;
371                 default:
372                         /* do nothing */
373                         break;
374                 }
375         }
376 }
377
378 static int __add_vconf(struct appcore *ac, enum sys_event se)
379 {
380         int r;
381
382         switch (se) {
383         case SE_LOWMEM:
384                 r = vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __vconf_cb, ac);
385                 break;
386         case SE_LOWBAT:
387                 r = vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __vconf_cb, ac);
388                 break;
389         case SE_LANGCHG:
390                 r = vconf_notify_key_changed(VCONFKEY_LANGSET, __vconf_cb, ac);
391                 break;
392         case SE_REGIONCHG:
393                 r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, __vconf_cb, ac);
394                 if (r < 0)
395                         break;
396
397                 r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __vconf_cb, ac);
398                 break;
399         default:
400                 r = -1;
401                 break;
402         }
403
404         return r;
405 }
406
407 static int __del_vconf(enum sys_event se)
408 {
409         int r;
410
411         switch (se) {
412         case SE_LOWMEM:
413                 r = vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __vconf_cb);
414                 break;
415         case SE_LOWBAT:
416                 r = vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __vconf_cb);
417                 break;
418         case SE_LANGCHG:
419                 r = vconf_ignore_key_changed(VCONFKEY_LANGSET, __vconf_cb);
420                 break;
421         case SE_REGIONCHG:
422                 r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __vconf_cb);
423                 if (r < 0)
424                         break;
425
426                 r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __vconf_cb);
427                 break;
428         default:
429                 r = -1;
430                 break;
431         }
432
433         return r;
434 }
435
436 static int __del_vconf_list(void)
437 {
438         int r;
439         enum sys_event se;
440
441         for (se = SE_LOWMEM; se < SE_MAX; se++) {
442                 if (appcore_event_initialized[se]) {
443                         r = __del_vconf(se);
444                         if (r < 0)
445                                 _ERR("Delete vconf callback failed");
446                         else
447                                 appcore_event_initialized[se] = 0;
448                 }
449         }
450
451         return 0;
452 }
453
454 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
455 static gboolean __flush_memory(gpointer data)
456 {
457         int suspend = APPCORE_SUSPENDED_STATE_WILL_ENTER_SUSPEND;
458         struct appcore *ac = (struct appcore *)data;
459
460         appcore_flush_memory();
461
462         if (!ac)
463                 return FALSE;
464
465         ac->tid = 0;
466
467         if (!ac->allowed_bg && !ac->suspended_state) {
468                 _DBG("[__SUSPEND__] flush case");
469                 __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
470                 ac->suspended_state = true;
471         }
472
473         return FALSE;
474 }
475
476 static void __add_suspend_timer(struct appcore *ac)
477 {
478         ac->tid = g_timeout_add_seconds(5, __flush_memory, ac);
479 }
480
481 static void __remove_suspend_timer(struct appcore *ac)
482 {
483         if (ac->tid > 0) {
484                 g_source_remove(ac->tid);
485                 ac->tid = 0;
486         }
487 }
488 #endif
489
490 static int __aul_handler(aul_type type, bundle *b, void *data)
491 {
492         int ret;
493         const char **tep_path = NULL;
494         int len = 0;
495         int i;
496 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
497         const char *bg = NULL;
498         struct appcore *ac = data;
499 #endif
500
501         switch (type) {
502         case AUL_START:
503                 _DBG("[APP %d]     AUL event: AUL_START", _pid);
504                 tep_path = bundle_get_str_array(b, AUL_TEP_PATH, &len);
505                 if (tep_path) {
506                         for (i = 0; i < len; i++) {
507                                 ret = aul_check_tep_mount(tep_path[i]);
508                                 if (ret == -1) {
509                                         _ERR("mount request not completed within 1 sec");
510                                         exit(-1);
511                                 }
512                         }
513                 }
514
515 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
516                 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
517                 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
518                         _DBG("[__SUSPEND__] allowed background");
519                         ac->allowed_bg = true;
520                         __remove_suspend_timer(data);
521                 }
522 #endif
523
524                 __app_reset(data, b);
525                 break;
526         case AUL_RESUME:
527                 _DBG("[APP %d]     AUL event: AUL_RESUME", _pid);
528 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
529                 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
530                 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
531                         _DBG("[__SUSPEND__] allowed background");
532                         ac->allowed_bg = true;
533                         __remove_suspend_timer(data);
534                 }
535 #endif
536
537                 if (open.callback) {
538                         ret = open.callback(open.cbdata);
539                         if (ret == 0)
540                                 __app_resume(data);
541                 } else {
542                         __app_resume(data);
543                 }
544                 break;
545         case AUL_TERMINATE:
546                 _DBG("[APP %d]     AUL event: AUL_TERMINATE", _pid);
547 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
548                 if (!ac->allowed_bg)
549                         __remove_suspend_timer(data);
550 #endif
551
552                 __app_terminate(data);
553                 break;
554         case AUL_TERMINATE_BGAPP:
555                 _DBG("[APP %d]     AUL event: AUL_TERMINATE_BGAPP", _pid);
556 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
557                 if (!ac->allowed_bg)
558                         __remove_suspend_timer(data);
559 #endif
560
561                 __bgapp_terminate(data);
562                 break;
563         case AUL_PAUSE:
564                 _DBG("[APP %d]     AUL event: AUL_PAUSE", _pid);
565                 __app_pause(data);
566                 break;
567 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
568         case AUL_WAKE:
569                 _DBG("[APP %d]     AUL event: AUL_WAKE", _pid);
570                 if (!ac->allowed_bg && ac->suspended_state) {
571                         int suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
572                         __remove_suspend_timer(data);
573                         __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
574                         ac->suspended_state = false;
575                 }
576                 break;
577         case AUL_SUSPEND:
578                 _DBG("[APP %d]     AUL event: AUL_SUSPEND", _pid);
579                 if (!ac->allowed_bg && !ac->suspended_state) {
580                         __remove_suspend_timer(data);
581                         __flush_memory((gpointer)ac);
582                 }
583                 break;
584 #endif
585         default:
586                 _DBG("[APP %d]     AUL event: %d", _pid, type);
587                 /* do nothing */
588                 break;
589         }
590
591         return 0;
592 }
593
594
595 static void __clear(struct appcore *ac)
596 {
597         memset(ac, 0, sizeof(struct appcore));
598 }
599
600 EXPORT_API void appcore_get_app_core(struct appcore **ac)
601 {
602         *ac = &core;
603 }
604
605 EXPORT_API int appcore_set_open_cb(int (*cb) (void *),
606                                        void *data)
607 {
608         open.callback = cb;
609         open.cbdata = data;
610
611         return 0;
612 }
613
614 EXPORT_API int appcore_set_event_callback(enum appcore_event event,
615                                           int (*cb) (void *, void *), void *data)
616 {
617         struct appcore *ac = &core;
618         struct sys_op *op;
619         enum sys_event se;
620         int r = 0;
621
622         for (se = SE_UNKNOWN; se < SE_MAX; se++) {
623                 if (event == to_ae[se])
624                         break;
625         }
626
627         if (se == SE_UNKNOWN || se >= SE_MAX) {
628                 _ERR("Unregistered event");
629                 errno = EINVAL;
630                 return -1;
631         }
632
633         op = &ac->sops[se];
634
635         op->func = cb;
636         op->data = data;
637
638         if (op->func && !appcore_event_initialized[se]) {
639                 r = __add_vconf(ac, se);
640                 if (r < 0)
641                         _ERR("Add vconf callback failed");
642                 else
643                         appcore_event_initialized[se] = 1;
644         } else if (!op->func && appcore_event_initialized[se]) {
645                 r = __del_vconf(se);
646                 if (r < 0)
647                         _ERR("Delete vconf callback failed");
648                 else
649                         appcore_event_initialized[se] = 0;
650         }
651
652         return 0;
653 }
654
655 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
656 static gboolean __init_suspend(gpointer data)
657 {
658         int r;
659
660         r = _appcore_init_suspend_dbus_handler(&core);
661         if (r == -1) {
662                 _ERR("Initailzing suspended state handler failed");
663         }
664
665         return FALSE;
666 }
667 #endif
668
669 EXPORT_API int appcore_init(const char *name, const struct ui_ops *ops,
670                             int argc, char **argv)
671 {
672         int r;
673         char locale_dir[PATH_MAX];
674
675         if (core.state != 0) {
676                 _ERR("Already in use");
677                 errno = EALREADY;
678                 return -1;
679         }
680
681         if (ops == NULL || ops->cb_app == NULL) {
682                 _ERR("ops or callback function is null");
683                 errno = EINVAL;
684                 return -1;
685         }
686
687         r = __get_locale_resource_dir(locale_dir, sizeof(locale_dir));
688         r = set_i18n(name, locale_dir);
689         _retv_if(r == -1, -1);
690
691         r = aul_launch_init(__aul_handler, &core);
692         if (r < 0) {
693                 _ERR("Aul init failed: %d", r);
694                 goto err;
695         }
696
697         r = aul_launch_argv_handler(argc, argv);
698         if (r < 0) {
699                 _ERR("Aul argv handler failed: %d", r);
700                 goto err;
701         }
702
703         core.ops = ops;
704         core.state = 1;         /* TODO: use enum value */
705         core.tid = 0;
706         core.suspended_state = false;
707         core.allowed_bg = false;
708
709         _pid = getpid();
710
711 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
712         g_idle_add(__init_suspend, NULL);
713 #endif
714
715         return 0;
716  err:
717         __del_vconf_list();
718         __clear(&core);
719         return -1;
720 }
721
722 EXPORT_API void appcore_exit(void)
723 {
724         if (core.state) {
725                 __del_vconf_list();
726                 __clear(&core);
727 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
728                 __remove_suspend_timer(&core);
729 #endif
730         }
731         aul_finalize();
732 }
733
734 EXPORT_API int appcore_flush_memory(void)
735 {
736         int (*flush_fn) (int);
737
738         struct appcore *ac = &core;
739
740         if (!core.state) {
741                 _ERR("Appcore not initialized");
742                 return -1;
743         }
744
745         _DBG("[APP %d] Flushing memory ...", _pid);
746
747         if (ac->ops->cb_app)
748                 ac->ops->cb_app(AE_MEM_FLUSH, ac->ops->data, NULL);
749
750         flush_fn = dlsym(RTLD_DEFAULT, "sqlite3_release_memory");
751         if (flush_fn)
752                 flush_fn(SQLITE_FLUSH_MAX);
753
754         malloc_trim(0);
755         /*
756         *Disabled - the impact of stack_trim() is unclear
757         *stack_trim();
758         */
759
760         _DBG("[APP %d] Flushing memory DONE", _pid);
761
762         return 0;
763 }
764
765 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
766 static void __suspend_dbus_signal_handler(GDBusConnection *connection,
767                                         const gchar *sender_name,
768                                         const gchar *object_path,
769                                         const gchar *interface_name,
770                                         const gchar *signal_name,
771                                         GVariant *parameters,
772                                         gpointer user_data)
773 {
774         struct appcore *ac = (struct appcore *)user_data;
775         gint suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
776         gint pid;
777         gint status;
778
779         if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
780                 g_variant_get(parameters, "(ii)", &status, &pid);
781                 if (pid == getpid() && status == 0) { /* thawed */
782                         if (ac && !ac->allowed_bg && ac->suspended_state) {
783                                 __remove_suspend_timer(ac);
784                                 __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
785                                 ac->suspended_state = false;
786                                 __add_suspend_timer(ac);
787                         }
788                 }
789         }
790 }
791
792 int _appcore_init_suspend_dbus_handler(void *data)
793 {
794         GError *err = NULL;
795
796         if (__suspend_dbus_handler_initialized)
797                 return 0;
798
799         if (!bus) {
800                 bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
801                 if (!bus) {
802                         _ERR("Failed to connect to the D-BUS daemon: %s",
803                                                 err->message);
804                         g_error_free(err);
805                         return -1;
806                 }
807         }
808
809         __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
810                                                 bus,
811                                                 NULL,
812                                                 RESOURCED_FREEZER_INTERFACE,
813                                                 RESOURCED_FREEZER_SIGNAL,
814                                                 RESOURCED_FREEZER_PATH,
815                                                 NULL,
816                                                 G_DBUS_SIGNAL_FLAGS_NONE,
817                                                 __suspend_dbus_signal_handler,
818                                                 data,
819                                                 NULL);
820         if (__suspend_dbus_handler_initialized == 0) {
821                 _ERR("g_dbus_connection_signal_subscribe() is failed.");
822                 return -1;
823         }
824
825         _DBG("[__SUSPEND__] suspend signal initialized");
826
827         return 0;
828 }
829 #endif