2 * Copyright (c) 2000 - 2021 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <bundle_internal.h>
27 #include "app_request.h"
30 #include "aul_error.h"
33 #include "aul_svc_priv_key.h"
37 using namespace aul::internal;
41 using ErrCb = std::function<void(int, void*)>;
42 using ReplyCb = std::function<void(bundle*, int, void*)>;
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) {}
52 void SetCallerCb(ErrCb cb,
54 caller_cb_ = std::move(cb);
55 caller_data_ = caller_data;
58 void UnsetCallerCb() {
60 caller_data_ = nullptr;
63 int GetLaunchedPid() const {
67 const ErrCb& GetCallerCb() const {
71 void* GetCallerData() const {
76 friend class ReplyList;
83 void* caller_data_ = nullptr;
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));
98 std::unique_ptr<ReplyInfo> Pop(const std::string& seq_num) {
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);
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) {
125 void Push(std::unique_ptr<ReplyInfo> info) {
129 std::unique_lock<std::mutex> lock(mutex_);
130 list_.push_back(std::move(info));
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);
138 i->launched_pid_ = launched_pid;
141 bool SetCallerCb(int pid, ErrCb cb,
143 std::unique_lock<std::mutex> lock(mutex_);
147 i->SetCallerCb(std::move(cb), caller_data);
151 bool UnsetCallerCb(int pid, void* caller_data) {
152 std::unique_lock<std::mutex> lock(mutex_);
153 auto* i = Find(pid, caller_data);
160 int InvokeReplyCb(const tizen_base::Bundle& b, bool is_cancel,
162 if (launched_pid < 0) {
163 _E("Received pid(%d)", launched_pid);
167 auto seq_num = b.GetString(AUL_K_SEQ_NUM);
168 if (seq_num.empty()) {
169 _E("Failed to get seq num");
173 auto info = Pop(seq_num);
174 if (info == nullptr) {
175 _E("Failed to find reply info");
179 if (info->reply_cb_ == nullptr) {
180 _E("Reply callback function is nullptr");
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));
191 if (info->caller_cb_ != nullptr)
192 info->caller_cb_(launched_pid, info->caller_data_);
194 _W("Change reply info. fwd pid: %d", launched_pid);
198 info->reply_cb_(b.GetHandle(), is_cancel ? 1 : 0, info->user_data_);
204 ReplyInfo* Find(const std::string& seq_num) {
205 for (auto& i : list_) {
206 if (i->seq_num_ == seq_num)
213 ReplyInfo* Find(int pid) {
214 for (auto& i : list_) {
215 if (i->launched_pid_ == pid && i->caller_cb_ == nullptr)
222 ReplyInfo* Find(int pid, void* caller_data) {
223 for (auto& i : list_) {
224 if (i->launched_pid_ == pid && i->caller_data_ == caller_data)
232 std::list<std::unique_ptr<ReplyInfo>> list_;
236 ReplyList __reply_list;
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) {
246 ErrorInfo(const ErrorInfo&) = delete;
247 ErrorInfo& operator = (const ErrorInfo&) = delete;
251 g_io_channel_unref(io_);
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");
263 guint source = g_io_add_watch(io_, cond, ErrorHandlerCb, this);
265 _E("Failed to add gio watch");
268 g_io_channel_set_close_on_unref(io_, TRUE);
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);
278 if (info == nullptr) {
279 _E("Critical error!");
280 return G_SOURCE_REMOVE;
283 int res = aul_sock_recv_result_with_fd(fd);
285 res = aul_error_convert(res);
286 if (res == AUL_R_LOCAL)
287 res = app_request_local(info->cmd_, info->b_.GetHandle());
289 __reply_list.UpdatePid(info->seq_num_, res);
292 _W("Sequence(%s), result(%d)", info->seq_num_.c_str(), res);
294 if (info->error_cb_ != nullptr) {
295 info->error_cb_(res, info->user_data_);
296 info->error_cb_ = nullptr;
300 __reply_list.Pop(info->seq_num_);
303 return G_SOURCE_REMOVE;
307 GIOChannel* io_ = nullptr;
308 std::string seq_num_;
309 tizen_base::Bundle b_;
315 std::string __gen_seq_num() {
319 uuid_unparse(u, uuid);
320 return std::string(uuid);
323 int __get_caller_pid(const tizen_base::Bundle& b) {
324 std::string pid_str = b.GetString(AUL_K_ORG_CALLER_PID);
326 pid_str = b.GetString(AUL_K_CALLER_PID);
331 int pid = atoi(pid_str.c_str());
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;
345 if (appid == nullptr || callback == nullptr || kb == nullptr)
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());
352 auto info = std::make_unique<ReplyInfo>(-1, seq_num, callback, data);
353 __reply_list.Push(std::move(info));
355 int ret = AppRequest(cmd, uid)
361 __reply_list.UpdatePid(seq_num, ret);
363 __reply_list.Pop(seq_num);
368 int __set_caller_info(bundle* kb) {
369 const char* caller_pid;
370 const char* caller_uid;
372 caller_pid = bundle_get_val(kb, AUL_K_CALLER_PID);
373 if (caller_pid == nullptr) {
374 _E("Failed to get caller pid");
378 caller_uid = bundle_get_val(kb, AUL_K_CALLER_UID);
379 if (caller_uid == nullptr) {
380 _E("Failed to get caller uid");
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);
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);
396 _E("Failed to receive the packet. result(%d)", ret);
398 return AUL_R_ETIMEOUT;
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");
411 _E("The launch request is failed. result(%d)", ret);
413 return AUL_R_ETIMEOUT;
418 bundle* kb = bundle_decode(pkt_auto->data, pkt_auto->len);
428 int __send_request_with_callback(int cmd, const char* appid, bundle* b,
430 void (*reply_cb)(bundle* b, int, void*),
431 void (*error_cb)(int, void*),
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;
440 if (appid == nullptr || b == nullptr || error_cb == nullptr) {
441 _E("Invalid parameter");
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());
449 if (reply_cb != nullptr) {
450 auto r_info = std::make_unique<ReplyInfo>(-1, seq_num, reply_cb,
452 __reply_list.Push(std::move(r_info));
455 int fd = AppRequest(cmd, uid)
459 if (fd < 0 || fd >= sysconf(_SC_OPEN_MAX)) {
460 _E("Failed to send launch request. appid(%s), result(%d)",
463 __reply_list.Pop(seq_num);
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);
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);
484 error_info.release();
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);
494 int fd = AppRequest(APP_SEND_LAUNCH_REQUEST_SYNC, uid)
498 if (fd < 0 || fd >= sysconf(_SC_OPEN_MAX)) {
499 _E("Failed to send launch request. appid(%s), result(%d)",
509 extern "C" int app_result(int cmd, bundle* kb, int launched_pid) {
512 __reply_list.InvokeReplyCb(tizen_base::Bundle(kb, false, false), false,
516 __reply_list.InvokeReplyCb(tizen_base::Bundle(kb, false, false), true,
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,
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,
536 extern "C" void aul_set_instance_info(const char* app_id, bundle* kb) {
537 const char* component_id;
543 uuid_unparse(u, uuid);
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);
550 snprintf(buf, sizeof(buf), "%s:%s", uuid, app_id);
553 bundle_del(kb, AUL_K_INSTANCE_ID);
554 bundle_add(kb, AUL_K_INSTANCE_ID, buf);
557 extern "C" API int aul_forward_app(const char* pkgname, bundle* kb) {
558 if (pkgname == nullptr || kb == nullptr)
561 if (__set_caller_info(kb) < 0)
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);
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);
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)
582 ret = AppRequest(APP_START)
589 bundle* outb = nullptr;
591 ret = aul_create_result_bundle(dupb.GetHandle(), &outb);
594 tizen_base::Bundle outb_auto(outb, false, true);
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);
601 extern "C" API int aul_create_result_bundle(bundle* inb, bundle** outb) {
604 if (inb == nullptr) {
605 _E("return msg create fail");
609 tizen_base::Bundle inb_auto(inb, false, false);
610 tizen_base::Bundle outb_auto;
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");
616 _D("original msg is not msg with result");
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");
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);
635 pid_str = inb_auto.GetString(AUL_K_CALLER_PID);
636 if (pid_str.empty()) {
637 _E("original msg does not have caller pid");
641 outb_auto.Add(AUL_K_CALLER_PID, pid_str);
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;
650 outb_auto.Add(AUL_K_SEQ_NUM, num_str);
651 *outb = outb_auto.Detach();
655 extern "C" int aul_send_result(bundle* kb, int is_cancel) {
660 char callee_appid[256];
665 tizen_base::Bundle b(kb, false, false);
666 if ((pid = __get_caller_pid(b)) < 0)
669 _D("caller pid : %d", pid);
671 if (b.GetString(AUL_K_SEND_RESULT).empty()) {
672 _D("original msg is not msg with result");
676 callee_pid = getpid();
677 callee_pgid = getpgid(callee_pid);
678 b.Add(AUL_K_CALLEE_PID, std::to_string(callee_pgid));
680 ret = aul_app_get_appid_bypid(callee_pid, callee_appid,
681 sizeof(callee_appid));
683 b.Add(AUL_K_CALLEE_APPID, callee_appid);
685 _W("fail(%d) to get callee appid by pid", ret);
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);
694 extern "C" API int aul_subapp_terminate_request_pid(int pid) {
698 __reply_list.Remove(pid);
699 return AppRequest(APP_TERM_REQ_BY_PID)
704 extern "C" int aul_subapp_terminate_request(const char* instance_id, int pid) {
708 __reply_list.Remove(pid);
709 return aul_terminate_instance_async(instance_id, pid);
712 extern "C" API int aul_add_caller_cb(int pid, void (*caller_cb)(int, void*),
717 if (__reply_list.SetCallerCb(pid, caller_cb, data))
723 extern "C" API int aul_remove_caller_cb(int pid, void* data) {
727 if (__reply_list.UnsetCallerCb(pid, data))
733 extern "C" API int aul_invoke_caller_cb(void* data) {
734 auto info = __reply_list.FindByCallerData(data);
738 g_idle_add_full(G_PRIORITY_DEFAULT, [](gpointer data) -> gboolean {
739 auto* info = reinterpret_cast<ReplyInfo*>(data);
741 if (info != nullptr && info->GetCallerCb() != nullptr)
742 info->GetCallerCb()(info->GetLaunchedPid(), info->GetCallerData());
745 return G_SOURCE_REMOVE;
746 }, info.release(), nullptr);
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,
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,
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);
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;
779 if (appid == nullptr || b == nullptr || res_b == nullptr) {
780 _E("Invalid parameter");
784 int fd = __send_launch_request(appid, b, uid);
788 return __recv_reply_bundle(fd, res_b);
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);