Support launch reqeust async API 01/189001/6
authorHwankyu Jhun <h.jhun@samsung.com>
Wed, 12 Sep 2018 10:15:12 +0000 (19:15 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Mon, 17 Sep 2018 01:59:29 +0000 (10:59 +0900)
Change-Id: I47d8ea203f2d9bb572babcfbd537483af4b73892
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
include/aul_cmd.h
include/aul_svc.h
include/launch.h
src/aul_cmd.c
src/aul_launch.c
src/launch.c
src/launch_with_result.c
src/service.c

index fa7ee7b..880f62d 100755 (executable)
@@ -138,6 +138,7 @@ enum app_cmd {
        WATCHDOG_DISABLE = 106,
        WATCHDOG_PING = 107,
        WATCHDOG_KICK = 108,
+       APP_SEND_LAUNCH_REQUEST = 109,
 
        APP_CMD_MAX
 };
index 7818a53..d2a0239 100755 (executable)
@@ -154,6 +154,14 @@ typedef enum _aul_svc_result_val {
 */
 typedef void (*aul_svc_res_fn)(bundle *b, int request_code, aul_svc_result_val result, void *data);
 
+/**
+ * @brief Called when the result of the launch request is delivered.
+ *
+ * @param[in]   request_code    The request code
+ * @param[in]   result          The result, the process ID of the callee on success otherwise a negative error value
+ * @param[in]   user_data       The user data passed from the callback registration function
+ */
+typedef void (*aul_svc_err_cb)(int request_code, int result, void *user_data);
 
 /**
  * @brief iterator function running with aul_svc_get_list
@@ -1292,6 +1300,40 @@ int aul_svc_run_service_async(bundle *b, int request_code,
 int aul_svc_run_service_async_for_uid(bundle *b, int request_code,
                aul_svc_res_fn cbfunc, void *data, uid_t uid);
 
+
+/**
+ * @brief Sends the launch request asynchronous.
+ *
+ * @param[in]   b               The bundle object
+ * @param[in]   request_code    The request code
+ * @param[in]   cbfunc          The reply callback function
+ * @param[in]   err_cb          The result callback function
+ * @param[in]   user_data       The user data to be passed to the callback function
+ *
+ * @return      a pid of the callee on success,
+ *              otherwise a negative error value
+ */
+int aul_svc_send_launch_request(bundle *b, int request_code,
+               aul_svc_res_fn cbfunc, aul_svc_err_cb err_cb,
+               void *user_data);
+
+/**
+ * @brief Sends the launch request asynchronous.
+ *
+ * @param[in]   b               The bundle object
+ * @param[in]   request_code    The request code
+ * @param[in]   cbfunc          The reply callback function
+ * @param[in]   err_cb          The result callback function
+ * @param[in]   user_data       The user data to be passed to the callback function
+ * @param[in]   uid             The user ID
+ *
+ * @return      a pid of the callee on success,
+ *              otherwise a negative error value
+ */
+int aul_svc_send_launch_request_for_uid(bundle *b, int request_code,
+               aul_svc_res_fn cbfunc, aul_svc_err_cb err_cb,
+               void *user_data, uid_t uid);
+
 #ifdef __cplusplus
 }
 #endif
index d78a0eb..dda2ecf 100644 (file)
@@ -46,3 +46,6 @@ int aul_launch_app_with_result_async_for_uid(const char *appid, bundle *b,
                void (*callback)(bundle *, int, void *), void *data, uid_t uid);
 int aul_resume_local(void);
 int aul_launch_fini(void);
+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);
index 61eaf15..06c9d7b 100755 (executable)
@@ -242,6 +242,8 @@ API const char *aul_cmd_convert_to_string(int cmd)
                return "WATCHDOG_PING";
        case WATCHDOG_KICK:
                return "WATCHDOG_KICK";
+       case APP_SEND_LAUNCH_REQUEST:
+               return "APP_SEND_LAUNCH_REQUEST";
        default:
                return "CUSTOM_COMMAND";
        }
