X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fappcore.c;h=20fb3c49aec5e160ad83f71a174ebb62abe92464;hb=47b9ae1d0ce4cd51bf37e58c4ba914c4ad011b30;hp=5d4604812f2669015b9ae5881daf3604ee456575;hpb=e5c06d1aa6bcb42993fcf05bd8fe7c1c30247bd4;p=platform%2Fcore%2Fappfw%2Fapp-core.git diff --git a/src/appcore.c b/src/appcore.c index 5d46048..20fb3c4 100644 --- a/src/appcore.c +++ b/src/appcore.c @@ -1,9 +1,5 @@ /* - * app-core - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. - * - * Contact: Jayoun Lee , Sewook Park , Jaeho Lee + * 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. - * */ @@ -35,15 +30,23 @@ #include #include #include +#include #include "appcore-internal.h" +#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT +#include + +#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/usr/apps" -#define PATH_RO_APP_ROOT "/usr/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, @@ -133,25 +139,23 @@ static struct evt_ops evtops[] = { }, }; -static int __get_dir_name(char *dirname) -{ - char pkg_name[PKGNAME_MAX]; - int r; - int pid; +#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT +static GDBusConnection *bus; +static guint __suspend_dbus_handler_initialized; +#endif - pid = getpid(); - if (pid < 0) - return -1; +static int __get_locale_resource_dir(char *locale_dir, int size) +{ + const char *res_path; - if (aul_app_get_pkgname_bypid(pid, pkg_name, PKGNAME_MAX) != AUL_R_OK) + res_path = aul_get_app_resource_path(); + if (res_path == NULL) { + _ERR("Failed to get resource path"); return -1; + } - r = snprintf(dirname, PATH_MAX, PATH_APP_ROOT "/%s" PATH_RES PATH_LOCALE,pkg_name); - if (r < 0) - return -1; - if (access(dirname, R_OK) == 0) return 0; - r = snprintf(dirname, PATH_MAX, PATH_RO_APP_ROOT "/%s" PATH_RES PATH_LOCALE,pkg_name); - if (r < 0) + snprintf(locale_dir, size, "%s" PATH_LOCALE, res_path); + if (access(locale_dir, R_OK) != 0) return -1; return 0; @@ -169,6 +173,18 @@ static int __app_terminate(void *data) return 0; } +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_BGAPP, ac->ops->data, NULL); + + return 0; +} + static gboolean __prt_ltime(gpointer data) { int msec; @@ -195,17 +211,32 @@ static int __app_reset(void *data, bundle * k) static int __app_resume(void *data) { -#ifdef WAYLAND 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_RESUME, ac->ops->data, NULL); + ac->ops->cb_app(AE_LOWER, ac->ops->data, NULL); + return 0; +} + +static int __app_update_requested(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_UPDATE_REQUESTED, ac->ops->data, NULL); -#else - x_raise_win(getpid()); -#endif return 0; } @@ -226,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; @@ -237,7 +268,7 @@ 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) @@ -266,7 +297,7 @@ static int __sys_lowmem(void *data, void *evt) val = vconf_keynode_get_int(key); if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) - return __sys_do(data, SE_LOWMEM); + return __sys_do(data, (void *)&val, SE_LOWMEM); return 0; } @@ -280,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; } @@ -293,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) @@ -304,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) @@ -346,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); @@ -410,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 */ @@ -427,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) { @@ -437,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]) @@ -459,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"); @@ -482,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); @@ -506,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; } @@ -519,8 +750,12 @@ 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(); } @@ -528,7 +763,6 @@ EXPORT_API void appcore_exit(void) EXPORT_API int appcore_flush_memory(void) { int (*flush_fn) (int); - int size = 0; struct appcore *ac = &core; @@ -539,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); /* @@ -558,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 +