add background management 92/64292/4 accepted/tizen/common/20160428.144214 accepted/tizen/common/20160502.183623 accepted/tizen/ivi/20160502.114028 accepted/tizen/mobile/20160502.113935 accepted/tizen/tv/20160502.113957 accepted/tizen/wearable/20160502.114015 submit/tizen/20160427.083148 submit/tizen/20160502.051049 submit/tizen/20160502.053803
authorDaehyeon Jung <darrenh.jung@samsung.com>
Tue, 29 Mar 2016 09:49:56 +0000 (18:49 +0900)
committerDaehyeon Jung <darrenh.jung@samsung.com>
Wed, 27 Apr 2016 07:57:48 +0000 (16:57 +0900)
Change-Id: I412e68a8088badedf884259426386a4f7c69b8ca
Signed-off-by: Daehyeon Jung <darrenh.jung@samsung.com>
CMakeLists.txt
include/appcore-agent.h
packaging/appcore-agent.spec
src/appcore-agent.c
src/service_app_main.c

index 1cf11df..47ae7ff 100644 (file)
@@ -11,6 +11,10 @@ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
 
 SET(CMAKE_SKIP_BUILD_RPATH TRUE)
 
+IF(_APPFW_FEATURE_BACKGROUND_MANAGEMENT)
+       ADD_DEFINITIONS("-D_APPFW_FEATURE_BACKGROUND_MANAGEMENT")
+ENDIF(_APPFW_FEATURE_BACKGROUND_MANAGEMENT)
+
 #################################################################
 # Build appcore-agent Library
 # ------------------------------
index 164a8f8..53a7316 100644 (file)
@@ -57,6 +57,8 @@ enum appcore_agent_event {
                        /**< Language setting is changed */
        APPCORE_AGENT_EVENT_REGION_CHANGE,
                        /**< Region setting is changed */
+       APPCORE_AGENT_EVENT_SUSPENDED_STATE_CHANGE,
+                       /**< Suspend state is changed */
 };
 
 int appcore_agent_main(int argc, char **argv, struct agentcore_ops *ops);
@@ -68,6 +70,7 @@ int appcore_agent_terminate_without_restart();
 int appcore_agent_set_event_callback(enum appcore_agent_event event,
                                          int (*cb) (void *, void *), void *data);
 
+int _appcore_agent_init_suspend_dbus_handler(void *data);
 #ifdef __cplusplus
 }
 #endif
index cf705ff..2ed30cf 100644 (file)
@@ -19,21 +19,49 @@ BuildRequires:  pkgconfig(vconf-internal-keys)
 %description
 Service Application basic
 
+%if "%{?profile}" == "wearable"
+%define appfw_feature_background_management 1
+%else
+%if "%{?profile}" == "mobile"
+%define appfw_feature_background_management 1
+%else
+%if "%{?profile}" == "tv"
+%define appfw_feature_background_management 0
+%endif
+%endif
+%endif
+
 %package devel
 Summary:        Application Core Agent
 Group:          Application Framework/Development
 Requires:       %{name} = %{version}-%{release}
+
 %description devel
-Service Application basic (development files)
+appcore agent (developement files)
+
+%package -n capi-appfw-service-application-devel
+Summary:    service appliation
+Group:      Development/Libraries
+Requires:    appcore-agent-devel = %{version}-%{release}
+
+%description -n capi-appfw-service-application-devel
+Service Application basic (developement files)
 
 %prep
 %setup -q
 cp %{SOURCE1001} .
 
 %build
+
+%if 0%{?appfw_feature_background_management}
+_APPFW_FEATURE_BACKGROUND_MANAGEMENT=ON
+%endif
+
 MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
 
-%cmake . -DFULLVER=%{version} -DMAJORVER=${MAJORVER}
+%cmake -DFULLVER=%{version} -DMAJORVER=${MAJORVER} \
+       -D_APPFW_FEATURE_BACKGROUND_MANAGEMENT:BOOL=${_APPFW_FEATURE_BACKGROUND_MANAGEMENT} \
+       .
 %__make %{?_smp_mflags}
 
 %install
