Fix aul app socket handler 35/265335/13
authorHwankyu Jhun <h.jhun@samsung.com>
Fri, 15 Oct 2021 05:49:13 +0000 (14:49 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Wed, 3 Nov 2021 03:27:54 +0000 (12:27 +0900)
After handling requests, AUL doesn't close the socket connection.
AMD monitors the socket connection. When the connection is closed,
AMD removes the status information of the application. This is a
fallback of the zombie process of the application.

Requires:
 - https://review.tizen.org/gerrit/#/c/platform/core/appfw/aul-1/+/265335/
 - https://review.tizen.org/gerrit/#/c/platform/core/appfw/amd/+/265818/
 - https://review.tizen.org/gerrit/#/c/platform/core/appfw/launchpad/+/265825/

Change-Id: Ia2b7e8ddaa2ced39862cb0fc085be1b08ff78d49
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
include/aul_cmd.h
include/aul_sock.h
src/aul_cmd.c
src/aul_launch.c
src/aul_sock.c
src/aul_worker.c
src/aul_worker.h

index a654f43..793db1c 100644 (file)
@@ -213,6 +213,8 @@ enum app_cmd {
        PROC_GROUP_ADD = 169,
        PROC_GROUP_REMOVE = 170,
 
+       APP_CONNECT = 171,
+
        APP_CMD_MAX
 };
 
index 34235c4..5dc8e89 100644 (file)
@@ -23,6 +23,7 @@
 #include <unistd.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <stdbool.h>
 #include <bundle.h>
 
 #include <aul_cmd.h>
@@ -132,6 +133,16 @@ int aul_sock_destroy_server(int fd);
  */
 int aul_sock_send_result(int fd, int res);
 
+/**
+ * This API is only for Appfw internally.
+ */
+int aul_sock_send_result_v2(int fd, int res, bool do_close);
+
+/**
+ * This API is only for Appfw internally.
+ */
+int aul_sock_recv_reply_pkt_v2(int fd, app_pkt_t **pkt, bool do_close);
+
 #ifdef __cplusplus
 }
 #endif
index 7ba85f0..daf62ec 100644 (file)
@@ -215,6 +215,8 @@ API const char *aul_cmd_convert_to_string(int cmd)
                "PROC_GROUP_ADD",
                "PROC_GROUP_REMOVE",
 
+               "APP_CONNECT",
+
                "CUSTOM_COMMAND"
        };
 
index 7b5376a..dd5acbc 100644 (file)
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
 
