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