sync app group with tizen_2.4 23/50923/8 accepted/tizen/mobile/20151111.232020 accepted/tizen/tv/20151111.232037 accepted/tizen/wearable/20151111.232050 submit/tizen/20151111.072844
authorJiwoong Im <jiwoong.im@samsung.com>
Tue, 3 Nov 2015 05:07:37 +0000 (14:07 +0900)
committerJiwoong Im <jiwoong.im@samsung.com>
Tue, 10 Nov 2015 11:24:51 +0000 (20:24 +0900)
- sync implementation of app group from tizen_2.4
- add appgroup_info tool

Change-Id: Ib5bd77ff6c969bab18d6dbb7affa6fd8c677c5fc
Signed-off-by: Jiwoong Im <jiwoong.im@samsung.com>
14 files changed:
CMakeLists.txt
am_daemon/amd_app_group.c
am_daemon/amd_app_group.h
am_daemon/amd_appinfo.c
am_daemon/amd_appinfo.h
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
packaging/aul.spec
src/app_group.c
tool/app_group_info.c [new file with mode: 0644]

index 91813ab..a5834c5 100644 (file)
@@ -15,7 +15,7 @@ ENDIF (with_x11)
 INCLUDE(FindPkgConfig)
 SET(AUL-1_LIB_PKG_CHECK_MODULES dlog bundle dbus-glib-1 xdgmime libtzplatform-config pkgmgr-info libsystemd-daemon security-manager cynara-client cynara-creds-socket cynara-session capi-system-info vconf sqlite3 iniparser)
 IF (with_wayland)
-       pkg_check_modules(libpkgs REQUIRED ${AUL-1_LIB_PKG_CHECK_MODULES} wayland-client tizen-extension-client)
+       pkg_check_modules(libpkgs REQUIRED ${AUL-1_LIB_PKG_CHECK_MODULES} wayland-client tizen-extension-client ecore-wayland)
 ENDIF (with_wayland)
 IF (with_x11)
        pkg_check_modules(libpkgs REQUIRED ${AUL-1_LIB_PKG_CHECK_MODULES})
@@ -105,6 +105,12 @@ ADD_EXECUTABLE(${APP_LAUNCHER} app_launcher.c)
 TARGET_LINK_LIBRARIES(${APP_LAUNCHER} aul aul_mods ${APP_LAUNCHER_DEPS_LDFLAGS})
 INSTALL(TARGETS app_launcher DESTINATION bin)
 
+# appgroup info tool
+SET(APPGROUP_INFO "appgroup_info")
+ADD_EXECUTABLE(${APPGROUP_INFO} tool/app_group_info.c)
+TARGET_LINK_LIBRARIES(${APPGROUP_INFO} aul aul_mods ${APPGROUP_INFO_DEPS_LDFLAGS})
+INSTALL(TARGETS appgroup_info DESTINATION bin)
+
 # pkgconfig file
 CONFIGURE_FILE(aul.pc.in aul.pc @ONLY)
 CONFIGURE_FILE(legacy/preload_list.txt.in legacy/preload_list.txt @ONLY)
index 1b66a38..c22c7d5 100644 (file)
+#define _GNU_SOURCE
 #include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
-#include <stdint.h>
-
+#include <stdlib.h>
+#include <stdbool.h>
 #include <glib.h>
-
 #include <aul.h>
-#include <pkgmgr-info.h>
+#include <aul_svc.h>
+#include <bundle_internal.h>
 
 #include "app_sock.h"
 #include "simple_util.h"
-#include "amd_launch.h"
 #include "amd_app_group.h"
+#include "amd_launch.h"
+#include "amd_request.h"
+#include "amd_status.h"
+#include "app_signal.h"
+#include "amd_appinfo.h"
 
 #define APP_SVC_K_LAUNCH_MODE   "__APP_SVC_LAUNCH_MODE__"
 
+#ifdef WAYLAND
+#include <Ecore_Wayland.h>
+#include <wayland-client.h>
+#include <tizen-extension-client-protocol.h>
+static struct tizen_policy *tz_policy;
+
+static void _reg_handle_global(void *data, struct wl_registry *reg,
+               uint32_t id, const char *interface, uint32_t ver)
+{
+       if (!strcmp(interface, "tizen_policy")) {
+               tz_policy = wl_registry_bind(reg,
+                               id,
+                               &tizen_policy_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
+
 static GHashTable *app_group_hash = NULL;
 static int dead_pid = -1;
 static int focused_leader_pid = -1;
+static GList *recycle_bin = NULL;
+
+extern char *home_appid;
 
 typedef struct _app_group_context_t {
        int pid;
        int wid;
        int status;
+       int fg;
+       int group_sig;
+       int can_be_leader;
+       int reroute;
+       int caller_pid;
+       int can_shift;
+       int recycle;
+       app_group_launch_mode launch_mode;
 } app_group_context_t;
 
+static void __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_policy) {
+               _E("ERR: no tizen_policy global interface");
+               wl_registry_destroy(reg);
+               wl_display_disconnect(dpy);
+               return;
+       }
+
+       tizen_policy_set_transient_for(tz_policy, child_wid, parent_wid);
+       wl_display_roundtrip(dpy);
+
+       tizen_policy_destroy(tz_policy);
+       wl_registry_destroy(reg);
+       wl_display_disconnect(dpy);
+#else
+       //ecore_x_icccm_transient_for_set(child_wid, parent_wid);
+#endif
+}
+
+static void __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_policy) {
+               _E("ERR: no tz_policy global interface");
+               wl_registry_destroy(reg);
+               wl_display_disconnect(dpy);
+               return;
+       }
+
+       tizen_policy_unset_transient_for(tz_policy, child_wid);
+       wl_display_roundtrip(dpy);
+
+       tizen_policy_destroy(tz_policy);
+       wl_registry_destroy(reg);
+       wl_display_disconnect(dpy);
+#else
+       //ecore_x_icccm_transient_for_unset(child_wid);
+#endif
+}
+
 static gint __comp_pid(gconstpointer a, gconstpointer b)
 {
        app_group_context_t *ac1 = (app_group_context_t*) a;
@@ -62,21 +164,32 @@ static gboolean __hash_table_cb(gpointer key, gpointer value,
        return FALSE;
 }
 
-static gboolean __is_top(int pid)
+static GList* __find_removable_apps(int from)
 {
        int cnt;
        int *pids = NULL;
-       int i;
+       GList *list = NULL;
        gboolean found = FALSE;
 
        app_group_get_leader_pids(&cnt, &pids);
+
+       int i, j;
+
        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;
+               for (j = 0; j < gcnt; j++) {
+                       if (gpids[j] == from) {
+                               found = TRUE;
+                               continue;
+                       }
+
+                       if (found) {
+                               list = g_list_append(list, GINT_TO_POINTER(gpids[j]));
+                       }
+               }
 
                if (gpids != NULL)
                        free(gpids);
@@ -88,87 +201,285 @@ static gboolean __is_top(int pid)
        if (pids != NULL)
                free(pids);
 
-       _D("is top: %d", found);
-       return found;
+       return list;
 }
-
-static GList* __find_removable_apps(int from)
+/*
+ *  TODO : BG manangement should be merged
+static void __prepare_to_suspend_services(int pid)
 {
-       int cnt;
-       int *pids = NULL;
-       GList *list = NULL;
-       gboolean found = FALSE;
-       int i, j;
+       int dummy;
+       SECURE_LOGD("[__SUSPEND__] pid: %d", pid);
+       __app_send_raw_with_noreply(pid, APP_SUSPEND, (unsigned char *)&dummy, sizeof(int));
+}
 
-       app_group_get_leader_pids(&cnt, &pids);
+static void __prepare_to_wake_services(int pid)
+{
+       int dummy;
+       SECURE_LOGD("[__SUSPEND__] pid: %d", pid);
+       __app_send_raw_with_noreply(pid, APP_WAKE, (unsigned char *)&dummy, sizeof(int));
+}
 
-       for (i = 0; i < cnt; i++) {
-               int *gpids = NULL;
-               int gcnt;
+static void __set_fg_flag(int cpid, int flag, gboolean force)
+{
+       int lpid = app_group_get_leader_pid(cpid);
+       GHashTableIter iter;
+       gpointer key, value;
+       int bg_category = 0x00;
 
-               app_group_get_group_pids(pids[i], &gcnt, &gpids);
-               for (j = 0; j < gcnt; j++) {
-                       if (gpids[j] == from) {
-                               found = TRUE;
-                               continue;
+       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);
+               app_group_context_t *ac = (app_group_context_t*) i->data;
+
+               if (ac->pid == lpid) {
+
+                       while (i != NULL) {
+                               ac = (app_group_context_t*) i->data;
+
+                               if (ac->fg != flag || force == TRUE) {
+                                       const char *appid = NULL;
+                                       const char *pkgid = NULL;
+                                       const struct appinfo *ai = NULL;
+
+                                       appid = _status_app_get_appid_bypid(ac->pid);
+                                       ai = appinfo_find(getuid(), appid);
+                                       pkgid = appinfo_get_value(ai, AIT_PKGID);
+                                       bg_category = (bool)appinfo_get_value(ai, AIT_BG_CATEGORY);
+
+                                       if (flag) {
+                                               _D("send_signal FG %s", appid);
+
+                                               aul_send_app_status_change_signal(ac->pid, appid,
+                                                                               pkgid,
+                                                                               STATUS_FOREGROUND,
+                                                                               APP_TYPE_UI);
+                                               if (!bg_category)
+                                                       _status_find_service_apps(ac->pid, STATUS_VISIBLE, __prepare_to_wake_services, false);
+                                       } else {
+                                               _D("send_signal BG %s", appid);
+                                               aul_send_app_status_change_signal(ac->pid, appid,
+                                                                               pkgid,
+                                                                               STATUS_BACKGROUND,
+                                                                               APP_TYPE_UI);
+                                               if (!bg_category)
+                                                       _status_find_service_apps(ac->pid, STATUS_BG, __prepare_to_suspend_services, true);
+                                       }
+                                       ac->fg = flag;
+                               }
+                               i = g_list_next(i);
                        }
+                       break;
+               }
+       }
+}
+*/
 
-                       if (found) {
-                               list = g_list_append(list, GINT_TO_POINTER(gpids[j]));
+static gboolean __is_visible(int cpid)
+{
+       int lpid = app_group_get_leader_pid(cpid);
+       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);
+               app_group_context_t *ac = (app_group_context_t*) i->data;
+
+               if (ac->pid == lpid) {
+                       while (i != NULL) {
+                               ac = (app_group_context_t*) i->data;
+
+                               if (ac->status == STATUS_VISIBLE)
+                                       return TRUE;
+
+                               i = g_list_next(i);
                        }
+                       break;
                }
+       }
 
-               if (gpids != NULL)
-                       free(gpids);
+       return FALSE;
+}
 
