From 087feb80a9be565e4ec4388b8d2ef4610552e28a Mon Sep 17 00:00:00 2001 From: "jh9216.park" Date: Wed, 26 May 2021 20:07:07 -0400 Subject: [PATCH] Refactor launch_with_result.c - Use c++ syntax - Extract class 'AppRequest' Change-Id: Ic9fe84e25d89a5d33b00034de18152bbb077215c Signed-off-by: jh9216.park --- src/app_request.cc | 166 +++++ src/app_request.h | 59 ++ src/launch.cc | 137 +--- src/launch.h | 1 - src/launch_with_result.c | 1004 ---------------------------- src/launch_with_result.cc | 792 ++++++++++++++++++++++ test/unit_tests/mock/glib_mock.cc | 79 +++ test/unit_tests/mock/glib_mock.h | 74 ++ test/unit_tests/test_launch_with_result.cc | 181 +++++ 9 files changed, 1354 insertions(+), 1139 deletions(-) create mode 100644 src/app_request.cc create mode 100644 src/app_request.h delete mode 100644 src/launch_with_result.c create mode 100644 src/launch_with_result.cc create mode 100644 test/unit_tests/mock/glib_mock.cc create mode 100644 test/unit_tests/mock/glib_mock.h diff --git a/src/app_request.cc b/src/app_request.cc new file mode 100644 index 0000000..e2001a5 --- /dev/null +++ b/src/app_request.cc @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "app_request.h" +#include "app_signal.h" +#include "aul_api.h" +#include "aul_app_com.h" +#include "aul_error.h" +#include "aul_util.h" +#include "key.h" +#include "launch.h" + +namespace aul { +namespace internal { + +AppRequest::AppRequest(int cmd, uid_t uid) : cmd_(cmd), uid_(uid) { + SetUid(uid); +} + +AppRequest::AppRequest(int cmd) : cmd_(cmd), uid_(getuid()) { + SetUid(uid_); +} + +AppRequest& AppRequest::With(tizen_base::Bundle b) { + bundle_ = std::move(b); + ClearInternalKey(); + SetUid(uid_); + return *this; +} + +AppRequest& AppRequest::With(bundle* b) { + if (b == nullptr) + return *this; + bundle_ = tizen_base::Bundle(b, false, false); + ClearInternalKey(); + SetUid(uid_); + return *this; +} + +AppRequest& AppRequest::SetAppId(const std::string& app_id) { + bundle_.Delete(AUL_K_APPID); + bundle_.Add(AUL_K_APPID, app_id); + return *this; +} + +AppRequest& AppRequest::SetInstId(const std::string& inst_id) { + bundle_.Delete(AUL_K_INSTANCE_ID); + bundle_.Add(AUL_K_INSTANCE_ID, inst_id); + return *this; +} + +AppRequest& AppRequest::SetAppIdAsPid(pid_t pid) { + char buf[MAX_PID_STR_BUFSZ]; + snprintf(buf, sizeof(buf), "%d", pid); + bundle_.Delete(AUL_K_APPID); + bundle_.Add(AUL_K_APPID, buf); + return *this; +} + +AppRequest& AppRequest::SetPid(pid_t pid) { + char buf[MAX_PID_STR_BUFSZ]; + snprintf(buf, sizeof(buf), "%d", pid); + bundle_.Delete(AUL_K_PID); + bundle_.Add(AUL_K_PID, buf); + return *this; +} + +int AppRequest::Send(int opt) { + traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "AUL:REQ_TO_PAD"); + std::string appid = bundle_.GetString(AUL_K_APPID); + _W("Request cmd(%d): appid(%s), target_uid(%u)", + cmd_, appid.c_str(), uid_); + + SetTime(); + switch (cmd_) { + case APP_SEND_LAUNCH_REQUEST: + case APP_SEND_LAUNCH_REQUEST_SYNC: + case APP_SEND_RESUME_REQUEST: + opt |= AUL_SOCK_ASYNC; + break; + } + + int ret = aul_sock_send_bundle(AUL_UTIL_PID, uid_, cmd_, + bundle_.GetHandle(), opt); + if (ret < 0) + ret = aul_error_convert(ret); + _W("Request cmd(%d): result(%d)", cmd_, ret); + if (ret == AUL_R_LOCAL) + ret = app_request_local(cmd_, bundle_.GetHandle()); + traceEnd(TTRACE_TAG_APPLICATION_MANAGER); + return ret; +} + +int AppRequest::SendSimply(int opt) { + _W("Request cmd(%d): target_uid(%u)", cmd_, uid_); + int ret = aul_sock_send_bundle(AUL_UTIL_PID, uid_, cmd_, + bundle_.GetHandle(), opt); + if (ret < 0) + ret = aul_error_convert(ret); + _W("Request cmd(%d): result(%d)", cmd_, ret); + return ret; +} + +int AppRequest::SendCmdOnly(int opt) { + _W("Request cmd(%d): target_uid(%u)", cmd_, uid_); + int ret = aul_sock_send_raw(AUL_UTIL_PID, uid_, cmd_, nullptr, 0, opt); + _W("Request cmd(%d): result(%d)", cmd_, ret); + return ret; +} + +void AppRequest::ClearInternalKey() { + bundle_.Delete(AUL_K_CALLER_PID); + bundle_.Delete(AUL_K_APPID); + bundle_.Delete(AUL_K_WAIT_RESULT); + bundle_.Delete(AUL_K_SEND_RESULT); + bundle_.Delete(AUL_K_ARGV0); +} + +void AppRequest::SetTime() { + struct timespec start; + clock_gettime(CLOCK_MONOTONIC, &start); + char tmp[MAX_LOCAL_BUFSZ]; + snprintf(tmp, sizeof(tmp), "%ld/%ld", start.tv_sec, start.tv_nsec); + bundle_.Delete(AUL_K_STARTTIME); + bundle_.Add(AUL_K_STARTTIME, tmp); +} + +void AppRequest::SetUid(uid_t uid) { + char buf[MAX_PID_STR_BUFSZ]; + snprintf(buf, sizeof(buf), "%d", uid); + bundle_.Delete(AUL_K_TARGET_UID); + bundle_.Add(AUL_K_TARGET_UID, buf); +} + +} // namespace internal +} // namespace aul diff --git a/src/app_request.h b/src/app_request.h new file mode 100644 index 0000000..28f066f --- /dev/null +++ b/src/app_request.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef APP_REQUEST_H_ +#define APP_REQUEST_H_ + +#include +#include +#include + +#include "aul.h" +#include "aul_sock.h" + +namespace aul { +namespace internal { + +class AppRequest { + public: + AppRequest(int cmd, uid_t uid); + AppRequest(int cmd); + + AppRequest& With(tizen_base::Bundle b); + AppRequest& With(bundle* b); + AppRequest& SetAppId(const std::string& app_id); + AppRequest& SetInstId(const std::string& inst_id); + AppRequest& SetAppIdAsPid(pid_t pid); + AppRequest& SetPid(pid_t pid); + int Send(int opt = AUL_SOCK_QUEUE); + int SendSimply(int opt = AUL_SOCK_NONE); + int SendCmdOnly(int opt = AUL_SOCK_NONE); + + private: + void ClearInternalKey(); + void SetTime(); + void SetUid(uid_t uid); + + private: + int cmd_; + uid_t uid_; + tizen_base::Bundle bundle_; +}; + +} // namespace internal +} // namespace aul + +#endif // APP_REQUEST_H_ \ No newline at end of file diff --git a/src/launch.cc b/src/launch.cc index bb658b6..74e30fd 100644 --- a/src/launch.cc +++ b/src/launch.cc @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include #include @@ -31,6 +30,7 @@ #include +#include "app_request.h" #include "app_signal.h" #include "aul.h" #include "aul_api.h" @@ -41,138 +41,12 @@ #include "key.h" #include "launch.h" +using namespace aul::internal; + namespace { constexpr const int TEP_ISMOUNT_MAX_RETRY_CNT = 20; -class AppRequest { - public: - AppRequest(int cmd, uid_t uid) : cmd_(cmd), uid_(uid) { - SetUid(uid); - } - - AppRequest(int cmd) : cmd_(cmd), uid_(getuid()) { - SetUid(uid_); - } - - AppRequest& With(tizen_base::Bundle b) { - bundle_ = std::move(b); - ClearInternalKey(); - SetUid(uid_); - return *this; - } - - AppRequest& With(bundle* b) { - if (b == nullptr) - return *this; - bundle_ = tizen_base::Bundle(b, false, false); - ClearInternalKey(); - SetUid(uid_); - return *this; - } - - AppRequest& SetAppId(const std::string& app_id) { - bundle_.Delete(AUL_K_APPID); - bundle_.Add(AUL_K_APPID, app_id); - return *this; - } - - AppRequest& SetInstId(const std::string& inst_id) { - bundle_.Delete(AUL_K_INSTANCE_ID); - bundle_.Add(AUL_K_INSTANCE_ID, inst_id); - return *this; - } - - AppRequest& SetAppIdAsPid(pid_t pid) { - char buf[MAX_PID_STR_BUFSZ]; - snprintf(buf, sizeof(buf), "%d", pid); - bundle_.Delete(AUL_K_APPID); - bundle_.Add(AUL_K_APPID, buf); - return *this; - } - - AppRequest& SetPid(pid_t pid) { - char buf[MAX_PID_STR_BUFSZ]; - snprintf(buf, sizeof(buf), "%d", pid); - bundle_.Delete(AUL_K_PID); - bundle_.Add(AUL_K_PID, buf); - return *this; - } - - int Send(int opt = AUL_SOCK_QUEUE) { - traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "AUL:REQ_TO_PAD"); - std::string appid = bundle_.GetString(AUL_K_APPID); - _W("Request cmd(%d): appid(%s), target_uid(%u)", - cmd_, appid.c_str(), uid_); - - SetTime(); - switch (cmd_) { - case APP_SEND_LAUNCH_REQUEST: - case APP_SEND_LAUNCH_REQUEST_SYNC: - case APP_SEND_RESUME_REQUEST: - opt |= AUL_SOCK_ASYNC; - break; - } - - int ret = aul_sock_send_bundle(AUL_UTIL_PID, uid_, cmd_, - bundle_.GetHandle(), opt); - if (ret < 0) - ret = aul_error_convert(ret); - _W("Request cmd(%d): result(%d)", cmd_, ret); - if (ret == AUL_R_LOCAL) - ret = app_request_local(cmd_, bundle_.GetHandle()); - traceEnd(TTRACE_TAG_APPLICATION_MANAGER); - return ret; - } - - int SendSimply(int opt = AUL_SOCK_NONE) { - _W("Request cmd(%d): target_uid(%u)", cmd_, uid_); - int ret = aul_sock_send_bundle(AUL_UTIL_PID, uid_, cmd_, - bundle_.GetHandle(), opt); - if (ret < 0) - ret = aul_error_convert(ret); - _W("Request cmd(%d): result(%d)", cmd_, ret); - return ret; - } - - int SendCmdOnly(int opt = AUL_SOCK_NONE) { - _W("Request cmd(%d): target_uid(%u)", cmd_, uid_); - int ret = aul_sock_send_raw(AUL_UTIL_PID, uid_, cmd_, nullptr, 0, opt); - _W("Request cmd(%d): result(%d)", cmd_, ret); - return ret; - } - - private: - void ClearInternalKey() { - bundle_.Delete(AUL_K_CALLER_PID); - bundle_.Delete(AUL_K_APPID); - bundle_.Delete(AUL_K_WAIT_RESULT); - bundle_.Delete(AUL_K_SEND_RESULT); - bundle_.Delete(AUL_K_ARGV0); - } - - void SetTime() { - struct timespec start; - clock_gettime(CLOCK_MONOTONIC, &start); - char tmp[MAX_LOCAL_BUFSZ]; - snprintf(tmp, sizeof(tmp), "%ld/%ld", start.tv_sec, start.tv_nsec); - bundle_.Delete(AUL_K_STARTTIME); - bundle_.Add(AUL_K_STARTTIME, tmp); - } - - void SetUid(uid_t uid) { - char buf[MAX_PID_STR_BUFSZ]; - snprintf(buf, sizeof(buf), "%d", uid); - bundle_.Delete(AUL_K_TARGET_UID); - bundle_.Add(AUL_K_TARGET_UID, buf); - } - - private: - int cmd_; - uid_t uid_; - tizen_base::Bundle bundle_; -}; - int aul_initialized = 0; int aul_fd; void* window_object = nullptr; @@ -310,11 +184,6 @@ extern "C" int app_request_local(int cmd, bundle* kb) { } } -extern "C" int app_request_to_launchpad(int cmd, const char* appid, - bundle* kb) { - return app_request_to_launchpad_for_uid(cmd, appid, kb, getuid()); -} - extern "C" int app_request_to_launchpad_for_uid(int cmd, const char* appid, bundle* kb, uid_t uid) { return AppRequest(cmd, uid) diff --git a/src/launch.h b/src/launch.h index 6967e82..6bd31cd 100644 --- a/src/launch.h +++ b/src/launch.h @@ -30,7 +30,6 @@ int app_send_cmd(int pid, int cmd, bundle *kb); int app_send_cmd_for_uid(int pid, uid_t uid, int cmd, bundle *kb); int app_send_cmd_with_noreply(int pid, int cmd, bundle *kb); int app_send_cmd_to_launchpad(const char *pad_type, uid_t uid, int cmd, bundle *kb); -int app_request_to_launchpad(int cmd, const char *pkgname, bundle *kb); int app_request_to_launchpad_for_uid(int cmd, const char *pkgname, bundle *kb, uid_t uid); int app_result(int cmd, bundle *kb, int launched_pid); diff --git a/src/launch_with_result.c b/src/launch_with_result.c deleted file mode 100644 index 5e03462..0000000 --- a/src/launch_with_result.c +++ /dev/null @@ -1,1004 +0,0 @@ -/* - * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "aul.h" -#include "aul_api.h" -#include "aul_error.h" -#include "aul_sock.h" -#include "aul_svc.h" -#include "aul_svc_priv_key.h" -#include "aul_util.h" -#include "launch.h" - -typedef struct _aul_error_info_t { - GIOChannel *io; - char *seq_num; - bundle *b; - int cmd; - void (*error_cb)(int res, void *user_data); - void *user_data; -} aul_error_info_t; - -typedef struct _aul_reply_info_t { - char *seq_num; - int launched_pid; - void (*reply_cb)(bundle *b, int is_cancel, void *user_data); - void *user_data; - void (*caller_cb)(int launched_pid, void *user_data); - void *caller_data; -} aul_reply_info_t; - -static pthread_mutex_t __aul_mutex = PTHREAD_MUTEX_INITIALIZER; -static GList *__reply_info_list; - -static int __rand(int n) -{ - unsigned int seed = time(NULL) + n; - - return rand_r(&seed); -} - -static char *__gen_seq_num(void) -{ - static int num; - char buf[MAX_LOCAL_BUFSZ]; - - g_atomic_int_inc(&num); - snprintf(buf, sizeof(buf), "%d@%d", __rand(num), num); - - return strdup(buf); -} - -static void __destroy_aul_error_info(aul_error_info_t *info) -{ - if (!info) - return; - - if (info->io) - g_io_channel_unref(info->io); - - if (info->b) - bundle_free(info->b); - - if (info->seq_num) - free(info->seq_num); - - free(info); -} - -static aul_error_info_t *__create_aul_error_info(const char *seq_num, - bundle *b, int cmd, void (*error_cb)(int, void *), - void *user_data) -{ - aul_error_info_t *info; - - info = calloc(1, sizeof(aul_error_info_t)); - if (!info) { - _E("Out of memory"); - return NULL; - } - - info->seq_num = strdup(seq_num); - if (!info->seq_num) { - _E("Failed to duplicate seq num"); - __destroy_aul_error_info(info); - return NULL; - } - - info->b = bundle_dup(b); - if (!info->b) { - _E("Failed to duplicate bundle"); - __destroy_aul_error_info(info); - return NULL; - } - - info->cmd = cmd; - info->error_cb = error_cb; - info->user_data = user_data; - - return info; -} - -static void __destroy_aul_reply_info(gpointer data) -{ - aul_reply_info_t *info = (aul_reply_info_t *)data; - - if (!info) - return; - - if (info->seq_num) - free(info->seq_num); - - free(info); -} - -static aul_reply_info_t *__create_aul_reply_info(int pid, - const char *seq_num, - void (*reply_cb)(bundle *, int, void *), - void *user_data) -{ - aul_reply_info_t *info; - - info = calloc(1, sizeof(aul_reply_info_t)); - if (!info) { - _E("Out of memory"); - return NULL; - } - - info->seq_num = strdup(seq_num); - if (!info->seq_num) { - _E("Failed to duplicate seq num"); - __destroy_aul_reply_info(info); - return NULL; - } - - info->launched_pid = pid; - info->reply_cb = reply_cb; - info->user_data = user_data; - - return info; -} - -static void __update_aul_reply_info(const char *seq_num, - int launched_pid) -{ - aul_reply_info_t *info; - GList *iter; - - if (!seq_num) - return; - - pthread_mutex_lock(&__aul_mutex); - iter = __reply_info_list; - while (iter) { - info = (aul_reply_info_t *)iter->data; - if (!strcmp(info->seq_num, seq_num)) { - info->launched_pid = launched_pid; - break; - } - iter = g_list_next(iter); - } - pthread_mutex_unlock(&__aul_mutex); -} - -static void __push_aul_reply_info(aul_reply_info_t *info) -{ - if (!info) - return; - - pthread_mutex_lock(&__aul_mutex); - __reply_info_list = g_list_prepend(__reply_info_list, info); - pthread_mutex_unlock(&__aul_mutex); -} - -static aul_reply_info_t *__pop_aul_reply_info(const char *seq_num) -{ - aul_reply_info_t *info; - GList *iter; - - if (!seq_num) - return NULL; - - pthread_mutex_lock(&__aul_mutex); - iter = __reply_info_list; - while (iter) { - info = (aul_reply_info_t *)iter->data; - if (!strcmp(info->seq_num, seq_num)) { - __reply_info_list = g_list_remove(__reply_info_list, - info); - pthread_mutex_unlock(&__aul_mutex); - return info; - } - iter = g_list_next(iter); - } - pthread_mutex_unlock(&__aul_mutex); - - return NULL; -} - -static int __invoke_aul_reply_cb(bundle *kb, int is_cancel, - int launched_pid) -{ - aul_reply_info_t *new_info; - aul_reply_info_t *info; - const char *fwdpid_str; - const char *seq_num; - - if (!kb) { - _E("Invalid parameter"); - return -1; - } - - if (launched_pid < 0) { - _E("Received pid(%d)", launched_pid); - return -1; - } - - seq_num = bundle_get_val(kb, AUL_K_SEQ_NUM); - if (!seq_num) { - _E("Failed to get seq num"); - return -1; - } - - info = __pop_aul_reply_info(seq_num); - if (!info) { - _E("Failed to find reply info"); - return -1; - } - - if (!info->reply_cb) { - _E("Reply callback function is nullptr"); - return -1; - } - - fwdpid_str = bundle_get_val(kb, AUL_K_FWD_CALLEE_PID); - if (is_cancel == 1 && fwdpid_str) { - launched_pid = atoi(fwdpid_str); - new_info = __create_aul_reply_info(launched_pid, - seq_num, info->reply_cb, - info->user_data); - if (new_info) - __push_aul_reply_info(new_info); - - if (info->caller_cb) - info->caller_cb(launched_pid, info->caller_data); - - __destroy_aul_reply_info(info); - _W("Change reply info. fwd pid: %d", launched_pid); - return 0; - } - - info->reply_cb(kb, is_cancel, info->user_data); - __destroy_aul_reply_info(info); - - return 0; -} - -static int __get_caller_pid(bundle *kb) -{ - const char *pid_str; - int pid; - - pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID); - if (!pid_str) - pid_str = bundle_get_val(kb, AUL_K_CALLER_PID); - - if (pid_str == NULL) - return -1; - - pid = atoi(pid_str); - if (pid <= 1) - return -1; - - return pid; -} - -int app_result(int cmd, bundle *kb, int launched_pid) -{ - switch (cmd) { - case APP_RESULT: - __invoke_aul_reply_cb(kb, 0, launched_pid); - break; - case APP_CANCEL: - __invoke_aul_reply_cb(kb, 1, launched_pid); - break; - } - - return 0; -} - -static int __launch_app_with_result(int cmd, const char *appid, bundle *kb, - void (*callback)(bundle *, int, void *), void *data, uid_t uid) -{ - int ret; - char *seq_num; - aul_reply_info_t *info; - - if (!aul_is_initialized()) { - if (aul_launch_init(NULL, NULL) < 0) - return AUL_R_ENOINIT; - } - - if (appid == NULL || callback == NULL || kb == NULL) - return AUL_R_EINVAL; - - seq_num = __gen_seq_num(); - if (seq_num == NULL) { - _E("Out of memory"); - return AUL_R_ERROR; - } - - bundle_del(kb, AUL_K_SEQ_NUM); - bundle_add(kb, AUL_K_SEQ_NUM, seq_num); - - info = __create_aul_reply_info(-1, seq_num, callback, data); - if (info) - __push_aul_reply_info(info); - - ret = app_request_to_launchpad_for_uid(cmd, appid, kb, uid); - if (ret > 0) { - __update_aul_reply_info(seq_num, ret); - } else { - info = __pop_aul_reply_info(seq_num); - if (info) - __destroy_aul_reply_info(info); - } - free(seq_num); - - return ret; -} - -API int aul_launch_app_with_result(const char *pkgname, bundle *kb, - void (*cbfunc) (bundle *, int, void *), - void *data) -{ - return __launch_app_with_result(APP_START_RES, pkgname, kb, cbfunc, - data, getuid()); -} - -API int aul_launch_app_with_result_for_uid(const char *pkgname, bundle *kb, - void (*cbfunc) (bundle *, int, void *), void *data, uid_t uid) -{ - return __launch_app_with_result(APP_START_RES, pkgname, kb, cbfunc, - data, uid); -} - -static int __set_caller_info(bundle *kb) -{ - const char *caller_pid; - const char *caller_uid; - - caller_pid = bundle_get_val(kb, AUL_K_CALLER_PID); - if (caller_pid == NULL) { - _E("Failed to get caller pid"); - return AUL_R_EINVAL; - } - - caller_uid = bundle_get_val(kb, AUL_K_CALLER_UID); - if (caller_uid == NULL) { - _E("Failed to get caller uid"); - return AUL_R_EINVAL; - } - - bundle_del(kb, AUL_K_ORG_CALLER_PID); - bundle_add(kb, AUL_K_ORG_CALLER_PID, caller_pid); - bundle_del(kb, AUL_K_ORG_CALLER_UID); - bundle_add(kb, AUL_K_ORG_CALLER_UID, caller_uid); - - return AUL_R_OK; -} - -void aul_set_instance_info(const char *app_id, bundle *kb) -{ - const char *component_id; - char buf[1024]; - char uuid[37]; - uuid_t u; - - uuid_generate(u); - uuid_unparse(u, uuid); - - component_id = bundle_get_val(kb, AUL_K_COMPONENT_ID); - if (component_id) { - snprintf(buf, sizeof(buf), "%s:%s:%s", - uuid, app_id, component_id); - } else { - snprintf(buf, sizeof(buf), "%s:%s", uuid, app_id); - } - - bundle_del(kb, AUL_K_INSTANCE_ID); - bundle_add(kb, AUL_K_INSTANCE_ID, buf); -} - -API int aul_forward_app(const char* pkgname, bundle *kb) -{ - int ret; - bundle *dupb; - bundle *outb; - char tmp_pid[MAX_PID_STR_BUFSZ]; - const char *launch_mode; - - if (pkgname == NULL || kb == NULL) - return AUL_R_EINVAL; - - if (__set_caller_info(kb) < 0) - return AUL_R_EINVAL; - - bundle_del(kb, AUL_SVC_K_CAN_BE_LEADER); - bundle_del(kb, AUL_SVC_K_REROUTE); - bundle_del(kb, AUL_SVC_K_RECYCLE); - - launch_mode = bundle_get_val(kb, AUL_SVC_K_LAUNCH_MODE); - if (launch_mode && !strcmp(launch_mode, "group")) - aul_set_instance_info(pkgname, kb); - - dupb = bundle_dup(kb); - if (dupb == NULL) { - _E("bundle duplicate fail"); - return AUL_R_EINVAL; - } - - if (bundle_get_val(kb, AUL_K_WAIT_RESULT) != NULL) { - ret = app_request_to_launchpad(APP_START_RES, pkgname, kb); - if (ret < 0) - goto end; - } else { - ret = app_request_to_launchpad(APP_START, pkgname, kb); - goto end; - } - - snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", ret); - - ret = aul_create_result_bundle(dupb, &outb); - if (ret < 0) - goto end; - - bundle_del(outb, AUL_K_FWD_CALLEE_PID); - bundle_add(outb, AUL_K_FWD_CALLEE_PID, tmp_pid); - - ret = aul_send_result(outb, 1); - - bundle_free(outb); -end: - bundle_free(dupb); - - return ret; -} - -API int aul_create_result_bundle(bundle *inb, bundle **outb) -{ - const char *pid_str; - const char *num_str; - const char *uid_str; - - *outb = NULL; - - if (inb == NULL) { - _E("return msg create fail"); - return AUL_R_EINVAL; - } - - *outb = bundle_create(); - if (*outb == NULL) { - _E("return msg create fail"); - return AUL_R_ERROR; - } - - if (bundle_get_val(inb, AUL_K_WAIT_RESULT) != NULL) { - bundle_add(*outb, AUL_K_SEND_RESULT, "1"); - _D("original msg is msg with result"); - } else { - _D("original msg is not msg with result"); - } - - uid_str = bundle_get_val(inb, AUL_K_ORG_CALLER_UID); - if (uid_str == NULL) - uid_str = bundle_get_val(inb, AUL_K_CALLER_UID); - - if (uid_str == NULL) { - _E("Failed to find caller uid"); - bundle_free(*outb); - *outb = NULL; - return AUL_R_EINVAL; - } - bundle_add(*outb, AUL_K_ORG_CALLER_UID, uid_str); - - pid_str = bundle_get_val(inb, AUL_K_ORG_CALLER_PID); - if (pid_str) { - bundle_add(*outb, AUL_K_ORG_CALLER_PID, pid_str); - goto end; - } - - pid_str = bundle_get_val(inb, AUL_K_CALLER_PID); - if (pid_str == NULL) { - _E("original msg does not have caller pid"); - bundle_free(*outb); - *outb = NULL; - return AUL_R_EINVAL; - } - bundle_add(*outb, AUL_K_CALLER_PID, pid_str); - -end: - num_str = bundle_get_val(inb, AUL_K_SEQ_NUM); - if (num_str == NULL) { - _E("original msg does not have seq num"); - bundle_free(*outb); - *outb = NULL; - return AUL_R_ECANCELED; - } - bundle_add(*outb, AUL_K_SEQ_NUM, num_str); - - return AUL_R_OK; -} - -int aul_send_result(bundle *kb, int is_cancel) -{ - int pid; - int ret; - int callee_pid; - int callee_pgid; - char callee_appid[256]; - char tmp_pid[MAX_PID_STR_BUFSZ]; - - if ((pid = __get_caller_pid(kb)) < 0) - return AUL_R_EINVAL; - - _D("caller pid : %d", pid); - - if (bundle_get_val(kb, AUL_K_SEND_RESULT) == NULL) { - _D("original msg is not msg with result"); - return AUL_R_OK; - } - - callee_pid = getpid(); - callee_pgid = getpgid(callee_pid); - snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", callee_pgid); - bundle_add(kb, AUL_K_CALLEE_PID, tmp_pid); - - ret = aul_app_get_appid_bypid(callee_pid, callee_appid, - sizeof(callee_appid)); - if (ret == 0) - bundle_add(kb, AUL_K_CALLEE_APPID, callee_appid); - else - _W("fail(%d) to get callee appid by pid", ret); - - ret = app_send_cmd_with_noreply(AUL_UTIL_PID, - (is_cancel == 1) ? APP_CANCEL : APP_RESULT, kb); - _D("app_send_cmd_with_noreply : %d", ret); - - return ret; -} - -API int aul_subapp_terminate_request_pid(int pid) -{ - char pid_str[MAX_PID_STR_BUFSZ]; - aul_reply_info_t *info; - GList *iter; - int ret; - - if (pid <= 0) - return AUL_R_EINVAL; - - pthread_mutex_lock(&__aul_mutex); - iter = __reply_info_list; - while (iter) { - info = (aul_reply_info_t *)iter->data; - iter = g_list_next(iter); - if (info->launched_pid == pid) { - __reply_info_list = g_list_remove(__reply_info_list, - info); - __destroy_aul_reply_info(info); - } - } - pthread_mutex_unlock(&__aul_mutex); - - snprintf(pid_str, MAX_PID_STR_BUFSZ, "%d", pid); - ret = app_request_to_launchpad(APP_TERM_REQ_BY_PID, pid_str, NULL); - return ret; -} - -int aul_subapp_terminate_request(const char *instance_id, int pid) -{ - aul_reply_info_t *info; - GList *iter; - - if (pid <= 0) - return AUL_R_EINVAL; - - pthread_mutex_lock(&__aul_mutex); - iter = __reply_info_list; - while (iter) { - info = (aul_reply_info_t *)iter->data; - iter = g_list_next(iter); - if (info->launched_pid == pid) { - __reply_info_list = g_list_remove(__reply_info_list, - info); - __destroy_aul_reply_info(info); - } - } - pthread_mutex_unlock(&__aul_mutex); - - return aul_terminate_instance_async(instance_id, pid); -} - -API int aul_add_caller_cb(int pid, void (*caller_cb)(int, void *), - void *data) -{ - aul_reply_info_t *info; - GList *iter; - - if (pid <= 0) - return AUL_R_EINVAL; - - pthread_mutex_lock(&__aul_mutex); - iter = __reply_info_list; - while (iter) { - info = (aul_reply_info_t *)iter->data; - if (info->launched_pid == pid && - !info->caller_cb) { - info->caller_cb = caller_cb; - info->caller_data = data; - pthread_mutex_unlock(&__aul_mutex); - return AUL_R_OK; - } - iter = g_list_next(iter); - } - pthread_mutex_unlock(&__aul_mutex); - - return AUL_R_ERROR; -} - -API int aul_remove_caller_cb(int pid, void *data) -{ - aul_reply_info_t *info; - GList *iter; - - if (pid <= 0) - return AUL_R_EINVAL; - - pthread_mutex_lock(&__aul_mutex); - iter = __reply_info_list; - while (iter) { - info = (aul_reply_info_t *)iter->data; - if (info->launched_pid == pid && - info->caller_data == data) { - info->caller_cb = NULL; - info->caller_data = NULL; - pthread_mutex_unlock(&__aul_mutex); - return AUL_R_OK; - } - iter = g_list_next(iter); - } - pthread_mutex_unlock(&__aul_mutex); - - return AUL_R_ERROR; -} - -static gboolean __invoke_caller_cb(gpointer data) -{ - aul_reply_info_t *info = (aul_reply_info_t *)data; - - if (info && info->caller_cb) - info->caller_cb(info->launched_pid, info->caller_data); - - __destroy_aul_reply_info(info); - - return G_SOURCE_REMOVE; -} - -API int aul_invoke_caller_cb(void *data) -{ - aul_reply_info_t *new_info; - aul_reply_info_t *info; - GList *iter; - - pthread_mutex_lock(&__aul_mutex); - iter = __reply_info_list; - while (iter) { - info = (aul_reply_info_t *)iter->data; - if (info->caller_data == data) { - new_info = __create_aul_reply_info( - info->launched_pid, - info->seq_num, - info->reply_cb, - info->user_data); - if (!new_info) { - _E("Out of memory"); - break; - } - - new_info->caller_cb = info->caller_cb; - new_info->caller_data = info->caller_data; - - g_idle_add_full(G_PRIORITY_DEFAULT, - __invoke_caller_cb, - new_info, NULL); - break; - } - iter = g_list_next(iter); - - } - pthread_mutex_unlock(&__aul_mutex); - - return 0; -} - -API int aul_launch_app_with_result_async(const char *appid, bundle *b, - void (*callback)(bundle *, int, void *), void *data) -{ - return __launch_app_with_result(APP_START_RES_ASYNC, appid, b, callback, - data, getuid()); -} - -API int aul_launch_app_with_result_async_for_uid(const char *appid, bundle *b, - void (*callback)(bundle *, int, void *), void *data, uid_t uid) -{ - return __launch_app_with_result(APP_START_RES_ASYNC, appid, b, callback, - data, uid); -} - -static gboolean __aul_error_handler(GIOChannel *io, - GIOCondition cond, gpointer user_data) -{ - int fd = g_io_channel_unix_get_fd(io); - aul_error_info_t *info = (aul_error_info_t *)user_data; - aul_reply_info_t *r_info; - int res; - - if (!info) { - _E("Critical error!"); - return G_SOURCE_REMOVE; - } - - res = aul_sock_recv_result_with_fd(fd); - if (res < 1) { - res = aul_error_convert(res); - if (res == AUL_R_LOCAL) - res = app_request_local(info->cmd, info->b); - } else { - __update_aul_reply_info(info->seq_num, res); - } - - _W("Sequence(%s), result(%d)", info->seq_num, res); - - if (info->error_cb) { - info->error_cb(res, info->user_data); - info->error_cb = NULL; - } - - if (res < 1) { - r_info = __pop_aul_reply_info(info->seq_num); - if (r_info) - __destroy_aul_reply_info(r_info); - } - - __destroy_aul_error_info(info); - - return G_SOURCE_REMOVE; -} - -static int __aul_error_info_add_watch(int fd, aul_error_info_t *info) -{ - GIOCondition cond = G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP; - guint source; - - info->io = g_io_channel_unix_new(fd); - if (!info->io) { - _E("Failed to create gio channel"); - return -1; - } - - source = g_io_add_watch(info->io, cond, __aul_error_handler, info); - if (!source) { - _E("Failed to add gio watch"); - return -1; - } - g_io_channel_set_close_on_unref(info->io, TRUE); - - return 0; -} - -static int __send_request_with_callback(int cmd, const char *appid, bundle *b, - uid_t uid, - void (*reply_cb)(bundle *b, int, void *), - void (*error_cb)(int, void *), - void *user_data) -{ - aul_error_info_t *info; - aul_reply_info_t *r_info; - char *seq_num; - int fd; - - if (!aul_is_initialized()) { - if (aul_launch_init(NULL, NULL) < 0) { - _E("Failed to initialize aul launch"); - return AUL_R_ENOINIT; - } - } - - if (!appid || !b || !error_cb) { - _E("Invalid parameter"); - return AUL_R_EINVAL; - } - - seq_num = __gen_seq_num(); - if (!seq_num) { - _E("Out of memory"); - return AUL_R_ERROR; - } - - bundle_del(b, AUL_K_SEQ_NUM); - bundle_add(b, AUL_K_SEQ_NUM, seq_num); - - if (reply_cb) { - r_info = __create_aul_reply_info(-1, seq_num, - reply_cb, user_data); - if (!r_info) { - _E("Failed to create reply info"); - free(seq_num); - return AUL_R_ERROR; - } - __push_aul_reply_info(r_info); - } - - fd = app_request_to_launchpad_for_uid(cmd, - appid, b, uid); - if (fd < 0 || fd > sysconf(_SC_OPEN_MAX)) { - _E("Failed to send launch request. appid(%s), result(%d)", - appid, fd); - if (reply_cb) { - r_info = __pop_aul_reply_info(seq_num); - if (r_info) - __destroy_aul_reply_info(r_info); - } - free(seq_num); - return AUL_R_ECOMM; - } - - info = __create_aul_error_info(seq_num ,b, cmd, - error_cb, user_data); - if (!info) { - _E("Failed to create error info"); - if (reply_cb) { - r_info = __pop_aul_reply_info(seq_num); - if (r_info) - __destroy_aul_reply_info(r_info); - } - free(seq_num); - return AUL_R_ERROR; - } - - if (__aul_error_info_add_watch(fd, info) < 0) { - _E("Failed to add resultcb watch"); - __destroy_aul_error_info(info); - if (reply_cb) { - r_info = __pop_aul_reply_info(seq_num); - if (r_info) - __destroy_aul_reply_info(r_info); - } - free(seq_num); - close(fd); - return AUL_R_ERROR; - } - free(seq_num); - - return AUL_R_OK; -} - -API int aul_send_launch_request_for_uid(const char *appid, bundle *b, uid_t uid, - void (*reply_cb)(bundle *, int, void *), - void (*error_cb)(int, void *), - void *user_data) -{ - int ret; - - ret = __send_request_with_callback(APP_SEND_LAUNCH_REQUEST, appid, b, - uid, reply_cb, error_cb, user_data); - - return ret; -} - -static int __send_launch_request(const char *appid, bundle *b, uid_t uid) -{ - char *seq_num; - int fd; - - seq_num = __gen_seq_num(); - if (!seq_num) { - _E("Out of memory"); - return AUL_R_ERROR; - } - - bundle_del(b, AUL_K_SEQ_NUM); - bundle_add(b, AUL_K_SEQ_NUM, seq_num); - free(seq_num); - - fd = app_request_to_launchpad_for_uid(APP_SEND_LAUNCH_REQUEST_SYNC, - appid, b, uid); - if (fd < 0 || fd > sysconf(_SC_OPEN_MAX)) { - _E("Failed to send launch request. appid(%s), result(%d)", - appid, fd); - return AUL_R_ECOMM; - } - - return fd; -} - -static int __recv_reply_bundle(int fd, bundle **reply_b) -{ - app_pkt_t *pkt = NULL; - bundle *kb; - int ret; - - ret = aul_sock_recv_reply_pkt(fd, &pkt); - if (ret != 0) { - _E("Failed to receive the packet. result(%d)", ret); - return AUL_R_ECOMM; - } - - if (!(pkt->opt & AUL_SOCK_BUNDLE)) { - _E("Invalid protocol"); - free(pkt); - return AUL_R_ECOMM; - } - - ret = pkt->cmd; - if (ret < 0) { - _E("The launch request is failed. result(%d)", ret); - free(pkt); - return AUL_R_ERROR; - } - - kb = bundle_decode(pkt->data, pkt->len); - if (kb == NULL) { - _E("Out of memory"); - free(pkt); - return AUL_R_ERROR; - } - free(pkt); - *reply_b = kb; - - return ret; -} - -API int aul_send_launch_request_sync_for_uid(const char *appid, bundle *b, - uid_t uid, bundle **res_b) -{ - int fd; - - if (!aul_is_initialized()) { - if (aul_launch_init(NULL, NULL) < 0) { - _E("Failed to initialize aul launch"); - return AUL_R_ENOINIT; - } - } - - if (!appid || !b || !res_b) { - _E("Invalid parameter"); - return AUL_R_EINVAL; - } - - fd = __send_launch_request(appid, b, uid); - if (fd < 0) - return fd; - - return __recv_reply_bundle(fd, res_b); -} - -API int aul_send_resume_request_for_uid(const char *appid, bundle *b, uid_t uid, - void (*error_cb)(int, void *), void *user_data) -{ - int ret; - - ret = __send_request_with_callback(APP_SEND_RESUME_REQUEST, appid, b, - uid, NULL, error_cb, user_data); - - return ret; -} diff --git a/src/launch_with_result.cc b/src/launch_with_result.cc new file mode 100644 index 0000000..3fc7a4d --- /dev/null +++ b/src/launch_with_result.cc @@ -0,0 +1,792 @@ +/* +* Copyright (c) 2000 - 2021 Samsung Electronics Co., Ltd All Rights Reserved +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "app_request.h" +#include "aul.h" +#include "aul_api.h" +#include "aul_error.h" +#include "aul_sock.h" +#include "aul_svc.h" +#include "aul_svc_priv_key.h" +#include "aul_util.h" +#include "launch.h" + +using namespace aul::internal; + +namespace { + +using ErrCb = std::function; +using ReplyCb = std::function; + +class ReplyList; +class ReplyInfo { + public: + ReplyInfo(int pid, std::string seq_num, + ReplyCb reply_cb, void* user_data) + : seq_num_(std::move(seq_num)), launched_pid_(pid), + reply_cb_(std::move(reply_cb)), user_data_(user_data) {} + + void SetCallerCb(ErrCb cb, + void* caller_data) { + caller_cb_ = std::move(cb); + caller_data_ = caller_data; + } + + void UnsetCallerCb() { + caller_cb_ = nullptr; + caller_data_ = nullptr; + } + + int GetLaunchedPid() const { + return launched_pid_; + } + + const ErrCb& GetCallerCb() const { + return caller_cb_; + } + + void* GetCallerData() const { + return caller_data_; + } + + private: + friend class ReplyList; + + std::string seq_num_; + int launched_pid_; + ReplyCb reply_cb_; + void* user_data_; + ErrCb caller_cb_; + void* caller_data_ = nullptr; +}; + +class ReplyList { + public: + std::unique_ptr FindByCallerData(void* caller_data) { + std::unique_lock lock(mutex_); + for (auto& i : list_) { + if (i->caller_data_ == caller_data) + return std::unique_ptr(new ReplyInfo(*i)); + } + + return {}; + } + + std::unique_ptr Pop(const std::string& seq_num) { + if (seq_num.empty()) + return nullptr; + + std::unique_lock lock(mutex_); + for (auto i = list_.begin(); i != list_.end(); ++i) { + if ((*i)->seq_num_ == seq_num) { + auto ret = std::move(*i); + list_.erase(i); + return ret; + } + } + + return nullptr; + } + + void Remove(int pid) { + std::unique_lock lock(mutex_); + for (auto i = list_.begin(); i != list_.end(); ) { + if ((*i)->launched_pid_ == pid) { + i = list_.erase(i); + } else { + ++i; + } + } + } + + void Push(std::unique_ptr info) { + if (info == nullptr) + return; + + std::unique_lock lock(mutex_); + list_.push_back(std::move(info)); + } + + void UpdatePid(const std::string& seq_num, int launched_pid) { + std::unique_lock lock(mutex_); + auto* i = Find(seq_num); + if (i == nullptr) + return; + i->launched_pid_ = launched_pid; + } + + bool SetCallerCb(int pid, ErrCb cb, + void* caller_data) { + std::unique_lock lock(mutex_); + auto* i = Find(pid); + if (i == nullptr) + return false; + i->SetCallerCb(std::move(cb), caller_data); + return true; + } + + bool UnsetCallerCb(int pid, void* caller_data) { + std::unique_lock lock(mutex_); + auto* i = Find(pid, caller_data); + if (i == nullptr) + return false; + i->UnsetCallerCb(); + return true; + } + + int InvokeReplyCb(const tizen_base::Bundle& b, bool is_cancel, + int launched_pid) { + if (launched_pid < 0) { + _E("Received pid(%d)", launched_pid); + return -1; + } + + auto seq_num = b.GetString(AUL_K_SEQ_NUM); + if (seq_num.empty()) { + _E("Failed to get seq num"); + return -1; + } + + auto info = Pop(seq_num); + if (info == nullptr) { + _E("Failed to find reply info"); + return -1; + } + + if (info->reply_cb_ == nullptr) { + _E("Reply callback function is nullptr"); + return -1; + } + + auto fwdpid_str = b.GetString(AUL_K_FWD_CALLEE_PID); + if (is_cancel && !fwdpid_str.empty()) { + launched_pid = atoi(fwdpid_str.c_str()); + auto new_info = std::make_unique(launched_pid, seq_num, + info->reply_cb_, info->user_data_); + Push(std::move(new_info)); + + if (info->caller_cb_ != nullptr) + info->caller_cb_(launched_pid, info->caller_data_); + + _W("Change reply info. fwd pid: %d", launched_pid); + return 0; + } + + info->reply_cb_(b.GetHandle(), is_cancel ? 1 : 0, info->user_data_); + + return 0; + } + + private: + ReplyInfo* Find(const std::string& seq_num) { + for (auto& i : list_) { + if (i->seq_num_ == seq_num) + return i.get(); + } + + return nullptr; + } + + ReplyInfo* Find(int pid) { + for (auto& i : list_) { + if (i->launched_pid_ == pid && i->caller_cb_ == nullptr) + return i.get(); + } + + return nullptr; + } + + ReplyInfo* Find(int pid, void* caller_data) { + for (auto& i : list_) { + if (i->launched_pid_ == pid && i->caller_data_ == caller_data) + return i.get(); + } + + return nullptr; + } + + private: + std::list> list_; + std::mutex mutex_; +}; + +ReplyList __reply_list; + +class ErrorInfo { + public: + ErrorInfo(std::string seq_num, tizen_base::Bundle b, int cmd, + ErrCb error_cb, void* user_data) + : seq_num_(std::move(seq_num)), b_(std::move(b)), cmd_(cmd), + error_cb_(std::move(error_cb)), user_data_(user_data) { + } + + ErrorInfo(const ErrorInfo&) = delete; + ErrorInfo& operator = (const ErrorInfo&) = delete; + + ~ErrorInfo() { + if (io_ != nullptr) + g_io_channel_unref(io_); + } + + int AddWatch(int fd) { + GIOCondition cond = static_cast (G_IO_IN | G_IO_PRI | + G_IO_ERR | G_IO_HUP); + io_ = g_io_channel_unix_new(fd); + if (io_ == nullptr) { + _E("Failed to create gio channel"); + return -1; + } + + guint source = g_io_add_watch(io_, cond, ErrorHandlerCb, this); + if (source == 0) { + _E("Failed to add gio watch"); + return -1; + } + g_io_channel_set_close_on_unref(io_, TRUE); + + return 0; + } + + static gboolean ErrorHandlerCb(GIOChannel* io, GIOCondition cond, + gpointer user_data) { + int fd = g_io_channel_unix_get_fd(io); + auto* info = reinterpret_cast(user_data); + + if (info == nullptr) { + _E("Critical error!"); + return G_SOURCE_REMOVE; + } + + int res = aul_sock_recv_result_with_fd(fd); + if (res < 1) { + res = aul_error_convert(res); + if (res == AUL_R_LOCAL) + res = app_request_local(info->cmd_, info->b_.GetHandle()); + } else { + __reply_list.UpdatePid(info->seq_num_, res); + } + + _W("Sequence(%s), result(%d)", info->seq_num_.c_str(), res); + + if (info->error_cb_ != nullptr) { + info->error_cb_(res, info->user_data_); + info->error_cb_ = nullptr; + } + + if (res < 1) + __reply_list.Pop(info->seq_num_); + + delete info; + return G_SOURCE_REMOVE; + } + + private: + GIOChannel* io_ = nullptr; + std::string seq_num_; + tizen_base::Bundle b_; + int cmd_; + ErrCb error_cb_; + void* user_data_; +}; + +std::string __gen_seq_num() { + static std::atomic num; + char buf[MAX_LOCAL_BUFSZ]; + + int n = num.fetch_add(1); + unsigned int seed = time(nullptr) + n; + snprintf(buf, sizeof(buf), "%d@%d", rand_r(&seed), n); + + return buf; +} + +int __get_caller_pid(const tizen_base::Bundle& b) { + std::string pid_str = b.GetString(AUL_K_ORG_CALLER_PID); + if (pid_str.empty()) + pid_str = b.GetString(AUL_K_CALLER_PID); + + if (pid_str.empty()) + return -1; + + int pid = atoi(pid_str.c_str()); + if (pid <= 1) + return -1; + + return pid; +} + +int __launch_app_with_result(int cmd, const char* appid, bundle* kb, + void (*callback)(bundle*, int, void*), void* data, uid_t uid) { + if (!aul_is_initialized()) { + if (aul_launch_init(nullptr, nullptr) < 0) + return AUL_R_ENOINIT; + } + + if (appid == nullptr || callback == nullptr || kb == nullptr) + return AUL_R_EINVAL; + + std::string seq_num = __gen_seq_num(); + bundle_del(kb, AUL_K_SEQ_NUM); + bundle_add(kb, AUL_K_SEQ_NUM, seq_num.c_str()); + + auto info = std::make_unique(-1, seq_num, callback, data); + __reply_list.Push(std::move(info)); + + int ret = AppRequest(cmd, uid) + .With(kb) + .SetAppId(appid) + .Send(); + + if (ret > 0) + __reply_list.UpdatePid(seq_num, ret); + else + __reply_list.Pop(seq_num); + + return ret; +} + +int __set_caller_info(bundle* kb) { + const char* caller_pid; + const char* caller_uid; + + caller_pid = bundle_get_val(kb, AUL_K_CALLER_PID); + if (caller_pid == nullptr) { + _E("Failed to get caller pid"); + return AUL_R_EINVAL; + } + + caller_uid = bundle_get_val(kb, AUL_K_CALLER_UID); + if (caller_uid == nullptr) { + _E("Failed to get caller uid"); + return AUL_R_EINVAL; + } + + bundle_del(kb, AUL_K_ORG_CALLER_PID); + bundle_add(kb, AUL_K_ORG_CALLER_PID, caller_pid); + bundle_del(kb, AUL_K_ORG_CALLER_UID); + bundle_add(kb, AUL_K_ORG_CALLER_UID, caller_uid); + + return AUL_R_OK; +} + +int __recv_reply_bundle(int fd, bundle** reply_b) { + app_pkt_t* pkt = nullptr; + int ret = aul_sock_recv_reply_pkt(fd, &pkt); + if (ret != 0) { + _E("Failed to receive the packet. result(%d)", ret); + return AUL_R_ECOMM; + } + + std::unique_ptr pkt_auto(pkt, free); + if (!(pkt_auto->opt & AUL_SOCK_BUNDLE)) { + _E("Invalid protocol"); + return AUL_R_ECOMM; + } + + ret = pkt_auto->cmd; + if (ret < 0) { + _E("The launch request is failed. result(%d)", ret); + return AUL_R_ERROR; + } + + bundle* kb = bundle_decode(pkt_auto->data, pkt_auto->len); + if (kb == nullptr) { + _E("Out of memory"); + return AUL_R_ERROR; + } + + *reply_b = kb; + return ret; +} + +int __send_request_with_callback(int cmd, const char* appid, bundle* b, + uid_t uid, + void (*reply_cb)(bundle* b, int, void*), + void (*error_cb)(int, void*), + void* user_data) { + if (!aul_is_initialized()) { + if (aul_launch_init(nullptr, nullptr) < 0) { + _E("Failed to initialize aul launch"); + return AUL_R_ENOINIT; + } + } + + if (appid == nullptr || b == nullptr || error_cb == nullptr) { + _E("Invalid parameter"); + return AUL_R_EINVAL; + } + + std::string seq_num = __gen_seq_num(); + bundle_del(b, AUL_K_SEQ_NUM); + bundle_add(b, AUL_K_SEQ_NUM, seq_num.c_str()); + + if (reply_cb != nullptr) { + auto r_info = std::make_unique(-1, seq_num, reply_cb, + user_data); + __reply_list.Push(std::move(r_info)); + } + + int fd = AppRequest(cmd, uid) + .With(b) + .SetAppId(appid) + .Send(); + if (fd < 0 || fd > sysconf(_SC_OPEN_MAX)) { + _E("Failed to send launch request. appid(%s), result(%d)", + appid, fd); + if (reply_cb) + __reply_list.Pop(seq_num); + return AUL_R_ECOMM; + } + + auto error_info = std::make_unique(seq_num, + tizen_base::Bundle(b, true, true), cmd, error_cb, user_data); + if (error_info.get() == nullptr) { + _E("Failed to create error info"); + if (reply_cb != nullptr) + __reply_list.Pop(seq_num); + return AUL_R_ERROR; + } + + if (error_info->AddWatch(fd) < 0) { + _E("Failed to add resultcb watch"); + if (reply_cb != nullptr) + __reply_list.Pop(seq_num); + close(fd); + return AUL_R_ERROR; + } + + error_info.release(); + return AUL_R_OK; +} + +int __send_launch_request(const std::string& appid, bundle* kb, uid_t uid) { + std::string seq_num = __gen_seq_num(); + tizen_base::Bundle b(kb, false, false); + b.Delete(AUL_K_SEQ_NUM); + b.Add(AUL_K_SEQ_NUM, seq_num); + + int fd = AppRequest(APP_SEND_LAUNCH_REQUEST_SYNC, uid) + .With(b) + .SetAppId(appid) + .Send(); + if (fd < 0 || fd > sysconf(_SC_OPEN_MAX)) { + _E("Failed to send launch request. appid(%s), result(%d)", + appid.c_str(), fd); + return AUL_R_ECOMM; + } + + return fd; +} + +} // namespace + +extern "C" int app_result(int cmd, bundle* kb, int launched_pid) { + switch (cmd) { + case APP_RESULT: + __reply_list.InvokeReplyCb(tizen_base::Bundle(kb, false, false), false, + launched_pid); + break; + case APP_CANCEL: + __reply_list.InvokeReplyCb(tizen_base::Bundle(kb, false, false), true, + launched_pid); + break; + } + + return 0; +} + +extern "C" API int aul_launch_app_with_result(const char* pkgname, bundle* kb, + void (*cbfunc)(bundle*, int, void*), void* data) { + return __launch_app_with_result(APP_START_RES, pkgname, kb, cbfunc, + data, getuid()); +} + +extern "C" API int aul_launch_app_with_result_for_uid(const char* pkgname, + bundle* kb, void (*cbfunc)(bundle*, int, void*), void* data, uid_t uid) { + return __launch_app_with_result(APP_START_RES, pkgname, kb, cbfunc, + data, uid); +} + +extern "C" void aul_set_instance_info(const char* app_id, bundle* kb) { + const char* component_id; + char buf[1024]; + char uuid[37]; + uuid_t u; + + uuid_generate(u); + uuid_unparse(u, uuid); + + component_id = bundle_get_val(kb, AUL_K_COMPONENT_ID); + if (component_id != nullptr) { + snprintf(buf, sizeof(buf), "%s:%s:%s", + uuid, app_id, component_id); + } else { + snprintf(buf, sizeof(buf), "%s:%s", uuid, app_id); + } + + bundle_del(kb, AUL_K_INSTANCE_ID); + bundle_add(kb, AUL_K_INSTANCE_ID, buf); +} + +extern "C" API int aul_forward_app(const char* pkgname, bundle* kb) { + if (pkgname == nullptr || kb == nullptr) + return AUL_R_EINVAL; + + if (__set_caller_info(kb) < 0) + return AUL_R_EINVAL; + + bundle_del(kb, AUL_SVC_K_CAN_BE_LEADER); + bundle_del(kb, AUL_SVC_K_REROUTE); + bundle_del(kb, AUL_SVC_K_RECYCLE); + + const char* launch_mode = bundle_get_val(kb, AUL_SVC_K_LAUNCH_MODE); + if (launch_mode != nullptr && !strcmp(launch_mode, "group")) + aul_set_instance_info(pkgname, kb); + + int ret; + tizen_base::Bundle dupb(kb, true, true); + if (bundle_get_val(kb, AUL_K_WAIT_RESULT) != nullptr) { + ret = AppRequest(APP_START_RES) + .With(kb) + .SetAppId(pkgname) + .Send(); + if (ret < 0) + return ret; + } else { + ret = AppRequest(APP_START) + .With(kb) + .SetAppId(pkgname) + .Send(); + return ret; + } + + bundle* outb = nullptr; + int pid = ret; + ret = aul_create_result_bundle(dupb.GetHandle(), &outb); + if (ret < 0) + return ret; + tizen_base::Bundle outb_auto(outb, false, true); + + outb_auto.Delete(AUL_K_FWD_CALLEE_PID); + outb_auto.Add(AUL_K_FWD_CALLEE_PID, std::to_string(pid)); + return aul_send_result(outb_auto.GetHandle(), 1); +} + +extern "C" API int aul_create_result_bundle(bundle* inb, bundle** outb) { + *outb = nullptr; + + if (inb == nullptr) { + _E("return msg create fail"); + return AUL_R_EINVAL; + } + + tizen_base::Bundle inb_auto(inb, false, false); + tizen_base::Bundle outb_auto; + + if (!inb_auto.GetString(AUL_K_WAIT_RESULT).empty()) { + outb_auto.Add(AUL_K_SEND_RESULT, "1"); + _D("original msg is msg with result"); + } else { + _D("original msg is not msg with result"); + } + + std::string uid_str = inb_auto.GetString(AUL_K_ORG_CALLER_UID); + if (uid_str.empty()) { + uid_str = inb_auto.GetString(AUL_K_CALLER_UID); + if (uid_str.empty()) { + _E("Failed to find caller uid"); + return AUL_R_EINVAL; + } + } + + outb_auto.Add(AUL_K_ORG_CALLER_UID, uid_str); + std::string pid_str = inb_auto.GetString(AUL_K_ORG_CALLER_PID); + if (!pid_str.empty()) { + outb_auto.Add(AUL_K_ORG_CALLER_PID, pid_str); + goto end; + } + + pid_str = inb_auto.GetString(AUL_K_CALLER_PID); + if (pid_str.empty()) { + _E("original msg does not have caller pid"); + return AUL_R_EINVAL; + } + + outb_auto.Add(AUL_K_CALLER_PID, pid_str); + +end: + std::string num_str = inb_auto.GetString(AUL_K_SEQ_NUM); + if (num_str.empty()) { + _E("original msg does not have seq num"); + return AUL_R_ECANCELED; + } + + outb_auto.Add(AUL_K_SEQ_NUM, num_str); + *outb = outb_auto.Detach(); + return AUL_R_OK; +} + +extern "C" int aul_send_result(bundle* kb, int is_cancel) { + int pid; + int ret; + int callee_pid; + int callee_pgid; + char callee_appid[256]; + + if (kb == nullptr) + return AUL_R_EINVAL; + + tizen_base::Bundle b(kb, false, false); + if ((pid = __get_caller_pid(b)) < 0) + return AUL_R_EINVAL; + + _D("caller pid : %d", pid); + + if (b.GetString(AUL_K_SEND_RESULT).empty()) { + _D("original msg is not msg with result"); + return AUL_R_OK; + } + + callee_pid = getpid(); + callee_pgid = getpgid(callee_pid); + b.Add(AUL_K_CALLEE_PID, std::to_string(callee_pgid)); + + ret = aul_app_get_appid_bypid(callee_pid, callee_appid, + sizeof(callee_appid)); + if (ret == 0) + b.Add(AUL_K_CALLEE_APPID, callee_appid); + else + _W("fail(%d) to get callee appid by pid", ret); + + ret = app_send_cmd_with_noreply(AUL_UTIL_PID, + (is_cancel == 1) ? APP_CANCEL : APP_RESULT, b.GetHandle()); + _D("app_send_cmd_with_noreply : %d", ret); + + return ret; +} + +extern "C" API int aul_subapp_terminate_request_pid(int pid) { + if (pid <= 0) + return AUL_R_EINVAL; + + __reply_list.Remove(pid); + return AppRequest(APP_TERM_REQ_BY_PID) + .SetAppIdAsPid(pid) + .Send(); +} + +extern "C" int aul_subapp_terminate_request(const char* instance_id, int pid) { + if (pid <= 0) + return AUL_R_EINVAL; + + __reply_list.Remove(pid); + return aul_terminate_instance_async(instance_id, pid); +} + +extern "C" API int aul_add_caller_cb(int pid, void (*caller_cb)(int, void*), + void* data) { + if (pid <= 0) + return AUL_R_EINVAL; + + if (__reply_list.SetCallerCb(pid, caller_cb, data)) + return AUL_R_OK; + + return AUL_R_ERROR; +} + +extern "C" API int aul_remove_caller_cb(int pid, void* data) { + if (pid <= 0) + return AUL_R_EINVAL; + + if (__reply_list.UnsetCallerCb(pid, data)) + return AUL_R_OK; + + return AUL_R_ERROR; +} + +extern "C" API int aul_invoke_caller_cb(void* data) { + auto info = __reply_list.FindByCallerData(data); + if (info == nullptr) + return 0; + + g_idle_add_full(G_PRIORITY_DEFAULT, [](gpointer data) -> gboolean { + auto* info = reinterpret_cast(data); + + if (info != nullptr && info->GetCallerCb() != nullptr) + info->GetCallerCb()(info->GetLaunchedPid(), info->GetCallerData()); + + delete info; + return G_SOURCE_REMOVE; + }, info.release(), nullptr); + + return 0; +} + +extern "C" API int aul_launch_app_with_result_async(const char* appid, + bundle* b, void (*callback)(bundle*, int, void*), void* data) { + return __launch_app_with_result(APP_START_RES_ASYNC, appid, b, callback, + data, getuid()); +} + +extern "C" API int aul_launch_app_with_result_async_for_uid(const char* appid, + bundle* b, void (*callback)(bundle*, int, void*), void* data, uid_t uid) { + return __launch_app_with_result(APP_START_RES_ASYNC, appid, b, callback, + data, uid); +} + +extern "C" API int aul_send_launch_request_for_uid(const char* appid, + bundle* b, uid_t uid, void (*reply_cb)(bundle*, int, void*), + void (*error_cb)(int, void*), void* user_data) { + return __send_request_with_callback(APP_SEND_LAUNCH_REQUEST, appid, b, + uid, reply_cb, error_cb, user_data); +} + +extern "C" API int aul_send_launch_request_sync_for_uid(const char* appid, + bundle* b, uid_t uid, bundle** res_b) { + if (!aul_is_initialized()) { + if (aul_launch_init(nullptr, nullptr) < 0) { + _E("Failed to initialize aul launch"); + return AUL_R_ENOINIT; + } + } + + if (appid == nullptr || b == nullptr || res_b == nullptr) { + _E("Invalid parameter"); + return AUL_R_EINVAL; + } + + int fd = __send_launch_request(appid, b, uid); + if (fd < 0) + return fd; + + return __recv_reply_bundle(fd, res_b); +} + +extern "C" API int aul_send_resume_request_for_uid(const char* appid, + bundle* b, uid_t uid, void (*error_cb)(int, void*), void* user_data) { + return __send_request_with_callback(APP_SEND_RESUME_REQUEST, appid, b, + uid, nullptr, error_cb, user_data); +} diff --git a/test/unit_tests/mock/glib_mock.cc b/test/unit_tests/mock/glib_mock.cc new file mode 100644 index 0000000..06cf826 --- /dev/null +++ b/test/unit_tests/mock/glib_mock.cc @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mock/glib_mock.h" +#include "mock/mock_hook.h" +#include "mock/test_fixture.h" + +extern "C" GIOChannel* g_io_channel_unix_new(gint fd) { + return MOCK_HOOK_P1(GlibMock, g_io_channel_unix_new, fd); +} + +extern "C" guint g_io_add_watch(GIOChannel* channel, GIOCondition condition, + GIOFunc func, gpointer user_data) { + return MOCK_HOOK_P4(GlibMock, g_io_add_watch, channel, condition, func, + user_data); +} + +extern "C" void g_io_channel_set_close_on_unref(GIOChannel* channel, + gboolean do_close) { + MOCK_HOOK_P2(GlibMock, g_io_channel_set_close_on_unref, channel, do_close); +} + +extern "C" void g_io_channel_unref(GIOChannel* channel) { + MOCK_HOOK_P1(GlibMock, g_io_channel_unref, channel); +} + +extern "C" gint g_io_channel_unix_get_fd(GIOChannel* channel) { + return MOCK_HOOK_P1(GlibMock, g_io_channel_unix_get_fd, channel); +} + +extern "C" guint g_idle_add_full(gint priority, GSourceFunc function, + gpointer data, GDestroyNotify notify) { + return MOCK_HOOK_P4(GlibMock, g_idle_add_full, priority, function, data, + notify); +} + +extern "C" GSource* g_io_create_watch(GIOChannel* channel, + GIOCondition condition) { + return MOCK_HOOK_P2(GlibMock, g_io_create_watch, channel, condition); +} + +extern "C" void g_source_unref(GSource* source) { + MOCK_HOOK_P1(GlibMock, g_source_unref, source); +} + +extern "C" void g_source_set_callback(GSource* source, GSourceFunc func, + gpointer data, GDestroyNotify notify) { + MOCK_HOOK_P4(GlibMock, g_source_set_callback, source, func, data, notify); +} + +extern "C" void g_source_set_priority(GSource* source, gint priority) { + MOCK_HOOK_P2(GlibMock, g_source_set_priority, source, priority); +} + +extern "C" guint g_source_attach (GSource* source, GMainContext* context) { + return MOCK_HOOK_P2(GlibMock, g_source_attach, source, context); +} + +extern "C" GIOStatus g_io_channel_shutdown(GIOChannel* channel, + gboolean flush, GError** err) { + return MOCK_HOOK_P3(GlibMock, g_io_channel_shutdown, channel, flush, err); +} + +extern "C" gboolean g_main_loop_is_running (GMainLoop *loop) { + return MOCK_HOOK_P1(GlibMock, g_main_loop_is_running, loop); +} diff --git a/test/unit_tests/mock/glib_mock.h b/test/unit_tests/mock/glib_mock.h new file mode 100644 index 0000000..16870f6 --- /dev/null +++ b/test/unit_tests/mock/glib_mock.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UNIT_TESTS_MOCK_GLIB_MOCK_H_ +#define UNIT_TESTS_MOCK_GLIB_MOCK_H_ + +#include +#include +#include + +#include "mock/module_mock.h" + +class GlibMock : public virtual ModuleMock { + public: + GlibMock() { + using ::testing::_; + using ::testing::Return; + using ::testing::Invoke; + + static int dummy; + GIOChannel* ch = (GIOChannel*)&dummy; + GSource* source = (GSource*)&dummy; + + ON_CALL(*this, g_io_channel_unix_new(_)) + .WillByDefault(Return(ch)); + ON_CALL(*this, g_io_add_watch(_, _, _, _)) + .WillByDefault(Return(1)); + ON_CALL(*this, g_io_channel_unix_get_fd(_)) + .WillByDefault(Return(1)); + ON_CALL(*this, g_idle_add_full(_, _, _, _)) + .WillByDefault(Invoke([&](gint priority, GSourceFunc function, + gpointer data, GDestroyNotify notify) -> guint { + function(data); + return 1; + })); + ON_CALL(*this, g_io_create_watch(_, _)) + .WillByDefault(Return(source)); + ON_CALL(*this, g_main_loop_is_running(_)) + .WillByDefault(Return(TRUE)); + } + + MOCK_METHOD1(g_io_channel_unix_new, GIOChannel* (gint)); + MOCK_METHOD4(g_io_add_watch, guint (GIOChannel*, GIOCondition, + GIOFunc, gpointer)); + MOCK_METHOD2(g_io_channel_set_close_on_unref, void (GIOChannel*, gboolean)); + MOCK_METHOD1(g_io_channel_unref, void (GIOChannel*)); + MOCK_METHOD1(g_io_channel_unix_get_fd, gint (GIOChannel*)); + MOCK_METHOD4(g_idle_add_full, guint (gint, GSourceFunc, gpointer, + GDestroyNotify)); + MOCK_METHOD1(g_main_loop_is_running, gboolean (GMainLoop*)); + MOCK_METHOD2(g_io_create_watch, GSource* (GIOChannel*, GIOCondition)); + MOCK_METHOD1(g_source_unref, void (GSource*)); + MOCK_METHOD4(g_source_set_callback, void (GSource*, GSourceFunc, gpointer, + GDestroyNotify)); + MOCK_METHOD2(g_source_set_priority, void (GSource*, gint)); + MOCK_METHOD2(g_source_attach, guint (GSource*, GMainContext*)); + MOCK_METHOD3(g_io_channel_shutdown, GIOStatus (GIOChannel*, gboolean, + GError**)); +}; + +#endif // UNIT_TESTS_MOCK_GLIB_MOCK_H_ diff --git a/test/unit_tests/test_launch_with_result.cc b/test/unit_tests/test_launch_with_result.cc index 33979c1..8f19368 100644 --- a/test/unit_tests/test_launch_with_result.cc +++ b/test/unit_tests/test_launch_with_result.cc @@ -26,6 +26,7 @@ #include "launch.h" #include "mock/dbus_mock.h" +#include "mock/glib_mock.h" #include "mock/mock_hook.h" #include "mock/os_mock.h" #include "mock/socket_mock.h" @@ -42,6 +43,7 @@ namespace { class Mocks : virtual public ::testing::NiceMock, virtual public ::testing::NiceMock, + virtual public ::testing::NiceMock, virtual public ::testing::NiceMock {}; } // namespace @@ -77,6 +79,18 @@ class LaunchWithResultTest : public TestFixture { return std::unique_ptr(pkt, free); } + + std::unique_ptr MakePacket( + std::string str) { + app_pkt_t* pkt = + static_cast(calloc(1, sizeof(app_pkt_t) + str.length() + 1)); + pkt->opt = AUL_SOCK_NONE; + pkt->cmd = APP_GET_INFO_OK; + pkt->len = str.length() + 1; + memcpy(pkt->data, str.c_str(), str.length()); + + return std::unique_ptr(pkt, free); + } }; TEST_F(LaunchWithResultTest, aul_send_resume_request_for_uid) { @@ -90,6 +104,19 @@ TEST_F(LaunchWithResultTest, aul_send_resume_request_for_uid) { cmd = header->cmd; return n; })); + EXPECT_CALL(GetMock(), g_io_add_watch(_, _, _, _)) + .WillOnce(Invoke([](GIOChannel* channel, GIOCondition condition, + GIOFunc func, gpointer user_data) -> guint { + func(channel, condition, user_data); + return 1; + })); + EXPECT_CALL(GetMock(), recv(_, _, _, _)) + .Times(1) + .WillOnce(Invoke([](int fd, void* buf, size_t n, int flags) -> ssize_t { + int ret = 100; + memcpy(buf, &ret, sizeof(int)); + return sizeof(int); + })); int ret = aul_send_resume_request_for_uid("test_appid", b.GetHandle(), getuid(), [](int, void*) {}, nullptr); @@ -224,6 +251,29 @@ TEST_F(LaunchWithResultTest, aul_subapp_terminate_request_pid) { EXPECT_EQ(cmd, APP_TERM_REQ_BY_PID); } +TEST_F(LaunchWithResultTest, aul_subapp_terminate_request) { + int cmd = -1; + EXPECT_CALL(GetMock(), send(_, _, _, _)) + .Times(1) + .WillOnce(Invoke([&](int fd, const void* buf, size_t n, int flags) + -> ssize_t { + const app_pkt_t* header = reinterpret_cast(buf); + cmd = header->cmd; + return n; + })); + EXPECT_CALL(GetMock(), recv(_, _, _, _)) + .Times(1) + .WillOnce(Invoke([](int fd, void* buf, size_t n, int flags) -> ssize_t { + int ret = 0; + memcpy(buf, &ret, sizeof(int)); + return sizeof(int); + })); + + int ret = aul_subapp_terminate_request("inst", 100); + EXPECT_EQ(ret, AUL_R_OK); + EXPECT_EQ(cmd, APP_TERM_INSTANCE_ASYNC); +} + TEST_F(LaunchWithResultTest, aul_create_result_bundle) { tizen_base::Bundle inb = { { AUL_K_CALLER_UID, "10" }, @@ -264,3 +314,134 @@ TEST_F(LaunchWithResultTest, aul_forward_app) { EXPECT_EQ(ret, AUL_R_OK); EXPECT_EQ(cmd, APP_START); } + +TEST_F(LaunchWithResultTest, aul_launch_app_with_result) { + int cmd = -1; + tizen_base::Bundle b; + + EXPECT_CALL(GetMock(), send(_, _, _, _)) + .Times(1) + .WillOnce(Invoke([&](int fd, const void* buf, size_t n, int flags) + -> ssize_t { + const app_pkt_t* header = reinterpret_cast(buf); + cmd = header->cmd; + return n; + })); + EXPECT_CALL(GetMock(), recv(_, _, _, _)) + .Times(1) + .WillOnce(Invoke([](int fd, void* buf, size_t n, int flags) -> ssize_t { + int ret = 100; + memcpy(buf, &ret, sizeof(int)); + return sizeof(int); + })); + + int ret = aul_launch_app_with_result("test_appid", b.GetHandle(), + [](bundle*, int, void*) {}, nullptr); + EXPECT_EQ(ret, 100); + EXPECT_EQ(cmd, APP_START_RES); + ret = app_result(APP_RESULT, b.GetHandle(), 100); + EXPECT_EQ(ret, AUL_R_OK); +} + +TEST_F(LaunchWithResultTest, aul_launch_app_with_result_for_uid) { + int cmd = -1; + tizen_base::Bundle b; + + EXPECT_CALL(GetMock(), send(_, _, _, _)) + .Times(1) + .WillOnce(Invoke([&](int fd, const void* buf, size_t n, int flags) + -> ssize_t { + const app_pkt_t* header = reinterpret_cast(buf); + cmd = header->cmd; + return n; + })); + EXPECT_CALL(GetMock(), recv(_, _, _, _)) + .Times(1) + .WillOnce(Invoke([](int fd, void* buf, size_t n, int flags) -> ssize_t { + int ret = 100; + memcpy(buf, &ret, sizeof(int)); + return sizeof(int); + })); + + int ret = aul_launch_app_with_result_for_uid("test_appid", b.GetHandle(), + [](bundle*, int, void*) {}, nullptr, getuid()); + EXPECT_EQ(ret, 100); + EXPECT_EQ(cmd, APP_START_RES); + b.Add(AUL_K_FWD_CALLEE_PID, "200"); + ret = app_result(APP_CANCEL, b.GetHandle(), 100); + EXPECT_EQ(ret, AUL_R_OK); +} + +TEST_F(LaunchWithResultTest, aul_set_instance_info) { + tizen_base::Bundle b = { + { AUL_K_COMPONENT_ID, "comp" } + }; + + aul_set_instance_info("test-app", b.GetHandle()); + EXPECT_FALSE(b.GetString(AUL_K_INSTANCE_ID).empty()); +} + +TEST_F(LaunchWithResultTest, aul_send_result) { + int cmd1 = -1; + int cmd2 = -1; + tizen_base::Bundle b = { + { AUL_K_SEND_RESULT, "1" }, + { AUL_K_CALLER_PID, "100" } + }; + auto pkt = MakePacket("test-appid"); + + EXPECT_CALL(GetMock(), send(_, _, _, _)) + .Times(2) + .WillOnce(Invoke([&](int fd, const void* buf, size_t n, int flags) + -> ssize_t { + const app_pkt_t* header = reinterpret_cast(buf); + cmd1 = header->cmd; + return n; + })) + .WillOnce(Invoke([&](int fd, const void* buf, size_t n, int flags) + -> ssize_t { + const app_pkt_t* header = reinterpret_cast(buf); + cmd2 = header->cmd; + return n; + })); + EXPECT_CALL(GetMock(), recv(_, _, _, _)) + .Times(2) + .WillOnce(Invoke([&](int fd, void* buf, size_t n, int flags) -> ssize_t { + memcpy(buf, pkt.get(), n); // Header + return n; + })) + .WillOnce(Invoke([&](int fd, void* buf, size_t n, int flags) -> ssize_t { + memcpy(buf, pkt->data, n); // Body + return n; + })); + + int ret = aul_send_result(b.GetHandle(), 0); + EXPECT_EQ(ret, AUL_R_OK); + EXPECT_EQ(cmd1, APP_GET_APPID_BYPID); + EXPECT_EQ(cmd2, APP_RESULT); +} + +TEST_F(LaunchWithResultTest, aul_add_caller_cb) { + tizen_base::Bundle b; + constexpr const int ret_pid = 9216; + EXPECT_CALL(GetMock(), send(_, _, _, _)) + .Times(1); + EXPECT_CALL(GetMock(), recv(_, _, _, _)) + .Times(1) + .WillOnce(Invoke([](int fd, void* buf, size_t n, int flags) -> ssize_t { + int ret = ret_pid; + memcpy(buf, &ret, sizeof(int)); + return sizeof(int); + })); + int ret = aul_launch_app_with_result("test_appid", b.GetHandle(), + [](bundle*, int, void*) {}, nullptr); + EXPECT_EQ(ret, ret_pid); + + static int dummy; + ret = aul_add_caller_cb(ret_pid, [](int pid, void* data) {}, &dummy); + EXPECT_EQ(ret, AUL_R_OK); + ret = aul_invoke_caller_cb(&dummy); + EXPECT_EQ(ret, AUL_R_OK); + ret = aul_remove_caller_cb(ret_pid, &dummy); + EXPECT_EQ(ret, AUL_R_OK); +} \ No newline at end of file -- 2.7.4