Merge branch 'tizen_3.0' into tizen
[platform/core/appfw/app-core.git] / src / appcore.c
old mode 100755 (executable)
new mode 100644 (file)
index 13cbc31..20fb3c4
@@ -1,9 +1,5 @@
 /*
- *  app-core
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * Contact: Jayoun Lee <airjany@samsung.com>, Sewook Park <sewook7.park@samsung.com>, Jaeho Lee <jaeho81.lee@samsung.com>
+ * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,7 +12,6 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- *
  */
 
 
 #include <dlfcn.h>
 #include <vconf.h>
 #include <aul.h>
-#include <rua.h>
+#include <bundle_internal.h>
 #include "appcore-internal.h"
 
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+#include <gio/gio.h>
+
+#define RESOURCED_FREEZER_PATH "/Org/Tizen/Resourced/Freezer"
+#define RESOURCED_FREEZER_INTERFACE "org.tizen.resourced.freezer"
+#define RESOURCED_FREEZER_SIGNAL "FreezerState"
+
+int __appcore_init_suspend_dbus_handler(void *data);
+void __appcore_fini_suspend_dbus_handler(void);
+#endif
+
 #define SQLITE_FLUSH_MAX               (1024*1024)
 
-#define PKGNAME_MAX 256
-#define PATH_APP_ROOT "/opt/apps"
-#define PATH_RES "/res"
-#define PATH_LOCALE "/locale"
+#define PATH_LOCALE "locale"
 
 static struct appcore core;
 static pid_t _pid;
@@ -54,8 +57,11 @@ static enum appcore_event to_ae[SE_MAX] = {
        APPCORE_EVENT_LOW_BATTERY,      /* SE_LOWBAT */
        APPCORE_EVENT_LANG_CHANGE,      /* SE_LANGCGH */
        APPCORE_EVENT_REGION_CHANGE,
+       APPCORE_EVENT_SUSPENDED_STATE_CHANGE,
+       APPCORE_EVENT_UPDATE_REQUESTED,
 };
 
