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