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 <bundle_internal.h>
30 #include <app_control_internal.h>
32 #include "service_app_extension.h"
33 #include "service_app_internal.h"
39 #define LOG_TAG "CAPI_APPFW_APPLICATION"
42 APP_STATE_NOT_RUNNING,
47 struct app_event_handler {
48 app_event_type_e type;
54 struct app_event_info {
55 app_event_type_e type;
59 struct service_app_context {
60 service_app_lifecycle_callback_s callback;
67 struct service_app_job_s {
69 service_app_job_cb callback;
81 static struct service_app_context __context;
82 static app_state_e __app_state = APP_STATE_NOT_RUNNING;
84 static int __app_event_converter[APPCORE_BASE_EVENT_MAX] = {
85 [APP_EVENT_LOW_MEMORY] = APPCORE_BASE_EVENT_LOW_MEMORY,
86 [APP_EVENT_LOW_BATTERY] = APPCORE_BASE_EVENT_LOW_BATTERY,
87 [APP_EVENT_LANGUAGE_CHANGED] = APPCORE_BASE_EVENT_LANG_CHANGE,
88 [APP_EVENT_DEVICE_ORIENTATION_CHANGED] = APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED,
89 [APP_EVENT_REGION_FORMAT_CHANGED] = APPCORE_BASE_EVENT_REGION_CHANGE,
90 [APP_EVENT_SUSPENDED_STATE_CHANGED] = APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE,
93 static int __on_error(app_error_e error, const char *function, const char *description);
94 static void __destroy_job_handler(gpointer data);
95 static bool __exist_job_handler(const char *job_id);
97 static struct job_s *__create_job(int job_status, const char *job_id,
102 job = calloc(1, sizeof(struct job_s));
104 /* LCOV_EXCL_START */
105 LOGE("Out of memory");
110 job->job_id = strdup(job_id);
111 if (job->job_id == NULL) {
112 /* LCOV_EXCL_START */
113 LOGE("Out of memory");
119 job->job_data = bundle_dup(job_data);
120 if (job->job_data == NULL) {
121 /* LCOV_EXCL_START */
122 LOGE("Out of memory");
129 job->job_status = job_status;
134 static void __destroy_job(gpointer data)
136 struct job_s *job = (struct job_s *)data;
142 g_source_remove(job->idler); /* LCOV_EXCL_LINE */
144 g_source_remove(job->timer); /* LCOV_EXCL_LINE */
146 bundle_free(job->job_data);
152 /* LCOV_EXCL_START */
153 static gboolean __pending_job_timeout_handler(gpointer data)
155 struct job_s *job = (struct job_s *)data;
157 LOGE("[__TIMEOUT__] Job(%s) Status(%d)", job->job_id, job->job_status);
158 __context.pending_jobs = g_list_remove(__context.pending_jobs, job);
162 return G_SOURCE_REMOVE;
166 static void __job_finish(void)
168 if (__context.running_jobs) {
169 /* LCOV_EXCL_START */
170 g_list_free_full(__context.running_jobs, __destroy_job);
171 __context.running_jobs = NULL;
175 if (__context.pending_jobs) {
176 /* LCOV_EXCL_START */
177 g_list_free_full(__context.pending_jobs, __destroy_job);
178 __context.pending_jobs = NULL;
182 if (__context.job_handlers) {
183 g_list_free_full(__context.job_handlers, __destroy_job_handler);
184 __context.job_handlers = NULL;
188 static int __service_app_create(void *data)
190 LOGW("service_app_create()");
191 appcore_base_on_create();
193 if (__context.callback.create == NULL ||
194 __context.callback.create(__context.data) == false)
195 return __on_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, "service_app_create_cb() returns false");
197 return APP_ERROR_NONE;
200 static int __service_app_terminate(void *data)
202 LOGW("service_app_terminate()");
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;
216 LOGW("service_app_control()");
217 appcore_base_on_control(b);
219 job_id = bundle_get_val(b, AUL_K_JOB_ID);
221 LOGD("[__JOB__] Job(%s)", job_id);
225 if (app_control_create_event(b, &app_control) != 0)
228 if (__context.callback.app_control)
229 __context.callback.app_control(app_control, __context.data);
231 app_control_destroy(app_control);
236 static int __service_app_receive(aul_type type, bundle *b, void *data)
238 appcore_base_on_receive(type, b);
240 if (type == AUL_TERMINATE_BGAPP) {
248 static void __loop_init(int argc, char **argv, void *data)
253 static void __loop_fini(void)
258 static void __loop_run(void *data)
260 ecore_main_loop_begin();
263 static void __exit_main_loop(void *data)
265 ecore_main_loop_quit();
268 static void __loop_exit(void *data)
270 ecore_main_loop_thread_safe_call_sync((Ecore_Data_Cb)__exit_main_loop, NULL);
273 static const char *__error_to_string(app_error_e error)
278 case APP_ERROR_INVALID_PARAMETER:
279 return "INVALID_PARAMETER";
280 case APP_ERROR_OUT_OF_MEMORY:
281 return "OUT_OF_MEMORY";
282 case APP_ERROR_INVALID_CONTEXT:
283 return "INVALID_CONTEXT";
284 case APP_ERROR_NO_SUCH_FILE:
285 return "NO_SUCH_FILE";
286 case APP_ERROR_ALREADY_RUNNING:
287 return "ALREADY_RUNNING";
293 static int __on_error(app_error_e error, const char *function, const char *description)
296 LOGE("[%s] %s(0x%08x) : %s", function, __error_to_string(error), error, description);
298 LOGE("[%s] %s(0x%08x)", function, __error_to_string(error), error);
303 EXPORT_API int service_app_main_ext(int argc, char **argv, service_app_lifecycle_callback_s *callback,
304 service_app_loop_method_s *method, void *user_data)
307 appcore_base_ops ops = appcore_base_get_default_ops();
309 if (argc < 1 || argv == NULL || callback == NULL || method == NULL)
310 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
312 if (callback->create == NULL)
313 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "service_app_create_cb() callback must be registered");
315 if (__app_state != APP_STATE_NOT_RUNNING)
316 return __on_error(APP_ERROR_ALREADY_RUNNING, __FUNCTION__, NULL); /* LCOV_EXCL_LINE */
318 /* override methods */
319 ops.create = __service_app_create;
320 ops.terminate = __service_app_terminate;
321 ops.control = __service_app_control;
322 ops.receive = __service_app_receive;
323 ops.run = method->run;
324 ops.exit = method->exit;
325 ops.init = method->init;
326 ops.finish = method->fini;
328 __context.callback = *callback;
329 __context.data = user_data;
331 __app_state = APP_STATE_CREATING;
332 ret = appcore_base_init(ops, argc, argv, NULL);
334 /* LCOV_EXCL_START */
335 __app_state = APP_STATE_NOT_RUNNING;
336 return __on_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
342 __app_state = APP_STATE_NOT_RUNNING;
343 return APP_ERROR_NONE;
346 EXPORT_API int service_app_main(int argc, char **argv, service_app_lifecycle_callback_s *callback, void *user_data)
348 service_app_loop_method_s method = {
355 LOGW("service_app_main()");
356 return service_app_main_ext(argc, argv, callback, &method, user_data);
359 EXPORT_API void service_app_exit(void)
361 LOGW("service_app_exit()");
365 static int __event_cb(void *event, void *data)
367 app_event_handler_h handler = data;
369 struct app_event_info app_event;
371 app_event.type = handler->type;
372 app_event.value = event;
375 handler->cb(&app_event, handler->data);
379 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)
381 app_event_handler_h handler;
383 if (event_handler == NULL || callback == NULL)
384 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "null parameter");
386 if (event_type < APP_EVENT_LOW_MEMORY || event_type > APP_EVENT_SUSPENDED_STATE_CHANGED ||
387 event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED)
388 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "invalid event type");
390 handler = calloc(1, sizeof(struct app_event_handler));
392 return __on_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__, "insufficient memory"); /* LCOV_EXCL_LINE */
394 handler->type = event_type;
395 handler->cb = callback;
396 handler->data = user_data;
397 handler->raw = appcore_base_add_event(__app_event_converter[event_type], __event_cb, handler);
399 *event_handler = handler;
401 return APP_ERROR_NONE;
404 EXPORT_API int service_app_remove_event_handler(app_event_handler_h event_handler)
407 app_event_type_e type;
409 if (event_handler == NULL)
410 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
412 type = event_handler->type;
413 if (type < APP_EVENT_LOW_MEMORY ||
414 type > APP_EVENT_SUSPENDED_STATE_CHANGED ||
415 type == APP_EVENT_DEVICE_ORIENTATION_CHANGED)
416 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); /* LCOV_EXCL_LINE */
418 ret = appcore_base_remove_event(event_handler->raw);
422 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); /* LCOV_EXCL_LINE */
424 return APP_ERROR_NONE;
427 EXPORT_API void service_app_exit_without_restart(void)
429 aul_status_update_v2(STATUS_NORESTART);
433 static void __invoke_job_callback(int status, const char *job_id,
436 struct service_app_job_s *handle;
439 iter = __context.job_handlers;
441 handle = (struct service_app_job_s *)iter->data;
443 if (strcmp(handle->job_id, job_id) == 0) {
444 handle->callback(status, job_id, job_data,
450 static gboolean __handle_job(gpointer data)
452 struct job_s *job = (struct job_s *)data;
454 __context.running_jobs = g_list_remove(__context.running_jobs, job);
456 LOGD("[__JOB___] Job(%s) Status(%d) START",
457 job->job_id, job->job_status);
458 if (job->job_status == SERVICE_APP_JOB_STATUS_START) {
459 aul_job_scheduler_update_job_status(job->job_id,
461 __invoke_job_callback(job->job_status, job->job_id,
464 __invoke_job_callback(job->job_status, job->job_id,
466 aul_job_scheduler_update_job_status(job->job_id,
469 LOGD("[__JOB__] Job(%s) Status(%d) END",
470 job->job_id, job->job_status);
475 return G_SOURCE_REMOVE;
478 static void __flush_pending_job(const char *job_id)
483 iter = __context.pending_jobs;
485 /* LCOV_EXCL_START */
486 job = (struct job_s *)iter->data;
488 if (strcmp(job->job_id, job_id) == 0) {
489 __context.pending_jobs = g_list_remove(
490 __context.pending_jobs, job);
493 g_source_remove(job->timer);
497 job->idler = g_idle_add(__handle_job, job);
498 __context.running_jobs = g_list_append(
499 __context.running_jobs, job);
505 static bool __exist_job_handler(const char *job_id)
507 struct service_app_job_s *handle;
510 iter = __context.job_handlers;
512 handle = (struct service_app_job_s *)iter->data;
513 if (strcmp(handle->job_id, job_id) == 0)
522 static struct service_app_job_s *__create_job_handler(const char *job_id,
523 service_app_job_cb callback, void *user_data)
525 struct service_app_job_s *handle;
527 handle = calloc(1, sizeof(struct service_app_job_s));
528 if (handle == NULL) {
529 /* LCOV_EXCL_START */
530 LOGE("Out of memory");
535 handle->job_id = strdup(job_id);
536 if (handle->job_id == NULL) {
537 /* LCOV_EXCL_START */
538 LOGE("Out of memory");
544 handle->callback = callback;
545 handle->user_data = user_data;
550 static void __destroy_job_handler(gpointer data)
552 struct service_app_job_s *handle = (struct service_app_job_s *)data;
558 free(handle->job_id);
562 EXPORT_API service_app_job_h service_app_add_job_handler(const char *job_id,
563 service_app_job_cb callback, void *user_data)
565 struct service_app_job_s *handle;
567 if (job_id == NULL || callback == NULL) {
568 /* LCOV_EXCL_START */
569 LOGE("Invalid parameter");
574 handle = __create_job_handler(job_id, callback, user_data);
578 __context.job_handlers = g_list_append(__context.job_handlers, handle);
580 __flush_pending_job(job_id);
585 EXPORT_API int service_app_remove_job_handler(service_app_job_h handle)
587 if (handle == NULL ||
588 g_list_index(__context.job_handlers, handle) < 0) {
589 /* LCOV_EXCL_START */
590 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__,
595 __context.job_handlers = g_list_remove(__context.job_handlers, handle);
597 __destroy_job_handler(handle);
599 return APP_ERROR_NONE;
602 EXPORT_API int service_app_job_raise(int job_status, const char *job_id,
607 if (job_status < SERVICE_APP_JOB_STATUS_START ||
608 job_status > SERVICE_APP_JOB_STATUS_STOP ||
609 job_id == NULL || job_data == NULL) {
610 /* LCOV_EXCL_START */
611 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__,
616 job = __create_job(job_status, job_id, job_data);
618 return __on_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL); /* LCOV_EXCL_LINE */
620 if (!__exist_job_handler(job_id)) {
621 /* LCOV_EXCL_START */
622 job->timer = g_timeout_add(5000, __pending_job_timeout_handler,
624 __context.pending_jobs = g_list_append(__context.pending_jobs,
628 job->idler = g_idle_add(__handle_job, job);
629 __context.running_jobs = g_list_append(__context.running_jobs,
633 return APP_ERROR_NONE;
636 static void __remove_running_job(const char *job_id)
641 iter = __context.running_jobs;
643 /* LCOV_EXCL_START */
644 job = (struct job_s *)iter->data;
646 if (strcmp(job->job_id, job_id) == 0) {
647 __context.running_jobs = g_list_remove(
648 __context.running_jobs, job);
655 EXPORT_API int service_app_job_finished(const char *job_id)
659 if (job_id == NULL) {
660 /* LCOV_EXCL_START */
661 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__,
666 __remove_running_job(job_id);
668 r = aul_job_scheduler_update_job_status(job_id, JOB_STATUS_FINISHED);
670 /* LCOV_EXCL_START */
671 return __on_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__,
676 return APP_ERROR_NONE;