Add AUL_SVC_RET_ETIMEOUT error
[platform/core/appfw/aul-1.git] / src / launch_with_result.cc
1 /*
2 * Copyright (c) 2000 - 2021 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 #include <bundle_internal.h>
18 #include <glib.h>
19 #include <gio/gio.h>
20 #include <uuid.h>
21
22 #include <atomic>
23 #include <functional>
24 #include <list>
25 #include <mutex>
26
27 #include "app_request.h"
28 #include "aul.h"
29 #include "aul_api.h"
30 #include "aul_error.h"
31 #include "aul_sock.h"
32 #include "aul_svc.h"
33 #include "aul_svc_priv_key.h"
34 #include "aul_util.h"
35 #include "launch.h"
36
37 using namespace aul::internal;
38
39 namespace {
40
41 using ErrCb = std::function<void(int, void*)>;
42 using ReplyCb = std::function<void(bundle*, int, void*)>;
43
44 class ReplyList;
45 class ReplyInfo {
46  public:
47   ReplyInfo(int pid, std::string seq_num,
48       ReplyCb reply_cb, void* user_data)
49       : seq_num_(std::move(seq_num)), launched_pid_(pid),
50         reply_cb_(std::move(reply_cb)), user_data_(user_data) {}
51
52   void SetCallerCb(ErrCb cb,
53       void* caller_data) {
54     caller_cb_ = std::move(cb);
55     caller_data_ = caller_data;
56   }
57
58   void UnsetCallerCb() {
59     caller_cb_ = nullptr;
60     caller_data_ = nullptr;
61   }
62
63   int GetLaunchedPid() const {
64     return launched_pid_;
65   }
66
67   const ErrCb& GetCallerCb() const {
68     return caller_cb_;
69   }
70
71   void* GetCallerData() const {
72     return caller_data_;
73   }
74
75  private:
76   friend class ReplyList;
77
78   std::string seq_num_;
79   int launched_pid_;
80   ReplyCb reply_cb_;
81   void* user_data_;
82   ErrCb caller_cb_;
83   void* caller_data_ = nullptr;
84 };
85
86 class ReplyList {
87  public:
88   std::unique_ptr<ReplyInfo> FindByCallerData(void* caller_data) {
89     std::unique_lock<std::mutex> lock(mutex_);
90     for (auto& i : list_) {
91       if (i->caller_data_ == caller_data)
92         return std::unique_ptr<ReplyInfo>(new ReplyInfo(*i));
93     }
94
95     return {};
96   }
97
98   std::unique_ptr<ReplyInfo> Pop(const std::string& seq_num) {
99     if (seq_num.empty())
100       return nullptr;
101
102     std::unique_lock<std::mutex> lock(mutex_);
103     for (auto i = list_.begin(); i != list_.end(); ++i) {
104       if ((*i)->seq_num_ == seq_num) {
105         auto ret = std::move(*i);
106         list_.erase(i);
107         return ret;
108       }
109     }
110
111     return nullptr;
112   }
113
114   void Remove(int pid) {
115     std::unique_lock<std::mutex> lock(mutex_);
116     for (auto i = list_.begin(); i != list_.end(); ) {
117       if ((*i)->launched_pid_ == pid) {
118         i = list_.erase(i);
119       } else {
120         ++i;
121       }
122     }
123   }
124
125   void Push(std::unique_ptr<ReplyInfo> info) {
126     if (info == nullptr)
127       return;
128
129     std::unique_lock<std::mutex> lock(mutex_);
130     list_.push_back(std::move(info));
131   }
132
133   void UpdatePid(const std::string& seq_num, int launched_pid) {
134     std::unique_lock<std::mutex> lock(mutex_);
135     auto* i = Find(seq_num);
136     if (i == nullptr)
137       return;
138     i->launched_pid_ = launched_pid;
139   }
140
141   bool SetCallerCb(int pid, ErrCb cb,
142       void* caller_data) {
143     std::unique_lock<std::mutex> lock(mutex_);
144     auto* i = Find(pid);
145     if (i == nullptr)
146       return false;
147     i->SetCallerCb(std::move(cb), caller_data);
148     return true;
149   }
150
151   bool UnsetCallerCb(int pid, void* caller_data) {
152     std::unique_lock<std::mutex> lock(mutex_);
153     auto* i = Find(pid, caller_data);
154     if (i == nullptr)
155       return false;
156     i->UnsetCallerCb();
157     return true;
158   }
159
160   int InvokeReplyCb(const tizen_base::Bundle& b, bool is_cancel,
161       int launched_pid) {
162     if (launched_pid < 0) {
163       _E("Received pid(%d)", launched_pid);
164       return -1;
165     }
166
167     auto seq_num = b.GetString(AUL_K_SEQ_NUM);
168     if (seq_num.empty()) {
169       _E("Failed to get seq num");
170       return -1;
171     }
172
173     auto info = Pop(seq_num);
174     if (info == nullptr) {
175       _E("Failed to find reply info");
176       return -1;
177     }
178
179     if (info->reply_cb_ == nullptr) {
180       _E("Reply callback function is nullptr");
181       return -1;
182     }
183
184     auto fwdpid_str = b.GetString(AUL_K_FWD_CALLEE_PID);
185     if (is_cancel && !fwdpid_str.empty()) {
186       launched_pid = atoi(fwdpid_str.c_str());
187       auto new_info = std::make_unique<ReplyInfo>(launched_pid, seq_num,
188           info->reply_cb_, info->user_data_);
189       Push(std::move(new_info));
190
191       if (info->caller_cb_ != nullptr)
192         info->caller_cb_(launched_pid, info->caller_data_);
193
194       _W("Change reply info. fwd pid: %d", launched_pid);
195       return 0;
196     }
197
198     info->reply_cb_(b.GetHandle(), is_cancel ? 1 : 0, info->user_data_);
199
200     return 0;
201   }
202
203  private:
204   ReplyInfo* Find(const std::string& seq_num) {
205     for (auto& i : list_) {
206       if (i->seq_num_ == seq_num)
207         return i.get();
208     }
209
210     return nullptr;
211   }
212
213   ReplyInfo* Find(int pid) {
214     for (auto& i : list_) {
215       if (i->launched_pid_ == pid && i->caller_cb_ == nullptr)
216         return i.get();
217     }
218
219     return nullptr;
220   }
221
222   ReplyInfo* Find(int pid, void* caller_data) {
223     for (auto& i : list_) {
224       if (i->launched_pid_ == pid && i->caller_data_ == caller_data)
225         return i.get();
226     }
227
228     return nullptr;
229   }
230
231  private:
232   std::list<std::unique_ptr<ReplyInfo>> list_;
233   std::mutex mutex_;
234 };
235
236 ReplyList __reply_list;
237
238 class ErrorInfo {
239  public:
240   ErrorInfo(std::string seq_num, tizen_base::Bundle b, int cmd,
241       ErrCb error_cb, void* user_data)
242       : seq_num_(std::move(seq_num)), b_(std::move(b)), cmd_(cmd),
243           error_cb_(std::move(error_cb)), user_data_(user_data) {
244   }
245
246   ErrorInfo(const ErrorInfo&) = delete;
247   ErrorInfo& operator = (const ErrorInfo&) = delete;
248
249   ~ErrorInfo() {
250     if (io_ != nullptr)
251       g_io_channel_unref(io_);
252   }
253
254   int AddWatch(int fd) {
255     GIOCondition cond = static_cast<GIOCondition> (G_IO_IN | G_IO_PRI |
256         G_IO_ERR | G_IO_HUP);
257     io_ = g_io_channel_unix_new(fd);
258     if (io_ == nullptr) {
259       _E("Failed to create gio channel");
260       return -1;
261     }
262
263     guint source = g_io_add_watch(io_, cond, ErrorHandlerCb, this);
264     if (source == 0) {
265       _E("Failed to add gio watch");
266       return -1;
267     }
268     g_io_channel_set_close_on_unref(io_, TRUE);
269
270     return 0;
271   }
272
273   static gboolean ErrorHandlerCb(GIOChannel* io, GIOCondition cond,
274       gpointer user_data) {
275     int fd = g_io_channel_unix_get_fd(io);
276     auto* info = reinterpret_cast<ErrorInfo*>(user_data);
277
278     if (info == nullptr) {
279       _E("Critical error!");
280       return G_SOURCE_REMOVE;
281     }
282
283     int res = aul_sock_recv_result_with_fd(fd);
284     if (res < 1) {
285       res = aul_error_convert(res);
286       if (res == AUL_R_LOCAL)
287         res = app_request_local(info->cmd_, info->b_.GetHandle());
288     } else {
289       __reply_list.UpdatePid(info->seq_num_, res);
290     }
291
292     _W("Sequence(%s), result(%d)", info->seq_num_.c_str(), res);
293
294     if (info->error_cb_ != nullptr) {
295       info->error_cb_(res, info->user_data_);
296       info->error_cb_ = nullptr;
297     }
298
299     if (res < 1)
300       __reply_list.Pop(info->seq_num_);
301
302     delete info;
303     return G_SOURCE_REMOVE;
304   }
305
306  private:
307   GIOChannel* io_ = nullptr;
308   std::string seq_num_;
309   tizen_base::Bundle b_;
310   int cmd_;
311   ErrCb error_cb_;
312   void* user_data_;
313 };
314
315 std::string __gen_seq_num() {
316   char uuid[37];
317   uuid_t u;
318   uuid_generate(u);
319   uuid_unparse(u, uuid);
320   return std::string(uuid);
321 }
322
323 int __get_caller_pid(const tizen_base::Bundle& b) {
324   std::string pid_str = b.GetString(AUL_K_ORG_CALLER_PID);
325   if (pid_str.empty())
326     pid_str = b.GetString(AUL_K_CALLER_PID);
327
328   if (pid_str.empty())
329     return -1;
330
331   int pid = atoi(pid_str.c_str());
332   if (pid <= 1)
333     return -1;
334
335   return pid;
336 }
337
338 int __launch_app_with_result(int cmd, const char* appid, bundle* kb,
339     void (*callback)(bundle*, int, void*), void* data, uid_t uid) {
340   if (!aul_is_initialized()) {
341     if (aul_launch_init(nullptr, nullptr) < 0)
342       return AUL_R_ENOINIT;
343   }
344
345   if (appid == nullptr || callback == nullptr || kb == nullptr)
346     return AUL_R_EINVAL;
347
348   std::string seq_num = __gen_seq_num();
349   bundle_del(kb, AUL_K_SEQ_NUM);
350   bundle_add(kb, AUL_K_SEQ_NUM, seq_num.c_str());
351
352   auto info = std::make_unique<ReplyInfo>(-1, seq_num, callback, data);
353   __reply_list.Push(std::move(info));
354
355   int ret = AppRequest(cmd, uid)
356       .With(kb)
357       .SetAppId(appid)
358       .Send();
359
360   if (ret > 0)
361     __reply_list.UpdatePid(seq_num, ret);
362   else
363     __reply_list.Pop(seq_num);
364
365   return ret;
366 }
367
368 int __set_caller_info(bundle* kb) {
369   const char* caller_pid;
370   const char* caller_uid;
371
372   caller_pid = bundle_get_val(kb, AUL_K_CALLER_PID);
373   if (caller_pid == nullptr) {
374     _E("Failed to get caller pid");
375     return AUL_R_EINVAL;
376   }
377
378   caller_uid = bundle_get_val(kb, AUL_K_CALLER_UID);
379   if (caller_uid == nullptr) {
380     _E("Failed to get caller uid");
381     return AUL_R_EINVAL;
382   }
383
384   bundle_del(kb, AUL_K_ORG_CALLER_PID);
385   bundle_add(kb, AUL_K_ORG_CALLER_PID, caller_pid);
386   bundle_del(kb, AUL_K_ORG_CALLER_UID);
387   bundle_add(kb, AUL_K_ORG_CALLER_UID, caller_uid);
388
389   return AUL_R_OK;
390 }
391
392 int __recv_reply_bundle(int fd, bundle** reply_b) {
393   app_pkt_t* pkt = nullptr;
394   int ret = aul_sock_recv_reply_pkt(fd, &pkt);
395   if (ret != 0) {
396     _E("Failed to receive the packet. result(%d)", ret);
397     if (ret == -EAGAIN)
398       return AUL_R_ETIMEOUT;
399
400     return AUL_R_ECOMM;
401   }
402
403   std::unique_ptr<app_pkt_t, decltype(free)*> pkt_auto(pkt, free);
404   if (!(pkt_auto->opt & AUL_SOCK_BUNDLE)) {
405     _E("Invalid protocol");
406     return AUL_R_ECOMM;
407   }
408
409   ret = pkt_auto->cmd;
410   if (ret < 0) {
411     _E("The launch request is failed. result(%d)", ret);
412     if (ret == -EAGAIN)
413       return AUL_R_ETIMEOUT;
414
415     return AUL_R_ERROR;
416   }
417
418   bundle* kb = bundle_decode(pkt_auto->data, pkt_auto->len);
419   if (kb == nullptr) {
420     _E("Out of memory");
421     return AUL_R_ERROR;
422   }
423
424   *reply_b = kb;
425   return ret;
426 }
427
428 int __send_request_with_callback(int cmd, const char* appid, bundle* b,
429     uid_t uid,
430     void (*reply_cb)(bundle* b, int, void*),
431     void (*error_cb)(int, void*),
432     void* user_data) {
433   if (!aul_is_initialized()) {
434     if (aul_launch_init(nullptr, nullptr) < 0) {
435       _E("Failed to initialize aul launch");
436       return AUL_R_ENOINIT;
437     }
438   }
439
440   if (appid == nullptr || b == nullptr || error_cb == nullptr) {
441     _E("Invalid parameter");
442     return AUL_R_EINVAL;
443   }
444
445   std::string seq_num = __gen_seq_num();
446   bundle_del(b, AUL_K_SEQ_NUM);
447   bundle_add(b, AUL_K_SEQ_NUM, seq_num.c_str());
448
449   if (reply_cb != nullptr) {
450     auto r_info = std::make_unique<ReplyInfo>(-1, seq_num, reply_cb,
451         user_data);
452     __reply_list.Push(std::move(r_info));
453   }
454
455   int fd = AppRequest(cmd, uid)
456       .With(b)
457       .SetAppId(appid)
458       .Send();
459   if (fd < 0 || fd >= sysconf(_SC_OPEN_MAX)) {
460     _E("Failed to send launch request. appid(%s), result(%d)",
461         appid, fd);
462     if (reply_cb)
463       __reply_list.Pop(seq_num);
464     return AUL_R_ECOMM;
465   }
466
467   auto error_info = std::make_unique<ErrorInfo>(seq_num,
468       tizen_base::Bundle(b, true, true), cmd, error_cb, user_data);
469   if (error_info.get() == nullptr) {
470     _E("Failed to create error info");
471     if (reply_cb != nullptr)
472       __reply_list.Pop(seq_num);
473     return AUL_R_ERROR;
474   }
475
476   if (error_info->AddWatch(fd) < 0) {
477     _E("Failed to add resultcb watch");
478     if (reply_cb != nullptr)
479       __reply_list.Pop(seq_num);
480     close(fd);
481     return AUL_R_ERROR;
482   }
483
484   error_info.release();
485   return AUL_R_OK;
486 }
487
488 int __send_launch_request(const std::string& appid, bundle* kb, uid_t uid) {
489   std::string seq_num = __gen_seq_num();
490   tizen_base::Bundle b(kb, false, false);
491   b.Delete(AUL_K_SEQ_NUM);
492   b.Add(AUL_K_SEQ_NUM, seq_num);
493
494   int fd = AppRequest(APP_SEND_LAUNCH_REQUEST_SYNC, uid)
495       .With(b)
496       .SetAppId(appid)
497       .Send();
498   if (fd < 0 || fd >= sysconf(_SC_OPEN_MAX)) {
499     _E("Failed to send launch request. appid(%s), result(%d)",
500         appid.c_str(), fd);
501     return AUL_R_ECOMM;
502   }
503
504   return fd;
505 }
506
507 }  // namespace
508
509 extern "C" int app_result(int cmd, bundle* kb, int launched_pid) {
510   switch (cmd) {
511   case APP_RESULT:
512     __reply_list.InvokeReplyCb(tizen_base::Bundle(kb, false, false), false,
513         launched_pid);
514     break;
515   case APP_CANCEL:
516     __reply_list.InvokeReplyCb(tizen_base::Bundle(kb, false, false), true,
517         launched_pid);
518     break;
519   }
520
521   return 0;
522 }
523
524 extern "C" API int aul_launch_app_with_result(const char* pkgname, bundle* kb,
525     void (*cbfunc)(bundle*, int, void*), void* data) {
526   return __launch_app_with_result(APP_START_RES, pkgname, kb, cbfunc,
527       data, getuid());
528 }
529
530 extern "C" API int aul_launch_app_with_result_for_uid(const char* pkgname,
531     bundle* kb, void (*cbfunc)(bundle*, int, void*), void* data, uid_t uid) {
532   return __launch_app_with_result(APP_START_RES, pkgname, kb, cbfunc,
533       data, uid);
534 }
535
536 extern "C" void aul_set_instance_info(const char* app_id, bundle* kb) {
537   const char* component_id;
538   char buf[1024];
539   char uuid[37];
540   uuid_t u;
541
542   uuid_generate(u);
543   uuid_unparse(u, uuid);
544
545   component_id = bundle_get_val(kb, AUL_K_COMPONENT_ID);
546   if (component_id != nullptr) {
547     snprintf(buf, sizeof(buf), "%s:%s:%s",
548         uuid, app_id, component_id);
549   } else {
550     snprintf(buf, sizeof(buf), "%s:%s", uuid, app_id);
551   }
552
553   bundle_del(kb, AUL_K_INSTANCE_ID);
554   bundle_add(kb, AUL_K_INSTANCE_ID, buf);
555 }
556
557 extern "C" API int aul_forward_app(const char* pkgname, bundle* kb) {
558   if (pkgname == nullptr || kb == nullptr)
559     return AUL_R_EINVAL;
560
561   if (__set_caller_info(kb) < 0)
562     return AUL_R_EINVAL;
563
564   bundle_del(kb, AUL_SVC_K_CAN_BE_LEADER);
565   bundle_del(kb, AUL_SVC_K_REROUTE);
566   bundle_del(kb, AUL_SVC_K_RECYCLE);
567
568   const char* launch_mode = bundle_get_val(kb, AUL_SVC_K_LAUNCH_MODE);
569   if (launch_mode != nullptr && !strcmp(launch_mode, "group"))
570     aul_set_instance_info(pkgname, kb);
571
572   int ret;
573   tizen_base::Bundle dupb(kb, true, true);
574   if (bundle_get_val(kb, AUL_K_WAIT_RESULT) != nullptr) {
575     ret = AppRequest(APP_START_RES)
576         .With(kb)
577         .SetAppId(pkgname)
578         .Send();
579     if (ret < 0)
580       return ret;
581   } else {
582     ret = AppRequest(APP_START)
583         .With(kb)
584         .SetAppId(pkgname)
585         .Send();
586     return ret;
587   }
588
589   bundle* outb = nullptr;
590   int pid = ret;
591   ret = aul_create_result_bundle(dupb.GetHandle(), &outb);
592   if (ret < 0)
593     return ret;
594   tizen_base::Bundle outb_auto(outb, false, true);
595
596   outb_auto.Delete(AUL_K_FWD_CALLEE_PID);
597   outb_auto.Add(AUL_K_FWD_CALLEE_PID, std::to_string(pid));
598   return aul_send_result(outb_auto.GetHandle(), 1);
599 }
600
601 extern "C" API int aul_create_result_bundle(bundle* inb, bundle** outb) {
602   *outb = nullptr;
603
604   if (inb == nullptr) {
605     _E("return msg create fail");
606     return AUL_R_EINVAL;
607   }
608
609   tizen_base::Bundle inb_auto(inb, false, false);
610   tizen_base::Bundle outb_auto;
611
612   if (!inb_auto.GetString(AUL_K_WAIT_RESULT).empty()) {
613     outb_auto.Add(AUL_K_SEND_RESULT, "1");
614     _D("original msg is msg with result");
615   } else {
616     _D("original msg is not msg with result");
617   }
618
619   std::string uid_str = inb_auto.GetString(AUL_K_ORG_CALLER_UID);
620   if (uid_str.empty()) {
621     uid_str = inb_auto.GetString(AUL_K_CALLER_UID);
622     if (uid_str.empty()) {
623       _E("Failed to find caller uid");
624       return AUL_R_EINVAL;
625     }
626   }
627
628   outb_auto.Add(AUL_K_ORG_CALLER_UID, uid_str);
629   std::string pid_str = inb_auto.GetString(AUL_K_ORG_CALLER_PID);
630   if (!pid_str.empty()) {
631     outb_auto.Add(AUL_K_ORG_CALLER_PID, pid_str);
632     goto end;
633   }
634
635   pid_str = inb_auto.GetString(AUL_K_CALLER_PID);
636   if (pid_str.empty()) {
637     _E("original msg does not have caller pid");
638     return AUL_R_EINVAL;
639   }
640
641   outb_auto.Add(AUL_K_CALLER_PID, pid_str);
642
643 end:
644   std::string num_str = inb_auto.GetString(AUL_K_SEQ_NUM);
645   if (num_str.empty()) {
646     _E("original msg does not have seq num");
647     return AUL_R_ECANCELED;
648   }
649
650   outb_auto.Add(AUL_K_SEQ_NUM, num_str);
651   *outb = outb_auto.Detach();
652   return AUL_R_OK;
653 }
654
655 extern "C" int aul_send_result(bundle* kb, int is_cancel) {
656   int pid;
657   int ret;
658   int callee_pid;
659   int callee_pgid;
660   char callee_appid[256];
661
662   if (kb == nullptr)
663     return AUL_R_EINVAL;
664
665   tizen_base::Bundle b(kb, false, false);
666   if ((pid = __get_caller_pid(b)) < 0)
667     return AUL_R_EINVAL;
668
669   _D("caller pid : %d", pid);
670
671   if (b.GetString(AUL_K_SEND_RESULT).empty()) {
672     _D("original msg is not msg with result");
673     return AUL_R_OK;
674   }
675
676   callee_pid = getpid();
677   callee_pgid = getpgid(callee_pid);
678   b.Add(AUL_K_CALLEE_PID, std::to_string(callee_pgid));
679
680   ret = aul_app_get_appid_bypid(callee_pid, callee_appid,
681       sizeof(callee_appid));
682   if (ret == 0)
683     b.Add(AUL_K_CALLEE_APPID, callee_appid);
684   else
685     _W("fail(%d) to get callee appid by pid", ret);
686
687   ret = app_send_cmd_with_noreply(AUL_UTIL_PID,
688       (is_cancel == 1) ? APP_CANCEL : APP_RESULT, b.GetHandle());
689   _D("app_send_cmd_with_noreply : %d", ret);
690
691   return ret;
692 }
693
694 extern "C" API int aul_subapp_terminate_request_pid(int pid) {
695   if (pid <= 0)
696     return AUL_R_EINVAL;
697
698   __reply_list.Remove(pid);
699   return AppRequest(APP_TERM_REQ_BY_PID)
700       .SetAppIdAsPid(pid)
701       .Send();
702 }
703
704 extern "C" int aul_subapp_terminate_request(const char* instance_id, int pid) {
705   if (pid <= 0)
706     return AUL_R_EINVAL;
707
708   __reply_list.Remove(pid);
709   return aul_terminate_instance_async(instance_id, pid);
710 }
711
712 extern "C" API int aul_add_caller_cb(int pid, void (*caller_cb)(int, void*),
713     void* data) {
714   if (pid <= 0)
715     return AUL_R_EINVAL;
716
717   if (__reply_list.SetCallerCb(pid, caller_cb, data))
718     return AUL_R_OK;
719
720   return AUL_R_ERROR;
721 }
722
723 extern "C" API int aul_remove_caller_cb(int pid, void* data) {
724   if (pid <= 0)
725     return AUL_R_EINVAL;
726
727   if (__reply_list.UnsetCallerCb(pid, data))
728     return AUL_R_OK;
729
730   return AUL_R_ERROR;
731 }
732
733 extern "C" API int aul_invoke_caller_cb(void* data) {
734   auto info = __reply_list.FindByCallerData(data);
735   if (info == nullptr)
736     return 0;
737
738   g_idle_add_full(G_PRIORITY_DEFAULT, [](gpointer data) -> gboolean {
739         auto* info = reinterpret_cast<ReplyInfo*>(data);
740
741         if (info != nullptr && info->GetCallerCb() != nullptr)
742           info->GetCallerCb()(info->GetLaunchedPid(), info->GetCallerData());
743
744         delete info;
745         return G_SOURCE_REMOVE;
746       }, info.release(), nullptr);
747
748   return 0;
749 }
750
751 extern "C" API int aul_launch_app_with_result_async(const char* appid,
752     bundle* b, void (*callback)(bundle*, int, void*), void* data) {
753   return __launch_app_with_result(APP_START_RES_ASYNC, appid, b, callback,
754       data, getuid());
755 }
756
757 extern "C" API int aul_launch_app_with_result_async_for_uid(const char* appid,
758     bundle* b, void (*callback)(bundle*, int, void*), void* data, uid_t uid) {
759   return __launch_app_with_result(APP_START_RES_ASYNC, appid, b, callback,
760       data, uid);
761 }
762
763 extern "C" API int aul_send_launch_request_for_uid(const char* appid,
764     bundle* b, uid_t uid, void (*reply_cb)(bundle*, int, void*),
765     void (*error_cb)(int, void*), void* user_data) {
766   return __send_request_with_callback(APP_SEND_LAUNCH_REQUEST, appid, b,
767       uid, reply_cb, error_cb, user_data);
768 }
769
770 extern "C" API int aul_send_launch_request_sync_for_uid(const char* appid,
771     bundle* b, uid_t uid, bundle** res_b) {
772   if (!aul_is_initialized()) {
773     if (aul_launch_init(nullptr, nullptr) < 0) {
774       _E("Failed to initialize aul launch");
775       return AUL_R_ENOINIT;
776     }
777   }
778
779   if (appid == nullptr || b == nullptr || res_b == nullptr) {
780     _E("Invalid parameter");
781     return AUL_R_EINVAL;
782   }
783
784   int fd = __send_launch_request(appid, b, uid);
785   if (fd < 0)
786     return fd;
787
788   return __recv_reply_bundle(fd, res_b);
789 }
790
791 extern "C" API int aul_send_resume_request_for_uid(const char* appid,
792     bundle* b, uid_t uid, void (*error_cb)(int, void*), void* user_data) {
793   return __send_request_with_callback(APP_SEND_RESUME_REQUEST, appid, b,
794       uid, nullptr, error_cb, user_data);
795 }