Add new internal APIs 81/293281/9
authorHwankyu Jhun <h.jhun@samsung.com>
Tue, 23 May 2023 23:31:27 +0000 (23:31 +0000)
committerHwankyu Jhun <h.jhun@samsung.com>
Wed, 24 May 2023 06:59:37 +0000 (06:59 +0000)
Adds:
 - aul_app_get_appid_bypid_async()
 - aul_terminate_pid_async_v2()
 - aul_terminate_app_async()
 - aul_kill_pid_async()

Change-Id: I1b7eafd0044fce8cfea8dbab4ecb01e6b715509b
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
include/aul.h
src/launch.cc
src/pkginfo.cc
test/unit_tests/mock/glib_mock.cc
test/unit_tests/mock/glib_mock.h
test/unit_tests/test_launch.cc
test/unit_tests/test_pkginfo.cc
tool/aul_test/tests/aul_app_get_appid_bypid_async_test.cc [new file with mode: 0644]
tool/aul_test/tests/aul_kill_pid_async_test.cc [new file with mode: 0644]
tool/aul_test/tests/aul_terminate_app_async_test.cc [new file with mode: 0644]
tool/aul_test/tests/aul_terminate_pid_async_v2_test.cc [new file with mode: 0644]

index ea54687..d4e0ce8 100644 (file)
@@ -3137,6 +3137,101 @@ int aul_launch_worker_init(void);
  */
 void aul_launch_worker_fini(void);
 
+/**
+ * @brief Called when the application ID is delivered.
+ * @since_tizen 8.0
+ * @param[in]   result          The result
+ * @param[in]   pid             The process ID
+ * @param[in]   appid           The application ID
+ * @param[in]   user_data       The user data passed from the regitration function
+ * @remarks This function is only for App Framework internally.
+ * @see aul_app_get_appid_bypid_async()
+ */
+typedef void (*aul_appid_cb)(int result, pid_t pid, const char *appid, void *user_data);
+
+/**
+ * @brief Gets the application ID from the process ID.
+ * @since_tizen 8.0
+ * @param[in]   pid             The process ID
+ * @param[in]   callback        The callback function
+ * @param[in]   user_data       The user data to be passed to the callaback function
+ * @return      @c 0 on success,
+ *              otherwise a negative error value
+ * @retval      #AUL_R_OK       Successful
+ * @retval      #AUL_R_EINVAL   Invalid parameter
+ * @retval      #AUL_R_ENOMEM   Out of memory
+ * @retval      #AUL_R_ERROR    Internal I/O error
+ * @remarks This function is only for App Framework internally.
+ * @see aul_appid_cb()
+ */
+int aul_app_get_appid_bypid_async(pid_t pid, aul_appid_cb callback, void *user_data);
+
+/**
+ * @brief Called when the result is delivered.
+ * @since_tizen 8.0
+ * @param[in]   result          The result
+ * @param[in]   user_data       The user data passed from the regitration function
+ * @remarks This function is only for App Framework internally.
+ */
+typedef void (*aul_result_cb)(int result, void *user_data);
+
+/**
+ * @brief Sends the termination request with the process ID.
+ * @since_tizen 8.0
+ * @privilege   %http://tizen.org/privilege/appmanager.kill
+ * @privlevel   platform
+ * @param[in]   pid             The process ID
+ * @param[in]   callback        The callback function
+ * @param[in]   user_data       The user data to be passed to the callback function
+ * @return      @c 0 on success,
+ *              otherwise a negative error value
+ * @retval      #AUL_R_OK       Successful
+ * @retval      #AUL_R_EINVAL   Invalid parameter
+ * @retval      #AUL_R_ENOMEM   Out of memory
+ * @retval      #AUL_R_ERROR    Internal I/O error
+ * @remarks This function is only for App Framework internally.
+ * @see aul_result_cb()
+ */
+int aul_terminate_pid_async_v2(pid_t pid, aul_result_cb callback, void *user_data);
+
+/**
+ * @brief Sends the termination request.
+ * @since_tizen 8.0
+ * @privilege   %http://tizen.org/privilege/appmanager.kill
+ * @privlevel   platform
+ * @param[in]   appid           The application ID
+ * @param[in]   callback        The callback function
+ * @param[in]   user_data       The user data to be passed to the callback function
+ * @return      @c 0 on success,
+ *              otherwise a negative error value
+ * @retval      #AUL_R_OK       Successful
+ * @retval      #AUL_R_EINVAL   Invalid parameter
+ * @retval      #AUL_R_ENOMEM   Out of memory
+ * @retval      #AUL_R_ERROR    Internal I/O error
+ * @remarks This function is only for App Framework internally.
+ * @see aul_result_cb()
+ */
+int aul_terminate_app_async(const char *appid, aul_result_cb callback, void *user_data);
+
+/**
+ * @brief Sends the request to kill the process ID.
+ * @since_tizen 8.0
+ * @privilege   %http://tizen.org/privilege/appmanager.kill
+ * @privlevel   platform
+ * @param[in]   pid             The process ID
+ * @param[in]   callback        The callback function
+ * @param[in]   user_data       The user data to be passed to the callback function
+ * @return      @c 0 on success,
+ *              otherwise a negative error value
+ * @retval      #AUL_R_OK       Successful
+ * @retval      #AUL_R_EINVAL   Invalid parameter
+ * @retval      #AUL_R_ENOMEM   Out of memory
+ * @retval      #AUL_R_ERROR    Internal I/O error
+ * @remarks This function is only for App Framework internally.
+ * @see aul_result_cb()
+ */
+int aul_kill_pid_async(pid_t pid, aul_result_cb callback, void *user_data);
+
 #ifdef __cplusplus
         }
 #endif
