4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Jayoun Lee <airjany@samsung.com>, Sewook Park <sewook7.park@samsung.com>, Jaeho Lee <jaeho81.lee@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
28 #include <sys/types.h>
32 #include <linux/limits.h>
38 #include <tzplatform_config.h>
39 #include <bundle_internal.h>
40 #include "appcore-internal.h"
42 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
43 #include <dbus/dbus.h>
44 #include <dbus/dbus-glib-lowlevel.h>
46 #define RESOURCED_FREEZER_PATH "/Org/Tizen/Resourced/Freezer"
47 #define RESOURCED_FREEZER_INTERFACE "org.tizen.resourced.freezer"
48 #define RESOURCED_FREEZER_SIGNAL "FreezerState"
51 #define SQLITE_FLUSH_MAX (1024*1024)
53 #define PKGNAME_MAX 256
54 #define PATH_APP_ROOT tzplatform_getenv(TZ_USER_APP)
55 #define PATH_RO_APP_ROOT tzplatform_getenv(TZ_SYS_RO_APP)
56 #define PATH_RES "/res"
57 #define PATH_LOCALE "/locale"
59 static struct appcore core;
62 static enum appcore_event to_ae[SE_MAX] = {
63 APPCORE_EVENT_UNKNOWN, /* SE_UNKNOWN */
64 APPCORE_EVENT_LOW_MEMORY, /* SE_LOWMEM */
65 APPCORE_EVENT_LOW_BATTERY, /* SE_LOWBAT */
66 APPCORE_EVENT_LANG_CHANGE, /* SE_LANGCGH */
67 APPCORE_EVENT_REGION_CHANGE,
68 APPCORE_EVENT_SUSPENDED_STATE_CHANGE,
71 static int appcore_event_initialized[SE_MAX] = {0,};
73 enum cb_type { /* callback */
83 enum appcore_event sys;
88 int (*cb_pre) (void *);
90 int (*cb_post) (void *);
92 int (*vcb_pre) (void *, void *);
93 int (*vcb) (void *, void *);
94 int (*vcb_post) (void *, void *);
98 int (*callback) (void *);
102 static struct open_s open;
104 static int __app_terminate(void *data);
105 static int __app_resume(void *data);
106 static int __app_reset(void *data, bundle *k);
108 static int __sys_lowmem_post(void *data, void *evt);
109 static int __sys_lowmem(void *data, void *evt);
110 static int __sys_lowbatt(void *data, void *evt);
111 static int __sys_langchg_pre(void *data, void *evt);
112 static int __sys_langchg(void *data, void *evt);
113 static int __sys_regionchg_pre(void *data, void *evt);
114 static int __sys_regionchg(void *data, void *evt);
115 extern void aul_finalize();
118 static struct evt_ops evtops[] = {
121 .key.vkey = VCONFKEY_SYSMAN_LOW_MEMORY,
122 .vcb_post = __sys_lowmem_post,
127 .key.vkey = VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
128 .vcb = __sys_lowbatt,
132 .key.vkey = VCONFKEY_LANGSET,
133 .vcb_pre = __sys_langchg_pre,
134 .vcb = __sys_langchg,
138 .key.vkey = VCONFKEY_REGIONFORMAT,
139 .vcb_pre = __sys_regionchg_pre,
140 .vcb = __sys_regionchg,
144 .key.vkey = VCONFKEY_REGIONFORMAT_TIME1224,
145 .vcb = __sys_regionchg,
149 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
150 static DBusConnection *bus = NULL;
151 static int __suspend_dbus_handler_initialized = 0;
154 static int __get_dir_name(char *dirname)
156 char pkg_name[PKGNAME_MAX];
164 if (aul_app_get_pkgname_bypid(pid, pkg_name, PKGNAME_MAX) != AUL_R_OK)
167 r = snprintf(dirname, PATH_MAX, "%s/%s" PATH_RES PATH_LOCALE,
168 PATH_APP_ROOT, pkg_name);
171 if (access(dirname, R_OK) == 0) return 0;
172 r = snprintf(dirname, PATH_MAX, "%s/%s" PATH_RES PATH_LOCALE,
173 PATH_RO_APP_ROOT, pkg_name);
180 static int __app_terminate(void *data)
182 struct appcore *ac = data;
184 _retv_if(ac == NULL || ac->ops == NULL, -1);
185 _retv_if(ac->ops->cb_app == NULL, 0);
187 ac->ops->cb_app(AE_TERMINATE, ac->ops->data, NULL);
192 static int __bgapp_terminate(void *data)
194 struct appcore *ac = data;
196 _retv_if(ac == NULL || ac->ops == NULL, -1);
197 _retv_if(ac->ops->cb_app == NULL, 0);
199 ac->ops->cb_app(AE_TERMINATE_BGAPP, ac->ops->data, NULL);
204 static gboolean __prt_ltime(gpointer data)
208 msec = appcore_measure_time_from(NULL);
210 _DBG("[APP %d] first idle after reset: %d msec", _pid, msec);
215 static int __app_reset(void *data, bundle * k)
217 struct appcore *ac = data;
218 _retv_if(ac == NULL || ac->ops == NULL, -1);
219 _retv_if(ac->ops->cb_app == NULL, 0);
221 g_idle_add(__prt_ltime, ac);
223 ac->ops->cb_app(AE_RESET, ac->ops->data, k);
228 static int __app_resume(void *data)
230 struct appcore *ac = data;
231 _retv_if(ac == NULL || ac->ops == NULL, -1);
232 _retv_if(ac->ops->cb_app == NULL, 0);
234 ac->ops->cb_app(AE_RAISE, ac->ops->data, NULL);
238 static int __app_pause(void *data)
240 struct appcore *ac = data;
241 _retv_if(ac == NULL || ac->ops == NULL, -1);
242 _retv_if(ac->ops->cb_app == NULL, 0);
244 ac->ops->cb_app(AE_LOWER, ac->ops->data, NULL);
248 static int __sys_do_default(struct appcore *ac, enum sys_event event)
254 /*r = __def_lowbatt(ac);*/
265 static int __sys_do(struct appcore *ac, void *event_info, enum sys_event event)
269 _retv_if(ac == NULL || event >= SE_MAX, -1);
271 op = &ac->sops[event];
273 if (op->func == NULL)
274 return __sys_do_default(ac, event);
276 return op->func(event_info, op->data);
279 static int __sys_lowmem_post(void *data, void *evt)
281 keynode_t *key = evt;
284 val = vconf_keynode_get_int(key);
286 if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) {
287 #if defined(MEMORY_FLUSH_ACTIVATE)
288 struct appcore *ac = data;
289 ac->ops->cb_app(AE_LOWMEM_POST, ac->ops->data, NULL);
297 static int __sys_lowmem(void *data, void *evt)
299 keynode_t *key = evt;
302 val = vconf_keynode_get_int(key);
304 if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)
305 return __sys_do(data, (void *)&val, SE_LOWMEM);
310 static int __sys_lowbatt(void *data, void *evt)
312 keynode_t *key = evt;
315 val = vconf_keynode_get_int(key);
317 /* VCONFKEY_SYSMAN_BAT_CRITICAL_LOW or VCONFKEY_SYSMAN_POWER_OFF */
318 if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
319 return __sys_do(data, (void *)&val, SE_LOWBAT);
324 static int __sys_langchg_pre(void *data, void *evt)
330 static int __sys_langchg(void *data, void *evt)
332 keynode_t *key = evt;
335 val = vconf_keynode_get_str(key);
337 return __sys_do(data, (void *)val, SE_LANGCHG);
340 static int __sys_regionchg_pre(void *data, void *evt)
346 static int __sys_regionchg(void *data, void *evt)
348 keynode_t *key = evt;
352 name = vconf_keynode_get_name(key);
353 if (!strcmp(name, VCONFKEY_REGIONFORMAT))
354 val = vconf_keynode_get_str(key);
356 return __sys_do(data, (void *)val, SE_REGIONCHG);
359 static void __vconf_do(struct evt_ops *eo, keynode_t * key, void *data)
364 eo->vcb_pre(data, key);
370 eo->vcb_post(data, key);
373 static void __vconf_cb(keynode_t *key, void *data)
378 name = vconf_keynode_get_name(key);
379 _ret_if(name == NULL);
381 _DBG("[APP %d] vconf changed: %s", _pid, name);
383 for (i = 0; i < sizeof(evtops) / sizeof(evtops[0]); i++) {
384 struct evt_ops *eo = &evtops[i];
388 if (!strcmp(name, eo->key.vkey))
389 __vconf_do(eo, key, data);
398 static int __add_vconf(struct appcore *ac, enum sys_event se)
404 r = vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __vconf_cb, ac);
407 r = vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __vconf_cb, ac);
410 r = vconf_notify_key_changed(VCONFKEY_LANGSET, __vconf_cb, ac);
413 r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, __vconf_cb, ac);
417 r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __vconf_cb, ac);
427 static int __del_vconf(enum sys_event se)
433 r = vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __vconf_cb);
436 r = vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __vconf_cb);
439 r = vconf_ignore_key_changed(VCONFKEY_LANGSET, __vconf_cb);
442 r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __vconf_cb);
446 r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __vconf_cb);
456 static int __del_vconf_list(void)
461 for (se = SE_LOWMEM; se < SE_MAX; se++) {
462 if (appcore_event_initialized[se]) {
465 _ERR("Delete vconf callback failed");
467 appcore_event_initialized[se] = 0;
474 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
475 static gboolean __flush_memory(gpointer data)
477 int suspend = APPCORE_SUSPENDED_STATE_WILL_ENTER_SUSPEND;
478 struct appcore *ac = (struct appcore *)data;
480 appcore_flush_memory();
487 if (!ac->allowed_bg && !ac->suspended_state) {
488 _DBG("[__SUSPEND__] flush case");
489 __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
490 ac->suspended_state = true;
496 static void __add_suspend_timer(struct appcore *ac)
498 ac->tid = g_timeout_add_seconds(5, __flush_memory, ac);
501 static void __remove_suspend_timer(struct appcore *ac)
504 g_source_remove(ac->tid);
510 static int __aul_handler(aul_type type, bundle *b, void *data)
513 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
514 const char *bg = NULL;
515 struct appcore *ac = data;
520 _DBG("[APP %d] AUL event: AUL_START", _pid);
521 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
522 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
523 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
524 _DBG("[__SUSPEND__] allowed background");
525 ac->allowed_bg = true;
526 __remove_suspend_timer(data);
530 __app_reset(data, b);
533 _DBG("[APP %d] AUL event: AUL_RESUME", _pid);
534 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
535 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
536 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
537 _DBG("[__SUSPEND__] allowed background");
538 ac->allowed_bg = true;
539 __remove_suspend_timer(data);
544 ret = open.callback(open.cbdata);
552 _DBG("[APP %d] AUL event: AUL_TERMINATE", _pid);
553 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
555 __remove_suspend_timer(data);
558 __app_terminate(data);
560 case AUL_TERMINATE_BGAPP:
561 _DBG("[APP %d] AUL event: AUL_TERMINATE_BGAPP", _pid);
562 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
564 __remove_suspend_timer(data);
567 __bgapp_terminate(data);
570 _DBG("[APP %d] AUL event: AUL_PAUSE", _pid);
573 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
575 _DBG("[APP %d] AUL event: AUL_WAKE", _pid);
576 if (!ac->allowed_bg && ac->suspended_state) {
577 int suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
578 __remove_suspend_timer(data);
579 __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
580 ac->suspended_state = false;
584 _DBG("[APP %d] AUL event: AUL_SUSPEND", _pid);
585 if (!ac->allowed_bg && !ac->suspended_state) {
586 __remove_suspend_timer(data);
587 __flush_memory((gpointer)ac);
592 _DBG("[APP %d] AUL event: %d", _pid, type);
601 static void __clear(struct appcore *ac)
603 memset(ac, 0, sizeof(struct appcore));
606 void appcore_get_app_core(struct appcore **ac)
611 EXPORT_API int appcore_set_open_cb(int (*cb) (void *),
620 EXPORT_API int appcore_set_event_callback(enum appcore_event event,
621 int (*cb) (void *, void *), void *data)
623 struct appcore *ac = &core;
628 for (se = SE_UNKNOWN; se < SE_MAX; se++) {
629 if (event == to_ae[se])
633 if (se == SE_UNKNOWN || se >= SE_MAX) {
634 _ERR("Unregistered event");
644 if (op->func && !appcore_event_initialized[se]) {
645 r = __add_vconf(ac, se);
647 _ERR("Add vconf callback failed");
649 appcore_event_initialized[se] = 1;
650 } else if (!op->func && appcore_event_initialized[se]) {
653 _ERR("Delete vconf callback failed");
655 appcore_event_initialized[se] = 0;
661 EXPORT_API int appcore_init(const char *name, const struct ui_ops *ops,
662 int argc, char **argv)
665 char dirname[PATH_MAX];
667 if (core.state != 0) {
668 _ERR("Already in use");
673 if (ops == NULL || ops->cb_app == NULL) {
674 _ERR("ops or callback function is null");
679 r = __get_dir_name(dirname);
680 r = set_i18n(name, dirname);
681 _retv_if(r == -1, -1);
683 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
684 r = _appcore_init_suspend_dbus_handler(&core);
686 _ERR("Initailzing suspended state handler failed");
691 r = aul_launch_init(__aul_handler, &core);
693 _ERR("Aul init failed: %d", r);
697 r = aul_launch_argv_handler(argc, argv);
699 _ERR("Aul argv handler failed: %d", r);
704 core.state = 1; /* TODO: use enum value */
706 core.suspended_state = false;
707 core.allowed_bg = false;
718 EXPORT_API void appcore_exit(void)
723 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
724 __remove_suspend_timer(&core);
730 EXPORT_API int appcore_flush_memory(void)
732 int (*flush_fn) (int);
734 struct appcore *ac = &core;
737 _ERR("Appcore not initialized");
741 _DBG("[APP %d] Flushing memory ...", _pid);
744 ac->ops->cb_app(AE_MEM_FLUSH, ac->ops->data, NULL);
746 flush_fn = dlsym(RTLD_DEFAULT, "sqlite3_release_memory");
748 flush_fn(SQLITE_FLUSH_MAX);
752 *Disabled - the impact of stack_trim() is unclear
756 _DBG("[APP %d] Flushing memory DONE", _pid);
761 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
762 static DBusHandlerResult __suspend_dbus_signal_filter(DBusConnection *conn,
763 DBusMessage *message, void *user_data)
766 const char *interface;
772 dbus_error_init(&error);
774 sender = dbus_message_get_sender(message);
776 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
778 interface = dbus_message_get_interface(message);
779 if (interface == NULL) {
780 _ERR("reject by security issue - no interface\n");
781 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
784 if (dbus_message_is_signal(message, interface, RESOURCED_FREEZER_SIGNAL)) {
785 if (dbus_message_get_args(message, &error, DBUS_TYPE_INT32, &state,
786 DBUS_TYPE_INT32, &pid, DBUS_TYPE_INVALID) == FALSE) {
787 _ERR("Failed to get data: %s", error.message);
788 dbus_error_free(&error);
789 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
792 if (pid == getpid() && state == 0) { /* thawed */
793 suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
794 SECURE_LOGD("[__SUSPEND__] state: %d (0: thawed, 1: frozen), pid: %d", state, pid);
796 struct appcore *ac = (struct appcore *)user_data;
797 if (!ac->allowed_bg && ac->suspended_state) {
798 __remove_suspend_timer(ac);
799 __sys_do(user_data, &suspend, SE_SUSPENDED_STATE);
800 ac->suspended_state = false;
801 __add_suspend_timer(ac);
806 return DBUS_HANDLER_RESULT_HANDLED;
809 int _appcore_init_suspend_dbus_handler(void *data)
812 char rule[MAX_LOCAL_BUFSZ];
814 if (__suspend_dbus_handler_initialized)
817 dbus_error_init(&error);
819 bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
821 _ERR("Failed to connect to the D-BUS daemon: %s", error.message);
822 dbus_error_free(&error);
826 dbus_connection_setup_with_g_main(bus, NULL);
828 snprintf(rule, MAX_LOCAL_BUFSZ,
829 "path='%s',type='signal',interface='%s'", RESOURCED_FREEZER_PATH, RESOURCED_FREEZER_INTERFACE);
830 /* listening to messages */
831 dbus_bus_add_match(bus, rule, &error);
832 if (dbus_error_is_set(&error)) {
833 _ERR("Fail to rule set: %s", error.message);
834 dbus_error_free(&error);
838 if (dbus_connection_add_filter(bus, __suspend_dbus_signal_filter, data, NULL) == FALSE) {
839 _ERR("add filter fail");
843 __suspend_dbus_handler_initialized = 1;
844 _DBG("[__SUSPEND__] suspend signal initialized");