@@ -47,14 +75,16 @@ MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
 %manifest %{name}.manifest
 %license LICENSE
 %defattr(-,root,root,-)
-%{_libdir}/libappcore-agent.so.*
+%{_libdir}/libappcore-agent.so*
 
 %files devel
 %manifest %{name}.manifest
 %defattr(-,root,root,-)
 %{_libdir}/pkgconfig/appcore-agent.pc
-%{_libdir}/pkgconfig/capi-appfw-service-application.pc
-%{_libdir}/libappcore-agent.so
 %{_includedir}/appcore-agent/appcore-agent.h
+
+
+%files -n capi-appfw-service-application-devel
 %{_includedir}/appcore-agent/service_app.h
 %{_includedir}/appcore-agent/service_app_extension.h
+%{_libdir}/pkgconfig/capi-appfw-service-application.pc
index 4848a2f..5a5a4f0 100644 (file)
 #include <malloc.h>
 #include <Ecore.h>
 #include <linux/limits.h>
+#include <dlfcn.h>
+#include <glib.h>
 
-#include "aul.h"
-#include "appcore-agent.h"
+#include <bundle.h>
+#include <aul.h>
 #include <appcore-common.h>
 #include <app_control_internal.h>
 #include <dlog.h>
 #include <vconf.h>
 
+#include "appcore-agent.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.frezer"
+#define RESOURCED_FREEZER_SIGNAL "FreezerState"
+#define APPFW_SUSPEND_HINT_PATH "/Org/Tizen/Appfw/SuspendHint"
+#define APPFW_SUSPEND_HINT_INTERFACE "org.tizen.appfw.SuspendHint"
+#define APPFW_SUSPEND_HINT_SIGNAL "SuspendHint"
+
+#endif
+
 #ifdef LOG_TAG
 #undef LOG_TAG
 #endif
 
 #define LOG_TAG "APPCORE_AGENT"
+#define SQLITE_FLUSH_MAX       (1024 * 1024)
 
 #define _ERR(fmt, arg...) LOGE(fmt, ##arg)
 #define _INFO(fmt, arg...) LOGI(fmt, ##arg)
@@ -112,6 +129,7 @@ enum sys_event {
        SE_LOWBAT,
        SE_LANGCHG,
        SE_REGIONCHG,
+       SE_SUSPENDED_STATE,
        SE_MAX
 };
 
@@ -142,6 +160,7 @@ static enum appcore_agent_event to_ae[SE_MAX] = {
        APPCORE_AGENT_EVENT_LOW_BATTERY,        /* SE_LOWBAT */
        APPCORE_AGENT_EVENT_LANG_CHANGE,        /* SE_LANGCHG */
        APPCORE_AGENT_EVENT_REGION_CHANGE,      /* SE_REGIONCHG */
+       APPCORE_AGENT_EVENT_SUSPENDED_STATE_CHANGE, /* SE_SUSPENDED_STATE */
 };
 
 static int appcore_agent_event_initialized[SE_MAX] = {0};
@@ -153,6 +172,11 @@ enum cb_type {                     /* callback */
        _CB_VCONF,
 };
 
