Tizen 2.0 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
27 #include "aul.h"
28 #include "aul_api.h"
29 #include "app_sock.h"
30 #include "simple_util.h"
31 #include "launch.h"
32 #include "aul_util.h"
33
34 /*#define ACTIVATE_PREEMPT_FEATURE*/
35
36 typedef struct _app_resultcb_info_t {
37         int launched_pid;
38         void (*cb_func) (bundle *kb, int is_cancel, void *data);
39         void *priv_data;
40         struct _app_resultcb_info_t *next;
41 } app_resultcb_info_t;
42
43 static int latest_caller_pid = -1;
44 static app_resultcb_info_t *rescb_head = NULL;
45
46 static void __add_resultcb(int pid, void (*cbfunc) (bundle *, int, void *),
47                          void *data);
48 static app_resultcb_info_t *__find_resultcb(int pid);
49 static void __remove_resultcb(app_resultcb_info_t *info);
50 static int __call_app_result_callback(bundle *kb, int is_cancel,
51                                     int launched_pid);
52 static int __get_caller_pid(bundle *kb);
53
54
55
56 static void __add_resultcb(int pid, void (*cbfunc) (bundle *, int, void *),
57                          void *data)
58 {
59         app_resultcb_info_t *info;
60
61         info = (app_resultcb_info_t *) malloc(sizeof(app_resultcb_info_t));
62         if(info == NULL)
63                 return;
64         info->launched_pid = pid;
65         info->cb_func = cbfunc;
66         info->priv_data = data;
67
68         info->next = rescb_head;
69         rescb_head = info;
70 }
71
72 static app_resultcb_info_t *__find_resultcb(int pid)
73 {
74         app_resultcb_info_t *tmp;
75
76         tmp = rescb_head;
77         while (tmp) {
78                 if (tmp->launched_pid == pid)
79                         return tmp;
80                 tmp = tmp->next;
81         }
82         return NULL;
83 }
84
85 static void __remove_resultcb(app_resultcb_info_t *info)
86 {
87         app_resultcb_info_t *tmp;
88
89         if (rescb_head == NULL || info == NULL)
90                 return;
91
92         if (rescb_head == info) {
93                 rescb_head = info->next;
94                 free(info);
95                 return;
96         }
97
98         tmp = rescb_head;
99         while (tmp) {
100                 if (tmp->next == info) {
101                         tmp->next = info->next;
102                         free(info);
103                         return;
104                 }
105                 tmp = tmp->next;
106         }
107 }
108
109 /**
110  * call result callback function
111  * run in caller
112  */
113 static int __call_app_result_callback(bundle *kb, int is_cancel,
114                                     int launched_pid)
115 {
116         app_resultcb_info_t *info;
117         int pgid;
118         char *fwdpid_str;
119
120         if (((info = __find_resultcb(launched_pid)) == NULL)
121             || (launched_pid < 0)) {
122                 _E("reject by pid - wait pid = %d, recvd pid = %d\n", getpid(),
123                    launched_pid);
124
125                 /* second chance - support app launched by shell script*/
126                 pgid = getpgid(launched_pid);
127                 if (pgid <= 1)
128                         return -1;
129                 if ((info = __find_resultcb(pgid)) == NULL) {
130                         _E("second chance : also reject pgid - %d\n", pgid);
131                         return -1;
132                 }
133         }
134
135         if (info->cb_func == NULL || kb == NULL)
136                 return -1;
137
138         /* In case of aul_forward_app, update the callback data */
139         if(is_cancel == 1 &&
140         (fwdpid_str = (char *)bundle_get_val(kb, AUL_K_FWD_CALLEE_PID)))
141         {
142                 app_resultcb_info_t newinfo;
143                 newinfo.launched_pid = atoi(fwdpid_str);
144                 newinfo.cb_func = info->cb_func;
145                 newinfo.priv_data = info->priv_data;
146                 
147                 __remove_resultcb(info);
148                 __add_resultcb(newinfo.launched_pid, newinfo.cb_func, newinfo.priv_data);
149
150                 _D("change callback - %s\n",AUL_K_FWD_CALLEE_PID);
151                 
152                 goto end;
153         }               
154
155         info->cb_func(kb, is_cancel, info->priv_data);
156         __remove_resultcb(info);
157
158 end:
159         return 0;
160 }
161
162 static int __get_caller_pid(bundle *kb)
163 {
164         const char *pid_str;
165         int pid;
166
167         pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
168         if(pid_str)
169                 goto end;
170
171         pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
172         if (pid_str == NULL)
173                 return -1;
174
175 end:
176         pid = atoi(pid_str);
177         if (pid <= 1)
178                 return -1;
179
180         return pid;
181 }
182
183 #ifdef ACTIVATE_PREEMPT_FEATURE
184 static int __send_to_cancel(int pid)
185 {
186         /* Say "Your result request is cancel!" to caller */
187         bundle *kb;
188         int ret;
189         char tmp_pid[MAX_PID_STR_BUFSZ];
190
191         kb = bundle_create();
192         if (kb == NULL)
193                 return AUL_R_ERROR;
194         bundle_add(kb, AUL_K_SEND_RESULT, "1");
195
196         snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", pid);
197         bundle_add(kb, AUL_K_CALLER_PID, tmp_pid);
198
199         ret = app_send_cmd(LAUNCHPAD_PID, APP_CANCEL, kb);
200
201         bundle_free(kb);
202         return ret;
203 }
204 #else
205 static int __send_to_cancel(int pid)
206 {
207         return 0;
208 }
209 #endif
210
211 int _app_start_res_prepare(bundle *kb)
212 {
213         int pid;
214
215         if (bundle_get_val(kb, AUL_K_WAIT_RESULT) == NULL)
216                 return 0;
217
218         if ((pid = __get_caller_pid(kb)) < 0) {
219                 _E("caller pid is not valid");
220                 return -1;
221         }
222         /* If previous caller is still waiting result, 
223            send cancel packet to the caller. */
224         if (latest_caller_pid != -1)
225                 __send_to_cancel(latest_caller_pid);
226
227         latest_caller_pid = pid;
228         _D("result msg prepare done");
229
230         return 0;
231 }
232
233 int app_result(int cmd, bundle *kb, int launched_pid)
234 {
235         switch (cmd) {
236         case APP_RESULT:
237                 __call_app_result_callback(kb, 0, launched_pid);
238                 break;
239         case APP_CANCEL:
240                 __call_app_result_callback(kb, 1, launched_pid);
241                 break;
242         }
243
244         return 0;
245 }
246
247 SLPAPI int aul_launch_app_with_result(const char *pkgname, bundle *kb,
248                                void (*cbfunc) (bundle *, int, void *),
249                                void *data)
250 {
251         int ret;
252
253         if (!aul_is_initialized()) {
254                 if (aul_launch_init(NULL, NULL) < 0)
255                         return AUL_R_ENOINIT;
256         }
257
258         if (pkgname == NULL || cbfunc == NULL || kb == NULL)
259                 return AUL_R_EINVAL;
260
261         ret = app_request_to_launchpad(APP_START_RES, pkgname, kb);
262
263         if (ret > 0)
264                 __add_resultcb(ret, cbfunc, data);
265
266         return ret;
267 }
268
269 void __iterate(const char *key, const char *val, void *data)
270 {
271         static int i=0; 
272         _D("%d %s %s", i++, key, val);
273 }
274
275 SLPAPI int aul_forward_app(const char* pkgname, bundle *kb)
276 {
277         char *caller;
278         int ret;
279         bundle *dupb;
280         bundle *outb;
281         char tmp_pid[MAX_PID_STR_BUFSZ];
282
283         if(pkgname == NULL || kb == NULL)
284                 return AUL_R_EINVAL;
285         
286         caller = (char *)bundle_get_val(kb, AUL_K_CALLER_PID);
287         if(caller == NULL) {
288                 _E("original msg doest not have caller pid");
289                 return AUL_R_EINVAL;
290         }
291         
292         bundle_del(kb, AUL_K_ORG_CALLER_PID);
293         bundle_add(kb, AUL_K_ORG_CALLER_PID, caller);
294
295         dupb = bundle_dup(kb);
296         if(dupb == NULL) {
297                 _E("bundle duplicate fail");
298                 return AUL_R_EINVAL;
299         }
300         
301         if(bundle_get_val(kb, AUL_K_WAIT_RESULT) != NULL) {
302                 ret = app_request_to_launchpad(APP_START_RES, pkgname, kb);
303                 if(ret < 0) 
304                         goto end;       
305         } else {
306                 ret = app_request_to_launchpad(APP_START, pkgname, kb);
307                 goto end;
308         }
309                 
310 //      bundle_iterate(dupb, __iterate, NULL);
311
312         snprintf(tmp_pid, MAX_PID_STR_BUFSZ,"%d",ret);
313
314         ret = aul_create_result_bundle(dupb, &outb);
315         if(ret < 0)
316                 return ret;
317
318         bundle_del(outb, AUL_K_FWD_CALLEE_PID);         
319         bundle_add(outb, AUL_K_FWD_CALLEE_PID, tmp_pid);
320
321 //      bundle_iterate(outb, __iterate, NULL);
322
323         ret = aul_send_result(outb, 1);
324
325         bundle_free(outb);
326 end:
327         bundle_free(dupb);
328
329         return ret;
330 }
331
332
333 SLPAPI int aul_create_result_bundle(bundle *inb, bundle **outb)
334 {
335         const char *pid_str;
336
337         *outb = NULL;
338         
339         if(inb == NULL){
340                 _E("return msg create fail");
341                 return AUL_R_EINVAL;
342         }
343
344         *outb = bundle_create();
345         if (*outb == NULL) {
346                 _E("return msg create fail");
347                 return AUL_R_ERROR;
348         }
349
350         if(bundle_get_val(inb, AUL_K_WAIT_RESULT) != NULL) {
351                 bundle_add(*outb, AUL_K_SEND_RESULT, "1");
352                 _D("original msg is msg with result");
353         } else {
354                 _D("original msg is not msg with result");
355         }
356         
357
358         pid_str = bundle_get_val(inb, AUL_K_ORG_CALLER_PID);
359         if(pid_str) {
360                 bundle_add(*outb, AUL_K_ORG_CALLER_PID, pid_str);
361                 goto end;
362         }
363         
364         pid_str = bundle_get_val(inb, AUL_K_CALLER_PID);
365         if (pid_str == NULL) {
366                 _E("original msg doest not have caller pid");
367                 bundle_free(*outb);
368                 *outb = NULL;
369                 return AUL_R_EINVAL;
370         }
371         bundle_add(*outb, AUL_K_CALLER_PID, pid_str);
372
373 end:
374         return AUL_R_OK;
375 }
376
377 int aul_send_result(bundle *kb, int is_cancel)
378 {
379         int pid;
380         int ret;
381
382         if ((pid = __get_caller_pid(kb)) < 0)
383                 return AUL_R_EINVAL;
384
385         if (bundle_get_val(kb, AUL_K_SEND_RESULT) == NULL)
386         {
387                 _D("original msg is not msg with result");
388                 return AUL_R_OK;
389         }
390
391         ret = app_send_cmd(AUL_UTIL_PID, (is_cancel==1)? APP_CANCEL : APP_RESULT, kb);
392         
393         if(latest_caller_pid == pid)
394                 latest_caller_pid = -1;
395
396         return ret;
397 }
398