Home | History | Annotate | Download | only in crash_reporter
      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 
     68 static bool IsFeedbackAllowed() {
     69   return s_metrics_lib.AreMetricsEnabled();
     70 }
     71 
     72 static bool TouchFile(const FilePath &file_path) {
     73   return base::WriteFile(file_path, "", 0) == 0;
     74 }
     75 
     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 
     83 static void CountKernelCrash() {
     84   SendCrashMetrics(kCrashKindKernel, "kernel");
     85 }
     86 
     87 static void CountUdevCrash() {
     88   SendCrashMetrics(kCrashKindUdev, "udevcrash");
     89 }
     90 
     91 static void CountUncleanShutdown() {
     92   SendCrashMetrics(kCrashKindUncleanShutdown, "uncleanshutdown");
     93 }
     94 
     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 
    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 
    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__)
    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 
    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.
    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.
    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 
    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