+enum appcore_agent_suspended_state {
+       APPCORE_AGENT_SUSPENDED_STATE_WILL_ENTER_SUSPEND = 0,
+       APPCORE_AGENT_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND
+};
+
 struct evt_ops {
        enum cb_type type;
        union {
@@ -173,6 +197,7 @@ struct evt_ops {
 struct agent_priv {
        enum agent_state state;
 
+       struct agent_appcore *app_core;
        struct agentcore_ops *ops;
 };
 
@@ -193,6 +218,9 @@ struct sys_op {
 
 struct agent_appcore {
        int state;
+       unsigned int tid;
+       bool suspended_state;
+       bool allowed_bg;
 
        const struct agent_ops *ops;
        struct sys_op sops[SE_MAX];
@@ -239,11 +267,140 @@ static struct evt_ops evtops[] = {
         },
 };
 
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+static GDBusConnection *bus = NULL;
+static guint __suspend_dbus_handler_initialized = 0;
+#endif
+
 extern int app_control_create_event(bundle *data, struct app_control_s **app_control);
+static int __sys_do(struct agent_appcore *ac, void *event_info, enum sys_event event);
+
+static int appcore_agent_flush_memory(void)
+{
+       int (*flush_fn) (int);
+
+       if (!core.state) {
+               _ERR("Appcore not initialized");
+               return -1;
+       }
+
+       flush_fn = dlsym(RTLD_DEFAULT, "sqlite3_release_memory");
+       if (flush_fn) {
+               flush_fn(SQLITE_FLUSH_MAX);
+       }
+
+       malloc_trim(0);
+
+       return 0;
+}
+
+static int _appcore_agent_request_to_suspend(int pid)
+{
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+       GError *err = NULL;
+
+       if (bus == NULL) {
+               bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+               if (bus == NULL) {
+                       _ERR("g_bus_get_sync() is failed: %s", err->message);
+                       g_error_free(err);
+                       return -1;
+               }
+       }
+
+       if (g_dbus_connection_emit_signal(bus,
+                                       NULL,
+                                       APPFW_SUSPEND_HINT_PATH,
+                                       APPFW_SUSPEND_HINT_INTERFACE,
+                                       APPFW_SUSPEND_HINT_SIGNAL,
+                                       g_variant_new("(i)", pid),
+                                       &err) == FALSE) {
+               _ERR("g_dbus_connection_emit_signal() is failed: %s",
+                                       err->message);
+               g_error_free(err);
+               return -1;
+       }
+
+       if (g_dbus_connection_flush_sync(bus, NULL, &err) == FALSE) {
+               _ERR("g_dbus_connection_flush_sync() is failed: %s",
+                                       err->message);
+               g_error_free(err);
+               return -1;
+       }
+
+       _DBG("[__SUSPEND__] Send suspend hint, pid: %d", pid);
+#endif
+       return 0;
+}
+
+static void __prepare_to_suspend(void *data)
+{
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+       int suspend = APPCORE_AGENT_SUSPENDED_STATE_WILL_ENTER_SUSPEND;
+       struct agent_appcore *ac = data;
+
+       if (ac && !ac->allowed_bg && !ac->suspended_state) {
+               _DBG("[__SUSPEND__]");
+               __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
+               _appcore_agent_request_to_suspend(getpid()); /* send dbus signal to resourced */
+               ac->suspended_state = true;
+       }
+#endif
+}
+
+static void __exit_from_suspend(void *data)
+{
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+       int suspend = APPCORE_AGENT_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
+       struct agent_appcore *ac = data;
+
+       if (ac && !ac->allowed_bg && ac->suspended_state) {
+               _DBG("[__SUSPEND__]");
+               __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
+               ac->suspended_state = false;
+       }
+#endif
+}
+
+static gboolean __flush_memory(gpointer data)
+{
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+       struct agent_appcore *ac = (struct agent_appcore *)data;
+
+       appcore_agent_flush_memory();
+
+       if (!ac) {
+               return FALSE;
+       }
+       ac->tid = 0;
+
+       _DBG("[__SUSPEND__] flush case");
+       __prepare_to_suspend(ac);
+#endif
+       return FALSE;
+}
+
+static void __add_suspend_timer(struct agent_appcore *ac)
+{
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+       ac->tid = g_timeout_add_seconds(5, __flush_memory, ac);
+#endif
+}
+
+static void __remove_suspend_timer(struct agent_appcore *ac)
+{
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+       if (ac->tid > 0) {
+               g_source_remove(ac->tid);
+               ac->tid = 0;
+       }
+#endif
+}
 
 static void __exit_loop(void *data)
 {
        ecore_main_loop_quit();
+       __remove_suspend_timer(&core);
 }
 
 static void __do_app(enum agent_event event, void *data, bundle * b)
@@ -297,6 +454,7 @@ static int __set_data(struct agent_priv *agent, struct agentcore_ops *ops)
        }
 
        agent->ops = ops;
+       agent->app_core = NULL;
 
        _pid = getpid();
 
@@ -360,7 +518,7 @@ static int __sys_do(struct agent_appcore *ac, void *event_info, enum sys_event e
 static int __sys_lowmem_post(void *data, void *evt)
 {
 #if defined(MEMORY_FLUSH_ACTIVATE)
-       struct appcore *ac = data;
+       struct agent_appcore *ac = data;
        ac->ops->cb_app(AE_LOWMEM_POST, ac->ops->data, NULL);
 #else
        malloc_trim(0);
@@ -585,11 +743,27 @@ static int __del_vconf_list(void)
 
 static int __aul_handler(aul_type type, bundle *b, void *data)
 {
+       int ret = 0;
+       char *bg = NULL;
+       struct agent_appcore *ac = data;
+
        switch (type) {
        case AUL_START:
-               __agent_request(data, b);
+               bundle_get_str(b, AUL_K_ALLOWED_BG, &bg);
+               if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
+                       _DBG("[__SUSPEND__] allowed background");
+                       ac->allowed_bg = true;
+                       __remove_suspend_timer(data);
+               }
+               ret = __agent_request(data, b);
                break;
        case AUL_RESUME:
+               bundle_get_str(b, AUL_K_ALLOWED_BG, &bg);
+               if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
+                       _DBG("[__SUSPEND__] allowed background");
+                       ac->allowed_bg = true;
+                       __remove_suspend_timer(data);
+               }
                break;
 /*     case AUL_STOP:
                __service_stop(data);
@@ -597,14 +771,30 @@ static int __aul_handler(aul_type type, bundle *b, void *data)
 */
        case AUL_TERMINATE:
        case AUL_TERMINATE_BGAPP:
-               __agent_terminate(data);
+               if (!ac->allowed_bg) {
+                       __remove_suspend_timer(data);
+               }
+               ret = __agent_terminate(data);
+               break;
+       case AUL_SUSPEND:
+               if (!ac->allowed_bg) {
+                       _DBG("[__SUSPEND__] suspend");
+                       __add_suspend_timer(data);
+               }
+               break;
+       case AUL_WAKE:
+               if (!ac->allowed_bg) {
+                       _DBG("[__SUSPEND__] wake");
+                       __remove_suspend_timer(data);
+                       __exit_from_suspend(data);
+               }
                break;
        default:
                /* do nothing */
                break;
        }
 
-       return 0;
+       return ret;
 }
 
 static int __get_package_app_name(int pid, char **app_name)
@@ -674,6 +864,19 @@ EXPORT_API int appcore_agent_set_event_callback(enum appcore_agent_event event,
        return r;
 }
 
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+static gboolean __init_suspend(gpointer data)
+{
+       int r;
+
+       r = _appcore_agent_init_suspend_dbus_handler(&core);
+       if (r == -1)
+               _ERR("Initailzing suspended state handler failed");
+
+       return FALSE;
+}
+#endif
+
 EXPORT_API int appcore_agent_init(const struct agent_ops *ops,
                            int argc, char **argv)
 {
@@ -704,6 +907,10 @@ EXPORT_API int appcore_agent_init(const struct agent_ops *ops,
        free(app_name);
        _retv_if(r == -1, -1);
 
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+       g_idle_add(__init_suspend, NULL);
+#endif
+
        r = aul_launch_init(__aul_handler, &core);
        if (r < 0)
                goto err;
@@ -713,19 +920,26 @@ EXPORT_API int appcore_agent_init(const struct agent_ops *ops,
                goto err;
 
        core.ops = ops;
-       core.state = 1; /* TODO: use enum value */
+       core.state = 1;         /* TODO: use enum value */
+       core.tid = 0;
+       core.suspended_state = false;
+       core.allowed_bg = false;
 
        return 0;
  err:
        __del_vconf_list();
-
        return -1;
 }
 
+static void appcore_agent_get_app_core(struct agent_appcore **ac)
+{
+       *ac = &core;
+}
 
 static int __before_loop(struct agent_priv *agent, int argc, char **argv)
 {
        int r;
+       struct agent_appcore *ac = NULL;
 
        if (argc <= 0 || argv == NULL) {
                errno = EINVAL;
@@ -737,6 +951,10 @@ static int __before_loop(struct agent_priv *agent, int argc, char **argv)
        r = appcore_agent_init(&s_ops, argc, argv);
        _retv_if(r == -1, -1);
 
+       appcore_agent_get_app_core(&ac);
+       agent->app_core = ac;
+       SECURE_LOGD("[__SUSPEND__] agent appcore initialized, appcore addr: 0x%x", ac);
+
        if (agent->ops && agent->ops->create) {
                r = agent->ops->create(agent->ops->data);
                if (r < 0) {
@@ -797,3 +1015,70 @@ EXPORT_API int appcore_agent_main(int argc, char **argv,
 
        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 agent_appcore *ac = (struct agent_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_agent_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;
+}
+
+#endif
index a8704f7..24afe8f 100644 (file)
@@ -94,7 +94,7 @@ EXPORT_API void service_app_exit_without_restart(void)
        appcore_agent_terminate_without_restart();
 }
 
-#define SERVICE_APP_EVENT_MAX 5
+#define SERVICE_APP_EVENT_MAX 6
 static Eina_List *handler_list[SERVICE_APP_EVENT_MAX] = {NULL, };
 static int handler_initialized = 0;
 static int appcore_agent_initialized = 0;
@@ -125,6 +125,7 @@ static void _free_handler_list(void)
 
        for (i = 0; i < SERVICE_APP_EVENT_MAX; i++) {
                EINA_LIST_FREE(handler_list[i], handler)
+               if (handler)
                        free(handler);
        }
 
@@ -208,6 +209,25 @@ static int _service_app_region_changed(void *event_info, void *data)
        return APP_ERROR_NONE;
 }
 
+static int _service_app_appcore_suspended_state_changed(void *event_info, void *data)
+{
+       Eina_List *l;
+       app_event_handler_h handler;
+       struct app_event_info event;
+
+       LOGI("_service_app_appcore_suspended_state_changed");
+       LOGD("[__SUSPEND__] suspended state: %d (0: suspend, 1: wake)", *(int *)event_info);
+
+       event.type = APP_EVENT_SUSPENDED_STATE_CHANGED;
+       event.value = event_info;
+
+       EINA_LIST_FOREACH(handler_list[APP_EVENT_SUSPENDED_STATE_CHANGED], l, handler) {
+               handler->cb(&event, handler->data);
+       }
+
+       return APP_ERROR_NONE;
+}
+
 static void _service_app_appcore_agent_set_event_cb(app_event_type_e event_type)
 {
        switch (event_type) {
@@ -223,6 +243,10 @@ static void _service_app_appcore_agent_set_event_cb(app_event_type_e event_type)
        case APP_EVENT_REGION_FORMAT_CHANGED:
                appcore_agent_set_event_callback(APPCORE_AGENT_EVENT_REGION_CHANGE, _service_app_region_changed, NULL);
                break;
+       case APP_EVENT_SUSPENDED_STATE_CHANGED:
+               LOGD("[__SUSPEND__]");
+               appcore_agent_set_event_callback(APPCORE_AGENT_EVENT_SUSPENDED_STATE_CHANGE, _service_app_appcore_suspended_state_changed, NULL);
+               break;
        default:
                break;
        }
@@ -243,6 +267,10 @@ static void _service_app_appcore_agent_unset_event_cb(app_event_type_e event_typ
        case APP_EVENT_REGION_FORMAT_CHANGED:
                appcore_agent_set_event_callback(APPCORE_AGENT_EVENT_REGION_CHANGE, NULL, NULL);
                break;
+       case APP_EVENT_SUSPENDED_STATE_CHANGED:
+               LOGD("[__SUSPEND__]");
+               appcore_agent_set_event_callback(APPCORE_AGENT_EVENT_SUSPENDED_STATE_CHANGE, NULL, NULL);
+               break;
        default:
                break;
        }
@@ -250,22 +278,28 @@ static void _service_app_appcore_agent_unset_event_cb(app_event_type_e event_typ
 
 static void _service_app_set_appcore_event_cb(void)
 {
-       app_event_type_e event;
+       _service_app_appcore_agent_set_event_cb(APP_EVENT_LOW_MEMORY);
+       _service_app_appcore_agent_set_event_cb(APP_EVENT_LANGUAGE_CHANGED);
+       _service_app_appcore_agent_set_event_cb(APP_EVENT_REGION_FORMAT_CHANGED);
 
-       for (event = APP_EVENT_LOW_MEMORY; event <= APP_EVENT_REGION_FORMAT_CHANGED; event++) {
-               if (eina_list_count(handler_list[event]) > 0)
-                       _service_app_appcore_agent_set_event_cb(event);
-       }
+       if (eina_list_count(handler_list[APP_EVENT_LOW_BATTERY]) > 0)
+               _service_app_appcore_agent_set_event_cb(APP_EVENT_LOW_BATTERY);
+
+       if (eina_list_count(handler_list[APP_EVENT_SUSPENDED_STATE_CHANGED]) > 0)
+               _service_app_appcore_agent_set_event_cb(APP_EVENT_SUSPENDED_STATE_CHANGED);
 }
 
 static void _service_app_unset_appcore_event_cb(void)
 {
-       app_event_type_e event;
+       _service_app_appcore_agent_unset_event_cb(APP_EVENT_LOW_MEMORY);
+       _service_app_appcore_agent_unset_event_cb(APP_EVENT_LANGUAGE_CHANGED);
+       _service_app_appcore_agent_unset_event_cb(APP_EVENT_REGION_FORMAT_CHANGED);
 
-       for (event = APP_EVENT_LOW_MEMORY; event <= APP_EVENT_REGION_FORMAT_CHANGED; event++) {
-               if (eina_list_count(handler_list[event]) > 0)
-                       _service_app_appcore_agent_unset_event_cb(event);
-       }
+       if (eina_list_count(handler_list[APP_EVENT_LOW_BATTERY]) > 0)
+               _service_app_appcore_agent_unset_event_cb(APP_EVENT_LOW_BATTERY);
+
+       if (eina_list_count(handler_list[APP_EVENT_SUSPENDED_STATE_CHANGED]) > 0)
+               _service_app_appcore_agent_unset_event_cb(APP_EVENT_SUSPENDED_STATE_CHANGED);
 }
 
 static int _service_app_create(void *data)
@@ -382,19 +416,19 @@ EXPORT_API int service_app_add_event_handler(app_event_handler_h *event_handler,
        }
 
        if (event_handler == NULL || callback == NULL)
-               return service_app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
+               return service_app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "null parameter");
 
-       if (event_type < APP_EVENT_LOW_MEMORY || event_type > APP_EVENT_REGION_FORMAT_CHANGED)
-               return service_app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
+       if (event_type < APP_EVENT_LOW_MEMORY || event_type > APP_EVENT_SUSPENDED_STATE_CHANGED)
+               return service_app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "invalid event type");
 
        EINA_LIST_FOREACH(handler_list[event_type], l_itr, handler) {
                if (handler->cb == callback)
-                       return service_app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
+                       return service_app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "already registered");
        }
 
        handler = calloc(1, sizeof(struct app_event_handler));
        if (!handler)
-               return service_app_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
+               return service_app_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__, "insufficient memory");
 
        handler->type = event_type;
        handler->cb = callback;