Add new APIs for sending/receiving diagnostics events 52/248952/20
authorKonrad Kuchciak <k.kuchciak@samsung.com>
Mon, 30 Nov 2020 10:37:21 +0000 (11:37 +0100)
committerKonrad Kuchciak <k.kuchciak@samsung.com>
Tue, 16 Mar 2021 07:42:11 +0000 (08:42 +0100)
Change-Id: Ib318c6a3f6fbdee1538caf2be22719af25a89509
Signed-off-by: Konrad Kuchciak <k.kuchciak@samsung.com>
CMakeLists.txt
doc/diagnostics_doc.h
include/diagnostics.h
packaging/diagnostics.spec
src/library/CMakeLists.txt
src/library/dbus.c
src/library/dbus.h
src/library/diagnostics.c
src/library/signal.c [deleted file]
src/library/signal.h [deleted file]

index a7eb9c851eaf5ba8b98946cbce9305feb682361d..7d4112694752191999e48e4c594253afa4c60b26 100644 (file)
@@ -1,7 +1,7 @@
 CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
 PROJECT(diagnostics LANGUAGES C)
 SET(target ${PROJECT_NAME})
-SET(dependency "glib-2.0 gio-unix-2.0 dlog dumpsys capi-system-info")
+SET(dependency "glib-2.0 gio-unix-2.0 dlog dumpsys dumpsys-system bugreport capi-system-info bundle aul")
 # ADD_DEFINITIONS(-Wall -Werror -Wextra)
 
 # Options
@@ -20,11 +20,11 @@ ADD_SUBDIRECTORY(src/library)
 
 # cmocka tasts and coverage
 option(ENABLE_COVERAGE "Measure the coverage and generate report" OFF)
-option(ENABLE_TESTS "Run unit tests after build" ON)
-if(ENABLE_TESTS OR ENABLE_COVERAGE)
+option(ENABLE_TESTS "Run unit tests after build" OFF)
+if(ENABLE_TESTS)
        FIND_PACKAGE(CMocka CONFIG REQUIRED)
        enable_testing()
        include(CTest)
        INCLUDE_DIRECTORIES(${LIBCMOCKA_INCLUDE_DIR})
        ADD_SUBDIRECTORY(src/test)
-endif(ENABLE_TESTS OR ENABLE_COVERAGE)
+endif(ENABLE_TESTS)
index 561feb15a159c73252edd476709d67e040268fab..f0a16a07e7eed1233c378926636317bd09821845 100644 (file)
 /**
  * @ingroup   CAPI_SYSTEM_FRAMEWORK
  * @defgroup  CAPI_SYSTEM_DIAGNOSTICS_MODULE Diagnostics
- * @brief     The @ref CAPI_SYSTEM_DIAGNOSTICS_MODULE API provides functions to receive crash reports and request logs from other apps.
+ * @brief     The @ref CAPI_SYSTEM_DIAGNOSTICS_MODULE API provides functions to send and receive diagnostic events and data from other applications/services.
  *
  * @section   CAPI_SYSTEM_DIAGNOSTICS_MODULE_HEADER Required Header
  *            \#include <diagnostics.h>
  *
  * @section   CAPI_SYSTEM_DIAGNOSTICS_MODULE_OVERVIEW Overview
- * This @ref CAPI_SYSTEM_DIAGNOSTICS_MODULE API allows applications to receive notification about newly created crash report,
- * as well as request other apps to dump their logs in real time. Moreover, functions for reading crash and log contents are provided.
+ * This @ref CAPI_SYSTEM_DIAGNOSTICS_MODULE API allows applications to exchange diagnostic information.
+ *
+ * Client - a program using this API. In case of applications, client ID is set to the application ID, but services must set their ID explicitly using diagnostics_set_client_id().
+ *
+ * Provider - a client that sends diagnostic events or serves diagnostic data.
+ *
+ * Subscriber - a client that subscribes to diagnostic events or requests diagnostic data.
+ *
+ * Event - simple signal sent to all subscribed clients. \n
+ * Event may be sent with additional data (bundle). \n
+ * There is a diagnostic context associated with the event, which holds information about sender (client ID), event name and event data.
+ *
+ * Data - any data, logs or files sent by providers via this API (dumpsys underneath). \n
+ * Subscribers may specify additional parameters when requesting diagnostic data. Based on this parameters, providers send appropriate data.
+ *
+ * Bugreport - diagnostic report created on demand with diagnostics_request_bugreport(). \n
+ * Bugreport may be process-specific (when pid argument is given) or system-specific (when pid <= 0).
  *
  * @section   CAPI_SYSTEM_DIAGNOSTICS_MODULE_FEATURE Realted Features
  *
  * This API is related with the following feature:\n
  * - %http://tizen.org/feature/diagnostics\n
  *
- * It is recommended to design feature related codes in your application for reliability.\n
+ * It is recommended to use features in your application for reliability. \n
  *
- * You can check if a device supports the related features for this API by using @ref CAPI_SYSTEM_SYSTEM_INFO_MODULE,thereby controlling the procedure of your application.\n
+ * You can check if the device supports the related features for this API by using System Information, and control your application's actions accordingly. \n
  *
- * To ensure your application is only running on the device with specific features, please define the features in your manifest file using the manifest editor in the SDK.\n
+ * To ensure your application is running only on devices with specific features, please define the features in your manifest file using the manifest editor in the SDK.
  *
- * More details on featuring your application can be found from <a href="https://docs.tizen.org/application/tizen-studio/native-tools/manifest-text-editor#feature-element"><b>Feature Element</b>.</a>
+ * More details on using features in your application can be found in the <a href="https://developer.tizen.org/development/tizen-studio/native-tools/configuring-your-app/manifest-text-editor#feature"><b>feature element description</b></a>.
  */
index 3db30e71605505eb6c1d49eb5eecac9b70eb0950..c97045a60e45e8e604195bcb0f0f9ed0dcfc1586 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <stdio.h>
 #include <tizen.h>
