2 * Copyright (c) 2018 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.
25 #include <sys/types.h>
29 #include <bundle_internal.h>
37 #include "aul_watch_control_internal.h"
38 #include "aul_worker.h"
39 #include "aul_watchdog.h"
41 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
43 #define K_SERVICE_THREAD "__K_SERVICE_THREAD"
45 #define AUL_CTOR __attribute__ ((constructor))
46 #define AUL_DTOR __attribute__ ((destructor))
48 typedef struct client_channel_s {
55 struct aul_request_s {
61 typedef struct aul_request_s *aul_request_h;
63 typedef void (*dispatcher)(aul_request_h req);
65 typedef struct aul_handler_s {
66 aul_handler_fn callback;
70 typedef struct subapp_handler_s {
76 typedef struct data_control_provider_handler_s {
77 data_control_provider_handler_fn callback;
78 } data_control_provider_handler;
80 typedef struct launch_context_s {
84 subapp_handler subapp;
85 data_control_provider_handler dcp;
89 GMainContext *tizen_context;
90 bool touch_argv_handler;
93 static launch_context __context;
95 AUL_CTOR static void __aul_constructor(void)
97 g_rec_mutex_init(&__context.init_mutex);
100 AUL_DTOR static void __aul_destructor(void)
102 if (g_rec_mutex_trylock(&__context.init_mutex))
103 g_rec_mutex_unlock(&__context.init_mutex);
105 g_rec_mutex_clear(&__context.init_mutex);
108 static void __destroy_client_channel(gpointer data)
110 client_channel_t *channel = data;
112 g_rec_mutex_lock(&channel->mutex);
113 g_rec_mutex_unlock(&channel->mutex);
114 g_rec_mutex_clear(&channel->mutex);
119 static client_channel_t *__create_client_channel(int fd, pid_t pid, uid_t uid)
121 client_channel_t *channel;
123 channel = calloc(1, sizeof(client_channel_t));
129 g_rec_mutex_init(&channel->mutex);
138 static void __add_client_channel(client_channel_t *channel)
140 g_rec_mutex_lock(&__context.mutex);
141 __context.clients = g_list_append(__context.clients, channel);
142 g_rec_mutex_unlock(&__context.mutex);
145 static void __remove_client_channel(client_channel_t *channel)
147 g_rec_mutex_lock(&__context.mutex);
148 __context.clients = g_list_remove(__context.clients, channel);
149 g_rec_mutex_unlock(&__context.mutex);
152 static client_channel_t *__find_client_channel(int fd)
154 client_channel_t *channel;
157 g_rec_mutex_lock(&__context.mutex);
158 iter = __context.clients;
160 channel = iter->data;
161 if (channel->fd == fd) {
162 g_rec_mutex_unlock(&__context.mutex);
166 iter = g_list_next(iter);
168 g_rec_mutex_unlock(&__context.mutex);
173 static void __invoke_aul_handler(aul_type type, bundle *b)
175 if (__context.aul.callback)
176 __context.aul.callback(type, b, __context.aul.user_data);
179 static void __dispatch_app_start(aul_request_h req)
183 aul_watch_control_invoke(req->b);
184 __invoke_aul_handler(AUL_START, req->b);
185 str = bundle_get_val(req->b, AUL_K_DATA_CONTROL_TYPE);
186 if (str && !strcmp(str, "CORE")) {
187 if (__context.dcp.callback)
188 __context.dcp.callback(req->b, 0, NULL);
192 static void __dispatch_app_resume(aul_request_h req)
194 __invoke_aul_handler(AUL_RESUME, NULL);
197 static void __dispatch_app_term_by_pid(aul_request_h req)
199 __invoke_aul_handler(AUL_TERMINATE, NULL);
202 static void __dispatch_app_term_bgapp_by_pid(aul_request_h req)
204 __invoke_aul_handler(AUL_TERMINATE_BGAPP, NULL);
207 static void __dispatch_app_term_req_by_pid(aul_request_h req)
209 if (__context.subapp.is_subapp) {
210 if (__context.subapp.callback)
211 __context.subapp.callback(__context.subapp.user_data);
213 __invoke_aul_handler(AUL_TERMINATE, NULL);
217 static void __dispatch_app_result(aul_request_h req)
222 pid_str = bundle_get_val(req->b, AUL_K_CALLEE_PID);
226 app_result(req->cmd, req->b, pid);
229 static void __dispatch_app_pause_by_pid(aul_request_h req)
231 __invoke_aul_handler(AUL_PAUSE, req->b);
234 static void __dispatch_app_com_message(aul_request_h req)
236 app_com_recv(req->b);
239 static void __dispatch_app_wake(aul_request_h req)
241 __invoke_aul_handler(AUL_WAKE, req->b);
244 static void __dispatch_app_suspend(aul_request_h req)
246 __invoke_aul_handler(AUL_SUSPEND, req->b);
249 static void __dispatch_widget_get_content(aul_request_h req)
251 const char *widget_id;
252 const char *instance_id;
253 const char *content_info;
257 r = aul_sock_recv_reply_sock_fd(req->clifd, &fds, 1);
259 _E("Failed to receive fds");
263 widget_id = bundle_get_val(req->b, AUL_K_WIDGET_ID);
265 _E("Failed to get widget ID");
266 aul_sock_send_raw_with_fd(fds[0], -EINVAL, 0, 0,
271 instance_id = bundle_get_val(req->b, AUL_K_WIDGET_INSTANCE_ID);
273 _E("Failed to get instance ID");
274 aul_sock_send_raw_with_fd(fds[0], -EINVAL, 0, 0,
279 __invoke_aul_handler(AUL_WIDGET_CONTENT, req->b);
281 content_info = bundle_get_val(req->b, AUL_K_WIDGET_CONTENT_INFO);
283 r = aul_sock_send_raw_with_fd(fds[0], 0,
284 (unsigned char *)content_info,
285 strlen(content_info) + 1, AUL_SOCK_NOREPLY);
287 r = aul_sock_send_raw_with_fd(fds[0], -ENOENT,
288 NULL, 0, AUL_SOCK_NOREPLY);
292 _E("Failed to send content info. fd(%d), result(%d)",
297 static void __dispatch_app_update_requested(aul_request_h req)
299 __invoke_aul_handler(AUL_UPDATE_REQUESTED, req->b);
302 static void __dispatch_app_term_inst(aul_request_h req)
304 __invoke_aul_handler(AUL_TERMINATE_INST, req->b);
307 static void __dispatch_app_resume_inst(aul_request_h req)
309 __invoke_aul_handler(AUL_RESUME, req->b);
312 static void __dispatch_app_pause_inst(aul_request_h req)
314 __invoke_aul_handler(AUL_PAUSE, req->b);
317 static void __dispatch_app_term_bg_inst(aul_request_h req)
319 __invoke_aul_handler(AUL_TERMINATE_BG_INST, req->b);
322 static void __dispatch_watchdog_enable(aul_request_h req)
324 const char *interval_str;
325 unsigned int interval;
327 interval_str = bundle_get_val(req->b, AUL_K_INTERVAL);
329 _E("Invalid request");
333 interval = strtoul(interval_str, NULL, 10);
334 aul_watchdog_start(interval);
337 static void __dispatch_watchdog_disable(aul_request_h req)
342 static void __dispatch_app_connect(aul_request_h req)
346 static dispatcher __dispatcher[] = {
347 [APP_START] = __dispatch_app_start,
348 [APP_START_RES] = __dispatch_app_start,
349 [APP_START_ASYNC] = __dispatch_app_start,
350 [APP_START_RES_ASYNC] = __dispatch_app_start,
351 [APP_OPEN] = __dispatch_app_resume,
352 [APP_RESUME] = __dispatch_app_resume,
353 [APP_RESUME_BY_PID] = __dispatch_app_resume,
354 [APP_TERM_BY_PID] = __dispatch_app_term_by_pid,
355 [APP_TERM_BY_PID_ASYNC] = __dispatch_app_term_by_pid,
356 [APP_TERM_BY_PID_SYNC] = __dispatch_app_term_by_pid,
357 [APP_TERM_BGAPP_BY_PID] = __dispatch_app_term_bgapp_by_pid,
358 [APP_TERM_REQ_BY_PID] = __dispatch_app_term_req_by_pid,
359 [APP_RESULT] = __dispatch_app_result,
360 [APP_CANCEL] = __dispatch_app_result,
361 [APP_PAUSE_BY_PID] = __dispatch_app_pause_by_pid,
362 [APP_COM_MESSAGE] = __dispatch_app_com_message,
363 [APP_WAKE] = __dispatch_app_wake,
364 [APP_SUSPEND] = __dispatch_app_suspend,
365 [WIDGET_GET_CONTENT] = __dispatch_widget_get_content,
366 [APP_UPDATE_REQUESTED] = __dispatch_app_update_requested,
367 [APP_SEND_LAUNCH_REQUEST] = __dispatch_app_start,
368 [APP_SEND_LAUNCH_REQUEST_SYNC] = __dispatch_app_start,
369 [APP_TERM_INSTANCE_ASYNC] = __dispatch_app_term_inst,
370 [APP_RESUME_INSTANCE] = __dispatch_app_resume_inst,
371 [APP_PAUSE_INSTANCE] = __dispatch_app_pause_inst,
372 [APP_TERM_BG_INSTANCE] = __dispatch_app_term_bg_inst,
373 [WATCHDOG_ENABLE] = __dispatch_watchdog_enable,
374 [WATCHDOG_DISABLE] = __dispatch_watchdog_disable,
375 [APP_CONNECT] = __dispatch_app_connect,
378 static void __destroy_request(struct aul_request_s *req)
385 static struct aul_request_s *__create_request(int cmd, int clifd, bundle *b)
387 struct aul_request_s *req;
389 req = malloc(sizeof(struct aul_request_s));
402 static int __send_result(struct aul_request_s *req, int res)
404 client_channel_t *channel;
407 if (req->cmd != WIDGET_GET_CONTENT && req->clifd >= 0) {
408 channel = __find_client_channel(req->clifd);
410 _E("Failed to find client channel. fd(%d)", req->clifd);
414 g_rec_mutex_lock(&channel->mutex);
415 ret = aul_sock_send_result_v2(req->clifd, res, false);
416 g_rec_mutex_unlock(&channel->mutex);
418 _E("Failed to send result. cmd(%s:%d)",
419 aul_cmd_convert_to_string(req->cmd),
428 static gboolean __dispatch_request(gpointer data)
430 struct aul_request_s *req = (struct aul_request_s *)data;
433 if (!__context.initialized) {
434 _W("Ignore request(%d)", req->cmd);
435 __destroy_request(req);
436 return G_SOURCE_REMOVE;
439 aul_worker_remove_anr_timer(__context.worker);
441 ret = __send_result(req, 0);
443 __destroy_request(req);
444 return G_SOURCE_REMOVE;
447 if (req->cmd >= APP_START && req->cmd < ARRAY_SIZE(__dispatcher) &&
448 __dispatcher[req->cmd]) {
450 aul_cmd_convert_to_string(req->cmd), req->cmd);
451 __dispatcher[req->cmd](req);
453 _E("Command(%s:%d) is not available",
454 aul_cmd_convert_to_string(req->cmd), req->cmd);
457 __destroy_request(req);
459 return G_SOURCE_REMOVE;
462 static guint __g_idle_add_full(GMainContext *context, gint priority,
463 GSourceFunc func, gpointer data)
468 source = g_idle_source_new();
472 g_source_set_callback(source, (GSourceFunc)func, data, NULL);
473 g_source_set_priority(source, priority);
474 tag = g_source_attach(source, context);
475 g_source_unref(source);
480 static GMainContext *__get_glib_context(int cmd, bundle *b)
482 GMainContext *context;
484 if (b && bundle_get_type(b, K_SERVICE_THREAD) != BUNDLE_TYPE_NONE)
490 case APP_START_ASYNC:
491 case APP_START_RES_ASYNC:
494 case APP_RESUME_BY_PID:
495 case APP_PAUSE_BY_PID:
496 case APP_SEND_LAUNCH_REQUEST:
497 case APP_SEND_LAUNCH_REQUEST_SYNC:
498 case APP_RESUME_INSTANCE:
499 case APP_PAUSE_INSTANCE:
500 context = __context.tizen_context;
510 static void __process_app_pkt(app_pkt_t *pkt, int clifd)
512 struct aul_request_s *req;
515 if (pkt->opt & AUL_SOCK_BUNDLE) {
516 b = bundle_decode(pkt->data, pkt->len);
518 _E("Failed to decode the packet");
523 req = __create_request(pkt->cmd, clifd, b);
529 __g_idle_add_full(__get_glib_context(pkt->cmd, b), G_PRIORITY_DEFAULT,
530 __dispatch_request, req);
533 static bool __received_event_cb(int fd, int condition, void *user_data)
535 aul_worker_h worker = user_data;
536 client_channel_t *channel;
540 channel = __find_client_channel(fd);
542 _E("Failed to find client channel. fd(%d)", fd);
546 if (condition & (AUL_IO_HUP | AUL_IO_ERR | AUL_IO_NVAL)) {
547 _E("IO error occurred. condition(%d), fd(%d)", condition, fd);
548 __remove_client_channel(channel);
549 __destroy_client_channel(channel);
553 g_rec_mutex_lock(&channel->mutex);
554 ret = aul_sock_recv_reply_pkt_v2(fd, &pkt, false);
555 g_rec_mutex_unlock(&channel->mutex);
557 _E("Failed to receive the packet. error(%d)", ret);
561 aul_worker_add_anr_timer(worker, pkt->cmd);
562 __process_app_pkt(pkt, fd);
568 static bool __connected_event_cb(int fd, int condition, void *user_data)
570 int cond = AUL_IO_IN | AUL_IO_HUP | AUL_IO_ERR | AUL_IO_NVAL;
571 aul_worker_h worker = user_data;
572 client_channel_t *channel = NULL;
578 pkt = aul_sock_recv_pkt(fd, &clifd, &cr);
580 _E("Failed to receive the packet");
584 _W("pid(%d), clifd(%d), cmd(%d)", cr.pid, clifd, pkt->cmd);
585 if (pkt->cmd != WIDGET_GET_CONTENT) {
586 if (pkt->opt & AUL_SOCK_NOREPLY) {
590 channel = __create_client_channel(clifd,
598 __add_client_channel(channel);
602 aul_worker_add_anr_timer(worker, pkt->cmd);
603 __process_app_pkt(pkt, clifd);
605 if (pkt->cmd == WIDGET_GET_CONTENT)
613 ret = aul_worker_add_io_job(worker, "client", clifd, cond,
614 __received_event_cb, worker);
616 _E("Failed to add io job. error(%d)", ret);
617 __remove_client_channel(channel);
618 __destroy_client_channel(channel);
625 static void __finalize_context(void)
627 g_rec_mutex_lock(&__context.init_mutex);
628 if (!__context.initialized) {
629 g_rec_mutex_unlock(&__context.init_mutex);
633 __context.touch_argv_handler = false;
635 if (__context.worker) {
636 aul_worker_destroy(__context.worker);
637 __context.worker = NULL;
640 if (__context.tizen_context) {
641 g_main_context_unref(__context.tizen_context);
642 __context.tizen_context = NULL;
645 if (__context.clients) {
646 g_list_free_full(__context.clients, __destroy_client_channel);
647 __context.clients = NULL;
650 if (g_rec_mutex_trylock(&__context.mutex))
651 g_rec_mutex_unlock(&__context.mutex);
653 g_rec_mutex_clear(&__context.mutex);
655 __context.initialized = false;
656 g_rec_mutex_unlock(&__context.init_mutex);
659 static GMainContext *__get_tizen_glib_context(void)
661 GMainContext *context;
664 env = getenv("TIZEN_GLIB_CONTEXT");
666 context = (GMainContext *)strtoul(env, NULL, 10);
673 static int __initialize_context(void)
675 GMainContext *context;
679 if (__context.initialized) {
680 _E("Already initialized");
681 context = __get_tizen_glib_context();
683 __context.tizen_context = g_main_context_ref(context);
688 fd = aul_initialize();
690 _E("Failed to initialize aul");
694 g_rec_mutex_init(&__context.mutex);
696 context = __get_tizen_glib_context();
698 __context.tizen_context = g_main_context_ref(context);
700 __context.tizen_context = NULL;
702 __context.worker = aul_worker_create("aul+");
703 if (!__context.worker) {
704 __finalize_context();
708 ret = aul_worker_add_io_job(__context.worker, "server", fd, AUL_IO_IN,
709 __connected_event_cb, __context.worker);
711 __finalize_context();
715 __context.initialized = true;
720 API int aul_launch_init(aul_handler_fn callback, void *user_data)
724 g_rec_mutex_lock(&__context.init_mutex);
726 __context.aul.callback = callback;
727 __context.aul.user_data = user_data;
730 ret = __initialize_context();
731 g_rec_mutex_unlock(&__context.init_mutex);
736 API int aul_launch_fini(void)
738 __finalize_context();
742 static gboolean __app_start_cb(gpointer data)
744 bundle *b = (bundle *)data;
745 struct aul_request_s req = {
751 __dispatch_app_start(&req);
756 return G_SOURCE_REMOVE;
759 API int aul_launch_argv_handler(int argc, char **argv)
763 if (!aul_is_initialized()) {
764 _E("AUL is not initialized");
765 return AUL_R_ENOINIT;
768 if (__context.touch_argv_handler) {
769 _E("Already registered");
773 b = bundle_import_from_argv(argc, argv);
775 _E("Bundle is nullptr");
777 if (!__g_idle_add_full(__get_glib_context(APP_START, b),
778 G_PRIORITY_HIGH, __app_start_cb, b)) {
779 _E("Failed to add idler");
783 __context.touch_argv_handler = true;
787 API int aul_launch_local(bundle *b)
789 if (!aul_is_initialized()) {
790 _E("AUL is not initialized");
791 return AUL_R_ENOINIT;
795 _E("Bundle is nullptr");
797 if (!__g_idle_add_full(__get_glib_context(APP_START, b),
798 G_PRIORITY_DEFAULT, __app_start_cb, b)) {
799 _E("Failed to add idler");
806 int aul_resume_local(void)
808 if (!aul_is_initialized()) {
809 _E("AUL is not initialized");
810 return AUL_R_ENOINIT;
813 __dispatch_app_resume(NULL);
818 API int aul_set_subapp(subapp_fn callback, void *user_data)
820 __context.subapp.is_subapp = true;
821 __context.subapp.callback = callback;
822 __context.subapp.user_data = user_data;
827 API int aul_is_subapp(void)
829 return (int)__context.subapp.is_subapp;
832 API int aul_set_data_control_provider_cb(data_control_provider_handler_fn cb)
834 __context.dcp.callback = cb;
839 API int aul_unset_data_control_provider_cb(void)
841 __context.dcp.callback = NULL;