-               if (found)
+static gboolean __can_attach_window(bundle *b, const char *appid, app_group_launch_mode *launch_mode)
+{
+       char *str = NULL;
+       const char *mode = NULL;
+       const struct appinfo *ai = NULL;
+
+       ai = appinfo_find(getuid(), appid);
+       mode = appinfo_get_value(ai, AIT_LAUNCH_MODE);
+
+       if (mode == NULL)
+               *launch_mode = APP_GROUP_LAUNCH_MODE_SINGLE;
+       else if (strcmp(mode, "caller") == 0)
+               *launch_mode = APP_GROUP_LAUNCH_MODE_CALLER;
+       else if (strcmp(mode, "single") == 0)
+               *launch_mode = APP_GROUP_LAUNCH_MODE_SINGLE;
+       else if (strcmp(mode, "group") == 0)
+               *launch_mode = APP_GROUP_LAUNCH_MODE_GROUP;
+       else if (strcmp(mode, "singleton") == 0)
+               *launch_mode = APP_GROUP_LAUNCH_MODE_SINGLETON;
+
+       switch (*launch_mode) {
+               case APP_GROUP_LAUNCH_MODE_CALLER:
+               case APP_GROUP_LAUNCH_MODE_SINGLETON:
+                       _D("launch mode from db is caller or singleton");
+
+                       bundle_get_str(b, APP_SVC_K_LAUNCH_MODE, &str);
+                       if (str != NULL && strncmp(str, "group", 5) == 0) {
+                               return TRUE;
+                       }
                        break;
+
+               case APP_GROUP_LAUNCH_MODE_GROUP:
+                       return TRUE;
+
+               case APP_GROUP_LAUNCH_MODE_SINGLE:
+                       return FALSE;
        }
 
-       if (pids != NULL)
-               free(pids);
+       return FALSE;
+}
 
-       return list;
+static gboolean __can_be_leader(bundle *b)
+{
+       char *str = NULL;
+
+       bundle_get_str(b, AUL_SVC_K_CAN_BE_LEADER, &str);
+
+       if (str != NULL && strcmp(str, "true") == 0)
+               return TRUE;
+
+       return FALSE;
 }
 
-void app_group_init(void)
+static int __get_previous_pid(int pid)
 {
-       app_group_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
-                       NULL);
+       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);
+
+               int previous_pid = -1;
+               while (i != NULL) {
+                       app_group_context_t *ac = (app_group_context_t*) i->data;
+
+                       if (ac->pid == pid) {
+                               return previous_pid;
+                       }
+                       previous_pid = ac->pid;
+                       i = g_list_next(i);
+               }
+       }
+
+       return -1;
 }
 
-void app_group_add(int leader_pid, int pid, int wid)
+static int __get_caller_pid(bundle *kb)
 {
-       app_group_context_t *ac = malloc(sizeof(app_group_context_t));
-       if (ac == NULL) {
-               _E("out of memory");
-               return;
+       const char *pid_str;
+       int pid;
+
+       pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
+       if(pid_str)
+               goto end;
+
+       pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
+       if (pid_str == NULL)
+               return -1;
+
+end:
+       pid = atoi(pid_str);
+       if (pid <= 1)
+               return -1;
+
+       return pid;
+}
+
+static app_group_context_t* __detach_context_from_recycle_bin(int pid)
+{
+       GList *iter = recycle_bin;
+
+       while (iter) {
+               app_group_context_t *ac = (app_group_context_t*) iter->data;
+
+               if (ac->pid == pid) {
+                       recycle_bin = g_list_remove_link(recycle_bin, iter);
+                       return ac;
+               }
+
+               iter = g_list_next(iter);
        }
 
-       ac->pid = pid;
-       ac->wid = wid;
+       return NULL;
+
+}
+
+static void __group_add(int leader_pid, int pid, int wid, app_group_launch_mode mode,
+                       int caller_pid, int can_shift, int recycle)
+{
+       app_group_context_t *ac = NULL;
+
+       if ((ac = __detach_context_from_recycle_bin(pid)) == NULL) {
+               ac = malloc(sizeof(app_group_context_t));
+
+               if (ac == NULL) {
+                       _E("out of memory");
+                       return;
+               }
+               ac->pid = pid;
+               ac->wid = wid;
+               ac->fg = 0;
+               ac->can_be_leader = 0;
+               ac->reroute = 0;
+               ac->launch_mode = mode;
+               ac->caller_pid = caller_pid;
+               ac->can_shift = can_shift;
+               ac->recycle = recycle;
+       }
+
+       if (leader_pid == pid || ac->recycle)
+               ac->group_sig = 1;
+       else
+               ac->group_sig = 0;
+
        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)(intptr_t)pid, __comp_pid) != NULL) {
+               if (g_list_find_custom(list, GINT_TO_POINTER(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);
+
+       if (ac->wid != 0)
+               app_group_set_window(pid, ac->wid);
 }
 
-void app_group_remove(int pid)
+static void __group_remove(int pid)
 {
+       int ppid = __get_previous_pid(pid);
        g_hash_table_foreach_remove(app_group_hash, __hash_table_cb,
                        GINT_TO_POINTER(pid));
+
+       if (ppid != -1) {
+               app_group_set_status(ppid, -1, false);
+       }
 }
 
-int app_group_get_window(int pid)
+static app_group_context_t* __get_context(int pid)
 {
        GHashTableIter iter;
        gpointer key, value;
@@ -182,81 +493,200 @@ int app_group_get_window(int pid)
                        app_group_context_t *ac = (app_group_context_t*) i->data;
 
                        if (ac->pid == pid) {
-                               return ac->wid;
+                               return ac;
                        }
                        i = g_list_next(i);
                }
        }
 
+       return NULL;
+}
+
+static int __can_recycle(int pid)
+{
+       app_group_context_t *context = __get_context(pid);
+
+       if (context)
+               return context->recycle;
+
+       return 0;
+}
+
+static int __can_reroute(int pid)
+{
+       app_group_context_t *context = __get_context(pid);
+
+       if (context)
+               return context->reroute;
+
+       return 0;
+}
+
+static app_group_context_t* __context_dup(const app_group_context_t *context)
+{
+       app_group_context_t* dup;
+
+       if (!context) {
+               _E("context is NULL.");
+               return NULL;
+       }
+
+       dup = malloc(sizeof(app_group_context_t));
+       if (!dup) {
+               _E("out of memory");
+               return NULL;
+       }
+
+       memcpy(dup, context, sizeof(app_group_context_t));
+       return dup;
+}
+
+static void __do_recycle(app_group_context_t *context)
+{
+       if (context->fg) {
+               const char *appid = NULL;
+               const char *pkgid = NULL;
+               const struct appinfo *ai = NULL;
+
+               appid = _status_app_get_appid_bypid(context->pid);
+               ai = appinfo_find(getuid(), appid);
+               pkgid = appinfo_get_value(ai, AIT_PKGID);
+
+               _D("send_signal BG %s", appid);
+               aul_send_app_status_change_signal(context->pid, appid, pkgid,
+                                               STATUS_BACKGROUND,
+                                               APP_TYPE_UI);
+//             _status_find_service_apps(context->pid, STATUS_BG, __prepare_to_suspend_services, true);
+               context->fg = 0;
+       }
+       recycle_bin = g_list_append(recycle_bin, context);
+//     _revoke_temporary_permission(context->pid);
+}
+
+void app_group_init()
+{
+       app_group_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
+                       NULL);
+}
+
+void app_group_remove(int pid)
+{
+       __group_remove(pid);
+       app_group_context_t *context = __detach_context_from_recycle_bin(pid);
+
+       if (context)
+               free(context);
+}
+
+void app_group_remove_from_recycle_bin(int pid)
+{
+       app_group_context_t *context = __detach_context_from_recycle_bin(pid);
+
+       if (context)
+               free(context);
+}
+
+int app_group_get_window(int pid)
+{
+       app_group_context_t *context = __get_context(pid);
+
+       if (context)
+               return context->wid;
+
        return -1;
 }
 
