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() {
316 static std::atomic<int> num;
317 char buf[MAX_LOCAL_BUFSZ];
319 int n = num.fetch_add(1);
320 unsigned int seed = time(nullptr) + n;
321 snprintf(buf, sizeof(buf), "%d@%d", rand_r(&seed), n);
326 int __get_caller_pid(const tizen_base::Bundle& b) {
327 std::string pid_str = b.GetString(AUL_K_ORG_CALLER_PID);
329 pid_str = b.GetString(AUL_K_CALLER_PID);
334 int pid = atoi(pid_str.c_str());
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;
348 if (appid == nullptr || callback == nullptr || kb == nullptr)
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());
355 auto info = std::make_unique<ReplyInfo>(-1, seq_num, callback, data);
356 __reply_list.Push(std::move(info));
358 int ret = AppRequest(cmd, uid)
364 __reply_list.UpdatePid(seq_num, ret);
366 __reply_list.Pop(seq_num);
371 int __set_caller_info(bundle* kb) {
372 const char* caller_pid;
373 const char* caller_uid;
375 caller_pid = bundle_get_val(kb, AUL_K_CALLER_PID);
376 if (caller_pid == nullptr) {
377 _E("Failed to get caller pid");
381 caller_uid = bundle_get_val(kb, AUL_K_CALLER_UID);
382 if (caller_uid == nullptr) {
383 _E("Failed to get caller uid");
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);
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);
399 _E("Failed to receive the packet. result(%d)", ret);
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);
415 bundle* kb = bundle_decode(pkt_auto->data, pkt_auto->len);
425 int __send_request_with_callback(int cmd, const char* appid, bundle* b,
427 void (*reply_cb)(bundle* b, int, void*),
428 void (*error_cb)(int, void*),
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;
437 if (appid == nullptr || b == nullptr || error_cb == nullptr) {
438 _E("Invalid parameter");
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());
446 if (reply_cb != nullptr) {
447 auto r_info = std::make_unique<ReplyInfo>(-1, seq_num, reply_cb,
449 __reply_list.Push(std::move(r_info));
452 int fd = AppRequest(cmd, uid)
456 if (fd < 0 || fd > sysconf(_SC_OPEN_MAX)) {
457 _E("Failed to send launch request. appid(%s), result(%d)",
460 __reply_list.Pop(seq_num);
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);
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);
481 error_info.release();
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);
491 int fd = AppRequest(APP_SEND_LAUNCH_REQUEST_SYNC, uid)
495 if (fd < 0 || fd > sysconf(_SC_OPEN_MAX)) {
496 _E("Failed to send launch request. appid(%s), result(%d)",
506 extern "C" int app_result(int cmd, bundle* kb, int launched_pid) {
509 __reply_list.InvokeReplyCb(tizen_base::Bundle(kb, false, false), false,
513 __reply_list.InvokeReplyCb(tizen_base::Bundle(kb, false, false), true,
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,
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,
533 extern "C" void aul_set_instance_info(const char* app_id, bundle* kb) {
534 const char* component_id;
540 uuid_unparse(u, uuid);
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);
547 snprintf(buf, sizeof(buf), "%s:%s", uuid, app_id);
550 bundle_del(kb, AUL_K_INSTANCE_ID);
551 bundle_add(kb, AUL_K_INSTANCE_ID, buf);
554 extern "C" API int aul_forward_app(const char* pkgname, bundle* kb) {
555 if (pkgname == nullptr || kb == nullptr)
558 if (__set_caller_info(kb) < 0)
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);
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);
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)
579 ret = AppRequest(APP_START)
586 bundle* outb = nullptr;
588 ret = aul_create_result_bundle(dupb.GetHandle(), &outb);
591 tizen_base::Bundle outb_auto(outb, false, true);
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);
598 extern "C" API int aul_create_result_bundle(bundle* inb, bundle** outb) {
601 if (inb == nullptr) {
602 _E("return msg create fail");
606 tizen_base::Bundle inb_auto(inb, false, false);
607 tizen_base::Bundle outb_auto;
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");
613 _D("original msg is not msg with result");
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");
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);
632 pid_str = inb_auto.GetString(AUL_K_CALLER_PID);
633 if (pid_str.empty()) {
634 _E("original msg does not have caller pid");
638 outb_auto.Add(AUL_K_CALLER_PID, pid_str);
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;
647 outb_auto.Add(AUL_K_SEQ_NUM, num_str);
648 *outb = outb_auto.Detach();
652 extern "C" int aul_send_result(bundle* kb, int is_cancel) {
657 char callee_appid[256];
662 tizen_base::Bundle b(kb, false, false);
663 if ((pid = __get_caller_pid(b)) < 0)
666 _D("caller pid : %d", pid);
668 if (b.GetString(AUL_K_SEND_RESULT).empty()) {
669 _D("original msg is not msg with result");
673 callee_pid = getpid();
674 callee_pgid = getpgid(callee_pid);
675 b.Add(AUL_K_CALLEE_PID, std::to_string(callee_pgid));
677 ret = aul_app_get_appid_bypid(callee_pid, callee_appid,
678 sizeof(callee_appid));
680 b.Add(AUL_K_CALLEE_APPID, callee_appid);
682 _W("fail(%d) to get callee appid by pid", ret);
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);
691 extern "C" API int aul_subapp_terminate_request_pid(int pid) {
695 __reply_list.Remove(pid);
696 return AppRequest(APP_TERM_REQ_BY_PID)
701 extern "C" int aul_subapp_terminate_request(const char* instance_id, int pid) {
705 __reply_list.Remove(pid);
706 return aul_terminate_instance_async(instance_id, pid);
709 extern "C" API int aul_add_caller_cb(int pid, void (*caller_cb)(int, void*),
714 if (__reply_list.SetCallerCb(pid, caller_cb, data))
720 extern "C" API int aul_remove_caller_cb(int pid, void* data) {
724 if (__reply_list.UnsetCallerCb(pid, data))
730 extern "C" API int aul_invoke_caller_cb(void* data) {
731 auto info = __reply_list.FindByCallerData(data);
735 g_idle_add_full(G_PRIORITY_DEFAULT, [](gpointer data) -> gboolean {
736 auto* info = reinterpret_cast<ReplyInfo*>(data);
738 if (info != nullptr && info->GetCallerCb() != nullptr)
739 info->GetCallerCb()(info->GetLaunchedPid(), info->GetCallerData());
742 return G_SOURCE_REMOVE;
743 }, info.release(), nullptr);
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,
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,
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);
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;
776 if (appid == nullptr || b == nullptr || res_b == nullptr) {
777 _E("Invalid parameter");
781 int fd = __send_launch_request(appid, b, uid);
785 return __recv_reply_bundle(fd, res_b);
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);