tizen 2.3.1 release
[framework/appfw/aul-1.git] / src / launch_with_result.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
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <pthread.h>
27
28 #include "aul.h"
29 #include "aul_api.h"
30 #include "app_sock.h"
31 #include "simple_util.h"
32 #include "launch.h"
33 #include "aul_util.h"
34
35 /*#define ACTIVATE_PREEMPT_FEATURE*/
36
37 typedef struct _app_resultcb_info_t {
38         int launched_pid;
39         void (*cb_func) (bundle *kb, int is_cancel, void *data);
40         void *priv_data;
41         void (*caller_cb) (int launched_pid, void *data);
42         void *caller_data;
43         struct _app_resultcb_info_t *next;
44 } app_resultcb_info_t;
45
46 static int latest_caller_pid = -1;
47 static app_resultcb_info_t *rescb_head = NULL;
48 #ifdef _APPFW_FEATURE_APP_CONTROL_LITE
49 static app_resultcb_info_t *rescb_head2 = NULL;
50 #endif
51
52
53 static int is_subapp = 0;
54 subapp_fn subapp_cb = NULL;
55 void *subapp_data = NULL;
56
57 pthread_mutex_t result_lock = PTHREAD_MUTEX_INITIALIZER;
58
59 static void __add_resultcb(int pid, void (*cbfunc) (bundle *, int, void *),
60                          void *data);
61 static app_resultcb_info_t *__find_resultcb(int pid);
62 static void __remove_resultcb(app_resultcb_info_t *info);
63 static int __call_app_result_callback(bundle *kb, int is_cancel,
64                                     int launched_pid);
65 static int __get_caller_pid(bundle *kb);
66
67
68
69 static void __add_resultcb(int pid, void (*cbfunc) (bundle *, int, void *),
70                          void *data)
71 {
72         app_resultcb_info_t *info;
73
74         info = (app_resultcb_info_t *) malloc(sizeof(app_resultcb_info_t));
75         if(info == NULL)
76                 return;
77         info->launched_pid = pid;
78         info->cb_func = cbfunc;
79         info->priv_data = data;
80         info->caller_cb = NULL;
81         info->caller_data = NULL;
82
83         info->next = rescb_head;
84         rescb_head = info;
85 }
86
87 static app_resultcb_info_t *__find_resultcb(int pid)
88 {
89         app_resultcb_info_t *tmp;
90         app_resultcb_info_t *ret = NULL;
91
92         pthread_mutex_lock(&result_lock);
93         tmp = rescb_head;
94         while (tmp) {
95                 if (tmp->launched_pid == pid) {
96                         ret = tmp;
97                 }
98                 tmp = tmp->next;
99         }
100         pthread_mutex_unlock(&result_lock);
101
102         return ret;
103 }
104
105 static void __remove_resultcb(app_resultcb_info_t *info)
106 {
107         app_resultcb_info_t *tmp;
108
109         if (rescb_head == NULL || info == NULL)
110                 return;
111
112         if (rescb_head == info) {
113                 rescb_head = info->next;
114                 free(info);
115                 return;
116         }
117
118         tmp = rescb_head;
119         while (tmp) {
120                 if (tmp->next == info) {
121                         tmp->next = info->next;
122                         free(info);
123                         return;
124                 }
125                 tmp = tmp->next;
126         }
127 }
128
129 #ifdef _APPFW_FEATURE_APP_CONTROL_LITE
130 static void __add_resultcb2(int pid, void (*cbfunc) (bundle *, int, void *),
131                          void *data)
132 {
133         app_resultcb_info_t *info;
134
135         _D("id : %d", pid);
136
137         info = (app_resultcb_info_t *) malloc(sizeof(app_resultcb_info_t));
138         if(info == NULL)
139                 return;
140         info->launched_pid = pid;
141         info->cb_func = cbfunc;
142         info->priv_data = data;
143         info->caller_cb = NULL;
144         info->caller_data = NULL;
145
146         info->next = rescb_head2;
147         rescb_head2 = info;
148 }
149
150 static app_resultcb_info_t *__find_resultcb2(int pid)
151 {
152         app_resultcb_info_t *tmp;
153         app_resultcb_info_t *ret = NULL;
154
155         pthread_mutex_lock(&result_lock);
156         tmp = rescb_head2;
157         while (tmp) {
158                 _D("id_id : %d", tmp->launched_pid);
159                 if (tmp->launched_pid == pid) {
160                         ret = tmp;
161                 }
162                 tmp = tmp->next;
163         }
164         pthread_mutex_unlock(&result_lock);
165
166         return ret;
167 }
168
169 static void __remove_resultcb2(app_resultcb_info_t *info)
170 {
171         app_resultcb_info_t *tmp;
172
173         if (rescb_head2 == NULL || info == NULL)
174                 return;
175
176         if (rescb_head2 == info) {
177                 rescb_head2 = info->next;
178                 free(info);
179                 return;
180         }
181
182         tmp = rescb_head2;
183         while (tmp) {
184                 if (tmp->next == info) {
185                         tmp->next = info->next;
186                         free(info);
187                         return;
188                 }
189                 tmp = tmp->next;
190         }
191 }
192 #endif
193
194 /**
195  * call result callback function
196  * run in caller
197  */
198 static int __call_app_result_callback(bundle *kb, int is_cancel,
199                                     int launched_pid)
200 {
201         app_resultcb_info_t *info;
202         int pgid;
203         char *fwdpid_str;
204
205         if (((info = __find_resultcb(launched_pid)) == NULL)
206             || (launched_pid < 0)) {
207                 _E("reject by pid - wait pid = %d, recvd pid = %d\n", getpid(),
208                    launched_pid);
209
210                 /* second chance - support app launched by shell script*/
211                 pgid = getpgid(launched_pid);
212                 if (pgid <= 1)
213                         return -1;
214                 if ((info = __find_resultcb(pgid)) == NULL) {
215                         _E("second chance : also reject pgid - %d\n", pgid);
216                         return -1;
217                 }
218         }
219
220         if (info->cb_func == NULL || kb == NULL)
221                 return -1;
222
223         /* In case of aul_forward_app, update the callback data */
224 #ifdef _APPFW_FEATURE_APP_CONTROL_LITE
225         if(is_cancel == 1 && (fwdpid_str = (char *)bundle_get_val(kb, "__AUL_FWD_UG_ID__")))
226         {
227                 app_resultcb_info_t newinfo;
228                 newinfo.launched_pid = atoi(fwdpid_str);
229                 newinfo.cb_func = info->cb_func;
230                 newinfo.priv_data = info->priv_data;
231                 newinfo.caller_cb = NULL;
232                 newinfo.caller_data = NULL;
233
234                 if(info->caller_cb) {
235                         info->caller_cb(newinfo.launched_pid, info->caller_data);
236                 }
237
238                 __remove_resultcb(info);
239                 __add_resultcb2(newinfo.launched_pid, newinfo.cb_func, newinfo.priv_data);
240
241                 _D("change callback __AUL_FWD_UG_ID__ - %d\n", newinfo.launched_pid);
242
243                 goto end;
244         }
245         else if(is_cancel == 1 && (fwdpid_str = (char *)bundle_get_val(kb, AUL_K_FWD_CALLEE_PID)))
246 #else
247         if(is_cancel == 1 && (fwdpid_str = (char *)bundle_get_val(kb, AUL_K_FWD_CALLEE_PID)))
248 #endif
249         {
250                 app_resultcb_info_t newinfo;
251                 newinfo.launched_pid = atoi(fwdpid_str);
252                 newinfo.cb_func = info->cb_func;
253                 newinfo.priv_data = info->priv_data;
254                 newinfo.caller_cb = NULL;
255                 newinfo.caller_data = NULL;
256
257                 if(info->caller_cb) {
258                         info->caller_cb(newinfo.launched_pid, info->caller_data);
259                 }
260
261                 __remove_resultcb(info);
262                 __add_resultcb(newinfo.launched_pid, newinfo.cb_func, newinfo.priv_data);
263
264                 _D("change callback - %s\n",AUL_K_FWD_CALLEE_PID);
265
266                 goto end;
267         }
268
269         info->cb_func(kb, is_cancel, info->priv_data);
270         __remove_resultcb(info);
271
272 end:
273         return 0;
274 }
275
276 static int __get_caller_pid(bundle *kb)
277 {
278         const char *pid_str;
279         int pid;
280
281         pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
282         if(pid_str)
283                 goto end;
284
285         pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
286         if (pid_str == NULL)
287                 return -1;
288
289 end:
290         pid = atoi(pid_str);
291         if (pid <= 1)
292                 return -1;
293
294         return pid;
295 }
296
297 #ifdef ACTIVATE_PREEMPT_FEATURE
298 static int __send_to_cancel(int pid)
299 {
300         /* Say "Your result request is cancel!" to caller */
301         bundle *kb;
302         int ret;
303         char tmp_pid[MAX_PID_STR_BUFSZ];
304
305         kb = bundle_create();
306         if (kb == NULL)
307                 return AUL_R_ERROR;
308         bundle_add(kb, AUL_K_SEND_RESULT, "1");
309
310         snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", pid);
311         bundle_add(kb, AUL_K_CALLER_PID, tmp_pid);
312
313         ret = app_send_cmd(LAUNCHPAD_PID, APP_CANCEL, kb);
314
315         bundle_free(kb);
316         return ret;
317 }
318 #else
319 static int __send_to_cancel(int pid)
320 {
321         return 0;
322 }
323 #endif
324
325 int _app_start_res_prepare(bundle *kb)
326 {
327         int pid;
328         const char* str = NULL;
329
330         if (bundle_get_val(kb, AUL_K_WAIT_RESULT) == NULL)
331                 return 0;
332
333         str = bundle_get_val(kb, AUL_K_NO_CANCEL);
334         if( str && strncmp("1", str, 1) == 0) {
335                 _D("no cancel");
336                 return 0;
337         }
338
339         if ((pid = __get_caller_pid(kb)) < 0) {
340                 _E("caller pid is not valid");
341                 return -1;
342         }
343         /* If previous caller is still waiting result,
344            send cancel packet to the caller. */
345         if (latest_caller_pid != -1)
346                 __send_to_cancel(latest_caller_pid);
347
348         latest_caller_pid = pid;
349         _D("result msg prepare done");
350
351         return 0;
352 }
353
354 int app_result(int cmd, bundle *kb, int launched_pid)
355 {
356         switch (cmd) {
357         case APP_RESULT:
358                 __call_app_result_callback(kb, 0, launched_pid);
359                 break;
360         case APP_CANCEL:
361                 __call_app_result_callback(kb, 1, launched_pid);
362                 break;
363         }
364
365         return 0;
366 }
367
368 SLPAPI int aul_launch_app_with_result(const char *pkgname, bundle *kb,
369                                void (*cbfunc) (bundle *, int, void *),
370                                void *data)
371 {
372         int ret;
373 #ifdef _APPFW_FEATURE_APP_CONTROL_LITE
374         int id = -1;
375         char id_str[256] = {0, };
376 #endif
377
378         if (!aul_is_initialized()) {
379                 if (aul_launch_init(NULL, NULL) < 0)
380                         return AUL_R_ENOINIT;
381         }
382
383         if (pkgname == NULL || cbfunc == NULL || kb == NULL)
384                 return AUL_R_EINVAL;
385
386         pthread_mutex_lock(&result_lock);
387 #ifdef _APPFW_FEATURE_APP_CONTROL_LITE
388         id = rand();
389         sprintf(id_str, "%d", id);
390         bundle_add(kb, "__AUL_UG_ID__", id_str);
391 #endif
392         ret = app_request_to_launchpad(APP_START_RES, pkgname, kb);
393         if (ret > 0)
394                 __add_resultcb(ret, cbfunc, data);
395 #ifdef _APPFW_FEATURE_APP_CONTROL_LITE
396         else if (ret == AUL_R_UG_LOCAL) {
397                 __add_resultcb2(id, cbfunc, data);
398                 pthread_mutex_unlock(&result_lock);
399                 return getpid();
400         }
401 #endif
402         pthread_mutex_unlock(&result_lock);
403
404         return ret;
405 }
406
407 void __iterate(const char *key, const char *val, void *data)
408 {
409         static int i=0;
410         _D("%d %s %s", i++, key, val);
411 }
412
413 SLPAPI int aul_forward_app(const char* pkgname, bundle *kb)
414 {
415         char *caller;
416         int ret;
417         bundle *dupb;
418         bundle *outb;
419         char tmp_pid[MAX_PID_STR_BUFSZ];
420 #ifdef _APPFW_FEATURE_APP_CONTROL_LITE
421         int caller_pid;
422         int callee_pid;
423 #endif
424
425         if(pkgname == NULL || kb == NULL)
426                 return AUL_R_EINVAL;
427
428         caller = (char *)bundle_get_val(kb, AUL_K_CALLER_PID);
429         if(caller == NULL) {
430                 _E("original msg doest not have caller pid");
431                 return AUL_R_EINVAL;
432         }
433
434         bundle_del(kb, AUL_K_ORG_CALLER_PID);
435         bundle_add(kb, AUL_K_ORG_CALLER_PID, caller);
436
437 #ifdef _APPFW_FEATURE_APP_CONTROL_LITE
438         caller_pid = atoi(caller);
439 #endif
440
441         dupb = bundle_dup(kb);
442         if(dupb == NULL) {
443                 _E("bundle duplicate fail");
444                 return AUL_R_EINVAL;
445         }
446
447         if(bundle_get_val(kb, AUL_K_WAIT_RESULT) != NULL) {
448                 ret = app_request_to_launchpad(APP_START_RES, pkgname, kb);
449                 if(ret < 0)
450                         goto end;
451         } else {
452                 ret = app_request_to_launchpad(APP_START, pkgname, kb);
453                 goto end;
454         }
455
456 #ifdef _APPFW_FEATURE_APP_CONTROL_LITE
457         callee_pid = ret;
458 #endif
459
460         snprintf(tmp_pid, MAX_PID_STR_BUFSZ,"%d",ret);
461
462         ret = aul_create_result_bundle(dupb, &outb);
463         if(ret < 0)
464                 goto end;
465
466 #ifdef _APPFW_FEATURE_APP_CONTROL_LITE
467         _D("callee_pid(%d) caller_pid(%d)", callee_pid, caller_pid);
468
469         if(callee_pid == caller_pid) {
470                 bundle_del(outb, AUL_K_FWD_CALLEE_PID);
471                 bundle_add(outb, "__AUL_FWD_UG_ID__", bundle_get_val(kb, "__AUL_UG_ID__"));
472         } else {
473                 bundle_del(outb, AUL_K_FWD_CALLEE_PID);
474                 bundle_add(outb, AUL_K_FWD_CALLEE_PID, tmp_pid);
475         }
476 #else
477         bundle_del(outb, AUL_K_FWD_CALLEE_PID);
478         bundle_add(outb, AUL_K_FWD_CALLEE_PID, tmp_pid);
479 #endif
480
481 //      bundle_iterate(outb, __iterate, NULL);
482
483         ret = aul_send_result(outb, 1);
484
485         bundle_free(outb);
486 end:
487         bundle_free(dupb);
488
489         return ret;
490 }
491
492
493 SLPAPI int aul_create_result_bundle(bundle *inb, bundle **outb)
494 {
495         const char *pid_str;
496
497         *outb = NULL;
498
499         if(inb == NULL){
500                 _E("return msg create fail");
501                 return AUL_R_EINVAL;
502         }
503
504         *outb = bundle_create();
505         if (*outb == NULL) {
506                 _E("return msg create fail");
507                 return AUL_R_ERROR;
508         }
509
510         if(bundle_get_val(inb, AUL_K_WAIT_RESULT) != NULL) {
511                 bundle_add(*outb, AUL_K_SEND_RESULT, "1");
512                 _D("original msg is msg with result");
513         } else {
514                 _D("original msg is not msg with result");
515         }
516
517
518         pid_str = bundle_get_val(inb, AUL_K_ORG_CALLER_PID);
519         if(pid_str) {
520                 bundle_add(*outb, AUL_K_ORG_CALLER_PID, pid_str);
521                 goto end;
522         }
523
524         pid_str = bundle_get_val(inb, AUL_K_CALLER_PID);
525         if (pid_str == NULL) {
526                 _E("original msg doest not have caller pid");
527                 bundle_free(*outb);
528                 *outb = NULL;
529                 return AUL_R_EINVAL;
530         }
531         bundle_add(*outb, AUL_K_CALLER_PID, pid_str);
532
533 end:
534         return AUL_R_OK;
535 }
536
537 int aul_send_result(bundle *kb, int is_cancel)
538 {
539         int pid;
540         int ret;
541         int callee_pid;
542         int callee_pgid;
543         char callee_appid[256];
544         char tmp_pid[MAX_PID_STR_BUFSZ];
545
546         if ((pid = __get_caller_pid(kb)) < 0)
547                 return AUL_R_EINVAL;
548
549         _D("caller pid : %d", pid);
550
551         if (bundle_get_val(kb, AUL_K_SEND_RESULT) == NULL)
552         {
553                 _D("original msg is not msg with result");
554                 return AUL_R_OK;
555         }
556
557         callee_pid = getpid();
558         callee_pgid = getpgid(callee_pid);
559         snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", callee_pgid);
560         bundle_add(kb, AUL_K_CALLEE_PID, tmp_pid);
561
562         ret = aul_app_get_appid_bypid(callee_pid, callee_appid, sizeof(callee_appid));
563         if(ret == 0) {
564                 bundle_add(kb, AUL_K_CALLEE_APPID, callee_appid);
565         } else {
566                 _W("fail(%d) to get callee appid by pid", ret);
567         }
568
569         ret = app_send_cmd_with_noreply(AUL_UTIL_PID, (is_cancel==1)? APP_CANCEL : APP_RESULT, kb);
570
571         _D("app_send_cmd_with_noreply : %d", ret);
572
573         if(latest_caller_pid == pid)
574                 latest_caller_pid = -1;
575
576         return ret;
577 }
578
579 int app_subapp_terminate_request()
580 {
581         if(is_subapp) {
582                 subapp_cb(subapp_data);
583
584                 return 0;
585         }
586
587         return -1;
588 }
589
590 SLPAPI int aul_set_subapp(subapp_fn cb, void *data)
591 {
592         is_subapp = 1;
593         subapp_cb = cb;
594         subapp_data = data;
595
596         return 0;
597 }
598
599 SLPAPI int aul_subapp_terminate_request_pid(int pid)
600 {
601         char pid_str[MAX_PID_STR_BUFSZ];
602         int ret;
603         app_resultcb_info_t *info;
604
605         if (pid <= 0)
606                 return AUL_R_EINVAL;
607
608         info = __find_resultcb(pid);
609         if(info)
610                 __remove_resultcb(info);
611
612         snprintf(pid_str, MAX_PID_STR_BUFSZ, "%d", pid);
613         ret = app_request_to_launchpad(APP_TERM_REQ_BY_PID, pid_str, NULL);
614         return ret;
615 }
616
617 SLPAPI int aul_is_subapp()
618 {
619         return is_subapp;
620 }
621
622 SLPAPI int aul_add_caller_cb(int pid,  void (*caller_cb) (int, void *), void *data)
623 {
624         app_resultcb_info_t *info;
625
626         if (pid <= 0)
627                 return AUL_R_EINVAL;
628
629         info = __find_resultcb(pid);
630         if (info) {
631                 info->caller_cb = caller_cb;
632                 info->caller_data = data;
633         }
634
635         return 0;
636 }
637
638 SLPAPI int aul_remove_caller_cb(int pid)
639 {
640         app_resultcb_info_t *info;
641
642         if (pid <= 0)
643                 return AUL_R_EINVAL;
644
645         info = __find_resultcb(pid);
646         if(info) {
647                 info->caller_cb = NULL;
648                 info->caller_data = NULL;
649         }
650
651         return 0;
652 }
653
654 #ifdef _APPFW_FEATURE_APP_CONTROL_LITE
655 SLPAPI int aul_call_ug_result_callback(bundle *kb, int is_cancel, int id)
656 {
657         app_resultcb_info_t *info;
658         int pgid;
659
660         info = __find_resultcb2(id);
661
662         _D("id : %d", id);
663
664         info->cb_func(kb, is_cancel, info->priv_data);
665         __remove_resultcb2(info);
666
667         return 0;
668 }
669 #endif
670