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