+#include <bundle.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -58,9 +59,9 @@ typedef enum {
 } diagnostics_error_e;
 
 /**
- * @brief Notification callback fired when new bug report arrives.
+ * @brief Notification callback fired when new diagnostics event arrives.
  * @since_tizen 6.0
- * @remarks @a ctx should be released with diagnostics_destroy()
+ * @remarks @a ctx should be released with diagnostics_destroy().
  *
  * @param[in] ctx Diagnostics context handle
  * @param[in] user_data The user data passed from the callback registration function
@@ -68,8 +69,27 @@ typedef enum {
 typedef void(*diagnostics_notification_cb)(diagnostics_ctx_h ctx, void *user_data);
 
 /**
- * @brief Sets the callback for bug report notification.
+ * @brief Request callback fired when someone requests diagnostics data.
+ * @since_tizen 6.5
+ * @remarks @a data should be released with diagnostics_data_destroy().
+ *
+ * @param[in] data Diagnostics data handle
+ * @param[in] params Array of request's parameters \n
+ *            This array is owned by @a data, so it is available until @a data is released \n
+ *            @a params are the same as passed to diagnostics_request_client_data() or diagnostics_get_data()
+ * @param[in] params_size Number of parameters
+ * @param[in] ctx Diagnostics context handling an event that the request is related to \n
+ *            @a ctx is available when data has been requested with diagnostics_get_data() \n
+ *            @a ctx is NULL when data has been requested with diagnostics_request_client_data() \n
+ *            This parameter allows diagnostics client to find diagnostics data related to the specific event
+ * @param[in] user_data The user data passed from the callback registration function
+ */
+typedef void (*diagnostics_request_cb)(diagnostics_data_h data, char **params, int params_size, diagnostics_ctx_h ctx, void *user_data);
+
+/**
+ * @brief Sets the callback for diagnostics event notification.
  * @since_tizen 6.0
+ * @remarks This function is dedicated to diagnostic information subscribers.
  *
  * @param[in] callback A callback function to set
  * @param[in] user_data The user data to be passed to the callback function
@@ -79,32 +99,152 @@ typedef void(*diagnostics_notification_cb)(diagnostics_ctx_h ctx, void *user_dat
  * @retval #DIAGNOSTICS_ERROR_NOT_SUPPORTED Not supported
  * @retval #DIAGNOSTICS_ERROR_INVALID_PARAMETER Provided parameter is invalid
  * @retval #DIAGNOSTICS_ERROR_RESOURCE_BUSY Callback already registered
- * @retval #DIAGNOSTICS_ERROR_IO_ERROR Internal error occured
+ * @retval #DIAGNOSTICS_ERROR_IO_ERROR Internal error occurred
+ *
+ * @code
+ * #include <diagnostics.h>
+ *
+ * static void notification_handler(diagnostics_ctx_h ctx, void *user_data)
+ * {
+ *     // Process diagnostics event
+ *
+ *     diagnostics_destroy(ctx);
+ * }
+ *
+ * static GMainLoop *mainloop = NULL;
+ *
+ * int main(int argc, char **argv)
+ * {
+ *     diagnostics_set_notification_cb(notification_handler, NULL);
+ *     diagnostics_subscribe_event("ConnectionBroken", "org.tizen.someapp");
+ *
+ *     mainloop = g_main_loop_new(NULL, FALSE);
+ *     g_main_loop_run(mainloop);
+ * }
+ *
+ * @endcode
  */
 int diagnostics_set_notification_cb(diagnostics_notification_cb callback, void *user_data);
 
 /**
- * @brief Unsets the callback for bug report notification.
+ * @brief Unsets the callback for diagnostics event notification.
  * @since_tizen 6.0
- * 
+ * @remarks This function is dedicated to diagnostic information subscribers. \n
+ * It clears all the events added with diagnostics_subscribe_event().
+ *
  * @return 0 on success, otherwise a negative error value
  * @retval #DIAGNOSTICS_ERROR_NONE Success
  * @retval #DIAGNOSTICS_ERROR_NOT_SUPPORTED Not supported
- * @retval #DIAGNOSTICS_ERROR_IO_ERROR Internal error occured
+ * @retval #DIAGNOSTICS_ERROR_IO_ERROR Internal error occurred
  */
 int diagnostics_unset_notification_cb(void);
 
 /**
  * @platform
- * @brief Requests client to dump data.
+ * @brief Subscribes to an event sent by diagnostics client.
+ * @since_tizen 6.5
+ * @privlevel platform
+ * @privilege
+ * @remarks This function is dedicated to diagnostic information subscribers. \n
+ * It is permitted only to an app signed by platform level certificates.
+ *
+ * @param[in] event_name Event name \n
+ *            Its length is limited to 255 characters + null terminator
+ * @param[in] client_id The ID of the diagnostics client (event sender) \n
+ *            Its length is limited to 255 characters + null terminator
+ *
+ * @return 0 on success, otherwise a negative error value
+ * @retval #DIAGNOSTICS_ERROR_NONE Success
+ * @retval #DIAGNOSTICS_ERROR_NOT_SUPPORTED Not supported
+ * @retval #DIAGNOSTICS_ERROR_PERMISSION_DENIED Permission denied
+ * @retval #DIAGNOSTICS_ERROR_INVALID_PARAMETER Provided parameter is invalid
+ * @retval #DIAGNOSTICS_ERROR_IO_ERROR Internal error occurred
+ * @retval #DIAGNOSTICS_ERROR_OUT_OF_MEMORY Out of memory
+ */
+int diagnostics_subscribe_event(const char *event_name, const char *client_id);
+
+/**
+ * @platform
+ * @brief Sets the callback for diagnostics data request.
+ * @since_tizen 6.5
+ * @privlevel platform
+ * @privilege
+ * @remarks This function is dedicated to diagnostic information providers. \n
+ * It is permitted only to an app signed by platform level certificates.
+ *
+ * @param[in] callback A callback function to set
+ * @param[in] user_data The user data to be passed to the callback function
+ *
+ * @return 0 on success, otherwise a negative error value
+ * @retval #DIAGNOSTICS_ERROR_NONE Success
+ * @retval #DIAGNOSTICS_ERROR_NOT_SUPPORTED Not supported
+ * @retval #DIAGNOSTICS_ERROR_PERMISSION_DENIED Permission denied
+ * @retval #DIAGNOSTICS_ERROR_INVALID_PARAMETER Provided parameter is invalid or the caller ID not set (required for system services only)
+ * @retval #DIAGNOSTICS_ERROR_RESOURCE_BUSY Callback already registered
+ * @retval #DIAGNOSTICS_ERROR_IO_ERROR Internal error occurred
+ *
+ * @code
+ * #include <diagnostics.h>
+ *
+ * static void data_request_cb(diagnostics_data_h data, char **params, int params_size, diagnostics_ctx_h ctx, void *user_data)
+ * {
+ *     const char *buf = "Some data";
+ *     size_t bytes_written;
+ *
+ *     diagnostics_data_write(data, buf, sizeof(buf)/sizeof(char), &bytes_written);
+ *
+ *     diagnostics_data_destroy(data);
+ * }
+ *
+ * static GMainLoop *mainloop = NULL;
+ *
+ * int main(int argc, char **argv)
+ * {
+ *     diagnostics_data_h data;
+ *
+ *     // This is required for services only, not applications
+ *     diagnostics_set_client_id("diagnostics-client");
+ *
+ *     diagnostics_set_data_request_cb(data_request_cb, NULL);
+ *
+ *     mainloop = g_main_loop_new(NULL, FALSE);
+ *     g_main_loop_run(mainloop);
+ * }
+ *
+ * @endcode
+ */
+int diagnostics_set_data_request_cb(diagnostics_request_cb callback, void *user_data);
+
+/**
+ * @platform
+ * @brief Unsets the callback for diagnostics data request.
+ * @since_tizen 6.5
+ * @privlevel platform
+ * @privilege
+ * @remarks This function is dedicated to diagnostic information providers. \n
+ * It is permitted only to an app signed by platform level certificates.
+ *
+ * @return 0 on success, otherwise a negative error value
+ * @retval #DIAGNOSTICS_ERROR_NONE Success
+ * @retval #DIAGNOSTICS_ERROR_NOT_SUPPORTED Not supported
+ * @retval #DIAGNOSTICS_ERROR_PERMISSION_DENIED Permission denied
+ * @retval #DIAGNOSTICS_ERROR_IO_ERROR Internal error occurred
+ */
+int diagnostics_unset_data_request_cb(void);
+
+/**
+ * @platform
+ * @brief Requests diagnostics client to dump data.
  * @since_tizen 6.0
  * @privlevel platform
  * @privilege
- * @remarks @a data should be released with diagnostics_data_destroy().
- * This function is permitted only to an app signed by platform level certificates.
+ * @remarks This function is dedicated to diagnostic information subscribers. \n
+ * It is permitted only to an app signed by platform level certificates. \n
+ * @a data should be released with diagnostics_data_destroy().
  *
- * @param[in] client_id An id of app or service to request
- * @param[in] params Array of parameters
+ * @param[in] client_id An ID of application or service to request
+ * @param[in] params Array of parameters \n
+ *                   Refer to specific diagnostics client's documentation for available parameters
  * @param[in] params_size Number of parameters
  * @param[out] data Dumpsys data handle
  *
@@ -113,86 +253,329 @@ int diagnostics_unset_notification_cb(void);
  * @retval #DIAGNOSTICS_ERROR_NOT_SUPPORTED Not supported
  * @retval #DIAGNOSTICS_ERROR_PERMISSION_DENIED Permission denied
  * @retval #DIAGNOSTICS_ERROR_INVALID_PARAMETER Provided parameter is invalid
- * @retval #DIAGNOSTICS_ERROR_IO_ERROR Internal error occured
+ * @retval #DIAGNOSTICS_ERROR_IO_ERROR Internal error occurred
  * @retval #DIAGNOSTICS_ERROR_OUT_OF_MEMORY Not enough memory to create data handle
+ *
+ * @code
+ * #include <diagnostics.h>
+ *
+ * int main(int argc, char **argv)
+ * {
+ *     diagnostics_data_h data;
+ *     const char *params[] = {"foo", "bar", "baz"};
+ *     char buf[1000];
+ *     size_t bytes_read;
+ *
+ *     diagnostics_request_client_data("diagnostics-client", params, sizeof(params)/sizeof(char*), &data);
+ *
+ *     while (true) {
+ *         diagnostics_data_read(data, buf, sizeof(buf)/sizeof(char), -1, &bytes_read);
+ *         if (bytes_read == 0) // Reached EOF
+ *             break;
+ *
+ *         // Process the chunk of data
+ *     }
+ *
+ *     diagnostics_data_destroy(data);
+ * }
+ *
+ * @endcode
  */
 int diagnostics_request_client_data(const char *client_id, const char **params, int params_size, diagnostics_data_h *data);
 
