Handle RPC request
[platform/core/appfw/appcore-agent.git] / src / service_app_main.c
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <bundle.h>
20 #include <aul.h>
21 #include <dlog.h>
22 #include <vconf-internal-keys.h>
23 #include <app_common.h>
24 #include <Ecore.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>
30 #include <glib.h>
31
32 #include "service_app_extension.h"
33 #include "service_app_internal.h"
34
35 #ifdef LOG_TAG
36 #undef LOG_TAG
37 #endif
38
39 #define LOG_TAG "CAPI_APPFW_APPLICATION"
40
41 extern int app_control_create_event(bundle *data, struct app_control_s **app_control);
42
43 typedef enum {
44         APP_STATE_NOT_RUNNING,
45         APP_STATE_CREATING,
46         APP_STATE_RUNNING,
47 } app_state_e;
48
49 struct app_event_handler {
50         app_event_type_e type;
51         app_event_cb cb;
52         void *data;
53         void* raw;
54 };
55
56 struct app_event_info {
57         app_event_type_e type;
58         void *value;
59 };
60
61 struct service_app_context {
62         service_app_lifecycle_callback_s callback;
63         void *data;
64         GList *running_jobs;
65         GList *pending_jobs;
66         GList *job_handlers;
67 };
68
69 struct service_app_job_s {
70         char *job_id;
71         service_app_job_cb callback;
72         void *user_data;
73 };
74
75 struct job_s {
76         int job_status;
77         char *job_id;
78         bundle *job_data;
79         guint timer;
80         guint idler;
81 };
82
83 static struct service_app_context __context;
84 static app_state_e __app_state = APP_STATE_NOT_RUNNING;
85
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,
93 };
94
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);
98
99 static struct job_s *__create_job(int job_status, const char *job_id,
100                 bundle *job_data)
101 {
102         struct job_s *job;
103
104         job = calloc(1, sizeof(struct job_s));
105         if (job == NULL) {
106                 /* LCOV_EXCL_START */
107                 LOGE("Out of memory");
108                 return NULL;
109                 /* LCOV_EXCL_STOP */
110         }
111
112         job->job_id = strdup(job_id);
113         if (job->job_id == NULL) {
114                 /* LCOV_EXCL_START */
115                 LOGE("Out of memory");
116                 free(job);
117                 return NULL;
118                 /* LCOV_EXCL_STOP */
119         }
120
121         job->job_data = bundle_dup(job_data);
122         if (job->job_data == NULL) {
123                 /* LCOV_EXCL_START */
124                 LOGE("Out of memory");
125                 free(job->job_id);
126                 free(job);
127                 return NULL;
128                 /* LCOV_EXCL_STOP */
129         }
130
131         job->job_status = job_status;
132
133         return job;
134 }
135
136 static void __destroy_job(gpointer data)
137 {
138         struct job_s *job = (struct job_s *)data;
139
140         if (job == NULL)
141                 return;
142
143         if (job->idler)
144                 g_source_remove(job->idler); /* LCOV_EXCL_LINE */
145         if (job->timer)
146                 g_source_remove(job->timer); /* LCOV_EXCL_LINE */
147         if (job->job_data)
148                 bundle_free(job->job_data);
149         if (job->job_id)
150                 free(job->job_id);
151         free(job);
152 }
153
154 /* LCOV_EXCL_START */
155 static gboolean __pending_job_timeout_handler(gpointer data)
156 {
157         struct job_s *job = (struct job_s *)data;
158
159         LOGE("[__TIMEOUT__] Job(%s) Status(%d)", job->job_id, job->job_status);
160         __context.pending_jobs = g_list_remove(__context.pending_jobs, job);
161         job->timer = 0;
162         __destroy_job(job);
163
164         return G_SOURCE_REMOVE;
165 }
166 /* LCOV_EXCL_STOP */
167
168 static void __job_finish(void)
169 {
170         if (__context.running_jobs) {
171                 /* LCOV_EXCL_START */
172                 g_list_free_full(__context.running_jobs, __destroy_job);
173                 __context.running_jobs = NULL;
174                 /* LCOV_EXCL_STOP */
175         }
176
177         if (__context.pending_jobs) {
178                 /* LCOV_EXCL_START */
179                 g_list_free_full(__context.pending_jobs, __destroy_job);
180                 __context.pending_jobs = NULL;
181                 /* LCOV_EXCL_STOP */
182         }
183
184         if (__context.job_handlers) {
185                 g_list_free_full(__context.job_handlers, __destroy_job_handler);
186                 __context.job_handlers = NULL;
187         }
188 }
189
190 static int __service_app_create(void *data)
191 {
192         appcore_base_on_create();
193
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");
197
198         return APP_ERROR_NONE;
199 }
200
201 static int __service_app_terminate(void *data)
202 {
203         if (__context.callback.terminate)
204                 __context.callback.terminate(__context.data);
205
206         appcore_base_on_terminate();
207
208         return APP_ERROR_NONE;
209 }
210
211 static int __service_app_control(bundle *b, void *data)
212 {
213         app_control_h app_control = NULL;
214         const char *job_id;
215         const char *rpc_port;
216
217         LOGD("[SERVICE_APP] app_control callback");
218         appcore_base_on_control(b);
219
220         job_id = bundle_get_val(b, AUL_K_JOB_ID);
221         if (job_id) {
222                 LOGD("[__JOB__] Job(%s)", job_id);
223                 return 0;
224         }
225
226         rpc_port = bundle_get_val(b, AUL_K_RPC_PORT);
227         if (rpc_port) {
228                 LOGD("[__RPC_PORT_PORT__] %s", rpc_port);
229                 return 0;
230         }
231
232         if (app_control_create_event(b, &app_control) != 0)
233                 return -1;
234
235         if (__context.callback.app_control)
236                 __context.callback.app_control(app_control, __context.data);
237
238         app_control_destroy(app_control);
239
240         return 0;
241 }
242
243 static void __loop_init(int argc, char **argv, void *data)
244 {
245         ecore_init();
246 }
247
248 static void __loop_fini(void)
249 {
250         ecore_shutdown();
251 }
252
253 static void __loop_run(void *data)
254 {
255         ecore_main_loop_begin();
256 }
257
258 static void __loop_exit(void *data)
259 {
260         ecore_main_loop_quit();
261 }
262
263 static const char *__error_to_string(app_error_e error)
264 {
265         switch (error) {
266         case APP_ERROR_NONE:
267                 return "NONE";
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";
278         default:
279                 return "UNKNOWN";
280         }
281 }
282
283 static int __on_error(app_error_e error, const char *function, const char *description)
284 {
285         if (description)
286                 LOGE("[%s] %s(0x%08x) : %s", function, __error_to_string(error), error, description);
287         else
288                 LOGE("[%s] %s(0x%08x)", function, __error_to_string(error), error);
289
290         return error;
291 }
292
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)
295 {
296         int ret;
297         appcore_base_ops ops = appcore_base_get_default_ops();
298
299         if (argc < 1 || argv == NULL || callback == NULL || method == NULL)
300                 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
301
302         if (callback->create == NULL)
303                 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "service_app_create_cb() callback must be registered");
304
305         if (__app_state != APP_STATE_NOT_RUNNING)
306                 return __on_error(APP_ERROR_ALREADY_RUNNING, __FUNCTION__, NULL); /* LCOV_EXCL_LINE */
307
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;
316
317         __context.callback = *callback;
318         __context.data = user_data;
319
320         __app_state = APP_STATE_CREATING;
321         ret = appcore_base_init(ops, argc, argv, NULL);
322         if (ret < 0) {
323                 /* LCOV_EXCL_START */
324                 __app_state = APP_STATE_NOT_RUNNING;
325                 return __on_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
326                 /* LCOV_EXCL_STOP */
327         }
328
329         appcore_base_fini();
330         __job_finish();
331         __app_state = APP_STATE_NOT_RUNNING;
332         return APP_ERROR_NONE;
333 }
334
335 EXPORT_API int service_app_main(int argc, char **argv, service_app_lifecycle_callback_s *callback, void *user_data)
336 {
337         service_app_loop_method_s method = {
338                 .init = __loop_init,
339                 .fini = __loop_fini,
340                 .run = __loop_run,
341                 .exit = __loop_exit,
342         };
343
344         return service_app_main_ext(argc, argv, callback, &method, user_data);
345 }
346
347 EXPORT_API void service_app_exit(void)
348 {
349         appcore_base_exit();
350 }
351
352 static int __event_cb(void *event, void *data)
353 {
354         app_event_handler_h handler = data;
355
356         struct app_event_info app_event;
357
358         app_event.type = handler->type;
359         app_event.value = event;
360
361         if (handler->cb)
362                 handler->cb(&app_event, handler->data);
363         return 0;
364 }
365
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)
367 {
368         app_event_handler_h handler;
369
370         if (event_handler == NULL || callback == NULL)
371                 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "null parameter");
372
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");
376
377         handler = calloc(1, sizeof(struct app_event_handler));
378         if (!handler)
379                 return __on_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__, "insufficient memory"); /* LCOV_EXCL_LINE */
380
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);
385
386         *event_handler = handler;
387
388         return APP_ERROR_NONE;
389 }
390
391 EXPORT_API int service_app_remove_event_handler(app_event_handler_h event_handler)
392 {
393         int ret;
394         app_event_type_e type;
395
396         if (event_handler == NULL)
397                 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
398
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 */
404
405         ret = appcore_base_remove_event(event_handler->raw);
406         free(event_handler);
407
408         if (ret < 0)
409                 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL); /* LCOV_EXCL_LINE */
410
411         return APP_ERROR_NONE;
412 }
413
414 EXPORT_API void service_app_exit_without_restart(void)
415 {
416         aul_status_update(STATUS_NORESTART);
417         appcore_base_exit();
418 }
419
420 static void __invoke_job_callback(int status, const char *job_id,
421                 bundle *job_data)
422 {
423         struct service_app_job_s *handle;
424         GList *iter;
425
426         iter = __context.job_handlers;
427         while (iter) {
428                 handle = (struct service_app_job_s *)iter->data;
429                 iter = iter->next;
430                 if (strcmp(handle->job_id, job_id) == 0) {
431                         handle->callback(status, job_id, job_data,
432                                         handle->user_data);
433                 }
434         }
435 }
436
437 static gboolean __handle_job(gpointer data)
438 {
439         struct job_s *job = (struct job_s *)data;
440
441         __context.running_jobs = g_list_remove(__context.running_jobs, job);
442
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,
447                                 JOB_STATUS_START);
448                 __invoke_job_callback(job->job_status, job->job_id,
449                                 job->job_data);
450         } else {
451                 __invoke_job_callback(job->job_status, job->job_id,
452                                 job->job_data);
453                 aul_job_scheduler_update_job_status(job->job_id,
454                                 JOB_STATUS_STOPPED);
455         }
456         LOGD("[__JOB__] Job(%s) Status(%d) END",
457                         job->job_id, job->job_status);
458
459         job->idler = 0;
460         __destroy_job(job);
461
462         return G_SOURCE_REMOVE;
463 }
464
465 static void __flush_pending_job(const char *job_id)
466 {
467         struct job_s *job;
468         GList *iter;
469
470         iter = __context.pending_jobs;
471         while (iter) {
472                 /* LCOV_EXCL_START */
473                 job = (struct job_s *)iter->data;
474                 iter = iter->next;
475                 if (strcmp(job->job_id, job_id) == 0) {
476                         __context.pending_jobs = g_list_remove(
477                                         __context.pending_jobs, job);
478
479                         if (job->timer) {
480                                 g_source_remove(job->timer);
481                                 job->timer = 0;
482                         }
483
484                         job->idler = g_idle_add(__handle_job, job);
485                         __context.running_jobs = g_list_append(
486                                         __context.running_jobs, job);
487                 }
488                 /* LCOV_EXCL_STOP */
489         }
490 }
491
492 static bool __exist_job_handler(const char *job_id)
493 {
494         struct service_app_job_s *handle;
495         GList *iter;
496
497         iter = __context.job_handlers;
498         while (iter) {
499                 handle = (struct service_app_job_s *)iter->data;
500                 if (strcmp(handle->job_id, job_id) == 0)
501                         return true;
502
503                 iter = iter->next;
504         }
505
506         return false;
507 }
508
509 static struct service_app_job_s *__create_job_handler(const char *job_id,
510                 service_app_job_cb callback, void *user_data)
511 {
512         struct service_app_job_s *handle;
513
514         handle = calloc(1, sizeof(struct service_app_job_s));
515         if (handle == NULL) {
516                 /* LCOV_EXCL_START */
517                 LOGE("Out of memory");
518                 return NULL;
519                 /* LCOV_EXCL_STOP */
520         }
521
522         handle->job_id = strdup(job_id);
523         if (handle->job_id == NULL) {
524                 /* LCOV_EXCL_START */
525                 LOGE("Out of memory");
526                 free(handle);
527                 return NULL;
528                 /* LCOV_EXCL_STOP */
529         }
530
531         handle->callback = callback;
532         handle->user_data = user_data;
533
534         return handle;
535 }
536
537 static void __destroy_job_handler(gpointer data)
538 {
539         struct service_app_job_s *handle = (struct service_app_job_s *)data;
540
541         if (handle == NULL)
542                 return;
543
544         if (handle->job_id)
545                 free(handle->job_id);
546         free(handle);
547 }
548
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)
551 {
552         struct service_app_job_s *handle;
553
554         if (job_id == NULL || callback == NULL) {
555                 /* LCOV_EXCL_START */
556                 LOGE("Invalid parameter");
557                 return NULL;
558                 /* LCOV_EXCL_STOP */
559         }
560
561         handle = __create_job_handler(job_id, callback, user_data);
562         if (handle == NULL)
563                 return NULL;
564
565         __context.job_handlers = g_list_append(__context.job_handlers, handle);
566
567         __flush_pending_job(job_id);
568
569         return handle;
570 }
571
572 EXPORT_API int service_app_remove_job_handler(service_app_job_h handle)
573 {
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__,
578                                 NULL);
579                 /* LCOV_EXCL_STOP */
580         }
581
582         __context.job_handlers = g_list_remove(__context.job_handlers, handle);
583
584         __destroy_job_handler(handle);
585
586         return APP_ERROR_NONE;
587 }
588
589 EXPORT_API int service_app_job_raise(int job_status, const char *job_id,
590                 bundle *job_data)
591 {
592         struct job_s *job;
593
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__,
599                                 NULL);
600                 /* LCOV_EXCL_STOP */
601         }
602
603         job = __create_job(job_status, job_id, job_data);
604         if (job == NULL)
605                 return __on_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL); /* LCOV_EXCL_LINE */
606
607         if (!__exist_job_handler(job_id)) {
608                 /* LCOV_EXCL_START */
609                 job->timer = g_timeout_add(5000, __pending_job_timeout_handler,
610                                 job);
611                 __context.pending_jobs = g_list_append(__context.pending_jobs,
612                                 job);
613                 /* LCOV_EXCL_STOP */
614         } else {
615                 job->idler = g_idle_add(__handle_job, job);
616                 __context.running_jobs = g_list_append(__context.running_jobs,
617                                 job);
618         }
619
620         return APP_ERROR_NONE;
621 }
622
623 static void __remove_running_job(const char *job_id)
624 {
625         struct job_s *job;
626         GList *iter;
627
628         iter = __context.running_jobs;
629         while (iter) {
630                 /* LCOV_EXCL_START */
631                 job = (struct job_s *)iter->data;
632                 iter = iter->next;
633                 if (strcmp(job->job_id, job_id) == 0) {
634                         __context.running_jobs = g_list_remove(
635                                         __context.running_jobs, job);
636                         __destroy_job(job);
637                 }
638                 /* LCOV_EXCL_STOP */
639         }
640 }
641
642 EXPORT_API int service_app_job_finished(const char *job_id)
643 {
644         int r;
645
646         if (job_id == NULL) {
647                 /* LCOV_EXCL_START */
648                 return __on_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__,
649                                 NULL);
650                 /* LCOV_EXCL_STOP */
651         }
652
653         __remove_running_job(job_id);
654
655         r = aul_job_scheduler_update_job_status(job_id, JOB_STATUS_FINISHED);
656         if (r != AUL_R_OK) {
657                 /* LCOV_EXCL_START */
658                 return __on_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__,
659                                 NULL);
660                 /* LCOV_EXCL_STOP */
661         }
662
663         return APP_ERROR_NONE;
664 }