2acb5addf02acb773139c0c807d54e4dad69c8a4
[platform/core/appfw/aul-1.git] / src / 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
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/time.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <dirent.h>
31 #include <glib.h>
32
33 #include "aul.h"
34 #include "aul_api.h"
35 #include "app_sock.h"
36 #include "perf.h"
37 #include "simple_util.h"
38 #include "launch.h"
39 #include "key.h"
40 #include "aul_util.h"
41
42 static int aul_initialized = 0;
43 static int aul_fd;
44 static void *__window_object = NULL;
45 static void *__bg_object = NULL;
46 static void *__conformant_object = NULL;
47
48 static int (*_aul_handler) (aul_type type, bundle *kb, void *data) = NULL;
49 static void *_aul_data;
50
51 static int app_resume();
52 static int app_terminate();
53 static void __clear_internal_key(bundle *kb);
54 static inline void __set_stime(bundle *kb);
55 static int __app_start_internal(gpointer data);
56 static int __app_launch_local(bundle *b);
57 static int __send_result_to_launchpad(int fd, int res);
58
59 static data_control_provider_handler_fn __dc_handler = NULL;
60 extern  int aul_launch_fini();
61
62 int aul_is_initialized()
63 {
64         return aul_initialized;
65 }
66
67 int __call_aul_handler(aul_type type, bundle *kb)
68 {
69         if (_aul_handler)
70                 _aul_handler(type, kb, _aul_data);
71         return 0;
72 }
73
74 int app_start(bundle *kb)
75 {
76         const char *str = NULL;
77
78         _app_start_res_prepare(kb);
79         __call_aul_handler(AUL_START, kb);
80         // Handle the DataControl callback
81         str = bundle_get_val(kb, AUL_K_DATA_CONTROL_TYPE);
82         if (str != NULL && strcmp(str, "CORE") == 0)
83         {
84                 if (__dc_handler != NULL)
85                 {
86                         __dc_handler(kb, 0, NULL); // bundle, request_id, data
87                 }
88         }
89         return 0;
90 }
91
92 static int app_resume()
93 {
94         __call_aul_handler(AUL_RESUME, NULL);
95         return 0;
96 }
97
98 static int app_terminate()
99 {
100         __call_aul_handler(AUL_TERMINATE, NULL);
101         return 0;
102 }
103
104 static int bgapp_terminate(void)
105 {
106         __call_aul_handler(AUL_TERMINATE_BGAPP, NULL);
107         return 0;
108 }
109
110 static int app_pause(void)
111 {
112         __call_aul_handler(AUL_PAUSE, NULL);
113         return 0;
114 }
115
116 static int __get_aul_error(int res)
117 {
118         int ret;
119
120         switch (res) {
121         case -EREJECTED:
122                 ret = AUL_R_EREJECTED;
123                 break;
124         case -ENOENT:
125                 ret = AUL_R_ENOAPP;
126                 break;
127         case -ENOLAUNCHPAD:
128                 ret = AUL_R_ENOLAUNCHPAD;
129                 break;
130         case -ETERMINATING:
131                 ret = AUL_R_ETERMINATING;
132                 break;
133         case -EILLEGALACCESS:
134                 ret = AUL_R_EILLACC;
135                 break;
136         case -ELOCALLAUNCH_ID:
137                 ret = AUL_R_LOCAL;
138                 break;
139         case -EAGAIN:
140                 ret = AUL_R_ETIMEOUT;
141                 break;
142         case -EINVAL:
143                 ret = AUL_R_EINVAL;
144                 break;
145         case -ECOMM:
146                 ret = AUL_R_ECOMM;
147                 break;
148         default:
149                 ret = AUL_R_ERROR;
150         }
151
152         return ret;
153 }
154
155 static int __app_send_cmd_with_fd(int pid, int uid, int cmd, bundle *kb, int *ret_fd)
156 {
157         int datalen;
158         bundle_raw *kb_data = NULL;
159         int res = AUL_R_OK;
160
161         res = bundle_encode(kb, &kb_data, &datalen);
162         if (res != BUNDLE_ERROR_NONE) {
163                 return AUL_R_EINVAL;
164         }
165         if ((res = __app_send_raw_with_fd_reply(pid, uid, cmd, kb_data, datalen, ret_fd)) < 0) {
166                 switch (res) {
167                         case -EINVAL:
168                                 res = AUL_R_EINVAL;
169                                 break;
170                         case -ECOMM:
171                                 res = AUL_R_ECOMM;
172                                 break;
173                         case -EAGAIN:
174                                 res = AUL_R_ETIMEOUT;
175                                 break;
176                         case -ELOCALLAUNCH_ID:
177                                 res = AUL_R_LOCAL;
178                                 break;
179                         case -EILLEGALACCESS:
180                                 res = AUL_R_EILLACC;
181                                 break;
182                         case -ETERMINATING:
183                                 res = AUL_R_ETERMINATING;
184                                 break;
185                         case -ENOLAUNCHPAD:
186                                 res = AUL_R_ENOLAUNCHPAD;
187                                 break;
188 #ifdef _APPFW_FEATURE_APP_CONTROL_LITE
189                         case -EUGLOCAL_LAUNCH:
190                                 res = AUL_R_UG_LOCAL;
191                                 break;
192 #endif
193                         case -EREJECTED:
194                                 res = AUL_R_EREJECTED;
195                                 break;
196                         default:
197                                 res = AUL_R_ERROR;
198                 }
199         }
200         free(kb_data);
201
202         return res;
203 }
204
205 /**
206  * @brief       encode kb and send it to 'pid'
207  * @param[in]   pid             receiver's pid
208  * @param[in]   cmd             message's status (APP_START | APP_RESULT)
209  * @param[in]   kb              data
210  */
211 SLPAPI int app_agent_send_cmd(int uid, int cmd, bundle *kb)
212 {
213         int datalen;
214         bundle_raw *kb_data;
215         int res;
216
217         bundle_encode(kb, &kb_data, &datalen);
218         if ((res = __app_agent_send_raw(uid, cmd, kb_data, datalen)) < 0)
219                 res = __get_aul_error(res);
220         free(kb_data);
221
222         return res;
223 }
224
225 SLPAPI int app_agent_send_cmd_with_noreply(int uid, int cmd, bundle *kb)
226 {
227         int datalen;
228         bundle_raw *kb_data;
229         int res;
230
231         bundle_encode(kb, &kb_data, &datalen);
232         if ((res = __app_send_raw_with_noreply(uid, cmd, kb_data, datalen)) < 0)
233                 res = __get_aul_error(res);
234         free(kb_data);
235
236         return res;
237 }
238
239 /**
240  * @brief       encode kb and send it to 'pid'
241  * @param[in]   pid             receiver's pid
242  * @param[in]   cmd             message's status (APP_START | APP_RESULT)
243  * @param[in]   kb              data
244  */
245 SLPAPI int app_send_cmd(int pid, int cmd, bundle *kb)
246 {
247         return app_send_cmd_for_uid(pid, getuid(), cmd, kb);
248 }
249
250 SLPAPI int app_send_cmd_for_uid(int pid, uid_t uid, int cmd, bundle *kb)
251 {
252         int datalen;
253         bundle_raw *kb_data;
254         int res;
255
256         bundle_encode(kb, &kb_data, &datalen);
257         if ((res = __app_send_raw_for_uid(pid, uid, cmd, kb_data, datalen)) < 0)
258                 res = __get_aul_error(res);
259         free(kb_data);
260
261         return res;
262 }
263
264 SLPAPI int app_send_cmd_with_noreply(int pid, int cmd, bundle *kb)
265 {
266         int datalen;
267         bundle_raw *kb_data;
268         int res;
269
270         bundle_encode(kb, &kb_data, &datalen);
271         if ((res = __app_send_raw_with_noreply(pid, cmd, kb_data, datalen)) < 0)
272                 res = __get_aul_error(res);
273         free(kb_data);
274
275         return res;
276 }
277
278 static void __clear_internal_key(bundle *kb)
279 {
280         bundle_del(kb, AUL_K_CALLER_PID);
281         bundle_del(kb, AUL_K_APPID);
282         bundle_del(kb, AUL_K_WAIT_RESULT);
283         bundle_del(kb, AUL_K_SEND_RESULT);
284         bundle_del(kb, AUL_K_ARGV0);
285 }
286
287 static inline void __set_stime(bundle *kb)
288 {
289         struct timeval tv;
290         char tmp[MAX_LOCAL_BUFSZ];
291
292         gettimeofday(&tv, NULL);
293         snprintf(tmp, MAX_LOCAL_BUFSZ, "%ld/%ld", tv.tv_sec, tv.tv_usec);
294         bundle_add(kb, AUL_K_STARTTIME, tmp);
295 }
296
297 static int __app_start_internal(gpointer data)
298 {
299         bundle *kb;
300
301         kb = (bundle *) data;
302         app_start(kb);
303         bundle_free(kb);
304
305         return 0;
306 }
307
308 static int __app_launch_local(bundle *b)
309 {
310         if (!aul_is_initialized())
311                 return AUL_R_ENOINIT;
312
313         if (b == NULL) {
314                 _E("bundle for APP_START is NULL");
315         }
316         if (g_idle_add(__app_start_internal, b) > 0)
317                 return AUL_R_OK;
318         else
319                 return AUL_R_ERROR;
320 }
321
322 static int __app_resume_local()
323 {
324         if (!aul_is_initialized())
325                 return AUL_R_ENOINIT;
326
327         app_resume();
328
329         return 0;
330 }
331
332 int app_request_to_launchpad_with_fd(int cmd, const char *appid, bundle *kb, int *fd, int uid)
333 {
334         int must_free = 0;
335         int ret = 0;
336
337         SECURE_LOGD("launch request : %s", appid);
338         if (kb == NULL) {
339                 kb = bundle_create();
340                 must_free = 1;
341         } else
342                 __clear_internal_key(kb);
343
344         ret = __app_send_cmd_with_fd(AUL_UTIL_PID, uid, cmd, kb, fd);
345
346         _D("launch request result : %d", ret);
347         if (ret == AUL_R_LOCAL) {
348                 _E("app_request_to_launchpad : Same Process Send Local");
349                 bundle *b;
350
351                 switch (cmd) {
352                         case APP_START:
353                         case APP_START_RES:
354                                 b = bundle_dup(kb);
355                                 ret = __app_launch_local(b);
356                                 break;
357                         case APP_OPEN:
358                         case APP_RESUME:
359                         case APP_RESUME_BY_PID:
360                                 ret = __app_resume_local();
361                                 break;
362                         default:
363                                 _E("no support packet");
364                 }
365
366         }
367
368         /*   cleanup */
369         if (must_free)
370                 bundle_free(kb);
371
372         return ret;
373 }
374
375
376 /**
377  * @brief       start caller with kb
378  * @return      callee's pid
379  */
380 int app_request_to_launchpad(int cmd, const char *appid, bundle *kb)
381 {
382         return app_request_to_launchpad_for_uid(cmd, appid, kb, getuid());
383 }
384
385 int app_request_to_launchpad_for_uid(int cmd, const char *appid, bundle *kb, uid_t uid)
386 {
387         int must_free = 0;
388         int ret = 0;
389
390         SECURE_LOGD("launch request : %s", appid);
391         if (kb == NULL) {
392                 kb = bundle_create();
393                 must_free = 1;
394         } else
395                 __clear_internal_key(kb);
396
397         bundle_add(kb, AUL_K_APPID, appid);
398         __set_stime(kb);
399         ret = app_send_cmd_for_uid(AUL_UTIL_PID, uid, cmd, kb);
400
401         _D("launch request result : %d", ret);
402         if (ret == AUL_R_LOCAL) {
403                 _E("app_request_to_launchpad : Same Process Send Local");
404                 bundle *b;
405
406                 switch (cmd) {
407                         case APP_START:
408                         case APP_START_RES:
409                                 b = bundle_dup(kb);
410                                 ret = __app_launch_local(b);
411                                 break;
412                         case APP_OPEN:
413                         case APP_RESUME:
414                         case APP_RESUME_BY_PID:
415                                 ret = __app_resume_local();
416                                 break;
417                         default:
418                                 _E("no support packet");
419                 }
420
421         }
422
423         /* cleanup */
424         if (must_free)
425                 bundle_free(kb);
426
427         return ret;
428 }
429
430 static int __send_result_to_launchpad(int fd, int res)
431 {
432         if (send(fd, &res, sizeof(int), MSG_NOSIGNAL) < 0) {
433                 if (errno == EPIPE) {
434                         _E("send failed due to EPIPE.\n");
435                         close(fd);
436                         return -1;
437                 }
438                 _E("send fail to client");
439         }
440         close(fd);
441         return 0;
442 }
443
444 /**
445  * @brief       caller & callee's sock handler
446  */
447 int aul_sock_handler(int fd)
448 {
449         app_pkt_t *pkt;
450         bundle *kbundle;
451         int clifd;
452         struct ucred cr;
453
454         const char *pid_str;
455         int pid;
456         int ret;
457
458         if ((pkt = __app_recv_raw(fd, &clifd, &cr)) == NULL) {
459                 _E("recv error");
460                 return -1;
461         }
462
463         if (pkt->cmd != APP_RESULT && pkt->cmd != APP_CANCEL && pkt->cmd != APP_TERM_BY_PID_ASYNC) {
464                 ret = __send_result_to_launchpad(clifd, 0);
465                 if (ret < 0) {
466                         free(pkt);
467                         return -1;
468                 }
469         } else {
470                 close(clifd);
471         }
472
473         switch (pkt->cmd) {
474         case APP_START: /* run in callee */
475         case APP_START_RES:
476                 kbundle = bundle_decode(pkt->data, pkt->len);
477                 if (kbundle == NULL)
478                         goto err;
479                 app_start(kbundle);
480                 bundle_free(kbundle);
481                 break;
482
483         case APP_OPEN:  /* run in callee */
484         case APP_RESUME:
485         case APP_RESUME_BY_PID:
486                 app_resume();
487                 break;
488
489         case APP_TERM_BY_PID:   /* run in callee */
490         case APP_TERM_BY_PID_ASYNC:
491                 app_terminate();
492                 break;
493
494         case APP_TERM_BGAPP_BY_PID:
495                 bgapp_terminate();
496                 break;
497
498         case APP_TERM_REQ_BY_PID:       /* run in callee */
499                 app_subapp_terminate_request();
500                 break;
501
502         case APP_RESULT:        /* run in caller */
503         case APP_CANCEL:
504                 kbundle = bundle_decode(pkt->data, pkt->len);
505                 if (kbundle == NULL)
506                         goto err;
507
508                 pid_str = bundle_get_val(kbundle, AUL_K_CALLEE_PID);
509                 pid = atoi(pid_str);
510
511                 app_result(pkt->cmd, kbundle, pid);
512                 bundle_free(kbundle);
513                 break;
514
515         case APP_KEY_EVENT:     /* run in caller */
516                 kbundle = bundle_decode(pkt->data, pkt->len);
517                 if (kbundle == NULL)
518                         goto err;
519                 app_key_event(kbundle);
520                 bundle_free(kbundle);
521                 break;
522
523         case APP_PAUSE_BY_PID:
524                 app_pause();
525                 break;
526
527         default:
528                 _E("no support packet");
529         }
530
531         free(pkt);
532         return 0;
533
534 err:
535         free(pkt);
536         return -1;
537 }
538
539 int aul_make_bundle_from_argv(int argc, char **argv, bundle **kb)
540 {
541         int ac = 1;
542
543         char *buf = NULL;
544
545         *kb = bundle_create();
546         if (*kb == NULL)
547                 return AUL_R_ERROR;
548
549         if (argv == NULL)
550                 return AUL_R_OK;
551
552         if ((argv != NULL) && (argv[0] != NULL)) {
553                 buf = strdup(argv[0]);
554                 if (NULL == buf) {
555                         _E("Malloc failed");
556                         return AUL_R_ERROR;
557                 }
558
559                 bundle_add(*kb, AUL_K_ARGV0, buf);
560         }
561         if (buf) {              /*Prevent FIX: ID 38717 */
562                 free(buf);
563                 buf = NULL;
564         }
565
566         while (ac < argc) {
567                 if (ac + 1 == argc) {
568                         if (bundle_add(*kb, argv[ac], "") < 0) {
569                                 _E("bundle add error pos - %d", ac);
570                                 return AUL_R_ECANCELED;
571                         }
572                 } else {
573                         if (bundle_add(*kb, argv[ac], argv[ac + 1]) < 0) {
574                                 _E("bundle add error pos - %d", ac);
575                                 return AUL_R_ECANCELED;
576                         }
577                 }
578                 ac = ac + 2;
579         }
580
581         return AUL_R_OK;
582 }
583
584 int aul_register_init_callback(
585         int (*aul_handler) (aul_type type, bundle *, void *), void *data)
586 {
587         /* Save start handler function in static var */
588         _aul_handler = aul_handler;
589         _aul_data = data;
590         return 0;
591 }
592
593 int aul_initialize()
594 {
595         if (aul_initialized) {
596                 //_E("aul already initialized");
597                 return AUL_R_ECANCELED;
598         }
599
600         aul_fd = __create_server_sock(getpid());
601         if (aul_fd < 0) {
602                 _E("aul_init create sock failed");
603                 return AUL_R_ECOMM;
604         }
605         aul_initialized = 1;
606
607         return aul_fd;
608 }
609
610 SLPAPI void aul_finalize()
611 {
612
613         aul_launch_fini();
614
615         if (aul_initialized) {
616                 close(aul_fd);
617         }
618
619         return;
620 }
621
622 SLPAPI int aul_request_data_control_socket_pair(bundle *kb, int *fd)
623 {
624         return app_request_to_launchpad_with_fd(APP_GET_SOCKET_PAIR, NULL, kb, fd, getuid());
625 }
626
627 SLPAPI int aul_launch_app(const char *appid, bundle *kb)
628 {
629         int ret;
630
631         if (appid == NULL)
632                 return AUL_R_EINVAL;
633
634         ret = app_request_to_launchpad(APP_START, appid, kb);
635         return ret;
636 }
637
638 SLPAPI int aul_launch_app_for_uid(const char *appid, bundle *kb, uid_t uid)
639 {
640         int ret;
641         char buf[MAX_PID_STR_BUFSZ];
642         if (appid == NULL)
643                 return AUL_R_EINVAL;
644         snprintf(buf, MAX_UID_STR_BUFSZ, "%d", uid);
645         bundle_add(kb, AUL_K_TARGET_UID, buf);
646
647         ret = app_request_to_launchpad_for_uid(APP_START, appid, kb, uid);
648         return ret;
649 }
650
651 SLPAPI int aul_open_app(const char *appid)
652 {
653         int ret;
654
655         if (appid == NULL)
656                 return AUL_R_EINVAL;
657
658         ret = app_request_to_launchpad(APP_OPEN, appid, NULL);
659         return ret;
660 }
661
662 SLPAPI int aul_resume_app(const char *appid)
663 {
664         int ret;
665
666         if (appid == NULL)
667                 return AUL_R_EINVAL;
668
669         ret = app_request_to_launchpad(APP_RESUME, appid, NULL);
670         return ret;
671 }
672
673 SLPAPI int aul_resume_pid(int pid)
674 {
675         char pkgname[MAX_PID_STR_BUFSZ];
676         int ret;
677
678         if (pid <= 0)
679                 return AUL_R_EINVAL;
680
681         snprintf(pkgname, MAX_PID_STR_BUFSZ, "%d", pid);
682         ret = app_request_to_launchpad(APP_RESUME_BY_PID, pkgname, NULL);
683         return ret;
684 }
685
686 SLPAPI int aul_terminate_pid(int pid)
687 {
688         char pkgname[MAX_PID_STR_BUFSZ];
689         int ret;
690
691         if (pid <= 0)
692                 return AUL_R_EINVAL;
693
694         snprintf(pkgname, MAX_PID_STR_BUFSZ, "%d", pid);
695         ret = app_request_to_launchpad(APP_TERM_BY_PID, pkgname, NULL);
696         return ret;
697 }
698
699 SLPAPI int aul_terminate_bgapp_pid(int pid)
700 {
701         char pkgname[MAX_PID_STR_BUFSZ];
702         int ret;
703
704         if (pid <= 0)
705                 return AUL_R_EINVAL;
706
707         snprintf(pkgname, MAX_PID_STR_BUFSZ, "%d", pid);
708         ret = app_request_to_launchpad(APP_TERM_BGAPP_BY_PID, pkgname, NULL);
709         return ret;
710 }
711
712 SLPAPI int aul_terminate_pid_without_restart(int pid)
713 {
714         char pkgname[MAX_PID_STR_BUFSZ];
715         int ret;
716
717         if (pid <= 0)
718                 return AUL_R_EINVAL;
719
720         snprintf(pkgname, MAX_PID_STR_BUFSZ, "%d", pid);
721         ret = app_request_to_launchpad(APP_TERM_BY_PID_WITHOUT_RESTART, pkgname, NULL);
722         return ret;
723 }
724
725 SLPAPI int aul_terminate_pid_async(int pid)
726 {
727         char pkgname[MAX_PID_STR_BUFSZ];
728         int ret;
729
730         if (pid <= 0)
731                 return AUL_R_EINVAL;
732
733         snprintf(pkgname, MAX_PID_STR_BUFSZ, "%d", pid);
734         ret = app_request_to_launchpad(APP_TERM_BY_PID_ASYNC, pkgname, NULL);
735         return ret;
736 }
737
738 SLPAPI int aul_kill_pid(int pid)
739 {
740         char pkgname[MAX_PID_STR_BUFSZ];
741         int ret;
742
743         if (pid <= 0)
744                 return AUL_R_EINVAL;
745
746         snprintf(pkgname, MAX_PID_STR_BUFSZ, "%d", pid);
747         ret = app_request_to_launchpad(APP_KILL_BY_PID, pkgname, NULL);
748         return ret;
749 }
750
751 SLPAPI int aul_set_data_control_provider_cb(data_control_provider_handler_fn handler)
752 {
753         __dc_handler = handler;
754         return 0;
755 }
756
757 SLPAPI int aul_unset_data_control_provider_cb(void)
758 {
759         __dc_handler = NULL;
760         return 0;
761 }
762
763 SLPAPI void aul_set_preinit_window(void *evas_object)
764 {
765         __window_object = evas_object;
766 }
767
768 SLPAPI void* aul_get_preinit_window(const char *win_name)
769 {
770         return __window_object;
771 }
772
773 SLPAPI void aul_set_preinit_background(void *evas_object)
774 {
775         __bg_object = evas_object;
776 }
777
778 SLPAPI void* aul_get_preinit_background(void)
779 {
780         return __bg_object;
781 }
782
783 SLPAPI void aul_set_preinit_conformant(void *evas_object)
784 {
785         __conformant_object = evas_object;
786 }
787
788 SLPAPI void* aul_get_preinit_conformant(void)
789 {
790         return __conformant_object;
791 }
792
793 SLPAPI int aul_pause_app(const char *appid)
794 {
795         int ret;
796
797         if (appid == NULL)
798                 return AUL_R_EINVAL;
799
800         ret = app_request_to_launchpad(APP_PAUSE, appid, NULL);
801         return ret;
802 }
803
804 SLPAPI int aul_pause_pid(int pid)
805 {
806         char app_pid[MAX_PID_STR_BUFSZ];
807         int ret;
808
809         if (pid <= 0)
810                 return AUL_R_EINVAL;
811
812         snprintf(app_pid, MAX_PID_STR_BUFSZ, "%d", pid);
813         ret = app_request_to_launchpad(APP_PAUSE_BY_PID, app_pid, NULL);
814         return ret;
815 }
816
817 SLPAPI int aul_reload_appinfo(void)
818 {
819         char pkgname[MAX_PID_STR_BUFSZ];
820
821         snprintf(pkgname, MAX_PID_STR_BUFSZ, "%d", getpid());
822
823         return app_request_to_launchpad(AMD_RELOAD_APPINFO, pkgname, NULL);
824 }
825
826 /* vi: set ts=8 sts=8 sw=8: */
827