+static int appcore_event_initialized[SE_MAX] = {0,};
 
 enum cb_type {                 /* callback */
        _CB_NONE,
@@ -99,6 +105,8 @@ static int __sys_langchg_pre(void *data, void *evt);
 static int __sys_langchg(void *data, void *evt);
 static int __sys_regionchg_pre(void *data, void *evt);
 static int __sys_regionchg(void *data, void *evt);
+extern void aul_finalize();
+
 
 static struct evt_ops evtops[] = {
        {
@@ -131,93 +139,48 @@ static struct evt_ops evtops[] = {
         },
 };
 
-static int __get_dir_name(char *dirname)
-{
-       char pkg_name[PKGNAME_MAX];
-       int r;
-       int pid;
-
-       pid = getpid();
-       if (pid < 0)
-               return -1;
-
-       aul_app_get_pkgname_bypid(pid, pkg_name, PKGNAME_MAX);
-
-       r = snprintf(dirname, PATH_MAX, PATH_APP_ROOT "/%s" PATH_RES PATH_LOCALE,pkg_name);
-       if (r < 0)
-               return -1;
-
-       return 0;
-}
-
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+static GDBusConnection *bus;
+static guint __suspend_dbus_handler_initialized;
+#endif
 
-static int __get_cmd(char *buf)
+static int __get_locale_resource_dir(char *locale_dir, int size)
 {
-       FILE *fp;
-       int r;
-       char fname[FILENAME_MAX];
+       const char *res_path;
 
-       r = snprintf(fname, sizeof(fname), "/proc/%d/cmdline", getpid());
-       if (r < 0)
+       res_path = aul_get_app_resource_path();
+       if (res_path == NULL) {
+               _ERR("Failed to get resource path");
                return -1;
+       }
 
-       fp = fopen(fname, "r");
-       if (fp == NULL)
+       snprintf(locale_dir, size, "%s" PATH_LOCALE, res_path);
+       if (access(locale_dir, R_OK) != 0)
                return -1;
 
-       r = 0;
-       if (fgets(buf, PATH_MAX, fp) == NULL)
-               r = -1;
-
-       fclose(fp);
-
-       return r;
+       return 0;
 }
 
-static int __update_rua(bundle *b)
+static int __app_terminate(void *data)
 {
-       int r;
-       char buf[PATH_MAX];
-       struct rua_rec rec;
-
-       r = __get_cmd(buf);
-       if (r == -1)
-               return -1;
-
-       r = rua_init();
-       if (r == -1) {
-               _DBG("[APP %d] rua init error", _pid);
-               return -1;
-       }
-
-       memset(&rec, 0, sizeof(rec));
-
-       rec.pkg_name = getenv("PKG_NAME");
-       rec.app_path = buf;
-
-       if (b)
-               bundle_encode(b, (bundle_raw **)&rec.arg, NULL);
-
-       r = rua_add_history(&rec);
-       if (r == -1)
-               _DBG("[APP %d] rua add history error", _pid);
+       struct appcore *ac = data;
 
-       rua_fini();
+       _retv_if(ac == NULL || ac->ops == NULL, -1);
+       _retv_if(ac->ops->cb_app == NULL, 0);
 
-       if (rec.arg)
-               free(rec.arg);
+       ac->ops->cb_app(AE_TERMINATE, ac->ops->data, NULL);
 
        return 0;
 }
 
-static int __app_terminate(void *data)
+static int __bgapp_terminate(void *data)
 {
        struct appcore *ac = data;
 
        _retv_if(ac == NULL || ac->ops == NULL, -1);
        _retv_if(ac->ops->cb_app == NULL, 0);
 
-       ac->ops->cb_app(AE_TERMINATE, ac->ops->data, NULL);
+       ac->ops->cb_app(AE_TERMINATE_BGAPP, ac->ops->data, NULL);
 
        return 0;
 }
@@ -242,21 +205,39 @@ static int __app_reset(void *data, bundle * k)
        g_idle_add(__prt_ltime, ac);
 
        ac->ops->cb_app(AE_RESET, ac->ops->data, k);
-       __update_rua(k);
 
        return 0;
 }
 
 static int __app_resume(void *data)
 {
-       x_raise_win(getpid());
-       __update_rua(NULL);
+       struct appcore *ac = data;
+       _retv_if(ac == NULL || ac->ops == NULL, -1);
+       _retv_if(ac->ops->cb_app == NULL, 0);
+
+       ac->ops->cb_app(AE_RAISE, ac->ops->data, NULL);
+       return 0;
+}
+
+static int __app_pause(void *data)
+{
+       struct appcore *ac = data;
+       _retv_if(ac == NULL || ac->ops == NULL, -1);
+       _retv_if(ac->ops->cb_app == NULL, 0);
+
+       ac->ops->cb_app(AE_LOWER, ac->ops->data, NULL);
        return 0;
 }
 
-static int __def_lowbatt(struct appcore *ac)
+static int __app_update_requested(void *data)
 {
-       return __app_terminate(ac);
+       struct appcore *ac = data;
+
+       _retv_if(ac == NULL || ac->ops == NULL, -1);
+       _retv_if(ac->ops->cb_app == NULL, 0);
+       ac->ops->cb_app(AE_UPDATE_REQUESTED, ac->ops->data, NULL);
+
+       return 0;
 }
 
 static int __sys_do_default(struct appcore *ac, enum sys_event event)
@@ -276,7 +257,7 @@ static int __sys_do_default(struct appcore *ac, enum sys_event event)
        return r;
 }
 
-static int __sys_do(struct appcore *ac, enum sys_event event)
+static int __sys_do(struct appcore *ac, void *event_info, enum sys_event event)
 {
        struct sys_op *op;
 
@@ -287,23 +268,38 @@ static int __sys_do(struct appcore *ac, enum sys_event event)
        if (op->func == NULL)
                return __sys_do_default(ac, event);
 
-       return op->func(op->data);
+       return op->func(event_info, op->data);
 }
 
 static int __sys_lowmem_post(void *data, void *evt)
 {
+       keynode_t *key = evt;
+       int val;
+
+       val = vconf_keynode_get_int(key);
+
+       if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)     {
 #if defined(MEMORY_FLUSH_ACTIVATE)
-       struct appcore *ac = data;
-       ac->ops->cb_app(AE_LOWMEM_POST, ac->ops->data, NULL);
+               struct appcore *ac = data;
+               ac->ops->cb_app(AE_LOWMEM_POST, ac->ops->data, NULL);
 #else
-       malloc_trim(0);
+               malloc_trim(0);
 #endif
+       }
        return 0;
 }
 
 static int __sys_lowmem(void *data, void *evt)
 {
-       return __sys_do(data, SE_LOWMEM);
+       keynode_t *key = evt;
+       int val;
+
+       val = vconf_keynode_get_int(key);
+
+       if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)
+               return __sys_do(data, (void *)&val, SE_LOWMEM);
+
+       return 0;
 }
 
 static int __sys_lowbatt(void *data, void *evt)
