#include <unistd.h>
#include <string.h>
#include <errno.h>
+#include <pthread.h>
#include <glib.h>
#include <bundle.h>
} *app_control_request_context_h;
struct launch_request_s {
+ int id;
bool implicit_default_operation;
app_control_request_context_h request_context;
app_control_h app_control;
void *user_data;
};
+struct reply_info_s {
+ bundle *b;
+ aul_svc_result_val result;
+ void *user_data;
+};
+
+struct result_info_s {
+ int result;
+ void *user_data;
+};
+
+struct pending_item_s {
+ int id;
+ struct reply_info_s *reply_info;
+ struct result_info_s *result_info;
+};
+
typedef int (*launch_request_handler)(struct launch_request_s *req);
static int app_control_create_reply(bundle *data, struct app_control_s **app_control);
+static void app_control_request_reply_broker(bundle *appsvc_bundle,
+ int appsvc_request_code, aul_svc_result_val appsvc_result,
+ void *appsvc_data);
+static void app_control_request_result_broker(int request_code, int result,
+ void *user_data);
+
+static pthread_mutex_t __mutex = PTHREAD_MUTEX_INITIALIZER;
+static GList *__pending_list;
+
+static int __generate_request_id(void)
+{
+ static int id;
+
+ g_atomic_int_inc(&id);
+ return id;
+}
+
+static void __destroy_result_info(gpointer data)
+{
+ struct result_info_s *info = data;
+
+ if (!info)
+ return;
+
+ free(info);
+}
+
+static struct result_info_s *__create_result_info(int result,
+ void *user_data)
+{
+ struct result_info_s *info;
+
+ info = calloc(1, sizeof(struct result_info_s));
+ if (!info) {
+ LOGE("Out of memory");
+ return NULL;
+ }
+
+ info->result = result;
+ info->user_data = user_data;
+
+ return info;
+}
+
+static void __destroy_reply_info(gpointer data)
+{
+ struct reply_info_s *info = data;
+
+ if (!info)
+ return;
+
+ if (info->b)
+ bundle_free(info->b);
+
+ free(info);
+}
+
+static struct reply_info_s *__create_reply_info(bundle *b,
+ aul_svc_result_val result, void *user_data)
+{
+ struct reply_info_s *info;
+
+ info = calloc(1, sizeof(struct reply_info_s));
+ if (!info) {
+ LOGE("Out of memory");
+ return NULL;
+ }
+
+ info->b = bundle_dup(b);
+ if (!info->b) {
+ LOGE("Failed to duplicate bundle");
+ free(info);
+ return NULL;
+ }
+
+ info->result = result;
+ info->user_data = user_data;
+
+ return info;
+}
+
+static void __destroy_pending_item(gpointer data)
+{
+ struct pending_item_s *item = data;
+
+ if (!item)
+ return;
+
+ if (item->reply_info)
+ __destroy_reply_info(item->reply_info);
+
+ if (item->result_info)
+ __destroy_result_info(item->result_info);
+
+ free(item);
+}
+
+static struct pending_item_s *__create_pending_item(int id)
+{
+ struct pending_item_s *item;
+
+ item = calloc(1, sizeof(struct pending_item_s));
+ if (!item) {
+ LOGE("Out of memory");
+ return NULL;
+ }
+
+ item->id = id;
+
+ return item;
+}
+
+static void __add_pending_item(int id)
+{
+ struct pending_item_s *item;
+
+ item = __create_pending_item(id);
+ if (!item)
+ return;
+
+ pthread_mutex_lock(&__mutex);
+ __pending_list = g_list_prepend(__pending_list, item);
+ pthread_mutex_unlock(&__mutex);
+}
+
+static void __remove_pending_item(int id)
+{
+ struct pending_item_s *item;
+ GList *iter;
+
+ pthread_mutex_lock(&__mutex);
+ iter = __pending_list;
+ while (iter) {
+ item = (struct pending_item_s *)iter->data;
+ iter = g_list_next(iter);
+ if (item->id == id) {
+ __pending_list = g_list_remove(__pending_list, item);
+ __destroy_pending_item(item);
+ break;
+ }
+ }
+ pthread_mutex_unlock(&__mutex);
+}
+
+static struct pending_item_s *__pop_pending_item(int id)
+{
+ struct pending_item_s *item;
+ GList *iter;
+
+ pthread_mutex_lock(&__mutex);
+ iter = __pending_list;
+ while (iter) {
+ item = (struct pending_item_s *)iter->data;
+ iter = g_list_next(iter);
+ if (item->id == id) {
+ __pending_list = g_list_remove(__pending_list, item);
+ pthread_mutex_unlock(&__mutex);
+ return item;
+ }
+ }
+ pthread_mutex_unlock(&__mutex);
+
+ return NULL;
+}
+
+static gboolean __process_pending_item(gpointer data)
+{
+ struct pending_item_s *item = data;
+ struct result_info_s *result_info;
+ struct reply_info_s *reply_info;
+
+ if (!item)
+ return G_SOURCE_REMOVE;
+
+ if (item->result_info) {
+ result_info = item->result_info;
+ app_control_request_result_broker(item->id,
+ result_info->result, result_info->user_data);
+ __destroy_result_info(result_info);
+ item->result_info = NULL;
+ return G_SOURCE_CONTINUE;
+ }
+
+ if (item->reply_info) {
+ reply_info = item->reply_info;
+ app_control_request_reply_broker(reply_info->b, item->id,
+ reply_info->result, reply_info->user_data);
+ __destroy_reply_info(reply_info);
+ item->reply_info = NULL;
+ }
+ __destroy_pending_item(item);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void __flush_pending_item(int id)
+{
+ struct pending_item_s *item;
+
+ item = __pop_pending_item(id);
+ if (!item)
+ return;
+
+ if (!item->reply_info && !item->result_info) {
+ __destroy_pending_item(item);
+ return;
+ }
+
+ g_idle_add(__process_pending_item, item);
+}
+
+static bool __exist_pending_item(int id)
+{
+ struct pending_item_s *item;
+ GList *iter;
+
+ pthread_mutex_lock(&__mutex);
+ iter = __pending_list;
+ while (iter) {
+ item = (struct pending_item_s *)iter->data;
+ iter = g_list_next(iter);
+ if (item->id == id) {
+ pthread_mutex_unlock(&__mutex);
+ return true;
+ }
+ }
+ pthread_mutex_unlock(&__mutex);
+
+ return false;
+}
+
+static int __pending_item_set_reply_info(int id, struct reply_info_s *info)
+{
+ struct pending_item_s *item;
+ GList *iter;
+
+ pthread_mutex_lock(&__mutex);
+ iter = __pending_list;
+ while (iter) {
+ item = (struct pending_item_s *)iter->data;
+ iter = g_list_next(iter);
+ if (item->id == id) {
+ item->reply_info = info;
+ pthread_mutex_unlock(&__mutex);
+ return 0;
+ }
+ }
+ pthread_mutex_unlock(&__mutex);
+
+ return -1;
+}
+
+static int __pending_item_set_result_info(int id, struct result_info_s *info)
+{
+ struct pending_item_s *item;
+ GList *iter;
+
+ pthread_mutex_lock(&__mutex);
+ iter = __pending_list;
+ while (iter) {
+ item = (struct pending_item_s *)iter->data;
+ iter = g_list_next(iter);
+ if (item->id == id) {
+ item->result_info = info;
+ pthread_mutex_unlock(&__mutex);
+ return 0;
+ }
+ }
+ pthread_mutex_unlock(&__mutex);
+
+ return -1;
+}
static const char *app_control_error_to_string(app_control_error_e error)
{
return APP_CONTROL_ERROR_NONE;
}
-static int app_control_new_id()
+static int app_control_new_id(void)
{
- static int sid = 0;
- return sid++;
+ static int sid;
+
+ g_atomic_int_inc(&sid);
+ return sid;
}
int app_control_validate_internal_key(const char *key)
app_control_result_e result;
void *user_data;
app_control_reply_cb reply_cb;
+ struct reply_info_s *info;
+ int ret;
if (appsvc_data == NULL) {
app_control_error(APP_CONTROL_ERROR_INVALID_PARAMETER, __FUNCTION__, "invalid app_control reply");
return;
}
+ if (__exist_pending_item(appsvc_request_code)) {
+ info = __create_reply_info(appsvc_bundle,
+ appsvc_result, appsvc_data);
+ if (info) {
+ ret = __pending_item_set_reply_info(appsvc_request_code,
+ info);
+ if (ret == 0) {
+ LOGW("Reply info is pending");
+ return;
+ }
+ __destroy_reply_info(info);
+ }
+ }
+
if (app_control_create_reply(appsvc_bundle, &reply) != 0) {
app_control_error(APP_CONTROL_ERROR_INVALID_PARAMETER, __FUNCTION__, "failed to create app_control reply");
return;
app_control_request_context_h request_context;
app_control_error_e error = APP_CONTROL_ERROR_NONE;
app_control_h app_control;
+ struct result_info_s *info;
+ int ret;
+
+ if (__exist_pending_item(request_code)) {
+ info = __create_result_info(result, user_data);
+ if (info) {
+ ret = __pending_item_set_result_info(request_code,
+ info);
+ if (ret == 0) {
+ LOGW("Result info is pending");
+ return;
+ }
+ __destroy_result_info(info);
+ }
+ }
request_context = (app_control_request_context_h)user_data;
if (request_context == NULL) {
APP_CONTROL_OPERATION_DEFAULT);
}
+ if (req->request_context)
+ __add_pending_item(req->id);
+
if (req->result_cb) {
ret = aul_svc_send_launch_request_for_uid(app_control->data,
- app_control->id, reply_cb, result_cb,
+ req->id, reply_cb, result_cb,
req->request_context, getuid());
-
} else {
ret = aul_svc_run_service_for_uid(app_control->data,
- app_control->id, reply_cb,
+ req->id, reply_cb,
req->request_context, getuid());
}
bundle_del(req->app_control->data, BUNDLE_KEY_OPERATION);
if (ret < 0) {
+ if (req->request_context)
+ __remove_pending_item(req->id);
return app_control_error(__launch_request_convert_error(ret),
__FUNCTION__, NULL);
}
if (request_context)
__copy_callee_info(request_context->app_control, app_control);
- if (req->result_cb)
+ if (req->result_cb) {
+ __flush_pending_item(req->id);
return APP_CONTROL_ERROR_NONE;
+ }
if (!request_context)
return APP_CONTROL_ERROR_NONE;
__handle_app_started_result(app_control,
request_context->reply_cb ? request_context : NULL);
+ __flush_pending_item(req->id);
return APP_CONTROL_ERROR_NONE;
}
__FUNCTION__, NULL);
}
+ req.id = __generate_request_id();
for (i = 0; i < ARRAY_SIZE(handlers); i++) {
if (handlers[i]) {
ret = handlers[i](&req);
}
ret = aul_svc_send_launch_request_sync_for_uid(request->data,
- request->id, &reply_bundle, &appsvc_result, getuid());
+ req->id, &reply_bundle, &appsvc_result, getuid());
if (req->implicit_default_operation)
bundle_del(request->data, BUNDLE_KEY_OPERATION);
__FUNCTION__, NULL);
}
+ req.id = __generate_request_id();
for (i = 0; i < ARRAY_SIZE(handlers); i++) {
if (handlers[i]) {
ret = handlers[i](&req);