Refactor status API 27/283127/3
authorHwankyu Jhun <h.jhun@samsung.com>
Tue, 18 Oct 2022 10:34:23 +0000 (10:34 +0000)
committerHwankyu Jhun <h.jhun@samsung.com>
Thu, 20 Oct 2022 00:52:31 +0000 (00:52 +0000)
The status API is implmented using C++ language.

Change-Id: Ia1930ea1565b7710e266a224f02826486df54bb6
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
include/aul.h
src/status.c [deleted file]
src/status.cc [new file with mode: 0644]

index b3bf3fb..e031f1a 100644 (file)
@@ -1817,6 +1817,19 @@ int aul_app_get_status(const char *appid);
 int aul_app_get_status_for_uid(const char *appid, uid_t uid);
 
 /**
+ * @brief Called when the status is changed.
+ * @remarks If @c is a negative error value,
+ *          the registered callback function will be deregistered.
+ * @param[in]   status          The status
+ * @param[in]   user_data       The user data passed from the registration function
+ * @return @c 0 to continue with the next iteration of the loop,
+ *         otherwise a negative error value to break out of the loop
+ * @see aul_add_status_local_cb()
+ * @see aul_remove_status_local_cb();
+ */
+typedef int (*aul_status_local_cb)(int status, void *user_data);
+
+/**
  * @par Description
  *     This API sets callback function that on application status changed.
  * @par Purpose:
@@ -1824,8 +1837,8 @@ int aul_app_get_status_for_uid(const char *appid, uid_t uid);
  *     the caller process. In general, a library that required to release resource on
  *     application's status may use this API.
  *
- * @param[in]  func    callback function
- * @param[in]  data    user data
+ * @param[in]  callback        callback function
+ * @param[in]  data            user data
  * @return     0 if success, negative value if fail
  * @retval     AUL_R_OK        - success
  * @retval     AUL_R_ERROR     - general error
@@ -1852,7 +1865,7 @@ int aul_app_get_status_for_uid(const char *appid, uid_t uid);
  *     This API is only available in User Session.
  *
  */
-int aul_add_status_local_cb(int (*func) (int, void *), void *data);
+int aul_add_status_local_cb(aul_status_local_cb callback, void *data);
 
 /**
  * @par Description
@@ -1861,8 +1874,8 @@ int aul_add_status_local_cb(int (*func) (int, void *), void *data);
  *     This API's purpose is to remove callback that added by
  *     aul_add_status_local_cb.
  *
- * @param[in]  func    callback function
- * @param[in]  data    user data
+ * @param[in]  callback        callback function
+ * @param[in]  data            user data
  * @return     0 if success, negative value if fail
  * @retval     AUL_R_OK        - success
  * @retval     AUL_R_ERROR     - general error
@@ -1896,7 +1909,7 @@ int aul_add_status_local_cb(int (*func) (int, void *), void *data);
  *     This API is only available in User Session.
  *
  */