index 2b2d54f..424d857 100644 (file)
@@ -242,6 +242,7 @@ static dispatcher __dispatcher[] = {
        [WIDGET_GET_CONTENT] = __dispatch_widget_get_content,
        [APP_UPDATE_REQUESTED] = __dispatch_app_update_requested,
        [WATCHDOG_PING] = __dispatch_watchdog_ping,
+       [APP_SEND_LAUNCH_REQUEST] = __dispatch_app_start,
 };
 
 static gboolean __aul_launch_handler(GIOChannel *io, GIOCondition condition,
index 49794c9..6aa6462 100755 (executable)
@@ -67,12 +67,24 @@ static int __send_cmd_for_uid_opt(int pid, uid_t uid, int cmd, bundle *kb, int o
        return res;
 }
 
+static int __send_cmd_noreply_for_uid_opt(int pid, uid_t uid,
+               int cmd, bundle *kb, int opt)
+{
+       int res;
+
+       res = aul_sock_send_bundle(pid, uid, cmd, kb, opt | AUL_SOCK_NOREPLY);
+       if (res < 0)
+               res = aul_error_convert(res);
+
+       return res;
+}
+
 static int __send_cmd_async_for_uid_opt(int pid, uid_t uid,
-                                       int cmd, bundle *kb, int opt)
+               int cmd, bundle *kb, int opt)
 {
        int res;
 
-       res = aul_sock_send_bundle(pid, uid, cmd, kb, AUL_SOCK_NOREPLY);
+       res = aul_sock_send_bundle(pid, uid, cmd, kb, opt | AUL_SOCK_ASYNC);
        if (res < 0)
                res = aul_error_convert(res);
 
@@ -103,7 +115,7 @@ API int app_send_cmd_with_queue_for_uid(int pid, uid_t uid, int cmd, bundle *kb)
 API int app_send_cmd_with_queue_noreply_for_uid(int pid, uid_t uid,
                                        int cmd, bundle *kb)
 {
-       return __send_cmd_async_for_uid_opt(pid, uid, cmd, kb, AUL_SOCK_QUEUE);
+       return __send_cmd_noreply_for_uid_opt(pid, uid, cmd, kb, AUL_SOCK_QUEUE);
 }
 
 API int app_send_cmd_with_noreply(int pid, int cmd, bundle *kb)
@@ -213,6 +225,10 @@ int app_request_to_launchpad_for_uid(int cmd, const char *appid, bundle *kb, uid
                ret = app_send_cmd_with_queue_noreply_for_uid(AUL_UTIL_PID,
                                uid, cmd, kb);
                break;
+       case APP_SEND_LAUNCH_REQUEST:
+               ret = __send_cmd_async_for_uid_opt(AUL_UTIL_PID,
+                               uid, cmd, kb, AUL_SOCK_QUEUE);
+               break;
        default:
                ret = app_send_cmd_with_queue_for_uid(AUL_UTIL_PID, uid, cmd,
                                kb);
@@ -229,6 +245,7 @@ int app_request_to_launchpad_for_uid(int cmd, const char *appid, bundle *kb, uid
                case APP_START_ASYNC:
                case WIDGET_UPDATE:
                case APP_START_RES_ASYNC:
+               case APP_SEND_LAUNCH_REQUEST:
                        b = bundle_dup(kb);
                        ret = aul_launch_local(b);
                        break;
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;
+}
index 6f67566..2e03a0d 100755 (executable)
@@ -42,8 +42,9 @@
 
 /* callback handling */
 typedef struct _aul_svc_cb_info_t {
-       aul_svc_res_fn cb_func;
        int request_code;
+       aul_svc_res_fn cb_func;
+       aul_svc_err_cb err_cb;
        void *data;
 } aul_svc_cb_info_t;
 
@@ -72,12 +73,13 @@ pthread_mutex_t iniparser_lock = PTHREAD_MUTEX_INITIALIZER;
 GSList *tmp_list;
 
 static aul_svc_cb_info_t *__create_rescb(int request_code,
-                                       aul_svc_res_fn cbfunc, void *data);
+               aul_svc_res_fn cbfunc, aul_svc_err_cb err_cb, void *data);
 static void __remove_rescb(aul_svc_cb_info_t *info);
 static int __set_bundle(bundle *b, const char *key, const char *value);
 static void __aul_cb(bundle *b, int is_cancel, void *data);
 static int __run_svc_with_pkgname(char *pkgname, bundle *b, int request_code,
-               aul_svc_res_fn cbfunc, void *data, uid_t uid, bool sync);
+               aul_svc_res_fn cbfunc, aul_svc_err_cb err_cb, void *data,
+               uid_t uid, bool sync);
 static int __get_resolve_info(bundle *b, aul_svc_resolve_info_t *info);
 static int __free_resolve_info_data(aul_svc_resolve_info_t *info);
 
