bugreport-service: Get bugreport based on event data 27/256827/5 accepted/tizen/unified/20210417.022231 submit/tizen/20210416.144436
authorMateusz Moscicki <m.moscicki2@partner.samsung.com>
Fri, 9 Apr 2021 10:57:15 +0000 (12:57 +0200)
committerMateusz Moscicki <m.moscicki2@partner.samsung.com>
Fri, 16 Apr 2021 11:23:56 +0000 (13:23 +0200)
A bugreport identifier is sent along with BugreportCreated event so that
client can request the details of the bugreport to which the event
related:

  static void bugreport_created_cb(diagnostics_ctx_h ctx, void *user_data)
  {
      ...
      const char *params[] = {"--type", "crash-info-json"};
      diagnostics_data_h data;
      diagnostics_get_data(ctx, params, ARRAY_SIZE(params), &data);

      size_t bytes;
      char buff[1024];
      diagnostics_data_read(data, buff, sizeof(buff), 0, &bytes);
      ...
  }

  int main()
  {
      ...
      diagnostics_set_notification_cb(bugreport_created_cb, NULL);
      diagnostics_subscribe_event("BugreportCreated", "org.tizen.bugreport-service");
      g_main_loop_run(mainloop);
      ...
  }

Change-Id: I056f16743e656504dcefe0972eae00bc4b6f58ab

13 files changed:
packaging/crash-worker.spec
src/bugreport-service/CMakeLists.txt
src/bugreport-service/bugreport-service.c
src/bugreport-service/diagnostics/diagnostics_dump.c
src/crash-manager/CMakeLists.txt
src/crash-manager/crash-manager.c
src/shared/bugreport-util.c [new file with mode: 0644]
src/shared/bugreport-util.h [new file with mode: 0644]
src/shared/util.c
tests/system/CMakeLists.txt
tests/system/bugreport_created/bugreport_created.sh.template [new file with mode: 0644]
tests/system/utils/CMakeLists.txt
tests/system/utils/diagnostics_bugreporttest.c [new file with mode: 0644]

index fa977fa..e7d4bcf 100644 (file)
@@ -386,6 +386,7 @@ chsmack -a "System" -t %{crash_path}
 %{_bindir}/crash-worker-system-tests-run
 
 %{_libexecdir}/crash-worker/system-tests/bugreport_crash_info_json/bugreport_crash_info_json.sh
+%{_libexecdir}/crash-worker/system-tests/bugreport_created/bugreport_created.sh
 %{_libexecdir}/crash-worker/system-tests/check_minicore_mem/check_minicore_mem.sh
 %{_libexecdir}/crash-worker/system-tests/check_minicore_mem/cp.sh
 %{_libexecdir}/crash-worker/system-tests/clean_temp/clean_temp.sh
@@ -414,6 +415,7 @@ chsmack -a "System" -t %{crash_path}
 %{_libexecdir}/crash-worker/system-tests/utils/btee
 %{_libexecdir}/crash-worker/system-tests/utils/kenny
 %{_libexecdir}/crash-worker/system-tests/utils/libbugreport-servicetest
+%{_libexecdir}/crash-worker/system-tests/utils/diagnostics_bugreporttest
 %{_libexecdir}/crash-worker/system-tests/utils/minicore-utils.sh
 %{_libexecdir}/crash-worker/system-tests/wait_for_opt_usr/wait_for_opt_usr.sh
 %{_libexecdir}/crash-worker/system-tests/without_so_info_file/without_so_info_file.sh
index b289d70..77abd1d 100644 (file)
@@ -11,6 +11,7 @@ SET(CRASH_SERVICE_SRCS
        ${CMAKE_SOURCE_DIR}/src/shared/util.c
        ${CMAKE_SOURCE_DIR}/src/shared/spawn.c
        ${CMAKE_SOURCE_DIR}/src/shared/config.c
+       ${CMAKE_SOURCE_DIR}/src/shared/bugreport-util.c
        )
 
 INCLUDE(GNUInstallDirs)
index 8ee62db..6000f06 100644 (file)
@@ -34,6 +34,7 @@
 #include "bugreport-service.h"
 
 #include "crash-manager/crash-manager.h"
+#include "shared/bugreport-util.h"
 #include "shared/log.h"
 #include "shared/util.h"
 #include "diagnostics/diagnostics.h"
@@ -181,10 +182,7 @@ static gboolean read_result_cb(gpointer data)
        }
 
        if (!error_sent) {
-               int res = diagnostics_send_event("BugreportCreated", NULL);
-               if (res != DIAGNOSTICS_ERROR_NONE)
-                       _E("Send diagnostics event error: %d", res);
-
+               send_bugreport_created_event(report_path);
                g_dbus_method_invocation_return_value(cb_data->invocation,
                                                      g_variant_new("(s)", report_path));
        }
