diff options
-rw-r--r-- | CMakeLists.txt | 23 | ||||
-rw-r--r-- | include/appcore-common.h | 17 | ||||
-rw-r--r-- | include/appcore-internal.h | 9 | ||||
-rw-r--r-- | packaging/app-core.spec | 30 | ||||
-rw-r--r-- | src/appcore-efl.c | 84 | ||||
-rw-r--r-- | src/appcore.c | 210 |
6 files changed, 350 insertions, 23 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index d1086b5..c47c4e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,18 +25,23 @@ SET(CMAKE_SKIP_BUILD_RPATH TRUE) SET(APPCORE_COMMON "appcore-common") SET(SRCS_common src/appcore.c src/appcore-i18n.c src/appcore-measure.c src/appcore-rotation.c) -IF (with_wayland) +IF(_WITH_WAYLAND) ADD_DEFINITIONS("-DWAYLAND") -ENDIF (with_wayland) -IF (with_x11) +ENDIF(_WITH_WAYLAND) + +IF(_WITH_X11) ADD_DEFINITIONS("-DX11") SET(SRCS_common ${SRCS_common} src/appcore-X.c) -ENDIF (with_x11) +ENDIF(_WITH_X11) + +IF(_APPFW_FEATURE_BACKGROUND_MANAGEMENT) + ADD_DEFINITIONS("-D_APPFW_FEATURE_BACKGROUND_MANAGEMENT") +ENDIF(_APPFW_FEATURE_BACKGROUND_MANAGEMENT) SET(HEADERS_common appcore-common.h) INCLUDE(FindPkgConfig) -SET(APPCORE_PKG_CHECK_MODULES "dbus-1 vconf sensor aul dlog libtzplatform-config ecore") +SET(APPCORE_PKG_CHECK_MODULES "dbus-glib-1 vconf sensor aul dlog libtzplatform-config ecore") IF (with_x11) SET(APPCORE_PKG_CHECK_MODULES "${APPCORE_PKG_CHECK_MODULES} x11 eina ecore-x") ENDIF (with_x11) @@ -57,12 +62,12 @@ SET_TARGET_PROPERTIES(${APPCORE_COMMON} PROPERTIES VERSION ${VERSION}) SET_TARGET_PROPERTIES(${APPCORE_COMMON} PROPERTIES COMPILE_FLAGS ${EXTRA_CFLAGS_common}) TARGET_LINK_LIBRARIES(${APPCORE_COMMON} ${pkg_common_LDFLAGS} "-ldl") -IF (with_wayland) +IF(_WITH_WAYLAND) CONFIGURE_FILE(${APPCORE_COMMON}-wayland.pc.in ${APPCORE_COMMON}.pc @ONLY) -ENDIF (with_wayland) -IF (with_x11) +ENDIF(_WITH_WAYLAND) +IF(_WITH_X11) CONFIGURE_FILE(${APPCORE_COMMON}-x.pc.in ${APPCORE_COMMON}.pc @ONLY) -ENDIF (with_x11) +ENDIF(_WITH_X11) INSTALL(TARGETS ${APPCORE_COMMON} DESTINATION ${LIB_INSTALL_DIR} COMPONENT RuntimeLibraries) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${APPCORE_COMMON}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) diff --git a/include/appcore-common.h b/include/appcore-common.h index a79c4f3..e3d8304 100644 --- a/include/appcore-common.h +++ b/include/appcore-common.h @@ -65,15 +65,17 @@ extern "C" { */ enum appcore_event { APPCORE_EVENT_UNKNOWN, - /**< Unknown event */ + /**< Unknown event */ APPCORE_EVENT_LOW_MEMORY, - /**< Low memory */ + /**< Low memory */ APPCORE_EVENT_LOW_BATTERY, - /**< Low battery */ + /**< Low battery */ APPCORE_EVENT_LANG_CHANGE, - /**< Language setting is changed */ + /**< Language setting is changed */ APPCORE_EVENT_REGION_CHANGE, - /**< Region setting is changed */ + /**< Region setting is changed */ + APPCORE_EVENT_SUSPENDED_STATE_CHANGE, + /**< The suspended state is changed */ }; /** @@ -103,6 +105,11 @@ enum appcore_time_format { APPCORE_TIME_FORMAT_24, }; +enum appcore_suspended_state { + APPCORE_SUSPENDED_STATE_WILL_ENTER_SUSPEND = 0, + APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND +}; + /** * Appcore operations which are called during the application life-cycle * @see appcore_efl_main() diff --git a/include/appcore-internal.h b/include/appcore-internal.h index 2a6ab07..0e3c0d8 100644 --- a/include/appcore-internal.h +++ b/include/appcore-internal.h @@ -27,6 +27,7 @@ #define LOG_TAG "APP_CORE" #include <stdio.h> +#include <stdbool.h> #include <dlog.h> #include "appcore-common.h" @@ -128,6 +129,7 @@ enum sys_event { SE_LOWBAT, SE_LANGCHG, SE_REGIONCHG, + SE_SUSPENDED_STATE, SE_MAX }; @@ -144,6 +146,9 @@ struct sys_op { */ struct appcore { int state; + unsigned int tid; + bool suspended_state; + bool allowed_bg; const struct ui_ops *ops; struct sys_op sops[SE_MAX]; @@ -185,6 +190,10 @@ int appcore_set_wm_rotation(struct ui_wm_rotate* wm_rotate); void appcore_group_attach(); void appcore_group_lower(); unsigned int appcore_get_main_window(void); +void appcore_get_app_core(struct appcore **ac); +#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT +int _appcore_init_suspend_dbus_handler(void *data); +#endif #define ENV_START "APP_START_TIME" diff --git a/packaging/app-core.spec b/packaging/app-core.spec index 841c078..9441160 100644 --- a/packaging/app-core.spec +++ b/packaging/app-core.spec @@ -18,7 +18,7 @@ BuildRequires: pkgconfig(ecore-wayland) %endif %endif Source1001: app-core.manifest -BuildRequires: pkgconfig(dbus-1) +BuildRequires: pkgconfig(dbus-glib-1) BuildRequires: pkgconfig(sensor) BuildRequires: pkgconfig(vconf) BuildRequires: pkgconfig(aul) @@ -89,22 +89,38 @@ Group: Development/Libraries %description template Application basics template +%if "%{?tizen_profile_name}" == "wearable" +%define appfw_feature_background_management 1 +%else +%if "%{?tizen_profile_name}" == "mobile" +%define appfw_feature_background_management 1 +%else +%if "%{?tizen_profile_name}" == "tv" +%define appfw_feature_background_management 0 +%endif +%endif +%endif %prep %setup -q cp %{SOURCE1001} . - %build - -%cmake . \ %if %{with wayland} --Dwith_wayland=TRUE\ +_WITH_WAYLAND=ON %endif %if %{with x} --Dwith_x11=TRUE\ +_WITH_X11=ON +%endif +%if 0%{?appfw_feature_background_management} +_APPFW_FEATURE_BACKGROUND_MANAGEMENT=ON %endif --DENABLE_GTK=OFF + +%cmake . \ + -D_WITH_WAYLAND:BOOL=${_WITH_WAYLAND} \ + -D_WITH_X11:BOOL=${_WITH_X11} \ + -D_APPFW_FEATURE_BACKGROUND_MANAGEMENT:BOOL=${_APPFW_FEATURE_BACKGROUND_MANAGEMENT} \ + -DENABLE_GTK=OFF make %{?_smp_mflags} diff --git a/src/appcore-efl.c b/src/appcore-efl.c index f7e7dda..a43bc4e 100644 --- a/src/appcore-efl.c +++ b/src/appcore-efl.c @@ -45,6 +45,7 @@ #include <malloc.h> #include <glib.h> #include <dbus/dbus.h> +#include <dbus/dbus-glib-lowlevel.h> #include <stdbool.h> #include <aul.h> @@ -78,6 +79,11 @@ struct ui_priv { Ecore_Timer *mftimer; /* Ecore Timer for memory flushing */ +#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT + struct appcore *app_core; + void (*prepare_to_suspend) (void *data); + void (*exit_from_suspend) (void *data); +#endif struct appcore_ops *ops; void (*mfcb) (void); /* Memory Flushing Callback */ @@ -166,13 +172,55 @@ static void _send_to_resourced(enum proc_status_type type) static GSList *g_winnode_list; +#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT +static void __appcore_efl_prepare_to_suspend(void *data) +{ + struct ui_priv *ui = (struct ui_priv *)data; + struct sys_op *op = NULL; + int suspend = APPCORE_SUSPENDED_STATE_WILL_ENTER_SUSPEND; + + if (ui->app_core && !ui->app_core->allowed_bg && !ui->app_core->suspended_state) { + op = &ui->app_core->sops[SE_SUSPENDED_STATE]; + if (op && op->func) + op->func((void *)&suspend, op->data); /* calls c-api handler */ + + ui->app_core->suspended_state = true; + } + _DBG("[__SUSPEND__]"); +} + +static void __appcore_efl_exit_from_suspend(void *data) +{ + struct ui_priv *ui = (struct ui_priv *)data; + struct sys_op *op = NULL; + int suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND; + + if (ui->app_core && !ui->app_core->allowed_bg && ui->app_core->suspended_state) { + op = &ui->app_core->sops[SE_SUSPENDED_STATE]; + if (op && op->func) + op->func((void *)&suspend, op->data); /* calls c-api handler */ + + ui->app_core->suspended_state = false; + } + _DBG("[__SUSPEND__]"); +} +#endif + #if defined(MEMORY_FLUSH_ACTIVATE) static Eina_Bool __appcore_memory_flush_cb(void *data) { struct ui_priv *ui = (struct ui_priv *)data; appcore_flush_memory(); - ui->mftimer = NULL; + if (ui) + ui->mftimer = NULL; + +#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT + if (ui && ui->prepare_to_suspend) { + _DBG("[__SUSPEND__] flush case"); + ui->prepare_to_suspend(ui); + } +#endif return ECORE_CALLBACK_CANCEL; } @@ -309,6 +357,14 @@ static void __do_app(enum app_event event, void *data, bundle * b) _DBG("[APP %d] RESET", _pid); ui->pending_data = bundle_dup(b); LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:start]", ui->name); + +#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT + if (ui->exit_from_suspend) { + _DBG("[__SUSPEND__] reset case"); + ui->exit_from_suspend(ui); + } +#endif + if (ui->ops->reset) r = ui->ops->reset(b, ui->ops->data); LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:done]", ui->name); @@ -334,6 +390,13 @@ static void __do_app(enum app_event event, void *data, bundle * b) ui->state = AS_PAUSED; if (r >= 0 && resource_reclaiming == TRUE) __appcore_timer_add(ui); +#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT + else if (r >= 0 && resource_reclaiming == FALSE + && ui->prepare_to_suspend) { + _DBG("[__SUSPEND__] pause case"); + ui->prepare_to_suspend(ui); + } +#endif } /* TODO : rotation stop */ /* r = appcore_pause_rotation_cb(); */ @@ -343,6 +406,13 @@ static void __do_app(enum app_event event, void *data, bundle * b) case AE_RESUME: LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:start]", ui->name); +#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT + if (ui->exit_from_suspend) { + _DBG("[__SUSPEND__] resume case"); + ui->exit_from_suspend(ui); + } +#endif + if (ui->state == AS_PAUSED || ui->state == AS_CREATED) { _DBG("[APP %d] RESUME", _pid); @@ -837,6 +907,12 @@ static int __before_loop(struct ui_priv *ui, int *argc, char ***argv) r = appcore_init(ui->name, &efl_ops, *argc, *argv); _retv_if(r == -1, -1); +#if _APPFW_FEATURE_BACKGROUND_MANAGEMENT + appcore_get_app_core(&ac); + ui->app_core = ac; + SECURE_LOGD("[__SUSPEND__] appcore initialized, appcore addr: 0x%x", ac); +#endif + LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:appcore_init:done]", ui->name); if (ui->ops && ui->ops->create) { r = ui->ops->create(ui->ops->data); @@ -925,6 +1001,12 @@ static int __set_data(struct ui_priv *ui, const char *name, ui->rot_cb_data = NULL; ui->rot_mode = APPCORE_RM_UNKNOWN; +#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT + ui->app_core = NULL; + ui->prepare_to_suspend = __appcore_efl_prepare_to_suspend; + ui->exit_from_suspend = __appcore_efl_exit_from_suspend; +#endif + return 0; } diff --git a/src/appcore.c b/src/appcore.c index 711629b..afbef7d 100644 --- a/src/appcore.c +++ b/src/appcore.c @@ -38,6 +38,15 @@ #include <tzplatform_config.h> #include "appcore-internal.h" +#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT +#include <dbus/dbus.h> +#include <dbus/dbus-glib-lowlevel.h> + +#define RESOURCED_FREEZER_PATH "/Org/Tizen/Resourced/Freezer" +#define RESOURCED_FREEZER_INTERFACE "org.tizen.resourced.freezer" +#define RESOURCED_FREEZER_SIGNAL "FreezerState" +#endif + #define SQLITE_FLUSH_MAX (1024*1024) #define PKGNAME_MAX 256 @@ -134,6 +143,11 @@ static struct evt_ops evtops[] = { }, }; +#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT +static DBusConnection *bus = NULL; +static int __suspend_dbus_handler_initialized = 0; +#endif + static int __get_dir_name(char *dirname) { char pkg_name[PKGNAME_MAX]; @@ -421,18 +435,76 @@ static int __del_vconf(void) 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; +#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT + const char *bg = NULL; + struct appcore *ac = data; +#endif switch (type) { case AUL_START: _DBG("[APP %d] AUL event: AUL_START", _pid); +#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT + bg = bundle_get_val(b, AUL_K_ALLOWED_BG); + if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWGED_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); @@ -442,16 +514,44 @@ 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) { + int suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND; + __remove_suspend_timer(data); + __sys_do(ac, &suspend, SE_SUSPENDED_STATE); + ac->suspended_state = false; + } + break; + case AUL_SUSPEND: + _DBG("[APP %d] AUL event: AUL_SUSPEND", _pid); + if (!ac->allowed_bg && !ac->suspended_state) { + __remove_suspend_timer(data); + __flush_memory((gpointer)ac); + } + break; +#endif default: _DBG("[APP %d] AUL event: %d", _pid, type); /* do nothing */ @@ -467,6 +567,11 @@ static void __clear(struct appcore *ac) memset(ac, 0, sizeof(struct appcore)); } +void appcore_get_app_core(struct appcore **ac) +{ + *ac = &core; +} + EXPORT_API int appcore_set_open_cb(int (*cb) (void *), void *data) { @@ -526,6 +631,14 @@ EXPORT_API int appcore_init(const char *name, const struct ui_ops *ops, r = set_i18n(name, dirname); _retv_if(r == -1, -1); +#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT + r = _appcore_init_suspend_dbus_handler(&core); + if (r == -1) { + _ERR("Initailzing suspended state handler failed"); + goto err; + } +#endif + r = __add_vconf(&core); if (r == -1) { _ERR("Add vconf callback failed"); @@ -546,6 +659,9 @@ 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(); @@ -561,6 +677,9 @@ EXPORT_API void appcore_exit(void) if (core.state) { __del_vconf(); __clear(&core); +#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT + __remove_suspend_timer(&core); +#endif } aul_finalize(); } @@ -598,3 +717,92 @@ EXPORT_API int appcore_flush_memory(void) return 0; } + +#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT +static DBusHandlerResult __suspend_dbus_signal_filter(DBusConnection *conn, + DBusMessage *message, void *user_data) +{ + const char *sender; + const char *interface; + int pid; + int state; + int suspend; + + DBusError error; + dbus_error_init(&error); + + sender = dbus_message_get_sender(message); + if (sender == NULL) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + interface = dbus_message_get_interface(message); + if (interface == NULL) { + _ERR("reject by security issue - no interface\n"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + if (dbus_message_is_signal(message, interface, RESOURCED_FREEZER_SIGNAL)) { + if (dbus_message_get_args(message, &error, DBUS_TYPE_INT32, &state, + DBUS_TYPE_INT32, &pid, DBUS_TYPE_INVALID) == FALSE) { + _ERR("Failed to get data: %s", error.message); + dbus_error_free(&error); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + if (pid == getpid() && state == 0) { //thawed + suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND; + SECURE_LOGD("[__SUSPEND__] state: %d (0: thawed, 1: frozen), pid: %d", state, pid); + + struct appcore *ac = (struct appcore *)user_data; + if (!ac->allowed_bg && ac->suspended_state) { + __remove_suspend_timer(ac); + __sys_do(user_data, &suspend, SE_SUSPENDED_STATE); + ac->suspended_state = false; + __add_suspend_timer(ac); + } + } + } + + return DBUS_HANDLER_RESULT_HANDLED; +} + +int _appcore_init_suspend_dbus_handler(void *data) +{ + DBusError error; + char rule[MAX_LOCAL_BUFSZ]; + + if (__suspend_dbus_handler_initialized) + return 0; + + dbus_error_init(&error); + if (!bus) { + bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); + if (!bus) { + _ERR("Failed to connect to the D-BUS daemon: %s", error.message); + dbus_error_free(&error); + return -1; + } + } + dbus_connection_setup_with_g_main(bus, NULL); + + snprintf(rule, MAX_LOCAL_BUFSZ, + "path='%s',type='signal',interface='%s'", RESOURCED_FREEZER_PATH, RESOURCED_FREEZER_INTERFACE); + /* listening to messages */ + dbus_bus_add_match(bus, rule, &error); + if (dbus_error_is_set(&error)) { + _ERR("Fail to rule set: %s", error.message); + dbus_error_free(&error); + return -1; + } + + if (dbus_connection_add_filter(bus, __suspend_dbus_signal_filter, data, NULL) == FALSE) { + _ERR("add filter fail"); + return -1; + } + + __suspend_dbus_handler_initialized = 1; + _DBG("[__SUSPEND__] suspend signal initialized"); + + return 0; +} +#endif |