@@ -125,16 +127,19 @@ static bool __is_special_operation(bundle *b)
 }
 
 static aul_svc_cb_info_t *__create_rescb(int request_code,
-                                       aul_svc_res_fn cbfunc, void *data)
+               aul_svc_res_fn cbfunc, aul_svc_err_cb err_cb, void *data)
 {
        aul_svc_cb_info_t* info;
 
-       info = (aul_svc_cb_info_t*)calloc(1, sizeof(aul_svc_cb_info_t));
-       if (info == NULL)
+       info = calloc(1, sizeof(aul_svc_cb_info_t));
+       if (info == NULL) {
+               _E("Out of memory");
                return NULL;
+       }
 
        info->request_code = request_code;
        info->cb_func = cbfunc;
+       info->err_cb = err_cb;
        info->data = data;
 
        return info;
@@ -142,7 +147,8 @@ static aul_svc_cb_info_t *__create_rescb(int request_code,
 
 static void __remove_rescb(aul_svc_cb_info_t *info)
 {
-       if (info) free(info);
+       if (info)
+               free(info);
 }
 
 static int __set_bundle(bundle *b, const char *key, const char *value)
@@ -216,8 +222,45 @@ static void __aul_cb(bundle *b, int is_cancel, void *data)
        return;
 }
 
+static int __error_convert(int res)
+{
+       switch (res) {
+       case AUL_R_EILLACC:
+               return AUL_SVC_RET_EILLACC;
+       case AUL_R_EINVAL:
+               return AUL_SVC_RET_EINVAL;
+       case AUL_R_ETERMINATING:
+               return AUL_SVC_RET_ETERMINATING;
+       case AUL_R_EREJECTED:
+               return AUL_SVC_RET_EREJECTED;
+       case AUL_R_ENOAPP:
+               return AUL_SVC_RET_ENOMATCH;
+       default:
+               return AUL_SVC_RET_ELAUNCH;
+       }
+}
+
+static void __aul_error_cb(int err, void *data)
+{
+       aul_svc_cb_info_t *cb_info = (aul_svc_cb_info_t *)data;
+
+       if (!cb_info) {
+               _E("Critical error!");
+               return;
+       }
+
+       if (err < 0)
+               err = __error_convert(err);
+
+       if (cb_info->err_cb) {
+               cb_info->err_cb(cb_info->request_code, err, cb_info->data);
+               cb_info->err_cb = NULL;
+       }
+}
+
 static int __run_svc_with_pkgname(char *pkgname, bundle *b, int request_code,
-               aul_svc_res_fn cbfunc, void *data, uid_t uid, bool sync)
+               aul_svc_res_fn cbfunc, aul_svc_err_cb err_cb,
+               void *data, uid_t uid, bool sync)
 {
        aul_svc_cb_info_t *cb_info = NULL;
        int ret = -1;
@@ -242,13 +285,20 @@ static int __run_svc_with_pkgname(char *pkgname, bundle *b, int request_code,
        if (cbfunc) {
                SECURE_LOGD("pkg_name : %s - with result", pkgname);
 
-               cb_info = __create_rescb(request_code, cbfunc, data);
+               cb_info = __create_rescb(request_code, cbfunc, err_cb, data);
                if (sync) {
                        ret = aul_launch_app_with_result_for_uid(pkgname, b,
                                        __aul_cb, cb_info, uid);
                } else {
-                       ret = aul_launch_app_with_result_async_for_uid(pkgname,
-                                       b, __aul_cb, cb_info, uid);
+                       if (err_cb) {
+                               ret = aul_send_launch_request_for_uid(pkgname,
+                                               b, uid, __aul_cb,
+                                               __aul_error_cb, cb_info);
+                       } else {
+                               ret = aul_launch_app_with_result_async_for_uid(
+                                               pkgname, b, __aul_cb,
+                                               cb_info, uid);
+                       }
                }
        } else {
                SECURE_LOGD("pkg_name : %s - no result", pkgname);
@@ -280,27 +330,8 @@ static int __run_svc_with_pkgname(char *pkgname, bundle *b, int request_code,
 #endif
        }
 
-       if (ret < 0) {
-               switch (ret) {
-               case AUL_R_EILLACC:
-                       ret = AUL_SVC_RET_EILLACC;
-                       break;
-               case AUL_R_EINVAL:
-                       ret = AUL_SVC_RET_EINVAL;
-                       break;
-               case AUL_R_ETERMINATING:
-                       ret = AUL_SVC_RET_ETERMINATING;
-                       break;
-               case AUL_R_EREJECTED:
-                       ret = AUL_SVC_RET_EREJECTED;
-                       break;
-               case AUL_R_ENOAPP:
-                       ret = AUL_SVC_RET_ENOMATCH;
-                       break;
-               default:
-                       ret = AUL_SVC_RET_ELAUNCH;
-               }
-       }
+       if (ret < 0)
+               ret = __error_convert(ret);
 
        return ret;
 }
@@ -868,7 +899,8 @@ API int aul_svc_set_launch_mode(bundle *b, const char *mode)
 }
 
 static int __run_service(bundle *b, int request_code,
-               aul_svc_res_fn cbfunc, void *data, uid_t uid, bool sync)
+               aul_svc_res_fn cbfunc, aul_svc_err_cb err_cb,
+               void *data, uid_t uid, bool sync)
 {
        aul_svc_resolve_info_t info;
        char *pkgname;
@@ -894,7 +926,7 @@ static int __run_service(bundle *b, int request_code,
                if (operation == NULL)
                        aul_svc_set_operation(b, AUL_SVC_OPERATION_DEFAULT);
                ret = __run_svc_with_pkgname(pkgname, b, request_code, cbfunc,
-                               data, uid, sync);
+                               err_cb, data, uid, sync);
                return ret;
        }
 
