#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;
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;
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;
}
}
}
- if (info->cb_func == NULL) {
+ if (info->reply_cb == NULL) {
_E("Callback function is null");
return -1;
}
/* 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);
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);
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);
}
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;
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;
+}
/* 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;
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);
}
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;
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)
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;
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);
#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;
}
}
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;
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;
}
|| 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;
}
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);
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;
}
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);
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;
}
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;
}
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;
}
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);
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:
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,
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);
}