#pragma once
#include <service_app.h>
+#include <bundle.h>
#ifdef __cplusplus
extern "C" {
service_app_loop_method_s *method, void *user_data);
+/**
+ * @brief Enumeration for the job handler
+ * @since_tizen 4.0
+ * @remarks This is for App Framework internally.
+ */
+typedef enum {
+ SERVICE_APP_JOB_STATUS_START,
+ SERVICE_APP_JOB_STATUS_STOP,
+} service_app_job_status_e;
+
+/**
+ * @brief Called when the job is triggered.
+ * @since_tizen 4.0
+ * @param[in] job_status The status of the job
+ * @param[in] job_id The ID of the job
+ * @param[in] job_data The data of the job
+ * @param[in] user_data The user data passed from the callback registration function
+ * @remarks This is for App Framework internally.
+ */
+typedef int (*service_app_job_cb)(int job_status, const char *job_id,
+ bundle *job_data, void *user_data);
+
+/**
+ * @brief The job handle.
+ * @since_tizen 4.0
+ * @remarks This is for App Framework internally.
+ */
+typedef struct service_app_job_s *service_app_job_h;
+
+/**
+ * @brief Adds the job handler.
+ * @since_tizen 4.0
+ * @param[in] job_id The ID of the job
+ * @param[in] callback The job callback function
+ * @param[in] user_data The user data to be passed to the callback function
+ * @return @c the job handler on success,
+ * otherwise NULL.
+ * @remarks This is for App Framework internally.
+ */
+service_app_job_h service_app_add_job_handler(const char *job_id,
+ service_app_job_cb callback, void *user_data);
+
+/**
+ * @brief Removes the registered job handler.
+ * @since_tizen 4.0
+ * @param[in] handle The job handle
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @remarks This is for App Framework internally.
+ */
+int service_app_remove_job_handler(service_app_job_h handle);
+
+/**
+ * @brief Raises the job.
+ * @since_tizen 4.0
+ * @param[in] job_status The status of the job
+ * @param[in] job_id The ID of the job
+ * @param[in] job_data The data of the job
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @remarks This is for App Framework internally.
+ */
+int service_app_job_raise(int job_status, const char *job_id, bundle *job_data);
+
+/**
+ * @brief Notifies that the job is finished.
+ * @since_tizen 4.0
+ * @param[in] job_id The ID of the job
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @remarks This is for App Framework internally.
+ */
+int service_app_job_finished(const char *job_id);
+
#ifdef __cplusplus
}
#endif
#include <Ecore.h>
#include <appcore_base.h>
#include <service_app.h>
+#include <aul_job_scheduler.h>
+#include <bundle_internal.h>
+#include <glib.h>
#include "service_app_extension.h"
#include "service_app_internal.h"
struct service_app_context {
service_app_lifecycle_callback_s callback;
void *data;
+ GList *running_jobs;
+ GList *pending_jobs;
+ GList *job_handlers;
+};
+
+struct service_app_job_s {
+ char *job_id;
+ service_app_job_cb callback;
+ void *user_data;
+};
+
+struct job_s {
+ int job_status;
+ char *job_id;
+ bundle *job_data;
+ guint timer;
+ guint idler;
};
static struct service_app_context __context;
};
static int __on_error(app_error_e error, const char *function, const char *description);
+static void __destroy_job_handler(gpointer data);
+static bool __exist_job_handler(const char *job_id);
+
+static struct job_s *__create_job(int job_status, const char *job_id,
+ bundle *job_data)
+{
+ struct job_s *job;
+
+ job = calloc(1, sizeof(struct job_s));
+ if (job == NULL) {
+ LOGE("Out of memory");
+ return NULL;
+ }
+
+ job->job_id = strdup(job_id);
+ if (job->job_id == NULL) {
+ LOGE("Out of memory");
+ free(job);
+ return NULL;
+ }
+
+ job->job_data = bundle_dup(job_data);
+ if (job->job_data == NULL) {
+ LOGE("Out of memory");
+ free(job->job_id);
+ free(job);
+ return NULL;
+ }
+
+ job->job_status = job_status;
+
+ return job;
+}
+
+static void __destroy_job(gpointer data)
+{
+ struct job_s *job = (struct job_s *)data;
+
+ if (job == NULL)
+ return;
+
+ if (job->idler)
+ g_source_remove(job->idler);
+ if (job->timer)
+ g_source_remove(job->timer);
+ if (job->job_data)
+ bundle_free(job->job_data);
+ if (job->job_id)
+ free(job->job_id);
+ free(job);
+}
+
+static gboolean __pending_job_timeout_handler(gpointer data)
+{
+ struct job_s *job = (struct job_s *)data;
+
+ LOGE("[__TIMEOUT__] Job(%s) Status(%d)", job->job_id, job->job_status);
+ __context.pending_jobs = g_list_remove(__context.pending_jobs, job);
+ job->timer = 0;
+ __destroy_job(job);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void __job_finish(void)
+{
+ if (__context.running_jobs) {
+ g_list_free_full(__context.running_jobs, __destroy_job);
+ __context.running_jobs = NULL;
+ }
+
+ if (__context.pending_jobs) {
+ g_list_free_full(__context.pending_jobs, __destroy_job);
+ __context.pending_jobs = NULL;
+ }
+
+ if (__context.job_handlers) {
+ g_list_free_full(__context.job_handlers, __destroy_job_handler);
+ __context.job_handlers = NULL;
+ }
+}
static int __service_app_create(void *data)
{
static int __service_app_control(bundle *b, void *data)
{
app_control_h app_control = NULL;
+ const char *job_id;
LOGD("[SERVICE_APP] app_control callback");
appcore_base_on_control(b);
+ job_id = bundle_get_val(b, AUL_K_JOB_ID);
+ if (job_id) {
+ LOGD("[__JOB__] Job(%s)", job_id);
+ return 0;
+ }
+
if (app_control_create_event(b, &app_control) != 0)
return -1;
}
appcore_base_fini();
+ __job_finish();
__app_state = APP_STATE_NOT_RUNNING;
return APP_ERROR_NONE;
}
appcore_base_exit();
}
+static void __invoke_job_callback(int status, const char *job_id,
+ bundle *job_data)
+{
+ struct service_app_job_s *handle;
+ GList *iter;
+
+ iter = __context.job_handlers;
+ while (iter) {
+ handle = (struct service_app_job_s *)iter->data;
+ iter = iter->next;
+ if (strcmp(handle->job_id, job_id) == 0) {
+ handle->callback(status, job_id, job_data,
+ handle->user_data);
+ }
+ }
+}
+
+static gboolean __handle_job(gpointer data)
+{
+ struct job_s *job = (struct job_s *)data;
+
+ __context.running_jobs = g_list_remove(__context.running_jobs, job);
+
+ LOGD("[__JOB___] Job(%s) Status(%d) START",
+ job->job_id, job->job_status);
+ if (job->job_status == SERVICE_APP_JOB_STATUS_START) {
+ aul_job_scheduler_update_job_status(job->job_id,
+ JOB_STATUS_START);
+ __invoke_job_callback(job->job_status, job->job_id,
+ job->job_data);
+ } else {
+ __invoke_job_callback(job->job_status, job->job_id,
+ job->job_data);
+ aul_job_scheduler_update_job_status(job->job_id,
+ JOB_STATUS_STOPPED);
+ }
+ LOGD("[__JOB__] Job(%s) Status(%d) END",
+ job->job_id, job->job_status);
+
+ job->idler = 0;
+ __destroy_job(job);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void __flush_pending_job(const char *job_id)
+{
+ struct job_s *job;
+ GList *iter;
+
+ iter = __context.pending_jobs;
+ while (iter) {
+ job = (struct job_s *)iter->data;
+ iter = iter->next;
+ if (strcmp(job->job_id, job_id) == 0) {
+ __context.pending_jobs = g_list_remove(
+ __context.pending_jobs, job);
+
+ if (job->timer) {
+ g_source_remove(job->timer);
+ job->timer = 0;
+ }
+
+ job->idler = g_idle_add(__handle_job, job);
+ __context.running_jobs = g_list_append(
+ __context.running_jobs, job);
+ }
+ }
+}
+
+static bool __exist_job_handler(const char *job_id)
+{
+ struct service_app_job_s *handle;
+ GList *iter;
+
+ iter = __context.job_handlers;
+ while (iter) {
+ handle = (struct service_app_job_s *)iter->data;
+ if (strcmp(handle->job_id, job_id) == 0)
+ return true;
+
+ iter = iter->next;
+ }
+
+ return false;
+}
+
+static struct service_app_job_s *__create_job_handler(const char *job_id,
+ service_app_job_cb callback, void *user_data)
+{
+ struct service_app_job_s *handle;
+
+ handle = calloc(1, sizeof(struct service_app_job_s));
+ if (handle == NULL) {
+ LOGE("Out of memory");
+ return NULL;
+ }
+
+ handle->job_id = strdup(job_id);
+ if (handle->job_id == NULL) {
+ LOGE("Out of memory");
+ free(handle);
+ return NULL;
+ }
+
+ handle->callback = callback;
+ handle->user_data = user_data;
+
+ return handle;
+}
+
+static void __destroy_job_handler(gpointer data)
+{
+ struct service_app_job_s *handle = (struct service_app_job_s *)data;
+
+ if (handle == NULL)
+ return;
+
+ if (handle->job_id)
+ free(handle->job_id);
+ free(handle);
+}
+
+EXPORT_API service_app_job_h service_app_add_job_handler(const char *job_id,
+ service_app_job_cb callback, void *user_data)
+{
+ struct service_app_job_s *handle;
+
+ if (job_id == NULL || callback == NULL) {
+ LOGE("Invalid parameter");
+ return NULL;
+ }
+
+ handle = __create_job_handler(job_id, callback, user_data);
+ if (handle == NULL)
+ return NULL;
+
+ __context.job_handlers = g_list_append(__context.job_handlers, handle);
+
+ __flush_pending_job(job_id);
+
+ return handle;
+}
+
+EXPORT_API int service_app_remove_job_handler(service_app_job_h handle)
+{
+ if (handle == NULL ||
+ g_list_index(__context.job_handlers, handle) < 0) {
+ return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__,
+ NULL);
+ }
+
+ __context.job_handlers = g_list_remove(__context.job_handlers, handle);
+ __destroy_job_handler(handle);
+
+ return APP_ERROR_NONE;
+}
+
+EXPORT_API int service_app_job_raise(int job_status, const char *job_id,
+ bundle *job_data)
+{
+ struct job_s *job;
+
+ if (job_status < SERVICE_APP_JOB_STATUS_START ||
+ job_status > SERVICE_APP_JOB_STATUS_STOP ||
+ job_id == NULL || job_data == NULL) {
+ return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__,
+ NULL);
+ }
+
+ job = __create_job(job_status, job_id, job_data);
+ if (job == NULL)
+ return __on_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
+
+ if (!__exist_job_handler(job_id)) {
+ job->timer = g_timeout_add(5000, __pending_job_timeout_handler,
+ job);
+ __context.pending_jobs = g_list_append(__context.pending_jobs,
+ job);
+ } else {
+ job->idler = g_idle_add(__handle_job, job);
+ __context.running_jobs = g_list_append(__context.running_jobs,
+ job);
+ }
+
+ return APP_ERROR_NONE;
+}
+
+static void __remove_running_job(const char *job_id)
+{
+ struct job_s *job;
+ GList *iter;
+
+ iter = __context.running_jobs;
+ while (iter) {
+ job = (struct job_s *)iter->data;
+ iter = iter->next;
+ if (strcmp(job->job_id, job_id) == 0) {
+ __context.running_jobs = g_list_remove(
+ __context.running_jobs, job);
+ __destroy_job(job);
+ }
+ }
+}
+
+EXPORT_API int service_app_job_finished(const char *job_id)
+{
+ int r;
+
+ if (job_id == NULL) {
+ return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__,
+ NULL);
+ }
+
+ __remove_running_job(job_id);
+
+ r = aul_job_scheduler_update_job_status(job_id, JOB_STATUS_FINISHED);
+ if (r != AUL_R_OK) {
+ return __on_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__,
+ NULL);
+ }
+
+ return APP_ERROR_NONE;
+}