-void app_group_clear_top(int pid)
+int app_group_set_window(int pid, int wid)
 {
-       if (!__is_top(pid)) {
-               GList *list = __find_removable_apps(pid);
+       GHashTableIter iter;
+       gpointer key, value;
 
-               if (list != NULL) {
-                       GList *itr = g_list_last(list);
+       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);
+
+               int previous_wid = 0;
+               while (i != NULL) {
+                       app_group_context_t *ac = (app_group_context_t*) i->data;
+
+                       if (ac->pid == pid) {
+                               ac->wid = wid;
+                               if (previous_wid != 0)
+                                       __attach_window(previous_wid, wid);
+
+                               if (ac->can_shift && ac->caller_pid > 0) {
+                                       int caller_wid = app_group_get_window(ac->caller_pid);
+
+                                       if (caller_wid != 0)
+                                               __attach_window(caller_wid, wid);
+                               }
 
-                       while (itr != NULL) {
-                               int p = GPOINTER_TO_INT((itr->data));
+                               i = g_list_next(i);
+                               if (i) {
+                                       ac = (app_group_context_t*) i->data;
+                                       if (ac->wid != 0)
+                                               __attach_window(wid, ac->wid);
+                               }
 
-                               aul_app_group_detach_window(p);
-                               _term_sub_app(p);
-                               app_group_remove(p);
-                               itr = g_list_previous(itr);
+                               return 0;
                        }
-                       g_list_free(list);
+                       previous_wid = ac->wid;
+                       i = g_list_next(i);
                }
        }
+
+       return -1;
 }
 
-void app_group_resume(int pid)
+void app_group_clear_top(int pid)
 {
-       app_group_clear_top(pid);
+       GList *list = __find_removable_apps(pid);
+
+       if (list != NULL) {
+               GList *itr = g_list_last(list);
+
+               while (itr != NULL) {
+                       int p = GPOINTER_TO_INT(itr->data);
+
+                       __detach_window(p);
+                       _term_sub_app(p);
+                       app_group_remove(p);
+                       itr = g_list_previous(itr);
+               }
+               g_list_free(list);
+       }
 }
 
-gboolean app_group_is_group_app(bundle* kb, uid_t uid)
+gboolean app_group_is_group_app(bundle* kb)
 {
        if (kb == NULL)
                return FALSE;
 
        char *str = NULL;
-       char *mode = NULL;
+       const char *mode = NULL;
        char *appid = NULL;
-       int ret;
-
-       pkgmgrinfo_appinfo_h handle;
+       const struct appinfo *ai = NULL;
 
        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;
-       }
+       ai = appinfo_find(getuid(), appid);
+       mode = appinfo_get_value(ai, AIT_LAUNCH_MODE);
 
-       if (mode != NULL && strncmp(mode, "caller", 6) == 0) {
+       if (mode != NULL && (strncmp(mode, "caller", 6) == 0 ||
+                               strncmp(mode, "singleton", 9) == 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;
 }
 
@@ -369,7 +799,7 @@ gboolean app_group_is_sub_app(int pid)
                GList *found = NULL;
 
                if (list != NULL) {
-                       if ((found = g_list_find_custom(list, (gconstpointer)(intptr_t)pid, __comp_pid)) != NULL) {
+                       if ((found = g_list_find_custom(list, GINT_TO_POINTER(pid), __comp_pid)) != NULL) {
                                if (g_list_first(list) == found)
                                        return FALSE;
                                return TRUE;
@@ -393,7 +823,7 @@ void app_group_reroute(int pid)
                GList *after = NULL;
 
                if (list != NULL) {
-                       if ((found = g_list_find_custom(list, (gconstpointer)(intptr_t)pid, __comp_pid)) != NULL) {
+                       if ((found = g_list_find_custom(list, GINT_TO_POINTER(pid), __comp_pid)) != NULL) {
                                before = g_list_previous(found);
                                after = g_list_next(found);
 
@@ -404,8 +834,8 @@ void app_group_reroute(int pid)
                                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);
+                               __detach_window(ac2->wid);
+                               __attach_window(ac1->wid, ac2->wid);
                                break;
                        }
                }
@@ -425,7 +855,7 @@ repeat:
                GList *list = (GList*) value;
 
                if (list != NULL) {
-                       if (g_list_find_custom(list, (gconstpointer)(intptr_t)pid, __comp_pid) != NULL) {
+                       if (g_list_find_custom(list, GINT_TO_POINTER(pid), __comp_pid) != NULL) {
                                lpid = GPOINTER_TO_INT(key);
                                break;
                        }
@@ -477,26 +907,452 @@ int app_group_get_status(int pid)
        return -1;
 }
 
-int app_group_set_status(int pid, int status)
+int app_group_set_status(int pid, int status, gboolean force)
 {
-        GHashTableIter iter;
-        gpointer key, value;
+       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);
+       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;
+               while (i != NULL) {
+                       app_group_context_t *ac = (app_group_context_t*) i->data;
 
-                        if (ac->pid == pid) {
-                                ac->status = status;
+                       if (ac->pid == pid) {
+                               if (status > 0)
+                                       ac->status = status;
+                               GList *last = g_list_last(list);
+                               app_group_context_t *last_ac = (app_group_context_t*) last->data;
+
+                               if (last_ac->wid != 0 || status == STATUS_VISIBLE || force == TRUE) {
+                                       if (__is_visible(pid)) {
+                                               //__set_fg_flag(pid, 1, force);
+                                               if (!ac->group_sig && GPOINTER_TO_INT(key) != pid) {
+                                                       char *appid = NULL;
+                                                       const char *pkgid = NULL;
+                                                       const struct appinfo *ai = NULL;
+
+                                                       appid = _status_app_get_appid_bypid(pid);
+                                                       ai = appinfo_find(getuid(), appid);
+                                                       pkgid = appinfo_get_value(ai, AIT_PKGID);
+
+                                                       _D("send group signal %d", pid);
+                                                       aul_send_app_group_signal(GPOINTER_TO_INT(key), pid, pkgid);
+                                                       ac->group_sig = 1;
+                                               }
+                                       } /*else
+                                               __set_fg_flag(pid, 0, force);*/
+                               }
                                return 0;
                        }
-                        i = g_list_next(i);
-                }
-        }
+                       i = g_list_next(i);
+               }
+       }
+       return -1;
+}
+
+int app_group_get_fg_flag(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->fg;
+                       }
+                       i = g_list_next(i);
+               }
+       }
+
+       return 0;
+}
+
+int app_group_set_hint(int pid, bundle *kb)
+{
+       char *str_leader = NULL;
+       char *str_reroute = NULL;
+
+       if (kb == NULL)
+               return -1;
+
+       bundle_get_str(kb, AUL_SVC_K_CAN_BE_LEADER, &str_leader);
+       bundle_get_str(kb, AUL_SVC_K_REROUTE, &str_reroute);
+
+       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) {
+                               if (str_leader != NULL && strcmp(str_leader, "true") == 0)
+                                       ac->can_be_leader = 1;
+                               if (str_reroute != NULL && strcmp(str_reroute, "true") == 0)
+                                       ac->reroute = 1;
+                               return 0;
+                       }
+                       i = g_list_next(i);
+               }
+       }
+
+       return -1;
+}
+
+int app_group_find_second_leader(int lpid)
+{
+       GList *list = (GList*) g_hash_table_lookup(app_group_hash,
+                       GINT_TO_POINTER(lpid));
+       if (list != NULL) {
+               list = g_list_next(list);
+
+               if (list != NULL) {
+                       app_group_context_t *ac = (app_group_context_t*) list->data;
+                       if (ac->can_be_leader) {
+                               _W("found the second leader, lpid: %d, pid: %d", lpid, ac->pid);
+                               return ac->pid;
+                       }
+               }
+       }
+
        return -1;
+}
+
+void app_group_remove_leader_pid(int lpid)
+{
+       GList *list = (GList*)g_hash_table_lookup(app_group_hash,
+                     GINT_TO_POINTER(lpid));
 
+       if (list != NULL) {
+               GList *next = g_list_next(list);
+
+               if (next != NULL) {
+                       app_group_context_t *ac = (app_group_context_t*) list->data;
+                       free(ac);
+                       list = g_list_remove_link(list, list);
+
+                       ac = (app_group_context_t*) next->data;
+                       g_hash_table_insert(app_group_hash, GINT_TO_POINTER(ac->pid), next);
+                       g_hash_table_remove(app_group_hash, GINT_TO_POINTER(lpid));
+               }
+       }
 }
