Refactor app signal 40/274540/3
authorHwankyu Jhun <h.jhun@samsung.com>
Mon, 2 May 2022 05:05:46 +0000 (14:05 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Thu, 12 May 2022 08:07:05 +0000 (17:07 +0900)
The app_signal is implmeneted using C++. Locking mutex is added for
thread safe issue.

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

index 4026fe6..eef8280 100644 (file)
@@ -1555,112 +1555,147 @@ int aul_create_result_bundle(bundle *inb, bundle **outb);
 int aul_send_service_result(bundle *b);
 
 /**
- * @par Description:
- *     This API sets callback fuction that will be called when applications die.
- * @par Purpose:
- *     This API's purpose is to listen the application dead event.
- *     In general, task manager Application need this API.
+ * @brief Called when an application is terminated.
+ * @details This function is called when an application is terminated, after you register this callback using aul_listen_app_dead_signal().
+ * @param[in]   pid             The process ID
+ * @param[in]   user_data       The user data passed from the registeration function
  *
- * @param[in]  func            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
+ * @see aul_listen_app_dead_signal()
+ */
+typedef int (*aul_app_dead_event_cb)(int pid, void *user_data);
+
+/**
+ * @breif Registers a callback function to be invoked when the application is terminated.
+ * @remarks If the callback function is nullptr, the registered event will be deregistered.
+ * @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_ERROR    Internal I/O error
+ * @see aul_app_dead_event_cb()
+ *
+ * @remarks This function is only available for App Framework internally.
  *
- * @see
- *     aul_listen_app_launch_signal
  * @code
  * #include <aul.h>
  *
- * int app_dead_handler(int pid, void *data)
+ * static int app_dead_event_cb(int pid, void *user_data)
  * {
- *     printf("===> %s : %d\n", __FUNCTION__, pid);
- *     return 0;
+ *     dlog_print(DLOG_INFO, LOG_TAG, "application(%s) is terminated", pid);
+ *     return 0;
  * }
  *
- * void dead_listen()
+ * int listen_app_dead_signal(void)
  * {
- *     aul_listen_app_dead_signal(app_dead_handler, NULL);
- * }
+ *     int ret;
  *
- * @endcode
- * @remark
- *     This API is only available in User Session.
+ *     ret = aul_listen_app_dead_signal(app_dead_event_cb, NULL);
+ *     if (ret != AUL_R_OK) {
+ *         dlog_print(DLOG_ERROR, LOG_TAG, "aul_listen_app_dead_signal() is failed. error(%d)", ret);
+ *         return -1;
+ *     }
  *
+ *     return 0;
+ * }
  */
-int aul_listen_app_dead_signal(int (*func) (int, void *), void *data);
+int aul_listen_app_dead_signal(aul_app_dead_event_cb callback, void *user_data);
 
 /**
- * @par Description:
- *     This API sets callback fuction that will be called when applications are launched.
- * @par Purpose:
- *     This API's purpose is to listen the application launching event.
- *     In general, task manager Application need this API.
+ * @brief Called when an application is launched.
+ * @details This function is called when an application is launched, after you register this callback using aul_listen_app_launch_signal().
+ * @param[in]   pid             The process ID
+ * @param[in]   user_data       The user data passed from the registeration function
  *
- * @param[in]  func            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
+ * @see aul_listen_app_launch_signal()
+ */
+typedef int (*aul_app_launch_event_cb)(int pid, void *user_data);
+
+/**
+ * @brief Registers a callback function to be invoked when the application is launched.
+ * @remarks If the callback function is nullptr, the registered event will be deregistered.
+ * @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_ERROR    Internal I/O error
+ * @see aul_app_launch_event_cb()
+ *
+ * @remarks This function is only available for App Framework internally.
  *
  * @see
- *     aul_listen_app_dead_signal
- * @code
  * #include <aul.h>
  *
- * int app_launch_handler(int pid, void *data)
+ * static int app_launch_event_cb(int pid, void *user_data)
  * {
- *     printf("===> %s : %d\n", __FUNCTION__, pid);
- *     return 0;
+ *     dlog_print(DLOG_INFO, LOG_TAG, "application(%d) is launched", pid);
+ *     return 0;
  * }
  *
- * void dead_listen()
+ * int listen_app_launch_signal(void)
  * {
- *     aul_listen_app_launch_signal(app_launch_handler, NULL);
- * }
+ *     int ret;
  *
- * @endcode
- * @remark
- *     This API is only available in User Session.
+ *     ret = aul_listen_app_launch_signal(app_launch_event_cb, NULL);
+ *     if (ret != AUL_R_OK) {
+ *         dlog_print(DLOG_ERROR, LOG_TAG, "aul_listen_app_launch_signal() is failed. error(%d)", ret);
+ *         return -1;
+ *     }
  *
+ *     return 0;
+ * }
  */
-int aul_listen_app_launch_signal(int (*func) (int, void *), void *data);
+int aul_listen_app_launch_signal(aul_app_launch_event_cb callback, void *user_data);
 
 /**
- * @par Description:
- *     This API sets callback fuction that will be called when applications are launched.
- * @par Purpose:
- *     This API's purpose is to listen the application launching event.
- *     In general, task manager Application need this API.
+ * @brief Called when an application is launched.
+ * @details This function is called when an application is launched, after you register this callback using aul_listen_app_launch_signal_v2().
+ * @param[in]   pid             The process ID
+ * @param[in]   appid           The application ID
+ * @param[in]   user_data       The user data passed from the registeration function
  *
- * @param[in]  func            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
+ * @see aul_listen_app_launch_signal_v2()
+ */
+typedef int (*aul_app_launch_event_cb_v2)(int pid, const char *appid, void *user_data);
+
+/**
+ * @brief Registers a callback function to be invoked when the application is launched.
+ * @remarks If the callback function is nullptr, the registered event will be deregistered.
+ * @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_ERROR    Internal I/O error
+ *
+ * @see aul_app_launch_event_cb_v2()
+ *
+ * @remarks This function is only available for App Framework internally.
  *
- * @see
- *     aul_listen_app_dead_signal
  * @code
  * #include <aul.h>
  *
- * int app_launch_handler(int pid, const char *app_id, void *data)
+ * static int app_launch_event_cb(int pid, const char *appid, void *user_data)
  * {
- *     printf("===> %s : %d, %s\n", __FUNCTION__, pid, app_id);
- *     return 0;
+ *     dlog_print(DLOG_INFO, LOG_TAG, "application(%s:%d) is launched", appid, pid);
+ *     return 0;
  * }
  *
- * void dead_listen()
+ * int listen_app_launch_signal(void)
  * {
- *     aul_listen_app_launch_signal(app_launch_handler, NULL);
- * }
+ *     int ret;
  *
- * @endcode
- * @remark
- *     This API is only available in User Session.
+ *     ret = aul_listen_app_launch_signal_v2(app_launch_event_cb, NULL);
+ *     if (ret != AUL_R_OK) {
+ *         dlog_print(DLOG_ERROR, LOG_TAG, "aul_listen_app_launch_signal_v2() is failed. error(%d)", ret);
+ *         return -1;
+ *     }
  *
+ *     return 0;
+ * }
  */
-int aul_listen_app_launch_signal_v2(int (*func) (int, const char *, void *), void *data);
+int aul_listen_app_launch_signal_v2(aul_app_launch_event_cb_v2 callback, void *user_data);
 
 /**
  * @par Description:
@@ -2257,84 +2292,130 @@ int aul_app_group_activate_above(const char *above_appid);
  * This API is only for Appfw internally.
  */
 int aul_request_data_control_socket_pair(bundle *b, int *fd);
+
 /*
  * This API is only for Appfw internally.
  */
 int aul_request_message_port_socket_pair(int *fd);
-/*
- * This API is only for Appfw internally.
+
+/**
+ * @brief Called when the system booting is completed.
+ * @param[in]   unused          The unused parameter
+ * @param[in]   user_data       The use data passed from the registration function
+ * @return      The return value is not used.
+ *
+ * @see aul_listen_booting_done_signal();
  */
-int aul_listen_booting_done_signal(int (*func) (int, void *), void *data);
+typedef int (*aul_booting_done_event_cb)(int unused, void *user_data);
 
-/*
- * This API is only for Appfw internally.
+/**
+ * @brief Registers a callback function to be invoked when the system booting is completed.
+ * @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
+ *
+ * @see aul_booting_done_event_cb()a
+ * @remarks This function is only available for App Framework internally.
+ */
+int aul_listen_booting_done_signal(aul_booting_done_event_cb, void *user_data);
+
+/**
+ * @brief Called when the coodlown event occurs.
+ * @param[in]   status          The cooldown status
+ * @param[in]   user_data       The user data passed from the registration function
+ * @return      The return value is not used.
+ *
+ * @see aul_listen_cooldown_signal()
+ */
+typedef int (*aul_cooldown_event_cb)(const char *status, void *user_data);
+
+/**
+ * @brief Registers a callback function to be invoked when the cooldown event occurs.
+ * @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
+ *
+ * @see aul_coodlown_event_cb()
+ *
+ * @remarks This function is only available for App Framework internally.
  */
 int aul_listen_cooldown_signal(int (*func) (const char *, void *), void *data);
 
 /**
- * @par Description:
- *     This API registers a callback function that will be called when the
- *     status of the application is changed.
- * @par Purpose:
- *     This API is for monitoring the status of all applications.
+ * @brief Called when the status of the app process is changed.
+ * @details This function is called when the app process status is changed, after you register this callback using aul_listen_app_status_signal().
+ * @param[in]   pid             The process ID
+ * @param[in]   status          The status of the process
+ * @param[in]   user_data       The user data passed from the registeration function
  *
- * @param[in]  func            callback function. Please refer to 'app_status_handler' below.
- * @param[in]  data            user data
- * @return     0 if success, negative value if fail
- * @retval     AUL_R_OK        - success
- * @retval     AUL_R_ERROR     - general error
- * @remark
- *     The callback will be invoked asynchronously.
- *     It can't guarantee that the real status would not be changed during the callback is called.
+ * @see @aul_listen_app_status_signal()
+ * @see #aul_process_status_e
+ */
+typedef int (*aul_app_status_changed_cb)(int pid, int status, void *user_data);
+
+/**
+ * @brief Registers a callback function to be invoked when the process status is changed.
+ * @remarks If the callback function is nullptr, the registered event will be deregistered.
+ * @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_ERROR    Internal I/O error
+ *
+ * @see @aul_app_status_changed_cb()
+ * @see #aul_process_status_e
+ *
+ * @remarks This function is only available for App Framework internally.
  *
  * @code
  * #include <aul.h>
  *
- * int app_status_handler(int pid, int status, void *data)
+ * static int app_status_changed_cb(int pid, int status, void *user_data)
  * {
- *     const char *app_status;
- *
- *     switch (status) {
- *     case AUL_PROC_STATUS_LAUNCH:
- *             app_status = "LAUNCHING";
- *             break;
- *     case AUL_PROC_STATUS_FG:
- *             app_status = "VISIBLE";
- *             break;
- *     case AUL_PROC_STATUS_BG:
- *             app_status = "BACKGROUND";
- *             break;
- *     case AUL_PROC_STATUS_FOCUS:
- *             app_status = "FOCUS";
- *             break;
- *     case AUL_PROC_STATUS_HIDE:
- *             app_status = "HIDE";
- *             break;
- *     default:
- *             app_status = "UNKNOWN";
- *     }
- *
- *     printf("pid: %d, status: %s", pid, status);
- *     return 0;
+ *     cosnt char *app_status;
+ *
+ *     switch (status) {
+ *     case AUL_PROC_STATUS_LAUNCH:
+ *         app_status = "LAUNCHING";
+ *         break;
+ *     case AUL_PROC_STATUS_FG:
+ *         app_status = "VISIBLE";
+ *         break;
+ *     case AUL_PROC_STATUS_BG:
+ *         app_status = "BACKGROUND";
+ *         break;
+ *     case AUL_PROC_STATUS_FOCUS:
+ *         app_status = "FOCUS";
+ *         break;
+ *     case AUL_PROC_STATUS_HIDE:
+ *         app_status = "HIDE";
+ *         break;
+ *     default:
+ *         app_status = "UNKNOWN";
+ *         break;
+ *     }
+ *
+ *     dlog_print(DLOG_INFO, LOG_TAG, "pid: %d, status: %%s(%d)", pid, app_status, status);
+ *     return 0;
  * }
  *
- * int main(int argc, char **argv)
+ * int listen_app_status_signal(void)
  * {
- *     int ret;
- *
- *     ret = aul_listen_app_status_signal(app_status_handler, NULL);
- *     if (ret != AUL_R_OK) {
- *             printf("Failed to add status handler");
- *             return -1;
- *     }
+ *     int ret;
  *
- *     ...
+ *     ret = aul_listen_app_status_signal(app_status_changed_cb, NULL);
+ *     if (ret != AUL_R_OK) {
+ *         dlog_print(DLOG_ERROR, LOG_TAG, "aul_listen_app_status_signal() is failed. error(%d)", ret);
+ *         return -1;
+ *     }
  *
- *     return 0;
+ *     return 0;
  * }
- * @endcode
  */
-int aul_listen_app_status_signal(int (*func)(int, int, void *), void *data);
+int aul_listen_app_status_signal(aul_app_status_changed_cb callback, void *user_data);
 
 /*
  * This API is only for Appfw internally.
diff --git a/src/app_signal.c b/src/app_signal.c
deleted file mode 100644 (file)
index f4425bb..0000000
+++ /dev/null
@@ -1,546 +0,0 @@
-/*
- * Copyright (c) 2000 - 2017 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 <stdbool.h>
-#include <gio/gio.h>
-#include <glib.h>
-
-#include "app_signal.h"
-#include "aul_api.h"
-#include "aul_util.h"
-#include "aul.h"
-
-static guint app_dead_subscription_id;
-static int (*app_dead_handler)(int pid, void *data);
-static void *app_dead_data;
-
-static guint app_launch_subscription_id;
-static int (*app_launch_handler)(int pid, void *data);
-static void *app_launch_data;
-
-static guint app_launch_subscription_id2;
-static int (*app_launch_handler2)(int pid, const char *app_id, void *data);
-static void *app_launch_data2;
-
-static guint booting_done_subscription_id;
-static int (*booting_done_handler) (int pid, void *data);
-static void *booting_done_data;
-
-static guint status_subscription_id;
-static int (*status_handler) (int pid, int status, void *data);
-static void *status_data;
-
-static guint cooldown_subscription_id;
-static int (*cooldown_handler) (const char *cooldown_status, void *data);
-static void *cooldown_data;
-
-static GDBusConnection *system_conn = NULL;
-
-static void __system_dbus_signal_handler(GDBusConnection *connection,
-                                       const gchar *sender_name,
-                                       const gchar *object_path,
-                                       const gchar *interface_name,
-                                       const gchar *signal_name,
-                                       GVariant *parameters,
-                                       gpointer user_data)
-{
-       gchar *cooldown_status;
-       gint pid = -1;
-       gint status;
-       guint upid;
-       gchar *appid;
-
-       if (g_strcmp0(signal_name, SYSTEM_SIGNAL_BOOTING_DONE) == 0) {
-               if (booting_done_handler)
-                       booting_done_handler((int)pid, booting_done_data);
-       } else if (g_strcmp0(signal_name, RESOURCED_PROC_STATUS_SIGNAL) == 0) {
-               g_variant_get(parameters, "(ii)", &status, &pid);
-
-               if (status_handler)
-                       status_handler((int)pid, (int)status, status_data);
-       } else if (g_strcmp0(signal_name,
-                               SYSTEM_SIGNAL_COOLDOWN_MODE_CHANGED) == 0) {
-               g_variant_get(parameters, "(s)", &cooldown_status);
-
-               if (cooldown_handler)
-                       cooldown_handler((const char *)cooldown_status,
-                                       cooldown_data);
-
-               g_free(cooldown_status);
-       } else if (g_strcmp0(signal_name, AUL_DBUS_APPDEAD_SIGNAL) == 0) {
-               g_variant_get(parameters, "(u)", &upid);
-
-               if (app_dead_handler)
-                       app_dead_handler((int)upid, app_dead_data);
-       } else if (g_strcmp0(signal_name, AUL_DBUS_APPLAUNCH_SIGNAL) == 0) {
-               g_variant_get(parameters, "(us)", &upid, &appid);
-
-               if (app_launch_handler)
-                       app_launch_handler((int)upid, app_launch_data);
-
-               if (app_launch_handler2)
-                       app_launch_handler2((int)upid,
-                                       (const char *)appid, app_launch_data2);
-
-               g_free(appid);
-       }
-}
-
-static guint __system_dbus_register_signal(const char *object_path,
-                                       const char *interface_name,
-                                       const char *signal_name)
-{
-       guint s_id;
-       GError *err = NULL;
-       GDBusConnection *conn = NULL;
-
-       if (system_conn == NULL) {
-               conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
-               if (conn == NULL) {
-                       _E("g_bus_get_sync() is failed. %s", err->message);
-                       g_error_free(err);
-                       return 0;
-               }
-               system_conn = conn;
-       }
-
-       s_id = g_dbus_connection_signal_subscribe(system_conn,
-                                       NULL,
-                                       interface_name,
-                                       signal_name,
-                                       object_path,
-                                       NULL,
-                                       G_DBUS_SIGNAL_FLAGS_NONE,
-                                       __system_dbus_signal_handler,
-                                       NULL,
-                                       NULL);
-       if (s_id == 0) {
-               _E("g_dbus_connection_signal_subscribe() is failed.");
-               if (conn) {
-                       g_object_unref(conn);
-                       system_conn = NULL;
-               }
-       }
-
-       g_clear_error(&err);
-
-       return s_id;
-}
-
-static guint __system_dbus_unregister_signal(guint s_id)
-{
-       if (system_conn == NULL)
-               return s_id;
-
-       g_dbus_connection_signal_unsubscribe(system_conn, s_id);
-
-       if (booting_done_handler == NULL
-                       && status_handler == NULL
-                       && cooldown_handler == NULL
-                       && app_dead_handler == NULL
-                       && app_launch_handler == NULL
-                       && app_launch_handler2 == NULL) {
-               g_object_unref(system_conn);
-               system_conn = NULL;
-       }
-
-       return 0;
-}
-
-API int aul_listen_app_dead_signal(int (*func)(int, void *), void *data)
-{
-       app_dead_handler = func;
-       app_dead_data = data;
-
-       if (app_dead_handler && app_dead_subscription_id == 0) {
-               app_dead_subscription_id = __system_dbus_register_signal(
-                                       AUL_DBUS_PATH,
-                                       AUL_DBUS_SIGNAL_INTERFACE,
-                                       AUL_DBUS_APPDEAD_SIGNAL);
-               if (app_dead_subscription_id == 0)
-                       return AUL_R_ERROR;
-       } else if (app_dead_handler == NULL && app_dead_subscription_id) {
-               app_dead_subscription_id = __system_dbus_unregister_signal(
-                                       app_dead_subscription_id);
-               if (app_dead_subscription_id)
-                       return AUL_R_ERROR;
-       }
-
-       return AUL_R_OK;
-}
-
-API int aul_listen_app_launch_signal(int (*func)(int, void *), void *data)
-{
-       app_launch_handler = func;
-       app_launch_data = data;
-
-       if (app_launch_handler && app_launch_subscription_id == 0) {
-               app_launch_subscription_id = __system_dbus_register_signal(
-                                       AUL_DBUS_PATH,
-                                       AUL_DBUS_SIGNAL_INTERFACE,
-                                       AUL_DBUS_APPLAUNCH_SIGNAL);
-               if (app_launch_subscription_id == 0)
-                       return AUL_R_ERROR;
-       } else if (app_launch_handler == NULL && app_launch_subscription_id) {
-               app_launch_subscription_id = __system_dbus_unregister_signal(
-                                       app_launch_subscription_id);
-               if (app_launch_subscription_id)
-                       return AUL_R_ERROR;
-       }
-
-       return AUL_R_OK;
-}
-
-API int aul_listen_app_launch_signal_v2(int (*func)(int, const char *, void *),
-               void *data)
-{
-       app_launch_handler2 = func;
-       app_launch_data2 = data;
-
-       if (app_launch_handler2 && app_launch_subscription_id2 == 0) {
-               app_launch_subscription_id2 = __system_dbus_register_signal(
-                                       AUL_DBUS_PATH,
-                                       AUL_DBUS_SIGNAL_INTERFACE,
-                                       AUL_DBUS_APPLAUNCH_SIGNAL);
-               if (app_launch_subscription_id2 == 0)
-                       return AUL_R_ERROR;
-       } else if (app_launch_handler2 == NULL && app_launch_subscription_id2) {
-               app_launch_subscription_id2 = __system_dbus_unregister_signal(
-                                       app_launch_subscription_id2);
-               if (app_launch_subscription_id2)
-                       return AUL_R_ERROR;
-       }
-
-       return AUL_R_OK;
-}
-
-API int aul_listen_booting_done_signal(int (*func)(int, void *), void *data)
-{
-       booting_done_handler = func;
-       booting_done_data = data;
-
-       if (booting_done_handler && booting_done_subscription_id == 0) {
-               booting_done_subscription_id = __system_dbus_register_signal(
-                                       SYSTEM_PATH_CORE,
-                                       SYSTEM_INTERFACE_CORE,
-                                       SYSTEM_SIGNAL_BOOTING_DONE);
-               if (booting_done_subscription_id == 0)
-                       return AUL_R_ERROR;
-       } else if (booting_done_handler == NULL
-                                       && booting_done_subscription_id) {
-               booting_done_subscription_id = __system_dbus_unregister_signal(
-                               booting_done_subscription_id);
-               if (booting_done_subscription_id)
-                       return AUL_R_ERROR;
-       }
-
-       return AUL_R_OK;
-}
-
-API int aul_listen_cooldown_signal(int (*func)(const char *, void *),
-                                       void *data)
-{
-       cooldown_handler = func;
-       cooldown_data = data;
-
-       if (cooldown_handler && cooldown_subscription_id == 0) {
-               cooldown_subscription_id = __system_dbus_register_signal(
-                                       SYSTEM_PATH_THERMAL,
-                                       SYSTEM_INTERFACE_THERMAL,
-                                       SYSTEM_SIGNAL_COOLDOWN_MODE_CHANGED);
-               if (cooldown_subscription_id == 0)
-                       return AUL_R_ERROR;
-       } else if (cooldown_handler == NULL && cooldown_subscription_id) {
-               cooldown_subscription_id = __system_dbus_unregister_signal(
-                                       cooldown_subscription_id);
-               if (cooldown_subscription_id)
-                       return AUL_R_ERROR;
-       }
-
-       return AUL_R_OK;
-}
-
-API int aul_listen_app_status_signal(int (*func)(int, int, void *),
-                                       void *data)
-{
-       status_handler = func;
-       status_data = data;
-
-       if (status_handler && status_subscription_id == 0) {
-               status_subscription_id = __system_dbus_register_signal(
-                                       RESOURCED_PROC_PATH,
-                                       RESOURCED_PROC_INTERFACE,
-                                       RESOURCED_PROC_STATUS_SIGNAL);
-               if (status_subscription_id == 0)
-                       return AUL_R_ERROR;
-       } else if (status_handler == NULL && status_subscription_id) {
-               status_subscription_id = __system_dbus_unregister_signal(
-                                       status_subscription_id);
-               if (status_subscription_id)
-                       return AUL_R_ERROR;
-       }
-
-       return AUL_R_OK;
-}
-
-static int __system_dbus_send_signal(const char *object_path,
-                                       const char *interface_name,
-                                       const char *signal_name,
-                                       GVariant *parameters)
-{
-       GError *err = NULL;
-       GDBusConnection *conn;
-       int ret = AUL_R_OK;
-
-       conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
-       if (conn == NULL) {
-               _E("g_bus_get_sync() is failed. %s", err->message);
-               g_error_free(err);
-               return AUL_R_ERROR;
-       }
-
-       if (g_dbus_connection_emit_signal(conn,
-                                       NULL,
-                                       object_path,
-                                       interface_name,
-                                       signal_name,
-                                       parameters,
-                                       &err) == FALSE) {
-               _E("g_dbus_connection_emit_signal() is failed. %s",
-                               err->message);
-               ret = AUL_R_ERROR;
-               goto end;
-       }
-
-       if (g_dbus_connection_flush_sync(conn, NULL, &err) == FALSE) {
-               _E("g_dbus_connection_flush_sync() is failed. %s",
-                               err->message);
-               ret = AUL_R_ERROR;
-       }
-
-end:
-       if (conn)
-               g_object_unref(conn);
-
-       g_clear_error(&err);
-
-       return ret;
-}
-
-static void __dbus_message_ready_cb(GObject *source_object,
-               GAsyncResult *res, gpointer user_data)
-{
-       GDBusConnection *conn = (GDBusConnection *)user_data;
-       GError *err = NULL;
-       GDBusMessage *reply;
-       int r;
-
-       reply = g_dbus_connection_send_message_with_reply_finish(conn,
-                       res, &err);
-       if (!reply) {
-               _E("No reply. err(%s)", err ? err->message : "Unknown");
-               r = -1;
-       } else {
-               r = 0;
-       }
-
-       g_clear_error(&err);
-       if (reply)
-               g_object_unref(reply);
-       if (conn)
-               g_object_unref(conn);
-
-       _I("Result(%d)", r);
-}
-
-static int __system_dbus_send_message(const char *name,
-               const char *path, const char *interface,
-               const char *method, GVariant *body)
-{
-       GError *err = NULL;
-       GDBusConnection *conn;
-       GDBusMessage *msg;
-
-       conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
-       if (conn == NULL) {
-               _E("Failed to connect to dbus. err(%s)", err->message);
-               g_error_free(err);
-               return AUL_R_ERROR;
-       }
-
-       msg = g_dbus_message_new_method_call(name, path, interface, method);
-       if (msg == NULL) {
-               _E("Failed to create a new message for a method call");
-               g_object_unref(conn);
-               return AUL_R_ERROR;
-       }
-
-       g_dbus_message_set_body(msg, body);
-       g_dbus_connection_send_message_with_reply(conn, msg,
-                       G_DBUS_SEND_MESSAGE_FLAGS_NONE,
-                       -1, NULL, NULL, __dbus_message_ready_cb,
-                       (gpointer)conn);
-       g_object_unref(msg);
-
-       return AUL_R_OK;
-}
-
-API int aul_update_freezer_status(int pid, const char *type)
-{
-       int ret;
-       GVariant *body;
-
-       body = g_variant_new("(si)", type, pid);
-       if (!body) {
-               _E("Out of memory");
-               return AUL_R_ERROR;
-       }
-
-       ret = __system_dbus_send_message(RESOURCED_BUS_NAME,
-                                       RESOURCED_PROC_PATH,
-                                       RESOURCED_PROC_INTERFACE,
-                                       RESOURCED_PROC_METHOD,
-                                       body);
-       if (ret != AUL_R_OK)
-               g_variant_unref(body);
-
-       return ret;
-}
-
-API int aul_send_app_launch_request_signal(int pid,
-                                       const char *appid,
-                                       const char *pkgid,
-                                       const char *type)
-{
-       int ret;
-       GVariant *param;
-
-       param = g_variant_new("(isss)", pid, appid, pkgid, type);
-       ret = __system_dbus_send_signal(AUL_APP_STATUS_DBUS_PATH,
-                                       AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE,
-                                       AUL_APP_STATUS_DBUS_LAUNCH_REQUEST,
-                                       param);
-
-       return ret;
-}
-
-API int aul_send_app_resume_request_signal(int pid,
-                                       const char *appid,
-                                       const char *pkgid,
-                                       const char *type)
-{
-       int ret;
-       const char *empty = "";
-       GVariant *param;
-
-       if (appid)
-               param = g_variant_new("(isss)", pid, appid, pkgid, type);
-       else
-               param = g_variant_new("(isss)", pid, empty, empty, empty);
-
-       ret = __system_dbus_send_signal(AUL_APP_STATUS_DBUS_PATH,
-                                       AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE,
-                                       AUL_APP_STATUS_DBUS_RESUME_REQUEST,
-                                       param);
-
-       return ret;
-}
-
-API int aul_send_app_terminate_request_signal(int pid,
-                                       const char *appid,
-                                       const char *pkgid,
-                                       const char *type)
-{
-       int ret;
-       const char *empty = "";
-       GVariant *param;
-
-       if (appid)
-               param = g_variant_new("(isss)", pid, appid, pkgid, type);
-       else
-               param = g_variant_new("(isss)", pid, empty, empty, empty);
-
-       ret = __system_dbus_send_signal(AUL_APP_STATUS_DBUS_PATH,
-                                       AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE,
-                                       AUL_APP_STATUS_DBUS_TERMINATE_REQUEST,
-                                       param);
-
-       return ret;
-}
-
-API int aul_send_app_status_change_signal(int pid,
-                                       const char *appid,
-                                       const char *pkgid,
-                                       const char *status,
-                                       const char *type)
-{
-       int ret;
-       const char *empty = "";
-       GVariant *param;
-
-       if (appid)
-               param = g_variant_new("(issss)",
-                               pid, appid, pkgid, status, type);
-       else
-               param = g_variant_new("(issss)",
-                               pid, empty, empty, status, type);
-
-       ret = __system_dbus_send_signal(AUL_APP_STATUS_DBUS_PATH,
-                                       AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE,
-                                       AUL_APP_STATUS_DBUS_STATUS_CHANGE,
-                                       param);
-
-       return ret;
-}
-
-API int aul_send_app_terminated_signal(int pid)
-{
-       int ret;
-       GVariant *param;
-
-       param = g_variant_new("(i)", pid);
-       ret = __system_dbus_send_signal(AUL_APP_STATUS_DBUS_PATH,
-                                       AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE,
-                                       AUL_APP_STATUS_DBUS_TERMINATED,
-                                       param);
-
-       return ret;
-}
-
-API int aul_send_app_group_signal(int owner_pid,
-               int child_pid,
-               const char *child_pkgid)
-{
-       int ret;
-       const char *empty = "";
-       GVariant *param;
-
-       if (child_pkgid)
-               param = g_variant_new("(iis)",
-                                       owner_pid, child_pid, child_pkgid);
-       else
-               param = g_variant_new("(iis)",
-                                       owner_pid, child_pid, empty);
-
-       ret = __system_dbus_send_signal(AUL_APP_STATUS_DBUS_PATH,
-                                       AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE,
-                                       AUL_APP_STATUS_DBUS_GROUP,
-                                       param);
-
-       return ret;
-}
diff --git a/src/app_signal.cc b/src/app_signal.cc
new file mode 100644 (file)
index 0000000..cead0f4
--- /dev/null
@@ -0,0 +1,658 @@
+/*
+ * 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 <gio/gio.h>
+#include <glib.h>
+
+#include <memory>
+#include <mutex>
+#include <string>
+
+#include "include/aul.h"
+#include "aul_api.h"
+
+#include "log_private.hh"
+
+namespace {
+
+constexpr const char AUL_DBUS_PATH[] = "/aul/dbus_handler";
+constexpr const char AUL_DBUS_SIGNAL_INTERFACE[] = "org.tizen.aul.signal";
+constexpr const char AUL_DBUS_APPDEAD_SIGNAL[] = "app_dead";
+constexpr const char AUL_DBUS_APPLAUNCH_SIGNAL[] = "app_launch";
+
+constexpr const char AUL_APP_STATUS_DBUS_PATH[] = "/Org/Tizen/Aul/AppStatus";
+constexpr const char AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE[] =
+    "org.tizen.aul.AppStatus";
+constexpr const char AUL_APP_STATUS_DBUS_LAUNCH_REQUEST[] = "AppLaunch";
+constexpr const char AUL_APP_STATUS_DBUS_RESUME_REQUEST[] = "AppResume";
+constexpr const char AUL_APP_STATUS_DBUS_TERMINATE_REQUEST[] = "AppTerminate";
+constexpr const char AUL_APP_STATUS_DBUS_STATUS_CHANGE[] = "AppStatusChange";
+constexpr const char AUL_APP_STATUS_DBUS_GROUP[] = "AppGroup";
+constexpr const char AUL_APP_STATUS_DBUS_TERMINATED[] = "AppTerminated";
+
+constexpr const char SYSTEM_PATH_CORE[] =  "/org/tizen/system";
+constexpr const char SYSTEM_INTERFACE_CORE[] = "org.tizen.system.Booting";
+constexpr const char SYSTEM_SIGNAL_BOOTING_DONE[] = "BootingDone";
+
+constexpr const char SYSTEM_PATH_THERMAL[] = "/Org/Tizen/System/Thermal";
+constexpr const char SYSTEM_INTERFACE_THERMAL[] = "org.tizen.system.thermal";
+constexpr const char SYSTEM_SIGNAL_COOLDOWN_MODE_CHANGED[] =
+    "CoolDownModeChanged";
+
+constexpr const char RESOURCED_BUS_NAME[] = "org.tizen.resourced";
+constexpr const char RESOURCED_PROC_PATH[] = "/Org/Tizen/ResourceD/Process";
+constexpr const char RESOURCED_PROC_INTERFACE[] = "org.tizen.resourced.process";
+constexpr const char RESOURCED_PROC_STATUS_SIGNAL[] = "ProcStatus";
+constexpr const char RESOURCED_PROC_METHOD[] = "ProcExclude";
+
+template <typename T>
+class Event {
+ public:
+  Event(std::string object_path, std::string interface_name,
+      std::string signal_name, T cb, void* user_data)
+      : object_path_(std::move(object_path)),
+        interface_name_(std::move(interface_name)),
+        signal_name_(std::move(signal_name)),
+        cb_(cb),
+        user_data_(user_data) {
+   }
+
+   virtual ~Event() {
+     Unsubscribe();
+   }
+
+   const std::string& GetObjectPath() const { return object_path_; }
+
+   const std::string& GetInterfaceName() const { return interface_name_; }
+
+   const std::string& GetSignalName() const { return signal_name_; }
+
+   virtual void Invoke(GVariant* parameters) {}
+
+   T GetCallback() const { return cb_; }
+
+   void* GetUserData() const { return user_data_; }
+
+   bool Subscribe() {
+     if (source_ != 0)
+       return true;
+
+     GError* err = nullptr;
+     conn_ = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &err);
+     if (conn_ == nullptr) {
+       _E("g_bus_get_sync() is failed. error(%s)", err ? err->message : "");
+       g_clear_error(&err);
+       return false;
+     }
+
+     source_ = g_dbus_connection_signal_subscribe(conn_, nullptr,
+         interface_name_.c_str(), signal_name_.c_str(), object_path_.c_str(),
+         nullptr, G_DBUS_SIGNAL_FLAGS_NONE, DBusSignalCb, this, nullptr);
+     if (source_ == 0) {
+       _E("g_dbus_connection_signal_subscribe() is failed");
+       g_object_unref(conn_);
+       conn_ = nullptr;
+       return false;
+     }
+
+     return true;
+   }
+
+ private:
+  void Unsubscribe() {
+    std::lock_guard<std::recursive_mutex> lock(GetMutex());
+    if (source_ == 0)
+      return;
+
+    g_dbus_connection_signal_unsubscribe(conn_, source_);
+    source_ = 0;
+
+    g_object_unref(conn_);
+    conn_ = nullptr;
+  }
+
+  std::recursive_mutex& GetMutex() const {
+    return mutex_;
+  }
+
+  static void DBusSignalCb(GDBusConnection* connection,
+      const gchar* sender_name, const gchar* object_path,
+      const gchar* interface_name, const gchar* signal_name,
+      GVariant* parameters, gpointer user_data) {
+    auto* event = static_cast<Event*>(user_data);
+    std::lock_guard<std::recursive_mutex> lock(event->GetMutex());
+    event->Invoke(parameters);
+  }
+
+ private:
+  std::string object_path_;
+  std::string interface_name_;
+  std::string signal_name_;
+  T cb_;
+  void* user_data_;
+  GDBusConnection* conn_ = nullptr;
+  guint source_ = 0;
+  mutable std::recursive_mutex mutex_;
+};
+
+class AppDeadEvent : public Event<aul_app_dead_event_cb> {
+ public:
+  AppDeadEvent(aul_app_dead_event_cb cb, void* user_data)
+      : Event<aul_app_dead_event_cb>(AUL_DBUS_PATH, AUL_DBUS_SIGNAL_INTERFACE,
+            AUL_DBUS_APPDEAD_SIGNAL, cb, user_data) {
+  }
+
+  void Invoke(GVariant* parameters) override {
+    guint pid;
+    g_variant_get(parameters, "(u)", &pid);
+
+    auto cb = GetCallback();
+    if (cb != nullptr)
+      cb(static_cast<int>(pid), GetUserData());
+  }
+};
+
+class AppLaunchEvent : public Event<aul_app_launch_event_cb> {
+ public:
+  AppLaunchEvent(aul_app_launch_event_cb cb, void* user_data)
+      : Event<aul_app_launch_event_cb>(AUL_DBUS_PATH, AUL_DBUS_SIGNAL_INTERFACE,
+            AUL_DBUS_APPLAUNCH_SIGNAL, cb, user_data) {
+  }
+
+  void Invoke(GVariant* parameters) override {
+    guint pid;
+    gchar* appid;
+    g_variant_get(parameters, "(u&s)", &pid, &appid);
+
+    auto cb = GetCallback();
+    if (cb != nullptr)
+      cb(static_cast<int>(pid), GetUserData());
+  }
+};
+
+class AppLaunchEvent2 : public Event<aul_app_launch_event_cb_v2> {
+ public:
+  AppLaunchEvent2(aul_app_launch_event_cb_v2 cb, void* user_data)
+      : Event<aul_app_launch_event_cb_v2>(AUL_DBUS_PATH,
+            AUL_DBUS_SIGNAL_INTERFACE, AUL_DBUS_APPLAUNCH_SIGNAL, cb,
+            user_data) {
+  }
+
+  void Invoke(GVariant* parameters) override {
+    guint pid;
+    gchar* appid;
+    g_variant_get(parameters, "(u&s)", &pid, &appid);
+
+    auto cb = GetCallback();
+    if (cb != nullptr)
+      cb(static_cast<int>(pid), appid, GetUserData());
+  }
+};
+
+class BootingDoneEvent : public Event<aul_booting_done_event_cb> {
+ public:
+  BootingDoneEvent(aul_booting_done_event_cb cb, void* user_data)
+      : Event<aul_booting_done_event_cb>(SYSTEM_PATH_CORE,
+            SYSTEM_INTERFACE_CORE, SYSTEM_SIGNAL_BOOTING_DONE, cb, user_data) {
+  }
+
+  void Invoke(GVariant* parameters) override {
+    auto cb = GetCallback();
+    if (cb != nullptr)
+      cb(0, GetUserData());
+  }
+};
+
+class CooldownEvent : public Event<aul_cooldown_event_cb> {
+ public:
+  CooldownEvent(aul_cooldown_event_cb cb, void* user_data)
+      : Event<aul_cooldown_event_cb>(SYSTEM_PATH_THERMAL,
+            SYSTEM_INTERFACE_THERMAL, SYSTEM_SIGNAL_COOLDOWN_MODE_CHANGED, cb,
+            user_data) {
+  }
+
+  void Invoke(GVariant* parameters) override {
+    gchar* cooldown_status;
+    g_variant_get(parameters, "(&s)", &cooldown_status);
+
+    auto cb = GetCallback();
+    if (cb != nullptr)
+      cb(cooldown_status, GetUserData());
+  }
+};
+
+class AppStatusChangedEvent : public Event<aul_app_status_changed_cb> {
+ public:
+  AppStatusChangedEvent(aul_app_status_changed_cb cb, void* user_data)
+      : Event<aul_app_status_changed_cb>(RESOURCED_PROC_PATH,
+            RESOURCED_PROC_INTERFACE, RESOURCED_PROC_STATUS_SIGNAL, cb,
+            user_data) {
+  }
+
+  void Invoke(GVariant* parameters) override {
+    gint pid = -1;
+    gint status = -1;
+    g_variant_get(parameters, "(ii)", &status, &pid);
+
+    auto cb = GetCallback();
+    if (cb != nullptr)
+      cb(pid, status, GetUserData());
+  }
+};
+
+class AppSignalContext {
+ public:
+  AppSignalContext() = default;
+  ~AppSignalContext() {
+  }
+
+  bool AppDeadEventSubscribe(aul_app_dead_event_cb cb, void* user_data) {
+    std::lock_guard<std::recursive_mutex> lock(mutex_);
+    if (cb == nullptr) {
+      app_dead_event_.reset();
+      return true;
+    }
+
+    app_dead_event_.reset(new AppDeadEvent(cb, user_data));
+    return app_dead_event_->Subscribe();
+  }
+
+  bool AppLaunchEventSubscribe(aul_app_launch_event_cb cb, void* user_data) {
+    std::lock_guard<std::recursive_mutex> lock(mutex_);
+    if (cb == nullptr) {
+      app_launch_event_.reset();
+      return true;
+    }
+
+    app_launch_event_.reset(new AppLaunchEvent(cb, user_data));
+    return app_launch_event_->Subscribe();
+  }
+
+  bool AppLaunchEvent2Subscribe(aul_app_launch_event_cb_v2 cb,
+      void* user_data) {
+    std::lock_guard<std::recursive_mutex> lock(mutex_);
+    if (cb == nullptr) {
+      app_launch_event2_.reset();
+      return true;
+    }
+
+    app_launch_event2_.reset(new AppLaunchEvent2(cb, user_data));
+    return app_launch_event2_->Subscribe();
+  }
+
+  bool BootingDoneEventSubscribe(aul_booting_done_event_cb cb,
+      void* user_data) {
+    std::lock_guard<std::recursive_mutex> lock(mutex_);
+    if (cb == nullptr) {
+      booting_done_event_.reset();
+      return true;
+    }
+
+    booting_done_event_.reset(new BootingDoneEvent(cb, user_data));
+    return booting_done_event_->Subscribe();
+  }
+
+  bool CooldownEventSubscribe(aul_cooldown_event_cb cb, void* user_data) {
+    std::lock_guard<std::recursive_mutex> lock(mutex_);
+    if (cb == nullptr) {
+      cooldown_event_.reset();
+      return true;
+    }
+
+    cooldown_event_.reset(new CooldownEvent(cb, user_data));
+    return cooldown_event_->Subscribe();
+  }
+
+  bool AppStatusChangedEventSubscribe(aul_app_status_changed_cb cb,
+      void* user_data) {
+    std::lock_guard<std::recursive_mutex> lock(mutex_);
+    if (cb == nullptr) {
+      app_status_changed_event_.reset();
+      return true;
+    }
+
+    app_status_changed_event_.reset(new AppStatusChangedEvent(cb, user_data));
+    return app_status_changed_event_->Subscribe();
+  }
+
+ private:
+  std::recursive_mutex mutex_;
+  std::unique_ptr<AppDeadEvent> app_dead_event_;
+  std::unique_ptr<AppLaunchEvent> app_launch_event_;
+  std::unique_ptr<AppLaunchEvent2> app_launch_event2_;
+  std::unique_ptr<BootingDoneEvent> booting_done_event_;
+  std::unique_ptr<CooldownEvent> cooldown_event_;
+  std::unique_ptr<AppStatusChangedEvent> app_status_changed_event_;
+};
+
+AppSignalContext context;
+
+bool EmitSignal(const std::string& object_path,
+    const std::string& interface_name, const std::string& signal_name,
+    GVariant* parameters) {
+  GError* err = nullptr;
+  auto* conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &err);
+  if (conn == nullptr) {
+    _E("g_bus_get_sync() is failed. error(%s)", err ? err->message : "");
+    g_clear_error(&err);
+    return false;
+  }
+  std::unique_ptr<GDBusConnection, decltype(g_object_unref)*> conn_auto(
+      conn, g_object_unref);
+
+  if (!g_dbus_connection_emit_signal(conn, nullptr, object_path.c_str(),
+        interface_name.c_str(), signal_name.c_str(), parameters, &err)) {
+    _E("g_dbus_connection_emit_signal() is failed. error(%s)",
+        err ? err->message : "");
+    g_clear_error(&err);
+    return false;
+  }
+
+  if (!g_dbus_connection_flush_sync(conn, nullptr, &err)) {
+    _E("g_dbus_connection_flush_sync() is failed. error(%s)",
+        err ? err->message : "");
+    g_clear_error(&err);
+    return false;
+  }
+
+  return true;
+}
+
+bool SendMessage(const std::string& name, const std::string& path,
+    const std::string& interface, const std::string& method, GVariant* body) {
+  GError* err = nullptr;
+  auto* conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &err);
+  if (conn == nullptr) {
+    _E("g_bus_get_sync() is failed. error(%s)", err ? err->message : "");
+    g_clear_error(&err);
+    return false;
+  }
+  std::unique_ptr<GDBusConnection, decltype(g_object_unref)*> conn_auto(
+      conn, g_object_unref);
+
+  auto* msg = g_dbus_message_new_method_call(name.c_str(), path.c_str(),
+      interface.c_str(), method.c_str());
+  if (msg == nullptr) {
+    _E("g_dbus_message_new_method_call() is failed");
+    return false;
+  }
+  std::unique_ptr<GDBusMessage, decltype(g_object_unref)*> msg_auto(
+      msg, g_object_unref);
+
+  g_dbus_message_set_body(msg, body);
+  g_dbus_connection_send_message_with_reply(conn, msg,
+      G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, nullptr, nullptr,
+      [](GObject* source_object, GAsyncResult* res, gpointer user_data) {
+        auto* conn = static_cast<GDBusConnection*>(user_data);
+        int result;
+        GError* err = nullptr;
+        auto* reply = g_dbus_connection_send_message_with_reply_finish(conn,
+            res, &err);
+        if (reply == nullptr) {
+          _E("No reply. error(%s)", err ? err->message : "");
+          result = -1;
+        } else {
+          result = 0;
+        }
+
+        g_clear_error(&err);
+        if (reply != nullptr)
+          g_object_unref(reply);
+        if (conn != nullptr)
+          g_object_unref(conn);
+
+        _I("Result: %d", result);
+      }, conn);
+  conn_auto.release();
+  return true;
+}
+
+}  // namespace
+
+extern "C" API int aul_listen_app_dead_signal(aul_app_dead_event_cb callback,
+    void* user_data) {
+  if (!context.AppDeadEventSubscribe(callback, user_data))
+    return AUL_R_ERROR;
+
+  return AUL_R_OK;
+}
+
+extern "C" API int aul_listen_app_launch_signal(
+    aul_app_launch_event_cb callback, void* user_data) {
+  if (!context.AppLaunchEventSubscribe(callback, user_data))
+    return AUL_R_ERROR;
+
+  return AUL_R_OK;
+}
+
+extern "C" API int aul_listen_app_launch_signal_v2(
+    aul_app_launch_event_cb_v2 callback, void* user_data) {
+  if (!context.AppLaunchEvent2Subscribe(callback, user_data))
+    return AUL_R_ERROR;
+
+  return AUL_R_OK;
+}
+
+extern "C" API int aul_listen_booting_done_signal(
+    aul_booting_done_event_cb callback, void* user_data) {
+  _W("DEPRECATION WARNING: %s() is deprecated and will be remove from next release.", __FUNCTION__);
+  if (!context.BootingDoneEventSubscribe(callback, user_data))
+    return AUL_R_ERROR;
+
+  return AUL_R_OK;
+}
+
+extern "C" API int aul_listen_cooldown_signal(aul_cooldown_event_cb callback,
+    void *user_data) {
+  _W("DEPRECATION WARNING: %s() is deprecated and will be remove from next release.", __FUNCTION__);
+  if (!context.CooldownEventSubscribe(callback, user_data))
+    return AUL_R_ERROR;
+
+  return AUL_R_OK;
+}
+
+extern "C" API int aul_listen_app_status_signal(
+    aul_app_status_changed_cb callback, void *user_data) {
+  if (!context.AppStatusChangedEventSubscribe(callback, user_data))
+    return AUL_R_ERROR;
+
+  return AUL_R_OK;
+}
+
+extern "C" API int aul_update_freezer_status(int pid, const char* type) {
+  if (pid <= 1 || type == nullptr) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  GVariant* body = g_variant_new("(si)", type, pid);
+  if (body == nullptr) {
+    _E("Out of memory");
+    return AUL_R_ENOMEM;
+  }
+
+  if (!SendMessage(RESOURCED_BUS_NAME, RESOURCED_PROC_PATH,
+        RESOURCED_PROC_INTERFACE, RESOURCED_PROC_METHOD, body)) {
+    g_variant_unref(body);
+    return AUL_R_ERROR;
+  }
+
+  return AUL_R_OK;
+}
+
+extern "C" API int aul_send_app_launch_request_signal(int pid,
+    const char* appid, const char* pkgid, const char* type) {
+  if (pid <= 1 || appid == nullptr || pkgid == nullptr || type == nullptr) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  GVariant* parameters = g_variant_new("(isss)", pid, appid, pkgid, type);
+  if (parameters == nullptr) {
+    _E("Out of memory");
+    return AUL_R_ENOMEM;
+  }
+
+  if (!EmitSignal(AUL_APP_STATUS_DBUS_PATH,
+        AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE,
+        AUL_APP_STATUS_DBUS_LAUNCH_REQUEST, parameters)) {
+    g_variant_unref(parameters);
+    return AUL_R_ERROR;
+  }
+
+  return AUL_R_OK;
+}
+
+extern "C" API int aul_send_app_resume_request_signal(int pid,
+    const char* appid, const char* pkgid, const char* type) {
+  if (pid <= 1) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  if (appid == nullptr)
+    appid = "";
+  if (pkgid == nullptr)
+    pkgid = "";
+  if (type == nullptr)
+    type = "";
+
+  GVariant* parameters = g_variant_new("(isss)", pid, appid, pkgid, type);
+  if (parameters == nullptr) {
+    _E("Out of memory");
+    return AUL_R_ENOMEM;
+  }
+
+  if (!EmitSignal(AUL_APP_STATUS_DBUS_PATH,
+        AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE,
+        AUL_APP_STATUS_DBUS_RESUME_REQUEST, parameters)) {
+    g_variant_unref(parameters);
+    return AUL_R_ERROR;
+  }
+
+  return AUL_R_OK;
+}
+
+extern "C" API int aul_send_app_terminate_request_signal(int pid,
+    const char* appid, const char* pkgid, const char* type) {
+  if (pid <= 1) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  if (appid == nullptr)
+    appid = "";
+  if (pkgid == nullptr)
+    pkgid = "";
+  if (type == nullptr)
+    type = "";
+
+  GVariant* parameters = g_variant_new("(isss)", pid, appid, pkgid, type);
+  if (parameters == nullptr) {
+    _E("Out of memory");
+    return AUL_R_ENOMEM;
+  }
+
+  if (!EmitSignal(AUL_APP_STATUS_DBUS_PATH,
+        AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE,
+        AUL_APP_STATUS_DBUS_TERMINATE_REQUEST, parameters)) {
+    g_variant_unref(parameters);
+    return AUL_R_ERROR;
+  }
+
+  return AUL_R_OK;
+}
+
+extern "C" API int aul_send_app_status_change_signal(int pid,
+    const char* appid, const char* pkgid, const char* status,
+    const char* type) {
+  if (pid <= 1 || status == nullptr) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  if (appid == nullptr)
+    appid = "";
+  if (pkgid == nullptr)
+    pkgid = "";
+  if (type == nullptr)
+    type = "";
+
+  GVariant* parameters = g_variant_new("(issss)",
+      pid, appid, pkgid, status, type);
+  if (parameters == nullptr) {
+    _E("Out of memory");
+    return AUL_R_ENOMEM;
+  }
+
+  if (!EmitSignal(AUL_APP_STATUS_DBUS_PATH,
+        AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE,
+        AUL_APP_STATUS_DBUS_STATUS_CHANGE, parameters)) {
+    g_variant_unref(parameters);
+    return AUL_R_ERROR;
+  }
+
+  return AUL_R_OK;
+}
+
+extern "C" API int aul_send_app_terminated_signal(int pid) {
+  if (pid <= 1) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  GVariant* parameters = g_variant_new("(i)", pid);
+  if (parameters == nullptr) {
+    _E("Out of memory");
+    return AUL_R_ENOMEM;
+  }
+
+  if (!EmitSignal(AUL_APP_STATUS_DBUS_PATH,
+        AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE,
+        AUL_APP_STATUS_DBUS_TERMINATED, parameters)) {
+    g_variant_unref(parameters);
+    return AUL_R_ERROR;
+  }
+
+  return AUL_R_OK;
+}
+
+extern "C" API int aul_send_app_group_signal(int owner_pid, int child_pid,
+    const char* child_pkgid) {
+  if (owner_pid <= 1 || child_pid <= 1) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  if (child_pkgid == nullptr)
+    child_pkgid = "";
+
+  GVariant* parameters = g_variant_new("(iis)",
+      owner_pid, child_pid, child_pkgid);
+  if (parameters == nullptr) {
+    _E("Out of memory");
+    return AUL_R_ENOMEM;
+  }
+
+  if (!EmitSignal(AUL_APP_STATUS_DBUS_PATH,
+        AUL_APP_STATUS_DBUS_SIGNAL_INTERFACE,
+        AUL_APP_STATUS_DBUS_GROUP, parameters)) {
+    g_variant_unref(parameters);
+    return AUL_R_ERROR;
+  }
+
+  return AUL_R_OK;
+}