+/**
+ * @platform
+ * @brief Requests diagnostics context's provider to dump data.
+ * @since_tizen 6.0
+ * @privlevel platform
+ * @privilege
+ * @remarks This function is dedicated to diagnostic information subscribers. \n
+ * It is permitted only to an app signed by platform level certificates. \n
+ * @a data should be released with diagnostics_data_destroy(). \n
+ * The difference between this function and diagnostics_request_client_data() is that
+ * this function sends back the whole context to the context's provider to help it find the data specific to the generated event.
+ *
+ * @param[in] ctx Diagnostics context handle
+ * @param[in] params Array of parameters \n
+ *                   Refer to specific diagnostics client's documentation for available parameters
+ * @param[in] params_size Number of parameters
+ * @param[out] data Diagnostics data handle
+ *
+ * @return 0 on success, otherwise a negative error value
+ * @retval #DIAGNOSTICS_ERROR_NONE Success
+ * @retval #DIAGNOSTICS_ERROR_NOT_SUPPORTED Not supported
+ * @retval #DIAGNOSTICS_ERROR_PERMISSION_DENIED Permission denied
+ * @retval #DIAGNOSTICS_ERROR_INVALID_PARAMETER Provided parameter is invalid
+ * @retval #DIAGNOSTICS_ERROR_IO_ERROR Internal error occurred
+ * @retval #DIAGNOSTICS_ERROR_OUT_OF_MEMORY Not enough memory to create data handle
+ *
+ * @code
+ *
+ * void notification_handler(diagnostics_ctx_h ctx, void *user_data)
+ * {
+ *     diagnostics_data_h data;
+ *     const char *params[] = {"foo", "bar", "baz"};
+ *
+ *     // Request more data from the client that the event came from
+ *     diagnostics_get_data(ctx, params, sizeof(params)/sizeof(char*), &data);
+ *
+ *     // Read data
+ *
+ *     diagnostics_data_destroy(data);
+ *     diagnostics_destroy(ctx);
+ * }
+ *
+ * @endcode
+ */
+int diagnostics_get_data(diagnostics_ctx_h ctx, const char **params, int params_size, diagnostics_data_h *data);
+
+/**
+ * @brief Gets a file descriptor for diagnostics data.
+ * @since_tizen 6.5
+ * @remarks This function provides a file descriptor to read/write diagnostic data in a custom way
+ * instead of using our diagnostics_data_read() and diagnostics_data_write() functions. \n
+ * Moreover, keep in mind that reading is allowed for diagnostic data subscribers and writing is allowed for providers.
+ * @param[in] data Diagnostics data handle
+ * @param[in,out] fd A file descriptor related to diagnostics data
+ *
+ * @return 0 on success, otherwise a negative error value
+ * @retval #DIAGNOSTICS_ERROR_NONE Success
+ * @retval #DIAGNOSTICS_ERROR_NOT_SUPPORTED Not supported
+ * @retval #DIAGNOSTICS_ERROR_INVALID_PARAMETER Provided parameter is invalid
+ */
+int diagnostics_data_get_fd(diagnostics_data_h data, int *fd);
+
 /**
  * @brief Reads diagnostics data.
  * @since_tizen 6.0
- * @remarks @a data should be released with diagnostics_data_destroy().
- *          This function is intended for use in loop until EOF is reached.
- *          EOF is when @a bytes_read == 0 and function returns #DIAGNOSTICS_ERROR_NONE.
+ * @remarks This function is dedicated to diagnostic information subscribers. \n
+ * It is intended for use in loop until EOF is reached. EOF is when @a bytes_read == 0 and function returns #DIAGNOSTICS_ERROR_NONE.
+ *
  * @param[in] data Diagnostics data handle
  * @param[in,out] buf Buffer to store read data \n
- *                    Provided buffer must be large enough to contain @a count number of bytes
+ *                    Provided buffer must be large enough to contain @a count number of bytes
  * @param[in] count Number of bytes to read
  * @param[in] timeout_ms Timeout [ms] for reading requested number of bytes (timeout_ms <= 0 means to wait forever)
- * @param[out] bytes_read Real number of read bytes
+ * @param[out] bytes_read Real number of bytes read
  *
  * @return 0 on success, otherwise a negative error value
  * @retval #DIAGNOSTICS_ERROR_NONE Success
  * @retval #DIAGNOSTICS_ERROR_NOT_SUPPORTED Not supported
  * @retval #DIAGNOSTICS_ERROR_INVALID_PARAMETER Provided parameter is invalid
- * @retval #DIAGNOSTICS_ERROR_TIMED_OUT Timeout occured
+ * @retval #DIAGNOSTICS_ERROR_TIMED_OUT Timeout occurred
  * @retval #DIAGNOSTICS_ERROR_TRY_AGAIN Try again
- * @retval #DIAGNOSTICS_ERROR_IO_ERROR Internal error occured while trying to read data, result is unspecified and *bytes_read is not updated
+ * @retval #DIAGNOSTICS_ERROR_IO_ERROR Internal error occurred while trying to read data, result is unspecified and *bytes_read is not updated
  */
 int diagnostics_data_read(diagnostics_data_h data, void *buf, size_t count, int timeout_ms, size_t *bytes_read);
 
 /**
- * @brief Frees diagnostics data.
- * @since_tizen 6.0
+ * @brief Writes diagnostics data.
+ * @since_tizen 6.5
+ * @remarks This function is dedicated to diagnostic information providers. \n
+ * Data is being written to the special file descriptor and then copied to the diagnostic information subscriber's endpoint.
  *
  * @param[in] data Diagnostics data handle
+ * @param[in] buf Buffer with data to write \n
+ *                Provided buffer must be of size not less than a @a count number of bytes
+ * @param[in] count Number of bytes to write
+ * @param[out] bytes_written Real number of bytes written
  *
  * @return 0 on success, otherwise a negative error value
  * @retval #DIAGNOSTICS_ERROR_NONE Success
  * @retval #DIAGNOSTICS_ERROR_NOT_SUPPORTED Not supported
  * @retval #DIAGNOSTICS_ERROR_INVALID_PARAMETER Provided parameter is invalid
+ * @retval #DIAGNOSTICS_ERROR_TRY_AGAIN Try again
+ * @retval #DIAGNOSTICS_ERROR_IO_ERROR Internal error occurred while trying to write data, result is unspecified and *bytes_written is not updated
  */
-int diagnostics_data_destroy(diagnostics_data_h data);
+int diagnostics_data_write(diagnostics_data_h data, const void *buf, size_t count, size_t *bytes_written);
+
+/**
+ * @platform
+ * @brief Sends diagnostics event.
+ * @since_tizen 6.5
+ * @privlevel platform
+ * @privilege
+ * @remarks This function is dedicated to diagnostic information providers. \n
+ * It is permitted only to an app signed by platform level certificates.
+ *
+ * @param[in] event_name Diagnostics event name
+ * @param[in] event_data Event data or NULL.
+ *
+ * @return 0 on success, otherwise a negative error value
+ * @retval #DIAGNOSTICS_ERROR_NONE Success
+ * @retval #DIAGNOSTICS_ERROR_NOT_SUPPORTED Not supported
+ * @retval #DIAGNOSTICS_ERROR_PERMISSION_DENIED Permission denied
+ * @retval #DIAGNOSTICS_ERROR_INVALID_PARAMETER Provided parameter is invalid or the caller ID not set (required for system services only)
+ * @retval #DIAGNOSTICS_ERROR_IO_ERROR Internal error occurred
+ *
+ * @code
+ *
+ * int main(int argc, char *argv[])
+ * {
+ *     bundle *event_data = bundle_create();
+ *
+ *     // This is required for services only, not applications
+ *     diagnostics_set_client_id("diagnostics-client");
+ *
+ *     bundle_add_str(event_data, "somekey", "somevalue");
+ *     diagnostics_send_event("ConnectionBroken", event_data);
+ *
+ *     bundle_free(event_data);
+ * }
+ *
+ * @endcode
+ */
+int diagnostics_send_event(const char *event_name, bundle *event_data);
 
 /**
- * @brief Gets diagnostics context provider's id.
+ * @brief Gets diagnostics client ID (event sender).
  * @since_tizen 6.0
- * @remarks @a client_id should be released with free().
+ * @remarks This function is dedicated to diagnostic information subscribers. \n
+ * @a client_id should be released with free().
  *
  * @param[in] ctx Diagnostics context handle
- * @param[out] client_id An id of the context provider
+ * @param[out] client_id ID of the diagnostics client
  *
  * @return 0 on success, otherwise a negative error value
  * @retval #DIAGNOSTICS_ERROR_NONE Success
  * @retval #DIAGNOSTICS_ERROR_NOT_SUPPORTED Not supported
  * @retval #DIAGNOSTICS_ERROR_INVALID_PARAMETER Provided parameter is invalid
+ *
+ * @code
+ *
+ * void notification_handler(diagnostics_ctx_h ctx, void *user_data)
+ * {
+ *     char *client_id;
+ *
+ *     diagnostics_get_client_id(ctx, &client_id);
+ *
+ *     // Process diagnostics event
+ *
+ *     free(client_id);
+ *     diagnostics_destroy(ctx);
+ * }
+ *
+ * @endcode
  */
 int diagnostics_get_client_id(diagnostics_ctx_h ctx, char **client_id);
 
+/**
+ * @brief Gets diagnostics event name.
+ * @since_tizen 6.5
+ * @remarks This function is dedicated to diagnostic information subscribers. \n
+ * @a event_name should be released with free().
+ *
+ * @param[in] ctx Diagnostics context handle
+ * @param[out] event_name Name of the diagnostics event
+ *
+ * @return 0 on success, otherwise a negative error value
+ * @retval #DIAGNOSTICS_ERROR_NONE Success
+ * @retval #DIAGNOSTICS_ERROR_NOT_SUPPORTED Not supported
+ * @retval #DIAGNOSTICS_ERROR_INVALID_PARAMETER Provided parameter is invalid
+ *
+ * @code
+ *
+ * void notification_handler(diagnostics_ctx_h ctx, void *user_data)
+ * {
+ *     char *event_name;
+ *
+ *     diagnostics_get_event_name(ctx, &event_name);
+ *
+ *     // Process diagnostics event
+ *
+ *     free(event_name);
+ *     diagnostics_destroy(ctx);
+ * }
+ *
+ * @endcode
+ */
+int diagnostics_get_event_name(diagnostics_ctx_h ctx, char **event_name);
+
+/**
+ * @brief Gets diagnostics event data.
+ * @since_tizen 6.5
+ * @remarks This function is dedicated to diagnostic information subscribers. \n
+ * @a event_data should be released with bundle_free().
+ *
+ * @param[in] ctx Diagnostics context handle
+ * @param[out] event_data Data that came with the diagnostics event (may be NULL when no data has been provided)
+ *
+ * @return 0 on success, otherwise a negative error value
+ * @retval #DIAGNOSTICS_ERROR_NONE Success
+ * @retval #DIAGNOSTICS_ERROR_NOT_SUPPORTED Diagnostics feature is missing or the function has been called by application, not system service
+ * @retval #DIAGNOSTICS_ERROR_INVALID_PARAMETER Provided parameter is invalid
+ *
+ * @code
+ *
+ * void notification_handler(diagnostics_ctx_h ctx, void *user_data)
+ * {
+ *     bundle *event_data;
+ *
+ *     diagnostics_get_event_data(ctx, &event_data);
+ *
+ *     // Process diagnostics event
+ *
+ *     bundle_free(event_data);
+ *     diagnostics_destroy(ctx);
+ * }
+ *
+ * @endcode
+ */
+int diagnostics_get_event_data(diagnostics_ctx_h ctx, bundle **event_data);
+
+/**
+ * @brief Sets the diagnostics client ID.
+ * @since_tizen 6.5
+ * @remarks This function is dedicated to diagnostic information providers. \n
+ * As services do not have any name associated with them, ID must be set explicitly with this function before calling any of the following functions: \n
+ * diagnostics_set_data_request_cb() \n
+ * diagnostics_send_event() \n
+ * diagnostics_request_bugreport() \n
+ * For applications, client ID is set to the application ID and cannot be changed.
+ *
+ * @param[in] client_id Diagnostics client ID to set.
+ *
+ * @return 0 on success, otherwise a negative error value
+ * @retval #DIAGNOSTICS_ERROR_NONE Success
+ * @retval #DIAGNOSTICS_ERROR_NOT_SUPPORTED Not supported
+ * @retval #DIAGNOSTICS_ERROR_INVALID_PARAMETER Provided parameter is invalid
+ * @retval #DIAGNOSTICS_ERROR_RESOURCE_BUSY Client ID has already been set, not possible to change
+ * @retval #DIAGNOSTICS_ERROR_IO_ERROR Internal error occurred
+ */
+int diagnostics_set_client_id(const char *client_id);
+
 /**
  * @platform
- * @brief Gets report data.
- * @since_tizen 6.0
+ * @brief Requests bugreport creation.
+ * @since_tizen 6.5
  * @privlevel platform
- * @privilege
- * @remarks @a data should be released with diagnostics_data_destroy().
- * This function is permitted only to an app signed by platform level certificates.
+ * @privilege http://tizen.org/privilege/bugreport.admin
+ * @remarks This function is dedicated to diagnostic information subscribers. \n
+ * To get bugreport's content, user must subscribe to 'BugreportCreated' diagnostics event, which is sent by crash-service after creating the report.
  *
- * @param[in] ctx Diagnostics context handle
- * @param[in] params Array of parameters \n
- *                   Refer to context provider's documentation for available parameters
- * @param[in] params_size Number of parameters
- * @param[out] data Diagnostics data handle
+ * @param[in] pid ID of a process that should be livedumped. When @a pid <= 0, system-wide bugreport is created.
  *
  * @return 0 on success, otherwise a negative error value
  * @retval #DIAGNOSTICS_ERROR_NONE Success
  * @retval #DIAGNOSTICS_ERROR_NOT_SUPPORTED Not supported
  * @retval #DIAGNOSTICS_ERROR_PERMISSION_DENIED Permission denied
+ * @retval #DIAGNOSTICS_ERROR_INVALID_PARAMETER Provided parameter is invalid or the caller ID not set (required for system services only)
+ * @retval #DIAGNOSTICS_ERROR_IO_ERROR Internal error occurred
+ */
+int diagnostics_request_bugreport(int pid);
+
+/**
+ * @brief Frees diagnostics data.
+ * @since_tizen 6.0
+ *
+ * @param[in] data Diagnostics data handle
+ *
+ * @return 0 on success, otherwise a negative error value
+ * @retval #DIAGNOSTICS_ERROR_NONE Success
+ * @retval #DIAGNOSTICS_ERROR_NOT_SUPPORTED Not supported
  * @retval #DIAGNOSTICS_ERROR_INVALID_PARAMETER Provided parameter is invalid
- * @retval #DIAGNOSTICS_ERROR_IO_ERROR Internal error occured
- * @retval #DIAGNOSTICS_ERROR_OUT_OF_MEMORY Not enough memory to create data handle
  */
