Fix static analysis issues
[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   static std::atomic<int> num;
317   char buf[MAX_LOCAL_BUFSZ];
318
319   int n = num.fetch_add(1);
320   unsigned int seed = static_cast<unsigned int>(time(nullptr) + n);
321   snprintf(buf, sizeof(buf), "%d@%d", rand_r(&seed), n);
322
323   return buf;
324 }
325
326 int __get_caller_pid(const tizen_base::Bundle& b) {
327   std::string pid_str = b.GetString(AUL_K_ORG_CALLER_PID);
328   if (pid_str.empty())
329     pid_str = b.GetString(AUL_K_CALLER_PID);
330
331   if (pid_str.empty())
332     return -1;
333
334   int pid = atoi(pid_str.c_str());
335   if (pid <= 1)
336     return -1;
337
338   return pid;
339 }
340
341 int __launch_app_with_result(int cmd, const char* appid, bundle* kb,
342     void (*callback)(bundle*, int, void*), void* data, uid_t uid) {
343   if (!aul_is_initialized()) {
344     if (aul_launch_init(nullptr, nullptr) < 0)
345       return AUL_R_ENOINIT;
346   }
347
348   if (appid == nullptr || callback == nullptr || kb == nullptr)
349     return AUL_R_EINVAL;
350
351   std::string seq_num = __gen_seq_num();
352   bundle_del(kb, AUL_K_SEQ_NUM);
353   bundle_add(kb, AUL_K_SEQ_NUM, seq_num.c_str());
354
355   auto info = std::make_unique<ReplyInfo>(-1, seq_num, callback, data);
356   __reply_list.Push(std::move(info));
357
358   int ret = AppRequest(cmd, uid)
359       .With(kb)
360       .SetAppId(appid)
361       .Send();
362
363   if (ret > 0)
364     __reply_list.UpdatePid(seq_num, ret);
365   else
366     __reply_list.Pop(seq_num);
367
368   return ret;
369 }
370
371 int __set_caller_info(bundle* kb) {
372   const char* caller_pid;
373   const char* caller_uid;
374
375   caller_pid = bundle_get_val(kb, AUL_K_CALLER_PID);
376   if (caller_pid == nullptr) {
377     _E("Failed to get caller pid");
378     return AUL_R_EINVAL;
379   }
380
381   caller_uid = bundle_get_val(kb, AUL_K_CALLER_UID);
382   if (caller_uid == nullptr) {
383     _E("Failed to get caller uid");
384     return AUL_R_EINVAL;
385   }
386
387   bundle_del(kb, AUL_K_ORG_CALLER_PID);
388   bundle_add(kb, AUL_K_ORG_CALLER_PID, caller_pid);
389   bundle_del(kb, AUL_K_ORG_CALLER_UID);
390   bundle_add(kb, AUL_K_ORG_CALLER_UID, caller_uid);
391
392   return AUL_R_OK;
393 }
394
395 int __recv_reply_bundle(int fd, bundle** reply_b) {
396   app_pkt_t* pkt = nullptr;
397   int ret = aul_sock_recv_reply_pkt(fd, &pkt);
398   if (ret != 0) {
399     _E("Failed to receive the packet. result(%d)", ret);
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     return AUL_R_ERROR;
413   }
414
415   bundle* kb = bundle_decode(pkt_auto->data, pkt_auto->len);
416   if (kb == nullptr) {
417     _E("Out of memory");
418     return AUL_R_ERROR;
419   }
420
421   *reply_b = kb;
422   return ret;
423 }
424
425 int __send_request_with_callback(int cmd, const char* appid, bundle* b,
426     uid_t uid,
427     void (*reply_cb)(bundle* b, int, void*),
428     void (*error_cb)(int, void*),
429     void* user_data) {
430   if (!aul_is_initialized()) {
431     if (aul_launch_init(nullptr, nullptr) < 0) {
432       _E("Failed to initialize aul launch");
433       return AUL_R_ENOINIT;
434     }
435   }
436
437   if (appid == nullptr || b == nullptr || error_cb == nullptr) {
438     _E("Invalid parameter");
439     return AUL_R_EINVAL;
440   }
441
442   std::string seq_num = __gen_seq_num();
443   bundle_del(b, AUL_K_SEQ_NUM);
444   bundle_add(b, AUL_K_SEQ_NUM, seq_num.c_str());
445
446   if (reply_cb != nullptr) {
447     auto r_info = std::make_unique<ReplyInfo>(-1, seq_num, reply_cb,
448         user_data);
449     __reply_list.Push(std::move(r_info));
450   }
451
452   int fd = AppRequest(cmd, uid)
453       .With(b)
454       .SetAppId(appid)
455       .Send();
456   if (fd < 0 || fd >= sysconf(_SC_OPEN_MAX)) {
457     _E("Failed to send launch request. appid(%s), result(%d)",
458         appid, fd);
459     if (reply_cb)
460       __reply_list.Pop(seq_num);
461     return AUL_R_ECOMM;
462   }
463
464   auto error_info = std::make_unique<ErrorInfo>(seq_num,
465       tizen_base::Bundle(b, true, true), cmd, error_cb, user_data);
466   if (error_info.get() == nullptr) {
467     _E("Failed to create error info");
468     if (reply_cb != nullptr)
469       __reply_list.Pop(seq_num);
470     return AUL_R_ERROR;
471   }
472
473   if (error_info->AddWatch(fd) < 0) {
474     _E("Failed to add resultcb watch");
475     if (reply_cb != nullptr)
476       __reply_list.Pop(seq_num);
477     close(fd);
478     return AUL_R_ERROR;
479   }
480
481   error_info.release();
482   return AUL_R_OK;
483 }
484
485 int __send_launch_request(const std::string& appid, bundle* kb, uid_t uid) {
486   std::string seq_num = __gen_seq_num();
487   tizen_base::Bundle b(kb, false, false);
488   b.Delete(AUL_K_SEQ_NUM);
489   b.Add(AUL_K_SEQ_NUM, seq_num);
490
491   int fd = AppRequest(APP_SEND_LAUNCH_REQUEST_SYNC, uid)
492       .With(b)
493       .SetAppId(appid)
494       .Send();
495   if (fd < 0 || fd >= sysconf(_SC_OPEN_MAX)) {
496     _E("Failed to send launch request. appid(%s), result(%d)",
497         appid.c_str(), fd);
498     return AUL_R_ECOMM;
499   }
500
501   return fd;
502 }
503
504 }  // namespace
505
506 extern "C" int app_result(int cmd, bundle* kb, int launched_pid) {
507   switch (cmd) {
508   case APP_RESULT:
509     __reply_list.InvokeReplyCb(tizen_base::Bundle(kb, false, false), false,
510         launched_pid);
511     break;
512   case APP_CANCEL:
513     __reply_list.InvokeReplyCb(tizen_base::Bundle(kb, false, false), true,
514         launched_pid);
515     break;
516   }
517
518   return 0;
519 }
520
521 extern "C" API int aul_launch_app_with_result(const char* pkgname, bundle* kb,
522     void (*cbfunc)(bundle*, int, void*), void* data) {
523   return __launch_app_with_result(APP_START_RES, pkgname, kb, cbfunc,
524       data, getuid());
525 }
526
527 extern "C" API int aul_launch_app_with_result_for_uid(const char* pkgname,
528     bundle* kb, void (*cbfunc)(bundle*, int, void*), void* data, uid_t uid) {
529   return __launch_app_with_result(APP_START_RES, pkgname, kb, cbfunc,
530       data, uid);
531 }
532
533 extern "C" void aul_set_instance_info(const char* app_id, bundle* kb) {
534   const char* component_id;
535   char buf[1024];
536   char uuid[37];
537   uuid_t u;
538
539   uuid_generate(u);
540   uuid_unparse(u, uuid);
541
542   component_id = bundle_get_val(kb, AUL_K_COMPONENT_ID);
543   if (component_id != nullptr) {
544     snprintf(buf, sizeof(buf), "%s:%s:%s",
545         uuid, app_id, component_id);
546   } else {
547     snprintf(buf, sizeof(buf), "%s:%s", uuid, app_id);
548   }
549
550   bundle_del(kb, AUL_K_INSTANCE_ID);
551   bundle_add(kb, AUL_K_INSTANCE_ID, buf);
552 }
553
554 extern "C" API int aul_forward_app(const char* pkgname, bundle* kb) {
555   if (pkgname == nullptr || kb == nullptr)
556     return AUL_R_EINVAL;
557
558   if (__set_caller_info(kb) < 0)
559     return AUL_R_EINVAL;
560
561   bundle_del(kb, AUL_SVC_K_CAN_BE_LEADER);
562   bundle_del(kb, AUL_SVC_K_REROUTE);
563   bundle_del(kb, AUL_SVC_K_RECYCLE);
564
565   const char* launch_mode = bundle_get_val(kb, AUL_SVC_K_LAUNCH_MODE);
566   if (launch_mode != nullptr && !strcmp(launch_mode, "group"))
567     aul_set_instance_info(pkgname, kb);
568
569   int ret;
570   tizen_base::Bundle dupb(kb, true, true);
571   if (bundle_get_val(kb, AUL_K_WAIT_RESULT) != nullptr) {
572     ret = AppRequest(APP_START_RES)
573         .With(kb)
574         .SetAppId(pkgname)
575         .Send();
576     if (ret < 0)
577       return ret;
578   } else {
579     ret = AppRequest(APP_START)
580         .With(kb)
581         .SetAppId(pkgname)
582         .Send();
583     return ret;
584   }
585
586   bundle* outb = nullptr;
587   int pid = ret;
588   ret = aul_create_result_bundle(dupb.GetHandle(), &outb);
589   if (ret < 0)
590     return ret;
591   tizen_base::Bundle outb_auto(outb, false, true);
592
593   outb_auto.Delete(AUL_K_FWD_CALLEE_PID);
594   outb_auto.Add(AUL_K_FWD_CALLEE_PID, std::to_string(pid));
595   return aul_send_result(outb_auto.GetHandle(), 1);
596 }
597
598 extern "C" API int aul_create_result_bundle(bundle* inb, bundle** outb) {
599   *outb = nullptr;
600
601   if (inb == nullptr) {
602     _E("return msg create fail");
603     return AUL_R_EINVAL;
604   }
605
606   tizen_base::Bundle inb_auto(inb, false, false);
607   tizen_base::Bundle outb_auto;
608
609   if (!inb_auto.GetString(AUL_K_WAIT_RESULT).empty()) {
610     outb_auto.Add(AUL_K_SEND_RESULT, "1");
611     _D("original msg is msg with result");
612   } else {
613     _D("original msg is not msg with result");
614   }
615
616   std::string uid_str = inb_auto.GetString(AUL_K_ORG_CALLER_UID);
617   if (uid_str.empty()) {
618     uid_str = inb_auto.GetString(AUL_K_CALLER_UID);
619     if (uid_str.empty()) {
620       _E("Failed to find caller uid");
621       return AUL_R_EINVAL;
622     }
623   }
624
625   outb_auto.Add(AUL_K_ORG_CALLER_UID, uid_str);
626   std::string pid_str = inb_auto.GetString(AUL_K_ORG_CALLER_PID);
627   if (!pid_str.empty()) {
628     outb_auto.Add(AUL_K_ORG_CALLER_PID, pid_str);
629     goto end;
630   }
631
632   pid_str = inb_auto.GetString(AUL_K_CALLER_PID);
633   if (pid_str.empty()) {
634     _E("original msg does not have caller pid");
635     return AUL_R_EINVAL;
636   }
637
638   outb_auto.Add(AUL_K_CALLER_PID, pid_str);
639
640 end:
641   std::string num_str = inb_auto.GetString(AUL_K_SEQ_NUM);
642   if (num_str.empty()) {
643     _E("original msg does not have seq num");
644     return AUL_R_ECANCELED;
645   }
646
647   outb_auto.Add(AUL_K_SEQ_NUM, num_str);
648   *outb = outb_auto.Detach();
649   return AUL_R_OK;
650 }
651
652 extern "C" int aul_send_result(bundle* kb, int is_cancel) {
653   int pid;
654   int ret;
655   int callee_pid;
656   int callee_pgid;
657   char callee_appid[256];
658
659   if (kb == nullptr)
660     return AUL_R_EINVAL;
661
662   tizen_base::Bundle b(kb, false, false);
663   if ((pid = __get_caller_pid(b)) < 0)
664     return AUL_R_EINVAL;
665
666   _D("caller pid : %d", pid);
667
668   if (b.GetString(AUL_K_SEND_RESULT).empty()) {
669     _D("original msg is not msg with result");
670     return AUL_R_OK;
671   }
672
673   callee_pid = getpid();
674   callee_pgid = getpgid(callee_pid);
675   b.Add(AUL_K_CALLEE_PID, std::to_string(callee_pgid));
676
677   ret = aul_app_get_appid_bypid(callee_pid, callee_appid,
678       sizeof(callee_appid));
679   if (ret == 0)
680     b.Add(AUL_K_CALLEE_APPID, callee_appid);
681   else
682     _W("fail(%d) to get callee appid by pid", ret);
683
684   ret = app_send_cmd_with_noreply(AUL_UTIL_PID,
685       (is_cancel == 1) ? APP_CANCEL : APP_RESULT, b.GetHandle());
686   _D("app_send_cmd_with_noreply : %d", ret);
687
688   return ret;
689 }
690
691 extern "C" API int aul_subapp_terminate_request_pid(int pid) {
692   if (pid <= 0)
693     return AUL_R_EINVAL;
694
695   __reply_list.Remove(pid);
696   return AppRequest(APP_TERM_REQ_BY_PID)
697       .SetAppIdAsPid(pid)
698       .Send();
699 }
700
701 extern "C" int aul_subapp_terminate_request(const char* instance_id, int pid) {
702   if (pid <= 0)
703     return AUL_R_EINVAL;
704
705   __reply_list.Remove(pid);
706   return aul_terminate_instance_async(instance_id, pid);
707 }
708
709 extern "C" API int aul_add_caller_cb(int pid, void (*caller_cb)(int, void*),
710     void* data) {
711   if (pid <= 0)
712     return AUL_R_EINVAL;
713
714   if (__reply_list.SetCallerCb(pid, caller_cb, data))
715     return AUL_R_OK;
716
717   return AUL_R_ERROR;
718 }
719
720 extern "C" API int aul_remove_caller_cb(int pid, void* data) {
721   if (pid <= 0)
722     return AUL_R_EINVAL;
723
724   if (__reply_list.UnsetCallerCb(pid, data))
725     return AUL_R_OK;
726
727   return AUL_R_ERROR;
728 }
729
730 extern "C" API int aul_invoke_caller_cb(void* data) {
731   auto info = __reply_list.FindByCallerData(data);
732   if (info == nullptr)
733     return 0;
734
735   g_idle_add_full(G_PRIORITY_DEFAULT, [](gpointer data) -> gboolean {
736         auto* info = reinterpret_cast<ReplyInfo*>(data);
737
738         if (info != nullptr && info->GetCallerCb() != nullptr)
739           info->GetCallerCb()(info->GetLaunchedPid(), info->GetCallerData());
740
741         delete info;
742         return G_SOURCE_REMOVE;
743       }, info.release(), nullptr);
744
745   return 0;
746 }
747
748 extern "C" API int aul_launch_app_with_result_async(const char* appid,
749     bundle* b, void (*callback)(bundle*, int, void*), void* data) {
750   return __launch_app_with_result(APP_START_RES_ASYNC, appid, b, callback,
751       data, getuid());
752 }
753
754 extern "C" API int aul_launch_app_with_result_async_for_uid(const char* appid,
755     bundle* b, void (*callback)(bundle*, int, void*), void* data, uid_t uid) {
756   return __launch_app_with_result(APP_START_RES_ASYNC, appid, b, callback,
757       data, uid);
758 }
759
760 extern "C" API int aul_send_launch_request_for_uid(const char* appid,
761     bundle* b, uid_t uid, void (*reply_cb)(bundle*, int, void*),
762     void (*error_cb)(int, void*), void* user_data) {
763   return __send_request_with_callback(APP_SEND_LAUNCH_REQUEST, appid, b,
764       uid, reply_cb, error_cb, user_data);
765 }
766
767 extern "C"  API int aul_send_launch_request_sync_for_uid(const char* appid,
768     bundle* b, uid_t uid, bundle** res_b) {
769   if (!aul_is_initialized()) {
770     if (aul_launch_init(nullptr, nullptr) < 0) {
771       _E("Failed to initialize aul launch");
772       return AUL_R_ENOINIT;
773     }
774   }
775
776   if (appid == nullptr || b == nullptr || res_b == nullptr) {
777     _E("Invalid parameter");
778     return AUL_R_EINVAL;
779   }
780
781   int fd = __send_launch_request(appid, b, uid);
782   if (fd < 0)
783     return fd;
784
785   return __recv_reply_bundle(fd, res_b);
786 }
787
788 extern "C" API int aul_send_resume_request_for_uid(const char* appid,
789     bundle* b, uid_t uid, void (*error_cb)(int, void*), void* user_data) {
790   return __send_request_with_callback(APP_SEND_RESUME_REQUEST, appid, b,
791       uid, nullptr, error_cb, user_data);
792 }