add new api to enable on external memory using pkgid
[framework/appfw/aul-1.git] / am_daemon / amd_launch.c
1 /*
2  *  aul
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jayoun Lee <airjany@samsung.com>, Sewook Park <sewook7.park@samsung.com>, Jaeho Lee <jaeho81.lee@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <signal.h>
23 #include <bundle.h>
24 #include <aul.h>
25 #include <glib.h>
26 #include <app-checker-server.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <app2ext_interface.h>
31
32 #include "amd_config.h"
33 #include "amd_launch.h"
34 #include "amd_appinfo.h"
35 #include "amd_status.h"
36 #include "app_sock.h"
37 #include "simple_util.h"
38 #include "amd_cgutil.h"
39
40
41 #define TERM_WAIT_SEC 3
42 #define INIT_PID 1
43
44 struct appinfomgr *_laf;
45 struct cginfo *_lcg;
46
47 typedef struct {
48         char *pkg_name;         /* package */
49         char *app_path;         /* exec */
50         char *original_app_path;        /* exec */
51         int multiple;           /* x_slp_multiple */
52         char *pkg_type;
53 } app_info_from_pkgmgr;
54
55 static GList *_kill_list;
56
57 struct ktimer {
58         pid_t pid;
59         char *group;
60         guint tid; /* timer ID */
61         struct cginfo *cg;
62 };
63
64 static void _prepare_exec(void)
65 {
66         setsid();
67
68         signal(SIGINT, SIG_DFL);
69         signal(SIGTERM, SIG_DFL);
70         signal(SIGCHLD, SIG_DFL);
71
72         /* TODO: do security job */
73         /* TODO: setuid */
74 }
75
76 static int _add_cgroup(struct cginfo *cg, const char *group, int pid)
77 {
78         int r;
79
80         r = cgutil_exist_group(cg, CTRL_MGR, group);
81         if (r == -1) {
82                 _E("exist check error: %s", strerror(errno));
83                 return -1;
84         }
85
86         if (r == 0) { /* not exist */
87                 r = cgutil_create_group(cg, CTRL_MGR, group);
88                 if (r == -1) {
89                         _E("create group error");
90                         return -1;
91                 }
92         }
93
94         r = cgutil_group_add_pid(cg, CTRL_MGR, group, pid);
95         if (r == -1) {
96                 _E("add pid to group error");
97                 cgutil_remove_group(cg, CTRL_MGR, group);
98                 return -1;
99         }
100
101         return 0;
102 }
103
104 static char **__create_argc_argv(bundle * kb, int *margc)
105 {
106         char **argv;
107         int argc;
108
109         argc = bundle_export_to_argv(kb, &argv);
110
111         *margc = argc;
112         return argv;
113 }
114 static void _do_exec(struct cginfo *cg, const char *cmd, const char *group, bundle *kb)
115 {
116         gchar **argv;
117         gint argc;
118         char **b_argv;
119         int b_argc;
120         gboolean b;
121         int r;
122
123         r = _add_cgroup(cg, group, getpid());
124         if (r == -1)
125                 return;
126
127         b = g_shell_parse_argv(cmd, &argc, &argv, NULL);
128
129         if (kb) {
130                 b_argv = __create_argc_argv(kb, &b_argc);
131                 b_argv[0] = strdup(argv[0]);
132                 _prepare_exec();
133                 execv(b_argv[0], b_argv);
134         }
135
136         if (b) {
137                 _prepare_exec();
138                 execv(argv[0], argv);
139         }
140
141         _E("exec error: %s", strerror(errno));
142         g_strfreev(argv);
143 }
144
145 int service_start(struct cginfo *cg, const char *group, const char *cmd, bundle *kb)
146 {
147         int r;
148         pid_t p;
149
150         if (!cg || !group || !*group || !cmd || !*cmd) {
151                 errno = EINVAL;
152                 _E("service start: %s", strerror(errno));
153                 return -1;
154         }
155
156         p = fork();
157         switch (p) {
158         case 0: /* child process */
159                 _do_exec(cg, cmd, group, kb);
160                 /* exec error */
161                 exit(0);
162                 break;
163         case -1:
164                 _E("service start: fork: %s", strerror(errno));
165                 r = -1;
166                 break;
167         default: /* parent process */
168                 _D("child process: %d", p);
169                 r = p;
170                 break;
171         }
172
173         return r;
174 }
175
176 int _start_srv(struct appinfo *ai, bundle *kb)
177 {
178         int r;
179         const char *group;
180         const char *cmd;
181
182         group = appinfo_get_filename(ai);
183
184         cmd = appinfo_get_value(ai, AIT_EXEC);
185         if (!cmd) {
186                 _E("start service: '%s' has no exec", group);
187                 return -1;
188         }
189
190         r = service_start(_lcg, group, cmd, kb);
191         if (r == -1) {
192                 _E("start service: '%s': failed", group);
193                 return -1;
194         }
195
196         return 0;
197 }
198
199 static void _free_kt(struct ktimer *kt)
200 {
201         if (!kt)
202                 return;
203
204         cgutil_unref(&kt->cg);
205         free(kt->group);
206         free(kt);
207 }
208
209 static void _kill_pid(struct cginfo *cg, const char *group, pid_t pid)
210 {
211         int r;
212
213         if (pid <= INIT_PID) /* block sending to all process or init */
214                 return;
215
216         r = cgutil_exist_group(cg, CTRL_MGR, group);
217         if (r == -1) {
218                 _E("send SIGKILL: exist: %s", strerror(errno));
219                 return;
220         }
221         if (r == 0) {
222                 _D("send SIGKILL: '%s' not exist", group);
223                 return;
224         }
225
226         /* TODO: check pid exist in group */
227
228         r = kill(pid, 0);
229         if (r == -1) {
230                 _D("send SIGKILL: pid %d not exist", pid);
231                 return;
232         }
233
234         r = kill(pid, SIGKILL);
235         if (r == -1)
236                 _E("send SIGKILL: %s", strerror(errno));
237 }
238
239 static gboolean _ktimer_cb(gpointer data)
240 {
241         struct ktimer *kt = data;
242
243         _kill_pid(kt->cg, kt->group, kt->pid);
244         _kill_list = g_list_remove(_kill_list, kt);
245         _free_kt(kt);
246
247         return FALSE;
248 }
249
250 static void _add_list(struct cginfo *cg, const char *group, pid_t pid)
251 {
252         struct ktimer *kt;
253
254         kt = calloc(1, sizeof(*kt));
255         if (!kt)
256                 return;
257
258         kt->pid = pid;
259         kt->group = strdup(group);
260         if (!kt->group) {
261                 free(kt);
262                 return;
263         }
264
265         kt->cg = cgutil_ref(cg);
266         kt->tid = g_timeout_add_seconds(TERM_WAIT_SEC, _ktimer_cb, kt);
267
268         _kill_list = g_list_append(_kill_list, kt);
269 }
270
271 static inline void _del_list(GList *l)
272 {
273         struct ktimer *kt;
274
275         if (!l)
276                 return;
277
278         kt = l->data;
279
280         g_source_remove(kt->tid);
281         _free_kt(kt);
282         _kill_list = g_list_delete_link(_kill_list, l);
283 }
284
285 static int _kill_pid_cb(void *user_data, const char *group, pid_t pid)
286 {
287         int r;
288
289         if (pid <= INIT_PID) /* block sending to all process or init */
290                 return 0;
291
292         r = kill(pid, SIGTERM);
293         if (r == -1)
294                 _E("send SIGTERM: %s", strerror(errno));
295
296         _add_list(user_data, group, pid);
297
298         return 0;
299 }
300
301 int service_stop(struct cginfo *cg, const char *group)
302 {
303         if (!cg || !group || !*group) {
304                 errno = EINVAL;
305                 return -1;
306         }
307
308         return cgutil_group_foreach_pid(cg, CTRL_MGR, FILENAME(group),
309                         _kill_pid_cb, cg);
310 }
311
312 void service_release(const char *group)
313 {
314         GList *l;
315         GList *d;
316
317         if (!group || !*group)
318                 return;
319
320         group = FILENAME(group);
321
322         d = NULL;
323         for (l = _kill_list; l; l = g_list_next(l)) {
324                 struct ktimer *k = l->data;
325
326                 _del_list(d);
327
328                 if (k->group && !strcmp(k->group, group))
329                         d = l;
330         }
331
332         _del_list(d);
333 }
334
335 int _send_to_sigkill(int pid)
336 {
337         int pgid;
338
339         pgid = getpgid(pid);
340         if (pgid <= 1)
341                 return -1;
342
343         if (killpg(pgid, SIGKILL) < 0)
344                 return -1;
345
346         return 0;
347 }
348 int _resume_app(int pid)
349 {
350         int dummy;
351         int ret;
352         if ((ret =
353              __app_send_raw(pid, APP_RESUME_BY_PID, (unsigned char *)&dummy,
354                             sizeof(int))) < 0) {
355                 if (ret == -EAGAIN)
356                         _E("resume packet timeout error");
357                 else {
358                         _E("raise failed - %d resume fail\n", pid);
359                         _E("we will term the app - %d\n", pid);
360                         _send_to_sigkill(pid);
361                         ret = -1;
362                 }
363         }
364         _D("resume done\n");
365         return ret;
366 }
367
368 int _term_app(int pid)
369 {
370         int dummy;
371         if (__app_send_raw
372             (pid, APP_TERM_BY_PID, (unsigned char *)&dummy, sizeof(int)) < 0) {
373                 _D("terminate packet send error - use SIGKILL");
374                 if (_send_to_sigkill(pid) < 0) {
375                         _E("fail to killing - %d\n", pid);
376                         return -1;
377                 }
378         }
379         _D("term done\n");
380         return 0;
381 }
382
383 int _fake_launch_app(int cmd, int pid, bundle * kb)
384 {
385         int datalen;
386         int ret;
387         bundle_raw *kb_data;
388
389         bundle_encode(kb, &kb_data, &datalen);
390         if ((ret = __app_send_raw(pid, cmd, kb_data, datalen)) < 0)
391                 _E("error request fake launch - error code = %d", ret);
392         free(kb_data);
393         return ret;
394 }
395
396 static int __nofork_processing(int cmd, int pid, bundle * kb)
397 {
398         int ret = -1;
399         switch (cmd) {
400         case APP_OPEN:
401         case APP_RESUME:
402                 _D("resume app's pid : %d\n", pid);
403                 if ((ret = _resume_app(pid)) < 0)
404                         _E("__resume_app failed. error code = %d", ret);
405                 _D("resume app done");
406                 break;
407
408         case APP_START:
409         case APP_START_RES:
410                 _D("fake launch pid : %d\n", pid);
411                 if ((ret = _fake_launch_app(cmd, pid, kb)) < 0)
412                         _E("fake_launch failed. error code = %d", ret);
413                 _D("fake launch done");
414                 break;
415         }
416         return ret;
417 }
418
419 static void __real_send(int clifd, int ret)
420 {
421         if (send(clifd, &ret, sizeof(int), MSG_NOSIGNAL) < 0) {
422                 if (errno == EPIPE) {
423                         _E("send failed due to EPIPE.\n");
424                 }
425                 _E("send fail to client");
426         }
427
428         close(clifd);
429 }
430
431 int __sat_ui_is_running()
432 {
433         char *apppath = "/usr/apps/org.tizen.sat-ui/bin/sat-ui";
434         int ret = 0;
435
436         ret = __proc_iter_cmdline(NULL, apppath);
437
438         return ret;
439 }
440
441 int __sat_ui_launch(char* appid, bundle* kb, int cmd, int caller_pid, int fd)
442 {
443         int ret = -1;
444         char *app_path = "/usr/apps/org.tizen.sat-ui/bin/sat-ui KEY_EXEC_TYPE 0";
445         int pid = -1;
446         char tmp_pid[MAX_PID_STR_BUFSZ];
447
448         snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", caller_pid);
449         bundle_add(kb, AUL_K_CALLER_PID, tmp_pid);
450
451         pid = __sat_ui_is_running();
452
453         if (pid > 0) {
454                 if (caller_pid == pid) {
455                         _D("caller process & callee process is same.[%s:%d]", appid, pid);
456                         pid = -ELOCALLAUNCH_ID;
457                 } else if ((ret = __nofork_processing(cmd, pid, kb)) < 0) {
458                         pid = ret;
459                 }
460         } else if (cmd != APP_RESUME) {
461                 bundle_add(kb, AUL_K_HWACC, "NOT_USE");
462                 bundle_add(kb, AUL_K_EXEC, app_path);
463                 bundle_add(kb, AUL_K_PACKAGETYPE, "rpm");
464                 pid = app_send_cmd(LAUNCHPAD_PID, cmd, kb);
465         }
466
467         __real_send(fd, pid);
468
469         if(pid > 0) {
470                 //_status_add_app_info_list(appid, app_path, pid);
471                 ac_server_check_launch_privilege(appid, "rpm", pid);
472         }
473
474         return pid;
475 }
476
477 int _start_app(char* appid, bundle* kb, int cmd, int caller_pid, int fd)
478 {
479         struct appinfo *ai;
480         int ret = -1;
481         char *componet = NULL;
482         char *multiple = NULL;
483         char *app_path = NULL;
484         char *pkg_type = NULL;
485         char *pkg_id = NULL;
486         int pid = -1;
487         char tmp_pid[MAX_PID_STR_BUFSZ];
488         char *hwacc;
489
490         if(strncmp(appid, "org.tizen.sat-ui", 18) == 0) {
491                 pid = __sat_ui_launch(appid, kb, cmd, caller_pid, fd);
492                 return pid;
493         }
494
495         snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", caller_pid);
496         bundle_add(kb, AUL_K_CALLER_PID, tmp_pid);
497
498         if (cmd == APP_START_RES)
499                 bundle_add(kb, AUL_K_WAIT_RESULT, "1");
500
501         ai = appinfo_find(_laf, appid);
502
503         componet = appinfo_get_value(ai, AIT_COMP);
504         app_path = appinfo_get_value(ai, AIT_EXEC);
505         pkg_type = appinfo_get_value(ai, AIT_TYPE);
506         pkg_id = appinfo_get_value(ai, AIT_PKGID);
507
508         ret = app2ext_enable_external_pkg(pkg_id);
509         if (ret < 0)
510                 _E("pass enable external pkg");
511
512         if (componet && strncmp(componet, "ui", 2) == 0) {
513                 multiple = appinfo_get_value(ai, AIT_MULTI);
514                 if (!multiple || strncmp(multiple, "false", 5) == 0) {
515                         pid = _status_app_is_running_v2(appid);
516                 }
517
518                 if (pid > 0) {
519                         if (caller_pid == pid) {
520                                 _D("caller process & callee process is same.[%s:%d]", appid, pid);
521                                 pid = -ELOCALLAUNCH_ID;
522                         } else if ((ret = __nofork_processing(cmd, pid, kb)) < 0) {
523                                 pid = ret;
524                         }
525                 } else if (cmd != APP_RESUME) {
526                         hwacc = appinfo_get_value(ai, AIT_HWACC);
527                         bundle_add(kb, AUL_K_HWACC, hwacc);
528                         bundle_add(kb, AUL_K_EXEC, app_path);
529                         bundle_add(kb, AUL_K_PACKAGETYPE, pkg_type);
530                         if(strncmp(pkg_type, "wgt", 3) == 0) {
531                                 pid = app_send_cmd(WEB_LAUNCHPAD_PID, cmd, kb);
532                         } else {
533                                 pid = app_send_cmd(LAUNCHPAD_PID, cmd, kb);
534                         }
535                         //_add_cgroup(_lcg, appid, pid);
536                 }
537         } else if (componet && strncmp(componet, "svc", 3) == 0) {
538                 pid = _status_app_is_running_v2(appid);
539                 if (pid > 0) {
540                         if ((ret = __nofork_processing(cmd, pid, kb)) < 0) {
541                                 pid = ret;
542                         }
543                 } else if (cmd != APP_RESUME) {
544                         pid = service_start(_lcg, appid, app_path, kb);
545                 }
546         } else {
547                 _E("unkown application");
548         }
549
550         __real_send(fd, pid);
551
552         if(pid > 0) {
553                 //_status_add_app_info_list(appid, app_path, pid);
554                 ret = ac_server_check_launch_privilege(appid, appinfo_get_value(ai, AIT_TYPE), pid);
555                 return ret != AC_R_ERROR ? pid : -1;
556         }
557
558         return pid;
559 }
560
561
562 int _launch_init(struct amdmgr* amd)
563 {
564         _laf = amd->af;
565         _lcg = amd->cg;
566
567         return 0;
568 }
569
570
571