Let amd wait application's launching using inotify 71/53571/20 accepted/tizen/mobile/20151214.233910 accepted/tizen/tv/20151214.233931 accepted/tizen/wearable/20151214.233950 submit/tizen/20151214.102546
authorSangyoon Jang <s89.jang@samsung.com>
Tue, 8 Dec 2015 02:47:36 +0000 (11:47 +0900)
committerSangyoon Jang <s89.jang@samsung.com>
Mon, 14 Dec 2015 08:58:35 +0000 (17:58 +0900)
amd should not use busy waiting.
amd now monitors socket creation and returns result to caller when socket
is created.
if somebody request app_control to launching app, it will be pended
until the app launched(socket created).

Change-Id: I708cd6db27bc7e751e552be5507cda7c419d08e5
Signed-off-by: Sangyoon Jang <s89.jang@samsung.com>
am_daemon/amd_launch.c
am_daemon/amd_launch.h
am_daemon/amd_main.c
am_daemon/amd_request.c
am_daemon/amd_request.h
am_daemon/amd_status.c
am_daemon/amd_status.h
packaging/aul.spec

index 4ceebac..01811d4 100644 (file)
@@ -19,6 +19,7 @@
  *
  */
 
+#include <stdbool.h>
 #include <signal.h>
 #include <bundle.h>
 #include <aul.h>
@@ -92,9 +93,11 @@ static void __set_stime(bundle *kb)
 
 int _start_app_local_with_bundle(uid_t uid, const char *appid, bundle *kb)
 {
+       bool dummy;
+
        __set_stime(kb);
        bundle_add(kb, AUL_K_APPID, appid);
-       return  _start_app(appid, kb, APP_START, getpid(), uid, -1);
+       return  _start_app(appid, kb, APP_START, getpid(), uid, -1, &dummy);
 }
 
 int _start_app_local(uid_t uid, const char *appid)