@@ -315,7 +311,7 @@ static int __sys_lowbatt(void *data, void *evt)
 
        /* VCONFKEY_SYSMAN_BAT_CRITICAL_LOW or VCONFKEY_SYSMAN_POWER_OFF */
        if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
-               return __sys_do(data, SE_LOWBAT);
+               return __sys_do(data, (void *)&val, SE_LOWBAT);
 
        return 0;
 }
@@ -328,7 +324,12 @@ static int __sys_langchg_pre(void *data, void *evt)
 
 static int __sys_langchg(void *data, void *evt)
 {
-       return __sys_do(data, SE_LANGCHG);
+       keynode_t *key = evt;
+       char *val;
+
+       val = vconf_keynode_get_str(key);
+
+       return __sys_do(data, (void *)val, SE_LANGCHG);
 }
 
 static int __sys_regionchg_pre(void *data, void *evt)
@@ -339,7 +340,15 @@ static int __sys_regionchg_pre(void *data, void *evt)
 
 static int __sys_regionchg(void *data, void *evt)
 {
-       return __sys_do(data, SE_REGIONCHG);
+       keynode_t *key = evt;
+       char *val = NULL;
+       const char *name;
+
+       name = vconf_keynode_get_name(key);
+       if (!strcmp(name, VCONFKEY_REGIONFORMAT))
+               val = vconf_keynode_get_str(key);
+
+       return __sys_do(data, (void *)val, SE_REGIONCHG);
 }
 
 static void __vconf_do(struct evt_ops *eo, keynode_t * key, void *data)
@@ -381,61 +390,167 @@ static void __vconf_cb(keynode_t *key, void *data)
        }
 }
 
-static int __add_vconf(struct appcore *ac)
+static int __add_vconf(struct appcore *ac, enum sys_event se)
 {
-       int i;
        int r;
 
-       for (i = 0; i < sizeof(evtops) / sizeof(evtops[0]); i++) {
-               struct evt_ops *eo = &evtops[i];
-
-               switch (eo->type) {
-               case _CB_VCONF:
-                       r = vconf_notify_key_changed(eo->key.vkey, __vconf_cb,
-                                                    ac);
-                       break;
-               default:
-                       /* do nothing */
+       switch (se) {
+       case SE_LOWMEM:
+               r = vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __vconf_cb, ac);
+               break;
+       case SE_LOWBAT:
+               r = vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __vconf_cb, ac);
+               break;
+       case SE_LANGCHG:
+               r = vconf_notify_key_changed(VCONFKEY_LANGSET, __vconf_cb, ac);
+               break;
+       case SE_REGIONCHG:
+               r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, __vconf_cb, ac);
+               if (r < 0)
                        break;
-               }
+
+               r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __vconf_cb, ac);
+               break;
+       default:
+               r = -1;
+               break;
        }
 
-       return 0;
+       return r;
 }
 
