Refactor launch_with_result.c 52/258852/14
authorjh9216.park <jh9216.park@samsung.com>
Thu, 27 May 2021 00:07:07 +0000 (20:07 -0400)
committerjh9216.park <jh9216.park@samsung.com>
Thu, 3 Jun 2021 07:55:20 +0000 (03:55 -0400)
- Use c++ syntax
- Extract class 'AppRequest'

Change-Id: Ic9fe84e25d89a5d33b00034de18152bbb077215c
Signed-off-by: jh9216.park <jh9216.park@samsung.com>
src/app_request.cc [new file with mode: 0644]
src/app_request.h [new file with mode: 0644]
src/launch.cc
src/launch.h
src/launch_with_result.c [deleted file]
src/launch_with_result.cc [new file with mode: 0644]
test/unit_tests/mock/glib_mock.cc [new file with mode: 0644]
test/unit_tests/mock/glib_mock.h [new file with mode: 0644]
test/unit_tests/test_launch_with_result.cc

diff --git a/src/app_request.cc b/src/app_request.cc
new file mode 100644 (file)
index 0000000..e2001a5
--- /dev/null
@@ -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 <bundle_internal.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <gio/gio.h>
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <ttrace.h>
+
+#include <memory>
+#include <utility>
+
+#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 (file)
index 0000000..28f066f
--- /dev/null
@@ -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 <bundle_cpp.h>
+#include <bundle.h>
+#include <string>
+
+#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
index bb658b6..74e30fd 100644 (file)
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <bundle_cpp.h>
 #include <bundle_internal.h>
 #include <ctype.h>
 #include <dirent.h>
@@ -31,6 +30,7 @@
 
 #include <memory>
 
+#include "app_request.h"
 #include "app_signal.h"
 #include "aul.h"
 #include "aul_api.h"
 #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)
index 6967e82..6bd31cd 100644 (file)
@@ -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 (file)
index 5e03462..0000000
+++ /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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <pthread.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <time.h>
-#include <glib.h>
-#include <gio/gio.h>
-#include <bundle_internal.h>
-#include <uuid.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"
-
-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 (file)
index 0000000..3fc7a4d
--- /dev/null
@@ -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 <bundle_internal.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <uuid.h>
+
+#include <atomic>
+#include <functional>
+#include <list>
+#include <mutex>
+
+#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<void(int, void*)>;
+using ReplyCb = std::function<void(bundle*, int, void*)>;
+
+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<ReplyInfo> FindByCallerData(void* caller_data) {
+    std::unique_lock<std::mutex> lock(mutex_);
+    for (auto& i : list_) {
+      if (i->caller_data_ == caller_data)
+        return std::unique_ptr<ReplyInfo>(new ReplyInfo(*i));
+    }
+
+    return {};
+  }
+
+  std::unique_ptr<ReplyInfo> Pop(const std::string& seq_num) {
+    if (seq_num.empty())
+      return nullptr;
+
+    std::unique_lock<std::mutex> 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<std::mutex> 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<ReplyInfo> info) {
+    if (info == nullptr)
+      return;
+
+    std::unique_lock<std::mutex> lock(mutex_);
+    list_.push_back(std::move(info));
+  }
+
+  void UpdatePid(const std::string& seq_num, int launched_pid) {
+    std::unique_lock<std::mutex> 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<std::mutex> 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<std::mutex> 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<ReplyInfo>(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<std::unique_ptr<ReplyInfo>> 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<GIOCondition> (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<ErrorInfo*>(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<int> 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<ReplyInfo>(-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<app_pkt_t, decltype(free)*> 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<ReplyInfo>(-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<ErrorInfo>(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<ReplyInfo*>(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 (file)
index 0000000..06cf826
--- /dev/null
@@ -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 (file)
index 0000000..16870f6
--- /dev/null
@@ -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 <gmock/gmock.h>
+#include <glib.h>
+#include <gio/gio.h>
+
+#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_
index 33979c1..8f19368 100644 (file)
@@ -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<SocketMock>,
     virtual public ::testing::NiceMock<OsMock>,
+    virtual public ::testing::NiceMock<GlibMock>,
     virtual public ::testing::NiceMock<DbusMock> {};
 
 }  // namespace
@@ -77,6 +79,18 @@ class LaunchWithResultTest : public TestFixture {
 
     return std::unique_ptr<app_pkt_t, decltype(free)*>(pkt, free);
   }
+
+  std::unique_ptr<app_pkt_t, decltype(free)*> MakePacket(
+      std::string str) {
+    app_pkt_t* pkt =
+        static_cast<app_pkt_t*>(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<app_pkt_t, decltype(free)*>(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<GlibMock>(), 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<SocketMock>(), 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<SocketMock>(), send(_, _, _, _))
+      .Times(1)
+      .WillOnce(Invoke([&](int fd, const void* buf, size_t n, int flags)
+          -> ssize_t {
+        const app_pkt_t* header = reinterpret_cast<const app_pkt_t*>(buf);
+        cmd = header->cmd;
+        return n;
+      }));
+  EXPECT_CALL(GetMock<SocketMock>(), 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<SocketMock>(), send(_, _, _, _))
+      .Times(1)
+      .WillOnce(Invoke([&](int fd, const void* buf, size_t n, int flags)
+          -> ssize_t {
+        const app_pkt_t* header = reinterpret_cast<const app_pkt_t*>(buf);
+        cmd = header->cmd;
+        return n;
+      }));
+  EXPECT_CALL(GetMock<SocketMock>(), 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<SocketMock>(), send(_, _, _, _))
+      .Times(1)
+      .WillOnce(Invoke([&](int fd, const void* buf, size_t n, int flags)
+          -> ssize_t {
+        const app_pkt_t* header = reinterpret_cast<const app_pkt_t*>(buf);
+        cmd = header->cmd;
+        return n;
+      }));
+  EXPECT_CALL(GetMock<SocketMock>(), 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<SocketMock>(), send(_, _, _, _))
+      .Times(2)
+      .WillOnce(Invoke([&](int fd, const void* buf, size_t n, int flags)
+          -> ssize_t {
+        const app_pkt_t* header = reinterpret_cast<const app_pkt_t*>(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<const app_pkt_t*>(buf);
+        cmd2 = header->cmd;
+        return n;
+      }));
+  EXPECT_CALL(GetMock<SocketMock>(), 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<SocketMock>(), send(_, _, _, _))
+      .Times(1);
+  EXPECT_CALL(GetMock<SocketMock>(), 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