-int aul_remove_status_local_cb(int (*func) (int, void *), void *data);
+int aul_remove_status_local_cb(aul_status_local_cb callback, void *data);
 
 /*
  * This API is only for appfw internally.
diff --git a/src/status.c b/src/status.c
deleted file mode 100644 (file)
index a59985b..0000000
+++ /dev/null
@@ -1,439 +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 <aul.h>
-#include <bundle.h>
-#include <bundle_internal.h>
-
-#include "aul_util.h"
-#include "aul_sock.h"
-#include "aul_api.h"
-#include "launch.h"
-#include "aul_app_com.h"
-#include "aul_error.h"
-
-typedef struct _app_status_cb_info_t {
-       int (*handler)(int status, void *data);
-       void *data;
-} app_status_cb_info_t;
-
-struct status_listen_s {
-       aul_app_com_connection_h conn;
-       app_status_cb callback;
-       void *user_data;
-};
-
-static int app_status = STATUS_LAUNCHING;
-static GList *app_status_cb_list;
-
-API int aul_status_update(int status)
-{
-       int ret;
-       app_status_cb_info_t *cb;
-       GList *iter;
-
-       if (app_status == status)
-               return 0;
-
-       app_status = status;
-
-       ret = aul_sock_send_raw(AUL_UTIL_PID, getuid(), APP_STATUS_UPDATE,
-               (unsigned char *)&status, sizeof(status), AUL_SOCK_NOREPLY);
-
-       if (!ret) {
-               iter = g_list_first(app_status_cb_list);
-               while (iter) {
-                       cb = (app_status_cb_info_t *)iter->data;
-                       iter = g_list_next(iter);
-                       if (cb && cb->handler) {
-                               if (cb->handler(app_status, cb->data) < 0) {
-                                       app_status_cb_list = g_list_remove(
-                                                       app_status_cb_list, cb);
-                                       free(cb);
-                               }
-                       }
-               }
-       }
-
-       return ret;
-}
-
-API int aul_app_get_status_bypid(int pid)
-{
-       return aul_app_get_status_bypid_for_uid(pid, getuid());
-}
-
-API int aul_app_get_status_bypid_for_uid(int pid, uid_t uid)
-{
-       int ret;
-       char buf[MAX_PID_STR_BUFSZ];
-       bundle *b;
-
-       if (pid == getpid())
-               return app_status;
-
-       b = bundle_create();
-       if (b == NULL) {
-               _E("out of memory");
-               return AUL_R_ERROR;
-       }
-
-       snprintf(buf, sizeof(buf), "%d", pid);
-       bundle_add(b, AUL_K_PID, buf);
-       snprintf(buf, sizeof(buf), "%d", uid);
-       bundle_add(b, AUL_K_TARGET_UID, buf);
-
-       ret = aul_sock_send_bundle(AUL_UTIL_PID, uid, APP_GET_STATUS,
-                       b, AUL_SOCK_NONE);
-       bundle_free(b);
-
-       return ret;
-}
-
-API int aul_app_get_status(const char *appid)
-{
-       return aul_app_get_status_for_uid(appid, getuid());
-}
-
-API int aul_app_get_status_for_uid(const char *appid, uid_t uid)
-{
-       int ret;
-       bundle *kb;
-       char buf[MAX_PID_STR_BUFSZ];
-
-       if (appid == NULL)
-               return AUL_R_EINVAL;
-
-       kb = bundle_create();
-       if (kb == NULL) {
-               _E("out of memory");
-               return AUL_R_ERROR;
-       }
-
-       snprintf(buf, sizeof(buf), "%d", uid);
-       bundle_add(kb, AUL_K_APPID, appid);
-       bundle_add(kb, AUL_K_TARGET_UID, buf);
-       ret = app_send_cmd_for_uid(AUL_UTIL_PID, uid,
-                       APP_GET_STATUS_BY_APPID, kb);
-       bundle_free(kb);
-
-       return ret;
-}
-
-API int aul_add_status_local_cb(int (*func)(int status, void *data), void *data)
-{
-       app_status_cb_info_t *cb;
-       GList *iter;
-
-       if (func == NULL)
-               return -1;
-
-       iter = g_list_first(app_status_cb_list);
-       while (iter) {
-               cb = (app_status_cb_info_t *)iter->data;
-               if (cb && cb->handler == func && cb->data == data) {
-                       _D("Already exists");
-                       return 0;
-               }
-
-               iter = g_list_next(iter);
-       }
-
-       cb = (app_status_cb_info_t *)malloc(sizeof(app_status_cb_info_t));
-       if (cb == NULL) {
-               _E("out of memory");
-               return -1;
-       }
-
-       cb->handler = func;
-       cb->data = data;
-
-       app_status_cb_list = g_list_append(app_status_cb_list, cb);
-
-       return 0;
-}
-
-API int aul_remove_status_local_cb(int (*func)(int status, void *data), void *data)
-{
-       app_status_cb_info_t *cb;
-       GList *iter;
-
-       iter = g_list_first(app_status_cb_list);
-       while (iter) {
-               cb = (app_status_cb_info_t *)iter->data;
-               iter = g_list_next(iter);
-               if (cb && cb->handler == func && cb->data == data) {
-                       app_status_cb_list = g_list_remove(app_status_cb_list, cb);
-                       free(cb);
-                       return 0;
-               }
-       }
-
-       return -1;
-}
-
-API int aul_invoke_status_local_cb(int status)
-{
-       app_status_cb_info_t *cb;
-       GList *iter;
-
-       iter = g_list_first(app_status_cb_list);
-       while (iter) {
-               cb = (app_status_cb_info_t *)iter->data;
-               iter = g_list_next(iter);
-               if (cb && cb->handler) {
-                       if (cb->handler(status, cb->data) < 0) {
-                               app_status_cb_list = g_list_remove(
-                                               app_status_cb_list, cb);
-                               free(cb);
-                       }
-               }
-       }
-
-       return 0;
-}
-
-API int aul_set_process_group(int owner_pid, int child_pid)
-{
-       int ret = -1;
-       bundle *kb = NULL;
-       char pid_buf[MAX_PID_STR_BUFSZ] = {0,};
-
-       kb = bundle_create();
-
-       if (kb == NULL)
-               return -1;
-
-       snprintf(pid_buf, MAX_PID_STR_BUFSZ, "%d", owner_pid);
-       bundle_add(kb, AUL_K_OWNER_PID, pid_buf);
-       snprintf(pid_buf, MAX_PID_STR_BUFSZ, "%d", child_pid);
-       bundle_add(kb, AUL_K_CHILD_PID, pid_buf);
-       ret = app_send_cmd(AUL_UTIL_PID, APP_SET_PROCESS_GROUP, kb);
-       bundle_free(kb);
-
-       return ret;
-}
-
-static int __app_status_event_cb(const char *endpoint, aul_app_com_result_e res,
-               bundle *envelope, void *user_data)
-{
-       struct status_listen_s *listen = (struct status_listen_s *)user_data;
-       aul_app_info app_info = { 0, };
-       const char *val;
-       int context_status;
-
-       if (listen == NULL) {
-               _E("Critical error");
-               return -1;
-       }
-
-       bundle_get_str(envelope, AUL_K_APPID, &app_info.appid);
-       if (app_info.appid == NULL) {
-               _E("Failed to get application id");
-               return -1;
-       }
-
-       bundle_get_str(envelope, AUL_K_PKGID, &app_info.pkgid);
-       if (app_info.pkgid == NULL) {
-               _E("Failed to get package id");
-               return -1;
-       }
-
-       bundle_get_str(envelope, AUL_K_EXEC, &app_info.app_path);
-       if (app_info.app_path == NULL) {
-               _E("Failed to get app path");
-               return -1;
-       }
-
-       bundle_get_str(envelope, AUL_K_INSTANCE_ID, &app_info.instance_id);
-
-       val = bundle_get_val(envelope, AUL_K_PID);
-       if (val == NULL) {
-               _E("Failed to get pid");
-               return -1;
-       }
-       app_info.pid = atoi(val);
-
-       val = bundle_get_val(envelope, AUL_K_STATUS);
-       if (val == NULL) {
-               _E("Failed to get status");
-               return -1;
-       }
-       app_info.status = atoi(val);
-
-       val = bundle_get_val(envelope, AUL_K_IS_SUBAPP);
-       if (val == NULL) {
-               _E("Failed to get is_subapp");
-               return -1;
-       }
-       app_info.is_sub_app = atoi(val);
-
-       val = bundle_get_val(envelope, "__CONTEXT_STATUS__");
-       if (val == NULL) {
-               _E("Failed to get context status");
-               return -1;
-       }
-       context_status = atoi(val);
-
-       listen->callback(&app_info, context_status, listen->user_data);
-
-       return 0;
-}
-
-API int aul_listen_app_status_for_uid(const char *appid, app_status_cb callback,
-               void *data, status_listen_h *handle, uid_t uid)
-{
-       struct status_listen_s *listen;
-       char endpoint[128];
-
-       if (appid == NULL || callback == NULL || handle == NULL) {
-               _E("Invalid parameter");
-               return AUL_R_EINVAL;
-       }
-
-       listen = calloc(1, sizeof(struct status_listen_s));
-       if (listen == NULL) {
-               _E("Out of memory");
-               return AUL_R_ERROR;
-       }
-
-       if (uid < REGULAR_UID_MIN) {
-               snprintf(endpoint, sizeof(endpoint),
-                               "app_status_event:%s", appid);
-       } else {
-               snprintf(endpoint, sizeof(endpoint),
-                               "app_status_event:%s:%d", appid, uid);
-       }
-
-       aul_app_com_create(endpoint, NULL, __app_status_event_cb,
-                       listen, &listen->conn);
-       if (listen->conn == NULL) {
-               _E("Failed to create app com");
-               free(listen);
-               return AUL_R_ERROR;
-       }
-
-       listen->callback = callback;
-       listen->user_data = data;
-
-       *handle = listen;
-
-       return AUL_R_OK;
-}
-
-API int aul_listen_app_status(const char *appid, app_status_cb callback,
-               void *data, status_listen_h *handle)
-{
-       return aul_listen_app_status_for_uid(appid, callback, data, handle,
-                       getuid());
-}
-
-API int aul_ignore_app_status(status_listen_h handle)
-{
-       if (handle == NULL)
-               return AUL_R_EINVAL;
-
-       if (handle->conn)
-               aul_app_com_leave(handle->conn);
-       free(handle);
-
-       return AUL_R_OK;
-}
-
-API int aul_notify_exit(void)
-{
-       return aul_sock_send_raw(AUL_UTIL_PID, getuid(),
-                       APP_NOTIFY_EXIT, NULL, 0, AUL_SOCK_NOREPLY);
-}
-
-API int aul_notify_start(void)
-{
-       int r;
-
-       r = aul_sock_send_raw(AUL_UTIL_PID, getuid(),
-                       APP_NOTIFY_START, NULL, 0, AUL_SOCK_NOREPLY);
-       return r;
-}
-
-API const char *aul_app_status_convert_to_string(int status)
-{
-       switch (status) {
-       case STATUS_LAUNCHING:
-               return "STATUS_LAUNCHING";
-       case STATUS_CREATED:
-               return "STATUS_CREATED";
-       case STATUS_FOCUS:
-               return "STATUS_FOCUS";
-       case STATUS_VISIBLE:
-               return "STATUS_VISIBLE";
-       case STATUS_BG:
-               return "STATUS_BG";
-       case STATUS_DYING:
-               return "STATUS_DYING";
-       case STATUS_HOME:
-               return "STATUS_HOME";
-       case STATUS_NORESTART:
-               return "STATUS_NORESTART";
-       case STATUS_SERVICE:
-               return "STATUS_SERVICE";
-       case STATUS_TERMINATE:
-               return "STATUS_TERMINATE";
-       default:
-               return "Unknown status";
-       }
-}
-
-API int aul_status_update_v2(int status)
-{
-       char buf[12];
-       bundle *b;
-       int ret;
-
-       if (status < 0) {
-               _E("Invalid parameter");
-               return AUL_R_EINVAL;
-       }
-
-       if (app_status == status)
-               return AUL_R_OK;
-
-       app_status = status;
-
-       b = bundle_create();
-       if (!b) {
-               _E("Out of memory");
-               return AUL_R_ENOMEM;
-       }
-
-       snprintf(buf, sizeof(buf), "%d", status);
-       bundle_add(b, AUL_K_STATUS, buf);
-
-       ret = aul_sock_send_bundle(AUL_UTIL_PID, getuid(), APP_STATUS_UPDATE_V2,
-                       b, AUL_SOCK_NONE);
-       bundle_free(b);
-       if (ret != 0) {
-               _E("Failed to update app status. error(%d)", ret);
-               return aul_error_convert(ret);
-       } else {
-               aul_invoke_status_local_cb(status);
-       }
-
-       return AUL_R_OK;
-}
diff --git a/src/status.cc b/src/status.cc
new file mode 100644 (file)
index 0000000..9b206f4
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2000 - 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/aul.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <bundle_cpp.h>
+
+#include <list>
+#include <memory>
+#include <mutex>
+
+#include "aul_api.h"
+#include "aul_util.h"
+#include "include/aul_app_com.h"
+#include "include/aul_error.h"
+#include "include/aul_sock.h"
+#include "launch.h"
+
+#include "app_request.h"
+#include "aul/common/exception.hh"
+
+using namespace aul::internal;
+
+struct status_listen_s {
+  void* dummy;
+};
+
+namespace {
+using namespace aul;
+
+class AppStatusEvent {
+ public:
+  AppStatusEvent(std::string appid, uid_t uid, app_status_cb cb,
+      void* user_data)
+      : appid_(std::move(appid)),
+        uid_(uid),
+        cb_(cb),
+        user_data_(user_data) {
+    std::string endpoint = "app_status_event:" + appid_;
+    if (uid_ < REGULAR_UID_MIN)
+      endpoint += ":" + std::to_string(uid_);
+
+    int ret = aul_app_com_create(endpoint.c_str(), nullptr, OnAppComCb, this,
+        &connection_);
+    if (ret != AUL_R_OK) {
+      _E("aul_app_com_create() is failed. endpoint(%s), error(%d)",
+          endpoint.c_str(), ret);
+      THROW(ret);
+    }
+  }
+
+  ~AppStatusEvent() {
+    if (connection_ != nullptr)
+      aul_app_com_leave(connection_);
+  }
+
+ private:
+  static int OnAppComCb(const char* endpoint, aul_app_com_result_e res,
+      bundle* envelope, void* user_data) {
+    tizen_base::Bundle b(envelope);
+    aul_app_info app_info = { 0, };
+    app_info.appid = const_cast<char*>(b.GetString(AUL_K_APPID).c_str());
+    app_info.pkgid = const_cast<char*>(b.GetString(AUL_K_PKGID).c_str());
+    app_info.app_path = const_cast<char*>(b.GetString(AUL_K_EXEC).c_str());
+    app_info.instance_id = const_cast<char*>(
+        b.GetString(AUL_K_INSTANCE_ID).c_str());
+    app_info.pid = std::stoi(b.GetString(AUL_K_PID));
+    app_info.status = std::stoi(b.GetString(AUL_K_STATUS));
+    app_info.is_sub_app = std::stoi(b.GetString(AUL_K_IS_SUBAPP));
+    int context_status = std::stoi(b.GetString("__CONTEXT_STATUS__"));
+
+    auto* event = static_cast<AppStatusEvent*>(user_data);
+    event->cb_(&app_info, context_status, event->user_data_);
+    return 0;
+  }
+
+ private:
+  std::string appid_;
+  uid_t uid_;
+  app_status_cb cb_;
+  void* user_data_;
+  aul_app_com_connection_h connection_ = nullptr;
+};
+
+class StatusLocalCb {
+ public:
+  StatusLocalCb(aul_status_local_cb cb, void* user_data)
+      : cb_(cb), user_data_(user_data) {
+  }
+
+  aul_status_local_cb GetCb() const {
+    return cb_;
+  }
+
+  void* GetUserData() const {
+    return user_data_;
+  }
+
+  int Invoke(int status) {
+    if (cb_ != nullptr)
+      return cb_(status, user_data_);
+
+    return 0;
+  }
+
+ private:
+  aul_status_local_cb cb_;
+  void* user_data_;
+};
+
+class Context {
+ public:
+  Context() = default;
+
+  int GetStatus() const {
+    return status_;
+  }
+
+  void SetStatus(int status) {
+    status_ = status;
+  }
+
+  void AddLocalCb(aul_status_local_cb cb, void* user_data) {
+    std::lock_guard<std::recursive_mutex> lock(mutex_);
+    cbs_.emplace_back(new StatusLocalCb(cb, user_data));
+  }
+
+  std::size_t RemoveLocalCb(aul_status_local_cb cb, void* user_data) {
+    std::lock_guard<std::recursive_mutex> lock(mutex_);
+    auto count = cbs_.size();
+    cbs_.remove_if([&](const std::unique_ptr<StatusLocalCb>& local_cb) {
+          return local_cb->GetCb() == cb &&
+              local_cb->GetUserData() == user_data;
+        });
+    return count - cbs_.size();
+  }
+
+  void InvokeLocalCb(int status) {
+    std::lock_guard<std::recursive_mutex> lock(mutex_);
+    auto iter = cbs_.begin();
+    while (iter != cbs_.end()) {
+      if ((*iter)->Invoke(status) < 0)
+        iter = cbs_.erase(iter);
+      else
+        iter++;
+    }
+  }
+
+ private:
+  int status_ = STATUS_LAUNCHING;
+  std::list<std::unique_ptr<StatusLocalCb>> cbs_;
+  std::recursive_mutex mutex_;
+};
+
+Context context;
+
+}  // namespace
+
+extern "C" API int aul_status_update(int status) {
+  if (status < STATUS_LAUNCHING || status > STATUS_TERMINATE) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  if (context.GetStatus() == status)
+    return AUL_R_OK;
+
+  context.SetStatus(status);
+
+  int ret = aul_sock_send_raw(AUL_UTIL_PID, getuid(), APP_STATUS_UPDATE,
+      reinterpret_cast<unsigned char*>(&status), sizeof(status),
+      AUL_SOCK_NOREPLY);
+  if (ret == 0)
+    context.InvokeLocalCb(status);
+  else
+    ret = aul_error_convert(ret);
+
+  return ret;
+}
+
+extern "C" API int aul_app_get_status_bypid(int pid) {
+  return aul_app_get_status_bypid_for_uid(pid, getuid());
+}
+
+extern "C" API int aul_app_get_status_bypid_for_uid(int pid, uid_t uid) {
+  if (pid < 0) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  if (pid == getpid())
+    return context.GetStatus();
+
+  return AppRequest(APP_GET_STATUS, uid)
+      .SetPid(pid)
+      .SendSimply();
+}
+
+extern "C" API int aul_app_get_status(const char* appid) {
+  return aul_app_get_status_for_uid(appid, getuid());
+}
+
+extern "C" API int aul_app_get_status_for_uid(const char* appid, uid_t uid) {
+  if (appid == nullptr) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  return AppRequest(APP_GET_STATUS_BY_APPID, uid)
+      .SetAppId(appid)
+      .SendSimply();
+}
+
+extern "C" API int aul_add_status_local_cb(aul_status_local_cb callback,
+    void* user_data) {
+  if (callback == nullptr) {
+    _E("Invalid parameter");
+    return AUL_R_ERROR;
+  }
+
+  context.RemoveLocalCb(callback, user_data);
+  context.AddLocalCb(callback, user_data);
+  return AUL_R_OK;
+}
+
+extern "C" API int aul_remove_status_local_cb(aul_status_local_cb callback,
+    void* user_data) {
+  if (callback == nullptr) {
+    _E("Invalid parameter");
+    return AUL_R_ERROR;
+  }
+
+  if (context.RemoveLocalCb(callback, user_data) > 0)
+    return AUL_R_OK;
+
+  return AUL_R_EINVAL;
+}
+
+extern "C" API int aul_invoke_status_local_cb(int status) {
+  if (status < STATUS_LAUNCHING || status > STATUS_TERMINATE) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  context.InvokeLocalCb(status);
+  return AUL_R_OK;
+}
+
+extern "C" API int aul_set_process_group(int owner_pid, int child_pid) {
+  if (owner_pid < 1 || child_pid < 1) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  tizen_base::Bundle b {
+    { AUL_K_OWNER_PID, std::to_string(owner_pid) },
+    { AUL_K_CHILD_PID, std::to_string(child_pid) }
+  };
+
+  return AppRequest(APP_SET_PROCESS_GROUP, getuid())
+      .With(std::move(b))
+      .SendSimply();
+}
+
+extern "C" API int aul_listen_app_status(const char* appid,
+    app_status_cb callback, void* user_data, status_listen_h* handle) {
+  return aul_listen_app_status_for_uid(appid, callback, user_data, handle,
+      getuid());
+}
+
+extern "C" API int aul_listen_app_status_for_uid(const char* appid,
+    app_status_cb callback, void* user_data, status_listen_h* handle,
+    uid_t uid) {
+  if (appid == nullptr || callback == nullptr || handle == nullptr) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  try {
+    auto* event = new (std::nothrow) AppStatusEvent(
+        appid, uid, callback, user_data);
+    if (event == nullptr) {
+      _E("Out of memory");
+      return AUL_R_ENOMEM;
+    }
+
+    *handle = reinterpret_cast<status_listen_h>(event);
+  } catch (const Exception& e) {
+    _E("Exception occurs. error(%s)", e.what());
+    return e.GetErrorCode();
+  }
+
+  return AUL_R_OK;
+}
+
+extern "C" API int aul_ignore_app_status(status_listen_h handle) {
+  if (handle == nullptr) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  auto* event = reinterpret_cast<AppStatusEvent*>(handle);
+  delete event;
+  return AUL_R_OK;
+}
+
+extern "C" API int aul_notify_exit(void) {
+  return AppRequest(APP_NOTIFY_EXIT, getuid())
+      .SendCmdOnly(AUL_SOCK_NOREPLY);
+}
+
+extern "C" API int aul_notify_start(void) {
+  return AppRequest(APP_NOTIFY_START, getuid())
+      .SendCmdOnly(AUL_SOCK_NOREPLY);
+}
+
+extern "C" API const char* aul_app_status_convert_to_string(int status) {
+  switch (status) {
+    case STATUS_LAUNCHING:
+      return "STATUS_LAUNCHING";
+    case STATUS_CREATED:
+      return "STATUS_CREATED";
+    case STATUS_FOCUS:
+      return "STATUS_FOCUS";
+    case STATUS_VISIBLE:
+      return "STATUS_VISIBLE";
+    case STATUS_BG:
+      return "STATUS_BG";
+    case STATUS_DYING:
+      return "STATUS_DYING";
+    case STATUS_HOME:
+      return "STATUS_HOME";
+    case STATUS_NORESTART:
+      return "STATUS_NORESTART";
+    case STATUS_SERVICE:
+      return "STATUS_SERVICE";
+    case STATUS_TERMINATE:
+      return "STATUS_TERMINATE";
+    default:
+      return "Unknown status";
+  }
+}
+
+extern "C" API int aul_status_update_v2(int status) {
+  if (status < STATUS_LAUNCHING || status > STATUS_TERMINATE) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  if (context.GetStatus() == status)
+    return AUL_R_OK;
+
+  context.SetStatus(status);
+
+  tizen_base::Bundle b { { AUL_K_STATUS, std::to_string(status) } };
+  int ret = AppRequest(APP_STATUS_UPDATE_V2, getuid())
+      .With(std::move(b))
+      .SendSimply();
+  if (ret != 0) {
+    _E("Failed to update app status. error(%d)", ret);
+    return ret;
+  }
+
+  context.InvokeLocalCb(status);
+  return AUL_R_OK;
+}