9 #include <bundle_internal.h>
12 #include "simple_util.h"
13 #include "amd_app_group.h"
14 #include "amd_launch.h"
15 #include "amd_request.h"
16 #include "amd_status.h"
17 #include "app_signal.h"
18 #include "amd_appinfo.h"
20 #define APP_SVC_K_LAUNCH_MODE "__APP_SVC_LAUNCH_MODE__"
22 static GHashTable *app_group_hash = NULL;
23 static int dead_pid = -1;
24 static int focused_leader_pid = -1;
25 static GList *recycle_bin = NULL;
27 extern struct appinfomgr *_laf;
28 extern char *home_appid;
30 typedef struct _app_group_context_t {
41 app_group_launch_mode launch_mode;
42 } app_group_context_t;
44 static void __attach_window(int parent_wid, int child_wid)
46 ecore_x_icccm_transient_for_set(child_wid, parent_wid);
49 static void __detach_window(int child_wid)
51 ecore_x_icccm_transient_for_unset(child_wid);
54 static gint __comp_pid(gconstpointer a, gconstpointer b)
56 app_group_context_t *ac1 = (app_group_context_t*) a;
58 return ac1->pid - (int)b;
61 static void __list_destroy_cb(gpointer data)
66 static gboolean __hash_table_cb(gpointer key, gpointer value,
69 int pid = (int) user_data;
70 GList *list = (GList*) value;
71 GList *itr = g_list_first(list);
74 app_group_context_t *ac = (app_group_context_t*) itr->data;
78 list = g_list_remove_link(list, itr);
79 if (g_list_length(list) == 0) {
80 g_list_free_full(list, __list_destroy_cb);
85 itr = g_list_next(itr);
91 static GList* __find_removable_apps(int from)
96 gboolean found = FALSE;
98 app_group_get_leader_pids(&cnt, &pids);
102 for (i = 0; i < cnt; i++) {
106 app_group_get_group_pids(pids[i], &gcnt, &gpids);
107 for (j = 0; j < gcnt; j++) {
108 if (gpids[j] == from) {
114 list = g_list_append(list, (gpointer) gpids[j]);
131 static void __prepare_to_suspend_services(int pid)
134 SECURE_LOGD("[__SUSPEND__] pid: %d", pid);
135 __app_send_raw_with_noreply(pid, APP_SUSPEND, (unsigned char *)&dummy, sizeof(int));
138 static void __prepare_to_wake_services(int pid)
141 SECURE_LOGD("[__SUSPEND__] pid: %d", pid);
142 __app_send_raw_with_noreply(pid, APP_WAKE, (unsigned char *)&dummy, sizeof(int));
145 static void __set_fg_flag(int cpid, int flag)
147 int lpid = app_group_get_leader_pid(cpid);
151 g_hash_table_iter_init(&iter, app_group_hash);
152 while (g_hash_table_iter_next(&iter, &key, &value)) {
153 GList *list = (GList*) value;
154 GList *i = g_list_first(list);
155 app_group_context_t *ac = (app_group_context_t*) i->data;
157 if (ac->pid == lpid) {
160 ac = (app_group_context_t*) i->data;
162 if (ac->fg != flag) {
163 const char *appid = NULL;
164 const char *pkgid = NULL;
165 const struct appinfo *ai = NULL;
167 appid = _status_app_get_appid_bypid(ac->pid);
168 ai = appinfo_find(_laf, appid);
169 pkgid = appinfo_get_value(ai, AIT_PKGID);
172 _D("send_signal FG %s", appid);
174 aul_send_app_status_change_signal(ac->pid, appid,
178 _status_find_service_apps(ac->pid, STATUS_VISIBLE, __prepare_to_wake_services);
180 _D("send_signal BG %s", appid);
181 aul_send_app_status_change_signal(ac->pid, appid,
185 _status_find_service_apps(ac->pid, STATUS_BG, __prepare_to_suspend_services);
196 static gboolean __is_visible(int cpid)
198 int lpid = app_group_get_leader_pid(cpid);
202 g_hash_table_iter_init(&iter, app_group_hash);
203 while (g_hash_table_iter_next(&iter, &key, &value)) {
204 GList *list = (GList*) value;
205 GList *i = g_list_first(list);
206 app_group_context_t *ac = (app_group_context_t*) i->data;
208 if (ac->pid == lpid) {
210 ac = (app_group_context_t*) i->data;
212 if (ac->status == STATUS_VISIBLE)
224 static gboolean __can_attach_window(bundle *b, const char *appid, app_group_launch_mode *launch_mode)
227 const char *mode = NULL;
228 const struct appinfo *ai = NULL;
230 ai = appinfo_find(_laf, appid);
231 mode = appinfo_get_value(ai, AIT_LAUNCH_MODE);
234 *launch_mode = APP_GROUP_LAUNCH_MODE_SINGLE;
235 else if (strcmp(mode, "caller") == 0)
236 *launch_mode = APP_GROUP_LAUNCH_MODE_CALLER;
237 else if (strcmp(mode, "single") == 0)
238 *launch_mode = APP_GROUP_LAUNCH_MODE_SINGLE;
239 else if (strcmp(mode, "group") == 0)
240 *launch_mode = APP_GROUP_LAUNCH_MODE_GROUP;
241 else if (strcmp(mode, "singleton") == 0)
242 *launch_mode = APP_GROUP_LAUNCH_MODE_SINGLETON;
244 switch (*launch_mode) {
245 case APP_GROUP_LAUNCH_MODE_CALLER:
246 case APP_GROUP_LAUNCH_MODE_SINGLETON:
247 _D("launch mode from db is caller or singleton");
249 bundle_get_str(b, APP_SVC_K_LAUNCH_MODE, &str);
250 if (str != NULL && strncmp(str, "group", 5) == 0) {
255 case APP_GROUP_LAUNCH_MODE_GROUP:
258 case APP_GROUP_LAUNCH_MODE_SINGLE:
265 static gboolean __can_be_leader(bundle *b)
269 bundle_get_str(b, AUL_SVC_K_CAN_BE_LEADER, &str);
271 if (str != NULL && strcmp(str, "true") == 0)
277 static int __get_previous_pid(int pid)
282 g_hash_table_iter_init(&iter, app_group_hash);
283 while (g_hash_table_iter_next(&iter, &key, &value)) {
284 GList *list = (GList*) value;
285 GList *i = g_list_first(list);
287 int previous_pid = -1;
289 app_group_context_t *ac = (app_group_context_t*) i->data;
291 if (ac->pid == pid) {
294 previous_pid = ac->pid;
302 static int __get_caller_pid(bundle *kb)
307 pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
311 pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
323 static app_group_context_t* __detach_context_from_recycle_bin(int pid)
325 GList *iter = recycle_bin;
328 app_group_context_t *ac = (app_group_context_t*) iter->data;
330 if (ac->pid == pid) {
331 recycle_bin = g_list_remove_link(recycle_bin, iter);
335 iter = g_list_next(iter);
342 static void __group_add(int leader_pid, int pid, int wid, app_group_launch_mode mode,
343 int caller_pid, int can_shift, int recycle)
345 app_group_context_t *ac = NULL;
347 if ((ac = __detach_context_from_recycle_bin(pid)) == NULL) {
348 ac = malloc(sizeof(app_group_context_t));
357 ac->can_be_leader = 0;
359 ac->launch_mode = mode;
360 ac->caller_pid = caller_pid;
361 ac->can_shift = can_shift;
362 ac->recycle = recycle;
365 if (leader_pid == pid || ac->recycle)
372 GList *list = (GList*) g_hash_table_lookup(app_group_hash,
373 GINT_TO_POINTER(leader_pid));
375 if (g_list_find_custom(list, (gconstpointer)pid, __comp_pid) != NULL) {
382 list = g_list_append(list, ac);
383 g_hash_table_insert(app_group_hash, GINT_TO_POINTER(leader_pid), list);
386 app_group_set_window(pid, ac->wid);
389 static void __group_remove(int pid)
391 int ppid = __get_previous_pid(pid);
392 g_hash_table_foreach_remove(app_group_hash, __hash_table_cb,
393 GINT_TO_POINTER(pid));
396 app_group_set_status(ppid, -1);
400 static app_group_context_t* __get_context(int pid)
405 g_hash_table_iter_init(&iter, app_group_hash);
406 while (g_hash_table_iter_next(&iter, &key, &value)) {
407 GList *list = (GList*) value;
408 GList *i = g_list_first(list);
411 app_group_context_t *ac = (app_group_context_t*) i->data;
413 if (ac->pid == pid) {
423 static int __can_recycle(int pid)
425 app_group_context_t *context = __get_context(pid);
428 return context->recycle;
433 static int __can_reroute(int pid)
435 app_group_context_t *context = __get_context(pid);
438 return context->reroute;
443 static app_group_context_t* __context_dup(const app_group_context_t *context)
445 app_group_context_t* dup;
448 _E("context is NULL.");
452 dup = malloc(sizeof(app_group_context_t));
458 memcpy(dup, context, sizeof(app_group_context_t));
462 static void __do_recycle(app_group_context_t *context)
465 const char *appid = NULL;
466 const char *pkgid = NULL;
467 const struct appinfo *ai = NULL;
469 appid = _status_app_get_appid_bypid(context->pid);
470 ai = appinfo_find(_laf, appid);
471 pkgid = appinfo_get_value(ai, AIT_PKGID);
473 _D("send_signal BG %s", appid);
474 aul_send_app_status_change_signal(context->pid, appid, pkgid,
477 _status_find_service_apps(context->pid, STATUS_BG, __prepare_to_suspend_services);
480 recycle_bin = g_list_append(recycle_bin, context);
481 _revoke_temporary_permission(context->pid);
484 void app_group_init()
486 app_group_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
490 void app_group_remove(int pid)
493 app_group_context_t *context = __detach_context_from_recycle_bin(pid);
499 void app_group_remove_from_recycle_bin(int pid)
501 app_group_context_t *context = __detach_context_from_recycle_bin(pid);
507 int app_group_get_window(int pid)
509 app_group_context_t *context = __get_context(pid);
517 int app_group_set_window(int pid, int wid)
522 g_hash_table_iter_init(&iter, app_group_hash);
523 while (g_hash_table_iter_next(&iter, &key, &value)) {
524 GList *list = (GList*) value;
525 GList *i = g_list_first(list);
527 int previous_wid = 0;
529 app_group_context_t *ac = (app_group_context_t*) i->data;
531 if (ac->pid == pid) {
533 if (previous_wid != 0)
534 __attach_window(previous_wid, wid);
536 if (ac->can_shift && ac->caller_pid > 0) {
537 int caller_wid = app_group_get_window(ac->caller_pid);
540 __attach_window(caller_wid, wid);
545 ac = (app_group_context_t*) i->data;
547 __attach_window(wid, ac->wid);
552 previous_wid = ac->wid;
560 void app_group_clear_top(int pid)
562 GList *list = __find_removable_apps(pid);
565 GList *itr = g_list_last(list);
567 while (itr != NULL) {
568 int p = (int)(itr->data);
573 itr = g_list_previous(itr);
579 gboolean app_group_is_group_app(bundle* kb)
585 const char *mode = NULL;
587 const struct appinfo *ai = NULL;
589 bundle_get_str(kb, AUL_K_PKG_NAME, &appid);
594 ai = appinfo_find(_laf, appid);
595 mode = appinfo_get_value(ai, AIT_LAUNCH_MODE);
597 if (mode != NULL && (strncmp(mode, "caller", 6) == 0 ||
598 strncmp(mode, "singleton", 9) == 0)) {
599 bundle_get_str(kb, APP_SVC_K_LAUNCH_MODE, &str);
601 if (str != NULL && strncmp(str, "group", 5) == 0) {
604 } else if (mode != NULL && strncmp(mode, "group", 5) == 0) {
611 void app_group_get_leader_pids(int *cnt, int **pids)
616 int size = g_hash_table_size(app_group_hash);
620 leader_pids = (int*) malloc(sizeof(int) * size);
621 if (leader_pids == NULL) {
628 g_hash_table_iter_init(&iter, app_group_hash);
630 while (g_hash_table_iter_next(&iter, &key, &value)) {
631 leader_pids[i] = (int) key;
643 gboolean app_group_is_leader_pid(int pid)
649 app_group_get_leader_pids(&cnt, &pids);
651 for (i=0; i<cnt; i++) {
652 if (pid == pids[i]) {
664 void app_group_get_group_pids(int leader_pid, int *cnt, int **pids)
669 g_hash_table_iter_init(&iter, app_group_hash);
670 while (g_hash_table_iter_next(&iter, &key, &value)) {
671 if ((int) key == leader_pid) {
672 GList *list = (GList*) value;
673 GList *i = g_list_first(list);
674 int size = g_list_length(list);
677 int *pid_array = (int*) malloc(sizeof(int) * size);
680 if (pid_array == NULL) {
688 app_group_context_t *ac = (app_group_context_t*) i->data;
690 pid_array[j] = ac->pid;
709 gboolean app_group_is_sub_app(int pid)
714 g_hash_table_iter_init(&iter, app_group_hash);
715 while (g_hash_table_iter_next(&iter, &key, &value)) {
716 GList *list = (GList*) value;
720 if ((found = g_list_find_custom(list, (gconstpointer)pid, __comp_pid)) != NULL) {
721 if (g_list_first(list) == found)
731 void app_group_reroute(int pid)
736 g_hash_table_iter_init(&iter, app_group_hash);
737 while (g_hash_table_iter_next(&iter, &key, &value)) {
738 GList *list = (GList*) value;
740 GList *before = NULL;
744 if ((found = g_list_find_custom(list, (gconstpointer)pid, __comp_pid)) != NULL) {
745 before = g_list_previous(found);
746 after = g_list_next(found);
748 if (before == NULL || after == NULL)
752 app_group_context_t *ac1 = (app_group_context_t*) before->data;
753 app_group_context_t *ac2 = (app_group_context_t*) after->data;
755 __detach_window(ac2->wid);
756 __attach_window(ac1->wid, ac2->wid);
763 int app_group_get_leader_pid(int pid)
771 g_hash_table_iter_init(&iter, app_group_hash);
772 while (g_hash_table_iter_next(&iter, &key, &value)) {
773 GList *list = (GList*) value;
776 if (g_list_find_custom(list, (gconstpointer)pid, __comp_pid) != NULL) {
783 if (lpid == -1 && dead_pid == pid)
784 lpid = focused_leader_pid;
786 if (lpid == -1 && again == 0) {
795 void app_group_set_dead_pid(int pid)
797 focused_leader_pid = app_group_get_leader_pid(pid);
800 if (dead_pid == focused_leader_pid) {
801 focused_leader_pid = -1;
806 int app_group_get_status(int pid)
811 g_hash_table_iter_init(&iter, app_group_hash);
812 while (g_hash_table_iter_next(&iter, &key, &value)) {
813 GList *list = (GList*) value;
814 GList *i = g_list_first(list);
817 app_group_context_t *ac = (app_group_context_t*) i->data;
828 int app_group_set_status(int pid, int status)
833 g_hash_table_iter_init(&iter, app_group_hash);
834 while (g_hash_table_iter_next(&iter, &key, &value)) {
835 GList *list = (GList*) value;
836 GList *i = g_list_first(list);
839 app_group_context_t *ac = (app_group_context_t*) i->data;
841 if (ac->pid == pid) {
844 GList *last = g_list_last(list);
845 app_group_context_t *last_ac = (app_group_context_t*) last->data;
847 if (last_ac->wid != 0 || status == STATUS_VISIBLE) {
848 if (__is_visible(pid)) {
849 __set_fg_flag(pid, 1);
850 if (!ac->group_sig && (int)key != pid) {
852 const char *pkgid = NULL;
853 const struct appinfo *ai = NULL;
855 appid = _status_app_get_appid_bypid(pid);
856 ai = appinfo_find(_laf, appid);
857 pkgid = appinfo_get_value(ai, AIT_PKGID);
859 _D("send group signal %d", pid);
860 aul_send_app_group_signal((int)key, pid, pkgid);
864 __set_fg_flag(pid, 0);
874 int app_group_get_fg_flag(int pid)
879 g_hash_table_iter_init(&iter, app_group_hash);
880 while (g_hash_table_iter_next(&iter, &key, &value)) {
881 GList *list = (GList*) value;
882 GList *i = g_list_first(list);
885 app_group_context_t *ac = (app_group_context_t*) i->data;
887 if (ac->pid == pid) {
897 int app_group_set_hint(int pid, bundle *kb)
899 char *str_leader = NULL;
900 char *str_reroute = NULL;
905 bundle_get_str(kb, AUL_SVC_K_CAN_BE_LEADER, &str_leader);
906 bundle_get_str(kb, AUL_SVC_K_REROUTE, &str_reroute);
911 g_hash_table_iter_init(&iter, app_group_hash);
912 while (g_hash_table_iter_next(&iter, &key, &value)) {
913 GList *list = (GList*) value;
914 GList *i = g_list_first(list);
917 app_group_context_t *ac = (app_group_context_t*) i->data;
919 if (ac->pid == pid) {
920 if (str_leader != NULL && strcmp(str_leader, "true") == 0)
921 ac->can_be_leader = 1;
922 if (str_reroute != NULL && strcmp(str_reroute, "true") == 0)
933 int app_group_find_second_leader(int lpid)
935 GList *list = (GList*) g_hash_table_lookup(app_group_hash,
936 GINT_TO_POINTER(lpid));
938 list = g_list_next(list);
941 app_group_context_t *ac = (app_group_context_t*) list->data;
942 if (ac->can_be_leader) {
951 void app_group_remove_leader_pid(int lpid)
953 GList *list = (GList*)g_hash_table_lookup(app_group_hash,
954 GINT_TO_POINTER(lpid));
957 GList *next = g_list_next(list);
960 app_group_context_t *ac = (app_group_context_t*) list->data;
962 list = g_list_remove_link(list, list);
964 ac = (app_group_context_t*) next->data;
965 g_hash_table_insert(app_group_hash, GINT_TO_POINTER(ac->pid), next);
966 g_hash_table_remove(app_group_hash, GINT_TO_POINTER(lpid));
971 int app_group_can_start_app(const char *appid, bundle *b, gboolean *can_attach,
972 int *lpid, app_group_launch_mode *mode)
974 const char *val = NULL;
979 if (__can_attach_window(b, appid, mode)) {
982 val = bundle_get_val(b, AUL_K_ORG_CALLER_PID);
984 val = bundle_get_val(b, AUL_K_CALLER_PID);
992 caller_pid = atoi(val);
993 #ifdef _APPFW_FEATURE_SEND_HOME_LAUNCH_SIGNAL
994 if (home_appid != NULL) {
995 char *caller_appid = _status_app_get_appid_bypid(caller_pid);
997 if (caller_appid != NULL && strcmp(caller_appid, home_appid) == 0) {
998 _E("can't be attached to home app");
1004 *lpid = app_group_get_leader_pid(caller_pid);
1006 caller_wid = app_group_get_window(caller_pid);
1008 if (caller_wid == 0) {
1009 _E("caller window wasn't ready");
1010 if (__can_be_leader(b))
1011 *can_attach = FALSE;
1018 if (__can_be_leader(b))
1019 *can_attach = FALSE;
1028 void app_group_start_app(int pid, bundle *b, int lpid, gboolean can_attach,
1029 app_group_launch_mode mode)
1031 _E("app_group_start_app");
1033 int caller_pid = __get_caller_pid(b);
1038 str = bundle_get_val(b, AUL_SVC_K_SHIFT_WINDOW);
1039 if (str != NULL && strcmp(str, "true") == 0)
1042 str = bundle_get_val(b, AUL_SVC_K_RECYCLE);
1043 if (str != NULL && strcmp(str, "true") == 0)
1047 __group_add(lpid, pid, 0, mode, caller_pid, 0, recycle);
1049 __group_add(pid, pid, 0, mode, caller_pid, can_shift, 0);
1050 app_group_set_hint(pid, b);
1053 int app_group_find_singleton(const char *appid, int *found_pid, int *found_lpid)
1055 GHashTableIter iter;
1056 gpointer key = NULL;
1057 gpointer value = NULL;
1058 char *target = NULL;
1060 g_hash_table_iter_init(&iter, app_group_hash);
1061 while (g_hash_table_iter_next(&iter, &key, &value)) {
1062 GList *list = (GList*) value;
1064 while (list != NULL) {
1065 app_group_context_t *ac = (app_group_context_t*) list->data;
1067 if (ac->launch_mode == APP_GROUP_LAUNCH_MODE_SINGLETON) {
1068 target = _status_app_get_appid_bypid(ac->pid);
1070 if (appid != NULL && target != NULL && strcmp(appid, target) == 0) {
1071 *found_pid = ac->pid;
1072 *found_lpid = (int)key;
1076 list = g_list_next(list);
1083 int app_group_can_reroute(int pid)
1085 GHashTableIter iter;
1086 gpointer key, value;
1088 g_hash_table_iter_init(&iter, app_group_hash);
1089 while (g_hash_table_iter_next(&iter, &key, &value)) {
1090 GList *list = (GList*) value;
1091 GList *i = g_list_first(list);
1094 app_group_context_t *ac = (app_group_context_t*) i->data;
1096 if (ac->pid == pid) {
1106 void app_group_lower(int pid, int *exit)
1108 if (app_group_is_sub_app(pid)) {
1109 if (__can_recycle(pid) && __can_reroute(pid)) {
1110 app_group_context_t *ac = __get_context(pid);
1113 __detach_window(ac->wid);
1114 app_group_reroute(pid);
1115 ac = __context_dup(ac);
1116 __group_remove(pid);
1128 GHashTableIter iter;
1129 gpointer key, value;
1132 g_hash_table_iter_init(&iter, app_group_hash);
1133 while (g_hash_table_iter_next(&iter, &key, &value)) {
1134 GList *list = (GList*) value;
1135 GList *i = g_list_first(list);
1138 app_group_context_t *ac = (app_group_context_t*) i->data;
1140 if (ac->pid == pid) {
1141 if (ac->can_shift) {
1142 __detach_window(ac->wid);
1144 ecore_x_window_lower(ac->wid);
1153 void app_group_restart_app(int pid, bundle *b)
1158 GHashTableIter iter;
1159 gpointer key, value;
1161 g_hash_table_iter_init(&iter, app_group_hash);
1162 while (g_hash_table_iter_next(&iter, &key, &value)) {
1163 GList *list = (GList*) value;
1164 GList *i = g_list_first(list);
1167 app_group_context_t *ac = (app_group_context_t*) i->data;
1169 if (ac->pid == pid) {
1170 const char *pid_str;
1171 ac->caller_pid = __get_caller_pid(b);
1173 if (ac->can_shift) {
1175 __detach_window(ac->wid);
1179 pid_str = bundle_get_val(b, AUL_SVC_K_SHIFT_WINDOW);
1180 if (pid_str != NULL && strcmp(pid_str, "true") == 0) {
1183 if (ac->caller_pid > 0) {
1184 int cwid = app_group_get_window(ac->caller_pid);
1187 __attach_window(cwid, ac->wid);
1189 _E("invalid caller wid");
1192 _E("invalid caller pid");
1204 int app_group_find_pid_from_recycle_bin(const char *appid)
1206 GList *iter = recycle_bin;
1209 app_group_context_t *ac = (app_group_context_t*) iter->data;
1210 const char *appid_from_bin = _status_app_get_appid_bypid(ac->pid);
1212 if (appid && appid_from_bin && strcmp(appid, appid_from_bin) == 0) {
1216 iter = g_list_next(iter);
1222 void app_group_get_idle_pids(int *cnt, int **pids)
1224 GList *iter = recycle_bin;
1225 int idle_cnt = g_list_length(iter);
1227 if (idle_cnt <= 0) {
1233 int *idle_pids = NULL;
1235 idle_pids = malloc(sizeof(int) * idle_cnt);
1236 if (idle_pids == NULL) {
1237 _E("Out-of-memory");
1245 app_group_context_t *ac = (app_group_context_t*) iter->data;
1246 idle_pids[i] = ac->pid;
1247 iter = g_list_next(iter);