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 <bundle_internal.h>
34 #include "appcore-internal.h"
36 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
39 #define RESOURCED_FREEZER_PATH "/Org/Tizen/Resourced/Freezer"
40 #define RESOURCED_FREEZER_INTERFACE "org.tizen.resourced.freezer"
41 #define RESOURCED_FREEZER_SIGNAL "FreezerState"
43 int __appcore_init_suspend_dbus_handler(void *data);
44 void __appcore_fini_suspend_dbus_handler(void);
47 #define SQLITE_FLUSH_MAX (1024*1024)
49 #define PATH_LOCALE "locale"
51 static struct appcore core;
54 static enum appcore_event to_ae[SE_MAX] = {
55 APPCORE_EVENT_UNKNOWN, /* SE_UNKNOWN */
56 APPCORE_EVENT_LOW_MEMORY, /* SE_LOWMEM */
57 APPCORE_EVENT_LOW_BATTERY, /* SE_LOWBAT */
58 APPCORE_EVENT_LANG_CHANGE, /* SE_LANGCGH */
59 APPCORE_EVENT_REGION_CHANGE,
60 APPCORE_EVENT_SUSPENDED_STATE_CHANGE,
61 APPCORE_EVENT_UPDATE_REQUESTED,
64 static int appcore_event_initialized[SE_MAX] = {0,};
66 enum cb_type { /* callback */
76 enum appcore_event sys;
81 int (*cb_pre) (void *);
83 int (*cb_post) (void *);
85 int (*vcb_pre) (void *, void *);
86 int (*vcb) (void *, void *);
87 int (*vcb_post) (void *, void *);
91 int (*callback) (void *);
95 static struct open_s open;
97 static int __app_terminate(void *data);
98 static int __app_resume(void *data);
99 static int __app_reset(void *data, bundle *k);
101 static int __sys_lowmem_post(void *data, void *evt);
102 static int __sys_lowmem(void *data, void *evt);
103 static int __sys_lowbatt(void *data, void *evt);
104 static int __sys_langchg_pre(void *data, void *evt);
105 static int __sys_langchg(void *data, void *evt);
106 static int __sys_regionchg_pre(void *data, void *evt);
107 static int __sys_regionchg(void *data, void *evt);
108 extern void aul_finalize();
111 static struct evt_ops evtops[] = {
114 .key.vkey = VCONFKEY_SYSMAN_LOW_MEMORY,
115 .vcb_post = __sys_lowmem_post,
120 .key.vkey = VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
121 .vcb = __sys_lowbatt,
125 .key.vkey = VCONFKEY_LANGSET,
126 .vcb_pre = __sys_langchg_pre,
127 .vcb = __sys_langchg,
131 .key.vkey = VCONFKEY_REGIONFORMAT,
132 .vcb_pre = __sys_regionchg_pre,
133 .vcb = __sys_regionchg,
137 .key.vkey = VCONFKEY_REGIONFORMAT_TIME1224,
138 .vcb = __sys_regionchg,
142 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
143 static GDBusConnection *bus;
144 static guint __suspend_dbus_handler_initialized;
147 static int __get_locale_resource_dir(char *locale_dir, int size)
149 const char *res_path;
151 res_path = aul_get_app_resource_path();
152 if (res_path == NULL) {
153 _ERR("Failed to get resource path");
157 snprintf(locale_dir, size, "%s" PATH_LOCALE, res_path);
158 if (access(locale_dir, R_OK) != 0)
164 static int __app_terminate(void *data)
166 struct appcore *ac = data;
168 _retv_if(ac == NULL || ac->ops == NULL, -1);
169 _retv_if(ac->ops->cb_app == NULL, 0);
171 ac->ops->cb_app(AE_TERMINATE, ac->ops->data, NULL);
176 static int __bgapp_terminate(void *data)
178 struct appcore *ac = data;
180 _retv_if(ac == NULL || ac->ops == NULL, -1);
181 _retv_if(ac->ops->cb_app == NULL, 0);
183 ac->ops->cb_app(AE_TERMINATE_BGAPP, ac->ops->data, NULL);
188 static gboolean __prt_ltime(gpointer data)
192 msec = appcore_measure_time_from(NULL);
194 _DBG("[APP %d] first idle after reset: %d msec", _pid, msec);
199 static int __app_reset(void *data, bundle * k)
201 struct appcore *ac = data;
202 _retv_if(ac == NULL || ac->ops == NULL, -1);
203 _retv_if(ac->ops->cb_app == NULL, 0);
205 g_idle_add(__prt_ltime, ac);
207 ac->ops->cb_app(AE_RESET, ac->ops->data, k);
212 static int __app_resume(void *data)
214 struct appcore *ac = data;
215 _retv_if(ac == NULL || ac->ops == NULL, -1);
216 _retv_if(ac->ops->cb_app == NULL, 0);
218 ac->ops->cb_app(AE_RAISE, ac->ops->data, NULL);
222 static int __app_pause(void *data)
224 struct appcore *ac = data;
225 _retv_if(ac == NULL || ac->ops == NULL, -1);
226 _retv_if(ac->ops->cb_app == NULL, 0);
228 ac->ops->cb_app(AE_LOWER, ac->ops->data, NULL);
232 static int __app_update_requested(void *data)
234 struct appcore *ac = data;
236 _retv_if(ac == NULL || ac->ops == NULL, -1);
237 _retv_if(ac->ops->cb_app == NULL, 0);
238 ac->ops->cb_app(AE_UPDATE_REQUESTED, ac->ops->data, NULL);
243 static int __sys_do_default(struct appcore *ac, enum sys_event event)
249 /*r = __def_lowbatt(ac);*/
260 static int __sys_do(struct appcore *ac, void *event_info, enum sys_event event)
264 _retv_if(ac == NULL || event >= SE_MAX, -1);
266 op = &ac->sops[event];
268 if (op->func == NULL)
269 return __sys_do_default(ac, event);
271 return op->func(event_info, op->data);
274 static int __sys_lowmem_post(void *data, void *evt)
276 keynode_t *key = evt;
279 val = vconf_keynode_get_int(key);
281 if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) {
282 #if defined(MEMORY_FLUSH_ACTIVATE)
283 struct appcore *ac = data;
284 ac->ops->cb_app(AE_LOWMEM_POST, ac->ops->data, NULL);
292 static int __sys_lowmem(void *data, void *evt)
294 keynode_t *key = evt;
297 val = vconf_keynode_get_int(key);
299 if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)
300 return __sys_do(data, (void *)&val, SE_LOWMEM);
305 static int __sys_lowbatt(void *data, void *evt)
307 keynode_t *key = evt;
310 val = vconf_keynode_get_int(key);
312 /* VCONFKEY_SYSMAN_BAT_CRITICAL_LOW or VCONFKEY_SYSMAN_POWER_OFF */
313 if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
314 return __sys_do(data, (void *)&val, SE_LOWBAT);
319 static int __sys_langchg_pre(void *data, void *evt)
325 static int __sys_langchg(void *data, void *evt)
327 keynode_t *key = evt;
330 val = vconf_keynode_get_str(key);
332 return __sys_do(data, (void *)val, SE_LANGCHG);
335 static int __sys_regionchg_pre(void *data, void *evt)
341 static int __sys_regionchg(void *data, void *evt)
343 keynode_t *key = evt;
347 name = vconf_keynode_get_name(key);
348 if (!strcmp(name, VCONFKEY_REGIONFORMAT))
349 val = vconf_keynode_get_str(key);
351 return __sys_do(data, (void *)val, SE_REGIONCHG);
354 static void __vconf_do(struct evt_ops *eo, keynode_t * key, void *data)
359 eo->vcb_pre(data, key);
365 eo->vcb_post(data, key);
368 static void __vconf_cb(keynode_t *key, void *data)
373 name = vconf_keynode_get_name(key);
374 _ret_if(name == NULL);
376 _DBG("[APP %d] vconf changed: %s", _pid, name);
378 for (i = 0; i < sizeof(evtops) / sizeof(evtops[0]); i++) {
379 struct evt_ops *eo = &evtops[i];
383 if (!strcmp(name, eo->key.vkey))
384 __vconf_do(eo, key, data);
393 static int __add_vconf(struct appcore *ac, enum sys_event se)
399 r = vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __vconf_cb, ac);
402 r = vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __vconf_cb, ac);
405 r = vconf_notify_key_changed(VCONFKEY_LANGSET, __vconf_cb, ac);
408 r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, __vconf_cb, ac);
412 r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __vconf_cb, ac);
422 static int __del_vconf(enum sys_event se)
428 r = vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __vconf_cb);
431 r = vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __vconf_cb);
434 r = vconf_ignore_key_changed(VCONFKEY_LANGSET, __vconf_cb);
437 r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __vconf_cb);
441 r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __vconf_cb);
451 static int __del_vconf_list(void)
456 for (se = SE_LOWMEM; se < SE_MAX; se++) {
457 if (appcore_event_initialized[se]) {
460 _ERR("Delete vconf callback failed");
462 appcore_event_initialized[se] = 0;
469 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
470 static gboolean __flush_memory(gpointer data)
472 int suspend = APPCORE_SUSPENDED_STATE_WILL_ENTER_SUSPEND;
473 struct appcore *ac = (struct appcore *)data;
475 appcore_flush_memory();
482 if (!ac->allowed_bg && !ac->suspended_state) {
483 _DBG("[__SUSPEND__] flush case");
484 __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
485 ac->suspended_state = true;
491 static void __add_suspend_timer(struct appcore *ac)
493 ac->tid = g_timeout_add_seconds(5, __flush_memory, ac);
496 static void __remove_suspend_timer(struct appcore *ac)
499 g_source_remove(ac->tid);
505 static int __aul_handler(aul_type type, bundle *b, void *data)
508 const char **tep_path = NULL;
511 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
512 const char *bg = NULL;
513 struct appcore *ac = data;
514 int suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
519 _DBG("[APP %d] AUL event: AUL_START", _pid);
520 tep_path = bundle_get_str_array(b, AUL_TEP_PATH, &len);
522 for (i = 0; i < len; i++) {
523 ret = aul_check_tep_mount(tep_path[i]);
525 _ERR("mount request not completed within 1 sec");
531 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
532 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
533 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
534 _DBG("[__SUSPEND__] allowed background");
535 ac->allowed_bg = true;
536 __remove_suspend_timer(data);
540 __app_reset(data, b);
543 _DBG("[APP %d] AUL event: AUL_RESUME", _pid);
544 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
545 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
546 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
547 _DBG("[__SUSPEND__] allowed background");
548 ac->allowed_bg = true;
549 __remove_suspend_timer(data);
554 ret = open.callback(open.cbdata);
562 _DBG("[APP %d] AUL event: AUL_TERMINATE", _pid);
563 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
565 __remove_suspend_timer(data);
568 __app_terminate(data);
570 case AUL_TERMINATE_BGAPP:
571 _DBG("[APP %d] AUL event: AUL_TERMINATE_BGAPP", _pid);
572 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
574 __remove_suspend_timer(data);
577 __bgapp_terminate(data);
580 _DBG("[APP %d] AUL event: AUL_PAUSE", _pid);
583 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
585 _DBG("[APP %d] AUL event: AUL_WAKE", _pid);
586 if (!ac->allowed_bg && ac->suspended_state) {
587 __remove_suspend_timer(data);
588 __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
589 ac->suspended_state = false;
593 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
594 if (bg && strcmp(bg, "ALLOWED_BG") == 0) {
595 _DBG("[__SUSPEND__] allowed background");
596 ac->allowed_bg = true;
601 _DBG("[APP %d] AUL event: AUL_SUSPEND", _pid);
602 ac->allowed_bg = false;
603 if (!ac->suspended_state) {
604 __remove_suspend_timer(data);
605 __flush_memory((gpointer)ac);
609 case AUL_UPDATE_REQUESTED:
610 _DBG("[APP %d] AUL event: AUL_UPDATE_REQUESTED", _pid);
611 __app_update_requested(data);
614 _DBG("[APP %d] AUL event: %d", _pid, type);
623 static void __clear(struct appcore *ac)
625 memset(ac, 0, sizeof(struct appcore));
628 EXPORT_API void appcore_get_app_core(struct appcore **ac)
633 EXPORT_API int appcore_set_open_cb(int (*cb) (void *),
642 EXPORT_API int appcore_set_event_callback(enum appcore_event event,
643 int (*cb) (void *, void *), void *data)
645 struct appcore *ac = &core;
650 for (se = SE_UNKNOWN; se < SE_MAX; se++) {
651 if (event == to_ae[se])
655 if (se == SE_UNKNOWN || se >= SE_MAX) {
656 _ERR("Unregistered event");
666 if (op->func && !appcore_event_initialized[se]) {
667 r = __add_vconf(ac, se);
669 _ERR("Add vconf callback failed");
671 appcore_event_initialized[se] = 1;
672 } else if (!op->func && appcore_event_initialized[se]) {
675 _ERR("Delete vconf callback failed");
677 appcore_event_initialized[se] = 0;
683 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
684 static gboolean __init_suspend(gpointer data)
688 r = __appcore_init_suspend_dbus_handler(&core);
690 _ERR("Initailzing suspended state handler failed");
697 EXPORT_API int appcore_init(const char *name, const struct ui_ops *ops,
698 int argc, char **argv)
701 char locale_dir[PATH_MAX];
703 if (core.state != 0) {
704 _ERR("Already in use");
709 if (ops == NULL || ops->cb_app == NULL) {
710 _ERR("ops or callback function is null");
715 r = __get_locale_resource_dir(locale_dir, sizeof(locale_dir));
716 r = set_i18n(name, locale_dir);
717 _retv_if(r == -1, -1);
719 r = aul_launch_init(__aul_handler, &core);
721 _ERR("Aul init failed: %d", r);
725 r = aul_launch_argv_handler(argc, argv);
727 _ERR("Aul argv handler failed: %d", r);
732 core.state = 1; /* TODO: use enum value */
734 core.suspended_state = false;
735 core.allowed_bg = false;
739 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
740 g_idle_add(__init_suspend, NULL);
750 EXPORT_API void appcore_exit(void)
755 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
756 __remove_suspend_timer(&core);
757 __appcore_fini_suspend_dbus_handler();
763 EXPORT_API int appcore_flush_memory(void)
765 int (*flush_fn) (int);
767 struct appcore *ac = &core;
770 _ERR("Appcore not initialized");
774 _DBG("[APP %d] Flushing memory ...", _pid);
777 ac->ops->cb_app(AE_MEM_FLUSH, ac->ops->data, NULL);
779 flush_fn = dlsym(RTLD_DEFAULT, "sqlite3_release_memory");
781 flush_fn(SQLITE_FLUSH_MAX);
785 *Disabled - the impact of stack_trim() is unclear
789 _DBG("[APP %d] Flushing memory DONE", _pid);
794 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
795 static void __suspend_dbus_signal_handler(GDBusConnection *connection,
796 const gchar *sender_name,
797 const gchar *object_path,
798 const gchar *interface_name,
799 const gchar *signal_name,
800 GVariant *parameters,
803 struct appcore *ac = (struct appcore *)user_data;
804 gint suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
808 if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
809 g_variant_get(parameters, "(ii)", &status, &pid);
810 if (pid == getpid() && status == 0) { /* thawed */
811 if (ac && !ac->allowed_bg && ac->suspended_state) {
812 __remove_suspend_timer(ac);
813 __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
814 ac->suspended_state = false;
815 __add_suspend_timer(ac);
821 int __appcore_init_suspend_dbus_handler(void *data)
825 if (__suspend_dbus_handler_initialized)
829 bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
831 _ERR("Failed to connect to the D-BUS daemon: %s",
838 __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
841 RESOURCED_FREEZER_INTERFACE,
842 RESOURCED_FREEZER_SIGNAL,
843 RESOURCED_FREEZER_PATH,
845 G_DBUS_SIGNAL_FLAGS_NONE,
846 __suspend_dbus_signal_handler,
849 if (__suspend_dbus_handler_initialized == 0) {
850 _ERR("g_dbus_connection_signal_subscribe() is failed.");
854 _DBG("[__SUSPEND__] suspend signal initialized");
859 void __appcore_fini_suspend_dbus_handler(void)
864 if (__suspend_dbus_handler_initialized) {
865 g_dbus_connection_signal_unsubscribe(bus,
866 __suspend_dbus_handler_initialized);
867 __suspend_dbus_handler_initialized = 0;