-int diagnostics_get_data(diagnostics_ctx_h ctx, const char **params, int params_size, diagnostics_data_h *data);
+int diagnostics_data_destroy(diagnostics_data_h data);
 
 /**
  * @brief Frees diagnostics context.
index dfd4865a68bd93ed17a9aa14ceee2aa416fac55d..323205dfa415b21ed420689c8e129e3a7b4629d7 100644 (file)
@@ -12,7 +12,11 @@ BuildRequires:  pkgconfig(glib-2.0)
 BuildRequires:  pkgconfig(gio-unix-2.0)
 BuildRequires:  pkgconfig(dlog)
 BuildRequires:  pkgconfig(dumpsys)
+BuildRequires:  pkgconfig(dumpsys-system)
+BuildRequires:  pkgconfig(bugreport)
 BuildRequires:  pkgconfig(capi-system-info)
+BuildRequires:  pkgconfig(bundle)
+BuildRequires:  pkgconfig(aul)
 BuildRequires:  glib2-devel
 %if 0%{?gcov:1}
 BuildRequires:  lcov
index 1fef613493bf9c3e5a614fa5fd768d075028f787..51240189c85a9ca02e96237e97da66ea06817057 100644 (file)
@@ -4,7 +4,7 @@ AUX_SOURCE_DIRECTORY(. SOURCES)
 
 # Build
 ADD_LIBRARY(${target} SHARED ${SOURCES})
-SET_TARGET_PROPERTIES(${target} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS} -fPIE")
+SET_TARGET_PROPERTIES(${target} PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS} -fPIC")
 SET_TARGET_PROPERTIES(${target} PROPERTIES LINK_FLAGS "-pie")
 SET_TARGET_PROPERTIES(${target} PROPERTIES SOVERSION ${MAJORVER})
 SET_TARGET_PROPERTIES(${target} PROPERTIES VERSION ${FULLVER})
@@ -12,7 +12,7 @@ TARGET_LINK_LIBRARIES(${target} ${pkgs_LDFLAGS})
 
 ADD_LIBRARY(${target}_static STATIC ${SOURCES})
 TARGET_INCLUDE_DIRECTORIES(${target}_static PRIVATE ${CMAKE_SOURCE_DIR}/src/library)
-TARGET_COMPILE_OPTIONS(${target}_static BEFORE PRIVATE -include ../test/test_diagnostics_add_function_defs.h)
+TARGET_COMPILE_OPTIONS(${target}_static BEFORE PRIVATE -include ../test/test_diagnostics_add_function_defs.h)
 TARGET_COMPILE_DEFINITIONS(${target}_static PUBLIC -DUNIT_TEST)
 if(ENABLE_COVERAGE)
 TARGET_COMPILE_OPTIONS(${target}_static PUBLIC -g -fprofile-arcs -ftest-coverage)
index e92f870c7793788a04d7b2c1dc453dd9584e6a84..e6b5b68ffc607c0cac099a18a7af2940671fb5f6 100644 (file)
@@ -19,8 +19,6 @@
 #include "dbus.h"
 #include "log.h"
 
-static int subscription_id = 0;
-
 static GDBusConnection *dbus_connect()
 {
        GDBusConnection *conn;
@@ -36,7 +34,10 @@ static GDBusConnection *dbus_connect()
        return conn;
 }
 
-int dbus_subscribe(void (*signal_handler)(GDBusConnection *,
+int dbus_subscribe(const char *interface_name,
+                                  const char *object_path,
+                                  const char *member_name,
+                                  void (*signal_handler)(GDBusConnection *,
                                                                                  const gchar *,
                                                                                  const gchar *,
                                                                                  const gchar *,
@@ -52,140 +53,70 @@ int dbus_subscribe(void (*signal_handler)(GDBusConnection *,
 
        ret = g_dbus_connection_signal_subscribe(conn,
                                                                                         NULL,
-                                                                                        NULL,
-                                                                                        DBUS_MEMBER_CRASH,
-                                                                                        NULL,
+                                                                                        interface_name,
+                                                                                        member_name,
+                                                                                        object_path,
                                                                                         NULL,
                                                                                         G_DBUS_SIGNAL_FLAGS_NONE,
                                                                                         signal_handler,
                                                                                         NULL,
                                                                                         NULL);
        if (ret == FALSE) {
-               _E("Unable to subscribe to crash signal");
+               _E("g_dbus_connection_signal_subscribe() failed");
                return -EIO;
        }
 
-       subscription_id = ret;
-
-       return 0;
+       return ret;
 }
 
-void dbus_unsubscribe(void)
+void dbus_unsubscribe(int subscription_id)
 {
        GDBusConnection *conn = dbus_connect();
 
        if (!conn)
                return;
 
-       if (subscription_id)
+       if (subscription_id > 0)
                g_dbus_connection_signal_unsubscribe(conn, subscription_id);
-
-       subscription_id = 0;
 }
 
-int dbus_get_file_from_report(const char *report_path, const int entry, int *fd)
+int dbus_send_signal(const char *interface_name,
+                                        const char *object_path,
+                                        const char *signal_name,
+                                        GVariant *parameters)
 {
-       GDBusConnection *conn = dbus_connect();
-       GDBusMessage *message = NULL;
-       GDBusMessage *reply = NULL;
-       GVariant *parameters = NULL;
-       GUnixFDList *fd_list = NULL;
-       GError *error = NULL;
-       int fd_out = -1;
+       GError *err = NULL;
+       gchar *parameters_str = parameters ? g_variant_print(parameters, TRUE) : NULL;
        int ret = -1;
 
+       GDBusConnection *conn = dbus_connect();
        if (!conn)
-               goto finish;
-
-       message = g_dbus_message_new_method_call(DBUS_BUS_NAME,
-                                                                                       DBUS_OBJECT_PATH,
-                                                                                       DBUS_INTERFACE_NAME,
-                                                                                       DBUS_METHOD_GET_FILE);
-       parameters = g_variant_new("(si)", report_path, entry);
-       g_dbus_message_set_body(message, parameters);
-
-       reply = g_dbus_connection_send_message_with_reply_sync(conn,
-                               message,
-                               G_DBUS_SEND_MESSAGE_FLAGS_NONE,
-                               10000,
-                               NULL,
-                               NULL,
-                               &error);
-
-       // _D("MESSAGE: \n%s", g_dbus_message_print(message, 4));
-       // _D("REPLY: \n%s", g_dbus_message_print(reply, 4));
-
-       if (reply != NULL && g_dbus_message_get_message_type(reply) == G_DBUS_MESSAGE_TYPE_ERROR)
-               g_dbus_message_to_gerror(reply, &error);
-
-       if (error != NULL) {
-               _E("Send message error: %s\n", error ? error->message : "unknown error");
-               ret = error->code == G_DBUS_ERROR_ACCESS_DENIED ? -EACCES : -1;
-               goto finish;
-       }
-
-       fd_list = g_dbus_message_get_unix_fd_list(reply);
-       if (!fd_list) {
-               _E("Method call get_file() haven't returned file descriptor");
+               goto cleanup;
+
+       ret = g_dbus_connection_emit_signal(conn,           /* connection */
+                                                                               NULL,           /* destination_bus_name */
+                                                                               object_path,    /* object_path */
+                                                                               interface_name, /* interface_name */
+                                                                               signal_name,    /* signal_name */
+                                                                               parameters,     /* parameters */
+                                                                               &err);          /* error */
+       if (ret == FALSE) {
+               _E("g_dbus_connection_emit_signal() failed: %s", err->message);
+               g_error_free(err);
                ret = -1;
-               goto finish;
+               goto cleanup;
        }
 