+typedef struct client_channel_s {
+       int fd;
+       pid_t pid;
+       uid_t uid;
+       GRecMutex mutex;
+} client_channel_t;
+
 struct aul_request_s {
        int cmd;
        int clifd;
@@ -72,10 +79,77 @@ typedef struct launch_context_s {
        aul_handler aul;
        subapp_handler subapp;
        data_control_provider_handler dcp;
+       GList* clients;
+       GRecMutex mutex;
 } launch_context;
 
 static launch_context __context;
 
+static void __destroy_client_channel(gpointer data)
+{
+       client_channel_t *channel = data;
+
+       g_rec_mutex_lock(&channel->mutex);
+       g_rec_mutex_unlock(&channel->mutex);
+       g_rec_mutex_clear(&channel->mutex);
+
+       free(channel);
+}
+
+static client_channel_t *__create_client_channel(int fd, pid_t pid, uid_t uid)
+{
+       client_channel_t *channel;
+
+       channel = calloc(1, sizeof(client_channel_t));
+       if (!channel) {
+               _E("Out of memory");
+               return NULL;
+       }
+
+       g_rec_mutex_init(&channel->mutex);
+
+       channel->fd = fd;
+       channel->pid = pid;
+       channel->uid = uid;
+
+       return channel;
+}
+
+static void __add_client_channel(client_channel_t *channel)
+{
+       g_rec_mutex_lock(&__context.mutex);
+       __context.clients = g_list_append(__context.clients, channel);
+       g_rec_mutex_unlock(&__context.mutex);
+}
+
+static void __remove_client_channel(client_channel_t *channel)
+{
+       g_rec_mutex_lock(&__context.mutex);
+       __context.clients = g_list_remove(__context.clients, channel);
+       g_rec_mutex_unlock(&__context.mutex);
+}
+
+static client_channel_t *__find_client_channel(int fd)
+{
+       client_channel_t *channel;
+       GList *iter;
+
+       g_rec_mutex_lock(&__context.mutex);
+       iter = __context.clients;
+       while (iter) {
+               channel = iter->data;
+               if (channel->fd == fd) {
+                       g_rec_mutex_unlock(&__context.mutex);
+                       return channel;
+               }
+
+               iter = g_list_next(iter);
+       }
+       g_rec_mutex_unlock(&__context.mutex);
+
+       return NULL;
+}
+
 static void __invoke_aul_handler(aul_type type, bundle *b)
 {
        if (__context.aul.callback)
@@ -250,6 +324,10 @@ static void __dispatch_watchdog_disable(aul_request_h req)
        aul_watchdog_stop();
 }
 
+static void __dispatch_app_connect(aul_request_h req)
+{
+}
+
 static dispatcher __dispatcher[] = {
        [APP_START] = __dispatch_app_start,
        [APP_START_RES] = __dispatch_app_start,
@@ -280,6 +358,7 @@ static dispatcher __dispatcher[] = {
        [APP_TERM_BG_INSTANCE] = __dispatch_app_term_bg_inst,
        [WATCHDOG_ENABLE] = __dispatch_watchdog_enable,
        [WATCHDOG_DISABLE] = __dispatch_watchdog_disable,
+       [APP_CONNECT] = __dispatch_app_connect,
 };
 
 static void __destroy_request(struct aul_request_s *req)
@@ -308,11 +387,19 @@ static struct aul_request_s *__create_request(int cmd, int clifd, bundle *b)
 
 static int __send_result(struct aul_request_s *req, int res)
 {
+       client_channel_t *channel;
        int ret;
 
-       if (req->cmd != WIDGET_GET_CONTENT && req->clifd > 0) {
-               ret = aul_sock_send_result(req->clifd, res);
-               req->clifd = -1;
+       if (req->cmd != WIDGET_GET_CONTENT && req->clifd >= 0) {
+               channel = __find_client_channel(req->clifd);
+               if (!channel) {
+                       _E("Failed to find client channel. fd(%d)", req->clifd);
+                       return -1;
+               }
+
+               g_rec_mutex_lock(&channel->mutex);
+               ret = aul_sock_send_result_v2(req->clifd, res, false);
+               g_rec_mutex_unlock(&channel->mutex);
                if (ret < 0) {
                        _E("Failed to send result. cmd(%s:%d)",
                                        aul_cmd_convert_to_string(req->cmd),
@@ -331,7 +418,6 @@ static gboolean __dispatch_request(gpointer data)
 
        if (!__context.initialized) {
                _W("Ignore request(%d)", req->cmd);
-               __send_result(req, -1);
                __destroy_request(req);
                return G_SOURCE_REMOVE;
        }
@@ -359,14 +445,72 @@ static gboolean __dispatch_request(gpointer data)
        return G_SOURCE_REMOVE;
 }
 
-static bool __worker_io_job_cb(int fd, void *user_data)
+static void __process_app_pkt(app_pkt_t *pkt, int clifd)
 {
-       aul_worker_h worker = user_data;
        struct aul_request_s *req;
-       app_pkt_t *pkt;
        bundle *b = NULL;
-       int clifd;
+
+       if (pkt->opt & AUL_SOCK_BUNDLE) {
+               b = bundle_decode(pkt->data, pkt->len);
+               if (!b) {
+                       _E("Failed to decode the packet");
+                       return;
+               }
+       }
+
+       req = __create_request(pkt->cmd, clifd, b);
+       if (!req) {
+               bundle_free(b);
+               return;
+       }
+
+       g_idle_add(__dispatch_request, req);
+}
+
+static bool __received_event_cb(int fd, int condition, void *user_data)
+{
+       aul_worker_h worker = user_data;
+       client_channel_t *channel;
+       app_pkt_t *pkt;
+       int ret;
+
+       channel = __find_client_channel(fd);
+       if (!channel) {
+               _E("Failed to find client channel. fd(%d)", fd);
+               return false;
+       }
+
+       if (condition & (AUL_IO_HUP | AUL_IO_ERR | AUL_IO_NVAL)) {
+               _E("IO error occurred. condition(%d), fd(%d)", condition, fd);
+               __remove_client_channel(channel);
+               __destroy_client_channel(channel);
+               return false;
+       }
+
+       g_rec_mutex_lock(&channel->mutex);
+       ret = aul_sock_recv_reply_pkt_v2(fd, &pkt, false);
+       g_rec_mutex_unlock(&channel->mutex);
+       if (ret != 0) {
+               _E("Failed to receive the packet. error(%d)", ret);
+               return true;
+       }
+
+       __process_app_pkt(pkt, fd);
+       aul_worker_add_anr_timer(worker, pkt->cmd);
+       free(pkt);
+
+       return true;
+}
+
+static bool __connected_event_cb(int fd, int condition, void *user_data)
+{
+       int cond = AUL_IO_IN | AUL_IO_HUP | AUL_IO_ERR | AUL_IO_NVAL;
+       aul_worker_h worker = user_data;
+       client_channel_t *channel = NULL;
        struct ucred cr;
+       int clifd;
+       app_pkt_t *pkt;
+       int ret;
 
        pkt = aul_sock_recv_pkt(fd, &clifd, &cr);
        if (!pkt) {
@@ -374,44 +518,66 @@ static bool __worker_io_job_cb(int fd, void *user_data)
                return true;
        }
 
+       _W("pid(%d), clifd(%d), cmd(%d)", cr.pid, clifd, pkt->cmd);
        if (pkt->cmd != WIDGET_GET_CONTENT) {
                if (pkt->opt & AUL_SOCK_NOREPLY) {
                        close(clifd);
                        clifd = -1;
-               }
-       }
-
-       if (pkt->opt & AUL_SOCK_BUNDLE) {
-               b = bundle_decode(pkt->data, pkt->len);
-               if (!b) {
-                       _E("Failed to decode the packet");
-                       if (clifd > 0)
+               } else {
+                       channel = __create_client_channel(clifd,
+                                       cr.pid, cr.uid);
+                       if (!channel) {
+                               free(pkt);
                                close(clifd);
-                       free(pkt);
-                       return true;
+                               return true;
+                       }
+
+                       __add_client_channel(channel);
                }
        }
 
-       req = __create_request(pkt->cmd, clifd, b);
+       __process_app_pkt(pkt, clifd);
+       aul_worker_add_anr_timer(worker, pkt->cmd);
+
+       if (pkt->cmd == WIDGET_GET_CONTENT)
+               clifd = -1;
+
        free(pkt);
-       if (!req) {
-               bundle_free(b);
+
+       if (clifd < 0)
                return true;
-       }
 
-       aul_worker_add_anr_timer(worker, req->cmd);
-       g_idle_add(__dispatch_request, req);
+       ret = aul_worker_add_io_job(worker, "client", clifd, cond,
+                               __received_event_cb, worker);
+       if (ret < 0) {
+               _E("Failed to add io job. error(%d)", ret);
+               __remove_client_channel(channel);
+               __destroy_client_channel(channel);
+               return true;
+       }
 
        return true;
 }
 
 static void __finalize_context(void)
 {
+       if (!__context.initialized)
+               return;
+
        if (__context.worker) {
                aul_worker_destroy(__context.worker);
                __context.worker = NULL;
        }
 
+       g_rec_mutex_lock(&__context.mutex);
+       if (__context.clients) {
+               g_list_free_full(__context.clients, __destroy_client_channel);
+               __context.clients = NULL;
+       }
+
+       g_rec_mutex_unlock(&__context.mutex);
+       g_rec_mutex_clear(&__context.mutex);
+
        __context.initialized = false;
 }
 
@@ -420,20 +586,27 @@ static int __initialize_context(void)
        int ret;
        int fd;
 
+       if (__context.initialized) {
+               _E("Already initialized");
+               return AUL_R_OK;
+       }
+
        fd = aul_initialize();
        if (fd < 0) {
                _E("Failed to initialize aul");
                return fd;
        }
 
+       g_rec_mutex_init(&__context.mutex);
+
        __context.worker = aul_worker_create("aul+");
        if (!__context.worker) {
                __finalize_context();
                return AUL_R_ERROR;
        }
 
-       ret = aul_worker_add_io_job(__context.worker, "AUL", fd,
-                       __worker_io_job_cb, __context.worker);
+       ret = aul_worker_add_io_job(__context.worker, "server", fd, AUL_IO_IN,
+                       __connected_event_cb, __context.worker);
        if (ret < 0) {
                __finalize_context();
                return ret;
index c4e7359..4980758 100644 (file)
@@ -625,20 +625,7 @@ API app_pkt_t *aul_sock_recv_pkt(int fd, int *clifd, struct ucred *cr)
 
 API int aul_sock_recv_reply_pkt(int fd, app_pkt_t **ret_pkt)
 {
-       int ret;
-
-       if (fd < 0 || fd > sysconf(_SC_OPEN_MAX))
-               return -EINVAL;
-
-       if (!ret_pkt) {
-               close(fd);
-               return -EINVAL;
-       }
-
-       ret = __recv_pkt(fd, ret_pkt);
-       close(fd);
-
-       return ret;
+       return aul_sock_recv_reply_pkt_v2(fd, ret_pkt, true);
 }
 
 static int __get_descriptors(struct cmsghdr *cmsg, struct msghdr *msg, int *fds, int maxdesc)
@@ -949,25 +936,44 @@ API int aul_sock_destroy_server(int fd)
 
 API int aul_sock_send_result(int fd, int res)
 {
-       int r;
+       return aul_sock_send_result_v2(fd, res, true);
+}
 
-       if (fd < 0) {
+API int aul_sock_send_result_v2(int fd, int res, bool do_close)
+{
+       int ret;
+
+       if (fd < 0 || fd > sysconf(_SC_OPEN_MAX)) {
                _E("Invalid parameter");
                return -EINVAL;
        }
 
-       r = send(fd, &res, sizeof(res), MSG_NOSIGNAL);
-       if (r < 0) {
-               if (errno == EPIPE) {
-                       _E("EPIPE error");
-                       close(fd);
-                       return r;
-               }
+       ret = send(fd, &res, sizeof(res), MSG_NOSIGNAL);
+       if (ret < 0)
+               _E("Failed to send result. fd(%d), errno(%d)", fd, errno);
 
-               _E("Failed to send result. fd(%d), errno(%d)",
-                               fd, errno);
+       if (do_close)
+               close(fd);
+
+       return ret;
+}
+
+API int aul_sock_recv_reply_pkt_v2(int fd, app_pkt_t **pkt, bool do_close)
+{
+       int ret;
+
+       if (fd < 0 || fd > sysconf(_SC_OPEN_MAX))
+               return -EINVAL;
+
+       if (!pkt) {
+               if (do_close)
+                       close(fd);
+               return -EINVAL;
        }
-       close(fd);
 
-       return 0;
+       ret = __recv_pkt(fd, pkt);
+       if (do_close)
+               close(fd);
+
+       return ret;
 }
index 151a9cd..3593bb2 100644 (file)
@@ -170,6 +170,46 @@ static int __set_comm(const char *name)
        return 0;
 }
 
+static GIOCondition __convert_aul_io_condition(int condition)
+{
+       GIOCondition cond = 0;
+
+       if (condition & AUL_IO_IN)
+               cond |= G_IO_IN;
+       if (condition & AUL_IO_OUT)
+               cond |= G_IO_OUT;
+       if (condition & AUL_IO_PRI)
+               cond |= G_IO_PRI;
+       if (condition & AUL_IO_HUP)
+               cond |= G_IO_HUP;
+       if (condition & AUL_IO_ERR)
+               cond |= G_IO_ERR;
+       if (condition & AUL_IO_NVAL)
+               cond |= G_IO_NVAL;
+
+       return cond;
+}
+
+static int __convert_g_io_condition(GIOCondition condition)
+{
+       int cond = 0;
+
+       if (condition & G_IO_IN)
+               cond |= AUL_IO_IN;
+       if (condition & G_IO_OUT)
+               cond |= AUL_IO_OUT;
+       if (condition & G_IO_PRI)
+               cond |= AUL_IO_PRI;
+       if (condition & G_IO_HUP)
+               cond |= AUL_IO_HUP;
+       if (condition & G_IO_ERR)
+               cond |= AUL_IO_ERR;
+       if (condition & G_IO_NVAL)
+               cond |= AUL_IO_NVAL;
+
+       return cond;
+}
+
 static gboolean __io_job_handler(GIOChannel *io, GIOCondition condition,
                gpointer data)
 {
@@ -177,6 +217,7 @@ static gboolean __io_job_handler(GIOChannel *io, GIOCondition condition,
        struct job_s *job = (struct job_s *)data;
        aul_worker_io_job_cb callback;
        GSource *source;
+       int cond;
 
        source = g_main_current_source();
        if (!source || g_source_is_destroyed(source)) {
@@ -184,14 +225,9 @@ static gboolean __io_job_handler(GIOChannel *io, GIOCondition condition,
                return G_SOURCE_REMOVE;
        }
 
-       if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
-               _E("[__JOB__] name(%s), condition(%d)", job->name, condition);
-               job->tag = 0;
-               return G_SOURCE_REMOVE;
-       }
-
+       cond = __convert_g_io_condition(condition);
        callback = (aul_worker_io_job_cb)job->callback;
-       if (callback(fd, job->user_data))
+       if (callback(fd, cond, job->user_data))
                return G_SOURCE_CONTINUE;
 
        _I("[__JOB__] name(%s)", job->name);
@@ -201,10 +237,10 @@ static gboolean __io_job_handler(GIOChannel *io, GIOCondition condition,
 }
 
 int aul_worker_add_io_job(aul_worker_h handle, const char *job_name,
-               int fd, aul_worker_io_job_cb callback, void *user_data)
+               int fd, int condition, aul_worker_io_job_cb callback,
+               void *user_data)
 {
-       GIOCondition cond = G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_ERR |
-               G_IO_NVAL;
+       GIOCondition cond = __convert_aul_io_condition(condition);
        struct aul_worker_s *worker = (struct aul_worker_s *)handle;
        struct job_s *job;
        GIOChannel *channel;
index 42c7a30..c4a1c10 100644 (file)
 
 typedef void *aul_worker_h;
 
-typedef bool (*aul_worker_io_job_cb)(int fd, void *user_data);
+typedef enum {
+       AUL_IO_IN = 0x01,
+       AUL_IO_OUT = 0x02,
+       AUL_IO_PRI = 0x04,
+       AUL_IO_ERR = 0x10,
+       AUL_IO_HUP = 0x20,
+       AUL_IO_NVAL = 0x40,
+} aul_io_condition_e;
+
+typedef bool (*aul_worker_io_job_cb)(int fd, int condition, void *user_data);
 
 aul_worker_h aul_worker_create(const char *name);
 
 void aul_worker_destroy(aul_worker_h handle);
 
 int aul_worker_add_io_job(aul_worker_h handle, const char *job_name,
-               int fd, aul_worker_io_job_cb callback, void *user_data);
+               int fd, int condition, aul_worker_io_job_cb callback,
+               void *user_data);
 
 int aul_worker_add_anr_timer(aul_worker_h handle, int cmd);