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