2 * This file is part of stability-monitor
4 * Copyright © 2019 Samsung Electronics
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 #include <sys/types.h>
24 #include <glib-unix.h>
40 struct data_source *ds;
42 GVariant *actual_value;
43 GVariant *allowed_value;
48 static void action_finish(struct action_data *ad)
50 char objpath[PATH_MAX];
51 char interface[PATH_MAX];
53 GVariantBuilder *builder;
54 GVariant *signal_params;
56 snprintf(format, 20, "(is@%s@%s@a{sv})", g_variant_get_type_string(ad->actual_value),
57 g_variant_get_type_string(ad->allowed_value));
59 snprintf(objpath, PATH_MAX, "%s/%s", TSM_DBUS_PATH, ad->ds->name);
60 snprintf(interface, PATH_MAX, "%s.%s", TSM_DBUS_INTERFACE, ad->ds->param_name);
63 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
64 g_variant_builder_add(builder, "{sv}",
66 g_variant_new_string(ad->report_path ? ad->report_path : ""));
68 g_variant_builder_add(builder, "{sv}",
70 g_variant_new_boolean(ad->ds->process->kill));
72 g_variant_builder_add(builder, "{sv}",
74 g_variant_new_string(ad->ds->process->name));
76 g_variant_builder_add(builder, "{sv}",
78 g_variant_new_string(process_is_foreground(ad->ds->process) ?
79 "foreground" : "background"));
81 signal_params = g_variant_new(format,
83 limit_type_to_string(ad->lt),
86 g_variant_builder_end(builder));
88 g_variant_builder_unref(builder);
90 /* Kill the process */
91 if (ad->ds->process->kill) {
92 _D_PROC(ad->ds->process, "Killing process");
93 if (kill(ad->ds->process->pid, SIGKILL))
94 _E("Unable to kill process %s(%d): %m",
95 ad->ds->process->name,
96 ad->ds->process->pid);
100 dbus_send_signal(objpath, interface, "AbnormalityDetected", signal_params);
102 _D_PROC(ad->ds->process, "Sent D-Bus signal (%s, %s)",
103 limit_type_to_string(ad->lt),
106 ad->ds->action_in_progress = 0;
108 process_unref(ad->ds->process);
109 close(ad->stdout_fd);
110 close(ad->stderr_fd);
111 free(ad->report_path);
115 static void crash_manager_exit_cb(GPid pid, gint status, gpointer user_data)
117 struct action_data *ad = user_data;
123 if (!g_spawn_check_exit_status (status, NULL)) {
124 _E("Crash-manager failed with code: %d", status);
126 stream = fdopen(ad->stderr_fd, "r");
128 _E("Unable to open stderr stream: %m");
132 while ((n = getline(&line, &len, stream)) != -1)
138 stream = fdopen(ad->stdout_fd, "r");
140 _E("Unable to open stdout stream: %m");
144 /* Get report path from stdout */
145 while ((n = getline(&line, &len, stream)) != -1) {
146 if (strncmp(line, "REPORT_PATH=", 12) == 0) {
149 ad->report_path = strndup(line + 12, n - 12);
150 if (!ad->report_path)
151 _E("Unable to allocate memory");
153 _D_PROC(ad->ds->process, "Received report: %s", ad->report_path);
159 _E("Crash-worker ended without error but didn't provide report path");
168 g_spawn_close_pid(pid);
171 static GPid spawn_crash_manager(struct action_data *ad)
174 GError *error = NULL;
175 char *pid_str = NULL;
176 if (asprintf(&pid_str, "%d", ad->ds->process->pid) == -1)
179 char *argv[] = {CRASH_MANAGER_BIN, "-lrp", pid_str, NULL};
181 _D_PROC(ad->ds->process, "Generating report...");
184 if (!g_spawn_async_with_pipes(NULL, argv, NULL,
185 G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH, NULL,
186 NULL, &child_pid, NULL, &ad->stdout_fd, &ad->stderr_fd, &error)) {
188 _E("Unable to spawn child process: %s", error->message);
191 _D("Spawned child process pid %d", child_pid);
198 static gboolean action_run(gpointer data)
200 struct action_data *ad = data;
203 if (ad->ds->process->report) {
204 child_pid = spawn_crash_manager(ad);
205 if (child_pid != 0) {
206 g_child_watch_add(child_pid, crash_manager_exit_cb, ad);
216 int action_run_default(struct data_source *ds, enum limit_type lt)
218 struct action_data *ad;
219 struct smpl_container *sc = process_is_foreground(ds->process) ? &ds->data_fg : &ds->data_bg;
221 if (ds->action_in_progress)
223 ds->action_in_progress = 1;
225 _D_PROC(ds->process, "Running default action");
227 ad = calloc(1, sizeof(*ad));
229 _E("Unable to allocate memory");
234 ad->report_path = NULL;
237 if (lt == LIMIT_TYPE_AVG) {
238 ad->actual_value = g_variant_new_double(sc->average);
239 ad->allowed_value = g_variant_new_double(ds->limit.avg);
241 ad->actual_value = sample_to_gvariant(list_first_entry(&sc->samples, struct sample_s, node));
242 ad->allowed_value = sample_to_gvariant(&ds->limit.peak);
245 process_ref(ds->process);
246 g_timeout_add(0, action_run, ad);