Support launch reqeust async API
[platform/core/appfw/aul-1.git] / src / aul_launch.c
1 /*
2  * Copyright (c) 2018 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 #ifndef _GNU_SOURCE
18 #define _GNU_SOURCE
19 #endif
20
21 #include <stdio.h>
22 #include <stdbool.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/time.h>
27 #include <ctype.h>
28 #include <glib.h>
29 #include <gio/gio.h>
30 #include <bundle_internal.h>
31
32 #include "aul_api.h"
33 #include "aul_cmd.h"
34 #include "aul_util.h"
35 #include "aul.h"
36 #include "aul_sock.h"
37 #include "launch.h"
38 #include "key.h"
39
40 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
41
42 struct aul_request_s {
43         int cmd;
44         int clifd;
45         bundle *b;
46 };
47
48 typedef struct aul_request_s *aul_request_h;
49
50 typedef void (*dispatcher)(aul_request_h req);
51
52 typedef struct aul_handler_s {
53         aul_handler_fn callback;
54         void *user_data;
55 } aul_handler;
56
57 typedef struct subapp_handler_s {
58         bool is_subapp;
59         subapp_fn callback;
60         void *user_data;
61 } subapp_handler;
62
63 typedef struct data_control_provider_handler_s {
64         data_control_provider_handler_fn callback;
65 } data_control_provider_handler;
66
67 typedef struct launch_context_s {
68         GIOChannel *io;
69         guint source;
70         aul_handler aul;
71         subapp_handler subapp;
72         data_control_provider_handler dcp;
73 } launch_context;
74
75 static launch_context __context;
76
77 static void __invoke_aul_handler(aul_type type, bundle *b)
78 {
79         if (__context.aul.callback)
80                 __context.aul.callback(type, b, __context.aul.user_data);
81 }
82
83 static void __dispatch_app_start(aul_request_h req)
84 {
85         const char *str;
86
87         __invoke_aul_handler(AUL_START, req->b);
88         str = bundle_get_val(req->b, AUL_K_DATA_CONTROL_TYPE);
89         if (str && !strcmp(str, "CORE")) {
90                 if (__context.dcp.callback)
91                         __context.dcp.callback(req->b, 0, NULL);
92         }
93 }
94
95 static void __dispatch_app_resume(aul_request_h req)
96 {
97         __invoke_aul_handler(AUL_RESUME, NULL);
98 }
99
100 static void __dispatch_app_term_by_pid(aul_request_h req)
101 {
102         __invoke_aul_handler(AUL_TERMINATE, NULL);
103 }
104
105 static void __dispatch_app_term_bgapp_by_pid(aul_request_h req)
106 {
107         __invoke_aul_handler(AUL_TERMINATE_BGAPP, NULL);
108 }
109
110 static void __dispatch_app_term_req_by_pid(aul_request_h req)
111 {
112         if (__context.subapp.is_subapp) {
113                 if (__context.subapp.callback)
114                         __context.subapp.callback(__context.subapp.user_data);
115         } else {
116                 __invoke_aul_handler(AUL_TERMINATE, NULL);
117         }
118 }
119
120 static void __dispatch_app_result(aul_request_h req)
121 {
122         const char *pid_str;
123         int pid = -1;
124
125         pid_str = bundle_get_val(req->b, AUL_K_CALLEE_PID);
126         if (pid_str)
127                 pid = atoi(pid_str);
128
129         app_result(req->cmd, req->b, pid);
130 }
131
132 static void __dispatch_app_key_event(aul_request_h req)
133 {
134         app_key_event(req->b);
135 }
136
137 static void __dispatch_app_pause_by_pid(aul_request_h req)
138 {
139         __invoke_aul_handler(AUL_PAUSE, req->b);
140 }
141
142 static void __dispatch_app_com_message(aul_request_h req)
143 {
144         app_com_recv(req->b);
145 }
146
147 static void __dispatch_app_wake(aul_request_h req)
148 {
149         __invoke_aul_handler(AUL_WAKE, req->b);
150 }
151
152 static void __dispatch_app_suspend(aul_request_h req)
153 {
154         __invoke_aul_handler(AUL_SUSPEND, req->b);
155 }
156
157 static void __dispatch_widget_get_content(aul_request_h req)
158 {
159         const char *widget_id;
160         const char *instance_id;
161         const char *content_info;
162         int fds[2] = { 0, };
163         int r;
164
165         r = aul_sock_recv_reply_sock_fd(req->clifd, &fds, 1);
166         if (r < 0) {
167                 _E("Failed to receive fds");
168                 return;
169         }
170
171         widget_id = bundle_get_val(req->b, AUL_K_WIDGET_ID);
172         if (!widget_id) {
173                 _E("Failed to get widget ID");
174                 aul_sock_send_raw_with_fd(fds[0], -EINVAL, 0, 0,
175                                 AUL_SOCK_NOREPLY);
176                 return;
177         }
178
179         instance_id = bundle_get_val(req->b, AUL_K_WIDGET_INSTANCE_ID);
180         if (!instance_id) {
181                 _E("Failed to get instance ID");
182                 aul_sock_send_raw_with_fd(fds[0], -EINVAL, 0, 0,
183                                 AUL_SOCK_NOREPLY);
184                 return;
185         }
186
187         __invoke_aul_handler(AUL_WIDGET_CONTENT, req->b);
188
189         content_info = bundle_get_val(req->b, AUL_K_WIDGET_CONTENT_INFO);
190         if (content_info) {
191                 r = aul_sock_send_raw_with_fd(fds[0], 0,
192                                 (unsigned char *)content_info,
193                                 strlen(content_info) + 1, AUL_SOCK_NOREPLY);
194         } else {
195                 r = aul_sock_send_raw_with_fd(fds[0], -ENOENT,
196                                 NULL, 0, AUL_SOCK_NOREPLY);
197         }
198
199         if (r < 0) {
200                 _E("Failed to send content info. fd(%d), result(%d)",
201                                 fds[0], r);
202         }
203 }
204
205 static void __dispatch_app_update_requested(aul_request_h req)
206 {
207         __invoke_aul_handler(AUL_UPDATE_REQUESTED, req->b);
208 }
209
210 static void __dispatch_watchdog_ping(aul_request_h req)
211 {
212         const char *start_time;
213         struct timeval tv;
214
215         gettimeofday(&tv, NULL);
216         start_time = bundle_get_val(req->b, AUL_K_STARTTIME);
217         _W("[__WATCHDOG__] Start time: %s, response time: %ld/%ld",
218                         start_time ? start_time : "Unknown",
219                         tv.tv_sec, tv.tv_usec);
220 }
221
222 static dispatcher __dispatcher[] = {
223         [APP_START] = __dispatch_app_start,
224         [APP_START_RES] = __dispatch_app_start,
225         [APP_START_ASYNC] = __dispatch_app_start,
226         [APP_START_RES_ASYNC] = __dispatch_app_start,
227         [APP_OPEN] = __dispatch_app_resume,
228         [APP_RESUME] = __dispatch_app_resume,
229         [APP_RESUME_BY_PID] = __dispatch_app_resume,
230         [APP_TERM_BY_PID] = __dispatch_app_term_by_pid,
231         [APP_TERM_BY_PID_ASYNC] = __dispatch_app_term_by_pid,
232         [APP_TERM_BY_PID_SYNC] = __dispatch_app_term_by_pid,
233         [APP_TERM_BGAPP_BY_PID] = __dispatch_app_term_bgapp_by_pid,
234         [APP_TERM_REQ_BY_PID] = __dispatch_app_term_req_by_pid,
235         [APP_RESULT] = __dispatch_app_result,
236         [APP_CANCEL] = __dispatch_app_result,
237         [APP_KEY_EVENT] = __dispatch_app_key_event,
238         [APP_PAUSE_BY_PID] = __dispatch_app_pause_by_pid,
239         [APP_COM_MESSAGE] = __dispatch_app_com_message,
240         [APP_WAKE] = __dispatch_app_wake,
241         [APP_SUSPEND] = __dispatch_app_suspend,
242         [WIDGET_GET_CONTENT] = __dispatch_widget_get_content,
243         [APP_UPDATE_REQUESTED] = __dispatch_app_update_requested,
244         [WATCHDOG_PING] = __dispatch_watchdog_ping,
245         [APP_SEND_LAUNCH_REQUEST] = __dispatch_app_start,
246 };
247
248 static gboolean __aul_launch_handler(GIOChannel *io, GIOCondition condition,
249                 gpointer data)
250 {
251         int fd = g_io_channel_unix_get_fd(io);
252         struct aul_request_s req = { 0, };
253         app_pkt_t *pkt;
254         bundle *b = NULL;
255         int clifd;
256         struct ucred cr;
257         int r;
258
259         pkt = aul_sock_recv_pkt(fd, &clifd, &cr);
260         if (!pkt) {
261                 _E("Failed to receive the packet");
262                 return G_SOURCE_CONTINUE;
263         }
264
265         if (pkt->cmd != WIDGET_GET_CONTENT) {
266                 if (pkt->opt & AUL_SOCK_NOREPLY) {
267                         close(clifd);
268                         clifd = -1;
269                 } else {
270                         r = aul_sock_send_result(clifd, 0);
271                         if (r < 0) {
272                                 _E("Failed to send result. cmd(%s:%d)",
273                                         aul_cmd_convert_to_string(pkt->cmd),
274                                         pkt->cmd);
275                                 free(pkt);
276                                 return G_SOURCE_CONTINUE;;
277                         }
278                         clifd = -1;
279                 }
280         }
281
282         if (pkt->opt & AUL_SOCK_BUNDLE) {
283                 b = bundle_decode(pkt->data, pkt->len);
284                 if (!b) {
285                         _E("Failed to decode the packet");
286                         if (clifd > 0)
287                                 close(clifd);
288                         free(pkt);
289                         return G_SOURCE_CONTINUE;
290                 }
291         }
292
293         req.cmd = pkt->cmd;
294         req.clifd = clifd;
295         req.b = b;
296
297         free(pkt);
298
299         if (req.cmd >= APP_START && req.cmd < ARRAY_SIZE(__dispatcher) &&
300                         __dispatcher[req.cmd]) {
301                 _W("Command(%s:%d)",
302                                 aul_cmd_convert_to_string(req.cmd), req.cmd);
303                 __dispatcher[req.cmd](&req);
304         } else {
305                 _E("Command(%s:%d) is not available",
306                                 aul_cmd_convert_to_string(req.cmd), req.cmd);
307         }
308
309         if (req.b)
310                 bundle_free(req.b);
311
312         return G_SOURCE_CONTINUE;
313 }
314
315 static void __finalize_context(void)
316 {
317         if (__context.source) {
318                 g_source_remove(__context.source);
319                 __context.source = 0;
320         }
321
322         if (__context.io) {
323                 g_io_channel_unref(__context.io);
324                 __context.io = NULL;
325         }
326 }
327
328 static int __initialize_context(void)
329 {
330         GIOCondition cond = G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_ERR;
331         int fd;
332
333         fd = aul_initialize();
334         if (fd < 0) {
335                 _E("Failed to initialize aul");
336                 return fd;
337         }
338
339         __context.io = g_io_channel_unix_new(fd);
340         if (!__context.io) {
341                 _E("Failed to create gio channel");
342                 __finalize_context();
343                 return AUL_R_ERROR;
344         }
345
346         __context.source = g_io_add_watch(__context.io,
347                         cond, __aul_launch_handler, NULL);
348         if (!__context.source) {
349                 _E("Failed to add gio watch");
350                 __finalize_context();
351                 return AUL_R_ERROR;
352         }
353
354         return AUL_R_OK;
355 }
356
357 API int aul_launch_init(aul_handler_fn callback, void *user_data)
358 {
359         if (callback) {
360                 __context.aul.callback = callback;
361                 __context.aul.user_data = user_data;
362         }
363
364         return __initialize_context();
365 }
366
367 API int aul_launch_fini(void)
368 {
369         __finalize_context();
370         return AUL_R_OK;
371 }
372
373 static gboolean __app_start_cb(gpointer data)
374 {
375         bundle *b = (bundle *)data;
376         struct aul_request_s req = {
377                 .cmd = APP_START,
378                 .clifd = 0,
379                 .b = b
380         };
381
382         __dispatch_app_start(&req);
383
384         if (req.b)
385                 bundle_free(req.b);
386
387         return G_SOURCE_REMOVE;
388 }
389
390 API int aul_launch_argv_handler(int argc, char **argv)
391 {
392         bundle *b;
393
394         if (!aul_is_initialized()) {
395                 _E("AUL is not initialized");
396                 return AUL_R_ENOINIT;
397         }
398
399         b = bundle_import_from_argv(argc, argv);
400         if (!b)
401                 _E("Bundle is nullptr");
402
403         if (!g_idle_add_full(G_PRIORITY_HIGH, __app_start_cb, b, NULL)) {
404                 _E("Failed to add idler");
405                 return AUL_R_ERROR;
406         }
407
408         return AUL_R_OK;
409 }
410
411 API int aul_launch_local(bundle *b)
412 {
413         if (!aul_is_initialized()) {
414                 _E("AUL is not initialized");
415                 return AUL_R_ENOINIT;
416         }
417
418         if (!b)
419                 _E("Bundle is nullptr");
420
421         if (!g_idle_add(__app_start_cb, b)) {
422                 _E("Failed to add idler");
423                 return AUL_R_ERROR;
424         }
425
426         return AUL_R_OK;
427 }
428
429 int aul_resume_local(void)
430 {
431         if (!aul_is_initialized()) {
432                 _E("AUL is not initialized");
433                 return AUL_R_ENOINIT;
434         }
435
436         __dispatch_app_resume(NULL);
437
438         return AUL_R_OK;
439 }
440
441 API int aul_set_subapp(subapp_fn callback, void *user_data)
442 {
443         __context.subapp.is_subapp = true;
444         __context.subapp.callback = callback;
445         __context.subapp.user_data = user_data;
446
447         return AUL_R_OK;
448 }
449
450 API int aul_is_subapp(void)
451 {
452         return (int)__context.subapp.is_subapp;
453 }
454
455 API int aul_set_data_control_provider_cb(data_control_provider_handler_fn cb)
456 {
457         __context.dcp.callback = cb;
458
459         return AUL_R_OK;
460 }
461
462 API int aul_unset_data_control_provider_cb(void)
463 {
464         __context.dcp.callback = NULL;
465
466         return AUL_R_OK;
467 }