2 * Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
23 #include <sys/types.h>
27 #include <linux/limits.h>
33 #include <tzplatform_config.h>
34 #include <bundle_internal.h>
35 #include "appcore-internal.h"
37 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
40 #define RESOURCED_FREEZER_PATH "/Org/Tizen/Resourced/Freezer"
41 #define RESOURCED_FREEZER_INTERFACE "org.tizen.resourced.freezer"
42 #define RESOURCED_FREEZER_SIGNAL "FreezerState"
45 #define SQLITE_FLUSH_MAX (1024*1024)
47 #define PKGNAME_MAX 256
48 #define PATH_APP_ROOT tzplatform_getenv(TZ_USER_APP)
49 #define PATH_SYS_RO_APP_ROOT tzplatform_getenv(TZ_SYS_RO_APP)
50 #define PATH_SYS_RW_APP_ROOT tzplatform_getenv(TZ_SYS_RW_APP)
51 #define PATH_RES "/res"
52 #define PATH_LOCALE "/locale"
54 static struct appcore core;
57 static enum appcore_event to_ae[SE_MAX] = {
58 APPCORE_EVENT_UNKNOWN, /* SE_UNKNOWN */
59 APPCORE_EVENT_LOW_MEMORY, /* SE_LOWMEM */
60 APPCORE_EVENT_LOW_BATTERY, /* SE_LOWBAT */
61 APPCORE_EVENT_LANG_CHANGE, /* SE_LANGCGH */
62 APPCORE_EVENT_REGION_CHANGE,
63 APPCORE_EVENT_SUSPENDED_STATE_CHANGE,
66 static int appcore_event_initialized[SE_MAX] = {0,};
68 enum cb_type { /* callback */
78 enum appcore_event sys;
83 int (*cb_pre) (void *);
85 int (*cb_post) (void *);
87 int (*vcb_pre) (void *, void *);
88 int (*vcb) (void *, void *);
89 int (*vcb_post) (void *, void *);
93 int (*callback) (void *);
97 static struct open_s open;
99 static int __app_terminate(void *data);
100 static int __app_resume(void *data);
101 static int __app_reset(void *data, bundle *k);
103 static int __sys_lowmem_post(void *data, void *evt);
104 static int __sys_lowmem(void *data, void *evt);
105 static int __sys_lowbatt(void *data, void *evt);
106 static int __sys_langchg_pre(void *data, void *evt);
107 static int __sys_langchg(void *data, void *evt);
108 static int __sys_regionchg_pre(void *data, void *evt);
109 static int __sys_regionchg(void *data, void *evt);
110 extern void aul_finalize();
113 static struct evt_ops evtops[] = {
116 .key.vkey = VCONFKEY_SYSMAN_LOW_MEMORY,
117 .vcb_post = __sys_lowmem_post,
122 .key.vkey = VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
123 .vcb = __sys_lowbatt,
127 .key.vkey = VCONFKEY_LANGSET,
128 .vcb_pre = __sys_langchg_pre,
129 .vcb = __sys_langchg,
133 .key.vkey = VCONFKEY_REGIONFORMAT,
134 .vcb_pre = __sys_regionchg_pre,
135 .vcb = __sys_regionchg,
139 .key.vkey = VCONFKEY_REGIONFORMAT_TIME1224,
140 .vcb = __sys_regionchg,
144 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
145 static GDBusConnection *bus = NULL;
146 static guint __suspend_dbus_handler_initialized = 0;
149 static int __get_dir_name(char *dirname)
151 char pkg_name[PKGNAME_MAX];
159 if (aul_app_get_pkgname_bypid(pid, pkg_name, PKGNAME_MAX) != AUL_R_OK)
162 r = snprintf(dirname, PATH_MAX, "%s/%s" PATH_RES PATH_LOCALE,
163 PATH_APP_ROOT, pkg_name);
166 if (access(dirname, R_OK) == 0)
168 r = snprintf(dirname, PATH_MAX, "%s/%s" PATH_RES PATH_LOCALE,
169 PATH_SYS_RO_APP_ROOT, pkg_name);
172 if (access(dirname, R_OK) == 0)
174 r = snprintf(dirname, PATH_MAX, "%s/%s" PATH_RES PATH_LOCALE,
175 PATH_SYS_RW_APP_ROOT, pkg_name);
182 static int __app_terminate(void *data)
184 struct appcore *ac = data;
186 _retv_if(ac == NULL || ac->ops == NULL, -1);
187 _retv_if(ac->ops->cb_app == NULL, 0);
189 ac->ops->cb_app(AE_TERMINATE, ac->ops->data, NULL);
194 static int __bgapp_terminate(void *data)
196 struct appcore *ac = data;
198 _retv_if(ac == NULL || ac->ops == NULL, -1);
199 _retv_if(ac->ops->cb_app == NULL, 0);
201 ac->ops->cb_app(AE_TERMINATE_BGAPP, ac->ops->data, NULL);
206 static gboolean __prt_ltime(gpointer data)
210 msec = appcore_measure_time_from(NULL);
212 _DBG("[APP %d] first idle after reset: %d msec", _pid, msec);
217 static int __app_reset(void *data, bundle * k)
219 struct appcore *ac = data;
220 _retv_if(ac == NULL || ac->ops == NULL, -1);
221 _retv_if(ac->ops->cb_app == NULL, 0);
223 g_idle_add(__prt_ltime, ac);
225 ac->ops->cb_app(AE_RESET, ac->ops->data, k);
230 static int __app_resume(void *data)
232 struct appcore *ac = data;
233 _retv_if(ac == NULL || ac->ops == NULL, -1);
234 _retv_if(ac->ops->cb_app == NULL, 0);
236 ac->ops->cb_app(AE_RAISE, ac->ops->data, NULL);
240 static int __app_pause(void *data)
242 struct appcore *ac = data;
243 _retv_if(ac == NULL || ac->ops == NULL, -1);
244 _retv_if(ac->ops->cb_app == NULL, 0);
246 ac->ops->cb_app(AE_LOWER, ac->ops->data, NULL);
250 static int __sys_do_default(struct appcore *ac, enum sys_event event)
256 /*r = __def_lowbatt(ac);*/
267 static int __sys_do(struct appcore *ac, void *event_info, enum sys_event event)
271 _retv_if(ac == NULL || event >= SE_MAX, -1);
273 op = &ac->sops[event];
275 if (op->func == NULL)
276 return __sys_do_default(ac, event);
278 return op->func(event_info, op->data);
281 static int __sys_lowmem_post(void *data, void *evt)
283 keynode_t *key = evt;
286 val = vconf_keynode_get_int(key);
288 if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) {
289 #if defined(MEMORY_FLUSH_ACTIVATE)
290 struct appcore *ac = data;
291 ac->ops->cb_app(AE_LOWMEM_POST, ac->ops->data, NULL);
299 static int __sys_lowmem(void *data, void *evt)
301 keynode_t *key = evt;
304 val = vconf_keynode_get_int(key);
306 if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)
307 return __sys_do(data, (void *)&val, SE_LOWMEM);
312 static int __sys_lowbatt(void *data, void *evt)
314 keynode_t *key = evt;
317 val = vconf_keynode_get_int(key);
319 /* VCONFKEY_SYSMAN_BAT_CRITICAL_LOW or VCONFKEY_SYSMAN_POWER_OFF */
320 if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
321 return __sys_do(data, (void *)&val, SE_LOWBAT);
326 static int __sys_langchg_pre(void *data, void *evt)
332 static int __sys_langchg(void *data, void *evt)
334 keynode_t *key = evt;
337 val = vconf_keynode_get_str(key);
339 return __sys_do(data, (void *)val, SE_LANGCHG);
342 static int __sys_regionchg_pre(void *data, void *evt)
348 static int __sys_regionchg(void *data, void *evt)
350 keynode_t *key = evt;
354 name = vconf_keynode_get_name(key);
355 if (!strcmp(name, VCONFKEY_REGIONFORMAT))
356 val = vconf_keynode_get_str(key);
358 return __sys_do(data, (void *)val, SE_REGIONCHG);
361 static void __vconf_do(struct evt_ops *eo, keynode_t * key, void *data)
366 eo->vcb_pre(data, key);
372 eo->vcb_post(data, key);
375 static void __vconf_cb(keynode_t *key, void *data)
380 name = vconf_keynode_get_name(key);
381 _ret_if(name == NULL);
383 _DBG("[APP %d] vconf changed: %s", _pid, name);
385 for (i = 0; i < sizeof(evtops) / sizeof(evtops[0]); i++) {
386 struct evt_ops *eo = &evtops[i];
390 if (!strcmp(name, eo->key.vkey))
391 __vconf_do(eo, key, data);
400 static int __add_vconf(struct appcore *ac, enum sys_event se)
406 r = vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __vconf_cb, ac);
409 r = vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __vconf_cb, ac);
412 r = vconf_notify_key_changed(VCONFKEY_LANGSET, __vconf_cb, ac);
415 r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, __vconf_cb, ac);
419 r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __vconf_cb, ac);
429 static int __del_vconf(enum sys_event se)
435 r = vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __vconf_cb);
438 r = vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __vconf_cb);
441 r = vconf_ignore_key_changed(VCONFKEY_LANGSET, __vconf_cb);
444 r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __vconf_cb);
448 r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __vconf_cb);
458 static int __del_vconf_list(void)
463 for (se = SE_LOWMEM; se < SE_MAX; se++) {
464 if (appcore_event_initialized[se]) {
467 _ERR("Delete vconf callback failed");
469 appcore_event_initialized[se] = 0;
476 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
477 static gboolean __flush_memory(gpointer data)
479 int suspend = APPCORE_SUSPENDED_STATE_WILL_ENTER_SUSPEND;
480 struct appcore *ac = (struct appcore *)data;
482 appcore_flush_memory();
489 if (!ac->allowed_bg && !ac->suspended_state) {
490 _DBG("[__SUSPEND__] flush case");
491 __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
492 ac->suspended_state = true;
498 static void __add_suspend_timer(struct appcore *ac)
500 ac->tid = g_timeout_add_seconds(5, __flush_memory, ac);
503 static void __remove_suspend_timer(struct appcore *ac)
506 g_source_remove(ac->tid);
512 static int __aul_handler(aul_type type, bundle *b, void *data)
515 const char *tep_path = NULL;
516 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
517 const char *bg = NULL;
518 struct appcore *ac = data;
523 _DBG("[APP %d] AUL event: AUL_START", _pid);
524 tep_path = bundle_get_val(b, AUL_TEP_PATH);
526 ret = aul_check_tep_mount(tep_path);
528 _ERR("mount request not completed within 1 sec");
533 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
534 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
535 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
536 _DBG("[__SUSPEND__] allowed background");
537 ac->allowed_bg = true;
538 __remove_suspend_timer(data);
542 __app_reset(data, b);
545 _DBG("[APP %d] AUL event: AUL_RESUME", _pid);
546 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
547 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
548 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
549 _DBG("[__SUSPEND__] allowed background");
550 ac->allowed_bg = true;
551 __remove_suspend_timer(data);
556 ret = open.callback(open.cbdata);
564 _DBG("[APP %d] AUL event: AUL_TERMINATE", _pid);
565 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
567 __remove_suspend_timer(data);
570 __app_terminate(data);
572 case AUL_TERMINATE_BGAPP:
573 _DBG("[APP %d] AUL event: AUL_TERMINATE_BGAPP", _pid);
574 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
576 __remove_suspend_timer(data);
579 __bgapp_terminate(data);
582 _DBG("[APP %d] AUL event: AUL_PAUSE", _pid);
585 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
587 _DBG("[APP %d] AUL event: AUL_WAKE", _pid);
588 if (!ac->allowed_bg && ac->suspended_state) {
589 int suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
590 __remove_suspend_timer(data);
591 __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
592 ac->suspended_state = false;
596 _DBG("[APP %d] AUL event: AUL_SUSPEND", _pid);
597 if (!ac->allowed_bg && !ac->suspended_state) {
598 __remove_suspend_timer(data);
599 __flush_memory((gpointer)ac);
604 _DBG("[APP %d] AUL event: %d", _pid, type);
613 static void __clear(struct appcore *ac)
615 memset(ac, 0, sizeof(struct appcore));
618 EXPORT_API void appcore_get_app_core(struct appcore **ac)
623 EXPORT_API int appcore_set_open_cb(int (*cb) (void *),
632 EXPORT_API int appcore_set_event_callback(enum appcore_event event,
633 int (*cb) (void *, void *), void *data)
635 struct appcore *ac = &core;
640 for (se = SE_UNKNOWN; se < SE_MAX; se++) {
641 if (event == to_ae[se])
645 if (se == SE_UNKNOWN || se >= SE_MAX) {
646 _ERR("Unregistered event");
656 if (op->func && !appcore_event_initialized[se]) {
657 r = __add_vconf(ac, se);
659 _ERR("Add vconf callback failed");
661 appcore_event_initialized[se] = 1;
662 } else if (!op->func && appcore_event_initialized[se]) {
665 _ERR("Delete vconf callback failed");
667 appcore_event_initialized[se] = 0;
673 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
674 static gboolean __init_suspend(gpointer data)
678 r = _appcore_init_suspend_dbus_handler(&core);
680 _ERR("Initailzing suspended state handler failed");
687 EXPORT_API int appcore_init(const char *name, const struct ui_ops *ops,
688 int argc, char **argv)
691 char dirname[PATH_MAX];
693 if (core.state != 0) {
694 _ERR("Already in use");
699 if (ops == NULL || ops->cb_app == NULL) {
700 _ERR("ops or callback function is null");
705 r = __get_dir_name(dirname);
706 r = set_i18n(name, dirname);
707 _retv_if(r == -1, -1);
709 r = aul_launch_init(__aul_handler, &core);
711 _ERR("Aul init failed: %d", r);
715 r = aul_launch_argv_handler(argc, argv);
717 _ERR("Aul argv handler failed: %d", r);
722 core.state = 1; /* TODO: use enum value */
724 core.suspended_state = false;
725 core.allowed_bg = false;
729 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
730 g_idle_add(__init_suspend, NULL);
740 EXPORT_API void appcore_exit(void)
745 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
746 __remove_suspend_timer(&core);
752 EXPORT_API int appcore_flush_memory(void)
754 int (*flush_fn) (int);
756 struct appcore *ac = &core;
759 _ERR("Appcore not initialized");
763 _DBG("[APP %d] Flushing memory ...", _pid);
766 ac->ops->cb_app(AE_MEM_FLUSH, ac->ops->data, NULL);
768 flush_fn = dlsym(RTLD_DEFAULT, "sqlite3_release_memory");
770 flush_fn(SQLITE_FLUSH_MAX);
774 *Disabled - the impact of stack_trim() is unclear
778 _DBG("[APP %d] Flushing memory DONE", _pid);
783 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
784 static void __suspend_dbus_signal_handler(GDBusConnection *connection,
785 const gchar *sender_name,
786 const gchar *object_path,
787 const gchar *interface_name,
788 const gchar *signal_name,
789 GVariant *parameters,
792 struct appcore *ac = (struct appcore *)user_data;
793 gint suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
797 if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
798 g_variant_get(parameters, "(ii)", &status, &pid);
799 if (pid == getpid() && status == 0) { /* thawed */
800 if (ac && !ac->allowed_bg && ac->suspended_state) {
801 __remove_suspend_timer(ac);
802 __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
803 ac->suspended_state = false;
804 __add_suspend_timer(ac);
810 int _appcore_init_suspend_dbus_handler(void *data)
814 if (__suspend_dbus_handler_initialized)
818 bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
820 _ERR("Failed to connect to the D-BUS daemon: %s",
827 __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
830 RESOURCED_FREEZER_INTERFACE,
831 RESOURCED_FREEZER_SIGNAL,
832 RESOURCED_FREEZER_PATH,
834 G_DBUS_SIGNAL_FLAGS_NONE,
835 __suspend_dbus_signal_handler,
838 if (__suspend_dbus_handler_initialized == 0) {
839 _ERR("g_dbus_connection_signal_subscribe() is failed.");
843 _DBG("[__SUSPEND__] suspend signal initialized");