Add Job Handler 91/149891/7
authorHwankyu Jhun <h.jhun@samsung.com>
Wed, 13 Sep 2017 11:41:52 +0000 (20:41 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Tue, 19 Sep 2017 22:51:07 +0000 (07:51 +0900)
When the application is launched by the job scheduler, the service core
finds the job handler. And then, the handler will be invoked.
If the request is for processing the job when the application is running,
the reset callback will not be invoked.

Change-Id: Ie76211330024f18ffcde0cdefa3cc782c1a95871
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
include/service_app_internal.h
src/service_app_main.c

index 43aa2f4..1d5b0cc 100644 (file)
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <service_app.h>
+#include <bundle.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -93,6 +94,80 @@ int service_app_main_ext(int argc, char **argv, service_app_lifecycle_callback_s
               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
index aea30cc..a9158bc 100644 (file)
@@ -24,6 +24,9 @@
 #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"
@@ -57,6 +60,23 @@ struct app_event_info {
 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;
@@ -72,6 +92,87 @@ static int __app_event_converter[APPCORE_BASE_EVENT_MAX] = {
 };
 
 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)
 {
@@ -97,10 +198,17 @@ static int __service_app_terminate(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;
 
@@ -197,6 +305,7 @@ EXPORT_API int service_app_main_ext(int argc, char **argv, service_app_lifecycle
        }
 
        appcore_base_fini();
+       __job_finish();
        __app_state = APP_STATE_NOT_RUNNING;
        return APP_ERROR_NONE;
 }
@@ -286,4 +395,228 @@ EXPORT_API void service_app_exit_without_restart(void)
        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;
+}