+
+int app_group_can_start_app(const char *appid, bundle *b, gboolean *can_attach,
+                               int *lpid, app_group_launch_mode *mode)
+{
+       const char *val = NULL;
+       int caller_pid;
+       int caller_wid;
+
+       *can_attach = FALSE;
+       if (__can_attach_window(b, appid, mode)) {
+               *can_attach = TRUE;
+
+               val = bundle_get_val(b, AUL_K_ORG_CALLER_PID);
+               if (val == NULL) {
+                       val = bundle_get_val(b, AUL_K_CALLER_PID);
+               }
+
+               if (val == NULL) {
+                       _E("no caller pid");
+                       return -1;
+               }
+
+               caller_pid = atoi(val);
+
+               *lpid = app_group_get_leader_pid(caller_pid);
+               if (*lpid != -1) {
+                       caller_wid = app_group_get_window(caller_pid);
+
+                       if (caller_wid == 0) {
+                               _E("caller window wasn't ready");
+                               if (__can_be_leader(b))
+                                       *can_attach = FALSE;
+                               else
+                                       *can_attach = TRUE;
+                       }
+
+               } else {
+                       _E("no lpid");
+                       if (__can_be_leader(b))
+                               *can_attach = FALSE;
+                       else
+                               return -1;
+               }
+       }
+
+       return 0;
+}
+
+void app_group_start_app(int pid, bundle *b, int lpid, gboolean can_attach,
+                       app_group_launch_mode mode)
+{
+       _E("app_group_start_app");
+
+       int caller_pid = __get_caller_pid(b);
+       int can_shift = 0;
+       int recycle = 0;
+       const char *str;
+
+       str = bundle_get_val(b, AUL_SVC_K_SHIFT_WINDOW);
+       if (str != NULL && strcmp(str, "true") == 0)
+               can_shift = 1;
+
+       str = bundle_get_val(b, AUL_SVC_K_RECYCLE);
+       if (str != NULL && strcmp(str, "true") == 0)
+               recycle = 1;
+
+       if (can_attach)
+               __group_add(lpid, pid, 0, mode, caller_pid, 0, recycle);
+       else
+               __group_add(pid, pid, 0, mode, caller_pid, can_shift, 0);
+       app_group_set_hint(pid, b);
+}
+
+int app_group_find_singleton(const char *appid, int *found_pid, int *found_lpid)
+{
+       GHashTableIter iter;
+       gpointer key = NULL;
+       gpointer value = NULL;
+       char *target = NULL;
+
+       g_hash_table_iter_init(&iter, app_group_hash);
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               GList *list = (GList*) value;
+
+               while (list != NULL) {
+                       app_group_context_t *ac = (app_group_context_t*) list->data;
+
+                       if (ac->launch_mode == APP_GROUP_LAUNCH_MODE_SINGLETON) {
+                               target = _status_app_get_appid_bypid(ac->pid);
+
+                               if (appid != NULL && target != NULL && strcmp(appid, target) == 0) {
+                                       *found_pid = ac->pid;
+                                       *found_lpid = GPOINTER_TO_INT(key);
+                                       return 0;
+                               }
+                       }
+                       list = g_list_next(list);
+               }
+       }
+
+       return -1;
+}
+
+int app_group_can_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 *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->reroute;
+                       }
+                       i = g_list_next(i);
+               }
+       }
+
+       return 0;
+}
+
+void app_group_lower(int pid, int *exit)
+{
+       if (app_group_is_sub_app(pid)) {
+               if (__can_recycle(pid) && __can_reroute(pid)) {
+                       app_group_context_t *ac = __get_context(pid);
+                       if (ac) {
+                               if (ac->wid != 0)
+                                       __detach_window(ac->wid);
+                               app_group_reroute(pid);
+                               ac = __context_dup(ac);
+                               __group_remove(pid);
+                       /*      if (ac)
+                                       __do_recycle(ac); */
+                       }
+                       *exit = 0;
+               } else
+                       *exit = 1;
+               return;
+       }
+
+       GHashTableIter iter;
+       gpointer key, value;
+
+       *exit = 0;
+       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) {
+                               if (ac->can_shift) {
+                                       __detach_window(ac->wid);
+                                       ac->can_shift = 0;
+#ifdef WAYLAND
+                                       ecore_wl_window_lower((Ecore_Wl_Window *)ac->wid);
+#else
+                                       //ecore_x_window_lower(ac->wid);
+#endif
+                               }
+                               return;
+                       }
+                       i = g_list_next(i);
+               }
+       }
+}
+
+void app_group_restart_app(int pid, bundle *b)
+{
+       if (b == NULL)
+               return;
+
+       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) {
+                               const char *pid_str;
+                               ac->caller_pid = __get_caller_pid(b);
+
+                               if (ac->can_shift) {
+                                       if (ac->wid != 0)
+                                               __detach_window(ac->wid);
+                                       ac->can_shift = 0;
+                               }
+
+                               pid_str = bundle_get_val(b, AUL_SVC_K_SHIFT_WINDOW);
+                               if (pid_str != NULL && strcmp(pid_str, "true") == 0) {
+                                       ac->can_shift = 1;
+                                       if (ac->wid != 0) {
+                                               if (ac->caller_pid > 0) {
+                                                       int cwid = app_group_get_window(ac->caller_pid);
+
+                                                       if (cwid != 0)
+                                                               __attach_window(cwid, ac->wid);
+                                                       else
+                                                               _E("invalid caller wid");
+
+                                               } else
+                                                       _E("invalid caller pid");
+
+
+                                       }
+                               }
+                               return;
+                       }
+                       i = g_list_next(i);
+               }
+       }
+}
+
+int app_group_find_pid_from_recycle_bin(const char *appid)
+{
+       GList *iter = recycle_bin;
+
+       while (iter) {
+               app_group_context_t *ac = (app_group_context_t*) iter->data;
+               const char *appid_from_bin = _status_app_get_appid_bypid(ac->pid);
+
+               if (appid && appid_from_bin && strcmp(appid, appid_from_bin) == 0) {
+                       return ac->pid;
+               }
+
+               iter = g_list_next(iter);
+       }
+
+       return -1;
+}
+
+void app_group_get_idle_pids(int *cnt, int **pids)
+{
+       GList *iter = recycle_bin;
+       int idle_cnt = g_list_length(iter);
+
+       if (idle_cnt <= 0) {
+               *cnt = 0;
+               *pids = NULL;
+               return;
+       }
+
+       int *idle_pids = NULL;
+
+       idle_pids = malloc(sizeof(int) * idle_cnt);
+       if (idle_pids == NULL) {
+               _E("Out-of-memory");
+               *cnt = 0;
+               *pids = NULL;
+               return;
+       }
+
+       int i = 0;
+       while (iter) {
+               app_group_context_t *ac = (app_group_context_t*) iter->data;
+               idle_pids[i] = ac->pid;
+               iter = g_list_next(iter);
+               i++;
+       }
+
+       *cnt = idle_cnt;
+       *pids = idle_pids;
+}
+
+int app_group_get_next_caller_pid(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) {
+                               i = g_list_next(i);
+                               if (i == NULL)
+                                       return -1;
+
+                               ac = (app_group_context_t*) i->data;
+                               return ac->caller_pid;
+                       }
+                       i = g_list_next(i);
+               }
+       }
+
+       return -1;
+}
+
+
index d85fadc..9d23295 100644 (file)
@@ -4,15 +4,21 @@
 #include <glib.h>
 #include <bundle.h>
 
