1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17 #include <fcntl.h> // for open
18
19 #include <string>
20 #include <vector>
21
22 #include <base/files/file_util.h>
23 #include <base/guid.h>
24 #include <base/logging.h>
25 #include <base/strings/string_split.h>
26 #include <base/strings/string_util.h>
27 #include <base/strings/stringprintf.h>
28 #include <binder/IServiceManager.h>
29 #include <brillo/flag_helper.h>
30 #include <brillo/syslog_logging.h>
31 #include <metrics/metrics_collector_service_client.h>
32 #include <metrics/metrics_library.h>
33 #include <utils/String16.h>
34
35
36 #include "kernel_collector.h"
37 #include "kernel_warning_collector.h"
38 #include "unclean_shutdown_collector.h"
39 #include "user_collector.h"
40
41 #if !defined(__ANDROID__)
42 #include "udev_collector.h"
43 #endif
44
45 static const char kCrashCounterHistogram[] = "Logging.CrashCounter";
46 static const char kKernelCrashDetected[] =
47 "/data/misc/crash_reporter/run/kernel-crash-detected";
48 static const char kUncleanShutdownDetected[] =
49 "/var/run/unclean-shutdown-detected";
50 static const char kGUIDFileName[] = "/data/misc/crash_reporter/guid";
51
52 // Enumeration of kinds of crashes to be used in the CrashCounter histogram.
53 enum CrashKinds {
54 kCrashKindUncleanShutdown = 1,
55 kCrashKindUser = 2,
56 kCrashKindKernel = 3,
57 kCrashKindUdev = 4,
58 kCrashKindKernelWarning = 5,
59 kCrashKindMax
60 };
61
62 static MetricsLibrary s_metrics_lib;
63
64 using android::brillo::metrics::IMetricsCollectorService;
65 using base::FilePath;
66 using base::StringPrintf;
67
IsFeedbackAllowed()68 static bool IsFeedbackAllowed() {
69 return s_metrics_lib.AreMetricsEnabled();
70 }
71
TouchFile(const FilePath & file_path)72 static bool TouchFile(const FilePath &file_path) {
73 return base::WriteFile(file_path, "", 0) == 0;
74 }
75
SendCrashMetrics(CrashKinds type,const char * name)76 static void SendCrashMetrics(CrashKinds type, const char* name) {
77 // TODO(kmixter): We can remove this histogram as part of
78 // crosbug.com/11163.
79 s_metrics_lib.SendEnumToUMA(kCrashCounterHistogram, type, kCrashKindMax);
80 s_metrics_lib.SendCrashToUMA(name);
81 }
82
CountKernelCrash()83 static void CountKernelCrash() {
84 SendCrashMetrics(kCrashKindKernel, "kernel");
85 }
86
CountUdevCrash()87 static void CountUdevCrash() {
88 SendCrashMetrics(kCrashKindUdev, "udevcrash");
89 }
90
CountUncleanShutdown()91 static void CountUncleanShutdown() {
92 SendCrashMetrics(kCrashKindUncleanShutdown, "uncleanshutdown");
93 }
94
CountUserCrash()95 static void CountUserCrash() {
96 SendCrashMetrics(kCrashKindUser, "user");
97 // Tell the metrics collector about the user crash, in order to log active
98 // use time between crashes.
99 MetricsCollectorServiceClient metrics_collector_service;
100
101 if (metrics_collector_service.Init())
102 metrics_collector_service.notifyUserCrash();
103 else
104 LOG(ERROR) << "Failed to send user crash notification to metrics_collector";
105 }
106
107
Initialize(KernelCollector * kernel_collector,UserCollector * user_collector,UncleanShutdownCollector * unclean_shutdown_collector,const bool unclean_check,const bool clean_shutdown)108 static int Initialize(KernelCollector *kernel_collector,
109 UserCollector *user_collector,
110 UncleanShutdownCollector *unclean_shutdown_collector,
111 const bool unclean_check,
112 const bool clean_shutdown) {
113 CHECK(!clean_shutdown) << "Incompatible options";
114
115 // Try to read the GUID from kGUIDFileName. If the file doesn't exist, is
116 // blank, or the read fails, generate a new GUID and write it to the file.
117 std::string guid;
118 base::FilePath filepath(kGUIDFileName);
119 if (!base::ReadFileToString(filepath, &guid) || guid.empty()) {
120 guid = base::GenerateGUID();
121 // If we can't read or write the file, log an error. However it is not
122 // a fatal error, as the crash server will assign a random GUID based
123 // on a hash of the IP address if one is not provided in the report.
124 if (base::WriteFile(filepath, guid.c_str(), guid.size()) <= 0) {
125 LOG(ERROR) << "Could not write guid " << guid << " to file "
126 << filepath.value();
127 }
128 }
129
130 bool was_kernel_crash = false;
131 bool was_unclean_shutdown = false;
132 kernel_collector->Enable();
133 if (kernel_collector->is_enabled()) {
134 was_kernel_crash = kernel_collector->Collect();
135 }
136
137 if (unclean_check) {
138 was_unclean_shutdown = unclean_shutdown_collector->Collect();
139 }
140
141 // Touch a file to notify the metrics daemon that a kernel
142 // crash has been detected so that it can log the time since
143 // the last kernel crash.
144 if (IsFeedbackAllowed()) {
145 if (was_kernel_crash) {
146 TouchFile(FilePath(kKernelCrashDetected));
147 } else if (was_unclean_shutdown) {
148 // We only count an unclean shutdown if it did not come with
149 // an associated kernel crash.
150 TouchFile(FilePath(kUncleanShutdownDetected));
151 }
152 }
153
154 // Must enable the unclean shutdown collector *after* collecting.
155 unclean_shutdown_collector->Enable();
156 user_collector->Enable();
157
158 return 0;
159 }
160
HandleUserCrash(UserCollector * user_collector,const std::string & user,const bool crash_test)161 static int HandleUserCrash(UserCollector *user_collector,
162 const std::string& user, const bool crash_test) {
163 // Handle a specific user space crash.
164 CHECK(!user.empty()) << "--user= must be set";
165
166 // Make it possible to test what happens when we crash while
167 // handling a crash.
168 if (crash_test) {
169 *(volatile char *)0 = 0;
170 return 0;
171 }
172
173 // Accumulate logs to help in diagnosing failures during user collection.
174 brillo::LogToString(true);
175 // Handle the crash, get the name of the process from procfs.
176 bool handled = user_collector->HandleCrash(user, nullptr);
177 brillo::LogToString(false);
178 if (!handled)
179 return 1;
180 return 0;
181 }
182
183 #if !defined(__ANDROID__)
HandleUdevCrash(UdevCollector * udev_collector,const std::string & udev_event)184 static int HandleUdevCrash(UdevCollector *udev_collector,
185 const std::string& udev_event) {
186 // Handle a crash indicated by a udev event.
187 CHECK(!udev_event.empty()) << "--udev= must be set";
188
189 // Accumulate logs to help in diagnosing failures during user collection.
190 brillo::LogToString(true);
191 bool handled = udev_collector->HandleCrash(udev_event);
192 brillo::LogToString(false);
193 if (!handled)
194 return 1;
195 return 0;
196 }
197 #endif
198
HandleKernelWarning(KernelWarningCollector * kernel_warning_collector)199 static int HandleKernelWarning(KernelWarningCollector
200 *kernel_warning_collector) {
201 // Accumulate logs to help in diagnosing failures during collection.
202 brillo::LogToString(true);
203 bool handled = kernel_warning_collector->Collect();
204 brillo::LogToString(false);
205 if (!handled)
206 return 1;
207 return 0;
208 }
209
210 // Interactive/diagnostics mode for generating kernel crash signatures.
GenerateKernelSignature(KernelCollector * kernel_collector,const std::string & kernel_signature_file)211 static int GenerateKernelSignature(KernelCollector *kernel_collector,
212 const std::string& kernel_signature_file) {
213 std::string kcrash_contents;
214 std::string signature;
215 if (!base::ReadFileToString(FilePath(kernel_signature_file),
216 &kcrash_contents)) {
217 fprintf(stderr, "Could not read file.\n");
218 return 1;
219 }
220 if (!kernel_collector->ComputeKernelStackSignature(
221 kcrash_contents,
222 &signature,
223 true)) {
224 fprintf(stderr, "Signature could not be generated.\n");
225 return 1;
226 }
227 printf("Kernel crash signature is \"%s\".\n", signature.c_str());
228 return 0;
229 }
230
231 // Ensure stdout, stdin, and stderr are open file descriptors. If
232 // they are not, any code which writes to stderr/stdout may write out
233 // to files opened during execution. In particular, when
234 // crash_reporter is run by the kernel coredump pipe handler (via
235 // kthread_create/kernel_execve), it will not have file table entries
236 // 1 and 2 (stdout and stderr) populated. We populate them here.
OpenStandardFileDescriptors()237 static void OpenStandardFileDescriptors() {
238 int new_fd = -1;
239 // We open /dev/null to fill in any of the standard [0, 2] file
240 // descriptors. We leave these open for the duration of the
241 // process. This works because open returns the lowest numbered
242 // invalid fd.
243 do {
244 new_fd = open("/dev/null", 0);
245 CHECK_GE(new_fd, 0) << "Unable to open /dev/null";
246 } while (new_fd >= 0 && new_fd <= 2);
247 close(new_fd);
248 }
249
main(int argc,char * argv[])250 int main(int argc, char *argv[]) {
251 DEFINE_bool(init, false, "Initialize crash logging");
252 DEFINE_bool(clean_shutdown, false, "Signal clean shutdown");
253 DEFINE_string(generate_kernel_signature, "",
254 "Generate signature from given kcrash file");
255 DEFINE_bool(crash_test, false, "Crash test");
256 DEFINE_string(user, "", "User crash info (pid:signal:exec_name)");
257 DEFINE_bool(unclean_check, true, "Check for unclean shutdown");
258
259 #if !defined(__ANDROID__)
260 DEFINE_string(udev, "", "Udev event description (type:device:subsystem)");
261 #endif
262
263 DEFINE_bool(kernel_warning, false, "Report collected kernel warning");
264 DEFINE_string(pid, "", "PID of crashing process");
265 DEFINE_string(uid, "", "UID of crashing process");
266 DEFINE_string(exe, "", "Executable name of crashing process");
267 DEFINE_bool(core2md_failure, false, "Core2md failure test");
268 DEFINE_bool(directory_failure, false, "Spool directory failure test");
269 DEFINE_string(filter_in, "",
270 "Ignore all crashes but this for testing");
271
272 OpenStandardFileDescriptors();
273 FilePath my_path = base::MakeAbsoluteFilePath(FilePath(argv[0]));
274 s_metrics_lib.Init();
275 brillo::FlagHelper::Init(argc, argv, "Chromium OS Crash Reporter");
276 brillo::OpenLog(my_path.BaseName().value().c_str(), true);
277 brillo::InitLog(brillo::kLogToSyslog);
278
279 KernelCollector kernel_collector;
280 kernel_collector.Initialize(CountKernelCrash, IsFeedbackAllowed);
281 UserCollector user_collector;
282 user_collector.Initialize(CountUserCrash,
283 my_path.value(),
284 IsFeedbackAllowed,
285 true, // generate_diagnostics
286 FLAGS_core2md_failure,
287 FLAGS_directory_failure,
288 FLAGS_filter_in);
289 UncleanShutdownCollector unclean_shutdown_collector;
290 unclean_shutdown_collector.Initialize(CountUncleanShutdown,
291 IsFeedbackAllowed);
292
293 #if !defined(__ANDROID__)
294 UdevCollector udev_collector;
295 udev_collector.Initialize(CountUdevCrash, IsFeedbackAllowed);
296 #endif
297
298 KernelWarningCollector kernel_warning_collector;
299 kernel_warning_collector.Initialize(CountUdevCrash, IsFeedbackAllowed);
300
301 if (FLAGS_init) {
302 return Initialize(&kernel_collector,
303 &user_collector,
304 &unclean_shutdown_collector,
305 FLAGS_unclean_check,
306 FLAGS_clean_shutdown);
307 }
308
309 if (FLAGS_clean_shutdown) {
310 unclean_shutdown_collector.Disable();
311 user_collector.Disable();
312 return 0;
313 }
314
315 if (!FLAGS_generate_kernel_signature.empty()) {
316 return GenerateKernelSignature(&kernel_collector,
317 FLAGS_generate_kernel_signature);
318 }
319
320 #if !defined(__ANDROID__)
321 if (!FLAGS_udev.empty()) {
322 return HandleUdevCrash(&udev_collector, FLAGS_udev);
323 }
324 #endif
325
326 if (FLAGS_kernel_warning) {
327 return HandleKernelWarning(&kernel_warning_collector);
328 }
329
330 return HandleUserCrash(&user_collector, FLAGS_user, FLAGS_crash_test);
331 }
332