-static int __del_vconf(void)
+static int __del_vconf(enum sys_event se)
 {
-       int i;
        int r;
 
-       for (i = 0; i < sizeof(evtops) / sizeof(evtops[0]); i++) {
-               struct evt_ops *eo = &evtops[i];
-
-               switch (eo->type) {
-               case _CB_VCONF:
-                       r = vconf_ignore_key_changed(eo->key.vkey, __vconf_cb);
-                       break;
-               default:
-                       /* do nothing */
+       switch (se) {
+       case SE_LOWMEM:
+               r = vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __vconf_cb);
+               break;
+       case SE_LOWBAT:
+               r = vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __vconf_cb);
+               break;
+       case SE_LANGCHG:
+               r = vconf_ignore_key_changed(VCONFKEY_LANGSET, __vconf_cb);
+               break;
+       case SE_REGIONCHG:
+               r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __vconf_cb);
+               if (r < 0)
                        break;
+
+               r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __vconf_cb);
+               break;
+       default:
+               r = -1;
+               break;
+       }
+
+       return r;
+}
+
+static int __del_vconf_list(void)
+{
+       int r;
+       enum sys_event se;
+
+       for (se = SE_LOWMEM; se < SE_MAX; se++) {
+               if (appcore_event_initialized[se]) {
+                       r = __del_vconf(se);
+                       if (r < 0)
+                               _ERR("Delete vconf callback failed");
+                       else
+                               appcore_event_initialized[se] = 0;
                }
        }
 
        return 0;
 }
 
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+static gboolean __flush_memory(gpointer data)
+{
+       int suspend = APPCORE_SUSPENDED_STATE_WILL_ENTER_SUSPEND;
+       struct appcore *ac = (struct appcore *)data;
+
+       appcore_flush_memory();
+
+       if (!ac)
+               return FALSE;
+
+       ac->tid = 0;
+
+       if (!ac->allowed_bg && !ac->suspended_state) {
+               _DBG("[__SUSPEND__] flush case");
+               __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
+               ac->suspended_state = true;
+       }
+
+       return FALSE;
+}
+
+static void __add_suspend_timer(struct appcore *ac)
+{
+       ac->tid = g_timeout_add_seconds(5, __flush_memory, ac);
+}
+
+static void __remove_suspend_timer(struct appcore *ac)
+{
+       if (ac->tid > 0) {
+               g_source_remove(ac->tid);
+               ac->tid = 0;
+       }
+}
+#endif
+
 static int __aul_handler(aul_type type, bundle *b, void *data)
 {
        int ret;
+       const char **tep_path = NULL;
+       int len = 0;
+       int i;
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+       const char *bg = NULL;
+       struct appcore *ac = data;
+       int suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
+#endif
 
        switch (type) {
        case AUL_START:
                _DBG("[APP %d]     AUL event: AUL_START", _pid);
+               tep_path = bundle_get_str_array(b, AUL_TEP_PATH, &len);
+               if (tep_path) {
+                       for (i = 0; i < len; i++) {
+                               ret = aul_check_tep_mount(tep_path[i]);
+                               if (ret == -1) {
+                                       _ERR("mount request not completed within 1 sec");
+                                       exit(-1);
+                               }
+                       }
+               }
+
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+               bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
+               if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
+                       _DBG("[__SUSPEND__] allowed background");
+                       ac->allowed_bg = true;
+                       __remove_suspend_timer(data);
+               }
+#endif
+
                __app_reset(data, b);
                break;
        case AUL_RESUME:
                _DBG("[APP %d]     AUL event: AUL_RESUME", _pid);
-               if(open.callback) {
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+               bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
+               if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
+                       _DBG("[__SUSPEND__] allowed background");
+                       ac->allowed_bg = true;
+                       __remove_suspend_timer(data);
+               }
+#endif
+
+               if (open.callback) {
                        ret = open.callback(open.cbdata);
                        if (ret == 0)
                                __app_resume(data);
@@ -445,8 +560,56 @@ static int __aul_handler(aul_type type, bundle *b, void *data)
                break;
        case AUL_TERMINATE:
                _DBG("[APP %d]     AUL event: AUL_TERMINATE", _pid);
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+               if (!ac->allowed_bg)
+                       __remove_suspend_timer(data);
+#endif
+
                __app_terminate(data);
                break;
+       case AUL_TERMINATE_BGAPP:
+               _DBG("[APP %d]     AUL event: AUL_TERMINATE_BGAPP", _pid);
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+               if (!ac->allowed_bg)
+                       __remove_suspend_timer(data);
+#endif
+
+               __bgapp_terminate(data);
+               break;
+       case AUL_PAUSE:
+               _DBG("[APP %d]     AUL event: AUL_PAUSE", _pid);
+               __app_pause(data);
+               break;
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+       case AUL_WAKE:
+               _DBG("[APP %d]     AUL event: AUL_WAKE", _pid);
+               if (!ac->allowed_bg && ac->suspended_state) {
+                       __remove_suspend_timer(data);
+                       __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
+                       ac->suspended_state = false;
+               }
+
+               if (b) {
+                       bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
+                       if (bg && strcmp(bg, "ALLOWED_BG") == 0) {
+                               _DBG("[__SUSPEND__] allowed background");
+                               ac->allowed_bg = true;
+                       }
+               }
+               break;
+       case AUL_SUSPEND:
+               _DBG("[APP %d]     AUL event: AUL_SUSPEND", _pid);
+               ac->allowed_bg = false;
+               if (!ac->suspended_state) {
+                       __remove_suspend_timer(data);
+                       __flush_memory((gpointer)ac);
+               }
+               break;
+#endif
+       case AUL_UPDATE_REQUESTED:
+               _DBG("[APP %d]     AUL event: AUL_UPDATE_REQUESTED", _pid);
+               __app_update_requested(data);
+               break;
        default:
                _DBG("[APP %d]     AUL event: %d", _pid, type);
                /* do nothing */
@@ -462,6 +625,11 @@ static void __clear(struct appcore *ac)
        memset(ac, 0, sizeof(struct appcore));
 }
 
+EXPORT_API void appcore_get_app_core(struct appcore **ac)
+{
+       *ac = &core;
+}
+
 EXPORT_API int appcore_set_open_cb(int (*cb) (void *),
                                       void *data)
 {
@@ -472,11 +640,12 @@ EXPORT_API int appcore_set_open_cb(int (*cb) (void *),
 }
 
 EXPORT_API int appcore_set_event_callback(enum appcore_event event,
-                                         int (*cb) (void *), void *data)
+                                         int (*cb) (void *, void *), void *data)
 {
        struct appcore *ac = &core;
        struct sys_op *op;
        enum sys_event se;
+       int r = 0;
 
        for (se = SE_UNKNOWN; se < SE_MAX; se++) {
                if (event == to_ae[se])
@@ -494,16 +663,42 @@ EXPORT_API int appcore_set_event_callback(enum appcore_event event,
        op->func = cb;
        op->data = data;
 
+       if (op->func && !appcore_event_initialized[se]) {
+               r = __add_vconf(ac, se);
+               if (r < 0)
+                       _ERR("Add vconf callback failed");
+               else
+                       appcore_event_initialized[se] = 1;
+       } else if (!op->func && appcore_event_initialized[se]) {
+               r = __del_vconf(se);
+               if (r < 0)
+                       _ERR("Delete vconf callback failed");
+               else
+                       appcore_event_initialized[se] = 0;
+       }
+
        return 0;
 }
 
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+static gboolean __init_suspend(gpointer data)
+{
+       int r;
 
+       r = __appcore_init_suspend_dbus_handler(&core);
+       if (r == -1) {
+               _ERR("Initailzing suspended state handler failed");
+       }
+
+       return FALSE;
+}
+#endif
 
 EXPORT_API int appcore_init(const char *name, const struct ui_ops *ops,
                            int argc, char **argv)
 {
        int r;
-       char dirname[PATH_MAX];
+       char locale_dir[PATH_MAX];
 
        if (core.state != 0) {
                _ERR("Already in use");
@@ -517,16 +712,10 @@ EXPORT_API int appcore_init(const char *name, const struct ui_ops *ops,
                return -1;
        }
 
-       r = __get_dir_name(dirname);
-       r = set_i18n(name, dirname);
+       r = __get_locale_resource_dir(locale_dir, sizeof(locale_dir));
+       r = set_i18n(name, locale_dir);
        _retv_if(r == -1, -1);
 
-       r = __add_vconf(&core);
-       if (r == -1) {
-               _ERR("Add vconf callback failed");
-               goto err;
-       }
-
        r = aul_launch_init(__aul_handler, &core);
        if (r < 0) {
                _ERR("Aul init failed: %d", r);
@@ -541,12 +730,19 @@ EXPORT_API int appcore_init(const char *name, const struct ui_ops *ops,
 
        core.ops = ops;
        core.state = 1;         /* TODO: use enum value */
+       core.tid = 0;
+       core.suspended_state = false;
+       core.allowed_bg = false;
 
        _pid = getpid();
 
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+       g_idle_add(__init_suspend, NULL);
+#endif
+
        return 0;
  err:
-       __del_vconf();
+       __del_vconf_list();
        __clear(&core);
        return -1;
 }
@@ -554,15 +750,19 @@ EXPORT_API int appcore_init(const char *name, const struct ui_ops *ops,
 EXPORT_API void appcore_exit(void)
 {
        if (core.state) {
-               __del_vconf();
+               __del_vconf_list();
                __clear(&core);
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+               __remove_suspend_timer(&core);
+               __appcore_fini_suspend_dbus_handler();
+#endif
        }
+       aul_finalize();
 }
 
 EXPORT_API int appcore_flush_memory(void)
 {
        int (*flush_fn) (int);
-       int size = 0;
 
        struct appcore *ac = &core;
 
@@ -573,14 +773,12 @@ EXPORT_API int appcore_flush_memory(void)
 
        _DBG("[APP %d] Flushing memory ...", _pid);
 
-       if (ac->ops->cb_app) {
+       if (ac->ops->cb_app)
                ac->ops->cb_app(AE_MEM_FLUSH, ac->ops->data, NULL);
-       }
 
        flush_fn = dlsym(RTLD_DEFAULT, "sqlite3_release_memory");
-       if (flush_fn) {
-               size = flush_fn(SQLITE_FLUSH_MAX);
-       }
+       if (flush_fn)
+               flush_fn(SQLITE_FLUSH_MAX);
 
        malloc_trim(0);
        /*
@@ -592,3 +790,85 @@ EXPORT_API int appcore_flush_memory(void)
 
        return 0;
 }
+
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+static void __suspend_dbus_signal_handler(GDBusConnection *connection,
+                                       const gchar *sender_name,
+                                       const gchar *object_path,
+                                       const gchar *interface_name,
+                                       const gchar *signal_name,
+                                       GVariant *parameters,
+                                       gpointer user_data)
+{
+       struct appcore *ac = (struct appcore *)user_data;
+       gint suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
+       gint pid;
+       gint status;
+
+       if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
+               g_variant_get(parameters, "(ii)", &status, &pid);
+               if (pid == getpid() && status == 0) { /* thawed */
+                       if (ac && !ac->allowed_bg && ac->suspended_state) {
+                               __remove_suspend_timer(ac);
+                               __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
+                               ac->suspended_state = false;
+                               __add_suspend_timer(ac);
+                       }
+               }
+       }
+}
+
+int __appcore_init_suspend_dbus_handler(void *data)
+{
+       GError *err = NULL;
+
+       if (__suspend_dbus_handler_initialized)
+               return 0;
+
+       if (!bus) {
+               bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+               if (!bus) {
+                       _ERR("Failed to connect to the D-BUS daemon: %s",
+                                               err->message);
+                       g_error_free(err);
+                       return -1;
+               }
+       }
+
+       __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
+                                               bus,
+                                               NULL,
+                                               RESOURCED_FREEZER_INTERFACE,
+                                               RESOURCED_FREEZER_SIGNAL,
+                                               RESOURCED_FREEZER_PATH,
+                                               NULL,
+                                               G_DBUS_SIGNAL_FLAGS_NONE,
+                                               __suspend_dbus_signal_handler,
+                                               data,
+                                               NULL);
+       if (__suspend_dbus_handler_initialized == 0) {
+               _ERR("g_dbus_connection_signal_subscribe() is failed.");
+               return -1;
+       }
+
+       _DBG("[__SUSPEND__] suspend signal initialized");
+
+       return 0;
+}
+
+void __appcore_fini_suspend_dbus_handler(void)
+{
+       if (bus == NULL)
+               return;
+
+       if (__suspend_dbus_handler_initialized) {
+               g_dbus_connection_signal_unsubscribe(bus,
+                               __suspend_dbus_handler_initialized);
+               __suspend_dbus_handler_initialized = 0;
+       }
+
+       g_object_unref(bus);
+       bus = NULL;
+}
+#endif
+