index 3d05137..fffa437 100644 (file)
@@ -19,6 +19,7 @@
 #include <dirent.h>
 #include <fcntl.h>
 #include <gio/gio.h>
+#include <glib-unix.h>
 #include <glib.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -29,6 +30,7 @@
 #include <ttrace.h>
 
 #include <memory>
+#include <utility>
 
 #include "app_request.h"
 #include "app_signal.h"
@@ -46,6 +48,69 @@ namespace {
 
 constexpr const int TEP_ISMOUNT_MAX_RETRY_CNT = 20;
 
+class ResultInfo {
+ public:
+  ResultInfo(int fd, aul_result_cb callback, void* user_data)
+      : fd_(fd), callback_(callback), user_data_(user_data) {}
+
+  ResultInfo(const ResultInfo&) = delete;
+  ResultInfo& operator = (const ResultInfo&) = delete;
+
+  ~ResultInfo() {
+    if (source_ != 0)
+      g_source_remove(source_);
+
+    if (fd_ > -1)
+      close(fd_);
+  }
+
+  bool Watch() {
+    source_ = g_unix_fd_add(fd_,
+        static_cast<GIOCondition>(G_IO_IN | G_IO_HUP | G_IO_ERR),
+        FdSourceFunc, this);
+    if (source_ == 0) {
+      _E("g_unix_fd_add() is failed");
+      return false;
+    }
+
+    return true;
+  }
+
+ private:
+  void ProcessReadEvent() {
+    int res = aul_sock_recv_result_with_fd(fd_);
+    if (res < 0)
+      res = aul_error_convert(res);
+    else
+      res = AUL_R_OK;
+
+    callback_(res, user_data_);
+  }
+
+  void ProcessErrorEvent() {
+    callback_(AUL_R_ERROR, user_data_);
+  }
+
+  static gboolean FdSourceFunc(int fd, GIOCondition condition,
+      void* user_data) {
+    auto* info = static_cast<ResultInfo*>(user_data);
+    if (condition & G_IO_IN)
+      info->ProcessReadEvent();
+    else
+      info->ProcessErrorEvent();
+
+    info->source_ = 0;
+    delete info;
+    return G_SOURCE_REMOVE;
+  }
+
+ private:
+  int fd_;
+  aul_result_cb callback_;
+  void *user_data_;
+  guint source_ = 0;
+};
+
 int aul_initialized = 0;
 int aul_fd;
 void* window_object = nullptr;
@@ -715,3 +780,84 @@ extern "C" API int aul_prepare_app_defined_loader_for_uid(
   _I("loader id(%d)", ret);
   return ret;
 }
+
+extern "C" API int aul_terminate_pid_async_v2(pid_t pid,
+    aul_result_cb callback, void *user_data) {
+  if (pid < 1 || callback == nullptr) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  int fd = AppRequest(APP_TERM_BY_PID, getuid())
+      .SetAppIdAsPid(pid)
+      .SendSimply(AUL_SOCK_ASYNC);
+  if (fd < 0) {
+    _E("Failed to send request. error(%d)", fd);
+    return fd;
+  }
+
+  try {
+    auto* info = new ResultInfo(fd, callback, user_data);
+    info->Watch();
+  } catch (const std::exception& e) {
+    _E("Exception occurs. error: %s", e.what());
+    close(fd);
+    return AUL_R_ERROR;
+  }
+
+  return AUL_R_OK;
+}
+
+extern "C" API int aul_terminate_app_async(const char* appid,
+    aul_result_cb callback, void *user_data) {
+  if (appid == nullptr || callback == nullptr) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  int fd = AppRequest(APP_TERMINATE, getuid())
+      .SetAppId(appid)
+      .SendSimply(AUL_SOCK_ASYNC);
+  if (fd < 0) {
+    _E("Failed to send request. error(%d)", fd);
+    return fd;
+  }
+
+  try {
+    auto* info = new ResultInfo(fd, callback, user_data);
+    info->Watch();
+  } catch (const std::exception& e) {
+    _E("Exception occurs. error: %s", e.what());
+    close(fd);
+    return AUL_R_ERROR;
+  }
+
+  return AUL_R_OK;
+}
+
+extern "C" API int aul_kill_pid_async(pid_t pid,
+    aul_result_cb callback, void *user_data) {
+  if (pid < 1 || callback == nullptr) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  int fd = AppRequest(APP_KILL_BY_PID, getuid())
+      .SetAppIdAsPid(pid)
+      .SendSimply(AUL_SOCK_ASYNC);
+  if (fd < 0) {
+    _E("Failed to send request. error(%d)", fd);
+    return fd;
+  }
+
+  try {
+    auto* info = new ResultInfo(fd, callback, user_data);
+    info->Watch();
+  } catch (const std::exception& e) {
+    _E("Exception occurs. error: %s", e.what());
+    close(fd);
+    return AUL_R_ERROR;
+  }
+
+  return AUL_R_OK;
+}
index d1f0483..c186e0b 100644 (file)
  * limitations under the License.
  */
 
+#include <bundle_cpp.h>
+#include <bundle_internal.h>
+#include <glib-unix.h>
+#include <glib.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <bundle_cpp.h>
-#include <bundle_internal.h>
-
 #include <atomic>
-#include <string>
+#include <exception>
 #include <memory>
+#include <string>
 
 #include "app_request.h"
 #include "aul_api.h"
@@ -49,6 +51,82 @@ constexpr const char* kAppInfoKeys[] = {
 
 constexpr const char kPathAmdReady[] = "/run/.amd_ready";
 
+class ResultInfo {
+ public:
+  ResultInfo(pid_t pid, int fd, aul_appid_cb callback, void* user_data)
+      : pid_(pid), fd_(fd), callback_(callback), user_data_(user_data) {}
+
+  ResultInfo(const ResultInfo&) = delete;
+  ResultInfo& operator = (const ResultInfo&) = delete;
+
+  ~ResultInfo() {
+    if (source_ != 0)
+      g_source_remove(source_);
+
+    if (fd_ > -1)
+      close(fd_);
+  }
+
+  bool Watch() {
+    source_ = g_unix_fd_add(fd_,
+        static_cast<GIOCondition>(G_IO_IN | G_IO_HUP | G_IO_ERR),
+        FdSourceFunc, this);
+    if (source_ == 0) {
+      _E("g_unix_fd_add() is failed");
+      return false;
+    }
+
+    return true;
+  }
+
+ private:
+  void ProcessReadEvent() {
+    app_pkt_t* pkt = nullptr;
+    int ret = aul_sock_recv_reply_pkt(fd_, &pkt);
+    if (ret < 0 || pkt == nullptr) {
+      ProcessErrorEvent();
+      return;
+    }
+
+    auto pkt_auto = std::unique_ptr<app_pkt_t, decltype(std::free)*>(
+        pkt, std::free);
+    if (pkt->cmd != APP_GET_INFO_OK) {
+      ProcessErrorEvent();
+      return;
+    }
+
+    char appid[256] = { 0, };
+    snprintf(appid, sizeof(appid), "%s", pkt->data);
+    SECURE_LOGD("pid: %d, appid: %s", pid_, appid);
+    callback_(AUL_R_OK, pid_, appid, user_data_);
+  }
+
+  void ProcessErrorEvent() {
+    callback_(AUL_R_ERROR, pid_, "", user_data_);
+  }
+
+  static gboolean FdSourceFunc(int fd, GIOCondition condition,
+      gpointer user_data) {
+    auto* info = static_cast<ResultInfo*>(user_data);
+    _E("GIOCondition: %d", static_cast<int>(condition));
+    if (condition & G_IO_IN)
+      info->ProcessReadEvent();
+    else
+      info->ProcessErrorEvent();
+
+    info->source_ = 0;
+    delete info;
+    return G_SOURCE_REMOVE;
+  }
+
+ private:
+  pid_t pid_;
+  int fd_;
+  aul_appid_cb callback_;
+  void* user_data_;
+  guint source_ = 0;
+};
+
 bool IsAmdReady() {
   static std::atomic<bool> amd_ready = false;
   if (amd_ready)
@@ -632,3 +710,37 @@ extern "C" API int aul_package_pre_event_send(uid_t uid, bundle* b) {
       .With(b)
       .SendSimply();
 }
+
+extern "C" API int aul_app_get_appid_bypid_async(pid_t pid,
+    aul_appid_cb callback, void* user_data) {
+  if (pid < 1 || callback == nullptr) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  if (getpid() == pid || getpgid(getpid()) == pid) {
+    context.Initialize();
+    auto& preinit_appid = context.GetPreInitAppId();
+    if (!preinit_appid.empty()) {
+      callback(AUL_R_OK, pid, preinit_appid.c_str(), user_data);
+      return AUL_R_OK;
+    }
+  }
+
+  int fd = AppRequest(APP_GET_APPID_BYPID, getuid())
+      .SetPid(pid)
+      .SendSimply(AUL_SOCK_ASYNC);
+  if (fd < 0)
+    return AUL_R_ERROR;
+
+  try {
+    auto* result_info = new ResultInfo(pid, fd, callback, user_data);
+    result_info->Watch();
+  } catch (const std::exception& e) {
+    _E("Exception occurs. error: %s", e.what());
+    close(fd);
+    return AUL_R_ERROR;
+  }
+
+  return AUL_R_OK;
+}
index d6c20f2..3867b29 100644 (file)
@@ -29,3 +29,12 @@ extern "C" GIOChannel* g_io_channel_unix_new(gint fd) {
 
   return nullptr;
 }
+
+extern "C" gboolean g_source_remove(guint source_id) {
+  return TRUE;
+}
+
+extern "C" guint g_unix_fd_add(gint fd, GIOCondition condition,
+    GUnixFDSourceFunc func, gpointer user_data) {
+  return MOCK_HOOK_P4(GlibMock, g_unix_fd_add, fd, condition, func, user_data);
+}
index 8012e5f..6befeb9 100644 (file)
 #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 <glib-unix.h>
+#include <glib.h>
+#include <gmock/gmock.h>
 
 #include "mock/module_mock.h"
 
@@ -32,6 +33,9 @@ class GlibMock : public virtual ModuleMock {
   }
 
   MOCK_METHOD1(g_io_channel_unix_new, GIOChannel* (gint));
+  MOCK_METHOD1(g_source_remove, gboolean (guint));
+  MOCK_METHOD4(g_unix_fd_add,
+      guint (gint, GIOCondition, GUnixFDSourceFunc, gpointer));
 };
 
 #endif  // UNIT_TESTS_MOCK_GLIB_MOCK_H_
index 7875fbc..612f77e 100644 (file)
  * limitations under the License.
  */
 
-#include <stdlib.h>
+#include <bundle_cpp.h>
 #include <gtest/gtest.h>
+#include <stdlib.h>
 
-#include <bundle_cpp.h>
 #include <iostream>
 #include <memory>
 #include <aul.h>
@@ -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,7 +43,8 @@ namespace {
 
 class Mocks : virtual public ::testing::NiceMock<SocketMock>,
     virtual public ::testing::NiceMock<OsMock>,
-    virtual public ::testing::NiceMock<DbusMock> {};
+    virtual public ::testing::NiceMock<DbusMock>,
+    virtual public ::testing::NiceMock<GlibMock> {};
 
 }  // namespace
 
@@ -784,3 +786,126 @@ TEST_F(LaunchTest, aul_check_tep_mount) {
   int ret = aul_check_tep_mount("/tmp/test.tep");
   EXPECT_EQ(ret, AUL_R_OK);
 }
+
+TEST_F(LaunchTest, aul_terminate_pid_async_v2_P) {
+  int cmd = -1;
+  EXPECT_CALL(GetMock<SocketMock>(), socket(_, _, _))
+      .Times(1);
+  EXPECT_CALL(GetMock<SocketMock>(), connect(_, _, _))
+      .Times(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);
+      }));
+  EXPECT_CALL(GetMock<GlibMock>(), g_unix_fd_add(_, _, _, _))
+      .Times(1)
+      .WillOnce(Invoke([&](gint fd, GIOCondition condtion,
+          GUnixFDSourceFunc func, gpointer user_data) -> guint {
+        func(fd, G_IO_IN, user_data);
+        return 1;
+      }));
+
+  int res = -1;
+  int ret = aul_terminate_pid_async_v2(1000,
+      [](int result, void* user_data) {
+        int* res_ptr = static_cast<int*>(user_data);
+        *res_ptr = result;
+      }, &res);
+  EXPECT_EQ(ret, AUL_R_OK);
+  EXPECT_EQ(cmd, APP_TERM_BY_PID);
+  EXPECT_EQ(res, AUL_R_OK);
+}
+
+TEST_F(LaunchTest, aul_terminate_app_async_P) {
+  int cmd = -1;
+  EXPECT_CALL(GetMock<SocketMock>(), socket(_, _, _))
+      .Times(1);
+  EXPECT_CALL(GetMock<SocketMock>(), connect(_, _, _))
+      .Times(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);
+      }));
+  EXPECT_CALL(GetMock<GlibMock>(), g_unix_fd_add(_, _, _, _))
+      .Times(1)
+      .WillOnce(Invoke([&](gint fd, GIOCondition condtion,
+          GUnixFDSourceFunc func, gpointer user_data) -> guint {
+        func(fd, G_IO_IN, user_data);
+        return 1;
+      }));
+
+  int res = -1;
+  int ret = aul_terminate_app_async("test-app",
+      [](int result, void* user_data) {
+        int* res_ptr = static_cast<int*>(user_data);
+        *res_ptr = result;
+      }, &res);
+  EXPECT_EQ(ret, AUL_R_OK);
+  EXPECT_EQ(cmd, APP_TERMINATE);
+  EXPECT_EQ(res, AUL_R_OK);
+}
+
+TEST_F(LaunchTest, aul_kill_pid_async_P) {
+  int cmd = -1;
+  EXPECT_CALL(GetMock<SocketMock>(), socket(_, _, _))
+      .Times(1);
+  EXPECT_CALL(GetMock<SocketMock>(), connect(_, _, _))
+      .Times(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);
+      }));
+  EXPECT_CALL(GetMock<GlibMock>(), g_unix_fd_add(_, _, _, _))
+      .Times(1)
+      .WillOnce(Invoke([&](gint fd, GIOCondition condtion,
+          GUnixFDSourceFunc func, gpointer user_data) -> guint {
+        func(fd, G_IO_IN, user_data);
+        return 1;
+      }));
+
+  int res = -1;
+  int ret = aul_kill_pid_async(10,
+      [](int result, void* user_data) {
+        int* res_ptr = static_cast<int*>(user_data);
+        *res_ptr = result;
+      }, &res);
+  EXPECT_EQ(ret, AUL_R_OK);
+  EXPECT_EQ(cmd, APP_KILL_BY_PID);
+  EXPECT_EQ(res, AUL_R_OK);
+}
index e58ecf7..cec975f 100644 (file)
@@ -26,6 +26,7 @@
 #include <memory>
 
 #include "mock/mock_hook.h"
