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);
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");
408 _E("The launch request is failed. result(%d)", ret);
412 bundle* kb = bundle_decode(pkt_auto->data, pkt_auto->len);
422 int __send_request_with_callback(int cmd, const char* appid, bundle* b,
424 void (*reply_cb)(bundle* b, int, void*),
425 void (*error_cb)(int, void*),
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;
434 if (appid == nullptr || b == nullptr || error_cb == nullptr) {
435 _E("Invalid parameter");
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());
443 if (reply_cb != nullptr) {
444 auto r_info = std::make_unique<ReplyInfo>(-1, seq_num, reply_cb,
446 __reply_list.Push(std::move(r_info));
449 int fd = AppRequest(cmd, uid)
453 if (fd < 0 || fd >= sysconf(_SC_OPEN_MAX)) {
454 _E("Failed to send launch request. appid(%s), result(%d)",
457 __reply_list.Pop(seq_num);
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);
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);
478 error_info.release();
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);
488 int fd = AppRequest(APP_SEND_LAUNCH_REQUEST_SYNC, uid)
492 if (fd < 0 || fd >= sysconf(_SC_OPEN_MAX)) {
493 _E("Failed to send launch request. appid(%s), result(%d)",
503 extern "C" int app_result(int cmd, bundle* kb, int launched_pid) {
506 __reply_list.InvokeReplyCb(tizen_base::Bundle(kb, false, false), false,
510 __reply_list.InvokeReplyCb(tizen_base::Bundle(kb, false, false), true,
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,
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,
530 extern "C" void aul_set_instance_info(const char* app_id, bundle* kb) {
531 const char* component_id;
537 uuid_unparse(u, uuid);
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);
544 snprintf(buf, sizeof(buf), "%s:%s", uuid, app_id);
547 bundle_del(kb, AUL_K_INSTANCE_ID);
548 bundle_add(kb, AUL_K_INSTANCE_ID, buf);
551 extern "C" API int aul_forward_app(const char* pkgname, bundle* kb) {
552 if (pkgname == nullptr || kb == nullptr)
555 if (__set_caller_info(kb) < 0)
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);
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);
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)
576 ret = AppRequest(APP_START)
583 bundle* outb = nullptr;
585 ret = aul_create_result_bundle(dupb.GetHandle(), &outb);
588 tizen_base::Bundle outb_auto(outb, false, true);
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);
595 extern "C" API int aul_create_result_bundle(bundle* inb, bundle** outb) {
598 if (inb == nullptr) {
599 _E("return msg create fail");
603 tizen_base::Bundle inb_auto(inb, false, false);
604 tizen_base::Bundle outb_auto;
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");
610 _D("original msg is not msg with result");
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");
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);
629 pid_str = inb_auto.GetString(AUL_K_CALLER_PID);
630 if (pid_str.empty()) {
631 _E("original msg does not have caller pid");
635 outb_auto.Add(AUL_K_CALLER_PID, pid_str);
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;
644 outb_auto.Add(AUL_K_SEQ_NUM, num_str);
645 *outb = outb_auto.Detach();
649 extern "C" int aul_send_result(bundle* kb, int is_cancel) {
654 char callee_appid[256];
659 tizen_base::Bundle b(kb, false, false);
660 if ((pid = __get_caller_pid(b)) < 0)
663 _D("caller pid : %d", pid);
665 if (b.GetString(AUL_K_SEND_RESULT).empty()) {
666 _D("original msg is not msg with result");
670 callee_pid = getpid();
671 callee_pgid = getpgid(callee_pid);
672 b.Add(AUL_K_CALLEE_PID, std::to_string(callee_pgid));
674 ret = aul_app_get_appid_bypid(callee_pid, callee_appid,
675 sizeof(callee_appid));
677 b.Add(AUL_K_CALLEE_APPID, callee_appid);
679 _W("fail(%d) to get callee appid by pid", ret);
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);
688 extern "C" API int aul_subapp_terminate_request_pid(int pid) {
692 __reply_list.Remove(pid);
693 return AppRequest(APP_TERM_REQ_BY_PID)
698 extern "C" int aul_subapp_terminate_request(const char* instance_id, int pid) {
702 __reply_list.Remove(pid);
703 return aul_terminate_instance_async(instance_id, pid);
706 extern "C" API int aul_add_caller_cb(int pid, void (*caller_cb)(int, void*),
711 if (__reply_list.SetCallerCb(pid, caller_cb, data))
717 extern "C" API int aul_remove_caller_cb(int pid, void* data) {
721 if (__reply_list.UnsetCallerCb(pid, data))
727 extern "C" API int aul_invoke_caller_cb(void* data) {
728 auto info = __reply_list.FindByCallerData(data);
732 g_idle_add_full(G_PRIORITY_DEFAULT, [](gpointer data) -> gboolean {
733 auto* info = reinterpret_cast<ReplyInfo*>(data);
735 if (info != nullptr && info->GetCallerCb() != nullptr)
736 info->GetCallerCb()(info->GetLaunchedPid(), info->GetCallerData());
739 return G_SOURCE_REMOVE;
740 }, info.release(), nullptr);
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,
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,
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);
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;
773 if (appid == nullptr || b == nullptr || res_b == nullptr) {
774 _E("Invalid parameter");
778 int fd = __send_launch_request(appid, b, uid);
782 return __recv_reply_bundle(fd, res_b);
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);