Fix background management feature
[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         int suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
503 #endif
504
505         switch (type) {
506         case AUL_START:
507                 _DBG("[APP %d]     AUL event: AUL_START", _pid);
508                 tep_path = bundle_get_str_array(b, AUL_TEP_PATH, &len);
509                 if (tep_path) {
510                         for (i = 0; i < len; i++) {
511                                 ret = aul_check_tep_mount(tep_path[i]);
512                                 if (ret == -1) {
513                                         _ERR("mount request not completed within 1 sec");
514                                         exit(-1);
515                                 }
516                         }
517                 }
518
519 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
520                 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
521                 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
522                         _DBG("[__SUSPEND__] allowed background");
523                         ac->allowed_bg = true;
524                         __remove_suspend_timer(data);
525                 }
526 #endif
527
528                 __app_reset(data, b);
529                 break;
530         case AUL_RESUME:
531                 _DBG("[APP %d]     AUL event: AUL_RESUME", _pid);
532 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
533                 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
534                 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
535                         _DBG("[__SUSPEND__] allowed background");
536                         ac->allowed_bg = true;
537                         __remove_suspend_timer(data);
538                 }
539 #endif
540
541                 if (open.callback) {
542                         ret = open.callback(open.cbdata);
543                         if (ret == 0)
544                                 __app_resume(data);
545                 } else {
546                         __app_resume(data);
547                 }
548                 break;
549         case AUL_TERMINATE:
550                 _DBG("[APP %d]     AUL event: AUL_TERMINATE", _pid);
551 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
552                 if (!ac->allowed_bg)
553                         __remove_suspend_timer(data);
554 #endif
555
556                 __app_terminate(data);
557                 break;
558         case AUL_TERMINATE_BGAPP:
559                 _DBG("[APP %d]     AUL event: AUL_TERMINATE_BGAPP", _pid);
560 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
561                 if (!ac->allowed_bg)
562                         __remove_suspend_timer(data);
563 #endif
564
565                 __bgapp_terminate(data);
566                 break;
567         case AUL_PAUSE:
568                 _DBG("[APP %d]     AUL event: AUL_PAUSE", _pid);
569                 __app_pause(data);
570                 break;
571 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
572         case AUL_WAKE:
573                 _DBG("[APP %d]     AUL event: AUL_WAKE", _pid);
574                 if (!ac->allowed_bg && ac->suspended_state) {
575                         __remove_suspend_timer(data);
576                         __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
577                         ac->suspended_state = false;
578                 }
579
580                 if (b) {
581                         bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
582                         if (bg && strcmp(bg, "ALLOWED_BG") == 0) {
583                                 _DBG("[__SUSPEND__] allowed background");
584                                 ac->allowed_bg = true;
585                         }
586                 }
587                 break;
588         case AUL_SUSPEND:
589                 _DBG("[APP %d]     AUL event: AUL_SUSPEND", _pid);
590                 ac->allowed_bg = false;
591                 if (!ac->suspended_state) {
592                         __remove_suspend_timer(data);
593                         __flush_memory((gpointer)ac);
594                 }
595                 break;
596 #endif
597         default:
598                 _DBG("[APP %d]     AUL event: %d", _pid, type);
599                 /* do nothing */
600                 break;
601         }
602
603         return 0;
604 }
605
606
607 static void __clear(struct appcore *ac)
608 {
609         memset(ac, 0, sizeof(struct appcore));
610 }
611
612 EXPORT_API void appcore_get_app_core(struct appcore **ac)
613 {
614         *ac = &core;
615 }
616
617 EXPORT_API int appcore_set_open_cb(int (*cb) (void *),
618                                        void *data)
619 {
620         open.callback = cb;
621         open.cbdata = data;
622
623         return 0;
624 }
625
626 EXPORT_API int appcore_set_event_callback(enum appcore_event event,
627                                           int (*cb) (void *, void *), void *data)
628 {
629         struct appcore *ac = &core;
630         struct sys_op *op;
631         enum sys_event se;
632         int r = 0;
633
634         for (se = SE_UNKNOWN; se < SE_MAX; se++) {
635                 if (event == to_ae[se])
636                         break;
637         }
638
639         if (se == SE_UNKNOWN || se >= SE_MAX) {
640                 _ERR("Unregistered event");
641                 errno = EINVAL;
642                 return -1;
643         }
644
645         op = &ac->sops[se];
646
647         op->func = cb;
648         op->data = data;
649
650         if (op->func && !appcore_event_initialized[se]) {
651                 r = __add_vconf(ac, se);
652                 if (r < 0)
653                         _ERR("Add vconf callback failed");
654                 else
655                         appcore_event_initialized[se] = 1;
656         } else if (!op->func && appcore_event_initialized[se]) {
657                 r = __del_vconf(se);
658                 if (r < 0)
659                         _ERR("Delete vconf callback failed");
660                 else
661                         appcore_event_initialized[se] = 0;
662         }
663
664         return 0;
665 }
666
667 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
668 static gboolean __init_suspend(gpointer data)
669 {
670         int r;
671
672         r = __appcore_init_suspend_dbus_handler(&core);
673         if (r == -1) {
674                 _ERR("Initailzing suspended state handler failed");
675         }
676
677         return FALSE;
678 }
679 #endif
680
681 EXPORT_API int appcore_init(const char *name, const struct ui_ops *ops,
682                             int argc, char **argv)
683 {
684         int r;
685         char locale_dir[PATH_MAX];
686
687         if (core.state != 0) {
688                 _ERR("Already in use");
689                 errno = EALREADY;
690                 return -1;
691         }
692
693         if (ops == NULL || ops->cb_app == NULL) {
694                 _ERR("ops or callback function is null");
695                 errno = EINVAL;
696                 return -1;
697         }
698
699         r = __get_locale_resource_dir(locale_dir, sizeof(locale_dir));
700         r = set_i18n(name, locale_dir);
701         _retv_if(r == -1, -1);
702
703         r = aul_launch_init(__aul_handler, &core);
704         if (r < 0) {
705                 _ERR("Aul init failed: %d", r);
706                 goto err;
707         }
708
709         r = aul_launch_argv_handler(argc, argv);
710         if (r < 0) {
711                 _ERR("Aul argv handler failed: %d", r);
712                 goto err;
713         }
714
715         core.ops = ops;
716         core.state = 1;         /* TODO: use enum value */
717         core.tid = 0;
718         core.suspended_state = false;
719         core.allowed_bg = false;
720
721         _pid = getpid();
722
723 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
724         g_idle_add(__init_suspend, NULL);
725 #endif
726
727         return 0;
728  err:
729         __del_vconf_list();
730         __clear(&core);
731         return -1;
732 }
733
734 EXPORT_API void appcore_exit(void)
735 {
736         if (core.state) {
737                 __del_vconf_list();
738                 __clear(&core);
739 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
740                 __remove_suspend_timer(&core);
741                 __appcore_fini_suspend_dbus_handler();
742 #endif
743         }
744         aul_finalize();
745 }
746
747 EXPORT_API int appcore_flush_memory(void)
748 {
749         int (*flush_fn) (int);
750
751         struct appcore *ac = &core;
752
753         if (!core.state) {
754                 _ERR("Appcore not initialized");
755                 return -1;
756         }
757
758         _DBG("[APP %d] Flushing memory ...", _pid);
759
760         if (ac->ops->cb_app)
761                 ac->ops->cb_app(AE_MEM_FLUSH, ac->ops->data, NULL);
762
763         flush_fn = dlsym(RTLD_DEFAULT, "sqlite3_release_memory");
764         if (flush_fn)
765                 flush_fn(SQLITE_FLUSH_MAX);
766
767         malloc_trim(0);
768         /*
769         *Disabled - the impact of stack_trim() is unclear
770         *stack_trim();
771         */
772
773         _DBG("[APP %d] Flushing memory DONE", _pid);
774
775         return 0;
776 }
777
778 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
779 static void __suspend_dbus_signal_handler(GDBusConnection *connection,
780                                         const gchar *sender_name,
781                                         const gchar *object_path,
782                                         const gchar *interface_name,
783                                         const gchar *signal_name,
784                                         GVariant *parameters,
785                                         gpointer user_data)
786 {
787         struct appcore *ac = (struct appcore *)user_data;
788         gint suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
789         gint pid;
790         gint status;
791
792         if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
793                 g_variant_get(parameters, "(ii)", &status, &pid);
794                 if (pid == getpid() && status == 0) { /* thawed */
795                         if (ac && !ac->allowed_bg && ac->suspended_state) {
796                                 __remove_suspend_timer(ac);
797                                 __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
798                                 ac->suspended_state = false;
799                                 __add_suspend_timer(ac);
800                         }
801                 }
802         }
803 }
804
805 int __appcore_init_suspend_dbus_handler(void *data)
806 {
807         GError *err = NULL;
808
809         if (__suspend_dbus_handler_initialized)
810                 return 0;
811
812         if (!bus) {
813                 bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
814                 if (!bus) {
815                         _ERR("Failed to connect to the D-BUS daemon: %s",
816                                                 err->message);
817                         g_error_free(err);
818                         return -1;
819                 }
820         }
821
822         __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
823                                                 bus,
824                                                 NULL,
825                                                 RESOURCED_FREEZER_INTERFACE,
826                                                 RESOURCED_FREEZER_SIGNAL,
827                                                 RESOURCED_FREEZER_PATH,
828                                                 NULL,
829                                                 G_DBUS_SIGNAL_FLAGS_NONE,
830                                                 __suspend_dbus_signal_handler,
831                                                 data,
832                                                 NULL);
833         if (__suspend_dbus_handler_initialized == 0) {
834                 _ERR("g_dbus_connection_signal_subscribe() is failed.");
835                 return -1;
836         }
837
838         _DBG("[__SUSPEND__] suspend signal initialized");
839
840         return 0;
841 }
842
843 void __appcore_fini_suspend_dbus_handler(void)
844 {
845         if (bus == NULL)
846                 return;
847
848         if (__suspend_dbus_handler_initialized) {
849                 g_dbus_connection_signal_unsubscribe(bus,
850                                 __suspend_dbus_handler_initialized);
851                 __suspend_dbus_handler_initialized = 0;
852         }
853
854         g_object_unref(bus);
855         bus = NULL;
856 }
857 #endif
858