implementation of app group 71/41071/4 accepted/tizen/mobile/20150616.010930 accepted/tizen/tv/20150616.010944 accepted/tizen/wearable/20150616.010958 submit/tizen/20150615.091318
authorJiwoong Im <jiwoong.im@samsung.com>
Thu, 11 Jun 2015 05:44:50 +0000 (14:44 +0900)
committerJiwoong Im <jiwoong.im@samsung.com>
Fri, 12 Jun 2015 03:40:46 +0000 (12:40 +0900)
- provides API to support app group
- amd manages grouped application using hash table

Change-Id: Ia507be21d1eaff8edf82d52fc215c952d0ed2a58
Signed-off-by: Jiwoong Im <jiwoong.im@samsung.com>
14 files changed:
CMakeLists.txt
am_daemon/amd_app_group.c [new file with mode: 0644]
am_daemon/amd_app_group.h [new file with mode: 0644]
am_daemon/amd_launch.c
am_daemon/amd_main.c
am_daemon/amd_request.c
am_daemon/amd_status.c
include/app_sock.h
include/aul.h
include/tizen-transient-for-client-protocol.h [new file with mode: 0644]
packaging/ac.service
packaging/aul.spec
src/app_group.c [new file with mode: 0644]
src/tizen-transient-for-protocol.c [new file with mode: 0644]

index 6150cfd..57d1874 100644 (file)
@@ -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 (file)
index 0000000..16180a6
--- /dev/null
@@ -0,0 +1,518 @@
+#include <stdio.h>
+#include <string.h>
+#include <glib.h>
+#include <aul.h>
+#include <pkgmgr-info.h>
+
+#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<cnt; i++) {
+               if (pid == pids[i]) {
+                       free(pids);
+                       return TRUE;
+               }
+       }
+
+       if (pids != NULL)
+               free(pids);
+
+       return FALSE;
+}
+
+void app_group_get_group_pids(int leader_pid, int *cnt, int **pids)
+{
+       GHashTableIter iter;
+       gpointer key, value;
+
+       g_hash_table_iter_init(&iter, app_group_hash);
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               if ((int) key == leader_pid) {
+                       GList *list = (GList*) value;
+                       GList *i = g_list_first(list);
+                       int size = g_list_length(list);
+
+                       if (size > 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 (file)
index 0000000..82b2dbf
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef __AUL_AMD_APP_GROUP_H_
+#define __AUL_AMD_APP_GROUP_H_
+
+#include <glib.h>
+#include <bundle.h>
+
+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
+
index 1354df3..94c4ff2 100644 (file)
@@ -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;
        }
index f22706a..f2a513e 100644 (file)
@@ -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)
index e6f216d..37527ed 100644 (file)
 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);
index c0eb78b..2f8167a 100644 (file)
@@ -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);
index 04b4060..73f8890 100644 (file)
@@ -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,
index c437ca6..7b1cab2 100644 (file)
@@ -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 (file)
index 0000000..1271fb9
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef TIZEN_TRANSIENT_FOR_CLIENT_PROTOCOL_H
+#define TIZEN_TRANSIENT_FOR_CLIENT_PROTOCOL_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+#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
index 24c5cf1..058f345 100644 (file)
@@ -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
index 7b1beac..2115822 100644 (file)
@@ -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 (file)
index 0000000..e5b2dbe
--- /dev/null
@@ -0,0 +1,259 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <bundle.h>
+#include "aul.h"
+#include "aul_api.h"
+#include "aul_util.h"
+#include "app_sock.h"
+#include "simple_util.h"
+
+#ifdef WAYLAND
+#include <wayland-client.h>
+#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, &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, &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 (file)
index 0000000..5864df8
--- /dev/null
@@ -0,0 +1,25 @@
+#include <stdlib.h>
+#include <stdint.h>
+#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,
+};
+