@@ -904,7 +936,7 @@ static int __run_service(bundle *b, int request_code,
                || strcmp(operation, AUL_SVC_OPERATION_MULTI_SHARE) == 0
                || strcmp(operation, AUL_SVC_OPERATION_SHARE_TEXT) == 0))) {
                ret = __run_svc_with_pkgname(SHARE_PANEL, b, request_code,
-                               cbfunc, data, uid, sync);
+                               cbfunc, err_cb, data, uid, sync);
                return ret;
        }
 
@@ -926,13 +958,14 @@ static int __run_service(bundle *b, int request_code,
                l = strlen("@APP_SELECTOR ");
                if (!strncmp("@APP_SELECTOR ", appid, l)) {
                        bundle_add(b, AUL_SVC_K_URI_R_INFO, &appid[l]);
-                       ret = __run_svc_with_pkgname(APP_SELECTOR, b, request_code,
-                               cbfunc, data, uid, sync);
+                       ret = __run_svc_with_pkgname(APP_SELECTOR, b,
+                                       request_code, cbfunc, err_cb,
+                                       data, uid, sync);
                } else if (!strcmp(appid, "^")) {
                        ret = AUL_SVC_RET_ENOMATCH;
                } else {
                        ret = __run_svc_with_pkgname(appid, b, request_code,
-                               cbfunc, data, uid, sync);
+                               cbfunc, err_cb, data, uid, sync);
                }
                free(appid);
                g_free(checksum);
@@ -952,7 +985,7 @@ static int __run_service(bundle *b, int request_code,
        if (pkgname != NULL) {
                __put_cache(checksum, pkgname, uid);
                ret = __run_svc_with_pkgname(pkgname, b, request_code,
-                       cbfunc, data, uid, sync);
+                       cbfunc, err_cb, data, uid, sync);
                free(pkgname);
                goto end;
        }
@@ -1008,14 +1041,14 @@ static int __run_service(bundle *b, int request_code,
                        if (pkgname != NULL) {
                                __put_cache(checksum, pkgname, uid);
                                ret = __run_svc_with_pkgname(pkgname, b, request_code,
-                                               cbfunc, data, uid, sync);
+                                               cbfunc, err_cb, data, uid, sync);
                                goto end;
                        }
                } else if (pkg_count > 1) {
                        bundle_add(b, AUL_SVC_K_URI_R_INFO, info.uri);
                        __put_cache_with_info(checksum, info.uri, uid);
                        ret = __run_svc_with_pkgname(APP_SELECTOR, b, request_code,
-                                       cbfunc, data, uid, sync);
+                                       cbfunc, err_cb, data, uid, sync);
                        goto end;
                }
                __free_pkg_list(pkg_list);
@@ -1029,7 +1062,7 @@ static int __run_service(bundle *b, int request_code,
                if (pkgname != NULL) {
                        __put_cache(checksum, pkgname, uid);
                        ret = __run_svc_with_pkgname(pkgname, b, request_code,
-                                       cbfunc, data, uid, sync);
+                                       cbfunc, err_cb, data, uid, sync);
                        free(pkgname);
                        goto end;
                }