-void app_group_init(void);
-void app_group_add(int leader_pid, int pid, int wid);
+typedef enum {
+       APP_GROUP_LAUNCH_MODE_SINGLE = 0,
+       APP_GROUP_LAUNCH_MODE_GROUP,
+       APP_GROUP_LAUNCH_MODE_CALLER,
+       APP_GROUP_LAUNCH_MODE_SINGLETON,
+} app_group_launch_mode;
+
+void app_group_init();
 void app_group_remove(int pid);
 int app_group_get_window(int pid);
+int app_group_set_window(int pid, int wid);
 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, uid_t uid);
+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();
@@ -20,6 +26,20 @@ 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);
+int app_group_set_status(int pid, int status, gboolean force);
+int app_group_get_fg_flag(int pid);
+int app_group_set_hint(int pid, bundle *kb);
+int app_group_find_second_leader(int lpid);
+void app_group_remove_leader_pid(int lpid);
+int app_group_can_start_app(const char *appid, bundle *b, gboolean *can_attach, int *lpid, app_group_launch_mode *mode);
+void app_group_start_app(int pid, bundle *b, int lpid, gboolean can_attach, app_group_launch_mode mode);
+int app_group_find_singleton(const char *appid, int *found_pid, int *found_lpid);
+int app_group_can_reroute(int pid);
+void app_group_lower(int pid, int *exit);
+void app_group_restart_app(int pid, bundle *b);
+int app_group_find_pid_from_recycle_bin(const char *appid);
+void app_group_get_idle_pids(int *cnt, int **pids);
+void app_group_remove_from_recycle_bin(int pid);
+int app_group_get_next_caller_pid(int pid);
 #endif
 
index e98254e..3726999 100644 (file)
@@ -39,6 +39,7 @@ enum _appinfo_idx {
        _AI_PKGID,
        _AI_PRELOAD,
        _AI_STATUS,
+       _AI_LAUNCH_MODE,
        _AI_MAX,
 };
 #define _AI_START _AI_NAME /* start index */