@@ -719,7 +722,7 @@ int _get_pid_of_last_launched_ui_app()
 }
 
 int _start_app(const char* appid, bundle* kb, int cmd, int caller_pid,
-               uid_t caller_uid, int fd)
+               uid_t caller_uid, int fd, bool *pending)
 {
        int ret;
        const struct appinfo *ai;
@@ -736,7 +739,6 @@ int _start_app(const char* appid, bundle* kb, int cmd, int caller_pid,
        char tmpbuf[MAX_PID_STR_BUFSZ];
        const char *hwacc;
        char *caller_appid;
-       int delay_reply = 0;
        int lpid;
        int callee_status = -1;
        gboolean can_attach = FALSE;
@@ -824,12 +826,13 @@ int _start_app(const char* appid, bundle* kb, int cmd, int caller_pid,
                if (caller_pid == pid) {
                        SECURE_LOGD("caller process & callee process is same.[%s:%d]", appid, pid);
                        pid = -ELOCALLAUNCH_ID;
+                       __real_send(fd, pid);
                } else {
                        aul_send_app_resume_request_signal(pid, appid, pkg_id, component_type);
-                       if ((ret = __nofork_processing(cmd, pid, kb, fd)) < 0)
+                       if ((ret = __nofork_processing(cmd, pid, kb, fd)) < 0) {
                                pid = ret;
-                       else
-                               delay_reply = 1;
+                               __real_send(fd, pid);
+                       }
                }
        } else {
                if (callee_status == STATUS_DYING && pid > 0) {
@@ -850,8 +853,10 @@ int _start_app(const char* appid, bundle* kb, int cmd, int caller_pid,
                        pad_type = DEBUG_LAUNCHPAD_SOCK;
 
                pid = app_agent_send_cmd(caller_uid, pad_type, PAD_CMD_LAUNCH, kb);
-               if (pid > 0)
+               if (pid > 0) {
+                       *pending = true;
                        aul_send_app_launch_request_signal(pid, appid, pkg_id, component_type);
+               }
        }
 
        if (pid > 0) {
@@ -867,8 +872,5 @@ int _start_app(const char* appid, bundle* kb, int cmd, int caller_pid,
                }
        }
 
-       if (!delay_reply)
-               __real_send(fd, pid);
-
        return pid;
 }
index 5c57d20..adfb375 100644 (file)
@@ -22,6 +22,8 @@
 #ifndef __AUL_AMD_LAUNCH_H_
 #define __AUL_AMD_LAUNCH_H_
 
+#include <stdbool.h>
+
 #include <bundle.h>
 #include "aul_util.h"
 #include "amd_appinfo.h"
@@ -34,7 +36,7 @@ int _term_req_app(int pid, int clifd);
 int _term_bgapp(int pid, int clifd);
 int _term_sub_app(int pid);
 int _fake_launch_app(int cmd, int pid, bundle * kb, int clifd);
-int _start_app(const char* appid, bundle* kb, int cmd, int caller_pid, uid_t caller_uid, int fd);
+int _start_app(const char* appid, bundle* kb, int cmd, int caller_pid, uid_t caller_uid, int fd, bool *pend);
 int _start_app_local(uid_t uid, const char *appid);
 int _start_app_local_with_bundle(uid_t uid, const char *appid, bundle *kb);
 int _get_pid_of_last_launched_ui_app();
index 4942226..4552ad9 100644 (file)
@@ -370,6 +370,7 @@ static int __app_dead_handler(int pid, void *data)
 
        __remove_item_running_list(pid, getuid());
        _status_remove_app_info_list(pid, getuid());
+       _request_flush_pending_request(pid);
        aul_send_app_terminated_signal(pid);
 
        if (restart)
@@ -477,6 +478,7 @@ static int __init(void)
 
        restart_tbl = g_hash_table_new(g_str_hash, g_str_equal);
        _request_init();
+       _status_init();
        app_group_init();
 
        if (vconf_notify_key_changed(VCONFKEY_SETAPPL_DEVOPTION_BGPROCESS,
index 6f01671..4cb86b5 100644 (file)
@@ -24,6 +24,7 @@
 #include <dirent.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <string.h>
 #include <dlfcn.h>
 #include <poll.h>
 #define PRIVILEGE_APPMANAGER_KILL_BGAPP "http://tizen.org/privilege/appmanager.kill.bgapp"
 
 #define MAX_NR_OF_DESCRIPTORS 2
+#define PENDING_REQUEST_TIMEOUT 5000 /* msec */
+
 static GHashTable *__socket_pair_hash = NULL;
+static GHashTable *pending_table;
+
+struct pending_item {
+       int clifd;
+       int pid;
+       guint timer;
+       GList *pending_list;
+};
+
+struct request {
+       int clifd;
+       app_pkt_t *pkt;
+       struct ucred cr;
+};
 
 typedef int (*app_cmd_dispatch_func)(int clifd, const app_pkt_t *pkt, struct ucred *cr);
 
 
 static int __send_result_to_client(int fd, int res);
 static gboolean __request_handler(gpointer data);
+static gboolean __timeout_pending_item(gpointer user_data);
 
 static int __send_message(int sock, const struct iovec *vec, int vec_size, const int *desc, int nr_desc)
 {
@@ -642,6 +660,8 @@ static int __dispatch_app_start(int clifd, const app_pkt_t *pkt, struct ucred *c
        char *stat_caller = NULL;
        char *stat_tag = NULL;
        rua_stat_pkt_t *rua_stat_item = NULL;
+       bool pending = false;
+       struct pending_item *pending_item;
 
        kb = bundle_decode(pkt->data, pkt->len);
        if (kb == NULL) {
@@ -658,7 +678,7 @@ static int __dispatch_app_start(int clifd, const app_pkt_t *pkt, struct ucred *c
                        if (strcmp(state, "offline") &&
                            strcmp(state, "closing")) {
                                ret = _start_app(appid, kb, pkt->cmd, cr->pid,
-                                               t_uid, clifd);
+                                               t_uid, clifd, &pending);
                        } else {
                                _E("uid:%d session is %s", t_uid, state);
                                __real_send(clifd, AUL_R_ERROR);
@@ -667,11 +687,24 @@ static int __dispatch_app_start(int clifd, const app_pkt_t *pkt, struct ucred *c
                } else {
                        _E("request from root, treat as global user");
                        ret = _start_app(appid, kb, pkt->cmd, cr->pid,
-                                       GLOBAL_USER, clifd);
+                                       GLOBAL_USER, clifd, &pending);
                }
        } else {
-               ret = _start_app(appid, kb, pkt->cmd, cr->pid, cr->uid, clifd);
+               ret = _start_app(appid, kb, pkt->cmd, cr->pid, cr->uid, clifd,
+                               &pending);
        }
+
+       /* add pending list to wait app launched successfully */
+       if (pending) {
+               pending_item = calloc(1, sizeof(struct pending_item));
+               pending_item->clifd = clifd;
+               pending_item->pid = ret;
+               pending_item->timer = g_timeout_add(PENDING_REQUEST_TIMEOUT,
+                               __timeout_pending_item, (gpointer)pending_item);
+               g_hash_table_insert(pending_table, GINT_TO_POINTER(ret),
+                               pending_item);
+       }
+
        if (ret > 0) {
                item = calloc(1, sizeof(item_pkt_t));
                if (item == NULL) {
@@ -1062,6 +1095,178 @@ static app_cmd_dispatch_func dispatch_table[APP_CMD_MAX] = {
        [AGENT_DEAD_SIGNAL] = __dispatch_agent_dead_signal,
 };
 
+static void __free_request(gpointer data)
+{
+       struct request *req = (struct request *)data;
+
+       free(req->pkt);
+       free(req);
+}
+
+static void __free_pending_item(struct pending_item *item)
+{
+       g_list_free_full(item->pending_list, __free_request);
+       if (g_main_context_find_source_by_user_data(NULL, item))
+               g_source_remove(item->timer);
+       free(item);
+}
+
+static void __process_pending_request(gpointer data, gpointer user_data)
+{
+       struct request *req = (struct request *)data;
+
+       dispatch_table[req->pkt->cmd](req->clifd, req->pkt, &req->cr);
+}
+
+static void __timeout_pending_request(gpointer data, gpointer user_data)
+{
+       struct request *req = (struct request *)data;
+
+       __send_result_to_client(req->clifd, -1);
+}
+
+static gboolean __timeout_pending_item(gpointer user_data)
+{
+       struct pending_item *item = (struct pending_item *)user_data;
+
+       __send_result_to_client(item->clifd, item->pid);
+       g_list_foreach(item->pending_list, __timeout_pending_request, NULL);
+
+       g_hash_table_remove(pending_table, GINT_TO_POINTER(item->pid));
+       __free_pending_item(item);
+
+       return FALSE;
+}
+
+int _request_flush_pending_request(int pid)
+{
+       struct pending_item *item;
+
+       item = (struct pending_item *)g_hash_table_lookup(
+                       pending_table, GINT_TO_POINTER(pid));
+       if (item == NULL)
+               return -1;
+
+       __timeout_pending_item((gpointer)item);
+
+       return 0;
+}
+
+int _request_reply_for_pending_request(int pid)
+{
+       struct pending_item *item;
+
+       item = (struct pending_item *)g_hash_table_lookup(
+                       pending_table, GINT_TO_POINTER(pid));
+       if (item == NULL)
+               return -1;
+
+       __send_result_to_client(item->clifd, pid);
+       g_hash_table_remove(pending_table, GINT_TO_POINTER(pid));
+       g_list_foreach(item->pending_list, __process_pending_request, NULL);
+
+       __free_pending_item(item);
+
+       return 0;
+}
+
+static struct request *__get_request(int clifd, app_pkt_t *pkt,
+               struct ucred cr)
+{
+       struct request *req;
+
+       req = malloc(sizeof(struct request));
+       if (req == NULL)
+               return NULL;
+
+       req->clifd = clifd;
+       req->pkt = calloc(1, AUL_PKT_HEADER_SIZE + pkt->len + 1);
+       memcpy(req->pkt, pkt, AUL_PKT_HEADER_SIZE + pkt->len + 1);
+       memcpy(&req->cr, &cr, sizeof(struct ucred));
+
+       return req;
+}
+
+static int __check_app_is_running(struct request *req)
+{
+       bundle *b;
+       char *str;
+       int pid;
+       int ret = 0;
+
+       b = bundle_decode(req->pkt->data, req->pkt->len);
+       if (b == NULL)
+               return -1;
+
+       if (bundle_get_str(b, AUL_K_APPID, &str)) {
+               _E("cannot get target pid");
+               bundle_free(b);
+               return -1;
+       }
+
+       switch (req->pkt->cmd) {
+       case APP_RESUME_BY_PID:
+       case APP_TERM_BY_PID:
+       case APP_TERM_BY_PID_WITHOUT_RESTART:
+       case APP_KILL_BY_PID:
+       case APP_TERM_REQ_BY_PID:
+       case APP_TERM_BY_PID_ASYNC:
+       case APP_TERM_BGAPP_BY_PID:
+       case APP_PAUSE_BY_PID:
+               /* get pid */
+               pid = atoi(str);
+               if (_status_app_get_appid_bypid(pid))
+                       ret = pid;
+               break;
+       default:
+               pid = _status_app_is_running(str, req->cr.uid);
+               if (pid > 0)
+                       ret = pid;
+       }
+
+       bundle_free(b);
+
+       return ret;
+}
+
+static int __check_request(struct request *req)
+{
+       int pid;
+       struct pending_item *item;
+
+       /* TODO: categorize commands */
+       if (req->pkt->cmd != APP_START && req->pkt->cmd != APP_OPEN &&
+                       req->pkt->cmd != APP_RESUME &&
+                       req->pkt->cmd != APP_RESUME_BY_PID &&
+                       req->pkt->cmd != APP_TERM_BY_PID &&
+                       req->pkt->cmd != APP_TERM_BY_PID_WITHOUT_RESTART &&
+                       req->pkt->cmd != APP_START_RES &&
+                       req->pkt->cmd != APP_KILL_BY_PID &&
+                       req->pkt->cmd != APP_TERM_REQ_BY_PID &&
+                       req->pkt->cmd != APP_TERM_BY_PID_ASYNC &&
+                       req->pkt->cmd != APP_TERM_BGAPP_BY_PID &&
+                       req->pkt->cmd != APP_PAUSE &&
+                       req->pkt->cmd != APP_PAUSE_BY_PID)
+               return 0;
+
+       pid = __check_app_is_running(req);
+       if (pid < 0)
+               return -1;
+       else if (pid == 0)
+               return 0;
+
+       if (_status_get_app_info_status(pid, req->cr.uid) == STATUS_DYING)
+               return 0;
+
+       item = g_hash_table_lookup(pending_table, GINT_TO_POINTER(pid));
+       if (item == NULL)
+               return 0;
+
+       item->pending_list = g_list_append(item->pending_list, req);
+
+       return 1;
+}
+
 static gboolean __request_handler(gpointer data)
 {
        GPollFD *gpollfd = (GPollFD *) data;
@@ -1071,12 +1276,20 @@ static gboolean __request_handler(gpointer data)
        int clifd;
        struct ucred cr;
        const char *privilege;
+       struct request *req;
 
        if ((pkt = __app_recv_raw(fd, &clifd, &cr)) == NULL) {
                _E("recv error");
                return FALSE;
        }
 
+       req = __get_request(clifd, pkt, cr);
+       if (req == NULL) {
+               close(clifd);
+               free(pkt);
+               return TRUE;
+       }
+
        if (cr.uid >= REGULAR_UID_MIN) {
                privilege = __convert_cmd_to_privilege(pkt->cmd);
                if (privilege) {
@@ -1085,12 +1298,24 @@ static gboolean __request_handler(gpointer data)
                                _E("request has been denied by smack");
                                ret = -EILLEGALACCESS;
                                __real_send(clifd, ret);
+                               __free_request(req);
                                free(pkt);
                                return TRUE;
                        }
                }
        }
 
+       ret = __check_request(req);
+       if (ret < 0) {
+               __real_send(clifd, ret);
+               __free_request(req);
+               free(pkt);
+               return TRUE;
+       } else if (ret > 0) {
+               free(pkt);
+               return TRUE;
+       }
+
        if (pkt->cmd >= 0 && pkt->cmd < APP_CMD_MAX && dispatch_table[pkt->cmd]) {
                if (dispatch_table[pkt->cmd](clifd, pkt, &cr) != 0)
                        _E("callback returns FALSE : %d", pkt->cmd);
@@ -1098,6 +1323,7 @@ static gboolean __request_handler(gpointer data)
                _E("Invalid packet or not supported command");
                close(clifd);
        }
+       __free_request(req);
        free(pkt);
 
        return TRUE;
@@ -1146,6 +1372,7 @@ int _request_init(void)
        GSource *src;
 
        __socket_pair_hash = g_hash_table_new_full(g_str_hash,  g_str_equal, free, free);
+       pending_table = g_hash_table_new(g_direct_hash, g_direct_equal);
 
        fd = __create_sock_activation();
        if (fd == -1) {
index db963fe..a915986 100644 (file)
@@ -24,6 +24,8 @@
 #define __AUL_AMD_REQUEST_H_
 
 int _request_init(void);
+int _request_reply_for_pending_request(int pid);
+int _request_flush_pending_request(int pid);
 
 #endif
 
index ddea373..9a8a415 100644 (file)
 #include <glib.h>
 #include <aul.h>
 #include <string.h>
+#include <linux/limits.h>
+
+#include <gio/gio.h>
 
 #include "amd_config.h"
 #include "amd_status.h"
 #include "amd_appinfo.h"
+#include "amd_request.h"
 #include "aul_util.h"
 #include "simple_util.h"
 #include "app_sock.h"
@@ -460,3 +464,49 @@ int _status_get_pkgid_bypid(int fd, int pid)
 
        return 0;
 }
+
+static void __socket_monitor_cb(GFileMonitor *monitor, GFile *file,
+               GFile *other_file, GFileMonitorEvent event_type,
+               gpointer user_data)
+{
+       char *path;
+       char *p;
+       int pid;
+
+       if (event_type != G_FILE_MONITOR_EVENT_CREATED)
+               return;
+
+       path = g_file_get_path(file);
+       p = strrchr(path, '/');
+       pid = atoi(p + 1);
+
+       if (pid < 1)
+               return;
+
+       _request_reply_for_pending_request(pid);
+
+       g_free(path);
+}
+
+int _status_init(void)
+{
+       char buf[PATH_MAX];
+       GFile *file;
+       GFileMonitor *monitor;
+       GError *err = NULL;
+
+       snprintf(buf, sizeof(buf), "/run/user/%d", getuid());
+       file = g_file_new_for_path(buf);
+       if (file == NULL)
+               return -1;
+
+       monitor = g_file_monitor_directory(file, G_FILE_MONITOR_NONE,
+                       NULL, &err);
+       if (monitor == NULL)
+               return -1;
+
+       g_signal_connect(monitor, "changed", G_CALLBACK(__socket_monitor_cb),
+                       NULL);
+
+       return 0;
+}
index ac1996c..a7bd581 100644 (file)
@@ -35,7 +35,7 @@ char *_status_app_get_appid_bypid(int pid);
 int _status_send_running_appinfo_v2(int fd); //depcrecated
 int _status_get_appid_bypid(int fd, int pid);
 int _status_get_pkgid_bypid(int fd, int pid);
-
+int _status_init(void);
 
 
 //TODO : remove
index 4f39cde..3ad3a80 100644 (file)
@@ -22,6 +22,8 @@ Requires:   tizen-platform-config
 
 BuildRequires:  cmake
 BuildRequires:  pkgconfig(dbus-glib-1)
+BuildRequires:  pkgconfig(glib-2.0)
+BuildRequires:  pkgconfig(gio-2.0)
 BuildRequires:  pkgconfig(bundle)
 BuildRequires:  pkgconfig(dlog)
 BuildRequires:  xdgmime-devel, pkgconfig(xdgmime)