mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			259 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			259 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
 | |
| // 2016 The Chromium Authors. All rights reserved. Use of this source code is
 | |
| // governed by a BSD-style license that can be found in the LICENSE file.
 | |
| 
 | |
| #include "libcef/common/crash_reporting.h"
 | |
| 
 | |
| #include "include/cef_crash_util.h"
 | |
| #include "libcef/common/cef_switches.h"
 | |
| 
 | |
| #include "base/base_switches.h"
 | |
| #include "base/command_line.h"
 | |
| #include "base/debug/crash_logging.h"
 | |
| #include "base/strings/string_piece.h"
 | |
| #include "base/strings/string_util.h"
 | |
| #include "chrome/common/crash_keys.h"
 | |
| #include "components/crash/core/common/crash_key.h"
 | |
| #include "components/crash/core/common/crash_keys.h"
 | |
| #include "content/public/common/content_switches.h"
 | |
| #include "services/service_manager/embedder/switches.h"
 | |
| 
 | |
| #if defined(OS_MACOSX)
 | |
| #include "base/mac/foundation_util.h"
 | |
| #include "components/crash/content/app/crashpad.h"
 | |
| #include "components/crash/core/common/crash_keys.h"
 | |
| #include "content/public/common/content_paths.h"
 | |
| #endif
 | |
| 
 | |
| #if defined(OS_POSIX)
 | |
| #include "base/lazy_instance.h"
 | |
| #include "libcef/common/crash_reporter_client.h"
 | |
| #endif
 | |
| 
 | |
| #if defined(OS_POSIX) && !defined(OS_MACOSX)
 | |
| #include "components/crash/content/app/breakpad_linux.h"
 | |
| #include "v8/include/v8.h"
 | |
| #endif
 | |
| 
 | |