-       fd_out = g_unix_fd_list_get(fd_list, 0, &error);
-       if (fd_out == -1 || error) {
-               _E("g_unix_fd_list_get() failed: %s", error ? error->message : "");
-               ret = -1;
-               goto finish;
-       }
+       _D("Sent signal\n"
+          "    interface_name: %s\n"
+          "    object_path: %s\n"
+          "    signal_name: %s\n"
+          "    parameters: %s\n",
+          interface_name, object_path, signal_name, parameters_str);
 
        ret = 0;
 
-finish:
-       *fd = fd_out;
-       if (parameters)
-               g_variant_unref(parameters);
-       if (message)
-               g_object_unref(message);
-       if (reply)
-               g_object_unref(reply);
-       if (error)
-               g_error_free(error);
+cleanup:
+       g_free(parameters_str);
        return ret;
 }
-
-struct dbus_signal_s *dbus_signal_create(const gchar *sender_name,
-                                                                               const gchar *object_path,
-                                                                               const gchar *interface_name,
-                                                                               const gchar *signal_name,
-                                                                               GVariant *parameters)
-{
-       struct dbus_signal_s *signal;
-
-       signal = calloc(1, sizeof(struct dbus_signal_s));
-       if (!signal) {
-               _E("Unable to allocate memory");
-               return NULL;
-       }
-
-       signal->sender_name = g_strdup(sender_name);
-       signal->object_path = g_strdup(object_path);
-       signal->interface_name = g_strdup(interface_name);
-       signal->signal_name = g_strdup(signal_name);
-       signal->parameters = parameters;
-       g_variant_ref(signal->parameters);
-
-       return signal;
-}
-
-void dbus_signal_cleanup(struct dbus_signal_s *signal)
-{
-       if (!signal)
-               return;
-
-       g_free(signal->sender_name);
-       g_free(signal->object_path);
-       g_free(signal->interface_name);
-       g_free(signal->signal_name);
-       g_variant_unref(signal->parameters);
-       free(signal);
-}
index 5b01f38ac14d6f64a609bf45f75cbdb02561a259..2940984f304ae7bc3a935ccc431d782cb0437c3b 100644 (file)
 #ifndef __DBUS_H__
 #define __DBUS_H__
 
-#define DBUS_MEMBER_CRASH "ProcessCrashedEx"
-#define DBUS_SENDER_CRASH "org.tizen.system.crash"
-
-#define DBUS_BUS_NAME "org.tizen.system.diagnostics"
-#define DBUS_OBJECT_PATH "/Org/Tizen/System/Diagnostics"
-#define DBUS_INTERFACE_NAME DBUS_BUS_NAME
-#define DBUS_METHOD_GET_FILE "get_file"
+#define DBUS_EVENT_INTERFACE_NAME "org.tizen.system.diagnostics.event"
+#define DBUS_EVENT_OBJECT_PATH "/Org/Tizen/System/Diagnostics/Event"
 
 #include <gio/gio.h>
-#include <gio/gunixfdlist.h>
 #include <glib.h>
 
