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