| Index: third_party/crashpad/crashpad/handler/handler_main.cc | 
| diff --git a/third_party/crashpad/crashpad/handler/handler_main.cc b/third_party/crashpad/crashpad/handler/handler_main.cc | 
| index 9433a6af5186ec33ebf6c68fb17948adb227381d..5006cf6723f6a59ffcc700d74ae652dc44a61f36 100644 | 
| --- a/third_party/crashpad/crashpad/handler/handler_main.cc | 
| +++ b/third_party/crashpad/crashpad/handler/handler_main.cc | 
| @@ -24,8 +24,10 @@ | 
| #include <memory> | 
| #include <string> | 
| #include <utility> | 
| +#include <vector> | 
|  | 
| #include "base/auto_reset.h" | 
| +#include "base/compiler_specific.h" | 
| #include "base/files/file_path.h" | 
| #include "base/files/scoped_file.h" | 
| #include "base/logging.h" | 
| @@ -64,6 +66,7 @@ | 
| #include "util/win/exception_handler_server.h" | 
| #include "util/win/handle.h" | 
| #include "util/win/initial_client_data.h" | 
| +#include "util/win/session_end_watcher.h" | 
| #endif  // OS_MACOSX | 
|  | 
| namespace crashpad { | 
| @@ -93,6 +96,7 @@ void Usage(const base::FilePath& me) { | 
| #endif  // OS_MACOSX | 
| "      --metrics-dir=DIR       store metrics files in DIR (only in Chromium)\n" | 
| "      --no-rate-limit         don't rate limit crash uploads\n" | 
| +"      --no-upload-gzip        don't use gzip compression when uploading\n" | 
| #if defined(OS_MACOSX) | 
| "      --reset-own-crash-exception-port-to-system-default\n" | 
| "                              reset the server's exception handler to default\n" | 
| @@ -107,11 +111,66 @@ void Usage(const base::FilePath& me) { | 
| ToolSupport::UsageTail(me); | 
| } | 
|  | 
| +// Calls Metrics::HandlerLifetimeMilestone, but only on the first call. This is | 
| +// to prevent multiple exit events from inadvertently being recorded, which | 
| +// might happen if a crash occurs during destruction in what would otherwise be | 
| +// a normal exit, or if a CallMetricsRecordNormalExit object is destroyed after | 
| +// something else logs an exit event. | 
| +void MetricsRecordExit(Metrics::LifetimeMilestone milestone) { | 
| +  static bool once = [](Metrics::LifetimeMilestone milestone) { | 
| +    Metrics::HandlerLifetimeMilestone(milestone); | 
| +    return true; | 
| +  }(milestone); | 
| +  ALLOW_UNUSED_LOCAL(once); | 
| +} | 
| + | 
| +// Calls MetricsRecordExit() to record a failure, and returns EXIT_FAILURE for | 
| +// the convenience of callers in main() which can simply write “return | 
| +// ExitFailure();”. | 
| +int ExitFailure() { | 
| +  MetricsRecordExit(Metrics::LifetimeMilestone::kFailed); | 
| +  return EXIT_FAILURE; | 
| +} | 
| + | 
| +class CallMetricsRecordNormalExit { | 
| + public: | 
| +  CallMetricsRecordNormalExit() {} | 
| +  ~CallMetricsRecordNormalExit() { | 
| +    MetricsRecordExit(Metrics::LifetimeMilestone::kExitedNormally); | 
| +  } | 
| + | 
| + private: | 
| +  DISALLOW_COPY_AND_ASSIGN(CallMetricsRecordNormalExit); | 
| +}; | 
| + | 
| #if defined(OS_MACOSX) | 
|  | 
| -struct sigaction g_original_crash_sigaction[NSIG]; | 
| +void InstallSignalHandler(const std::vector<int>& signals, | 
| +                          void (*handler)(int, siginfo_t*, void*)) { | 
| +  struct sigaction sa = {}; | 
| +  sigemptyset(&sa.sa_mask); | 
| +  sa.sa_flags = SA_SIGINFO; | 
| +  sa.sa_sigaction = handler; | 
| + | 
| +  for (int sig : signals) { | 
| +    int rv = sigaction(sig, &sa, nullptr); | 
| +    PCHECK(rv == 0) << "sigaction " << sig; | 
| +  } | 
| +} | 
| + | 
| +void RestoreDefaultSignalHandler(int sig) { | 
| +  struct sigaction sa = {}; | 
| +  sigemptyset(&sa.sa_mask); | 
| +  sa.sa_flags = 0; | 
| +  sa.sa_handler = SIG_DFL; | 
| +  int rv = sigaction(sig, &sa, nullptr); | 
| +  DPLOG_IF(ERROR, rv != 0) << "sigaction " << sig; | 
| +  ALLOW_UNUSED_LOCAL(rv); | 
| +} | 
|  | 
| void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) { | 
| +  MetricsRecordExit(Metrics::LifetimeMilestone::kCrashed); | 
| + | 
| // Is siginfo->si_code useful? The only interesting values on macOS are 0 (not | 
| // useful, signals generated asynchronously such as by kill() or raise()) and | 
| // small positive numbers (useful, signal generated via a hardware fault). The | 
| @@ -143,22 +202,17 @@ void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) { | 
| } | 
| Metrics::HandlerCrashed(metrics_code); | 
|  | 
| -  // Restore the previous signal handler. | 
| -  DCHECK_GT(sig, 0); | 
| -  DCHECK_LT(static_cast<size_t>(sig), arraysize(g_original_crash_sigaction)); | 
| -  struct sigaction* osa = &g_original_crash_sigaction[sig]; | 
| -  int rv = sigaction(sig, osa, nullptr); | 
| -  DPLOG_IF(ERROR, rv != 0) << "sigaction " << sig; | 
| +  RestoreDefaultSignalHandler(sig); | 
|  | 
| // If the signal was received synchronously resulting from a hardware fault, | 
| // returning from the signal handler will cause the kernel to re-raise it, | 
| // because this handler hasn’t done anything to alleviate the condition that | 
| -  // caused the signal to be raised in the first place. With the old signal | 
| -  // handler in place (expected to be SIG_DFL), it will cause the same behavior | 
| -  // to be taken as though this signal handler had never been installed at all | 
| -  // (expected to be a crash). This is ideal, because the signal is re-raised | 
| -  // with the same properties and from the same context that initially triggered | 
| -  // it, providing the best debugging experience. | 
| +  // caused the signal to be raised in the first place. With the default signal | 
| +  // handler in place, it will cause the same behavior to be taken as though | 
| +  // this signal handler had never been installed at all (expected to be a | 
| +  // crash). This is ideal, because the signal is re-raised with the same | 
| +  // properties and from the same context that initially triggered it, providing | 
| +  // the best debugging experience. | 
|  | 
| if ((sig != SIGILL && sig != SIGFPE && sig != SIGBUS && sig != SIGSEGV) || | 
| !si_code_valid) { | 
| @@ -166,8 +220,7 @@ void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) { | 
| // asynchronously via kill() and raise(), and those arising via hardware | 
| // traps such as int3 (resulting in SIGTRAP but advancing the instruction | 
| // pointer), will not reoccur on their own when returning from the signal | 
| -    // handler. Re-raise them or call to the previous signal handler as | 
| -    // appropriate. | 
| +    // handler. Re-raise them. | 
| // | 
| // Unfortunately, when SIGBUS is received asynchronously via kill(), | 
| // siginfo->si_code makes it appear as though it was actually received via a | 
| @@ -180,49 +233,68 @@ void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) { | 
| // very valuable for debugging and are visible to a Mach exception handler. | 
| // Since SIGBUS is normally received synchronously in response to a hardware | 
| // fault, don’t sweat the unexpected asynchronous case. | 
| -    if (osa->sa_handler == SIG_DFL) { | 
| -      // Because this signal handler executes with the signal blocked, this | 
| -      // raise() cannot immediately deliver the signal. Delivery is deferred | 
| -      // until this signal handler returns and the signal becomes unblocked. The | 
| -      // re-raised signal will appear with the same context as where it was | 
| -      // initially triggered. | 
| -      rv = raise(sig); | 
| -      DPLOG_IF(ERROR, rv != 0) << "raise"; | 
| -    } else if (osa->sa_handler != SIG_IGN) { | 
| -      if (osa->sa_flags & SA_SIGINFO) { | 
| -        osa->sa_sigaction(sig, siginfo, context); | 
| -      } else { | 
| -        osa->sa_handler(sig); | 
| -      } | 
| -    } | 
| +    // | 
| +    // Because this signal handler executes with the signal blocked, this | 
| +    // raise() cannot immediately deliver the signal. Delivery is deferred until | 
| +    // this signal handler returns and the signal becomes unblocked. The | 
| +    // re-raised signal will appear with the same context as where it was | 
| +    // initially triggered. | 
| +    int rv = raise(sig); | 
| +    DPLOG_IF(ERROR, rv != 0) << "raise"; | 
| +    ALLOW_UNUSED_LOCAL(rv); | 
| } | 
| } | 
|  | 
| -void InstallCrashHandler() { | 
| -  struct sigaction sa = {}; | 
| -  sigemptyset(&sa.sa_mask); | 
| -  sa.sa_flags = SA_SIGINFO; | 
| -  sa.sa_sigaction = HandleCrashSignal; | 
| +void HandleTerminateSignal(int sig, siginfo_t* siginfo, void* context) { | 
| +  MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated); | 
| + | 
| +  RestoreDefaultSignalHandler(sig); | 
|  | 
| +  // Re-raise the signal. See the explanation in HandleCrashSignal(). Note that | 
| +  // no checks for signals arising from synchronous hardware faults are made | 
| +  // because termination signals never originate in that way. | 
| +  int rv = raise(sig); | 
| +  DPLOG_IF(ERROR, rv != 0) << "raise"; | 
| +  ALLOW_UNUSED_LOCAL(rv); | 
| +} | 
| + | 
| +void InstallCrashHandler() { | 
| // These are the core-generating signals from 10.12.3 | 
| // xnu-3789.41.3/bsd/sys/signalvar.h sigprop: entries with SA_CORE are in the | 
| // set. | 
| -  const int kSignals[] = {SIGQUIT, | 
| -                          SIGILL, | 
| -                          SIGTRAP, | 
| -                          SIGABRT, | 
| -                          SIGEMT, | 
| -                          SIGFPE, | 
| -                          SIGBUS, | 
| -                          SIGSEGV, | 
| -                          SIGSYS}; | 
| - | 
| -  for (int sig : kSignals) { | 
| -    DCHECK_GT(sig, 0); | 
| -    DCHECK_LT(static_cast<size_t>(sig), arraysize(g_original_crash_sigaction)); | 
| -    int rv = sigaction(sig, &sa, &g_original_crash_sigaction[sig]); | 
| -    PCHECK(rv == 0) << "sigaction " << sig; | 
| -  } | 
| +  const int kCrashSignals[] = {SIGQUIT, | 
| +                               SIGILL, | 
| +                               SIGTRAP, | 
| +                               SIGABRT, | 
| +                               SIGEMT, | 
| +                               SIGFPE, | 
| +                               SIGBUS, | 
| +                               SIGSEGV, | 
| +                               SIGSYS}; | 
| +  InstallSignalHandler( | 
| +      std::vector<int>(&kCrashSignals[0], | 
| +                       &kCrashSignals[arraysize(kCrashSignals)]), | 
| +      HandleCrashSignal); | 
| + | 
| +  // Not a crash handler, but close enough. These are non-core-generating but | 
| +  // terminating signals from 10.12.3 xnu-3789.41.3/bsd/sys/signalvar.h sigprop: | 
| +  // entries with SA_KILL but not SA_CORE are in the set. SIGKILL is excluded | 
| +  // because it is uncatchable. | 
| +  const int kTerminateSignals[] = {SIGHUP, | 
| +                                   SIGINT, | 
| +                                   SIGPIPE, | 
| +                                   SIGALRM, | 
| +                                   SIGTERM, | 
| +                                   SIGXCPU, | 
| +                                   SIGXFSZ, | 
| +                                   SIGVTALRM, | 
| +                                   SIGPROF, | 
| +                                   SIGUSR1, | 
| +                                   SIGUSR2}; | 
| +  InstallSignalHandler( | 
| +      std::vector<int>(&kTerminateSignals[0], | 
| +                       &kTerminateSignals[arraysize(kTerminateSignals)]), | 
| +      HandleTerminateSignal); | 
| } | 
|  | 
| struct ResetSIGTERMTraits { | 
| @@ -242,6 +314,9 @@ ExceptionHandlerServer* g_exception_handler_server; | 
|  | 
| // This signal handler is only operative when being run from launchd. | 
| void HandleSIGTERM(int sig, siginfo_t* siginfo, void* context) { | 
| +  // Don’t call MetricsRecordExit(). This is part of the normal exit path when | 
| +  // running from launchd. | 
| + | 
| DCHECK(g_exception_handler_server); | 
| g_exception_handler_server->Stop(); | 
| } | 
| @@ -251,6 +326,7 @@ void HandleSIGTERM(int sig, siginfo_t* siginfo, void* context) { | 
| LONG(WINAPI* g_original_exception_filter)(EXCEPTION_POINTERS*) = nullptr; | 
|  | 
| LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { | 
| +  MetricsRecordExit(Metrics::LifetimeMilestone::kCrashed); | 
| Metrics::HandlerCrashed(exception_pointers->ExceptionRecord->ExceptionCode); | 
|  | 
| if (g_original_exception_filter) | 
| @@ -259,9 +335,37 @@ LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { | 
| return EXCEPTION_CONTINUE_SEARCH; | 
| } | 
|  | 
| +// Handles events like Control-C and Control-Break on a console. | 
| +BOOL WINAPI ConsoleHandler(DWORD console_event) { | 
| +  MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated); | 
| +  return false; | 
| +} | 
| + | 
| +// Handles a WM_ENDSESSION message sent when the user session is ending. | 
| +class TerminateHandler final : public SessionEndWatcher { | 
| + public: | 
| +  TerminateHandler() : SessionEndWatcher() {} | 
| +  ~TerminateHandler() override {} | 
| + | 
| + private: | 
| +  // SessionEndWatcher: | 
| +  void SessionEnding() override { | 
| +    MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated); | 
| +  } | 
| + | 
| +  DISALLOW_COPY_AND_ASSIGN(TerminateHandler); | 
| +}; | 
| + | 
| void InstallCrashHandler() { | 
| g_original_exception_filter = | 
| SetUnhandledExceptionFilter(&UnhandledExceptionHandler); | 
| + | 
| +  // These are termination handlers, not crash handlers, but that’s close | 
| +  // enough. Note that destroying the TerminateHandler would wait for its thread | 
| +  // to exit, which isn’t necessary or desirable. | 
| +  SetConsoleCtrlHandler(ConsoleHandler, true); | 
| +  static TerminateHandler* terminate_handler = new TerminateHandler(); | 
| +  ALLOW_UNUSED_LOCAL(terminate_handler); | 
| } | 
|  | 
| #endif  // OS_MACOSX | 
| @@ -270,6 +374,7 @@ void InstallCrashHandler() { | 
|  | 
| int HandlerMain(int argc, char* argv[]) { | 
| InstallCrashHandler(); | 
| +  CallMetricsRecordNormalExit metrics_record_normal_exit; | 
|  | 
| const base::FilePath argv0( | 
| ToolSupport::CommandLineArgumentToFilePathStringType(argv[0])); | 
| @@ -291,6 +396,7 @@ int HandlerMain(int argc, char* argv[]) { | 
| #endif  // OS_MACOSX | 
| kOptionMetrics, | 
| kOptionNoRateLimit, | 
| +    kOptionNoUploadGzip, | 
| #if defined(OS_MACOSX) | 
| kOptionResetOwnCrashExceptionPortToSystemDefault, | 
| #elif defined(OS_WIN) | 
| @@ -317,11 +423,13 @@ int HandlerMain(int argc, char* argv[]) { | 
| InitialClientData initial_client_data; | 
| #endif  // OS_MACOSX | 
| bool rate_limit; | 
| +    bool upload_gzip; | 
| } options = {}; | 
| #if defined(OS_MACOSX) | 
| options.handshake_fd = -1; | 
| #endif | 
| options.rate_limit = true; | 
| +  options.upload_gzip = true; | 
|  | 
| const option long_options[] = { | 
| {"annotation", required_argument, nullptr, kOptionAnnotation}, | 
| @@ -340,6 +448,7 @@ int HandlerMain(int argc, char* argv[]) { | 
| #endif  // OS_MACOSX | 
| {"metrics-dir", required_argument, nullptr, kOptionMetrics}, | 
| {"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit}, | 
| +    {"no-upload-gzip", no_argument, nullptr, kOptionNoUploadGzip}, | 
| #if defined(OS_MACOSX) | 
| {"reset-own-crash-exception-port-to-system-default", | 
| no_argument, | 
| @@ -362,7 +471,7 @@ int HandlerMain(int argc, char* argv[]) { | 
| std::string value; | 
| if (!SplitStringFirst(optarg, '=', &key, &value)) { | 
| ToolSupport::UsageHint(me, "--annotation requires KEY=VALUE"); | 
| -          return EXIT_FAILURE; | 
| +          return ExitFailure(); | 
| } | 
| std::string old_value; | 
| if (!MapInsertOrReplace(&options.annotations, key, value, &old_value)) { | 
| @@ -381,7 +490,7 @@ int HandlerMain(int argc, char* argv[]) { | 
| options.handshake_fd < 0) { | 
| ToolSupport::UsageHint(me, | 
| "--handshake-fd requires a file descriptor"); | 
| -          return EXIT_FAILURE; | 
| +          return ExitFailure(); | 
| } | 
| break; | 
| } | 
| @@ -394,7 +503,7 @@ int HandlerMain(int argc, char* argv[]) { | 
| if (!options.initial_client_data.InitializeFromString(optarg)) { | 
| ToolSupport::UsageHint( | 
| me, "failed to parse --initial-client-data"); | 
| -          return EXIT_FAILURE; | 
| +          return ExitFailure(); | 
| } | 
| break; | 
| } | 
| @@ -407,6 +516,10 @@ int HandlerMain(int argc, char* argv[]) { | 
| options.rate_limit = false; | 
| break; | 
| } | 
| +      case kOptionNoUploadGzip: { | 
| +        options.upload_gzip = false; | 
| +        break; | 
| +      } | 
| #if defined(OS_MACOSX) | 
| case kOptionResetOwnCrashExceptionPortToSystemDefault: { | 
| options.reset_own_crash_exception_port_to_system_default = true; | 
| @@ -424,15 +537,17 @@ int HandlerMain(int argc, char* argv[]) { | 
| } | 
| case kOptionHelp: { | 
| Usage(me); | 
| +        MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly); | 
| return EXIT_SUCCESS; | 
| } | 
| case kOptionVersion: { | 
| ToolSupport::Version(me); | 
| +        MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly); | 
| return EXIT_SUCCESS; | 
| } | 
| default: { | 
| ToolSupport::UsageHint(me, nullptr); | 
| -        return EXIT_FAILURE; | 
| +        return ExitFailure(); | 
| } | 
| } | 
| } | 
| @@ -442,34 +557,34 @@ int HandlerMain(int argc, char* argv[]) { | 
| #if defined(OS_MACOSX) | 
| if (options.handshake_fd < 0 && options.mach_service.empty()) { | 
| ToolSupport::UsageHint(me, "--handshake-fd or --mach-service is required"); | 
| -    return EXIT_FAILURE; | 
| +    return ExitFailure(); | 
| } | 
| if (options.handshake_fd >= 0 && !options.mach_service.empty()) { | 
| ToolSupport::UsageHint( | 
| me, "--handshake-fd and --mach-service are incompatible"); | 
| -    return EXIT_FAILURE; | 
| +    return ExitFailure(); | 
| } | 
| #elif defined(OS_WIN) | 
| if (!options.initial_client_data.IsValid() && options.pipe_name.empty()) { | 
| ToolSupport::UsageHint(me, | 
| "--initial-client-data or --pipe-name is required"); | 
| -    return EXIT_FAILURE; | 
| +    return ExitFailure(); | 
| } | 
| if (options.initial_client_data.IsValid() && !options.pipe_name.empty()) { | 
| ToolSupport::UsageHint( | 
| me, "--initial-client-data and --pipe-name are incompatible"); | 
| -    return EXIT_FAILURE; | 
| +    return ExitFailure(); | 
| } | 
| #endif  // OS_MACOSX | 
|  | 
| if (!options.database) { | 
| ToolSupport::UsageHint(me, "--database is required"); | 
| -    return EXIT_FAILURE; | 
| +    return ExitFailure(); | 
| } | 
|  | 
| if (argc) { | 
| ToolSupport::UsageHint(me, nullptr); | 
| -    return EXIT_FAILURE; | 
| +    return ExitFailure(); | 
| } | 
|  | 
| #if defined(OS_MACOSX) | 
| @@ -494,7 +609,7 @@ int HandlerMain(int argc, char* argv[]) { | 
| } | 
|  | 
| if (!receive_right.is_valid()) { | 
| -    return EXIT_FAILURE; | 
| +    return ExitFailure(); | 
| } | 
|  | 
| ExceptionHandlerServer exception_handler_server( | 
| @@ -511,6 +626,7 @@ int HandlerMain(int argc, char* argv[]) { | 
| // launchd.plist(5). | 
| // | 
| // Set up a SIGTERM handler that will call exception_handler_server.Stop(). | 
| +    // This replaces the HandleTerminateSignal handler for SIGTERM. | 
| struct sigaction sa = {}; | 
| sigemptyset(&sa.sa_mask); | 
| sa.sa_flags = SA_SIGINFO; | 
| @@ -544,18 +660,20 @@ int HandlerMain(int argc, char* argv[]) { | 
| } | 
| } | 
|  | 
| +  Metrics::HandlerLifetimeMilestone(Metrics::LifetimeMilestone::kStarted); | 
| + | 
| std::unique_ptr<CrashReportDatabase> database(CrashReportDatabase::Initialize( | 
| base::FilePath(ToolSupport::CommandLineArgumentToFilePathStringType( | 
| options.database)))); | 
| if (!database) { | 
| -    return EXIT_FAILURE; | 
| +    return ExitFailure(); | 
| } | 
|  | 
| // TODO(scottmg): options.rate_limit should be removed when we have a | 
| // configurable database setting to control upload limiting. | 
| // See https://crashpad.chromium.org/bug/23. | 
| CrashReportUploadThread upload_thread( | 
| -      database.get(), options.url, options.rate_limit); | 
| +      database.get(), options.url, options.rate_limit, options.upload_gzip); | 
| upload_thread.Start(); | 
|  | 
| PruneCrashReportThread prune_thread(database.get(), | 
|  |