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"
35 #include "cpu_inheritance.hh"
38 using namespace aul::internal;
42 using ErrCb = std::function<void(int, void*)>;
43 using ReplyCb = std::function<void(bundle*, int, void*)>;
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) {}
53 void SetCallerCb(ErrCb cb,
55 caller_cb_ = std::move(cb);
56 caller_data_ = caller_data;
59 void UnsetCallerCb() {
61 caller_data_ = nullptr;
64 int GetLaunchedPid() const {
68 const ErrCb& GetCallerCb() const {
72 void* GetCallerData() const {
77 friend class ReplyList;
84 void* caller_data_ = nullptr;
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));
99 std::unique_ptr<ReplyInfo> Pop(const std::string& seq_num) {
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);
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) {
126 void Push(std::unique_ptr<ReplyInfo> info) {
130 std::unique_lock<std::mutex> lock(mutex_);
131 list_.push_back(std::move(info));
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);
139 i->launched_pid_ = launched_pid;
142 bool SetCallerCb(int pid, ErrCb cb,
144 std::unique_lock<std::mutex> lock(mutex_);
148 i->SetCallerCb(std::move(cb), caller_data);
152 bool UnsetCallerCb(int pid, void* caller_data) {
153 std::unique_lock<std::mutex> lock(mutex_);
154 auto* i = Find(pid, caller_data);
161 int InvokeReplyCb(const tizen_base::Bundle& b, bool is_cancel,
163 if (launched_pid < 0) {
164 _E("Received pid(%d)", launched_pid);
168 auto seq_num = b.GetString(AUL_K_SEQ_NUM);
169 if (seq_num.empty()) {
170 _E("Failed to get seq num");
174 auto info = Pop(seq_num);
175 if (info == nullptr) {
176 _E("Failed to find reply info");
180 if (info->reply_cb_ == nullptr) {
181 _E("Reply callback function is nullptr");
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));
192 if (info->caller_cb_ != nullptr)
193 info->caller_cb_(launched_pid, info->caller_data_);
195 _W("Change reply info. fwd pid: %d", launched_pid);
199 info->reply_cb_(b.GetHandle(), is_cancel ? 1 : 0, info->user_data_);
205 ReplyInfo* Find(const std::string& seq_num) {
206 for (auto& i : list_) {
207 if (i->seq_num_ == seq_num)
214 ReplyInfo* Find(int pid) {
215 for (auto& i : list_) {
216 if (i->launched_pid_ == pid && i->caller_cb_ == nullptr)
223 ReplyInfo* Find(int pid, void* caller_data) {
224 for (auto& i : list_) {
225 if (i->launched_pid_ == pid && i->caller_data_ == caller_data)
233 std::list<std::unique_ptr<ReplyInfo>> list_;
237 ReplyList __reply_list;
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) {
249 ErrorInfo(const ErrorInfo&) = delete;
250 ErrorInfo& operator = (const ErrorInfo&) = delete;
254 g_io_channel_unref(io_);
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");
266 guint source = g_io_add_watch(io_, cond, ErrorHandlerCb, this);
268 _E("Failed to add gio watch");
271 g_io_channel_set_close_on_unref(io_, TRUE);
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);
281 if (info == nullptr) {
282 _E("Critical error!");
283 return G_SOURCE_REMOVE;
286 int res = aul_sock_recv_result_with_fd(fd);
288 res = aul_error_convert(res);
289 if (res == AUL_R_LOCAL)
290 res = app_request_local(info->cmd_, info->b_.GetHandle());
292 __reply_list.UpdatePid(info->seq_num_, res);
295 _W("Sequence(%s), result(%d)", info->seq_num_.c_str(), res);
297 if (info->error_cb_ != nullptr) {
298 info->error_cb_(res, info->user_data_);
299 info->error_cb_ = nullptr;
303 __reply_list.Pop(info->seq_num_);
306 return G_SOURCE_REMOVE;
310 GIOChannel* io_ = nullptr;
311 std::string seq_num_;
312 tizen_base::Bundle b_;
316 CPUInheritance inheritance_;
319 std::string __gen_seq_num() {
323 uuid_unparse(u, uuid);
324 return std::string(uuid);
327 int __get_caller_pid(const tizen_base::Bundle& b) {
328 std::string pid_str = b.GetString(AUL_K_ORG_CALLER_PID);
330 pid_str = b.GetString(AUL_K_CALLER_PID);
335 int pid = atoi(pid_str.c_str());
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;
349 if (appid == nullptr || callback == nullptr || kb == nullptr)
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());
356 auto info = std::make_unique<ReplyInfo>(-1, seq_num, callback, data);
357 __reply_list.Push(std::move(info));
359 int ret = AppRequest(cmd, uid)
365 __reply_list.UpdatePid(seq_num, ret);
367 __reply_list.Pop(seq_num);
372 int __set_caller_info(bundle* kb) {
373 const char* caller_pid;
374 const char* caller_uid;
376 caller_pid = bundle_get_val(kb, AUL_K_CALLER_PID);
377 if (caller_pid == nullptr) {
378 _E("Failed to get caller pid");
382 caller_uid = bundle_get_val(kb, AUL_K_CALLER_UID);
383 if (caller_uid == nullptr) {
384 _E("Failed to get caller uid");
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);
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);
400 _E("Failed to receive the packet. result(%d)", ret);
402 return AUL_R_ETIMEOUT;
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");
415 _E("The launch request is failed. result(%d)", ret);
417 return AUL_R_ETIMEOUT;
422 bundle* kb = bundle_decode(pkt_auto->data, pkt_auto->len);
432 int __send_request_with_callback(int cmd, const char* appid, bundle* b,
434 void (*reply_cb)(bundle* b, int, void*),
435 void (*error_cb)(int, void*),
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;
444 if (appid == nullptr || b == nullptr || error_cb == nullptr) {
445 _E("Invalid parameter");
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());
453 if (reply_cb != nullptr) {
454 auto r_info = std::make_unique<ReplyInfo>(-1, seq_num, reply_cb,
456 __reply_list.Push(std::move(r_info));
459 int fd = AppRequest(cmd, uid)
463 if (fd < 0 || fd >= sysconf(_SC_OPEN_MAX)) {
464 _E("Failed to send launch request. appid(%s), result(%d)",
467 __reply_list.Pop(seq_num);
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);
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);
488 error_info.release();
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);
498 int fd = AppRequest(APP_SEND_LAUNCH_REQUEST_SYNC, uid)
502 if (fd < 0 || fd >= sysconf(_SC_OPEN_MAX)) {
503 _E("Failed to send launch request. appid(%s), result(%d)",
513 extern "C" int app_result(int cmd, bundle* kb, int launched_pid) {
516 __reply_list.InvokeReplyCb(tizen_base::Bundle(kb, false, false), false,
520 __reply_list.InvokeReplyCb(tizen_base::Bundle(kb, false, false), true,
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,
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,
540 extern "C" void aul_set_instance_info(const char* app_id, bundle* kb) {
541 const char* component_id;
547 uuid_unparse(u, uuid);
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);
554 snprintf(buf, sizeof(buf), "%s:%s", uuid, app_id);
557 bundle_del(kb, AUL_K_INSTANCE_ID);
558 bundle_add(kb, AUL_K_INSTANCE_ID, buf);
561 extern "C" API int aul_forward_app(const char* pkgname, bundle* kb) {
562 if (pkgname == nullptr || kb == nullptr)
565 if (__set_caller_info(kb) < 0)
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);
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);
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)
586 ret = AppRequest(APP_START)
593 bundle* outb = nullptr;
595 ret = aul_create_result_bundle(dupb.GetHandle(), &outb);
598 tizen_base::Bundle outb_auto(outb, false, true);
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);
605 extern "C" API int aul_create_result_bundle(bundle* inb, bundle** outb) {
608 if (inb == nullptr) {
609 _E("return msg create fail");
613 tizen_base::Bundle inb_auto(inb, false, false);
614 tizen_base::Bundle outb_auto;
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");
620 _D("original msg is not msg with result");
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");
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);
639 pid_str = inb_auto.GetString(AUL_K_CALLER_PID);
640 if (pid_str.empty()) {
641 _E("original msg does not have caller pid");
645 outb_auto.Add(AUL_K_CALLER_PID, pid_str);
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;
654 outb_auto.Add(AUL_K_SEQ_NUM, num_str);
655 *outb = outb_auto.Detach();
659 extern "C" int aul_send_result(bundle* kb, int is_cancel) {
664 char callee_appid[256];
669 tizen_base::Bundle b(kb, false, false);
670 if ((pid = __get_caller_pid(b)) < 0)
673 _D("caller pid : %d", pid);
675 if (b.GetString(AUL_K_SEND_RESULT).empty()) {
676 _D("original msg is not msg with result");
680 callee_pid = getpid();
681 callee_pgid = getpgid(callee_pid);
682 b.Add(AUL_K_CALLEE_PID, std::to_string(callee_pgid));
684 ret = aul_app_get_appid_bypid(callee_pid, callee_appid,
685 sizeof(callee_appid));
687 b.Add(AUL_K_CALLEE_APPID, callee_appid);
689 _W("fail(%d) to get callee appid by pid", ret);
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);
698 extern "C" API int aul_subapp_terminate_request_pid(int pid) {
702 __reply_list.Remove(pid);
703 return AppRequest(APP_TERM_REQ_BY_PID)
708 extern "C" int aul_subapp_terminate_request(const char* instance_id, int pid) {
712 __reply_list.Remove(pid);
713 return aul_terminate_instance_async(instance_id, pid);
716 extern "C" API int aul_add_caller_cb(int pid, void (*caller_cb)(int, void*),
721 if (__reply_list.SetCallerCb(pid, caller_cb, data))
727 extern "C" API int aul_remove_caller_cb(int pid, void* data) {
731 if (__reply_list.UnsetCallerCb(pid, data))
737 extern "C" API int aul_invoke_caller_cb(void* data) {
738 auto info = __reply_list.FindByCallerData(data);
742 g_idle_add_full(G_PRIORITY_DEFAULT, [](gpointer data) -> gboolean {
743 auto* info = reinterpret_cast<ReplyInfo*>(data);
745 if (info != nullptr && info->GetCallerCb() != nullptr)
746 info->GetCallerCb()(info->GetLaunchedPid(), info->GetCallerData());
749 return G_SOURCE_REMOVE;
750 }, info.release(), nullptr);
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,
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,
767 extern "C" API int aul_send_launch_request_for_uid(const char* appid,
768 bundle* b, uid_t uid, aul_reply_cb reply_cb,
769 aul_result_cb result_cb, void* user_data) {
770 return __send_request_with_callback(APP_SEND_LAUNCH_REQUEST, appid, b,
771 uid, reply_cb, result_cb, user_data);
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;
783 if (appid == nullptr || b == nullptr || res_b == nullptr) {
784 _E("Invalid parameter");
788 int fd = __send_launch_request(appid, b, uid);
792 return __recv_reply_bundle(fd, res_b);
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);