2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <diagnostics.h>
19 #include <system_info.h>
22 #include <libdumpsys.h>
33 #define DIAGNOSTICS_FEATURE "http://tizen.org/feature/diagnostics"
35 #define FEATURE_UNKNOWN -1
36 #define FEATURE_FALSE 0
37 #define FEATURE_TRUE 1
39 STATIC struct _diagnostics_cb_info_s {
40 diagnostics_notification_cb cb;
47 struct _diagnostics_ctx_s {
49 struct dbus_signal_s *signal;
50 signal_type_e signal_type;
53 struct _diagnostics_data_s {
57 STATIC int diagnostics_feature = FEATURE_UNKNOWN;
59 STATIC bool __is_feature_supported(void)
61 int ret = SYSTEM_INFO_ERROR_NONE;
64 if (diagnostics_feature == FEATURE_UNKNOWN) {
65 ret = system_info_get_platform_bool(DIAGNOSTICS_FEATURE, &feature);
66 RETVM_IF(ret != SYSTEM_INFO_ERROR_NONE, false, "Failed to get system info");
68 diagnostics_feature = (feature ? FEATURE_TRUE : FEATURE_FALSE);
71 return (diagnostics_feature == FEATURE_TRUE ? true : false);
74 STATIC struct _diagnostics_ctx_s *diagnostics_create(struct dbus_signal_s *signal)
76 RETV_IF(signal == NULL, NULL);
78 struct _diagnostics_ctx_s *ctx;
80 ctx = calloc(1, sizeof(struct _diagnostics_ctx_s));
82 _E("Unable to allocate memory");
86 if (signal->signal_name && strcmp(signal->signal_name, DBUS_MEMBER_CRASH) == 0) {
87 ctx->client_id = DBUS_SENDER_CRASH;
88 ctx->signal_type = signal_is_valid_crash(signal) ? SIG_TYPE_CRASH : SIG_TYPE_INVALID;
90 _E("Unknown signal name");
99 STATIC struct _diagnostics_data_s *diagnostics_data_create(int fd)
101 RETV_IF(fd < 0, NULL);
103 struct _diagnostics_data_s *data;
105 data = calloc(1, sizeof(struct _diagnostics_data_s));
107 _E("Unable to allocate memory");
115 STATIC void signal_handler(GDBusConnection *connection,
116 const gchar *sender_name,
117 const gchar *object_path,
118 const gchar *interface_name,
119 const gchar *signal_name,
120 GVariant *parameters,
123 struct _diagnostics_ctx_s *ctx;
124 struct dbus_signal_s *signal;
126 _D("signal_handler");
127 _D("parameters: %s", g_variant_print(parameters, TRUE));
130 _E("No user cb set");
134 _D("dbus_signal_create");
135 signal = dbus_signal_create(sender_name,
141 _E("Unable to create signal structure");
145 _D("diagnostics_create");
146 ctx = diagnostics_create(signal);
148 _E("Unable to create diagnostics context");
149 dbus_signal_cleanup(signal);
153 _D("Fireing user cb!");
154 cb_info.cb(ctx, cb_info.user_data);
157 int diagnostics_set_notification_cb(diagnostics_notification_cb callback, void *user_data)
159 RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
160 RETV_IF(callback == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
164 _D("diagnostics_set_notification_cb()");
167 _E("Callback has already been set");
168 return DIAGNOSTICS_ERROR_RESOURCE_BUSY;
171 ret = dbus_subscribe(signal_handler);
173 _E("Unable to subscribe to dbus signals");
174 return DIAGNOSTICS_ERROR_IO_ERROR;
177 cb_info.cb = callback;
178 cb_info.user_data = user_data;
180 return DIAGNOSTICS_ERROR_NONE;
183 int diagnostics_unset_notification_cb(void)
185 RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
187 _D("diagnostics_unset_notification_cb()");
190 cb_info.user_data = NULL;
193 return DIAGNOSTICS_ERROR_NONE;
196 int diagnostics_request_client_data(const char *client_id, const char **params, int params_size, diagnostics_data_h *data)
198 RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
199 RETV_IF(client_id == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
200 RETV_IF(params_size < 0, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
201 RETV_IF(data == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
206 ret = dumpsys_dump(client_id, params_size, params, &fd);
207 if (ret != DIAGNOSTICS_ERROR_NONE) {
208 _E("dumpsys_dump() failed: %d", ret);
209 if (ret == TIZEN_ERROR_PERMISSION_DENIED)
210 return DIAGNOSTICS_ERROR_PERMISSION_DENIED;
211 return DIAGNOSTICS_ERROR_IO_ERROR;
214 *data = diagnostics_data_create(fd);
216 _E("Unable to create diagnostics_data");
217 return DIAGNOSTICS_ERROR_OUT_OF_MEMORY;
220 return DIAGNOSTICS_ERROR_NONE;
223 int diagnostics_data_read(diagnostics_data_h data, void *buf, size_t count, int timeout_ms, size_t *bytes_read)
225 RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
226 RETV_IF(data == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
227 RETV_IF(buf == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
228 RETV_IF(bytes_read == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
230 struct pollfd poll_fd;
234 poll_fd.fd = ((struct _diagnostics_data_s *)data)->fd;
235 poll_fd.events = POLLIN;
237 ready = poll(&poll_fd, 1, timeout_ms <= 0 ? -1 : timeout_ms);
240 _E("poll() timeout");
241 return DIAGNOSTICS_ERROR_TIMED_OUT;
245 _E("poll() failed: %m");
246 return DIAGNOSTICS_ERROR_IO_ERROR;
249 if (poll_fd.revents & POLLIN) {
250 ret = read(poll_fd.fd, buf, count);
252 _E("read() failed: %m, fd: %d", poll_fd.fd);
254 return DIAGNOSTICS_ERROR_TRY_AGAIN;
255 return DIAGNOSTICS_ERROR_IO_ERROR;
258 return DIAGNOSTICS_ERROR_NONE;
259 } else if (poll_fd.revents & POLLHUP) {
261 return DIAGNOSTICS_ERROR_NONE;
264 _E("received event: %d", poll_fd.revents);
265 return DIAGNOSTICS_ERROR_IO_ERROR;
268 int diagnostics_get_client_id(diagnostics_ctx_h ctx, char **client_id)
270 RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
271 RETV_IF(ctx == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
272 RETV_IF(client_id == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
274 *client_id = strdup(((struct _diagnostics_ctx_s *)ctx)->client_id);
276 return DIAGNOSTICS_ERROR_NONE;
279 STATIC int get_report_path(diagnostics_ctx_h ctx, const char **path, size_t *len)
281 RETV_IF(ctx == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
282 RETV_IF(path == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
283 RETV_IF(((struct _diagnostics_ctx_s *)ctx)->signal_type != SIG_TYPE_CRASH, DIAGNOSTICS_ERROR_NOT_SUPPORTED);
287 val = g_variant_get_child_value(((struct _diagnostics_ctx_s *)ctx)->signal->parameters, SIG_CRASH_REPORTPATH);
288 *path = g_variant_get_string(val, (gsize *)len);
290 return DIAGNOSTICS_ERROR_NONE;
293 int diagnostics_get_data(diagnostics_ctx_h ctx, const char **params, int params_size, diagnostics_data_h *data)
295 RETVM_IF(__is_feature_supported() == false, DIAGNOSTICS_ERROR_NOT_SUPPORTED, "Diagnostics feature is not supported");
296 RETV_IF(ctx == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
297 RETV_IF(params_size < 0, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
298 RETV_IF(data == NULL, DIAGNOSTICS_ERROR_INVALID_PARAMETER);
299 RETV_IF(((struct _diagnostics_ctx_s *)ctx)->signal_type != SIG_TYPE_CRASH, DIAGNOSTICS_ERROR_NOT_SUPPORTED);
301 const char *report_path;
308 * TODO: Make this suitable for supporting other clients, not just crash-worker
311 ret = get_report_path(((struct _diagnostics_ctx_s *)ctx), &report_path, &len);
313 _E("diagnostics_get_report_path() failed: %d", ret);
314 return DIAGNOSTICS_ERROR_IO_ERROR;
318 return DIAGNOSTICS_ERROR_NOT_SUPPORTED;
320 if (strcmp(params[0], "cs_full") == 0)
322 else if (strcmp(params[0], "cs_info_json") == 0)
325 _E("Unsupported parameter: %s", params[0]);
326 return DIAGNOSTICS_ERROR_NOT_SUPPORTED;
329 ret = dbus_get_file_from_report(report_path, report_id, &fd);
331 _E("dbus_get_file_from_report() failed: %d", ret);
333 return DIAGNOSTICS_ERROR_PERMISSION_DENIED;
334 return DIAGNOSTICS_ERROR_IO_ERROR;
337 *data = diagnostics_data_create(fd);
339 _E("Unable to create diagnostics_data");
341 return DIAGNOSTICS_ERROR_OUT_OF_MEMORY;
344 return DIAGNOSTICS_ERROR_NONE;
347 void diagnostics_destroy(diagnostics_ctx_h ctx) {
350 dbus_signal_cleanup(((struct _diagnostics_ctx_s *)ctx)->signal);
354 void diagnostics_data_destroy(diagnostics_data_h data) {
355 RET_IF(data == NULL);
357 close(((struct _diagnostics_data_s *)data)->fd);