| namespace crash_reporting {
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| #if defined(OS_WIN)
 | |
| 
 | |
| const base::FilePath::CharType kChromeElfDllName[] =
 | |
|     FILE_PATH_LITERAL("chrome_elf.dll");
 | |
| 
 | |
| // exported in crash_reporter_client.cc:
 | |
| //    int __declspec(dllexport) __cdecl SetCrashKeyValueImpl.
 | |
| typedef int(__cdecl* SetCrashKeyValue)(const char*,
 | |
|                                        size_t,
 | |
|                                        const char*,
 | |
|                                        size_t);
 | |
| 
 | |
| //    int __declspec(dllexport) __cdecl IsCrashReportingEnabledImpl.
 | |
| typedef int(__cdecl* IsCrashReportingEnabled)();
 | |
| 
 | |
| bool SetCrashKeyValueTrampoline(const base::StringPiece& key,
 | |
|                                 const base::StringPiece& value) {
 | |
|   static SetCrashKeyValue set_crash_key = []() {
 | |
|     HMODULE elf_module = GetModuleHandle(kChromeElfDllName);
 | |
|     return reinterpret_cast<SetCrashKeyValue>(
 | |
|         elf_module ? GetProcAddress(elf_module, "SetCrashKeyValueImpl")
 | |
|                    : nullptr);
 | |
|   }();
 | |
|   if (set_crash_key) {
 | |
|     return !!(set_crash_key)(key.data(), key.size(), value.data(),
 | |
|                              value.size());
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| bool IsCrashReportingEnabledTrampoline() {
 | |
|   static IsCrashReportingEnabled is_crash_reporting_enabled = []() {
 | |
|     HMODULE elf_module = GetModuleHandle(kChromeElfDllName);
 | |
|     return reinterpret_cast<IsCrashReportingEnabled>(
 | |
|         elf_module ? GetProcAddress(elf_module, "IsCrashReportingEnabledImpl")
 | |
|                    : nullptr);
 | |
|   }();
 | |
|   if (is_crash_reporting_enabled) {
 | |
|     return !!(is_crash_reporting_enabled)();
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| #endif  // defined(OS_WIN)
 | |
| 
 | |
| bool g_crash_reporting_enabled = false;
 | |
| 
 | |
| #if defined(OS_POSIX)
 | |
| base::LazyInstance<CefCrashReporterClient>::Leaky g_crash_reporter_client =
 | |
|     LAZY_INSTANCE_INITIALIZER;
 | |
| 
 | |
| void InitCrashReporter(const base::CommandLine& command_line,
 | |
|                        const std::string& process_type) {
 | |
|   CefCrashReporterClient* crash_client = g_crash_reporter_client.Pointer();
 | |
|   if (!crash_client->HasCrashConfigFile())
 | |
|     return;
 | |
| 
 | |
|   crash_reporter::SetCrashReporterClient(crash_client);
 | |
| 
 | |
| #if defined(OS_MACOSX)
 | |
|   // TODO(mark): Right now, InitializeCrashpad() needs to be called after
 | |
|   // CommandLine::Init() and configuration of chrome::DIR_CRASH_DUMPS. Ideally,
 | |
|   // Crashpad initialization could occur sooner, preferably even before the
 | |
|   // framework dylib is even loaded, to catch potential early crashes.
 | |
|   crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
 | |
| 
 | |
|   if (base::mac::AmIBundled()) {
 | |
|     // Mac Chrome is packaged with a main app bundle and a helper app bundle.
 | |
|     // The main app bundle should only be used for the browser process, so it
 | |
|     // should never see a --type switch (switches::kProcessType).  Likewise,
 | |
|     // the helper should always have a --type switch.
 | |
|     //
 | |
|     // This check is done this late so there is already a call to
 | |
|     // base::mac::IsBackgroundOnlyProcess(), so there is no change in
 | |
|     // startup/initialization order.
 | |
| 
 | |
|     // The helper's Info.plist marks it as a background only app.
 | |
|     if (base::mac::IsBackgroundOnlyProcess()) {
 | |
|       CHECK(command_line.HasSwitch(switches::kProcessType) &&
 | |
|             !process_type.empty())
 | |
|           << "Helper application requires --type.";
 | |
|     } else {
 | |
|       CHECK(!command_line.HasSwitch(switches::kProcessType) &&
 | |
|             process_type.empty())
 | |
|           << "Main application forbids --type, saw " << process_type;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   g_crash_reporting_enabled = true;
 | |
| #else   // !defined(OS_MACOSX)
 | |
|   breakpad::SetCrashServerURL(crash_client->GetCrashServerURL());
 | |
| 
 | |
|   if (process_type != service_manager::switches::kZygoteProcess) {
 | |
|     // Crash reporting for subprocesses created using the zygote will be
 | |
|     // initialized in ZygoteForked.
 | |
|     breakpad::InitCrashReporter(process_type);
 | |
| 
 | |
|     g_crash_reporting_enabled = true;
 | |
|   }
 | |
| #endif  // !defined(OS_MACOSX)
 | |
| }
 | |
| #endif  // defined(OS_POSIX)
 | |
| 
 | |
| // Used to exclude command-line flags from crash reporting.
 | |
| bool IsBoringCEFSwitch(const std::string& flag) {
 | |
|   if (crash_keys::IsBoringChromeSwitch(flag))
 | |
|     return true;
 | |
| 
 | |
|   static const char* const kIgnoreSwitches[] = {
 | |
|       // CEF internals.
 | |
|       switches::kLogFile,
 | |
| 
 | |
|       // Chromium internals.
 | |
|       "content-image-texture-target", "mojo-platform-channel-handle",
 | |
|       "primordial-pipe-token", "service-pipe-token",
 | |
|       "service-request-channel-token",
 | |
|   };
 | |
| 
 | |
|   if (!base::StartsWith(flag, "--", base::CompareCase::SENSITIVE))
 | |
|     return false;
 | |
| 
 | |
|   size_t end = flag.find("=");
 | |
|   size_t len = (end == std::string::npos) ? flag.length() - 2 : end - 2;
 | |
|   for (size_t i = 0; i < arraysize(kIgnoreSwitches); ++i) {
 | |
|     if (flag.compare(2, len, kIgnoreSwitches[i]) == 0)
 | |
|       return true;
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| }  // namespace
 | |
| 
 | |
| bool Enabled() {
 | |
|   return g_crash_reporting_enabled;
 | |
| }
 | |
| 
 | |
| bool SetCrashKeyValue(const base::StringPiece& key,
 | |
|                       const base::StringPiece& value) {
 | |
|   if (!g_crash_reporting_enabled)
 | |
|     return false;
 | |
| 
 | |
| #if defined(OS_WIN)
 | |
|   return SetCrashKeyValueTrampoline(key, value);
 | |
| #else
 | |
|   return g_crash_reporter_client.Pointer()->SetCrashKeyValue(key, value);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| #if defined(OS_POSIX)
 | |
| // Be aware that logging is not initialized at the time this method is called.
 | |
| void BasicStartupComplete(base::CommandLine* command_line) {
 | |
|   CefCrashReporterClient* crash_client = g_crash_reporter_client.Pointer();
 | |
|   if (crash_client->ReadCrashConfigFile()) {
 | |
| #if !defined(OS_MACOSX)
 | |
|     // Breakpad requires this switch.
 | |
|     command_line->AppendSwitch(switches::kEnableCrashReporter);
 | |
| 
 | |
|     breakpad::SetFirstChanceExceptionHandler(v8::V8::TryHandleSignal);
 | |
| #endif
 | |
|   }
 | |
| }
 | |
| #endif
 | |
| 
 | |
| void PreSandboxStartup(const base::CommandLine& command_line,
 | |
|                        const std::string& process_type) {
 | |
| #if defined(OS_POSIX)
 | |
|   // Initialize crash reporting here on macOS and Linux. Crash reporting on
 | |
|   // Windows is initialized from context.cc.
 | |
|   InitCrashReporter(command_line, process_type);
 | |
| #elif defined(OS_WIN)
 | |
|   g_crash_reporting_enabled = IsCrashReportingEnabledTrampoline();
 | |
| #endif
 | |
| 
 | |
|   if (g_crash_reporting_enabled) {
 | |
|     LOG(INFO) << "Crash reporting enabled for process: "
 | |
|               << (process_type.empty() ? "browser" : process_type.c_str());
 | |
|   }
 | |
| 
 | |
|   crash_reporter::InitializeCrashKeys();
 | |
| 
 | |
|   // After platform crash reporting have been initialized, store the command
 | |
|   // line for crash reporting.
 | |
|   crash_keys::SetSwitchesFromCommandLine(command_line, &IsBoringCEFSwitch);
 | |
| }
 | |
| 
 | |
| #if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
 | |
| void ZygoteForked(base::CommandLine* command_line,
 | |
|                   const std::string& process_type) {
 | |
|   CefCrashReporterClient* crash_client = g_crash_reporter_client.Pointer();
 | |
|   if (crash_client->HasCrashConfigFile()) {
 | |
|     // Breakpad requires this switch.
 | |
|     command_line->AppendSwitch(switches::kEnableCrashReporter);
 | |
|   }
 | |
| 
 | |
|   InitCrashReporter(*command_line, process_type);
 | |
| 
 | |
|   if (g_crash_reporting_enabled) {
 | |
|     LOG(INFO) << "Crash reporting enabled for process: " << process_type;
 | |
|   }
 | |
| 
 | |
|   // Reset the command line for the newly spawned process.
 | |
|   crash_keys::SetSwitchesFromCommandLine(*command_line, &IsBoringCEFSwitch);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| }  // namespace crash_reporting
 | |
| 
 | |
| bool CefCrashReportingEnabled() {
 | |
|   return crash_reporting::Enabled();
 | |
| }
 | |
| 
 | |
| void CefSetCrashKeyValue(const CefString& key, const CefString& value) {
 | |
|   if (!crash_reporting::SetCrashKeyValue(key.ToString(), value.ToString())) {
 | |
|     LOG(WARNING) << "Failed to set crash key: " << key.ToString()
 | |
|                  << " with value: " << value.ToString();
 | |
|   }
 | |
| }
 |