index 9e5e32e..bff0b00 100644 (file)
@@ -228,6 +228,8 @@ static bool write_crash_info(int fd, long time_from, long time_to, bool as_json)
        if (list == NULL) {
                if (as_json)
                        dprintf(fd, "{\"error\": \"Internal error.\"}");
+               else
+                       dprintf(fd, "Internal error\n");
                return false;
        }
 
@@ -309,6 +311,8 @@ static bool write_single_file(int fd, enum BUGREPORT_REPORT_TYPE report_type, co
        if (list == NULL) {
                if (report_type == BR_CRASHINFO_JSON)
                        dprintf(fd, "{\"error\": \"Internal error.\"}");
+               else
+                       dprintf(fd, "Internal error\n");
                return false;
        }
 
@@ -381,7 +385,58 @@ static void diagnostics_print_help(int out_fd)
        );
 }
 
-static bool diagnostics_call_parse_options(int out_fd, char **params, int params_size, struct diagnostics_call_options *dco)
+static bool get_file_from_ctx(diagnostics_ctx_h ctx, char **report_file)
+{
+       assert(report_file);
+
+       if (ctx == NULL)
+               return false;
+
+       bool result = false;
+       char *event_name = NULL;
+       bundle *event_data = NULL;
+
+       int ret = diagnostics_get_event_name(ctx, &event_name);
+       if (ret != DIAGNOSTICS_ERROR_NONE) {
+               _E("Get event name error: %d", ret);
+               goto out;
+       }
+       if (strcmp(event_name, "BugreportCreated") != 0) {
+               _E("Unknown context: %s", event_name);
+               goto out;
+       }
+
+       ret = diagnostics_get_event_data(ctx, &event_data);
+       if (ret != DIAGNOSTICS_ERROR_NONE) {
+               _E("Get event data error: %d", ret);
+               goto out;
+       }
+
+       char *tmp_report_file;
+       ret = bundle_get_str(event_data, "report_file", &tmp_report_file);
+       if (ret != BUNDLE_ERROR_NONE) {
+               _E("Can not get report_file from event data: %d", ret);
+               goto out;
+       }
+
+       *report_file = strdup(tmp_report_file);
+       if (*report_file == NULL) {
+               _E("Out of memory: %m");
+               goto out;
+       }
+       _D("Report file from event data: %s", *report_file);
+
+       result = true;
+out:
+       if (event_name != NULL)
+               free(event_name);
+       if (event_data != NULL)
+               bundle_free(event_data);
+
+       return result;
+}
+
+static bool diagnostics_call_parse_options(int out_fd, char **params, int params_size, diagnostics_ctx_h ctx, struct diagnostics_call_options *dco)
 {
        struct timespec cur_time;
        clock_gettime(CLOCK_REALTIME, &cur_time);
@@ -411,7 +466,7 @@ static bool diagnostics_call_parse_options(int out_fd, char **params, int params
        memcpy(&nparams[1], params, params_size*sizeof(char*));
        nparams[0] = "n";
        while ((opt = getopt_long_only(params_size+1, nparams, "", long_options, NULL)) != -1) {
-               switch(opt) {
+               switch (opt) {
                case PN_TYPE:
                        if (strcmp(optarg, "bugreport") == 0) {
                                dco->report_type = BR_BUGREPORT;
@@ -451,8 +506,15 @@ static bool diagnostics_call_parse_options(int out_fd, char **params, int params
                }
        }
 
-       if (optind < params_size+1)
-               dco->arg = nparams[optind];
+       if (optind < params_size+1) {
+               dco->arg = strdup(nparams[optind]);
+               if (dco->arg == NULL) {
+                       _E("Out of memory: %m");
+                       return false;
+               }
+       } else {
+               get_file_from_ctx(ctx, &dco->arg);
+       }
 
        return true;
 }
@@ -467,23 +529,23 @@ static void diagnostics_callback(diagnostics_data_h data, char **params, int par
        }
        struct diagnostics_call_options dco;
 
-       if (!diagnostics_call_parse_options(fd, params, params_size, &dco))
+       if (!diagnostics_call_parse_options(fd, params, params_size, ctx, &dco))
                return;
 
        if ((dco.last_set && (dco.from_set || dco.to_set)) || (dco.to_set && !dco.from_set)) {
                _E("Incorrect parameters set");
                dprintf(fd, "Incorrect parameters set.\n");
-               return;
+               goto out;
        }
 
        if (dco.arg != NULL) {
                if (dco.last_set || dco.from_set || dco.to_set) {
                        _E("Incorrect parameters set.");
                        dprintf(fd, "Incorrect parameters set.\n");
-                       return;
+                       goto out;
                }
                write_single_file(fd, dco.report_type, dco.arg);
-               return;
+               goto out;
        }
 
        switch(dco.report_type) {
@@ -505,6 +567,9 @@ static void diagnostics_callback(diagnostics_data_h data, char **params, int par
        default:
                _E("Unknown report type\n");
        }
+out:
+       if (dco.arg != NULL)
+               free(dco.arg);
 }
 
 bool diagnostics_init()
index d76671e..b3629c1 100644 (file)
@@ -8,6 +8,7 @@ SET(LIB_CRASH_MANAGER_SRCS
        ${CMAKE_SOURCE_DIR}/src/shared/util.c
        ${CMAKE_SOURCE_DIR}/src/shared/spawn.c
        ${CMAKE_SOURCE_DIR}/src/shared/config.c
+       ${CMAKE_SOURCE_DIR}/src/shared/bugreport-util.c
    )
 
 SET(CRASH_MANAGER_SRCS
index f37a0ee..d525588 100644 (file)
@@ -39,7 +39,6 @@
 #include <sys/ptrace.h>
 #include <sys/vfs.h>
 #include <unistd.h>
-#include <diagnostics.h>
 
 #include <pkgmgr-info.h>
 #include <tzplatform_config.h>
@@ -50,6 +49,7 @@
 #include "defs.h"
 #include "shared/log.h"
 #include "shared/config.h"
+#include "shared/bugreport-util.h"
 #include "shared/spawn.h"
 #include "shared/util.h"
 #include "so-info.h"
@@ -1322,7 +1322,7 @@ static bool run(struct crash_info *cinfo)
 
        if (move_dump_data(temp_report, cinfo)) {
                _I("Report for pid %d created at %s", cinfo->pid_info, cinfo->result_path);
-               diagnostics_send_event("BugreportCreated", NULL);
+               send_bugreport_created_event(cinfo->result_path);
        }
 
        if (cinfo->print_result_path)
diff --git a/src/shared/bugreport-util.c b/src/shared/bugreport-util.c
new file mode 100644 (file)
index 0000000..2bccab0
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * bugreport-util
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <diagnostics.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+
+#include "shared/log.h"
+
+bool send_bugreport_created_event(const char *report_path)
+{
+       char *result_file = rindex(report_path, '/');
+       if (result_file == NULL) {
+               _E("Out of memory: %m");
+               return false;
+       }
+
+       bundle *event_data = bundle_create();
+       bundle_add_str(event_data, "report_file", ++result_file);
+       int res = diagnostics_send_event("BugreportCreated", event_data);
+       if (res != DIAGNOSTICS_ERROR_NONE)
+               _E("Send diagnostics event error: %d", res);
+
+       bundle_free(event_data);
+       return res == DIAGNOSTICS_ERROR_NONE;
+}
+
diff --git a/src/shared/bugreport-util.h b/src/shared/bugreport-util.h
new file mode 100644 (file)
index 0000000..8cb44d0
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * bugreport-util
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __BUGREPORT_UTIL_H__
+#define __BUGREPORT_UTIL_H__
+#include <stdbool.h>
+
+bool send_bugreport_created_event(const char *report_path);
+
+#endif  // __BUGREPORT_UTIL_H__
index 0606045..4c04626 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include <assert.h>
+#include <diagnostics.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
index e770894..8cf1e9e 100644 (file)
@@ -1,5 +1,6 @@
 cmake_minimum_required(VERSION 2.6)
 
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src)
 ADD_SUBDIRECTORY(utils)
 
 macro(CONFIGURE_TEST_FILE dir_name file_name)
@@ -18,6 +19,7 @@ macro(CONFIGURE_TEST test_name)
 endmacro()
 
 configure_test("bugreport_crash_info_json")
+configure_test("bugreport_created")
 configure_test("check_minicore_mem")
 configure_test("clean_temp")
 configure_test("cmp_backtraces" "cp")
diff --git a/tests/system/bugreport_created/bugreport_created.sh.template b/tests/system/bugreport_created/bugreport_created.sh.template
new file mode 100644 (file)
index 0000000..81f82db
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+# Check the BugreportCreated signal
+
+if [ -z "${CRASH_WORKER_SYSTEM_TESTS}" ]; then
+    CRASH_WORKER_SYSTEM_TESTS="@CRASH_SYSTEM_TESTS_PATH@"
+fi
+
+. ${CRASH_WORKER_SYSTEM_TESTS}/utils/minicore-utils.sh
+
+( ${CRASH_WORKER_SYSTEM_TESTS}/utils/kenny &
+  pid=$!
+  sleep 2
+  kill -6 $pid ) &
+
+TMP=$(mktemp /tmp/dbus_notify.XXXXXX)
+${CRASH_WORKER_SYSTEM_TESTS}/utils/diagnostics_bugreporttest --type=crash-info-json > "${TMP}" &
+watchpid=$!
+
+cleanup()
+{
+       kill "${watchpid}"
+       rm -f "${TMP}"
+}
+
+trap cleanup 0
+
+sleep 3
+wait_for_app crash-manager
+sleep 1
+
+if [ $(wc -l "${TMP}" | cut -f1 -d' ') -lt 10 ]; then
+  fail "Output file is too short"
+fi
+
+if ! egrep "callstack" "${TMP}"; then
+  fail "No callstack in output file"
+fi
+
+if ! egrep "native_hash" "${TMP}"; then
+  fail "No native_hash in output file"
+fi
+
+exit_ok
index f8b7d6a..8b39458 100644 (file)
@@ -9,17 +9,26 @@ target_link_libraries(kenny ${CMAKE_THREAD_LIBS_INIT})
 set_target_properties(kenny PROPERTIES COMPILE_FLAGS "-std=c++11 -ggdb -O0")
 
 add_executable(libbugreport-servicetest libbugreport-servicetest.c)
+add_executable(diagnostics_bugreporttest diagnostics_bugreporttest.c)
 
 INCLUDE(FindPkgConfig)
 pkg_check_modules(helper_pkgs REQUIRED
                   gio-2.0
                   bugreport
+                  diagnostics
                   dlog)
 
+FOREACH(flag ${helper_pkgs_CFLAGS})
+                  SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+
 TARGET_LINK_LIBRARIES(libbugreport-servicetest bugreport ${helper_pkgs_LDFLAGS})
+TARGET_LINK_LIBRARIES(diagnostics_bugreporttest bugreport ${helper_pkgs_LDFLAGS})
 
 install(TARGETS kenny DESTINATION ${CRASH_SYSTEM_TESTS_PATH}/utils)
 install(TARGETS btee DESTINATION ${CRASH_SYSTEM_TESTS_PATH}/utils)
 install(FILES minicore-utils.sh DESTINATION ${CRASH_SYSTEM_TESTS_PATH}/utils)
 install(TARGETS libbugreport-servicetest DESTINATION ${CRASH_SYSTEM_TESTS_PATH}/utils)
+install(TARGETS diagnostics_bugreporttest DESTINATION ${CRASH_SYSTEM_TESTS_PATH}/utils)
 
diff --git a/tests/system/utils/diagnostics_bugreporttest.c b/tests/system/utils/diagnostics_bugreporttest.c
new file mode 100644 (file)
index 0000000..3e01b0a
--- /dev/null
@@ -0,0 +1,71 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <diagnostics.h>
+#include <glib.h>
+#include <getopt.h>
+#include "shared/util.h"
+
+GMainLoop *mainloop;
+
+static void bugreport_created_cb(diagnostics_ctx_h ctx, void *user_data)
+{
+       const char *params[] = {"--type", (char*)user_data};
+       diagnostics_data_h data;
+       int ret = diagnostics_get_data(ctx, params, ARRAY_SIZE(params), &data);
+       if (ret != DIAGNOSTICS_ERROR_NONE) {
+               printf("diagnostics_get_data error: %d\n", ret);
+               return;
+       }
+
+       size_t byte_read = 0;
+       char buff[1024];
+       printf("---- START ----\n");
+       do {
+              ret = diagnostics_data_read(data, buff, sizeof(buff)-1, 5000, &byte_read);
+              if (ret != DIAGNOSTICS_ERROR_NONE) {
+                      printf("diagnostics_data_read error: %d\n", ret);
+                      return;
+              }
+              buff[byte_read] = 0;
+              printf("%s", buff);
+       } while(byte_read > 0);
+
+       printf("\n----- END -----\n");
+       diagnostics_data_destroy(data);
+       diagnostics_destroy(ctx);
+       g_main_loop_quit(mainloop);
+}
+
+int main(int argc, char *argv[])
+{
+       struct option long_options[] = {
+               {"type", required_argument, NULL, 't'},
+               {}
+       };
+
+       int opt;
+       char *type = "crash-info";
+
+       while ((opt = getopt_long(argc, argv, "t:", long_options, NULL)) != -1) {
+               switch (opt) {
+               case 't':
+                       type = optarg;
+                       break;
+               default:
+                       printf("%s [--type=<type>]\n", argv[0]);
+                       return EXIT_FAILURE;
+               }
+       }
+
+       int ret = diagnostics_set_notification_cb(bugreport_created_cb, type);
+       if (ret != DIAGNOSTICS_ERROR_NONE) {
+               printf("diagnostics_set_notification_cb error: %d\n", ret);
+               return EXIT_FAILURE;
+       }
+
+       diagnostics_subscribe_event("BugreportCreated", "org.tizen.bugreport-service");
+       mainloop = g_main_loop_new(NULL, FALSE);
+       g_main_loop_run(mainloop);
+       return EXIT_SUCCESS;
+}