2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
22 #include <vconf-internal-keys.h>
23 #include <app_common.h>
25 #include <appcore_base.h>
26 #include <service_app.h>
27 #include <aul_job_scheduler.h>
28 #include <aul_rpc_port.h>
29 #include <bundle_internal.h>
32 #include "service_app_extension.h"
33 #include "service_app_internal.h"
39 #define LOG_TAG "CAPI_APPFW_APPLICATION"
41 extern int app_control_create_event(bundle *data, struct app_control_s **app_control);
44 APP_STATE_NOT_RUNNING,
49 struct app_event_handler {
50 app_event_type_e type;
56 struct app_event_info {
57 app_event_type_e type;
61 struct service_app_context {
62 service_app_lifecycle_callback_s callback;
69 struct service_app_job_s {
71 service_app_job_cb callback;
83 static struct service_app_context __context;
84 static app_state_e __app_state = APP_STATE_NOT_RUNNING;
86 static int __app_event_converter[APPCORE_BASE_EVENT_MAX] = {
87 [APP_EVENT_LOW_MEMORY] = APPCORE_BASE_EVENT_LOW_MEMORY,
88 [APP_EVENT_LOW_BATTERY] = APPCORE_BASE_EVENT_LOW_BATTERY,
89 [APP_EVENT_LANGUAGE_CHANGED] = APPCORE_BASE_EVENT_LANG_CHANGE,
90 [APP_EVENT_DEVICE_ORIENTATION_CHANGED] = APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED,
91 [APP_EVENT_REGION_FORMAT_CHANGED] = APPCORE_BASE_EVENT_REGION_CHANGE,
92 [APP_EVENT_SUSPENDED_STATE_CHANGED] = APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE,
95 static int __on_error(app_error_e error, const char *function, const char *description);
96 static void __destroy_job_handler(gpointer data);
97 static bool __exist_job_handler(const char *job_id);
99 static struct job_s *__create_job(int job_status, const char *job_id,
104 job = calloc(1, sizeof(struct job_s));
106 /* LCOV_EXCL_START */
107 LOGE("Out of memory");
112 job->job_id = strdup(job_id);
113 if (job->job_id == NULL) {
114 /* LCOV_EXCL_START */
115 LOGE("Out of memory");
121 job->job_data = bundle_dup(job_data);
122 if (job->job_data == NULL) {
123 /* LCOV_EXCL_START */
124 LOGE("Out of memory");
131 job->job_status = job_status;
136 static void __destroy_job(gpointer data)
138 struct job_s *job = (struct job_s *)data;
144 g_source_remove(job->idler); /* LCOV_EXCL_LINE */
146 g_source_remove(job->timer); /* LCOV_EXCL_LINE */
148 bundle_free(job->job_data);
154 /* LCOV_EXCL_START */
155 static gboolean __pending_job_timeout_handler(gpointer data)
157 struct job_s *job = (struct job_s *)data;
159 LOGE("[__TIMEOUT__] Job(%s) Status(%d)", job->job_id, job->job_status);
160 __context.pending_jobs = g_list_remove(__context.pending_jobs, job);
164 return G_SOURCE_REMOVE;
168 static void __job_finish(void)
170 if (__context.running_jobs) {
171 /* LCOV_EXCL_START */
172 g_list_free_full(__context.running_jobs, __destroy_job);
173 __context.running_jobs = NULL;
177 if (__context.pending_jobs) {
178 /* LCOV_EXCL_START */
179 g_list_free_full(__context.pending_jobs, __destroy_job);
180 __context.pending_jobs = NULL;
184 if (__context.job_handlers) {
185 g_list_free_full(__context.job_handlers, __destroy_job_handler);
186 __context.job_handlers = NULL;
190 static int __service_app_create(void *data)
192 appcore_base_on_create();
194 if (__context.callback.create == NULL ||
195 __context.callback.create(__context.data) == false)
196 return __on_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, "service_app_create_cb() returns false");
198 return APP_ERROR_NONE;
201 static int __service_app_terminate(void *data)
203 if (__context.callback.terminate)
204 __context.callback.terminate(__context.data);
206 appcore_base_on_terminate();
208 return APP_ERROR_NONE;
211 static int __service_app_control(bundle *b, void *data)
213 app_control_h app_control = NULL;
215 const char *rpc_port;
217 LOGD("[SERVICE_APP] app_control callback");
218 appcore_base_on_control(b);
220 job_id = bundle_get_val(b, AUL_K_JOB_ID);
222 LOGD("[__JOB__] Job(%s)", job_id);
226 rpc_port = bundle_get_val(b, AUL_K_RPC_PORT);
228 LOGD("[__RPC_PORT_PORT__] %s", rpc_port);
232 if (app_control_create_event(b, &app_control) != 0)
235 if (__context.callback.app_control)
236 __context.callback.app_control(app_control, __context.data);
238 app_control_destroy(app_control);
243 static void __loop_init(int argc, char **argv, void *data)
248 static void __loop_fini(void)
253 static void __loop_run(void *data)
255 ecore_main_loop_begin();
258 static void __loop_exit(void *data)
260 ecore_main_loop_quit();
263 static const char *__error_to_string(app_error_e error)
268 case APP_ERROR_INVALID_PARAMETER:
269 return "INVALID_PARAMETER";
270 case APP_ERROR_OUT_OF_MEMORY:
271 return "OUT_OF_MEMORY";
272 case APP_ERROR_INVALID_CONTEXT:
273 return "INVALID_CONTEXT";
274 case APP_ERROR_NO_SUCH_FILE:
275 return "NO_SUCH_FILE";
276 case APP_ERROR_ALREADY_RUNNING:
277 return "ALREADY_RUNNING";
283 static int __on_error(app_error_e error, const char *function, const char *description)
286 LOGE("[%s] %s(0x%08x) : %s", function, __error_to_string(error), error, description);
288 LOGE("[%s] %s(0x%08x)", function, __error_to_string(error), error);
293 EXPORT_API int service_app_main_ext(int argc, char **argv, service_app_lifecycle_callback_s *callback,
294 service_app_loop_method_s *method, void *user_data)
297 appcore_base_ops ops = appcore_base_get_default_ops();
299 if (argc < 1 || argv == NULL || callback == NULL || method == NULL)
300 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
302 if (callback->create == NULL)
303 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "service_app_create_cb() callback must be registered");
305 if (__app_state != APP_STATE_NOT_RUNNING)
306 return __on_error(APP_ERROR_ALREADY_RUNNING, __FUNCTION__, NULL); /* LCOV_EXCL_LINE */
308 /* override methods */
309 ops.create = __service_app_create;
310 ops.terminate = __service_app_terminate;
311 ops.control = __service_app_control;
312 ops.run = method->run;
313 ops.exit = method->exit;
314 ops.init = method->init;
315 ops.finish = method->fini;
317 __context.callback = *callback;
318 __context.data = user_data;
320 __app_state = APP_STATE_CREATING;
321 ret = appcore_base_init(ops, argc, argv, NULL);
323 /* LCOV_EXCL_START */
324 __app_state = APP_STATE_NOT_RUNNING;
325 return __on_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
331 __app_state = APP_STATE_NOT_RUNNING;
332 return APP_ERROR_NONE;
335 EXPORT_API int service_app_main(int argc, char **argv, service_app_lifecycle_callback_s *callback, void *user_data)
337 service_app_loop_method_s method = {
344 return service_app_main_ext(argc, argv, callback, &method, user_data);
347 EXPORT_API void service_app_exit(void)
352 static int __event_cb(void *event, void *data)
354 app_event_handler_h handler = data;
356 struct app_event_info app_event;
358 app_event.type = handler->type;
359 app_event.value = event;
362 handler->cb(&app_event, handler->data);
366 EXPORT_API int service_app_add_event_handler(app_event_handler_h *event_handler, app_event_type_e event_type, app_event_cb callback, void *user_data)
368 app_event_handler_h handler;
370 if (event_handler == NULL || callback == NULL)
371 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "null parameter");
373 if (event_type < APP_EVENT_LOW_MEMORY || event_type > APP_EVENT_SUSPENDED_STATE_CHANGED ||
374 event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED)
375 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "invalid event type");
377 handler = calloc(1, sizeof(struct app_event_handler));
379 return __on_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__, "insufficient memory"); /* LCOV_EXCL_LINE */
381 handler->type = event_type;
382 handler->cb = callback;
383 handler->data = user_data;
384 handler->raw = appcore_base_add_event(__app_event_converter[event_type], __event_cb, handler);
386 *event_handler = handler;
388 return APP_ERROR_NONE;
391 EXPORT_API int service_app_remove_event_handler(app_event_handler_h event_handler)
394 app_event_type_e type;
396 if (event_handler == NULL)
397 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
399 type = event_handler->type;
400 if (type < APP_EVENT_LOW_MEMORY ||
401 type > APP_EVENT_SUSPENDED_STATE_CHANGED ||
402 type == APP_EVENT_DEVICE_ORIENTATION_CHANGED)
403 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); /* LCOV_EXCL_LINE */
405 ret = appcore_base_remove_event(event_handler->raw);
409 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); /* LCOV_EXCL_LINE */
411 return APP_ERROR_NONE;
414 EXPORT_API void service_app_exit_without_restart(void)
416 aul_status_update(STATUS_NORESTART);
420 static void __invoke_job_callback(int status, const char *job_id,
423 struct service_app_job_s *handle;
426 iter = __context.job_handlers;
428 handle = (struct service_app_job_s *)iter->data;
430 if (strcmp(handle->job_id, job_id) == 0) {
431 handle->callback(status, job_id, job_data,
437 static gboolean __handle_job(gpointer data)
439 struct job_s *job = (struct job_s *)data;
441 __context.running_jobs = g_list_remove(__context.running_jobs, job);
443 LOGD("[__JOB___] Job(%s) Status(%d) START",
444 job->job_id, job->job_status);
445 if (job->job_status == SERVICE_APP_JOB_STATUS_START) {
446 aul_job_scheduler_update_job_status(job->job_id,
448 __invoke_job_callback(job->job_status, job->job_id,
451 __invoke_job_callback(job->job_status, job->job_id,
453 aul_job_scheduler_update_job_status(job->job_id,
456 LOGD("[__JOB__] Job(%s) Status(%d) END",
457 job->job_id, job->job_status);
462 return G_SOURCE_REMOVE;
465 static void __flush_pending_job(const char *job_id)
470 iter = __context.pending_jobs;
472 /* LCOV_EXCL_START */
473 job = (struct job_s *)iter->data;
475 if (strcmp(job->job_id, job_id) == 0) {
476 __context.pending_jobs = g_list_remove(
477 __context.pending_jobs, job);
480 g_source_remove(job->timer);
484 job->idler = g_idle_add(__handle_job, job);
485 __context.running_jobs = g_list_append(
486 __context.running_jobs, job);
492 static bool __exist_job_handler(const char *job_id)
494 struct service_app_job_s *handle;
497 iter = __context.job_handlers;
499 handle = (struct service_app_job_s *)iter->data;
500 if (strcmp(handle->job_id, job_id) == 0)
509 static struct service_app_job_s *__create_job_handler(const char *job_id,
510 service_app_job_cb callback, void *user_data)
512 struct service_app_job_s *handle;
514 handle = calloc(1, sizeof(struct service_app_job_s));
515 if (handle == NULL) {
516 /* LCOV_EXCL_START */
517 LOGE("Out of memory");
522 handle->job_id = strdup(job_id);
523 if (handle->job_id == NULL) {
524 /* LCOV_EXCL_START */
525 LOGE("Out of memory");
531 handle->callback = callback;
532 handle->user_data = user_data;
537 static void __destroy_job_handler(gpointer data)
539 struct service_app_job_s *handle = (struct service_app_job_s *)data;
545 free(handle->job_id);
549 EXPORT_API service_app_job_h service_app_add_job_handler(const char *job_id,
550 service_app_job_cb callback, void *user_data)
552 struct service_app_job_s *handle;
554 if (job_id == NULL || callback == NULL) {
555 /* LCOV_EXCL_START */
556 LOGE("Invalid parameter");
561 handle = __create_job_handler(job_id, callback, user_data);
565 __context.job_handlers = g_list_append(__context.job_handlers, handle);
567 __flush_pending_job(job_id);
572 EXPORT_API int service_app_remove_job_handler(service_app_job_h handle)
574 if (handle == NULL ||
575 g_list_index(__context.job_handlers, handle) < 0) {
576 /* LCOV_EXCL_START */
577 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__,
582 __context.job_handlers = g_list_remove(__context.job_handlers, handle);
584 __destroy_job_handler(handle);
586 return APP_ERROR_NONE;
589 EXPORT_API int service_app_job_raise(int job_status, const char *job_id,
594 if (job_status < SERVICE_APP_JOB_STATUS_START ||
595 job_status > SERVICE_APP_JOB_STATUS_STOP ||
596 job_id == NULL || job_data == NULL) {
597 /* LCOV_EXCL_START */
598 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__,
603 job = __create_job(job_status, job_id, job_data);
605 return __on_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL); /* LCOV_EXCL_LINE */
607 if (!__exist_job_handler(job_id)) {
608 /* LCOV_EXCL_START */
609 job->timer = g_timeout_add(5000, __pending_job_timeout_handler,
611 __context.pending_jobs = g_list_append(__context.pending_jobs,
615 job->idler = g_idle_add(__handle_job, job);
616 __context.running_jobs = g_list_append(__context.running_jobs,
620 return APP_ERROR_NONE;
623 static void __remove_running_job(const char *job_id)
628 iter = __context.running_jobs;
630 /* LCOV_EXCL_START */
631 job = (struct job_s *)iter->data;
633 if (strcmp(job->job_id, job_id) == 0) {
634 __context.running_jobs = g_list_remove(
635 __context.running_jobs, job);
642 EXPORT_API int service_app_job_finished(const char *job_id)
646 if (job_id == NULL) {
647 /* LCOV_EXCL_START */
648 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__,
653 __remove_running_job(job_id);
655 r = aul_job_scheduler_update_job_status(job_id, JOB_STATUS_FINISHED);
657 /* LCOV_EXCL_START */
658 return __on_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__,
663 return APP_ERROR_NONE;