@@ -61,6 +62,7 @@ static struct appinfo_t _appinfos[] = {
        [_AI_PKGID] = { "PackageId", AIT_PKGID, },
        [_AI_PRELOAD] = { "Preload", AIT_PRELOAD, },
        [_AI_STATUS] = { "Status", AIT_STATUS, },
+       [_AI_LAUNCH_MODE] = {"launch_mode", AIT_LAUNCH_MODE },
 };
 
 struct appinfo {
@@ -113,6 +115,7 @@ static int __app_info_insert_handler (const pkgmgrinfo_appinfo_h handle, void *d
        char *type;
        char *appid;
        char *pkgid;
+       char *mode;
        bool multiple;
        bool onboot;
        bool restart;
@@ -227,6 +230,13 @@ static int __app_info_insert_handler (const pkgmgrinfo_appinfo_h handle, void *d
        c->val[_AI_PKGID] = strdup(pkgid);
        c->val[_AI_STATUS] = strdup("installed");
 
+       if (pkgmgrinfo_appinfo_get_launch_mode(handle, &mode)) {
+               _E("failed to get launch_mode");
+               _free_appinfo(c);
+               return -1;
+       }
+       c->val[_AI_LAUNCH_MODE] = strdup(mode ? mode : "single");
+
        SECURE_LOGD("%s : %s : %s", c->val[_AI_FILE], c->val[_AI_COMP], c->val[_AI_TYPE]);
 
        g_hash_table_insert(info->tbl, c->val[_AI_FILE], c);
index ed94a44..e544090 100644 (file)
@@ -19,8 +19,13 @@ enum appinfo_type {
        AIT_PKGID,
        AIT_PRELOAD,
        AIT_STATUS,
+       AIT_LAUNCH_MODE,
+       AIT_MAX
 };
 
+#define APP_TYPE_UI            "ui"
+#define APP_TYPE_SERVICE       "svc"
+
 int appinfo_init(void);
 void appinfo_fini(void);
 
index 2112569..934639a 100644 (file)
@@ -283,9 +283,6 @@ int _term_req_app(int pid, int clifd)
 
 int _term_bgapp(int pid, int clifd)
 {
-       return _term_app(pid, clifd);
-       /* FIXME: app group feature should be merged */
-#if 0
        int dummy;
        int fd;
        int cnt;
@@ -296,7 +293,7 @@ int _term_bgapp(int pid, int clifd)
        if (app_group_is_leader_pid(pid)) {
                app_group_get_group_pids(pid, &cnt, &pids);
                if (cnt > 0) {
-                       status = _status_get_app_info_status(pids[cnt - 1]);
+                       status = _status_get_app_info_status(pids[cnt - 1], getuid());
                        if (status == STATUS_BG) {
                                for (i = cnt - 1 ; i >= 0; i--) {
                                        if (i != 0)
@@ -323,7 +320,6 @@ int _term_bgapp(int pid, int clifd)
                __set_reply_handler(fd, pid, clifd, APP_TERM_BGAPP_BY_PID);
 
        return 0;
-#endif
 }
 
 int _fake_launch_app(int cmd, int pid, bundle *kb, int clifd)
@@ -557,6 +553,51 @@ static int __compare_signature(const struct appinfo *ai, int cmd,
        return 0;
 }
 
+static int __get_pid_for_app_group(const char *appid, int pid, int caller_uid, bundle* kb,
+               int *lpid, gboolean *can_attach, gboolean *new_process, app_group_launch_mode* launch_mode)
+{
+       int st = -1;
+       int found_pid = -1;
+       int found_lpid = -1;
+
+       if (app_group_is_group_app(kb)) {
+               pid = -1;
+       }
+
+       if (pid > 0)
+               st = _status_get_app_info_status(pid, caller_uid);
+
+       if (pid == -1 || st == STATUS_DYING) {
+
+               if (app_group_find_singleton(appid, &found_pid, &found_lpid) == 0) {
+                       pid = found_pid;
+                       *new_process = FALSE;
+               } else {
+                       *new_process = TRUE;
+               }
+
+               if (app_group_can_start_app(appid, kb, can_attach, lpid, launch_mode) != 0 ) {
+                       _E("can't make group info");
+                       return -EILLEGALACCESS;
+               }
+
+               if (*can_attach && *lpid == found_lpid) {
+                       _E("can't launch singleton app in the same group");
+                       return -EILLEGALACCESS;
+               }
+
+               if (found_pid != -1) {
+                       _W("app_group_clear_top, pid: %d", found_pid);
+                       app_group_clear_top(found_pid);
+               }
+       }
+
+       if (pid == -1 && *can_attach)
+               pid = app_group_find_pid_from_recycle_bin(appid);
+
+       return pid;
+}
+
 int _start_app(const char* appid, bundle* kb, int cmd, int caller_pid,
                uid_t caller_uid, int fd)
 {
@@ -567,13 +608,17 @@ int _start_app(const char* appid, bundle* kb, int cmd, int caller_pid,
        const char *app_path = NULL;
        const char *pkg_type = NULL;
        const char *pkg_id = NULL;
+       const char *component_type = NULL;
        int pid = -1;
        char tmpbuf[MAX_PID_STR_BUFSZ];
        const char *hwacc;
        char *caller_appid;
        int delay_reply = 0;
        int pad_pid = LAUNCHPAD_PID;
-       gboolean is_group_app = FALSE;
+       int lpid;
+       gboolean can_attach;
+       gboolean new_process;
+       app_group_launch_mode launch_mode;
 
        snprintf(tmpbuf, MAX_PID_STR_BUFSZ, "%d", caller_pid);
        bundle_add(kb, AUL_K_CALLER_PID, tmpbuf);
@@ -625,9 +670,14 @@ int _start_app(const char* appid, bundle* kb, int cmd, int caller_pid,
                pid = _status_app_is_running(appid, caller_uid);
        }
 
-       if (app_group_is_group_app(kb, caller_uid)) {
-               pid = -1;
-               is_group_app = TRUE;
+       component_type = appinfo_get_value(ai, AIT_COMP);
+       if (strncmp(component_type, APP_TYPE_UI, strlen(APP_TYPE_UI)) == 0) {
+               pid = __get_pid_for_app_group(appid, pid, caller_uid, kb,
+                               &lpid, &can_attach, &new_process, &launch_mode);
+               if (pid == -EILLEGALACCESS) {
+                       __real_send(fd, pid);
+                       return pid;
+               }
        }
 
        if (pid > 0) {
@@ -652,15 +702,23 @@ int _start_app(const char* appid, bundle* kb, int cmd, int caller_pid,
                bundle_add(kb, AUL_K_PACKAGETYPE, pkg_type);
                bundle_add(kb, AUL_K_PKGID, pkg_id);
                pid = app_agent_send_cmd(caller_uid, cmd, kb);
-       }
 
-       if (!delay_reply)
-               __real_send(fd, pid);
+               if (strncmp(component_type, APP_TYPE_UI, strlen(APP_TYPE_UI)) == 0) {
+                       if (new_process) {
+                               _D("add app group info");
+                               app_group_start_app(pid, kb, lpid, can_attach, launch_mode);
+                       } else {
+                               app_group_restart_app(pid, kb);
+                       }
+               }
+       }
 
        if (pid > 0) {
-               if (!is_group_app)
-                       _status_add_app_info_list(appid, app_path, pid, pad_pid, caller_uid);
+               _status_add_app_info_list(appid, app_path, pid, pad_pid, caller_uid);
        }
 
+       if (!delay_reply)
+               __real_send(fd, pid);
+
        return pid;
 }
index 50026ed..81f41f6 100644 (file)
@@ -248,11 +248,24 @@ static int __app_dead_handler(int pid, void *data)
         _D("APP_DEAD_SIGNAL : %d", pid);
 
        if (app_group_is_leader_pid(pid)) {
-               app_group_clear_top(pid);
-               app_group_set_dead_pid(pid);
-               app_group_remove(pid);
+               _W("app_group_leader_app, pid: %d", pid);
+               if (app_group_find_second_leader(pid) == -1) {
+                       app_group_clear_top(pid);
+                       app_group_set_dead_pid(pid);
+                       app_group_remove(pid);
+               } else
+                       app_group_remove_leader_pid(pid);
        } else if (app_group_is_sub_app(pid)) {
-               app_group_reroute(pid);
+               _W("app_group_sub_app, pid: %d", pid);
+               int caller_pid = app_group_get_next_caller_pid(pid);
+
+               if (app_group_can_reroute(pid) || (caller_pid > 0 && caller_pid != pid)) {
+                       _W("app_group reroute");
+                       app_group_reroute(pid);
+               } else {
+                       _W("app_group clear top");
+                       app_group_clear_top(pid);
+               }
                app_group_set_dead_pid(pid);
                app_group_remove(pid);
        }
index cbe3546..c4c9493 100644 (file)
@@ -419,68 +419,67 @@ err_out:
        return -1;
 }
 
-static int __dispatch_app_group_add(int clifd, const app_pkt_t *pkt, struct ucred *cr)
+static int __dispatch_app_group_get_window(int clifd, const app_pkt_t *pkt, struct ucred *cr)
 {
        bundle *b;
        char *buf;
-       int pid, wid, leader_pid;
+       int pid;
+       int wid;
 
        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);
+       wid = app_group_get_window(pid);
+       __send_result_to_client(clifd, wid);
 
        return 0;
 }
 
-static int __dispatch_app_group_remove(int clifd, const app_pkt_t *pkt, struct ucred *cr)
+static int __dispatch_app_group_set_window(int clifd, const app_pkt_t *pkt, struct ucred *cr)
 {
        bundle *b;
        char *buf;
-       int pid;
+       int wid;
+       int ret;
 
        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_free(b);
-       app_group_remove(pid);
-       __real_send(clifd, 0);
+       ret = app_group_set_window(cr->pid, wid);
+       __send_result_to_client(clifd, ret);
 
-       return 0;
+       return ret;
 }
 
-static int __dispatch_app_group_get_window(int clifd, const app_pkt_t *pkt, struct ucred *cr)
+static int __dispatch_app_group_get_fg_flag(int clifd, const app_pkt_t *pkt, struct ucred *cr)
 {
        bundle *b;
        char *buf;
        int pid;
-       int wid;
+       int fg;
 
        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);
+       fg = app_group_get_fg_flag(pid);
+       __send_result_to_client(clifd, fg);
 
        return 0;
 }
 
-static int __dispatch_app_group_resume(int clifd, const app_pkt_t *pkt, struct ucred *cr)
+static int __dispatch_app_group_clear_top(int clifd, const app_pkt_t *pkt, struct ucred *cr)
 {
-       app_group_resume(cr->pid);
-       __real_send(clifd, 0);
+       app_group_clear_top(cr->pid);
+       __send_result_to_client(clifd, 0);
 
        return 0;
 }
 
-static int __dispatch_app_group_get_leader_pid(int clifd, const app_pkt_t *pkt, struct ucred *cr)
+static int __dispatch_app_group_get_leader_pid(int clifd,
+               const app_pkt_t *pkt, struct ucred *cr)
 {
        bundle *b;
        char *buf;
@@ -492,25 +491,46 @@ static int __dispatch_app_group_get_leader_pid(int clifd, const app_pkt_t *pkt,
        pid = atoi(buf);
        bundle_free(b);
        lpid = app_group_get_leader_pid(pid);
-       __real_send(clifd, lpid);
+       __send_result_to_client(clifd, lpid);
 
        return 0;
 }
 
-static int __dispatch_app_group_get_leader_pids(int clifd, const app_pkt_t *pkt, struct ucred *cr)
+static int __dispatch_app_group_get_leader_pids(int clifd,
+               const app_pkt_t *pkt, struct ucred *cr)
 {
        int cnt;
        int *pids;
-       int empty[1] = { 0 };
+       unsigned char empty[1] = { 0 };
 
        app_group_get_leader_pids(&cnt, &pids);
 
        if (pids == NULL || cnt == 0) {
-               __send_result_data(clifd, APP_GROUP_GET_LEADER_PIDS,
-                               (unsigned char *)empty, 0);
+               __send_result_data(clifd, APP_GROUP_GET_LEADER_PIDS, empty, 0);
        } else {
                __send_result_data(clifd, APP_GROUP_GET_LEADER_PIDS,
-                               (unsigned char *)pids, cnt * sizeof(int));
+                       (unsigned char *)pids, cnt * sizeof(int));
+       }
+       if (pids != NULL)
+               free(pids);
+
+       return 0;
+}
+
+static int __dispatch_app_group_get_idle_pids(int clifd,
+               const app_pkt_t *pkt, struct ucred *cr)
+{
+       int cnt;
+       int *pids;
+       unsigned char empty[1] = { 0 };
+
+       app_group_get_idle_pids(&cnt, &pids);
+
+       if (pids == NULL || cnt == 0) {
+               __send_result_data(clifd, APP_GROUP_GET_IDLE_PIDS, empty, 0);
+       } else {
+               __send_result_data(clifd, APP_GROUP_GET_IDLE_PIDS,
+                       (unsigned char *)pids, cnt * sizeof(int));
        }
        if (pids != NULL)
                free(pids);
@@ -525,7 +545,7 @@ static int __dispatch_app_group_get_group_pids(int clifd, const app_pkt_t *pkt,
        int leader_pid;
        int cnt;
        int *pids;
-       int empty[1] = { 0 };
+       unsigned char empty[1] = { 0 };
 
        b = bundle_decode(pkt->data, pkt->len);
        bundle_get_str(b, AUL_K_LEADER_PID, &buf);
@@ -534,11 +554,10 @@ static int __dispatch_app_group_get_group_pids(int clifd, const app_pkt_t *pkt,
 
        app_group_get_group_pids(leader_pid, &cnt, &pids);
        if (pids == NULL || cnt == 0) {
-               __send_result_data(clifd, APP_GROUP_GET_GROUP_PIDS,
-                               (unsigned char *)empty, 0);
+               __send_result_data(clifd, APP_GROUP_GET_GROUP_PIDS, empty, 0);
        } else {
                __send_result_data(clifd, APP_GROUP_GET_GROUP_PIDS,
-                               (unsigned char *)pids, cnt * sizeof(int));
+                       (unsigned char *)pids, cnt * sizeof(int));
        }
        if (pids != NULL)
                free(pids);
@@ -546,6 +565,16 @@ static int __dispatch_app_group_get_group_pids(int clifd, const app_pkt_t *pkt,
        return 0;
 }
 
+static int __dispatch_app_group_lower(int clifd, const app_pkt_t *pkt, struct ucred *cr)
+{
+       int ret = 0;
+
+       app_group_lower(cr->pid, &ret);
+       __send_result_to_client(clifd, ret);
+
+       return ret;
+}
+
 static int __dispatch_app_start(int clifd, const app_pkt_t *pkt, struct ucred *cr)
 {
        const char *appid;
@@ -956,13 +985,15 @@ static app_cmd_dispatch_func dispatch_table[APP_CMD_MAX] = {
        [APP_TERM_BGAPP_BY_PID] = __dispatch_app_term,
        [APP_PAUSE] = __dispatch_app_pause,
        [APP_PAUSE_BY_PID] = __dispatch_app_process_by_pid,
-       [APP_GROUP_ADD] = __dispatch_app_group_add,
-       [APP_GROUP_REMOVE] = __dispatch_app_group_remove,
        [APP_GROUP_GET_WINDOW] = __dispatch_app_group_get_window,
+       [APP_GROUP_SET_WINDOW] = __dispatch_app_group_set_window,
+       [APP_GROUP_GET_FG] = __dispatch_app_group_get_fg_flag,
+       [APP_GROUP_GET_LEADER_PID] = __dispatch_app_group_get_leader_pid,
        [APP_GROUP_GET_LEADER_PIDS] = __dispatch_app_group_get_leader_pids,
        [APP_GROUP_GET_GROUP_PIDS] = __dispatch_app_group_get_group_pids,
-       [APP_GROUP_RESUME] = __dispatch_app_group_resume,
-       [APP_GROUP_GET_LEADER_PID] = __dispatch_app_group_get_leader_pid,
+       [APP_GROUP_GET_IDLE_PIDS] = __dispatch_app_group_get_idle_pids,
+       [APP_GROUP_LOWER] = __dispatch_app_group_lower,
+       [APP_GROUP_CLEAR_TOP] = __dispatch_app_group_clear_top,
        [APP_GET_STATUS] = __dispatch_app_get_status,
        [AMD_RELOAD_APPINFO] = __dispatch_amd_reload_appinfo,
        [AGENT_DEAD_SIGNAL] = __dispatch_agent_dead_signal,
index 76dd2ec..ef2636b 100644 (file)
@@ -84,28 +84,17 @@ 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->uid == uid) || (info_t->uid == 0))) {
                        info_t->status = status;
-                       is_sub_app = false;
                        break;
                }
        }
 
-       for (iter = app_status_info_list; iter != NULL; iter = g_slist_next(iter))
-       {
-               info_t = (app_status_info_t *)iter->data;
-
-               //SECURE_LOGD("%s, %d, %d", info_t->appid, info_t->pid, info_t->status);
-       }
-
-       if (is_sub_app) {
-               app_group_set_status(pid, status);
-       }
+       app_group_set_status(pid, status, false);
 
        return 0;
 }
@@ -166,7 +155,7 @@ int _status_get_app_info_status(int pid, uid_t uid)
                }
        }
 
-       return -1;
+       return app_group_get_status(pid);
 }
 
 int _status_app_is_running(const char *appid, uid_t uid)
index b9c5411..d741363 100644 (file)
@@ -58,13 +58,15 @@ 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_SET_WINDOW,
+       APP_GROUP_GET_FG,
+       APP_GROUP_GET_LEADER_PID,
        APP_GROUP_GET_LEADER_PIDS,
        APP_GROUP_GET_GROUP_PIDS,
-       APP_GROUP_RESUME,
-       APP_GROUP_GET_LEADER_PID,
+       APP_GROUP_GET_IDLE_PIDS,
+       APP_GROUP_LOWER,
+       APP_GROUP_CLEAR_TOP,
        APP_GET_STATUS,
        APP_GET_SOCKET_PAIR,
 
index 4abb9f0..11836e0 100644 (file)
@@ -1788,6 +1788,16 @@ int aul_app_group_get_window(int pid);
 /*
  * This API is only for Appfw internally.
  */
+int aul_app_group_get_window(int pid);
+
+/*
+ * This API is only for Appfw internally.
+ */
+int aul_app_group_set_window(int wid);
+
+/*
+ * This API is only for Appfw internally.
+ */
 void aul_app_group_get_leader_pids(int *cnt, int **pids);
 
 /*
@@ -1813,6 +1823,21 @@ int aul_app_group_is_top(void);
 /*
  * This API is only for Appfw internally.
  */
+int aul_app_group_get_fg_flag(int pid);
+
+/*
+ * This API is only for Appfw internally.
+ */
+void aul_app_group_lower(int *exit);
+
+/*
+ * This API is only for Appfw internally.
+ */
+void aul_app_group_get_idle_pids(int *cnt, int **pids);
+
+/*
+ * This API is only for Appfw internally.
+ */
 int aul_request_data_control_socket_pair(bundle *b, int *fd);
 
 /*
index ca150e1..1531791 100644 (file)
@@ -41,6 +41,7 @@ BuildRequires:  pkgconfig(capi-system-info)
 BuildRequires:  pkgconfig(iniparser)
 BuildRequires:  pkgconfig(sqlite3)
 %if %{with wayland}
+BuildRequires:  pkgconfig(ecore-wayland)
 BuildRequires:  pkgconfig(wayland-client)
 BuildRequires:  pkgconfig(tizen-extension-client)
 %endif
@@ -133,6 +134,7 @@ systemctl daemon-reload
 %attr(0644,root,root) %{_libdir}/libaul.so.*
 %{_bindir}/aul_test
 %{_bindir}/app_launcher
+%{_bindir}/appgroup_info
 %{_datadir}/aul/miregex/*
 %{_datadir}/aul/preload_list.txt
 %{_datadir}/aul/preexec_list.txt
index 229e43a..7079ade 100644 (file)
+#define _GNU_SOURCE
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <limits.h>
-
-#include <bundle.h>
-
+#include <bundle_internal.h>
 #include "aul.h"
 #include "aul_api.h"
 #include "aul_util.h"
 #include "app_sock.h"
-#include "simple_util.h"
 #include "launch.h"
+#include "simple_util.h"
 
-#ifdef WAYLAND
-#include <wayland-client.h>
-#include <tizen-extension-client-protocol.h>
-static struct tizen_policy *tz_policy = 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_policy")) {
-               tz_policy = wl_registry_bind(reg, id,
-                               &tizen_policy_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)
-{
-       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);
-
-       app_send_cmd(AUL_UTIL_PID, APP_GROUP_ADD, b);
-       bundle_free(b);
-}
-
-SLPAPI void aul_app_group_remove(int pid)
+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);
-
-       app_send_cmd(AUL_UTIL_PID, APP_GROUP_REMOVE, b);
+       ret = app_send_cmd(AUL_UTIL_PID, APP_GROUP_GET_WINDOW, 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_policy) {
-               _E("ERR: no tizen_policy global interface");
-               wl_registry_destroy(reg);
-               wl_display_disconnect(dpy);
-               return;
-       }
-
-       tizen_policy_set_transient_for(tz_policy, child_wid, parent_wid);
-       wl_display_roundtrip(dpy);
-
-       tizen_policy_destroy(tz_policy);
-       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_policy) {
-               _E("ERR: no tz_policy global interface");
-               wl_registry_destroy(reg);
-               wl_display_disconnect(dpy);
-               return;
-       }
-
-       tizen_policy_unset_transient_for(tz_policy, child_wid);
-       wl_display_roundtrip(dpy);
-
-       tizen_policy_destroy(tz_policy);
-       wl_registry_destroy(reg);
-       wl_display_disconnect(dpy);
-#else
-       /* ecore_x_icccm_transient_for_unset(child_wid); */
-#endif
+       return ret;
 }
 
-SLPAPI int aul_app_group_get_window(int pid)
+SLPAPI int aul_app_group_set_window(int wid)
 {
        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);
+       snprintf(buf, 128, "%d", wid);
+       bundle_add_str(b, AUL_K_WID, buf);
+       ret = app_send_cmd(AUL_UTIL_PID, APP_GROUP_SET_WINDOW, b);
        bundle_free(b);
 
        return ret;
@@ -155,7 +52,7 @@ SLPAPI void aul_app_group_get_leader_pids(int *cnt, int **pids)
                        NULL, 0);
        if (ret != NULL) {
                *cnt = ret->len / sizeof(int);
-               if (ret->len > 0 && ret->len <= INT_MAX) {
+               if (ret->len > 0 && ret->len <= AUL_SOCK_MAXBUFF - 8) {
                        *pids = malloc(ret->len);
                        if (*pids == NULL) {
                                _E("out of memory");
@@ -226,8 +123,8 @@ SLPAPI int aul_app_group_get_leader_pid(int pid)
 
 SLPAPI int aul_app_group_clear_top(void)
 {
-       int dummy[1] = { 0 };
-       return  __app_send_raw(AUL_UTIL_PID, APP_GROUP_RESUME, (unsigned char *)dummy, 0);
+       unsigned char dummy[1] = { 0 };
+       return  __app_send_raw(AUL_UTIL_PID, APP_GROUP_CLEAR_TOP, dummy, 0);
 }
 
 SLPAPI int aul_app_group_is_top(void)
@@ -251,3 +148,51 @@ SLPAPI int aul_app_group_is_top(void)
 
        return 1;
 }
+
+SLPAPI int aul_app_group_get_fg_flag(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_FG, b);
+       bundle_free(b);
+
+       return ret;
+}
+
+SLPAPI void aul_app_group_lower(int *exit)
+{
+       int ret;
+       unsigned char dummy[1] = { 0 };
+       ret =  __app_send_raw(AUL_UTIL_PID, APP_GROUP_LOWER, dummy, 0);
+       *exit = ret;
+}
+
+SLPAPI void aul_app_group_get_idle_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_IDLE_PIDS,
+                       NULL, 0);
+       if (ret != NULL) {
+               *cnt = ret->len / sizeof(int);
+               if (ret->len > 0 && ret->len <= AUL_SOCK_MAXBUFF - 8) {
+                       *pids = malloc(ret->len);
+                       if (*pids == NULL) {
+                               _E("out of memory");
+                               free(ret);
+                               return;
+                       }
+
+                       memcpy(*pids, ret->data, ret->len);
+               }
+               free(ret);
+       }
+}
+
diff --git a/tool/app_group_info.c b/tool/app_group_info.c
new file mode 100644 (file)
index 0000000..833816c
--- /dev/null
@@ -0,0 +1,153 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "aul.h"
+
+static void print_app_status(int status);
+
+static void print_idle_info(void)
+{
+       int cnt = 0;
+       int *pids = NULL;
+       int i;
+       char appid_buf[1024] = {0,};
+       int ret;
+
+       aul_app_group_get_idle_pids(&cnt, &pids);
+       printf("< Idle : %d >\n", cnt);
+       if (pids) {
+               for (i = 0; i < cnt; ++i) {
+                       printf("---------------------------\n");
+                       printf("  pid : %d\n", pids[i]);
+                       ret = aul_app_get_appid_bypid(pids[i], appid_buf, sizeof(appid_buf) - 1);
+
+                       if (ret != AUL_R_OK) {
+                               appid_buf[0] = '\0';
+                       }
+                       printf("  appid : %s\n", appid_buf);
+               }
+
+               free(pids);
+       }
+}
+
+static int print_info(void)
+{
+       int *leader_pids = NULL;
+       int *member_pids = NULL;
+       int group_cnt = 0;
+       int member_cnt = 0;
+       int win_id = 0;
+       int group_num = 0;
+       int member_num = 0;
+       int app_status = -1;
+       int ret = 0;
+       char appid_buf[1024] = {0,};
+       char pkgid_buf[1024] = {0,};
+       int fg;
+
+       aul_app_group_get_leader_pids(&group_cnt, &leader_pids);
+       printf("App group count : %d\n", group_cnt);
+       printf("\n");
+
+       if(group_cnt == 0){
+               printf("No app groups\n");
+               goto FINISH;
+       }
+
+       for(group_num = 0; group_num < group_cnt; group_num++){
+               aul_app_group_get_group_pids(leader_pids[group_num], &member_cnt, &member_pids);
+
+               printf("< Group : %d >\n", group_num + 1);
+               printf("member cnt : %d\n", member_cnt);
+               printf("\n");
+
+               for(member_num = 0; member_num < member_cnt; member_num++){
+                       ret = aul_app_get_appid_bypid(member_pids[member_num], appid_buf, sizeof(appid_buf) - 1);
+
+                       if(ret != AUL_R_OK){
+                               appid_buf[0] = '\0';
+                       }
+
+                       ret = aul_app_get_pkgid_bypid(member_pids[member_num], pkgid_buf, sizeof(pkgid_buf) - 1);
+                       if(ret != AUL_R_OK){
+                               pkgid_buf[0] = '\0';
+                       }
+
+                       win_id = aul_app_group_get_window(member_pids[member_num]);
+                       fg = aul_app_group_get_fg_flag(member_pids[member_num]);
+
+                       printf("--- member   : %d\n", member_num + 1);
+                       printf("  - app id   : %s\n", appid_buf);
+                       printf("  - pkg id   : %s\n", pkgid_buf);
+                       printf("  - pid      : %d\n", member_pids[member_num]);
+                       printf("  - win id   : %d\n", win_id);
+                       if (fg)
+                               printf("  - fg group : TRUE\n");
+                       else
+                               printf("  - fg group : FALSE\n");
+
+                       app_status = aul_app_get_status_bypid(member_pids[member_num]);
+                       print_app_status(app_status);
+                       printf("\n");
+               }
+               printf("==================================\n");
+               printf("\n");
+       }
+
+FINISH:
+
+       if(leader_pids != NULL)
+               free(leader_pids);
+
+       if(leader_pids != NULL)
+               free(member_pids);
+
+       return 0;
+}
+
+static void print_app_status(int status)
+{
+       switch (status) {
+       case STATUS_LAUNCHING:
+               printf("  - status   : STATUS_LAUNCHING \n");
+               break;
+       case STATUS_CREATED:
+               printf("  - status   : STATUS_CREATED \n");
+               break;
+       case STATUS_FOCUS:
+               printf("  - status   : STATUS_FOCUS \n");
+               break;
+       case STATUS_VISIBLE:
+               printf("  - status   : STATUS_VISIBLE \n");
+               break;
+       case STATUS_BG:
+               printf("  - status   : STATUS_BG \n");
+               break;
+       case STATUS_DYING:
+               printf("  - status   : STATUS_DYING \n");
+               break;
+       case STATUS_HOME:
+               printf("  - status   : STATUS_HOME \n");
+               break;
+       case STATUS_NORESTART:
+               printf("  - status   : STATUS_NORESTART \n");
+               break;
+       default:
+               printf("  - status error or unknown status\n");
+               break;
+       };
+}
+
+int main(int argc, char** argv)
+{
+       printf("\n");
+       printf("### App Group Informantion ###\n");
+       printf("\n");
+
+       print_info();
+       print_idle_info();
+
+       printf("### end ###\n");
+
+       return 0;
+}