OSDN Git Service

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