@@ -1076,14 +1109,14 @@ static int __run_service(bundle *b, int request_code,
                                if (pkgname != NULL) {
                                        __put_cache(checksum, pkgname, uid);
                                        ret = __run_svc_with_pkgname(pkgname, b, request_code,
-                                                       cbfunc, data, uid, sync);
+                                                       cbfunc, err_cb, data, uid, sync);
                                        goto end;
                                }
                        } else if (pkg_count > 1) {
                                bundle_add(b, AUL_SVC_K_URI_R_INFO, info.uri_r_info);
                                __put_cache_with_info(checksum, info.uri_r_info, uid);
                                ret = __run_svc_with_pkgname(APP_SELECTOR, b, request_code,
-                                       cbfunc, data, uid, sync);
+                                       cbfunc, err_cb, data, uid, sync);
                                goto end;
                        }
 
@@ -1098,7 +1131,7 @@ static int __run_service(bundle *b, int request_code,
        if (pkgname != NULL) {
                __put_cache(checksum, pkgname, uid);
                ret = __run_svc_with_pkgname(pkgname, b, request_code,
-                       cbfunc, data, uid, sync);
+                       cbfunc, err_cb, data, uid, sync);
                free(pkgname);
                goto end;
        }
@@ -1136,7 +1169,7 @@ static int __run_service(bundle *b, int request_code,
                if (pkgname != NULL) {
                        __put_cache(checksum, pkgname, uid);
                        ret = __run_svc_with_pkgname(pkgname, b, request_code,
-                                       cbfunc, data, uid, sync);
+                                       cbfunc, err_cb, data, uid, sync);
                }
        } else if (pkg_count < 1) {
                __free_resolve_info_data(&info);
@@ -1147,7 +1180,7 @@ static int __run_service(bundle *b, int request_code,
                bundle_add(b, AUL_SVC_K_URI_R_INFO, info.scheme);
                __put_cache_with_info(checksum, info.scheme, uid);
                ret = __run_svc_with_pkgname(APP_SELECTOR, b, request_code,
-                               cbfunc, data, uid, sync);
+                               cbfunc, err_cb, data, uid, sync);
        }
 
 end:
@@ -1161,13 +1194,14 @@ end:
 API int aul_svc_run_service(bundle *b, int request_code,
                aul_svc_res_fn cbfunc, void *data)
 {
-       return __run_service(b, request_code, cbfunc, data, getuid(), true);
+       return __run_service(b, request_code, cbfunc, NULL, data,
+                       getuid(), true);
 }
 
 API int aul_svc_run_service_for_uid(bundle *b, int request_code,
                aul_svc_res_fn cbfunc, void *data, uid_t uid)
 {
-       return __run_service(b, request_code, cbfunc, data, uid, true);
+       return __run_service(b, request_code, cbfunc, NULL, data, uid, true);
 }
 
 API int aul_svc_get_list(bundle *b, aul_svc_info_iter_fn iter_fn,
@@ -1885,11 +1919,28 @@ API int aul_svc_set_instance_id(bundle *b, const char *instance_id)
 API int aul_svc_run_service_async(bundle *b, int request_code,
                aul_svc_res_fn cbfunc, void *data)
 {
-       return __run_service(b, request_code, cbfunc, data, getuid(), false);
+       return __run_service(b, request_code, cbfunc, NULL, data,
+                       getuid(), false);
 }
 
 API int aul_svc_run_service_async_for_uid(bundle *b, int request_code,
                aul_svc_res_fn cbfunc, void *data, uid_t uid)
 {
-       return __run_service(b, request_code, cbfunc, data, uid, false);
+       return __run_service(b, request_code, cbfunc, NULL, data, uid, false);
+}
+
+API int aul_svc_send_launch_request(bundle *b, int request_code,
+               aul_svc_res_fn cbfunc, aul_svc_err_cb err_cb,
+               void *user_data)
+{
+       return aul_svc_send_launch_request_for_uid(b, request_code,
+                       cbfunc, err_cb, user_data, getuid());
+}
+
+API int aul_svc_send_launch_request_for_uid(bundle *b, int request_code,
+               aul_svc_res_fn cbfunc, aul_svc_err_cb err_cb,
+               void *user_data, uid_t uid)
+{
+       return __run_service(b, request_code, cbfunc, err_cb, user_data,
+                       uid, false);
 }