2 * Copyright (c) 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.
24 #include <sys/types.h>
29 #include <linux/limits.h>
36 #include <bundle_internal.h>
37 #include "appcore_base.h"
38 #include "appcore_base_private.h"
40 #define PATH_LOCALE "locale"
41 #define RESOURCED_FREEZER_PATH "/Org/Tizen/Resourced/Freezer"
42 #define RESOURCED_FREEZER_INTERFACE "org.tizen.resourced.freezer"
43 #define RESOURCED_FREEZER_SIGNAL "FreezerState"
45 typedef struct _appcore_base_context {
53 } appcore_base_context;
55 typedef struct _appcore_base_event_node {
57 appcore_base_event_cb cb;
59 } appcore_base_event_node;
61 static appcore_base_context __context;
62 static GList *__events;
63 static GDBusConnection *__bus;
64 static guint __suspend_dbus_handler_initialized;
66 static void __invoke_callback(void *event, int type)
68 GList *iter = __events;
71 appcore_base_event_node *node = iter->data;
73 if (node->type == type)
74 node->cb(event, node->data);
75 iter = g_list_next(iter);
79 static bool __exist_callback(int type)
81 GList *iter = __events;
84 appcore_base_event_node *node = iter->data;
86 if (node->type == type)
89 iter = g_list_next(iter);
95 static void __on_low_memory(keynode_t *key, void *data)
99 val = vconf_keynode_get_int(key);
101 if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) {
102 __invoke_callback(key, APPCORE_BASE_EVENT_LOW_MEMORY);
107 static void __on_low_battery(keynode_t *key, void *data)
111 val = vconf_keynode_get_int(key);
113 if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
114 __invoke_callback(key, APPCORE_BASE_EVENT_LOW_BATTERY);
117 static void __update_lang(void)
123 lang = vconf_get_str(VCONFKEY_LANGSET);
125 snprintf(language, sizeof(language), "%s:en_US:en_GB:en", lang);
126 setenv("LANGUAGE", language, 1);
127 setenv("LANG", lang, 1);
128 setenv("LC_MESSAGES", lang, 1);
129 r = setlocale(LC_ALL, "");
131 r = setlocale(LC_ALL, lang);
133 _DBG("*****appcore setlocale=%s\n", r);
139 static void __update_region(void)
144 region = vconf_get_str(VCONFKEY_REGIONFORMAT);
146 setenv("LC_CTYPE", region, 1);
147 setenv("LC_NUMERIC", region, 1);
148 setenv("LC_TIME", region, 1);
149 setenv("LC_COLLATE", region, 1);
150 setenv("LC_MONETARY", region, 1);
151 setenv("LC_PAPER", region, 1);
152 setenv("LC_NAME", region, 1);
153 setenv("LC_ADDRESS", region, 1);
154 setenv("LC_TELEPHONE", region, 1);
155 setenv("LC_MEASUREMENT", region, 1);
156 setenv("LC_IDENTIFICATION", region, 1);
157 r = setlocale(LC_ALL, "");
159 _DBG("*****appcore setlocale=%s\n", r);
165 static void __on_language_change(keynode_t *key, void *data)
169 val = vconf_keynode_get_str(key);
172 __invoke_callback((void *)val, APPCORE_BASE_EVENT_LANG_CHANGE);
175 static void __on_region_change(keynode_t *key, void *data)
180 name = vconf_keynode_get_name(key);
181 if (!strcmp(name, VCONFKEY_REGIONFORMAT))
182 val = vconf_keynode_get_str(key);
185 __invoke_callback((void *)val, APPCORE_BASE_EVENT_REGION_CHANGE);
188 static gboolean __flush_memory(gpointer data)
190 int suspend = APPCORE_BASE_SUSPENDED_STATE_WILL_ENTER_SUSPEND;
192 appcore_base_flush_memory();
195 if (!__context.allowed_bg && !__context.suspended_state) {
196 _DBG("[__SUSPEND__] flush case");
197 __invoke_callback((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
198 __context.suspended_state = true;
204 static void __add_suspend_timer(void)
206 __context.tid = g_timeout_add_seconds(5, __flush_memory, NULL);
209 static void __remove_suspend_timer(void)
211 if (__context.tid > 0) {
212 g_source_remove(__context.tid);
217 static void __on_receive_suspend_signal(GDBusConnection *connection,
218 const gchar *sender_name,
219 const gchar *object_path,
220 const gchar *interface_name,
221 const gchar *signal_name,
222 GVariant *parameters,
225 gint suspend = APPCORE_BASE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
229 if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
230 g_variant_get(parameters, "(ii)", &status, &pid);
231 if (pid == getpid() && status == 0) {
232 if (!__context.allowed_bg && __context.suspended_state) {
233 __remove_suspend_timer();
234 __invoke_callback((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
235 __context.suspended_state = false;
236 __add_suspend_timer();
242 static int __init_suspend_dbus_handler(void)
246 if (__suspend_dbus_handler_initialized)
250 __bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
252 _ERR("Failed to connect to the D-BUS daemon: %s",
259 __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
262 RESOURCED_FREEZER_INTERFACE,
263 RESOURCED_FREEZER_SIGNAL,
264 RESOURCED_FREEZER_PATH,
266 G_DBUS_SIGNAL_FLAGS_NONE,
267 __on_receive_suspend_signal,
270 if (__suspend_dbus_handler_initialized == 0) {
271 _ERR("g_dbus_connection_signal_subscribe() is failed.");
275 _DBG("[__SUSPEND__] suspend signal initialized");
280 static void __fini_suspend_dbus_handler(void)
285 if (__suspend_dbus_handler_initialized) {
286 g_dbus_connection_signal_unsubscribe(__bus,
287 __suspend_dbus_handler_initialized);
288 __suspend_dbus_handler_initialized = 0;
291 g_object_unref(__bus);
295 static int __get_locale_resource_dir(char *locale_dir, int size)
297 const char *res_path;
299 res_path = aul_get_app_resource_path();
300 if (res_path == NULL) {
301 _ERR("Failed to get resource path");
305 snprintf(locale_dir, size, "%s" PATH_LOCALE, res_path);
306 if (access(locale_dir, R_OK) != 0)
312 static int __get_app_name(const char *appid, char **name)
314 char *name_token = NULL;
319 /* com.vendor.name -> name */
320 name_token = strrchr(appid, '.');
321 if (name_token == NULL)
326 *name = strdup(name_token);
333 static int __set_i18n(const char *domain, const char *dir)
338 if (domain == NULL) {
346 r = setlocale(LC_ALL, "");
347 /* if locale is not set properly, try again to set as language base */
349 lan = vconf_get_str(VCONFKEY_LANGSET);
351 r = setlocale(LC_ALL, lan);
352 _DBG("*****appcore setlocale=%s\n", r);
357 _ERR("appcore: setlocale() error");
359 r = bindtextdomain(domain, dir);
361 _ERR("appcore: bindtextdomain() error");
363 r = textdomain(domain);
365 _ERR("appcore: textdomain() error");
370 EXPORT_API int appcore_base_on_set_i18n(void)
373 char locale_dir[PATH_MAX];
374 char appid[PATH_MAX];
377 r = aul_app_get_appid_bypid(getpid(), appid, PATH_MAX);
381 r = __get_app_name(appid, &name);
385 r = __get_locale_resource_dir(locale_dir, sizeof(locale_dir));
391 r = __set_i18n(name, locale_dir);
402 EXPORT_API int appcore_base_init(appcore_base_ops ops, int argc, char **argv, void *data)
405 __context.argc = argc;
406 __context.argv = argv;
407 __context.data = data;
409 __context.suspended_state = false;
410 __context.allowed_bg = false;
412 if (__context.ops.set_i18n)
413 __context.ops.set_i18n(__context.data);
415 __init_suspend_dbus_handler();
417 if (__context.ops.create && __context.ops.create(__context.data) < 0) {
418 aul_status_update(STATUS_DYING);
422 if (__context.ops.run)
423 __context.ops.run(__context.data);
428 EXPORT_API void appcore_base_fini(void)
432 for (i = APPCORE_BASE_EVENT_START + 1; i < APPCORE_BASE_EVENT_MAX; i++) {
433 if (__exist_callback(i)) {
434 if (__context.ops.unset_event)
435 __context.ops.unset_event(i, __context.data);
439 g_list_free_full(__events, free);
441 __fini_suspend_dbus_handler();
443 aul_status_update(STATUS_DYING);
444 if (__context.ops.terminate)
445 __context.ops.terminate(__context.data);
449 EXPORT_API int appcore_base_flush_memory(void)
455 EXPORT_API int appcore_base_on_receive(aul_type type, bundle *b)
458 const char **tep_path;
466 _DBG("[APP %d] AUL event: AUL_START", getpid());
467 tep_path = bundle_get_str_array(b, AUL_TEP_PATH, &len);
469 for (i = 0; i < len; i++) {
470 ret = aul_check_tep_mount(tep_path[i]);
472 _ERR("mount request not completed within 1 sec");
478 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
479 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
480 _DBG("[__SUSPEND__] allowed background");
481 __context.allowed_bg = true;
482 __remove_suspend_timer();
485 if (__context.ops.control)
486 __context.ops.control(b, __context.data);
489 _DBG("[APP %d] AUL event: AUL_RESUME", getpid());
490 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
491 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
492 _DBG("[__SUSPEND__] allowed background");
493 __context.allowed_bg = true;
494 __remove_suspend_timer();
498 _DBG("[APP %d] AUL event: AUL_TERMINATE", getpid());
499 aul_status_update(STATUS_DYING);
500 if (!__context.allowed_bg)
501 __remove_suspend_timer();
503 if (__context.ops.exit)
504 __context.ops.exit(__context.data);
506 case AUL_TERMINATE_BGAPP:
507 _DBG("[APP %d] AUL event: AUL_TERMINATE_BGAPP", getpid());
508 if (!__context.allowed_bg)
509 __remove_suspend_timer();
512 _DBG("[APP %d] AUL event: AUL_WAKE", getpid());
513 if (!__context.allowed_bg && __context.suspended_state) {
514 int suspend = APPCORE_BASE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
515 __remove_suspend_timer();
516 __invoke_callback((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
517 __context.suspended_state = false;
521 _DBG("[APP %d] AUL event: AUL_SUSPEND", getpid());
522 if (!__context.allowed_bg && !__context.suspended_state) {
523 __remove_suspend_timer();
524 __flush_memory(NULL);
527 case AUL_UPDATE_REQUESTED:
528 _DBG("[APP %d] AUL event: AUL_UPDATE_REQUESTED", getpid());
529 __invoke_callback((void *)&dummy, APPCORE_BASE_EVENT_UPDATE_REQUESTED);
532 _DBG("[APP %d] AUL event: %d", getpid(), type);
540 EXPORT_API int appcore_base_on_create(void)
543 r = aul_launch_init(__context.ops.receive, NULL);
545 _ERR("Aul init failed: %d", r);
549 r = aul_launch_argv_handler(__context.argc, __context.argv);
551 _ERR("Aul argv handler failed: %d", r);
558 EXPORT_API int appcore_base_on_control(bundle *b)
563 EXPORT_API int appcore_base_on_terminate()
566 if (__context.ops.exit)
567 __context.ops.exit(__context.data);
572 EXPORT_API void appcore_base_on_set_event(enum appcore_base_event event)
577 case APPCORE_BASE_EVENT_LOW_MEMORY:
578 vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory, NULL);
580 case APPCORE_BASE_EVENT_LOW_BATTERY:
581 vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery, NULL);
583 case APPCORE_BASE_EVENT_LANG_CHANGE:
584 vconf_notify_key_changed(VCONFKEY_LANGSET, __on_language_change, NULL);
586 case APPCORE_BASE_EVENT_REGION_CHANGE:
587 r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, __on_region_change, NULL);
591 vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __on_region_change, NULL);
593 case APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE:
602 EXPORT_API void appcore_base_on_unset_event(enum appcore_base_event event)
607 case APPCORE_BASE_EVENT_LOW_MEMORY:
608 vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory);
610 case APPCORE_BASE_EVENT_LOW_BATTERY:
611 vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery);
613 case APPCORE_BASE_EVENT_LANG_CHANGE:
614 vconf_ignore_key_changed(VCONFKEY_LANGSET, __on_language_change);
616 case APPCORE_BASE_EVENT_REGION_CHANGE:
617 r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __on_region_change);
620 vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __on_region_change);
622 case APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE:
629 EXPORT_API appcore_base_event_h appcore_base_add_event(enum appcore_base_event event,
630 appcore_base_event_cb cb, void *data)
632 appcore_base_event_node *node;
634 if (!__exist_callback(event)) {
635 if (__context.ops.set_event)
636 __context.ops.set_event(event, __context.data);
639 node = malloc(sizeof(appcore_base_event_node));
647 __events = g_list_append(__events, node);
652 EXPORT_API int appcore_base_remove_event(appcore_base_event_h handle)
654 appcore_base_event_node *node = handle;
655 enum appcore_base_event event;
658 __events = g_list_remove(__events, node);
660 if (!__exist_callback(event)) {
661 if (__context.ops.unset_event)
662 __context.ops.unset_event(event, __context.data);
668 EXPORT_API int appcore_base_raise_event(void *event, enum appcore_base_event type)
670 __invoke_callback(event, type);
674 EXPORT_API int appcore_base_get_rotation_state(enum appcore_base_rm *curr)
679 EXPORT_API bool appcore_base_is_bg_allowed(void)
681 return __context.allowed_bg;
684 EXPORT_API bool appcore_base_is_suspended(void)
686 return __context.suspended_state;
689 EXPORT_API void appcore_base_toggle_suspended_state(void)
691 __context.suspended_state ^= __context.suspended_state;
694 static int __on_receive(aul_type type, bundle *b, void *data)
696 return appcore_base_on_receive(type, b);
699 static int __on_create(void *data)
701 return appcore_base_on_create();
704 static int __on_control(bundle *b, void *data)
706 return appcore_base_on_control(b);
709 static int __on_terminate(void *data)
711 return appcore_base_on_terminate();
714 static int __on_set_i18n(void *data)
716 return appcore_base_on_set_i18n();
719 static void __on_set_event(enum appcore_base_event event, void *data)
721 return appcore_base_on_set_event(event);
724 static void __on_unset_event(enum appcore_base_event event, void *data)
726 return appcore_base_on_unset_event(event);
729 EXPORT_API appcore_base_ops appcore_base_get_default_ops(void)
731 appcore_base_ops ops;
733 ops.create = __on_create;
734 ops.control = __on_control;
735 ops.terminate = __on_terminate;
736 ops.receive = __on_receive;
737 ops.set_i18n = __on_set_i18n;
740 ops.set_event = __on_set_event;
741 ops.unset_event = __on_unset_event;