-struct dbus_signal_s {
-       gchar *sender_name;
-       gchar *object_path;
-       gchar *interface_name;
-       gchar *signal_name;
-       GVariant *parameters;
-};
-
-int dbus_subscribe(void (*signal_handler)(GDBusConnection *,
+int dbus_subscribe(const char *interface_name,
+                                  const char *object_path,
+                                  const char *member_name,
+                                  void (*signal_handler)(GDBusConnection *,
                                                                                  const gchar *,
                                                                                  const gchar *,
                                                                                  const gchar *,
                                                                                  const gchar *,
                                                                                  GVariant *,
                                                                                  gpointer));
-void dbus_unsubscribe(void);
-int dbus_get_file_from_report(const char *report_path, const int entry, int *fd);
-struct dbus_signal_s *dbus_signal_create(const gchar *sender_name,
-                                                                                const gchar *object_path,
-                                                                                const gchar *interface_name,
-                                                                                const gchar *signal_name,
-                                                                                GVariant *parameters);
-void dbus_signal_cleanup(struct dbus_signal_s *signal);
+void dbus_unsubscribe(int subscription_id);
+
+int dbus_send_signal(const char *interface_name,
+                                        const char *object_path,
+                                        const char *signal_name,
+                                        GVariant *parameters);
 
 #endif /* __DBUS_H__ */
index e9dc5159f86a093d941a898baa803ac6f53c9ec0..203a42bbf190e96285f6fb2df003911fb6d5da01 100644 (file)
 #include <gio/gio.h>
 #include <glib.h>
 #include <libdumpsys.h>
+#include <dumpsys-system.h>
+#include <libbugreport.h>
 #include <poll.h>
+#include <bundle.h>
+#include <aul.h>
+#include <limits.h>
 
 #include "log.h"
 #include "signal.h"
 #include "dbus.h"
 
 #ifndef STATIC
-#define STATIC
-       static
+#define STATIC static
 #endif
 
 #define DIAGNOSTICS_FEATURE "http://tizen.org/feature/diagnostics"
 #define FEATURE_FALSE    0
 #define FEATURE_TRUE     1
 
-STATIC struct _diagnostics_cb_info_s {
-       diagnostics_notification_cb cb;
-       void *user_data;
-} cb_info = {
-       NULL,
-       NULL
-};
+#define MAX_EVENT_NAME_LEN 255
+#define MAX_CLIENT_ID_LEN 255
+#define MAX_INT_DIGITS 11
 
 struct _diagnostics_ctx_s {
        char *client_id;
-       struct dbus_signal_s *signal;
-       signal_type_e signal_type;
+       char *event_name;
+       bundle *event_data;
 };
 
 struct _diagnostics_data_s {
        int fd;
+       char **params;
+       int params_size;
+};
+
+struct _diagnostics_event_s {
+       char *event_name;
+       char *client_id;
+       int subscription_id;
+};
+
+STATIC struct _diagnostics_notification_cb_info_s {
+       diagnostics_notification_cb cb;
+       void *user_data;
+       struct _diagnostics_event_s **events;
+       int events_count;
+} notification_cb_info = {
+       NULL,
+       NULL,
+       NULL,
+       0
 };
 
+STATIC struct _dumpsys_cb_info_s {
+       diagnostics_request_cb cb;
+       void *user_data;
+       void *handler;
+} dumpsys_cb_info = {
+       NULL,
+       NULL,
+       NULL
+};
+
+enum _ctx_params {
+       CTX_PARAM_MAGIC_TOKEN = -5,
+       CTX_PARAM_CLIENT_ID = -4,
+       CTX_PARAM_EVENT_NAME = -3,
+       CTX_PARAM_EVENT_DATA_RAW = -2,
+       CTX_PARAM_EVENT_DATA_LEN = -1,
+       CTX_PARAM_LEN = 5
+};
+
+/*
+ * This magic_token is just a random string
+ * and is used to split user parameters and auto-added
+ * context parameters in dumpsys dump request
+ */
+STATIC char *magic_token = "4IJJSPh1CqITvhgm9KAg";
+
+STATIC char app_id[MAX_CLIENT_ID_LEN + 1] = {0, };
+STATIC char service_name[MAX_CLIENT_ID_LEN + 1] = {0, };
+
 STATIC int diagnostics_feature = FEATURE_UNKNOWN;
 
 STATIC bool __is_feature_supported(void)
@@ -72,11 +121,45 @@ STATIC bool __is_feature_supported(void)
        return (diagnostics_feature == FEATURE_TRUE ? true : false);
 }
 
-STATIC struct _diagnostics_ctx_s *diagnostics_create(struct dbus_signal_s *signal)
+STATIC bool is_app()
 {
-       RETV_IF(signal == NULL, NULL);
+       int ret;
 
-       struct _diagnostics_ctx_s *ctx;
+       if (app_id[0])
+               return true;
+
+       ret = aul_app_get_appid_bypid(getpid(), app_id, sizeof(app_id));
+       if (ret)
+               return false;
+
+       return true;
+}
+
+STATIC char *get_client_id()
+{
+       if (is_app())
+               return app_id;
+
+       if (service_name[0])
+               return service_name;
+
+       _E("Client ID not set, first call diagnostics_set_client_id()");
+       return NULL;
+}
+
+STATIC void diagnostics_event_destroy(struct _diagnostics_event_s *event)
+{
+       free(event->event_name);
+       free(event->client_id);
+       free(event);
+}
+
+STATIC struct _diagnostics_ctx_s *diagnostics_create(const char *client_id, const char *event_name, bundle *event_data)
+{
+       RETV_IF(client_id == NULL, NULL);
+       RETV_IF(event_name == NULL, NULL);
+
+       struct _diagnostics_ctx_s *ctx = NULL;
 
        ctx = calloc(1, sizeof(struct _diagnostics_ctx_s));
        if (!ctx) {
@@ -84,22 +167,67 @@ STATIC struct _diagnostics_ctx_s *diagnostics_create(struct dbus_signal_s *signa
                return NULL;
        }
 
-       if (signal->signal_name && strcmp(signal->signal_name, DBUS_MEMBER_CRASH) == 0) {
-               ctx->client_id = DBUS_SENDER_CRASH;
-               ctx->signal_type = signal_is_valid_crash(signal) ? SIG_TYPE_CRASH : SIG_TYPE_INVALID;
-       } else {
-               _E("Unknown signal name");
-               free(ctx);
+       ctx->client_id = strndup(client_id, MAX_CLIENT_ID_LEN);
+       if (!ctx->client_id) {
+               _E("Unable to allocate memory");
+               diagnostics_destroy(ctx);
+               return NULL;
+       }
+
+       ctx->event_name = strndup(event_name, MAX_EVENT_NAME_LEN);
+       if (!ctx->event_name) {
+               _E("Unable to allocate memory");
+               diagnostics_destroy(ctx);
+               return NULL;
+       }
+
+       ctx->event_data = event_data;
+
+       return ctx;
+}
+
+STATIC struct _diagnostics_ctx_s *diagnostics_create_from_params(char **params, int params_size)
+{
+       if (params == NULL || params_size < CTX_PARAM_LEN)
+               return NULL;
+
+       struct _diagnostics_ctx_s *ctx = NULL;
+       bundle *event_data = NULL;
+       int event_data_len = 0;
+
+       if (strncmp(params[params_size + CTX_PARAM_MAGIC_TOKEN], magic_token, strlen(magic_token)) != 0)
+               return NULL;
+
+       errno = 0;
+       event_data_len = (int) strtol(params[params_size + CTX_PARAM_EVENT_DATA_LEN], NULL, 10);
+       if (event_data_len < 0 || errno != 0) {
+               _E("Unable to convert raw bundle size to int");
+               return NULL;
+       }
+
+       if (event_data_len > 0) {
+               event_data = bundle_decode((const bundle_raw *) params[params_size + CTX_PARAM_EVENT_DATA_RAW], event_data_len);
+               if (!event_data) {
+                       _E("Unable to decode bundle");
+                       return NULL;
+               }
+       }
+
+       ctx = diagnostics_create(params[params_size + CTX_PARAM_CLIENT_ID], params[params_size + CTX_PARAM_EVENT_NAME], event_data);
+       if (!ctx) {
+               _E("Unable to create ctx");
+               bundle_free(event_data);
                return NULL;
        }
 
-       ctx->signal = signal;
        return ctx;
 }
 
-STATIC struct _diagnostics_data_s *diagnostics_data_create(int fd)
+STATIC struct _diagnostics_data_s *diagnostics_data_create(int fd, char **params, int params_size)
 {
        RETV_IF(fd < 0, NULL);
+       RETV_IF(params == NULL && params_size != 0, NULL);
+       RETV_IF(params_size < 0, NULL);
 
        struct _diagnostics_data_s *data;
 
@@ -110,49 +238,93 @@ STATIC struct _diagnostics_data_s *diagnostics_data_create(int fd)
        }
 
        data->fd = fd;
+
+       data->params = calloc(params_size, sizeof(char*));
+       if (!data->params) {
+               _E("Unable to allocate memory");
+               free(data);
+               return NULL;
+       }
+
+       for (int i = 0; i < params_size; i++) {
+               data->params[i] = strdup(params[i]);
+               if (!data->params[i]) {
+                       _E("Unable to allocate memory");
+                       diagnostics_data_destroy(data);
+                       return NULL;
+               }
+               data->params_size = i + 1;
+       }
+
        return data;
 }
 
 STATIC void 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)
+                                                  const gchar *sender_name,
+                                                  const gchar *object_path,
+                                                  const gchar *interface_name,
+                                                  const gchar *signal_name,
+                                                  GVariant *parameters,
+                                                  gpointer user_data)
 {
        struct _diagnostics_ctx_s *ctx;
-       struct dbus_signal_s *signal;
-
-       _D("signal_handler");
-       _D("parameters: %s", g_variant_print(parameters, TRUE));
-
-       if (!cb_info.cb) {
+       struct _diagnostics_event_s *event = NULL;
+       bundle *event_data = NULL;
+       char *event_data_raw = NULL;
+       char *client_id = NULL;
+       int event_data_len;
+
+       _D("Received signal\n"
+          "    sender: %s\n"
+          "    objpath: %s\n"
+          "    interface: %s\n"
+          "    member: %s\n"
+          "    parameters: %s\n",
+          sender_name, object_path, interface_name, signal_name, g_variant_print(parameters, TRUE));
+
+       if (!notification_cb_info.cb) {
                _E("No user cb set");
                return;
        }
 
-       _D("dbus_signal_create");
-       signal = dbus_signal_create(sender_name,
-                                                               object_path,
-                                                               interface_name,
-                                                               signal_name,
-                                                               parameters);
-       if (!signal) {
-               _E("Unable to create signal structure");
-               return;
+       g_variant_get(parameters, "(ssi)", &client_id, &event_data_raw, &event_data_len);
+
+       /* Check if the event comes from the right client */
+       for (int i = 0; i < notification_cb_info.events_count; i++) {
+               if (strncmp(notification_cb_info.events[i]->event_name, signal_name, MAX_EVENT_NAME_LEN) == 0 &&
+                       strncmp(notification_cb_info.events[i]->client_id, client_id, MAX_CLIENT_ID_LEN) == 0) {
+
+                       event = notification_cb_info.events[i];
+                       break;
+               }
+       }
+
+       if (!event) {
+               _W("Cannot find (event_name, client_id) pair in subscribed events, ignoring event");
+               goto cleanup;
+       }
+
+       if (strlen(event_data_raw) > 0) {
+               event_data = bundle_decode((const bundle_raw *) event_data_raw, event_data_len);
+               if (!event_data) {
+                       _E("Unable to decode bundle");
+                       goto cleanup;
+               }
        }
 
-       _D("diagnostics_create");
-       ctx = diagnostics_create(signal);
+       ctx = diagnostics_create(event->client_id, event->event_name, event_data);
        if (!ctx) {
                _E("Unable to create diagnostics context");
-               dbus_signal_cleanup(signal);
-               return;
+               bundle_free(event_data);
+               goto cleanup;
        }
 
-       _D("Fireing user cb!");
-       cb_info.cb(ctx, cb_info.user_data);
+       _D("Fireing notification cb");
+       notification_cb_info.cb(ctx, notification_cb_info.user_data);
+
+cleanup:
+       free(client_id);
+       free(event_data_raw);
 }
 
 int diagnostics_set_notification_cb(diagnostics_notification_cb callback, void *user_data)
@@ -160,51 +332,276 @@ int diagnostics_set_notification_cb(diagnostics_notification_cb callback, void *
        RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
        RETV_IF(callback == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
 
+       if (notification_cb_info.cb) {
+               _E("Notification callback has already been set");
+               return DIAGNOSTICS_ERROR_RESOURCE_BUSY;
+       }
+
+       notification_cb_info.cb = callback;
+       notification_cb_info.user_data = user_data;
+
+       return DIAGNOSTICS_ERROR_NONE;
+}
+
+int diagnostics_unset_notification_cb(void)
+{
+       RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
+
+       for (int i = 0; i < notification_cb_info.events_count; i++) {
+               dbus_unsubscribe(notification_cb_info.events[i]->subscription_id);
+               diagnostics_event_destroy(notification_cb_info.events[i]);
+       }
+       free(notification_cb_info.events);
+
+       notification_cb_info.cb = NULL;
+       notification_cb_info.user_data = NULL;
+       notification_cb_info.events = NULL;
+       notification_cb_info.events_count = 0;
+
+       return DIAGNOSTICS_ERROR_NONE;
+}
+
+int diagnostics_send_event(const char *event_name, bundle *event_data)
+{
+       RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
+       RETV_IF(event_name == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
+
+       char *client_id;
+       GVariant *parameters = NULL;
+       bundle_raw *event_data_raw = NULL;
+       int event_data_len = 0;
+       int ret;
+
+       client_id = get_client_id();
+       if (!client_id)
+               return DIAGNOSTICS_ERROR_INVALID_PARAMETER;
+
+       if (event_data) {
+               ret = bundle_encode(event_data, &event_data_raw, &event_data_len);
+               if (ret) {
+                       _E("Unable to encode bundle: %d", ret);
+                       return DIAGNOSTICS_ERROR_IO_ERROR;
+               }
+       }
+
+       parameters = g_variant_new("(ssi)", client_id, event_data_raw ? (char *) event_data_raw : "", event_data_len);
+       free(event_data_raw);
+
+       ret = dbus_send_signal(DBUS_EVENT_INTERFACE_NAME, DBUS_EVENT_OBJECT_PATH, event_name, parameters);
+       if (ret) {
+               _E("Unable to send dbus signal: %d", ret);
+               return DIAGNOSTICS_ERROR_IO_ERROR;
+       }
+
+       return DIAGNOSTICS_ERROR_NONE;
+}
+
+int diagnostics_subscribe_event(const char *event_name, const char *client_id)
+{
+       RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
+       RETV_IF(event_name == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
+       RETV_IF(client_id == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
+
+       struct _diagnostics_event_s *event;
        int ret;
 
-       _D("diagnostics_set_notification_cb()");
+       /* Create new event structure */
+       event = calloc(1, sizeof(struct _diagnostics_event_s));
+       if (!event) {
+               _E("Unable to allocate memory");
+               return DIAGNOSTICS_ERROR_OUT_OF_MEMORY;
+       }
+
+       event->client_id = strndup(client_id, MAX_CLIENT_ID_LEN);
+       if (!event->client_id) {
+               _E("Unable to allocate memory");
+               diagnostics_event_destroy(event);
+               return DIAGNOSTICS_ERROR_OUT_OF_MEMORY;
+       }
+
+       event->event_name = strndup(event_name, MAX_EVENT_NAME_LEN);
+       if (!event->event_name) {
+               _E("Unable to allocate memory");
+               diagnostics_event_destroy(event);
+               return DIAGNOSTICS_ERROR_OUT_OF_MEMORY;
+       }
+
+       /* Add event to registered events */
+       notification_cb_info.events = realloc(notification_cb_info.events,
+                                                                                 (notification_cb_info.events_count + 1) * sizeof(struct _diagnostics_event_s *));
+       if (!notification_cb_info.events) {
+               _E("Unable to allocate memory");
+               diagnostics_event_destroy(event);
+               return DIAGNOSTICS_ERROR_OUT_OF_MEMORY;
+       }
+
+       notification_cb_info.events[notification_cb_info.events_count++] = event;
+
+       ret = dbus_subscribe(DBUS_EVENT_INTERFACE_NAME, DBUS_EVENT_OBJECT_PATH, event_name, signal_handler);
+       if (ret <= 0) {
+               _E("Unable to subscribe to dbus signal: %d", ret);
+               diagnostics_event_destroy(event);
+               notification_cb_info.events_count--;
+               return DIAGNOSTICS_ERROR_IO_ERROR;
+       }
+
+       event->subscription_id = ret;
+
+       return DIAGNOSTICS_ERROR_NONE;
+}
+
+STATIC int dumpsys_handler(const int fd, const int argc, char **argv)
+{
+       struct _diagnostics_data_s *data;
+       struct _diagnostics_ctx_s *ctx = NULL;
+
+       _D("dumpsys_handler");
+       _D("argc: %d", argc);
+       for (int i = 0; i < argc; i++)
+               _D("argv[%d]: %s", i, argv[i]);
 
-       if (cb_info.cb) {
-               _E("Callback has already been set");
+       if (!dumpsys_cb_info.cb) {
+               _E("No data request cb set");
+               return -1;
+       }
+
+       /* Create ctx if is shipped with dumpsys parameters (last 5) */
+       ctx = diagnostics_create_from_params(argv, argc);
+
+       data = diagnostics_data_create(fd, argv, ctx ? argc - CTX_PARAM_LEN : argc);
+       if (data == NULL) {
+               _E("Unable to create diagnostics_data");
+               return -1;
+       }
+
+       _D("Fireing dumpsys cb");
+       dumpsys_cb_info.cb(data, data->params, data->params_size, ctx, dumpsys_cb_info.user_data);
+
+       return 0;
+}
+
+int diagnostics_set_data_request_cb(diagnostics_request_cb callback, void *user_data)
+{
+       RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
+       RETV_IF(callback == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
+
+       char *client_id;
+       int ret;
+
+       if (dumpsys_cb_info.cb) {
+               _E("Data request callback has already been set");
                return DIAGNOSTICS_ERROR_RESOURCE_BUSY;
        }
 
-       ret = dbus_subscribe(signal_handler);
+       client_id = get_client_id();
+       if (!client_id)
+               return DIAGNOSTICS_ERROR_INVALID_PARAMETER;
+
+       ret = dumpsys_system_register_dump_cb(dumpsys_handler, client_id, &dumpsys_cb_info.handler);
        if (ret) {
-               _E("Unable to subscribe to dbus signals");
+               _E("dumpsys_system_register_dump_cb failed: %d", ret);
                return DIAGNOSTICS_ERROR_IO_ERROR;
        }
 
-       cb_info.cb = callback;
-       cb_info.user_data = user_data;
+       dumpsys_cb_info.cb = callback;
+       dumpsys_cb_info.user_data = user_data;
 
        return DIAGNOSTICS_ERROR_NONE;
 }
 
-int diagnostics_unset_notification_cb(void)
+int diagnostics_unset_data_request_cb(void)
 {
        RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
 
-       _D("diagnostics_unset_notification_cb()");
+       int ret = dumpsys_system_unregister_dump_cb(dumpsys_cb_info.handler);
+       if (ret) {
+               _E("dumpsys_system_unregister_dump_cb failed: %d", ret);
+               return DIAGNOSTICS_ERROR_IO_ERROR;
+       }
 
-       cb_info.cb = NULL;
-       cb_info.user_data = NULL;
+       dumpsys_cb_info.cb = NULL;
+       dumpsys_cb_info.user_data = NULL;
+       dumpsys_cb_info.handler = NULL;
 
-       dbus_unsubscribe();
        return DIAGNOSTICS_ERROR_NONE;
 }
 
-int diagnostics_request_client_data(const char *client_id, const char **params, int params_size, diagnostics_data_h *data)
+STATIC int _diagnostics_request_client_data(const char *client_id, const char **params, int params_size, diagnostics_data_h *data, struct _diagnostics_ctx_s *ctx)
 {
        RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
        RETV_IF(client_id == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
+       RETV_IF(params == NULL && params_size != 0, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
        RETV_IF(params_size < 0, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
        RETV_IF(data == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
 
+       const char *params_empty[] = {0};
+       char **_params = NULL;
+       int _params_size;
+       bundle_raw *event_data_raw = NULL;
+       int event_data_len = 0;
+       char len_str[MAX_INT_DIGITS];
        int fd = -1;
        int ret;
 
-       ret = dumpsys_dump(client_id, params_size, params, &fd);
+       if (ctx) {
+               /* We are going to append 5 more parameters to store ctx:
+               *
+               * magic_token
+               * ctx->client_id
+               * ctx->event_name
+               * event_data_raw
+               * event_data_len
+               *
+               */
+
+               _params_size = params_size + CTX_PARAM_LEN;
+
+               _params = calloc(_params_size, sizeof(char *));
+               if (!_params) {
+                       _E("Unable to allocate memory");
+                       return DIAGNOSTICS_ERROR_OUT_OF_MEMORY;
+               }
+
+               if (ctx->event_data) {
+                       ret = bundle_encode(ctx->event_data, &event_data_raw, &event_data_len);
+                       if (ret) {
+                               _E("Unable to encode bundle: %d", ret);
+                               free(_params);
+                               return DIAGNOSTICS_ERROR_IO_ERROR;
+                       }
+               }
+
+               ret = snprintf(len_str, MAX_INT_DIGITS, "%d", event_data_len);
+               if (ret < 0) {
+                       _E("snprintf() failed: %d", ret);
+                       return DIAGNOSTICS_ERROR_IO_ERROR;
+               }
+
+               for (int i = 0; i < params_size; i++)
+                       _params[i] = (char *) params[i];
+
+               _params[_params_size + CTX_PARAM_MAGIC_TOKEN] = magic_token;
+               _params[_params_size + CTX_PARAM_CLIENT_ID] = ctx->client_id;
+               _params[_params_size + CTX_PARAM_EVENT_NAME] = ctx->event_name;
+               _params[_params_size + CTX_PARAM_EVENT_DATA_RAW] = event_data_raw ? (char *) event_data_raw : "";
+               _params[_params_size + CTX_PARAM_EVENT_DATA_LEN] = len_str;
+
+               _D("_params_size: %d", _params_size);
+               for (int i = 0; i < _params_size; i++)
+                       _D("_params[%d]: %s", i, _params[i]);
+
+       } else {
+               _params = (char **) (params ? params : params_empty);
+               _params_size = params_size;
+       }
+
+       ret = dumpsys_dump(client_id, _params_size, (const char **) _params, &fd);
+
+       if (ctx) {
+               free(event_data_raw);
+               free(_params);
+       }
+
        if (ret != DIAGNOSTICS_ERROR_NONE) {
                _E("dumpsys_dump() failed: %d", ret);
                if (ret == TIZEN_ERROR_PERMISSION_DENIED)
@@ -212,7 +609,7 @@ int diagnostics_request_client_data(const char *client_id, const char **params,
                return DIAGNOSTICS_ERROR_IO_ERROR;
        }
 
-       *data = diagnostics_data_create(fd);
+       *data = diagnostics_data_create(fd, (char **) params, params_size);
        if (*data == NULL) {
                _E("Unable to create diagnostics_data");
                return DIAGNOSTICS_ERROR_OUT_OF_MEMORY;
@@ -221,6 +618,29 @@ int diagnostics_request_client_data(const char *client_id, const char **params,
        return DIAGNOSTICS_ERROR_NONE;
 }
 
+int diagnostics_request_client_data(const char *client_id, const char **params, int params_size, diagnostics_data_h *data)
+{
+       return _diagnostics_request_client_data(client_id, params, params_size, data, NULL);
+}
+
+int diagnostics_get_data(diagnostics_ctx_h ctx, const char **params, int params_size, diagnostics_data_h *data)
+{
+       RETV_IF(ctx == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
+
+       return _diagnostics_request_client_data(((struct _diagnostics_ctx_s *)ctx)->client_id, params, params_size, data, ctx);
+}
+
+int diagnostics_data_get_fd(diagnostics_data_h data, int *fd)
+{
+       RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
+       RETV_IF(data == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
+       RETV_IF(fd == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
+
+       *fd = ((struct _diagnostics_data_s *)data)->fd;
+
+       return DIAGNOSTICS_ERROR_NONE;
+}
+
 int diagnostics_data_read(diagnostics_data_h data, void *buf, size_t count, int timeout_ms, size_t *bytes_read)
 {
        RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
@@ -230,7 +650,7 @@ int diagnostics_data_read(diagnostics_data_h data, void *buf, size_t count, int
 
        struct pollfd poll_fd;
        int ready;
-       int ret;
+       int ret, e;
 
        poll_fd.fd = ((struct _diagnostics_data_s *)data)->fd;
        poll_fd.events = POLLIN;
@@ -250,8 +670,9 @@ int diagnostics_data_read(diagnostics_data_h data, void *buf, size_t count, int
        if (poll_fd.revents & POLLIN) {
                ret = read(poll_fd.fd, buf, count);
                if (ret < 0) {
+                       e = errno;
                        _E("read() failed: %m, fd: %d", poll_fd.fd);
-                       if (errno == EAGAIN)
+                       if (e == EAGAIN)
                                return DIAGNOSTICS_ERROR_TRY_AGAIN;
                        return DIAGNOSTICS_ERROR_IO_ERROR;
                }
@@ -266,91 +687,120 @@ int diagnostics_data_read(diagnostics_data_h data, void *buf, size_t count, int
        return DIAGNOSTICS_ERROR_IO_ERROR;
 }
 
+int diagnostics_data_write(diagnostics_data_h data, const void *buf, size_t count, size_t *bytes_written)
+{
+       RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
+       RETV_IF(data == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
+       RETV_IF(buf == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
+       RETV_IF(bytes_written == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
+
+       struct _diagnostics_data_s *_data = (struct _diagnostics_data_s *) data;
+       int ret, e;
+
+       ret = write(_data->fd, buf, count);
+       if (ret < 0) {
+               e = errno;
+               _E("write() failed: %m, fd: %d", _data->fd);
+               if (e == EAGAIN)
+                       return DIAGNOSTICS_ERROR_TRY_AGAIN;
+               return DIAGNOSTICS_ERROR_IO_ERROR;
+       }
+       *bytes_written = ret;
+
+       return DIAGNOSTICS_ERROR_NONE;
+}
+
 int diagnostics_get_client_id(diagnostics_ctx_h ctx, char **client_id)
 {
        RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
        RETV_IF(ctx == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
        RETV_IF(client_id == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
 
-       *client_id = strdup(((struct _diagnostics_ctx_s *)ctx)->client_id);
+       *client_id = strndup(((struct _diagnostics_ctx_s *)ctx)->client_id, MAX_CLIENT_ID_LEN);
 
        return DIAGNOSTICS_ERROR_NONE;
 }
 
-STATIC int get_report_path(diagnostics_ctx_h ctx, const char **path, size_t *len)
+int diagnostics_get_event_name(diagnostics_ctx_h ctx, char **event_name)
 {
+       RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
        RETV_IF(ctx == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
-       RETV_IF(path == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
-       RETV_IF(((struct _diagnostics_ctx_s *)ctx)->signal_type != SIG_TYPE_CRASH, DIAGNOSTICS_ERROR_NOT_SUPPORTED);
-
-       GVariant *val;
+       RETV_IF(event_name == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
 
-       val = g_variant_get_child_value(((struct _diagnostics_ctx_s *)ctx)->signal->parameters, SIG_CRASH_REPORTPATH);
-       *path = g_variant_get_string(val, (gsize *)len);
+       *event_name = strndup(((struct _diagnostics_ctx_s *)ctx)->event_name, MAX_EVENT_NAME_LEN);
 
        return DIAGNOSTICS_ERROR_NONE;
 }
 
-int diagnostics_get_data(diagnostics_ctx_h ctx, const char **params, int params_size, diagnostics_data_h *data)
+int diagnostics_get_event_data(diagnostics_ctx_h ctx, bundle **event_data)
 {
        RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
        RETV_IF(ctx == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
-       RETV_IF(params_size < 0, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
-       RETV_IF(data == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
-       RETV_IF(((struct _diagnostics_ctx_s *)ctx)->signal_type != SIG_TYPE_CRASH, DIAGNOSTICS_ERROR_NOT_SUPPORTED);
+       RETV_IF(event_data == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
 
-       const char *report_path;
-       size_t len;
-       int report_id;
-       int fd;
-       int ret;
+       *event_data = bundle_dup(((struct _diagnostics_ctx_s *)ctx)->event_data);
 
-       /*
-       * TODO: Make this suitable for supporting other clients, not just crash-worker
-       */
+       return DIAGNOSTICS_ERROR_NONE;
+}
 
-       ret = get_report_path(((struct _diagnostics_ctx_s *)ctx), &report_path, &len);
-       if (ret) {
-               _E("diagnostics_get_report_path() failed: %d", ret);
-               return DIAGNOSTICS_ERROR_IO_ERROR;
-       }
+int diagnostics_set_client_id(const char *client_id)
+{
+       RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
+       RETV_IF(client_id == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
 
-       if (params_size < 1)
-               return DIAGNOSTICS_ERROR_NOT_SUPPORTED;
+       int ret;
 
-       if (strcmp(params[0], "cs_full") == 0)
-               report_id = 0;
-       else if (strcmp(params[0], "cs_info_json") == 0)
-               report_id = 1;
-       else {
-               _E("Unsupported parameter: %s", params[0]);
-               return DIAGNOSTICS_ERROR_NOT_SUPPORTED;
+       if (is_app()) {
+               _E("Setting client ID is only possible for system services, not apps");
+               return DIAGNOSTICS_ERROR_RESOURCE_BUSY;
        }
 
-       ret = dbus_get_file_from_report(report_path, report_id, &fd);
-       if (ret) {
-               _E("dbus_get_file_from_report() failed: %d", ret);
-               if (ret == -EACCES)
-                       return DIAGNOSTICS_ERROR_PERMISSION_DENIED;
-               return DIAGNOSTICS_ERROR_IO_ERROR;
+       if (service_name[0]) {
+               _E("Client ID is already set to: '%s', it is not possible to change it during runtime", service_name);
+               return DIAGNOSTICS_ERROR_RESOURCE_BUSY;
        }
 
-       *data = diagnostics_data_create(fd);
-       if (*data == NULL) {
-               _E("Unable to create diagnostics_data");
-               close(fd);
-               return DIAGNOSTICS_ERROR_OUT_OF_MEMORY;
+       ret = snprintf(service_name, MAX_CLIENT_ID_LEN, "%s", client_id);
+       if (ret < 0) {
+               _E("snprintf() failed: %d", ret);
+               return DIAGNOSTICS_ERROR_IO_ERROR;
        }
 
        return DIAGNOSTICS_ERROR_NONE;
 }
 
-int diagnostics_destroy(diagnostics_ctx_h ctx)
+int diagnostics_request_bugreport(int pid)
 {
-       RETV_IF(ctx == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
+       RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
+
+       char reason[256 + MAX_CLIENT_ID_LEN];
+       char report_path[PATH_MAX];
+       char *client_id;
+       int ret;
+
+       client_id = get_client_id();
+       if (!client_id)
+               return DIAGNOSTICS_ERROR_INVALID_PARAMETER;
 
-       dbus_signal_cleanup(((struct _diagnostics_ctx_s *)ctx)->signal);
-       free(ctx);
+       ret = snprintf(reason, sizeof(reason),
+                                  "Diagnostics API requested bugreport.\n"
+                                  "PID (requested): %d\n"
+                                  "Client ID (requester): %s\n",
+                                  pid, client_id);
+
+       if (ret < 0) {
+               _E("Unable to set reason: %m");
+               return DIAGNOSTICS_ERROR_IO_ERROR;
+       }
+
+       /*
+        * TODO: livedump_pid() should be changed to return
+        * TIZEN_ERROR_PERMISSION_DENIED in case of missing permission
+        * TIZEN_ERROR_INVALID_PARAMETER in case of no such process
+        */
+       ret = livedump_pid(pid > 0 ? pid : 0, reason, report_path, PATH_MAX);
+       if (ret == false)
+               return DIAGNOSTICS_ERROR_IO_ERROR;
 
        return DIAGNOSTICS_ERROR_NONE;
 }
@@ -359,8 +809,28 @@ int diagnostics_data_destroy(diagnostics_data_h data)
 {
        RETV_IF(data == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
 
-       close(((struct _diagnostics_data_s *)data)->fd);
-       free(data);
+       struct _diagnostics_data_s *_data = (struct _diagnostics_data_s *) data;
+       close(_data->fd);
+
+       for (int i = 0; i < _data->params_size; i++)
+               free(_data->params[i]);
+
+       free(_data->params);
+       free(_data);
+
+       return DIAGNOSTICS_ERROR_NONE;
+}
+
+int diagnostics_destroy(diagnostics_ctx_h ctx)
+{
+       RETV_IF(ctx == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
+
+       struct _diagnostics_ctx_s *_ctx = (struct _diagnostics_ctx_s *) ctx;
+
+       free(_ctx->client_id);
+       free(_ctx->event_name);
+       bundle_free(_ctx->event_data);
+       free(_ctx);
 
        return DIAGNOSTICS_ERROR_NONE;
 }
diff --git a/src/library/signal.c b/src/library/signal.c
deleted file mode 100644 (file)
index 88e5d24..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-* Copyright (c) 2020 Samsung Electronics Co., Ltd.
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-#include "signal.h"
-#include "log.h"
-#include "dbus.h"
-
-#include <gio/gio.h>
-#include <glib.h>
-
-int signal_is_valid_crash(struct dbus_signal_s *signal)
-{
-       GVariant *extra;
-
-       RETV_IF(signal == NULL, FALSE);
-       RETV_IF(g_variant_n_children(signal->parameters) != SIG_CRASH_SIZE, FALSE);
-
-       extra = g_variant_get_child_value(signal->parameters, SIG_CRASH_EX);
-       RETV_IF(g_variant_is_container(extra) == FALSE, FALSE);
-
-       return TRUE;
-}
diff --git a/src/library/signal.h b/src/library/signal.h
deleted file mode 100644 (file)
index d7a3a39..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-* Copyright (c) 2020 Samsung Electronics Co., Ltd.
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-#ifndef __SIGNAL_H__
-#define __SIGNAL_H__
-
-#define SIG_CRASH_SIZE 8
-#define SIG_CRASH_CMDNAME 0
-#define SIG_CRASH_CMDPATH 1
-#define SIG_CRASH_APPID 2
-#define SIG_CRASH_PKGID 3
-#define SIG_CRASH_REPORTPATH 4
-#define SIG_CRASH_PID 5
-#define SIG_CRASH_TID 6
-#define SIG_CRASH_EX 7
-#define SIG_CRASH_EX_SYSSIGNAL "sys.signal"
-#define SIG_CRASH_EX_SYSTIDCOMM "sys.tid.comm"
-#define SIG_CRASH_EX_ARMPC "arm.pc"
-#define SIG_CRASH_EX_ARMLR "arm.lr"
-
-struct dbus_signal_s;
-
-typedef enum {
-       SIG_TYPE_CRASH,
-       /* SIG_TYPE_CRASH_LEGACY ? */
-       SIG_TYPE_INVALID
-} signal_type_e;
-
-int signal_is_valid_crash(struct dbus_signal_s *signal);
-
-#endif /* __SIGNAL_H__ */