Adjust sending startup signal
[platform/core/appfw/launchpad.git] / src / lib / launchpad / src / launchpad_lib.c
1 /*
2  * Copyright (c) 2015 - 2019 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 #define _GNU_SOURCE
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <sys/socket.h>
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <sys/prctl.h>
24 #include <malloc.h>
25 #include <bundle_internal.h>
26 #include <aul.h>
27 #include <security-manager.h>
28 #include <trust-anchor.h>
29 #include <buxton2.h>
30 #include <vconf.h>
31
32 #include <signal.h>
33 #include <sys/types.h>
34 #include <sys/wait.h>
35
36 #include "launchpad.h"
37 #include "launchpad_common.h"
38 #include "launchpad_types.h"
39 #include "preexec.h"
40
41 #ifndef API
42 #define API __attribute__ ((visibility("default")))
43 #endif
44
45 #define AUL_PR_NAME 16
46
47 static loader_lifecycle_callback_s *__loader_callbacks;
48 static loader_adapter_s *__loader_adapter;
49 static void *__loader_user_data;
50 static int __argc;
51 static char **__argv;
52 static bundle *__bundle;
53 static int __loader_type = LAUNCHPAD_TYPE_UNSUPPORTED;
54 static int __loader_id;
55 static bool __loop_quit;
56
57 static void __at_exit_to_release_bundle(void)
58 {
59         if (__bundle)
60                 bundle_free(__bundle);
61 }
62
63 static int __prepare_exec(const char *appid, const char *app_path,
64                         const char *pkg_type, int type, const char* pkgid,
65                         const char *root_path, bool global, bundle *kb)
66 {
67         const char *file_name = NULL;
68         char process_name[AUL_PR_NAME] = { 0, };
69         int ret;
70         struct buxton_client *bxt_cli;
71
72         __preexec_run(pkg_type, appid, app_path);
73
74         ret = _enable_external_pkg(kb, pkgid, global ? GLOBAL_USER : getuid());
75         if (ret < 0)
76                 return -1;
77
78         /* SET PRIVILEGES*/
79         SECURE_LOGD("[candidata] appid : %s / pkg_type : %s / app_path : %s",
80                 appid, pkg_type, app_path);
81
82         if (global)
83                 ret = trust_anchor_launch(pkgid, GLOBAL_USER);
84         else
85                 ret = trust_anchor_launch(pkgid, getuid());
86
87         if (ret != TRUST_ANCHOR_ERROR_NONE &&
88                         ret != TRUST_ANCHOR_ERROR_NOT_INSTALLED) {
89                 _E("trust_anchor_launch() returns %d", ret);
90                 return -1;
91         }
92
93         ret = _mount_res_dir(root_path, kb);
94         if (ret < 0)
95                 return -1;
96
97         _W("security_manager_prepare_app ++");
98         ret = security_manager_prepare_app(appid);
99         _W("security_manager_prepare_app --");
100         if (ret != SECURITY_MANAGER_SUCCESS) {
101                 _E("Failed to set privileges %s:%d", appid, ret);
102                 return -1;
103         }
104
105         _setup_stdio(basename(app_path));
106
107         ret = buxton_open(&bxt_cli, NULL, NULL);
108         if (ret != 0) {
109                 _E("buxton_open() failed, errno(%d)", errno);
110                 return -1;
111         }
112         ret = buxton_update_client_label_sync(bxt_cli);
113         if (ret != 0) {
114                 _E("buxton_update_client_label() failed, errno(%d)", errno);
115                 buxton_close(bxt_cli);
116                 return -1;
117         }
118         buxton_close(bxt_cli);
119
120         /*
121          * SET DUMPABLE - for coredump
122          * This dumpable flag should be set after
123          * calling perm_app_set_privilege().
124          */
125         prctl(PR_SET_DUMPABLE, 1);
126
127         /* SET PROCESS NAME*/
128         if (app_path == NULL) {
129                 _D("app_path should not be NULL - check menu db");
130                 return -1;
131         }
132
133         file_name = strrchr(app_path, '/');
134         if (file_name == NULL) {
135                 _D("file_name is NULL");
136                 return -1;
137         }
138
139         file_name++;
140         if (*file_name == '\0') {
141                 _D("can't locate file name to execute");
142                 return -1;
143         }
144
145         memset(process_name, '\0', AUL_PR_NAME);
146         snprintf(process_name, AUL_PR_NAME, "%s", file_name);
147         prctl(PR_SET_NAME, process_name);
148
149         ret = _wait_tep_mount(kb);
150         if (ret < 0)
151                 return -1;
152
153         ret = _prepare_app_socket();
154         if (ret < 0)
155                 return -1;
156
157         ret = _prepare_id_file();
158         if (ret < 0)
159                 return -1;
160
161         _send_cmd_to_amd(APP_STARTUP_SIGNAL);
162         return 0;
163 }
164
165 static int __default_launch_cb(bundle *kb, const char *appid,
166                 const char *app_path, const char *root_path,
167                 const char *pkgid, const char *pkg_type, int loader_type, bool global)
168 {
169         char err_str[MAX_LOCAL_BUFSZ] = { 0, };
170         int r;
171
172         r = __prepare_exec(appid, app_path, pkg_type, loader_type, pkgid,
173                         root_path, global, kb);
174         if (r < 0) {
175                 _E("__candidate_process_prepare_exec() failed");
176                 if (access(app_path, F_OK | R_OK)) {
177                         SECURE_LOGE("access() failed for file: \"%s\", " \
178                                 "error: %d (%s)", app_path, errno,
179                                 strerror_r(errno, err_str, sizeof(err_str)));
180                 }
181                 exit(-1);
182         }
183
184         return 0;
185 }
186
187 static int __candidate_process_launchpad_main_loop(app_pkt_t *pkt,
188                 char *out_app_path, int *out_argc, char ***out_argv, int type)
189 {
190         bundle *kb;
191         appinfo_t *menu_info = NULL;
192         const char *app_path = NULL;
193         int tmp_argc = 0;
194         char **tmp_argv = NULL;
195         int ret = -1;
196         int i;
197
198         kb = bundle_decode(pkt->data, pkt->len);
199         if (!kb) {
200                 _E("bundle decode error");
201                 exit(-1);
202         }
203
204         if (__bundle != NULL)
205                 bundle_free(__bundle);
206
207         __bundle = kb;
208         atexit(__at_exit_to_release_bundle);
209
210         menu_info = _appinfo_create(kb);
211         if (menu_info == NULL) {
212                 _D("such pkg no found");
213                 exit(-1);
214         }
215
216         if (menu_info->appid == NULL) {
217                 _E("Unable to get app_id");
218                 exit(-1);
219         }
220
221         if (type < 0) {
222                 _E("Invalid launchpad type: %d", type);
223                 exit(-1);
224         }
225
226         SECURE_LOGD("app id: %s, launchpad type: %d", menu_info->appid, type);
227
228         app_path = _appinfo_get_app_path(menu_info);
229         if (app_path == NULL) {
230                 _E("app_path is NULL");
231                 exit(-1);
232         }
233
234         if (app_path[0] != '/') {
235                 _E("app_path is not absolute path");
236                 exit(-1);
237         }
238
239         _modify_bundle(kb, /*cr.pid - unused parameter*/ 0, menu_info,
240                         pkt->cmd);
241
242         if (menu_info->pkgid == NULL) {
243                 _E("unable to get pkg_id from menu_info");
244                 exit(-1);
245         }
246
247         SECURE_LOGD("pkg id: %s", menu_info->pkgid);
248
249         /* Set environments */
250         _set_env(menu_info, kb);
251
252         tmp_argv = _create_argc_argv(kb, &tmp_argc);
253
254         if (__loader_callbacks->prelaunch) {
255                 ret = __loader_callbacks->prelaunch(tmp_argc, tmp_argv,
256                                 app_path, menu_info->appid, menu_info->pkgid,
257                                 menu_info->pkg_type, __loader_user_data);
258
259                 if (ret < 0) {
260                         _E("prelaunch callback fail (%d)", ret);
261                         exit(-1);
262                 }
263         }
264
265         __default_launch_cb(kb, menu_info->appid, app_path,
266                         menu_info->root_path, menu_info->pkgid,
267                         menu_info->pkg_type, type, menu_info->global);
268
269         if (__loader_callbacks->launch) {
270                 ret = __loader_callbacks->launch(tmp_argc, tmp_argv, app_path,
271                                 menu_info->appid, menu_info->pkgid,
272                                 menu_info->pkg_type, __loader_user_data);
273         }
274
275         if (out_app_path != NULL && out_argc != NULL && out_argv != NULL) {
276                 memset(out_app_path, '\0', strlen(out_app_path));
277                 snprintf(out_app_path, LOADER_ARG_LEN, "%s", app_path);
278
279                 *out_argv = tmp_argv;
280                 *out_argc = tmp_argc;
281                 (*out_argv)[LOADER_ARG_PATH] = out_app_path;
282
283                 for (i = 0; i < *out_argc; i++) {
284                         SECURE_LOGD("input argument %d : %s##", i,
285                                         (*out_argv)[i]);
286                 }
287         } else {
288                 exit(-1);
289         }
290
291         if (menu_info != NULL)
292                 _appinfo_free(menu_info);
293
294         if (__bundle) {
295                 bundle_free(__bundle);
296                 __bundle = NULL;
297         }
298
299         return ret;
300 }
301
302 static void __receiver_cb(int fd)
303 {
304         int ret = -1;
305         app_pkt_t *pkt;
306
307         _D("[candidate] ECORE_FD_READ");
308         pkt = _recv_pkt_raw(fd);
309         if (!pkt) {
310                 _D("[candidate] _recv_pkt_raw error!");
311                 exit(-1);
312         }
313
314         __loader_adapter->remove_fd(__loader_user_data, fd);
315         close(fd);
316         ret = __candidate_process_launchpad_main_loop(pkt,
317                         __argv[LOADER_ARG_PATH], &__argc, &__argv,
318                         __loader_type);
319         SECURE_LOGD("[candidate] real app argv[0]: %s, real app argc: %d",
320                         __argv[LOADER_ARG_PATH], __argc);
321         free(pkt);
322
323         if (ret >= 0) {
324                 __loader_adapter->loop_quit(__loader_user_data);
325                 _D("[candidate] ecore main loop quit");
326                 __loop_quit = true;
327         }
328 }
329
330 static void __update_lang(keynode_t *node, void *user_data)
331 {
332         char *lang;
333
334         lang = vconf_keynode_get_str(node);
335         if (!lang) {
336                 _E("Failed to get language");
337                 return;
338         }
339
340         setenv("LANG", lang, 1);
341 }
342
343 static void __region_format_changed_cb(keynode_t *node, void *user_data)
344 {
345         char *region;
346
347         region = vconf_keynode_get_str(node);
348         if (!region) {
349                 _E("Failed to get regionformat");
350                 return;
351         }
352
353         setenv("LC_CTYPE", region, 1);
354 }
355
356 static int __before_loop(int argc, char **argv)
357 {
358         int client_fd;
359         int ret = -1;
360         bundle *extra = NULL;
361         int r;
362
363         if (_verify_proc_caps() < 0)
364                 return -1;
365
366         __preexec_init(argc, argv);
367
368         /* Set new session ID & new process group ID*/
369         /* In linux, child can set new session ID without check permission */
370         /* TODO : should be add to check permission in the kernel*/
371         setsid();
372
373         memset(argv[LOADER_ARG_TYPE], 0, strlen(argv[LOADER_ARG_TYPE]));
374         memset(argv[LOADER_ARG_ID], 0, strlen(argv[LOADER_ARG_ID]));
375         if (argc > 3) {
376                 extra = bundle_decode((bundle_raw *)argv[LOADER_ARG_EXTRA],
377                                 strlen(argv[LOADER_ARG_EXTRA]));
378                 memset(argv[LOADER_ARG_EXTRA], 0,
379                                 strlen(argv[LOADER_ARG_EXTRA]));
380         }
381
382         if (__loader_callbacks->create) {
383                 __loader_callbacks->create(extra, __loader_type,
384                                 __loader_user_data);
385                 ret = 0;
386         }
387
388         if (extra)
389                 bundle_free(extra);
390
391         malloc_trim(0);
392
393         client_fd = _connect_to_launchpad(__loader_type, __loader_id);
394         if (client_fd == -1) {
395                 _D("Connecting to candidate process was failed.");
396                 return -1;
397         }
398
399         __loader_adapter->add_fd(__loader_user_data, client_fd, __receiver_cb);
400
401         r = vconf_notify_key_changed(VCONFKEY_LANGSET, __update_lang, NULL);
402         if (r != VCONF_OK)
403                 _E("Failed to register callback for langset. error(%d)", r);
404
405         r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT,
406                         __region_format_changed_cb, NULL);
407         if (r != VCONF_OK)
408                 _E("Failed to register callback for regionformat. error(%d)", r);
409
410         return ret;
411 }
412
413 static int __after_loop(void)
414 {
415         vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT,
416                         __region_format_changed_cb);
417         vconf_ignore_key_changed(VCONFKEY_LANGSET, __update_lang);
418
419         if (__loader_callbacks->terminate) {
420                 return __loader_callbacks->terminate(__argc, __argv,
421                                 __loader_user_data);
422         }
423
424         return -1;
425 }
426
427 API bundle *launchpad_loader_get_bundle(void)
428 {
429         return __bundle;
430 }
431
432 API int launchpad_loader_main(int argc, char **argv,
433                 loader_lifecycle_callback_s *callbacks,
434                 loader_adapter_s *adapter, void *user_data)
435 {
436         int is_hydra;
437
438         if (argc < 4) {
439                 _E("too few argument.");
440                 return -1;
441         }
442
443         is_hydra = argv[LOADER_ARG_HYDRA][0] - '0';
444
445         if (is_hydra) {
446                 _D("Cannot run in hydra mode");
447                 return -1;
448         }
449
450         __loader_type = atoi(argv[LOADER_ARG_TYPE]);
451         if (__loader_type < 0 || __loader_type >= LAUNCHPAD_TYPE_MAX) {
452                 _E("invalid argument. (type: %d)", __loader_type);
453                 return -1;
454         }
455
456         __loader_id = atoi(argv[LOADER_ARG_ID]);
457
458         if (callbacks == NULL) {
459                 _E("invalid argument. callback is null");
460                 return -1;
461         }
462
463         if (adapter == NULL) {
464                 _E("invalid argument. adapter is null");
465                 return -1;
466         }
467
468         if (adapter->loop_begin == NULL || adapter->loop_quit == NULL
469                 || adapter->add_fd == NULL || adapter->remove_fd == NULL) {
470                 _E("invalid argument. adapter callback is null");
471                 return -1;
472         }
473
474         __loader_callbacks = callbacks;
475         __loader_adapter = adapter;
476         __loader_user_data = user_data;
477         __argc = argc;
478         __argv = argv;
479
480         if (__before_loop(argc, argv) != 0) {
481                 _E("Failed to prepare running loader. type(%d)", __loader_type);
482                 return -1;
483         }
484
485         _D("[candidate] ecore main loop begin");
486         __loader_adapter->loop_begin(__loader_user_data);
487
488         if (!__loop_quit) {
489                 _E("[candidate] loop was stopped forcedly");
490                 return -1;
491         }
492
493         return __after_loop();
494 }
495
496 API int launchpad_loader_set_priority(int prio)
497 {
498         return _set_priority(prio);
499 }