+#include "mock/glib_mock.h"
 #include "mock/socket_mock.h"
 #include "mock/test_fixture.h"
 #include "src/launch.h"
@@ -50,7 +51,8 @@ constexpr const char kExec[] =
     "/home/owner/apps_rw/org.tizen.helloworld/bin/helloworld";
 constexpr const char kRootPath[] = "/home/owner/apps_rw/org.tizen.helloworld";
 
-class Mocks : virtual public ::testing::NiceMock<SocketMock> {};
+class Mocks : virtual public ::testing::NiceMock<SocketMock>,
+              virtual public ::testing::NiceMock<GlibMock> {};
 
 }  // namespace
 
@@ -59,6 +61,7 @@ class PkgInfoTest : public TestFixture {
   PkgInfoTest() : TestFixture(std::make_unique<::Mocks>()) {}
 
   virtual void SetUp() {
+    loop_ = g_main_loop_new(nullptr, FALSE);
     touched_ = false;
     if (aul_is_initialized())
       return;
@@ -68,6 +71,8 @@ class PkgInfoTest : public TestFixture {
 
   virtual void TearDown() {
     aul_launch_fini();
+    g_main_loop_unref(loop_);
+    loop_ = nullptr;
   }
 
   tizen_base::Bundle MakeAppInfoBundle() {
@@ -111,7 +116,18 @@ class PkgInfoTest : public TestFixture {
     return std::shared_ptr<app_pkt_t>(pkt, free);
   }
 
+  void RunMainLoop() {
+    g_main_loop_run(loop_);
+  }
+
+  void QuitMainLoop() {
+    g_main_loop_quit(loop_);
+  }
+
   bool touched_ = false;
+
+ private:
+  GMainLoop* loop_ = nullptr;
 };
 
 TEST_F(PkgInfoTest, aul_app_get_pid_P) {
@@ -1072,3 +1088,56 @@ TEST_F(PkgInfoTest, aul_get_default_app_N) {
   ret = aul_get_default_app(b.GetHandle(), nullptr);
   EXPECT_EQ(ret, AUL_R_EINVAL);
 }
+
+TEST_F(PkgInfoTest, aul_app_get_appid_bypid_async_P) {
+  int cmd = -1;
+  int opt = 0;
+  bundle* kb = nullptr;
+  auto pkt = MakePacket(kAppId);
+  EXPECT_NE(pkt, nullptr);
+
+  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* app_pkt = reinterpret_cast<const app_pkt_t*>(buf);
+        cmd = app_pkt->cmd;
+        opt = app_pkt->opt;
+        kb = bundle_decode(app_pkt->data, app_pkt->len);
+        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);
+        return n;
+      }))
+      .WillOnce(Invoke([&](int fd, void* buf, size_t n, int flags) -> ssize_t {
+        memcpy(buf, pkt->data, n);
+        return n;
+      }));
+  EXPECT_CALL(GetMock<GlibMock>(), g_unix_fd_add(_, _, _, _))
+      .Times(1)
+      .WillOnce(Invoke([&](gint fd, GIOCondition condtion,
+          GUnixFDSourceFunc func, gpointer user_data) -> guint {
+        func(fd, G_IO_IN, user_data);
+        return 1;
+      }));
+
+  char* buf = nullptr;
+  int ret = aul_app_get_appid_bypid_async(100,
+      [](int result, pid_t pid, const char* appid, void *user_data) {
+        auto** buffer = static_cast<char**>(user_data);
+        *buffer = strdup(appid);
+      }, &buf);
+
+  std::unique_ptr<char, decltype(free)*> buf_auto(buf, free);
+  EXPECT_NE(kb, nullptr);
+  tizen_base::Bundle b(kb, false, true);
+
+  EXPECT_EQ(ret, AUL_R_OK);
+  EXPECT_EQ(std::string(buf), kAppId);
+  EXPECT_EQ(cmd, APP_GET_APPID_BYPID);
+  EXPECT_EQ(opt, (AUL_SOCK_BUNDLE | AUL_SOCK_ASYNC));
+  EXPECT_EQ(b.GetString(AUL_K_PID), std::to_string(100));
+}
diff --git a/tool/aul_test/tests/aul_app_get_appid_bypid_async_test.cc b/tool/aul_test/tests/aul_app_get_appid_bypid_async_test.cc
new file mode 100644 (file)
index 0000000..6a0b0fd
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2023 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 <stdlib.h>
+
+#include "include/aul.h"
+
+#include "aul_test.hh"
+#include "log_private.hh"
+
+namespace aul_test {
+
+class AulAppGetAppIdBypidAsyncTest : public AulTest {
+ public:
+  AulAppGetAppIdBypidAsyncTest()
+      : AulTest("get_appid_bypid_async", "aul_app_get_appid_bypid_async",
+            "get_appid_bypid_async <pid>", false) {}
+
+  virtual ~AulAppGetAppIdBypidAsyncTest() {}
+
+  void SetUp() override {}
+
+  void TearDown() override {}
+
+  int Test(int argc, char** argv) override {
+    if (argc < 3) {
+      Usage();
+      return -1;
+    }
+
+    _D("[aul_app_get_appid_bypid_async test] %s", argv[2]);
+    return aul_app_get_appid_bypid_async(atoi(argv[2]), AulAppIdCb,
+        this);
+  }
+
+ private:
+  static void AulAppIdCb(int result, pid_t pid, const char* appid,
+      void* user_data) {
+    _D("Result: %d, appid: %s", result, appid);
+  }
+};
+
+AUL_TEST_REGISTER(AulAppGetAppIdBypidAsyncTest, get_appid_bypid_async_test);
+
+}  // namespace aul_test
diff --git a/tool/aul_test/tests/aul_kill_pid_async_test.cc b/tool/aul_test/tests/aul_kill_pid_async_test.cc
new file mode 100644 (file)
index 0000000..5528cf7
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2023 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 <stdlib.h>
+
+#include "include/aul.h"
+
+#include "aul_test.hh"
+#include "log_private.hh"
+
+namespace aul_test {
+
+class AulKillPidAsyncTest : public AulTest {
+ public:
+  AulKillPidAsyncTest()
+      : AulTest("kill_pid_async", "aul_kill_pid_async",
+            "kill_pid_async <pid>", false) {}
+
+  virtual ~AulKillPidAsyncTest() {}
+
+  void SetUp() override {}
+
+  void TearDown() override {}
+
+  int Test(int argc, char** argv) override {
+    if (argc < 3) {
+      Usage();
+      return -1;
+    }
+
+    _D("[aul_kill_pid_async test] %s", argv[2]);
+    return aul_kill_pid_async(atoi(argv[2]), AulResultCb, this);
+  }
+
+ private:
+  static void AulResultCb(int result, void* user_data) {
+    _D("Result: %d", result);
+  }
+};
+
+AUL_TEST_REGISTER(AulKillPidAsyncTest, kill_pid_async_test);
+
+}  // namespace aul_test
diff --git a/tool/aul_test/tests/aul_terminate_app_async_test.cc b/tool/aul_test/tests/aul_terminate_app_async_test.cc
new file mode 100644 (file)
index 0000000..9dbca04
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2023 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 <stdlib.h>
+
+#include "include/aul.h"
+
+#include "aul_test.hh"
+#include "log_private.hh"
+
+namespace aul_test {
+
+class AulTerminateAppAsyncTest : public AulTest {
+ public:
+  AulTerminateAppAsyncTest()
+      : AulTest("terminate_app_async", "aul_terminate_app_async",
+            "terminate_app_async <appid>", false) {}
+
+  virtual ~AulTerminateAppAsyncTest() {}
+
+  void SetUp() override {}
+
+  void TearDown() override {}
+
+  int Test(int argc, char** argv) override {
+    if (argc < 3) {
+      Usage();
+      return -1;
+    }
+
+    _D("[aul_terminate_app_async test] %s", argv[2]);
+    return aul_terminate_app_async(argv[2], AulResultCb, this);
+  }
+
+ private:
+  static void AulResultCb(int result, void* user_data) {
+    _D("Result: %d", result);
+  }
+};
+
+AUL_TEST_REGISTER(AulTerminateAppAsyncTest, terminate_app_async_test);
+
+}  // namespace aul_test
diff --git a/tool/aul_test/tests/aul_terminate_pid_async_v2_test.cc b/tool/aul_test/tests/aul_terminate_pid_async_v2_test.cc
new file mode 100644 (file)
index 0000000..df39916
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2023 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 <stdlib.h>
+
+#include "include/aul.h"
+
+#include "aul_test.hh"
+#include "log_private.hh"
+
+namespace aul_test {
+
+class AulTerminatePidAsyncV2Test : public AulTest {
+ public:
+  AulTerminatePidAsyncV2Test()
+      : AulTest("terminate_pid_async_v2", "aul_terminate_pid_async_v2",
+            "terminate_pid_async_v2 <pid>", false) {}
+
+  virtual ~AulTerminatePidAsyncV2Test() {}
+
+  void SetUp() override {}
+
+  void TearDown() override {}
+
+  int Test(int argc, char** argv) override {
+    if (argc < 3) {
+      Usage();
+      return -1;
+    }
+
+    _D("[aul_terminate_pid_async_v2 test] %s", argv[2]);
+    return aul_terminate_pid_async_v2(atoi(argv[2]), AulResultCb, this);
+  }
+
+ private:
+  static void AulResultCb(int result, void* user_data) {
+    _D("Result: %d", result);
+  }
+};
+
+AUL_TEST_REGISTER(AulTerminatePidAsyncV2Test, terminate_pid_async_v2_test);
+
+}  // namespace aul_test