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