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, aul_worker_h worker)
512 struct aul_request_s *req;
515 unsigned int timeout = 5000;
518 if (pkt->opt & AUL_SOCK_BUNDLE) {
519 b = bundle_decode(pkt->data, pkt->len);
521 _E("Failed to decode the packet");
525 ret = bundle_get_str(b, AUL_K_SOCKET_TIMEOUT, &timeout_str);
526 if (ret == BUNDLE_ERROR_NONE && isdigit(timeout_str[0])) {
527 timeout = atoi(timeout_str);
528 _I("timeout: %ums", timeout);
532 req = __create_request(pkt->cmd, clifd, b);
538 aul_worker_add_anr_timer(worker, pkt->cmd, timeout);
539 __g_idle_add_full(__get_glib_context(pkt->cmd, b), G_PRIORITY_DEFAULT,
540 __dispatch_request, req);
543 static bool __received_event_cb(int fd, int condition, void *user_data)
545 aul_worker_h worker = user_data;
546 client_channel_t *channel;
550 channel = __find_client_channel(fd);
552 _E("Failed to find client channel. fd(%d)", fd);
556 if (condition & (AUL_IO_HUP | AUL_IO_ERR | AUL_IO_NVAL)) {
557 _E("IO error occurred. condition(%d), fd(%d)", condition, fd);
558 aul_worker_remove_io_job(worker, fd);
559 __remove_client_channel(channel);
560 __destroy_client_channel(channel);
564 g_rec_mutex_lock(&channel->mutex);
565 ret = aul_sock_recv_reply_pkt_v2(fd, &pkt, false);
566 g_rec_mutex_unlock(&channel->mutex);
568 _E("Failed to receive the packet. error(%d)", ret);
572 __process_app_pkt(pkt, fd, worker);
578 static bool __connected_event_cb(int fd, int condition, void *user_data)
580 int cond = AUL_IO_IN | AUL_IO_HUP | AUL_IO_ERR | AUL_IO_NVAL;
581 aul_worker_h worker = user_data;
582 client_channel_t *channel = NULL;
588 pkt = aul_sock_recv_pkt(fd, &clifd, &cr);
590 _E("Failed to receive the packet");
594 _W("pid(%d), clifd(%d), cmd(%d)", cr.pid, clifd, pkt->cmd);
595 if (pkt->cmd != WIDGET_GET_CONTENT) {
596 if (pkt->opt & AUL_SOCK_NOREPLY) {
600 channel = __create_client_channel(clifd,
608 __add_client_channel(channel);
612 __process_app_pkt(pkt, clifd, worker);
614 if (pkt->cmd == WIDGET_GET_CONTENT)
622 ret = aul_worker_add_io_job(worker, "client", clifd, cond, true,
623 __received_event_cb, worker);
625 _E("Failed to add io job. error(%d)", ret);
626 __remove_client_channel(channel);
627 __destroy_client_channel(channel);
634 static void __finalize_context(void)
636 g_rec_mutex_lock(&__context.init_mutex);
637 if (!__context.initialized) {
638 g_rec_mutex_unlock(&__context.init_mutex);
642 __context.touch_argv_handler = false;
644 aul_launch_worker_fini();
646 if (__context.tizen_context) {
647 g_main_context_unref(__context.tizen_context);
648 __context.tizen_context = NULL;
651 if (__context.clients) {
652 g_list_free_full(__context.clients, __destroy_client_channel);
653 __context.clients = NULL;
656 if (g_rec_mutex_trylock(&__context.mutex))
657 g_rec_mutex_unlock(&__context.mutex);
659 g_rec_mutex_clear(&__context.mutex);
661 __context.initialized = false;
662 g_rec_mutex_unlock(&__context.init_mutex);
665 static GMainContext *__get_tizen_glib_context(void)
667 GMainContext *context;
670 env = getenv("TIZEN_GLIB_CONTEXT");
672 context = (GMainContext *)strtoul(env, NULL, 10);
679 static int __initialize_context(void)
681 GMainContext *context;
685 if (__context.initialized) {
686 _E("Already initialized");
687 context = __get_tizen_glib_context();
689 __context.tizen_context = g_main_context_ref(context);
694 fd = aul_initialize();
696 _E("Failed to initialize aul");
700 g_rec_mutex_init(&__context.mutex);
702 context = __get_tizen_glib_context();
704 __context.tizen_context = g_main_context_ref(context);
706 __context.tizen_context = NULL;
708 if (aul_launch_worker_init() != AUL_R_OK) {
709 __finalize_context();
713 ret = aul_worker_add_io_job(__context.worker, "server", fd, AUL_IO_IN,
714 false, __connected_event_cb, __context.worker);
716 __finalize_context();
720 __context.initialized = true;
725 API int aul_launch_worker_init(void)
727 if (__context.worker != NULL)
730 __context.worker = aul_worker_create("aul+");
731 if (__context.worker == NULL)
737 API void aul_launch_worker_fini(void)
739 if (__context.worker == NULL)
742 aul_worker_destroy(__context.worker);
743 __context.worker = NULL;
746 API int aul_launch_init(aul_handler_fn callback, void *user_data)
750 g_rec_mutex_lock(&__context.init_mutex);
752 __context.aul.callback = callback;
753 __context.aul.user_data = user_data;
756 ret = __initialize_context();
757 g_rec_mutex_unlock(&__context.init_mutex);
762 API int aul_launch_fini(void)
764 __finalize_context();
768 static gboolean __app_start_cb(gpointer data)
770 bundle *b = (bundle *)data;
771 struct aul_request_s req = {
777 __dispatch_app_start(&req);
782 return G_SOURCE_REMOVE;
785 API int aul_launch_argv_handler(int argc, char **argv)
789 if (!aul_is_initialized()) {
790 _E("AUL is not initialized");
791 return AUL_R_ENOINIT;
794 if (__context.touch_argv_handler) {
795 _E("Already registered");
799 b = bundle_import_from_argv(argc, argv);
801 _E("Bundle is nullptr");
803 if (!__g_idle_add_full(__get_glib_context(APP_START, b),
804 G_PRIORITY_HIGH, __app_start_cb, b)) {
805 _E("Failed to add idler");
809 __context.touch_argv_handler = true;
813 API int aul_launch_local(bundle *b)
815 if (!aul_is_initialized()) {
816 _E("AUL is not initialized");
817 return AUL_R_ENOINIT;
821 _E("Bundle is nullptr");
823 if (!__g_idle_add_full(__get_glib_context(APP_START, b),
824 G_PRIORITY_DEFAULT, __app_start_cb, b)) {
825 _E("Failed to add idler");
832 int aul_resume_local(void)
834 if (!aul_is_initialized()) {
835 _E("AUL is not initialized");
836 return AUL_R_ENOINIT;
839 __dispatch_app_resume(NULL);
844 API int aul_set_subapp(subapp_fn callback, void *user_data)
846 __context.subapp.is_subapp = true;
847 __context.subapp.callback = callback;
848 __context.subapp.user_data = user_data;
853 API int aul_is_subapp(void)
855 return (int)__context.subapp.is_subapp;
858 API int aul_set_data_control_provider_cb(data_control_provider_handler_fn cb)
860 __context.dcp.callback = cb;
865 API int aul_unset_data_control_provider_cb(void)
867 __context.dcp.callback = NULL;