Support launch reqeust async API
[platform/core/appfw/aul-1.git] / src / launch_with_result.c
index f4c39e8..21e471b 100644 (file)
@@ -20,6 +20,7 @@
 #include <string.h>
 #include <pthread.h>
 #include <glib.h>
+#include <gio/gio.h>
 #include <bundle_internal.h>
 
 #include "aul.h"
 #include "aul_sock.h"
 #include "aul_util.h"
 #include "aul_svc.h"
+#include "aul_error.h"
 #include "launch.h"
 
 typedef struct _app_resultcb_info_t {
+       GIOChannel *io;
        int launched_pid;
        int seq_num;
-       void (*cb_func) (bundle *kb, int is_cancel, void *data);
-       void *priv_data;
+       void (*reply_cb)(bundle *b, int is_cancel, void *data);
+       void (*error_cb)(int result, void *data);
+       void *user_data;
        void (*caller_cb) (int launched_pid, void *data);
        void *caller_data;
 } app_resultcb_info_t;
@@ -95,16 +99,19 @@ static void __destroy_resultcb(app_resultcb_info_t *info)
        if (!info)
                return;
 
+       if (info->io)
+               g_io_channel_unref(info->io);
+
        free(info);
 }
 
-static app_resultcb_info_t *__create_resultcb(int pid,
-               void (*cbfunc)(bundle *b, int, void *),
-               void *data, int seq_num)
+static app_resultcb_info_t *__create_resultcb(int pid, int seq_num,
+               void (*reply_cb)(bundle *, int, void *),
+               void (*error_cb)(int, void *), void *data)
 {
        app_resultcb_info_t *info;
 
-       info = (app_resultcb_info_t *)malloc(sizeof(app_resultcb_info_t));
+       info = calloc(1, sizeof(app_resultcb_info_t));
        if (info == NULL) {
                _E("Out of memory");
                return NULL;
@@ -112,10 +119,9 @@ static app_resultcb_info_t *__create_resultcb(int pid,
 
        info->launched_pid = pid;
        info->seq_num = seq_num;
-       info->cb_func = cbfunc;
-       info->priv_data = data;
-       info->caller_cb = NULL;
-       info->caller_data = NULL;
+       info->reply_cb = reply_cb;
+       info->error_cb = error_cb;
+       info->user_data = data;
 
        return info;
 }
@@ -166,7 +172,7 @@ static int __call_app_result_callback(bundle *kb, int is_cancel,
                }
        }
 
-       if (info->cb_func == NULL) {
+       if (info->reply_cb == NULL) {
                _E("Callback function is null");
                return -1;
        }
@@ -175,8 +181,9 @@ static int __call_app_result_callback(bundle *kb, int is_cancel,
        /* In case of aul_forward_app, update the callback data */
        if (is_cancel == 1 && fwdpid_str) {
                launched_pid = atoi(fwdpid_str);
-               new_info = __create_resultcb(launched_pid, info->cb_func,
-                               info->priv_data, num);
+               new_info = __create_resultcb(launched_pid, num,
+                               info->reply_cb, info->error_cb,
+                               info->user_data);
                if (new_info)
                        __add_resultcb(new_info);
 
@@ -191,7 +198,7 @@ static int __call_app_result_callback(bundle *kb, int is_cancel,
                goto end;
        }
 
-       info->cb_func(kb, is_cancel, info->priv_data);
+       info->reply_cb(kb, is_cancel, info->user_data);
        __remove_resultcb(info);
        __destroy_resultcb(info);
 
@@ -257,7 +264,7 @@ static int __launch_app_with_result(int cmd, const char *appid, bundle *kb,
 
        ret = app_request_to_launchpad_for_uid(cmd, appid, kb, uid);
        if (ret > 0) {
-               info = __create_resultcb(ret, callback, data, num);
+               info = __create_resultcb(ret, num, callback, NULL, data);
                if (info)
                        __add_resultcb(info);
        }
@@ -575,9 +582,10 @@ API int aul_invoke_caller_cb(void *data)
                if (info->caller_data == data) {
                        /* Duplicate resultcb info */
                        new_info = __create_resultcb(info->launched_pid,
-                                       info->cb_func,
-                                       info->priv_data,
-                                       info->seq_num);
+                                       info->seq_num,
+                                       info->reply_cb,
+                                       info->error_cb,
+                                       info->user_data);
                        if (!new_info)
                                break;
 
@@ -609,3 +617,110 @@ API int aul_launch_app_with_result_async_for_uid(const char *appid, bundle *b,
        return __launch_app_with_result(APP_START_RES_ASYNC, appid, b, callback,
                        data, uid);
 }
+
+static gboolean __aul_error_handler(GIOChannel *io,
+               GIOCondition cond, gpointer user_data)
+{
+       int fd = g_io_channel_unix_get_fd(io);
+       app_resultcb_info_t *info = (app_resultcb_info_t *)user_data;
+       int res;
+
+       if (!info) {
+               _E("Critical error!");
+               return G_SOURCE_REMOVE;
+       }
+
+       res = aul_sock_recv_result_with_fd(fd);
+       if (res < 1)
+               res = aul_error_convert(res);
+
+       _W("Sequence(%d), result(%d)", info->seq_num, res);
+
+       if (info->error_cb) {
+               info->error_cb(res, info->user_data);
+               info->error_cb = NULL;
+       }
+
+       if (res > 0 && info->reply_cb) {
+               info->launched_pid = res;
+               __add_resultcb(info);
+       } else {
+               __destroy_resultcb(info);
+       }
+
+       return G_SOURCE_REMOVE;
+}
+
+static int __resultcb_add_watch(int fd, app_resultcb_info_t *info)
+{
+       GIOCondition cond = G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP;
+       guint source;
+
+       info->io = g_io_channel_unix_new(fd);
+       if (!info->io) {
+               _E("Failed to create gio channel");
+               return -1;
+       }
+
+       source = g_io_add_watch(info->io, cond, __aul_error_handler, info);
+       if (!source) {
+               _E("Failed to add gio watch");
+               return -1;
+       }
+       g_io_channel_set_close_on_unref(info->io, TRUE);
+
+       return 0;
+}
+
+API int aul_send_launch_request_for_uid(const char *appid, bundle *b, uid_t uid,
+               void (*reply_cb)(bundle *b, int, void *),
+               void (*error_cb)(int, void *),
+               void *user_data)
+{
+       app_resultcb_info_t *info;
+       char buf[12];
+       int seq_num;
+       int fd;
+
+       if (!aul_is_initialized()) {
+               if (aul_launch_init(NULL, NULL) < 0) {
+                       _E("Failed to initialize aul launch");
+                       return AUL_R_ENOINIT;
+               }
+       }
+
+       if (!appid || !b || !error_cb) {
+               _E("Invalid parameter");
+               return AUL_R_EINVAL;
+       }
+
+       seq_num = __gen_seq_num();
+       snprintf(buf, sizeof(buf), "%d", seq_num);
+       bundle_del(b, AUL_K_SEQ_NUM);
+       bundle_add(b, AUL_K_SEQ_NUM, buf);
+
+       _W("Sequence(%d), appid(%s)", seq_num, appid);
+       fd = app_request_to_launchpad_for_uid(APP_SEND_LAUNCH_REQUEST,
+                       appid, b, uid);
+       if (fd < 0 || fd > sysconf(_SC_OPEN_MAX)) {
+               _E("Failed to send launch request. appid(%s), result(%d)",
+                               appid, fd);
+               return AUL_R_ECOMM;
+       }
+
+       info = __create_resultcb(-1, seq_num, reply_cb, error_cb, user_data);
+       if (!info) {
+               _E("Failed to create resultcb info");
+               close(fd);
+               return AUL_R_ERROR;
+       }
+
+       if (__resultcb_add_watch(fd, info) < 0) {
+               _E("Failed to add resultcb watch");
+               __destroy_resultcb(info);
+               close(fd);
+               return AUL_R_ERROR;
+       }
+
+       return AUL_R_OK;
+}