From: Jiwoong Im Date: Thu, 11 Jun 2015 05:44:50 +0000 (+0900) Subject: implementation of app group X-Git-Tag: accepted/tizen/mobile/20150616.010930^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=faa07ebe83ef060243f96cc631f8b9a669ce018c;p=platform%2Fcore%2Fappfw%2Faul-1.git implementation of app group - provides API to support app group - amd manages grouped application using hash table Change-Id: Ia507be21d1eaff8edf82d52fc215c952d0ed2a58 Signed-off-by: Jiwoong Im --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 6150cfd..57d1874 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,13 +16,26 @@ IF("${CMAKE_BUILD_TYPE}" STREQUAL "") ENDIF() MESSAGE("Build type: ${CMAKE_BUILD_TYPE}") +IF (with_wayland) + ADD_DEFINITIONS("-DWAYLAND") +ENDIF (with_wayland) +IF (with_x11) + ADD_DEFINITIONS("-DX11") +ENDIF (with_x11) # Set required packages INCLUDE(FindPkgConfig) SET(AUL-1_PKG_CHECK_MODULES dlog app-checker rua glib-2.0 vconf pkgmgr-info privacy-manager-client pkgmgr) pkg_check_modules(pkgs REQUIRED ${AUL-1_PKG_CHECK_MODULES} ) -pkg_check_modules(libpkgs REQUIRED dlog bundle dbus-glib-1 ail xdgmime app-checker libtzplatform-config pkgmgr-info libsystemd-daemon security-manager) +SET(AUL-1_LIB_PKG_CHECK_MODULES dlog bundle dbus-glib-1 ail xdgmime app-checker libtzplatform-config pkgmgr-info libsystemd-daemon security-manager) +IF (with_wayland) + pkg_check_modules(libpkgs REQUIRED ${AUL-1_LIB_PKG_CHECK_MODULES} wayland-client) +ENDIF (with_wayland) +IF (with_x11) + pkg_check_modules(libpkgs REQUIRED ${AUL-1_LIB_PKG_CHECK_MODULES}) +ENDIF (with_x11) + PKG_CHECK_MODULES(PKGS REQUIRED glib-2.0 gio-2.0 dlog bundle rua) FIND_LIBRARY(LIB_DL dl) @@ -68,9 +81,12 @@ SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed") ### Build ### # aul_mods : modules (static library) +SET(SRCS_aul_mods src/app_sock.c src/simple_util.c) +IF (with_wayland) + SET(SRCS_aul_mods ${SRCS_aul_mods} src/tizen-transient-for-protocol.c) +ENDIF (with_wayland) add_library(aul_mods STATIC - src/app_sock.c - src/simple_util.c + ${SRCS_aul_mods} ) # aul @@ -87,6 +103,7 @@ add_library(aul SHARED src/key.c src/status.c src/aul_path.c + src/app_group.c ) target_link_libraries(aul aul_mods ${libpkgs_LDFLAGS}) SET_TARGET_PROPERTIES(aul PROPERTIES SOVERSION ${VERSION_MAJOR}) @@ -111,6 +128,7 @@ add_executable(amd am_daemon/amd_appinfo.c am_daemon/amd_launch.c am_daemon/amd_status.c + am_daemon/amd_app_group.c ) SET(AUL-1_LINK_LIBRARY amd aul_mods app-checker-server glib-2.0 bundle ail aul) target_link_libraries(${AUL-1_LINK_LIBRARY} ${pkgs_LDFLAGS}) diff --git a/am_daemon/amd_app_group.c b/am_daemon/amd_app_group.c new file mode 100644 index 0000000..16180a6 --- /dev/null +++ b/am_daemon/amd_app_group.c @@ -0,0 +1,518 @@ +#include +#include +#include +#include +#include + +#include "app_sock.h" +#include "simple_util.h" + +#define APP_SVC_K_LAUNCH_MODE "__APP_SVC_LAUNCH_MODE__" + +static GHashTable *app_group_hash = NULL; +static int dead_pid = -1; +static int focused_leader_pid = -1; + +typedef struct _app_group_context_t { + int pid; + int wid; + int status; +} app_group_context_t; + +static gint __comp_pid(gconstpointer a, gconstpointer b) +{ + app_group_context_t *ac1 = (app_group_context_t*) a; + + return ac1->pid - (int)b; +} + +static void __list_destroy_cb(gpointer data) +{ + free(data); +} + +static gboolean __hash_table_cb(gpointer key, gpointer value, + gpointer user_data) +{ + int pid = (int) user_data; + GList *list = (GList*) value; + GList *itr = g_list_first(list); + + while (itr != NULL) { + app_group_context_t *ac = (app_group_context_t*) itr->data; + + if (ac->pid == pid) { + free(ac); + list = g_list_remove_link(list, itr); + if (g_list_length(list) == 0) { + g_list_free_full(list, __list_destroy_cb); + return TRUE; + } else + return FALSE; + } + itr = g_list_next(itr); + } + + return FALSE; +} + +static void __print_table() +{ + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init(&iter, app_group_hash); + while (g_hash_table_iter_next(&iter, &key, &value)) { + GList *list = (GList*) value; + GList *i = g_list_first(list); + + while (i != NULL) { + app_group_context_t *ac = (app_group_context_t*) i->data; + + _D("app_group key= %d pid=%d", (int ) key, ac->pid); + i = g_list_next(i); + } + } + +} + +static gboolean __is_top(int pid) +{ + int cnt; + int *pids = NULL; + int i; + gboolean found = FALSE; + + app_group_get_leader_pids(&cnt, &pids); + for (i = 0; i < cnt; i++) { + int *gpids = NULL; + int gcnt; + + app_group_get_group_pids(pids[i], &gcnt, &gpids); + if (gcnt > 0 && gpids[gcnt - 1] == pid) + found = TRUE; + + if (gpids != NULL) + free(gpids); + + if (found) + break; + } + + if (pids != NULL) + free(pids); + + _D("is top: %d", found); + return found; +} + +static GList* __find_removable_apps(int from) +{ + int cnt; + int *pids = NULL; + GList *list = NULL; + gboolean found = FALSE; + + app_group_get_leader_pids(&cnt, &pids); + + int i, j; + int lpid = -1; + + for (i = 0; i < cnt; i++) { + int *gpids = NULL; + int gcnt; + + app_group_get_group_pids(pids[i], &gcnt, &gpids); + for (j = 0; j < gcnt; j++) { + if (gpids[j] == from) { + found = TRUE; + continue; + } + + if (found) { + list = g_list_append(list, (gpointer) gpids[j]); + } + } + + if (gpids != NULL) + free(gpids); + + if (found) + break; + } + + if (pids != NULL) + free(pids); + + return list; +} + +void app_group_init() +{ + app_group_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, + NULL); +} + +void app_group_add(int leader_pid, int pid, int wid) +{ + app_group_context_t *ac = malloc(sizeof(app_group_context_t)); + if (ac == NULL) { + _E("out of memory"); + return; + } + + ac->pid = pid; + ac->wid = wid; + dead_pid = -1; + + GList *list = (GList*) g_hash_table_lookup(app_group_hash, + GINT_TO_POINTER(leader_pid)); + if (list != NULL) { + if (g_list_find_custom(list, (gconstpointer)pid, __comp_pid) != NULL) { + _E("pid exist"); + free(ac); + return; + } + } + list = g_list_append(list, ac); + g_hash_table_insert(app_group_hash, GINT_TO_POINTER(leader_pid), list); +} + +void app_group_remove(int pid) +{ + g_hash_table_foreach_remove(app_group_hash, __hash_table_cb, + GINT_TO_POINTER(pid)); +} + +int app_group_get_window(int pid) +{ + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init(&iter, app_group_hash); + while (g_hash_table_iter_next(&iter, &key, &value)) { + GList *list = (GList*) value; + GList *i = g_list_first(list); + + while (i != NULL) { + app_group_context_t *ac = (app_group_context_t*) i->data; + + if (ac->pid == pid) { + return ac->wid; + } + i = g_list_next(i); + } + } + + return -1; +} + +void app_group_clear_top(int pid) +{ + if (!__is_top(pid)) { + GList *list = __find_removable_apps(pid); + + if (list != NULL) { + GList *itr = g_list_last(list); + + while (itr != NULL) { + int p = (int)(itr->data); + + aul_app_group_detach_window(p); + _term_sub_app(p); + app_group_remove(p); + itr = g_list_previous(itr); + } + g_list_free(list); + } + } +} + +void app_group_resume(int pid) +{ + app_group_clear_top(pid); +} + +gboolean app_group_is_group_app(bundle* kb, uid_t uid) +{ + if (kb == NULL) + return FALSE; + + char *str = NULL; + char *mode = NULL; + char *appid = NULL; + int ret; + + pkgmgrinfo_appinfo_h handle; + + bundle_get_str(kb, AUL_K_APPID, &appid); + + if (appid == NULL) + return FALSE; + + ret = pkgmgrinfo_appinfo_get_usr_appinfo(appid, uid, &handle); + if (ret != PMINFO_R_OK) + return FALSE; + ret = pkgmgrinfo_appinfo_get_launch_mode(handle, &mode); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_appinfo_destroy_appinfo(handle); + return FALSE; + } + + if (mode != NULL && strncmp(mode, "caller", 6) == 0) { + bundle_get_str(kb, APP_SVC_K_LAUNCH_MODE, &str); + + if (str != NULL && strncmp(str, "group", 5) == 0) { + pkgmgrinfo_appinfo_destroy_appinfo(handle); + return TRUE; + } + } else if (mode != NULL && strncmp(mode, "group", 5) == 0) { + pkgmgrinfo_appinfo_destroy_appinfo(handle); + return TRUE; + } + + pkgmgrinfo_appinfo_destroy_appinfo(handle); + + return FALSE; +} + +void app_group_get_leader_pids(int *cnt, int **pids) +{ + GHashTableIter iter; + gpointer key, value; + + int size = g_hash_table_size(app_group_hash); + int *leader_pids; + + if (size > 0) { + leader_pids = (int*) malloc(sizeof(int) * size); + if (leader_pids == NULL) { + _E("out of memory"); + *cnt = NULL; + *pids = NULL; + return; + } + + g_hash_table_iter_init(&iter, app_group_hash); + int i = 0; + while (g_hash_table_iter_next(&iter, &key, &value)) { + leader_pids[i] = (int) key; + i++; + } + + *cnt = size; + *pids = leader_pids; + } else { + *cnt = 0; + *pids = NULL; + } +} + +gboolean app_group_is_leader_pid(int pid) +{ + int cnt; + int *pids = NULL; + int i; + + app_group_get_leader_pids(&cnt, &pids); + + for (i=0; i 0) { + int *pid_array = (int*) malloc(sizeof(int) * size); + int j = 0; + + if (pid_array == NULL) { + _E("out of memory"); + *cnt = 0; + *pids = NULL; + return; + } + + while (i != NULL) { + app_group_context_t *ac = (app_group_context_t*) i->data; + + pid_array[j] = ac->pid; + i = g_list_next(i); + j++; + } + + *cnt = size; + *pids = pid_array; + } else { + *cnt = 0; + *pids = NULL; + } + return; + } + } + + *cnt = 0; + *pids = NULL; +} + +gboolean app_group_is_sub_app(int pid) +{ + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init(&iter, app_group_hash); + while (g_hash_table_iter_next(&iter, &key, &value)) { + GList *list = (GList*) value; + GList *found = NULL; + + if (list != NULL) { + if ((found = g_list_find_custom(list, (gconstpointer)pid, __comp_pid)) != NULL) { + if (g_list_first(list) == found) + return FALSE; + return TRUE; + } + } + } + + return FALSE; +} + +void app_group_reroute(int pid) +{ + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init(&iter, app_group_hash); + while (g_hash_table_iter_next(&iter, &key, &value)) { + GList *list = (GList*) value; + GList *found = NULL; + GList *before = NULL; + GList *after = NULL; + + if (list != NULL) { + if ((found = g_list_find_custom(list, (gconstpointer)pid, __comp_pid)) != NULL) { + before = g_list_previous(found); + after = g_list_next(found); + + if (before == NULL || after == NULL) + return; + + _D("reroute"); + app_group_context_t *ac1 = (app_group_context_t*) before->data; + app_group_context_t *ac2 = (app_group_context_t*) after->data; + + aul_app_group_detach_window(ac2->wid); + aul_app_group_attach_window(ac1->wid, ac2->wid); + break; + } + } + } +} + +int app_group_get_leader_pid(int pid) +{ + GHashTableIter iter; + gpointer key, value; + int lpid = -1; + int again = 0; + +repeat: + g_hash_table_iter_init(&iter, app_group_hash); + while (g_hash_table_iter_next(&iter, &key, &value)) { + GList *list = (GList*) value; + + if (list != NULL) { + if (g_list_find_custom(list, (gconstpointer)pid, __comp_pid) != NULL) { + lpid = (int)key; + break; + } + } + } + + if (lpid == -1 && dead_pid == pid) + lpid = focused_leader_pid; + + if (lpid == -1 && again == 0) { + pid = getpgid(pid); + again = 1; + goto repeat; + } + + return lpid; +} + +void app_group_set_dead_pid(int pid) +{ + focused_leader_pid = app_group_get_leader_pid(pid); + dead_pid = pid; + + if (dead_pid == focused_leader_pid) { + focused_leader_pid = -1; + dead_pid = -1; + } +} + +int app_group_get_status(int pid) +{ + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init(&iter, app_group_hash); + while (g_hash_table_iter_next(&iter, &key, &value)) { + GList *list = (GList*) value; + GList *i = g_list_first(list); + + while (i != NULL) { + app_group_context_t *ac = (app_group_context_t*) i->data; + + if (ac->pid == pid) + return ac->status; + + i = g_list_next(i); + } + } + return -1; +} + +int app_group_set_status(int pid, int status) +{ + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init(&iter, app_group_hash); + while (g_hash_table_iter_next(&iter, &key, &value)) { + GList *list = (GList*) value; + GList *i = g_list_first(list); + + while (i != NULL) { + app_group_context_t *ac = (app_group_context_t*) i->data; + + if (ac->pid == pid) { + ac->status = status; + return 0; + } + i = g_list_next(i); + } + } + return -1; + +} diff --git a/am_daemon/amd_app_group.h b/am_daemon/amd_app_group.h new file mode 100644 index 0000000..82b2dbf --- /dev/null +++ b/am_daemon/amd_app_group.h @@ -0,0 +1,24 @@ +#ifndef __AUL_AMD_APP_GROUP_H_ +#define __AUL_AMD_APP_GROUP_H_ + +#include +#include + +void app_group_add(int leader_pid, int pid, int wid); +void app_group_remove(int pid); +int app_group_get_window(int pid); +void app_group_get_leader_pids(int *cnt, int **pids); +void app_group_get_group_pids(int leader_pid, int *cnt, int **pids); +gboolean app_group_is_leader_pid(int pid); +void app_group_resume(int pid); +gboolean app_group_is_group_app(bundle* kb); +gboolean app_group_is_sub_app(int pid); +void app_group_reroute(int pid); +int app_group_get_caller_pid(); +void app_group_clear_top(int pid); +int app_group_get_leader_pid(int pid); +void app_group_set_dead_pid(int pid); +int app_group_get_status(int pid); +int app_group_set_status(int pid, int status); +#endif + diff --git a/am_daemon/amd_launch.c b/am_daemon/amd_launch.c index 1354df3..94c4ff2 100644 --- a/am_daemon/amd_launch.c +++ b/am_daemon/amd_launch.c @@ -433,22 +433,54 @@ int _pause_app(int pid, int clifd) return ret; } +void _term_sub_app(int pid) +{ + int dummy; + int ret; + + if ( (ret = __app_send_raw_with_noreply(pid, APP_TERM_BY_PID_ASYNC, + (unsigned char *)&dummy, sizeof(int))) < 0) { + _E("terminate packet send error - use SIGKILL"); + if (_send_to_sigkill(pid) < 0) { + _E("fail to killing - %d\n", pid); + return; + } + } +} + int _term_app(int pid, int clifd) { int dummy; int ret; - if ((ret = __app_send_raw_with_delay_reply(pid, APP_TERM_BY_PID, - (unsigned char *)&dummy, - sizeof(int))) < 0) { + if (app_group_is_leader_pid(pid)) { + int cnt; + int *pids = NULL; + int i; + + app_group_get_group_pids(pid, &cnt, &pids); + if (cnt > 0) { + for (i = cnt-1 ; i>=0; i--) { + if (i != 0) + _term_sub_app(pids[i]); + app_group_remove(pids[i]); + + } + free(pids); + } + } + + if ( (ret = __app_send_raw_with_delay_reply + (pid, APP_TERM_BY_PID, (unsigned char *)&dummy, sizeof(int))) < 0) { _D("terminate packet send error - use SIGKILL"); if (_send_to_sigkill(pid) < 0) { - _E("fail to killing - %d", pid); + _E("fail to killing - %d\n", pid); + __real_send(clifd, -1); return -1; } + __real_send(clifd, 0); } - _D("term done"); - + _D("term done\n"); if (ret > 0) __set_reply_handler(ret, pid, clifd, APP_TERM_BY_PID); @@ -738,6 +770,7 @@ int _start_app(char* appid, bundle* kb, int cmd, int caller_pid, uid_t caller_ui int delay_reply = 0; int pad_pid = LAUNCHPAD_PID; bool consented = true; + gboolean is_group_app = FALSE; snprintf(tmpbuf, MAX_PID_STR_BUFSZ, "%d", caller_pid); bundle_add(kb, AUL_K_CALLER_PID, tmpbuf); @@ -824,6 +857,11 @@ int _start_app(char* appid, bundle* kb, int cmd, int caller_pid, uid_t caller_ui pid = _status_app_is_running_v2(appid, caller_uid); } + if (app_group_is_group_app(kb, caller_uid)) { + pid = -1; + is_group_app = TRUE; + } + if (pid > 0) { if (_status_get_app_info_status(pid) == STATUS_DYING) { pid = -ETERMINATING; @@ -851,7 +889,8 @@ int _start_app(char* appid, bundle* kb, int cmd, int caller_pid, uid_t caller_ui __real_send(fd, pid); if(pid > 0) { - _status_add_app_info_list(appid, app_path, pid, pad_pid, caller_uid); + if (!is_group_app) + _status_add_app_info_list(appid, app_path, pid, pad_pid, caller_uid); ret = ac_server_check_launch_privilege(appid, appinfo_get_value(ai, AIT_TYPE), pid); return ret != AC_R_ERROR ? pid : -1; } diff --git a/am_daemon/amd_main.c b/am_daemon/amd_main.c index f22706a..f2a513e 100644 --- a/am_daemon/amd_main.c +++ b/am_daemon/amd_main.c @@ -40,6 +40,7 @@ #include "amd_status.h" #include "amd_launch.h" #include "amd_request.h" +#include "amd_app_group.h" #define GLOBAL_USER tzplatform_getuid(TZ_SYS_GLOBALAPP_USER) @@ -237,6 +238,19 @@ int __app_dead_handler(int pid, uid_t user) * listen any more on DBUS system to catch those events. * AMD Agents must connect to AMD Daemon to signal a dead process */ + if(pid <= 0) + return 0; + + if (app_group_is_leader_pid(pid)) { + app_group_clear_top(pid); + app_group_set_dead_pid(pid); + app_group_remove(pid); + } else if (app_group_is_sub_app(pid)) { + app_group_reroute(pid); + app_group_set_dead_pid(pid); + app_group_remove(pid); + } + __remove_item_running_list(pid, user); _status_remove_app_info_list(pid, user); return 0; @@ -256,6 +270,7 @@ static int __init() } _requset_init(); + app_group_init(); if (vconf_notify_key_changed(VCONFKEY_SETAPPL_DEVOPTION_BGPROCESS, __vconf_cb, NULL) != 0) diff --git a/am_daemon/amd_request.c b/am_daemon/amd_request.c index e6f216d..37527ed 100644 --- a/am_daemon/amd_request.c +++ b/am_daemon/amd_request.c @@ -47,6 +47,64 @@ static int __send_result_to_client(int fd, int res); static gboolean __request_handler(gpointer data); +static int __send_result_data(int fd, int cmd, unsigned char *kb_data, int datalen) +{ + int len; + int ret; + int res = 0; + app_pkt_t *pkt = NULL; + + if (datalen > AUL_SOCK_MAXBUFF - 8) { + _E("datalen > AUL_SOCK_MAXBUFF\n"); + return -EINVAL; + } + + pkt = (app_pkt_t *) malloc(sizeof(char) * AUL_SOCK_MAXBUFF); + if (NULL == pkt) { + _E("Malloc Failed!"); + return -ENOMEM; + } + memset(pkt, 0, AUL_SOCK_MAXBUFF); + + pkt->cmd = cmd; + pkt->len = datalen; + memcpy(pkt->data, kb_data, datalen); + + if ((len = send(fd, pkt, datalen + 8, MSG_NOSIGNAL)) != datalen + 8) { + _E("sendto() failed - %d %d (errno %d)", len, datalen + 8, errno); + if(len > 0) { + while (len != datalen + 8) { + ret = send(fd, &pkt->data[len-8], datalen + 8 - len, MSG_NOSIGNAL); + if (ret < 0) { + _E("second sendto() failed - %d %d (errno %d)", ret, datalen + 8, errno); + close(fd); + if (pkt) { + free(pkt); + pkt = NULL; + } + return -ECOMM; + } + len += ret; + _D("sendto() len - %d %d", len, datalen + 8); + } + } else { + close(fd); + if (pkt) { + free(pkt); + pkt = NULL; + } + return -ECOMM; + } + } + if (pkt) { + free(pkt); + pkt = NULL; + } + + close(fd); + return res; +} + extern int __app_dead_handler(int pid, uid_t user); extern int __agent_dead_handler(uid_t user); @@ -250,6 +308,120 @@ static void __handle_agent_dead_signal(struct ucred *pcr) __agent_dead_handler(pcr->uid); } +static void __dispatch_app_group_add(int clifd, const app_pkt_t *pkt) +{ + bundle *b; + char *buf; + int pid, wid, leader_pid; + + b = bundle_decode(pkt->data, pkt->len); + bundle_get_str(b, AUL_K_PID, &buf); + pid = atoi(buf); + bundle_get_str(b, AUL_K_WID, &buf); + wid = atoi(buf); + bundle_get_str(b, AUL_K_LEADER_PID, &buf); + leader_pid = atoi(buf); + bundle_free(b); + app_group_add(leader_pid, pid, wid); + __real_send(clifd, 0); +} + +static void __dispatch_app_group_remove(int clifd, const app_pkt_t *pkt) +{ + bundle *b; + char *buf; + int pid; + + b = bundle_decode(pkt->data, pkt->len); + bundle_get_str(b, AUL_K_PID, &buf); + pid = atoi(buf); + bundle_free(b); + app_group_remove(pid); + __real_send(clifd, 0); +} + +static void __dispatch_app_group_get_window(int clifd, const app_pkt_t *pkt) +{ + bundle *b; + char *buf; + int pid; + int wid; + + b = bundle_decode(pkt->data, pkt->len); + bundle_get_str(b, AUL_K_PID, &buf); + pid = atoi(buf); + bundle_free(b); + wid = app_group_get_window(pid); + __real_send(clifd, wid); +} + +static void __dispatch_app_group_resume(int clifd, int pid) +{ + app_group_resume(pid); + __real_send(clifd, 0); +} + +static void __dispatch_app_group_get_leader_pid(int clifd, + const app_pkt_t *pkt) +{ + bundle *b; + char *buf; + int pid; + int lpid; + + b = bundle_decode(pkt->data, pkt->len); + bundle_get_str(b, AUL_K_PID, &buf); + pid = atoi(buf); + bundle_free(b); + lpid = app_group_get_leader_pid(pid); + __real_send(clifd, lpid); +} + +static void __dispatch_app_group_get_leader_pids(int clifd, + const app_pkt_t *pkt) +{ + char *buf; + int cnt; + int *pids; + int empty[1] = { 0 }; + + app_group_get_leader_pids(&cnt, &pids); + + if (pids == NULL || cnt == 0) { + __send_result_data(clifd, APP_GROUP_GET_LEADER_PIDS, empty, 0); + } else { + __send_result_data(clifd, APP_GROUP_GET_LEADER_PIDS, pids, + cnt * sizeof(int)); + } + if (pids != NULL) + free(pids); +} + +static void __dispatch_app_group_get_group_pids(int clifd, const app_pkt_t *pkt) +{ + bundle *b; + char *buf; + int leader_pid; + int cnt; + int *pids; + int empty[1] = { 0 }; + + b = bundle_decode(pkt->data, pkt->len); + bundle_get_str(b, AUL_K_LEADER_PID, &buf); + leader_pid = atoi(buf); + bundle_free(b); + + app_group_get_group_pids(leader_pid, &cnt, &pids); + if (pids == NULL || cnt == 0) { + __send_result_data(clifd, APP_GROUP_GET_GROUP_PIDS, empty, 0); + } else { + __send_result_data(clifd, APP_GROUP_GET_GROUP_PIDS, pids, + cnt * sizeof(int)); + } + if (pids != NULL) + free(pids); +} + static gboolean __request_handler(gpointer data) { GPollFD *gpollfd = (GPollFD *) data; @@ -420,6 +592,34 @@ static gboolean __request_handler(gpointer data) appinfo_reload(); __send_result_to_client(clifd, 0); break; + + case APP_GROUP_ADD: + __dispatch_app_group_add(clifd, pkt); + break; + + case APP_GROUP_REMOVE: + __dispatch_app_group_remove(clifd, pkt); + break; + + case APP_GROUP_GET_WINDOW: + __dispatch_app_group_get_window(clifd, pkt); + break; + + case APP_GROUP_GET_LEADER_PIDS: + __dispatch_app_group_get_leader_pids(clifd, pkt); + break; + + case APP_GROUP_GET_GROUP_PIDS: + __dispatch_app_group_get_group_pids(clifd, pkt); + break; + + case APP_GROUP_RESUME: + __dispatch_app_group_resume(clifd, cr.pid); + break; + + case APP_GROUP_GET_LEADER_PID: + __dispatch_app_group_get_leader_pid(clifd, pkt); + break; default: _E("no support packet"); close(clifd); diff --git a/am_daemon/amd_status.c b/am_daemon/amd_status.c index c0eb78b..2f8167a 100644 --- a/am_daemon/amd_status.c +++ b/am_daemon/amd_status.c @@ -32,6 +32,7 @@ #include "simple_util.h" #include "app_sock.h" #include "menu_db_util.h" +#include "amd_app_group.h" GSList *app_status_info_list = NULL; @@ -78,12 +79,14 @@ int _status_update_app_info_list(int pid, int status, uid_t uid) { GSList *iter = NULL; app_status_info_t *info_t = NULL; + bool is_sub_app = true; for (iter = app_status_info_list; iter != NULL; iter = g_slist_next(iter)) { info_t = (app_status_info_t *)iter->data; if((pid == info_t->pid) && ((info_t->user == uid) || (info_t->user == 0))) { info_t->status = status; + is_sub_app = false; break; } } @@ -95,6 +98,10 @@ int _status_update_app_info_list(int pid, int status, uid_t uid) //SECURE_LOGD("%s, %d, %d", info_t->appid, info_t->pid, info_t->status); } + if (is_sub_app) { + app_group_set_status(pid, status); + } + return 0; } @@ -206,6 +213,9 @@ int _status_send_running_appinfo(int fd) for (iter = app_status_info_list; iter != NULL; iter = g_slist_next(iter)) { info_t = (app_status_info_t *)iter->data; + if (app_group_is_sub_app(info_t->pid)) + continue; + snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", info_t->pid); strncat((char *)pkt->data, tmp_pid, MAX_PID_STR_BUFSZ); strncat((char *)pkt->data, ":", 1); diff --git a/include/app_sock.h b/include/app_sock.h index 04b4060..73f8890 100644 --- a/include/app_sock.h +++ b/include/app_sock.h @@ -57,6 +57,13 @@ enum app_cmd { APP_TERM_BGAPP_BY_PID, APP_PAUSE, APP_PAUSE_BY_PID, + APP_GROUP_ADD, + APP_GROUP_REMOVE, + APP_GROUP_GET_WINDOW, + APP_GROUP_GET_LEADER_PIDS, + APP_GROUP_GET_GROUP_PIDS, + APP_GROUP_RESUME, + APP_GROUP_GET_LEADER_PID, /* for special purpose */ AMD_RELOAD_APPINFO, diff --git a/include/aul.h b/include/aul.h index c437ca6..7b1cab2 100644 --- a/include/aul.h +++ b/include/aul.h @@ -215,6 +215,10 @@ typedef enum _aul_type{ #define AUL_K_APPID "__AUL_APPID__" /** AUL internal private key */ #define AUL_K_PID "__AUL_PID__" +/** AUL internal private key */ +#define AUL_K_WID "__AUL_WID__" +/** AUL internal private key */ +#define AUL_K_LEADER_PID "__AUL_LEADER_PID__" /** AUL internal private key - To support data control*/ #define AUL_K_DATA_CONTROL_TYPE "__AUL_DATA_CONTROL_TYPE__" @@ -1658,6 +1662,18 @@ int aul_reload_appinfo(void); int aul_status_update(int status); int aul_running_list_update(char *appid, char *app_path, char *pid); +void aul_app_group_add(int leader_pid, int pid, int wid); +void aul_app_group_remove(int pid); +void aul_app_group_attach_window(int parent_wid, int child_wid); +void aul_app_group_detach_window(int child_wid); +int aul_app_group_get_window(int pid); +void aul_app_group_get_leader_pids(int *cnt, int **pids); +void aul_app_group_get_group_pids(int leader_pid, int *cnt, int **pids); +int aul_app_group_get_leader_pid(int pid); +int aul_app_group_clear_top(void); +int aul_app_group_is_top(void); + + /** @} */ diff --git a/include/tizen-transient-for-client-protocol.h b/include/tizen-transient-for-client-protocol.h new file mode 100644 index 0000000..1271fb9 --- /dev/null +++ b/include/tizen-transient-for-client-protocol.h @@ -0,0 +1,76 @@ +#ifndef TIZEN_TRANSIENT_FOR_CLIENT_PROTOCOL_H +#define TIZEN_TRANSIENT_FOR_CLIENT_PROTOCOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "wayland-client.h" + +struct wl_client; +struct wl_resource; + +struct tizen_transient_for; + +extern const struct wl_interface tizen_transient_for_interface; + +struct tizen_transient_for_listener { + /** + * done - (none) + * @child_id: (none) + */ + void (*done)(void *data, + struct tizen_transient_for *tizen_transient_for, + uint32_t child_id); +}; + +static inline int +tizen_transient_for_add_listener(struct tizen_transient_for *tizen_transient_for, + const struct tizen_transient_for_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) tizen_transient_for, + (void (**)(void)) listener, data); +} + +#define TIZEN_TRANSIENT_FOR_SET 0 +#define TIZEN_TRANSIENT_FOR_UNSET 1 + +static inline void +tizen_transient_for_set_user_data(struct tizen_transient_for *tizen_transient_for, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) tizen_transient_for, user_data); +} + +static inline void * +tizen_transient_for_get_user_data(struct tizen_transient_for *tizen_transient_for) +{ + return wl_proxy_get_user_data((struct wl_proxy *) tizen_transient_for); +} + +static inline void +tizen_transient_for_destroy(struct tizen_transient_for *tizen_transient_for) +{ + wl_proxy_destroy((struct wl_proxy *) tizen_transient_for); +} + +static inline void +tizen_transient_for_set(struct tizen_transient_for *tizen_transient_for, uint32_t child_id, uint32_t parent_id) +{ + wl_proxy_marshal((struct wl_proxy *) tizen_transient_for, + TIZEN_TRANSIENT_FOR_SET, child_id, parent_id); +} + +static inline void +tizen_transient_for_unset(struct tizen_transient_for *tizen_transient_for, uint32_t child_id) +{ + wl_proxy_marshal((struct wl_proxy *) tizen_transient_for, + TIZEN_TRANSIENT_FOR_UNSET, child_id); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packaging/ac.service b/packaging/ac.service index 24c5cf1..058f345 100644 --- a/packaging/ac.service +++ b/packaging/ac.service @@ -6,7 +6,7 @@ Description=Start the Access Control server [Service] -EnvironmentFile=-/etc/sysconfig/prelaunch +EnvironmentFile=-/run/tizen-system-env ExecStartPre=/usr/bin/mkdir -p -m 1777 /tmp/alaunch ExecStartPre=/usr/bin/chsmack -a * /tmp/alaunch ExecStart=/usr/bin/amd diff --git a/packaging/aul.spec b/packaging/aul.spec index 7b1beac..2115822 100644 --- a/packaging/aul.spec +++ b/packaging/aul.spec @@ -1,3 +1,6 @@ +%bcond_with x +%bcond_with wayland + Name: aul Summary: App utility library Version: 0.0.300 @@ -36,6 +39,9 @@ BuildRequires: libattr-devel BuildRequires: pkgconfig(privacy-manager-client) BuildRequires: pkgconfig(libtzplatform-config) BuildRequires: pkgconfig(libsystemd-daemon) +%if %{with wayland} +BuildRequires: pkgconfig(wayland-client) +%endif %description Application utility library @@ -49,7 +55,7 @@ Requires: %{name} = %{version}-%{release} Application utility library (devel) %package test -Summary: App utility test tools +Summary: App utility test tools Group: Development/Libraries Requires: %{name} = %{version}-%{release} @@ -67,7 +73,14 @@ cp %{SOURCE1001} . CFLAGS="%{optflags} -D__emul__"; export CFLAGS %endif -%cmake . +%cmake . \ +%if %{with wayland} +-Dwith_wayland=TRUE\ +%endif +%if %{with x} +-Dwith_x11=TRUE\ +%endif + %__make %{?_smp_mflags} %install diff --git a/src/app_group.c b/src/app_group.c new file mode 100644 index 0000000..e5b2dbe --- /dev/null +++ b/src/app_group.c @@ -0,0 +1,259 @@ +#include +#include +#include +#include +#include +#include +#include +#include "aul.h" +#include "aul_api.h" +#include "aul_util.h" +#include "app_sock.h" +#include "simple_util.h" + +#ifdef WAYLAND +#include +#include "tizen-transient-for-client-protocol.h" +static struct tizen_transient_for *tz_transient_for = NULL; + +static void +_reg_handle_global(void *data, struct wl_registry *reg, uint32_t id, const char *interface, uint32_t ver) +{ + if (!strcmp(interface, "tizen_transient_for")) + { + tz_transient_for = wl_registry_bind(reg, + id, + &tizen_transient_for_interface, + 1); + } +} + +static void +_reg_handle_global_remove(void *data, struct wl_registry *reg, uint32_t id) +{ + // do nothing + ; +} + +static const struct wl_registry_listener reg_listener = +{ + _reg_handle_global, + _reg_handle_global_remove +}; +#endif + +SLPAPI void aul_app_group_add(int leader_pid, int pid, int wid) +{ + int ret; + bundle *b; + char buf[128]; + + b = bundle_create(); + snprintf(buf, 128, "%d", leader_pid); + bundle_add_str(b, AUL_K_LEADER_PID, buf); + + snprintf(buf, 128, "%d", pid); + bundle_add_str(b, AUL_K_PID, buf); + + snprintf(buf, 128, "%d", wid); + bundle_add_str(b, AUL_K_WID, buf); + + ret = app_send_cmd(AUL_UTIL_PID, APP_GROUP_ADD, b); + bundle_free(b); +} + +SLPAPI void aul_app_group_remove(int pid) +{ + int ret; + bundle *b; + char buf[128]; + + b = bundle_create(); + snprintf(buf, 128, "%d", pid); + bundle_add_str(b, AUL_K_PID, buf); + + ret = app_send_cmd(AUL_UTIL_PID, APP_GROUP_REMOVE, b); + bundle_free(b); +} + +SLPAPI void aul_app_group_attach_window(int parent_wid, int child_wid) +{ +#ifdef WAYLAND + struct wl_display *dpy; + struct wl_registry *reg; + + dpy = wl_display_connect(NULL); + reg = wl_display_get_registry(dpy); + wl_registry_add_listener(reg, ®_listener, NULL); + wl_display_roundtrip(dpy); + + if (!tz_transient_for) + { + _E("ERR: no tizen_surface_extension global interface"); + wl_registry_destroy(reg); + wl_display_disconnect(dpy); + return; + } + + tizen_transient_for_set(tz_transient_for, child_wid, parent_wid); + wl_display_roundtrip(dpy); + + tizen_transient_for_destroy(tz_transient_for); + wl_registry_destroy(reg); + wl_display_disconnect(dpy); +#else + //ecore_x_icccm_transient_for_set(child_wid, parent_wid); +#endif +} + +SLPAPI void aul_app_group_detach_window(int child_wid) +{ +#ifdef WAYLAND + struct wl_display *dpy; + struct wl_registry *reg; + + dpy = wl_display_connect(NULL); + reg = wl_display_get_registry(dpy); + wl_registry_add_listener(reg, ®_listener, NULL); + wl_display_roundtrip(dpy); + + if (!tz_transient_for) + { + _E("ERR: no tizen_surface_extension global interface"); + wl_registry_destroy(reg); + wl_display_disconnect(dpy); + return; + } + + tizen_transient_for_unset(tz_transient_for, child_wid); + wl_display_roundtrip(dpy); + + tizen_transient_for_destroy(tz_transient_for); + wl_registry_destroy(reg); + wl_display_disconnect(dpy); +#else + //ecore_x_icccm_transient_for_unset(child_wid); +#endif +} + +SLPAPI int aul_app_group_get_window(int pid) +{ + int ret; + bundle *b; + char buf[128]; + + b = bundle_create(); + snprintf(buf, 128, "%d", pid); + bundle_add_str(b, AUL_K_PID, buf); + ret = app_send_cmd(AUL_UTIL_PID, APP_GROUP_GET_WINDOW, b); + bundle_free(b); + + return ret; +} + +SLPAPI void aul_app_group_get_leader_pids(int *cnt, int **pids) +{ + app_pkt_t *ret = NULL; + *cnt = 0; + *pids = NULL; + + ret = __app_send_cmd_with_result(AUL_UTIL_PID, APP_GROUP_GET_LEADER_PIDS, + NULL, 0); + if (ret != NULL) { + *cnt = ret->len / sizeof(int); + if (ret->len > 0 && ret->len <= INT_MAX) { + *pids = malloc(ret->len); + if (*pids == NULL) { + _E("out of memory"); + free(ret); + return; + } + + memcpy(*pids, ret->data, ret->len); + } + free(ret); + } + +} + +SLPAPI void aul_app_group_get_group_pids(int leader_pid, int *cnt, int **pids) +{ + app_pkt_t *ret = NULL; + bundle *b; + bundle_raw *br; + int datalen; + char buf[128]; + *cnt = 0; + *pids = NULL; + + b = bundle_create(); + snprintf(buf, 128, "%d", leader_pid); + bundle_add_str(b, AUL_K_LEADER_PID, buf); + + bundle_encode(b, &br, &datalen); + ret = __app_send_cmd_with_result(AUL_UTIL_PID, APP_GROUP_GET_GROUP_PIDS, br, + datalen); + + if (ret != NULL) { + *cnt = ret->len / sizeof(int); + if (ret->len > 0 && ret->len <= INT_MAX) { + *pids = malloc(ret->len); + if (*pids == NULL) { + _E("out of memory"); + free(br); + bundle_free(b); + free(ret); + return; + } + + memcpy(*pids, ret->data, ret->len); + } + free(ret); + } + + free(br); + bundle_free(b); +} + +SLPAPI int aul_app_group_get_leader_pid(int pid) +{ + int ret; + bundle *b; + char buf[128]; + + b = bundle_create(); + snprintf(buf, 128, "%d", pid); + bundle_add_str(b, AUL_K_PID, buf); + ret = app_send_cmd(AUL_UTIL_PID, APP_GROUP_GET_LEADER_PID, b); + bundle_free(b); + + return ret; +} + +SLPAPI int aul_app_group_clear_top(void) +{ + int dummy[1] = { 0 }; + return __app_send_raw(AUL_UTIL_PID, APP_GROUP_RESUME, dummy, 0); +} + +SLPAPI int aul_app_group_is_top(void) +{ + int lpid = aul_app_group_get_leader_pid(getpid()); + + if (lpid > 0) { + int cnt; + int *pids = NULL; + aul_app_group_get_group_pids(lpid, &cnt, &pids); + if (cnt > 0) { + if (pids[cnt-1] == getpid()) { + free(pids); + return 1; + } + + free(pids); + return 0; + } + } + + return 1; +} diff --git a/src/tizen-transient-for-protocol.c b/src/tizen-transient-for-protocol.c new file mode 100644 index 0000000..5864df8 --- /dev/null +++ b/src/tizen-transient-for-protocol.c @@ -0,0 +1,25 @@ +#include +#include +#include "wayland-util.h" + + +static const struct wl_interface *types[] = { + NULL, + NULL, +}; + +static const struct wl_message tizen_transient_for_requests[] = { + { "set", "uu", types + 0 }, + { "unset", "u", types + 0 }, +}; + +static const struct wl_message tizen_transient_for_events[] = { + { "done", "u", types + 0 }, +}; + +WL_EXPORT const struct wl_interface tizen_transient_for_interface = { + "tizen_transient_for", 1, + 2, tizen_transient_for_requests, + 1, tizen_transient_for_events, +}; +