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 <appcore-common.h>
39 #include <app_control_internal.h>
43 #include "appcore-agent.h"
45 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
48 #define RESOURCED_FREEZER_PATH "/Org/Tizen/Resourced/Freezer"
49 #define RESOURCED_FREEZER_INTERFACE "org.tizen.resourced.frezer"
50 #define RESOURCED_FREEZER_SIGNAL "FreezerState"
51 #define APPFW_SUSPEND_HINT_PATH "/Org/Tizen/Appfw/SuspendHint"
52 #define APPFW_SUSPEND_HINT_INTERFACE "org.tizen.appfw.SuspendHint"
53 #define APPFW_SUSPEND_HINT_SIGNAL "SuspendHint"
61 #define LOG_TAG "APPCORE_AGENT"
62 #define SQLITE_FLUSH_MAX (1024 * 1024)
64 #define _ERR(fmt, arg...) LOGE(fmt, ##arg)
65 #define _INFO(fmt, arg...) LOGI(fmt, ##arg)
66 #define _DBG(fmt, arg...) LOGD(fmt, ##arg)
69 #define EXPORT_API __attribute__ ((visibility("default")))
73 #define _ERR(fmt, arg...) LOGE(fmt, ##arg)
77 #define _INFO(...) LOGI(__VA_ARGS__)
81 #define _DBG(...) LOGD(__VA_ARGS__)
84 #define _warn_if(expr, fmt, arg...) do { \
90 #define _ret_if(expr) do { \
96 #define _retv_if(expr, val) do { \
102 #define _retm_if(expr, fmt, arg...) do { \
109 #define _retvm_if(expr, val, fmt, arg...) do { \
116 #define APPID_MAX 256
117 #define PATH_LOCALE "locale"
122 * Appcore internal system event
135 * agent internal state
155 static enum appcore_agent_event to_ae[SE_MAX] = {
156 APPCORE_AGENT_EVENT_UNKNOWN, /* SE_UNKNOWN */
157 APPCORE_AGENT_EVENT_LOW_MEMORY, /* SE_LOWMEM */
158 APPCORE_AGENT_EVENT_LOW_BATTERY, /* SE_LOWBAT */
159 APPCORE_AGENT_EVENT_LANG_CHANGE, /* SE_LANGCHG */
160 APPCORE_AGENT_EVENT_REGION_CHANGE, /* SE_REGIONCHG */
161 APPCORE_AGENT_EVENT_SUSPENDED_STATE_CHANGE, /* SE_SUSPENDED_STATE */
164 static int appcore_agent_event_initialized[SE_MAX] = {0};
166 enum cb_type { /* callback */
173 enum appcore_agent_suspended_state {
174 APPCORE_AGENT_SUSPENDED_STATE_WILL_ENTER_SUSPEND = 0,
175 APPCORE_AGENT_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND
181 enum appcore_agent_event sys;
182 enum agent_event app;
186 int (*cb_pre) (void *);
188 int (*cb_post) (void *);
190 int (*vcb_pre) (void *, void *);
191 int (*vcb) (void *, void *);
192 int (*vcb_post) (void *, void *);
196 enum agent_state state;
198 struct agent_appcore *app_core;
199 struct agentcore_ops *ops;
202 static struct agent_priv priv;
206 void (*cb_app)(enum agent_event, void *, bundle *);
210 * Appcore system event operation
213 int (*func) (void *, void *);
217 struct agent_appcore {
220 bool suspended_state;
223 const struct agent_ops *ops;
224 struct sys_op sops[SE_MAX];
227 static struct agent_appcore core;
229 static int __sys_lowmem_post(void *data, void *evt);
230 static int __sys_lowmem(void *data, void *evt);
231 static int __sys_lowbatt(void *data, void *evt);
232 static int __sys_langchg_pre(void *data, void *evt);
233 static int __sys_langchg(void *data, void *evt);
234 static int __sys_regionchg_pre(void *data, void *evt);
235 static int __sys_regionchg(void *data, void *evt);
237 static struct evt_ops evtops[] = {
240 .key.vkey = VCONFKEY_SYSMAN_LOW_MEMORY,
241 .vcb_post = __sys_lowmem_post,
246 .key.vkey = VCONFKEY_SYSMAN_BATTERY_STATUS_LOW,
247 .vcb = __sys_lowbatt,
251 .key.vkey = VCONFKEY_LANGSET,
252 .vcb_pre = __sys_langchg_pre,
253 .vcb = __sys_langchg,
257 .key.vkey = VCONFKEY_REGIONFORMAT,
258 .vcb_pre = __sys_regionchg_pre,
259 .vcb = __sys_regionchg,
263 .key.vkey = VCONFKEY_REGIONFORMAT_TIME1224,
264 .vcb = __sys_regionchg,
268 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
269 static GDBusConnection *bus = NULL;
270 static guint __suspend_dbus_handler_initialized = 0;
273 extern int app_control_create_event(bundle *data, struct app_control_s **app_control);
274 static int __sys_do(struct agent_appcore *ac, void *event_info, enum sys_event event);
276 /* LCOV_EXCL_START */
277 static int appcore_agent_flush_memory(void)
279 int (*flush_fn) (int);
282 _ERR("Appcore not initialized");
286 flush_fn = dlsym(RTLD_DEFAULT, "sqlite3_release_memory");
288 flush_fn(SQLITE_FLUSH_MAX);
297 /* LCOV_EXCL_START */
298 static void __prepare_to_suspend(void *data)
300 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
301 int suspend = APPCORE_AGENT_SUSPENDED_STATE_WILL_ENTER_SUSPEND;
302 struct agent_appcore *ac = data;
304 if (ac && !ac->allowed_bg && !ac->suspended_state) {
305 _DBG("[__SUSPEND__]");
306 __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
307 ac->suspended_state = true;
313 /* LCOV_EXCL_START */
314 static void __exit_from_suspend(void *data)
316 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
317 int suspend = APPCORE_AGENT_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
318 struct agent_appcore *ac = data;
320 if (ac && !ac->allowed_bg && ac->suspended_state) {
321 _DBG("[__SUSPEND__]");
322 __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
323 ac->suspended_state = false;
327 /* LCOV_EXCL_START */
329 /* LCOV_EXCL_START */
330 static gboolean __flush_memory(gpointer data)
332 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
333 struct agent_appcore *ac = (struct agent_appcore *)data;
335 appcore_agent_flush_memory();
342 _DBG("[__SUSPEND__] flush case");
343 __prepare_to_suspend(ac);
349 /* LCOV_EXCL_START */
350 static void __add_suspend_timer(struct agent_appcore *ac)
352 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
353 ac->tid = g_timeout_add_seconds(5, __flush_memory, ac);
358 /* LCOV_EXCL_START */
359 static void __remove_suspend_timer(struct agent_appcore *ac)
361 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
363 g_source_remove(ac->tid);
370 static void __exit_loop(void *data)
372 ecore_main_loop_quit();
373 __remove_suspend_timer(&core);
376 static void __do_app(enum agent_event event, void *data, bundle * b)
378 struct agent_priv *svc = data;
379 app_control_h app_control = NULL;
381 _ret_if(svc == NULL);
383 if (event == AGE_TERMINATE) {
384 svc->state = AGS_DYING;
385 ecore_main_loop_thread_safe_call_sync((Ecore_Data_Cb)__exit_loop, NULL);
389 _ret_if(svc->ops == NULL);
391 if (app_control_create_event(b, &app_control) != 0)
396 if (svc->ops->app_control)
397 svc->ops->app_control(app_control, svc->ops->data);
398 svc->state = AGS_RUNNING;
401 if(svc->state == AGS_RUNNING) {
403 svc->ops->stop(svc->ops->data);
404 svc->state = AGS_STOPED;
411 app_control_destroy(app_control);
414 static struct agent_ops s_ops = {
419 static int __set_data(struct agent_priv *agent, struct agentcore_ops *ops)
427 agent->app_core = NULL;
434 static int __agent_request(void *data, bundle * k)
436 struct agent_appcore *ac = data;
437 _retv_if(ac == NULL || ac->ops == NULL, -1);
438 _retv_if(ac->ops->cb_app == NULL, 0);
440 ac->ops->cb_app(AGE_REQUEST, ac->ops->data, k);
445 /* LCOV_EXCL_START */
446 static int __agent_terminate(void *data)
448 struct agent_appcore *ac = data;
450 _retv_if(ac == NULL || ac->ops == NULL, -1);
451 _retv_if(ac->ops->cb_app == NULL, 0);
453 ac->ops->cb_app(AGE_TERMINATE, ac->ops->data, NULL);
459 static int __sys_do_default(struct agent_appcore *ac, enum sys_event event)
465 /*r = __def_lowbatt(ac);*/
476 static int __sys_do(struct agent_appcore *ac, void *event_info, enum sys_event event)
480 _retv_if(ac == NULL || event >= SE_MAX, -1);
482 op = &ac->sops[event];
484 if (op->func == NULL)
485 return __sys_do_default(ac, event);
487 return op->func(event_info, op->data);
490 static int __sys_lowmem_post(void *data, void *evt)
492 #if defined(MEMORY_FLUSH_ACTIVATE)
493 struct agent_appcore *ac = data;
494 ac->ops->cb_app(AE_LOWMEM_POST, ac->ops->data, NULL);
501 static int __sys_lowmem(void *data, void *evt)
503 keynode_t *key = evt;
506 val = vconf_keynode_get_int(key);
508 if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING)
509 return __sys_do(data, (void *)&val, SE_LOWMEM);
514 static int __sys_lowbatt(void *data, void *evt)
516 keynode_t *key = evt;
519 val = vconf_keynode_get_int(key);
521 /* VCONFKEY_SYSMAN_BAT_CRITICAL_LOW or VCONFKEY_SYSMAN_POWER_OFF */
522 if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
523 return __sys_do(data, (void *)&val, SE_LOWBAT);
528 static int __sys_langchg_pre(void *data, void *evt)
530 keynode_t *key = evt;
535 lang = vconf_keynode_get_str(key);
537 snprintf(language, sizeof(language), "%s:en_US:en_GB:en", lang);
538 setenv("LANGUAGE", language, 1);
539 setenv("LANG", lang, 1);
540 setenv("LC_MESSAGES", lang, 1);
542 r = setlocale(LC_ALL, lang);
544 r = setlocale(LC_ALL, lang);
546 _DBG("*****appcore-agent setlocale=%s\n", r);
553 static int __sys_langchg(void *data, void *evt)
555 keynode_t *key = evt;
558 val = vconf_keynode_get_str(key);
560 return __sys_do(data, (void *)val, SE_LANGCHG);
563 static int __sys_regionchg_pre(void *data, void *evt)
565 keynode_t *key = evt;
569 region = vconf_keynode_get_str(key);
571 setenv("LC_CTYPE", region, 1);
572 setenv("LC_NUMERIC", region, 1);
573 setenv("LC_TIME", region, 1);
574 setenv("LC_COLLATE", region, 1);
575 setenv("LC_MONETARY", region, 1);
576 setenv("LC_PAPER", region, 1);
577 setenv("LC_NAME", region, 1);
578 setenv("LC_ADDRESS", region, 1);
579 setenv("LC_TELEPHONE", region, 1);
580 setenv("LC_MEASUREMENT", region, 1);
581 setenv("LC_IDENTIFICATION", region, 1);
583 r = setlocale(LC_ALL, "");
585 _DBG("*****appcore-agent setlocale=%s\n", r);
591 static int __sys_regionchg(void *data, void *evt)
593 keynode_t *key = evt;
597 name = vconf_keynode_get_name(key);
598 if (!strcmp(name, VCONFKEY_REGIONFORMAT))
599 val = vconf_keynode_get_str(key);
601 return __sys_do(data, (void *)val, SE_REGIONCHG);
604 static void __vconf_do(struct evt_ops *eo, keynode_t * key, void *data)
609 eo->vcb_pre(data, key);
615 eo->vcb_post(data, key);
618 static void __vconf_cb(keynode_t *key, void *data)
623 name = vconf_keynode_get_name(key);
624 _ret_if(name == NULL);
626 SECURE_LOGD("[APP %d] vconf changed: %s", _pid, name);
628 for (i = 0; i < sizeof(evtops) / sizeof(evtops[0]); i++) {
629 struct evt_ops *eo = &evtops[i];
633 if (!strcmp(name, eo->key.vkey))
634 __vconf_do(eo, key, data);
643 static int __add_vconf(struct agent_appcore *ac, enum sys_event se)
649 r = vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __vconf_cb, ac);
652 r = vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __vconf_cb, ac);
655 r = vconf_notify_key_changed(VCONFKEY_LANGSET, __vconf_cb, ac);
658 r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, __vconf_cb, ac);
662 r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __vconf_cb, ac);
672 static int __del_vconf(enum sys_event se)
678 r = vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __vconf_cb);
681 r = vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __vconf_cb);
684 r = vconf_ignore_key_changed(VCONFKEY_LANGSET, __vconf_cb);
687 r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __vconf_cb);
691 r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __vconf_cb);
701 static int __del_vconf_list(void)
706 for (se = SE_LOWMEM; se < SE_MAX; se++) {
707 if (appcore_agent_event_initialized[se]) {
710 _ERR("Delete vconf callback failed");
712 appcore_agent_event_initialized[se] = 0;
719 static int __aul_handler(aul_type type, bundle *b, void *data)
723 struct agent_appcore *ac = data;
727 bundle_get_str(b, AUL_K_ALLOWED_BG, &bg);
728 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
729 _DBG("[__SUSPEND__] allowed background");
730 ac->allowed_bg = true;
731 __remove_suspend_timer(data);
733 ret = __agent_request(data, b);
736 bundle_get_str(b, AUL_K_ALLOWED_BG, &bg);
737 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
738 _DBG("[__SUSPEND__] allowed background");
739 ac->allowed_bg = true;
740 __remove_suspend_timer(data);
744 __service_stop(data);
748 case AUL_TERMINATE_BGAPP:
749 if (!ac->allowed_bg) {
750 __remove_suspend_timer(data);
752 ret = __agent_terminate(data);
755 if (!ac->allowed_bg) {
756 _DBG("[__SUSPEND__] suspend");
757 __add_suspend_timer(data);
761 if (!ac->allowed_bg) {
762 _DBG("[__SUSPEND__] wake");
763 __remove_suspend_timer(data);
764 __exit_from_suspend(data);
775 static int __get_package_app_name(int pid, char **app_name)
777 char *name_token = NULL;
778 char appid[APPID_MAX] = {0};
781 r = aul_app_get_appid_bypid(pid, appid, APPID_MAX);
785 if (appid[0] == '\0')
788 name_token = strrchr(appid, '.');
789 if (name_token == NULL)
794 *app_name = strdup(name_token);
795 if (*app_name == NULL)
801 EXPORT_API int appcore_agent_set_event_callback(enum appcore_agent_event event,
802 int (*cb) (void *, void *), void *data)
804 struct agent_appcore *ac = &core;
809 for (se = SE_UNKNOWN; se < SE_MAX; se++) {
810 if (event == to_ae[se])
814 if (se == SE_UNKNOWN || se >= SE_MAX) {
815 _ERR("Unregistered event");
825 if (op->func && !appcore_agent_event_initialized[se]) {
826 r = __add_vconf(ac, se);
828 _ERR("Add vconf callback failed");
830 appcore_agent_event_initialized[se] = 1;
831 } else if (!op->func && appcore_agent_event_initialized[se]) {
834 _ERR("Delete vconf callback failed");
836 appcore_agent_event_initialized[se] = 0;
842 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
843 static gboolean __init_suspend(gpointer data)
847 r = _appcore_agent_init_suspend_dbus_handler(&core);
849 _ERR("Initailzing suspended state handler failed");
855 static int __get_locale_resource_dir(char *locale_dir, int size)
857 const char *res_path;
859 res_path = aul_get_app_resource_path();
860 if (res_path == NULL) {
861 _ERR("Failed to get resource path");
865 snprintf(locale_dir, size, "%s" PATH_LOCALE, res_path);
866 if (access(locale_dir, R_OK) != 0)
872 EXPORT_API int appcore_agent_init(const struct agent_ops *ops,
873 int argc, char **argv)
876 char locale_dir[PATH_MAX];
877 char *app_name = NULL;
879 if (core.state != 0) {
884 if (ops == NULL || ops->cb_app == NULL) {
889 r = __get_package_app_name(getpid(), &app_name);
893 r = __get_locale_resource_dir(locale_dir, sizeof(locale_dir));
894 SECURE_LOGD("dir : %s", locale_dir);
895 SECURE_LOGD("app name : %s", app_name);
896 r = appcore_set_i18n(app_name, locale_dir);
898 _retv_if(r == -1, -1);
900 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
901 g_idle_add(__init_suspend, NULL);
904 r = aul_launch_init(__aul_handler, &core);
908 r = aul_launch_argv_handler(argc, argv);
913 core.state = 1; /* TODO: use enum value */
915 core.suspended_state = false;
916 core.allowed_bg = false;
924 static void appcore_agent_get_app_core(struct agent_appcore **ac)
929 static int __before_loop(struct agent_priv *agent, int argc, char **argv)
932 struct agent_appcore *ac = NULL;
934 if (argc <= 0 || argv == NULL) {
941 r = appcore_agent_init(&s_ops, argc, argv);
942 _retv_if(r == -1, -1);
944 appcore_agent_get_app_core(&ac);
945 agent->app_core = ac;
946 SECURE_LOGD("[__SUSPEND__] agent appcore initialized, appcore addr: 0x%x", ac);
948 if (agent->ops && agent->ops->create) {
949 r = agent->ops->create(agent->ops->data);
951 if (agent->ops && agent->ops->terminate)
952 agent->ops->terminate(agent->ops->data);
957 agent->state = AGS_CREATED;
962 static void __after_loop(struct agent_priv *agent)
965 priv.state = AGS_DYING;
966 if (agent->ops && agent->ops->terminate)
967 agent->ops->terminate(agent->ops->data);
971 EXPORT_API int appcore_agent_terminate()
974 ecore_main_loop_thread_safe_call_sync((Ecore_Data_Cb)__exit_loop, NULL);
979 EXPORT_API int appcore_agent_terminate_without_restart()
982 aul_status_update(STATUS_NORESTART);
983 ecore_main_loop_thread_safe_call_sync((Ecore_Data_Cb)__exit_loop, NULL);
988 EXPORT_API int appcore_agent_main(int argc, char **argv,
989 struct agentcore_ops *ops)
993 r = __set_data(&priv, ops);
994 _retv_if(r == -1, -1);
996 r = __before_loop(&priv, argc, argv);
1000 ecore_main_loop_begin();
1002 aul_status_update(STATUS_DYING);
1004 __after_loop(&priv);
1009 /* LCOV_EXCL_START */
1010 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
1011 static void __suspend_dbus_signal_handler(GDBusConnection *connection,
1012 const gchar *sender_name,
1013 const gchar *object_path,
1014 const gchar *interface_name,
1015 const gchar *signal_name,
1016 GVariant *parameters,
1019 struct agent_appcore *ac = (struct agent_appcore *)user_data;
1020 gint suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
1024 if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
1025 g_variant_get(parameters, "(ii)", &status, &pid);
1026 if (pid == getpid() && status == 0) { /* thawed */
1027 if (ac && !ac->allowed_bg && ac->suspended_state) {
1028 __remove_suspend_timer(ac);
1029 __sys_do(ac, &suspend, SE_SUSPENDED_STATE);
1030 ac->suspended_state = false;
1031 __add_suspend_timer(ac);
1036 /* LCOV_EXCL_STOP */
1038 int _appcore_agent_init_suspend_dbus_handler(void *data)
1042 if (__suspend_dbus_handler_initialized)
1046 bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
1048 _ERR("Failed to connect to the D-BUS daemon: %s",
1055 __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
1058 RESOURCED_FREEZER_INTERFACE,
1059 RESOURCED_FREEZER_SIGNAL,
1060 RESOURCED_FREEZER_PATH,
1062 G_DBUS_SIGNAL_FLAGS_NONE,
1063 __suspend_dbus_signal_handler,
1066 if (__suspend_dbus_handler_initialized == 0) {
1067 _ERR("g_dbus_connection_signal_subscribe() is failed.");
1071 _DBG("[__SUSPEND__] suspend signal initialized");