#include <malloc.h>
#include <glib.h>
#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
#include <stdbool.h>
#include <aul.h>
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 */
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;
}
_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);
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(); */
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);
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);
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;
}
#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
},
};
+#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];
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);
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 */
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)
{
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");
core.ops = ops;
core.state = 1; /* TODO: use enum value */
+ core.tid = 0;
+ core.suspended_state = false;
+ core.allowed_bg = false;
_pid = getpid();
if (core.state) {
__del_vconf();
__clear(&core);
+#ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
+ __remove_suspend_timer(&core);
+#endif
}
aul_finalize();
}
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