mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			797 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			797 lines
		
	
	
		
			25 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_reporter_client.h"
 | |
| 
 | |
| #include <utility>
 | |
| 
 | |
| #if defined(OS_WIN)
 | |
| #include <windows.h>
 | |
| #endif
 | |
| 
 | |
| #include "base/environment.h"
 | |
| #include "base/logging.h"
 | |
| #include "base/strings/string16.h"
 | |
| #include "base/strings/string_number_conversions.h"
 | |
| #include "base/strings/string_split.h"
 | |
| #include "base/strings/string_util.h"
 | |
| #include "base/strings/utf_string_conversions.h"
 | |
| #include "components/crash/core/common/crash_key.h"
 | |
| #include "services/service_manager/embedder/switches.h"
 | |
| #include "third_party/crashpad/crashpad/client/annotation.h"
 | |
| 
 | |
| #if defined(OS_MACOSX)
 | |
| #include "libcef/common/util_mac.h"
 | |
| #endif
 | |
| 
 | |
| #if defined(OS_POSIX)
 | |
| // Don't use CommandLine, FilePath or PathService on Windows. FilePath has
 | |
| // dependencies outside of kernel32, which is disallowed by chrome_elf.
 | |
| // CommandLine and PathService depend on global state that will not be
 | |
| // initialized at the time the CefCrashReporterClient object is created.
 | |
| #include "base/command_line.h"
 | |
| #include "base/environment.h"
 | |
| #include "base/files/file_path.h"
 | |
| #include "base/path_service.h"
 | |
| #include "chrome/common/chrome_paths.h"
 | |
| #endif
 | |
| 
 | |
| #if defined(OS_POSIX) && !defined(OS_MACOSX)
 | |
| #include "content/public/common/content_switches.h"
 | |
| #include "libcef/common/cef_crash_report_utils.h"
 | |
| #endif
 | |
| 
 | |
| #if defined(OS_WIN)
 | |
| #include "base/debug/leak_annotations.h"
 | |
| #include "chrome/install_static/install_util.h"
 | |
| #include "components/crash/content/app/crashpad.h"
 | |
| #endif
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| #if defined(OS_WIN)
 | |
| typedef base::string16 PathString;
 | |
| const char kPathSep = '\\';
 | |
| #else
 | |
| typedef std::string PathString;
 | |
| #endif
 | |
| 
 | |
| PathString GetCrashConfigPath() {
 | |
| #if defined(OS_WIN)
 | |
|   // Start with the path to the running executable.
 | |
|   wchar_t module_path[MAX_PATH];
 | |
|   if (GetModuleFileName(nullptr, module_path, MAX_PATH) == 0)
 | |
|     return PathString();
 | |
| 
 | |
|   PathString config_path = module_path;
 | |
| 
 | |
|   // Remove the executable file name.
 | |
|   PathString::size_type last_backslash =
 | |
|       config_path.rfind(kPathSep, config_path.size());
 | |
|   if (last_backslash != PathString::npos)
 | |
|     config_path.erase(last_backslash + 1);
 | |
| 
 | |
|   config_path += L"crash_reporter.cfg";
 | |
|   return config_path;
 | |
| #elif defined(OS_POSIX)
 | |
|   base::FilePath config_path;
 | |
| 
 | |
| #if defined(OS_MACOSX)
 | |
|   // Start with the path to the main app Resources directory. May be empty if
 | |
|   // not running in an app bundle.
 | |
|   config_path = util_mac::GetMainResourcesDirectory();
 | |
| #endif
 | |
| 
 | |
|   if (config_path.empty()) {
 | |
|     // Start with the path to the running executable.
 | |
|     if (!base::PathService::Get(base::DIR_EXE, &config_path))
 | |
|       return PathString();
 | |
|   }
 | |
| 
 | |
|   return config_path.Append(FILE_PATH_LITERAL("crash_reporter.cfg")).value();
 | |
| #endif  // defined(OS_POSIX)
 | |
| }
 | |
| 
 | |
| #if defined(OS_WIN)
 | |
| 
 | |
| // On Windows, FAT32 and NTFS both limit filenames to a maximum of 255
 | |
| // characters. On POSIX systems, the typical filename length limit is 255
 | |
| // character units. HFS+'s limit is actually 255 Unicode characters using
 | |
| // Apple's modification of Normalization Form D, but the differences aren't
 | |
| // really worth dealing with here.
 | |
| const unsigned maxFilenameLength = 255;
 | |
| 
 | |
| const char kInvalidFileChars[] = "<>:\"/\\|?*";
 | |
| 
 | |
| bool isInvalidFileCharacter(unsigned char c) {
 | |
|   if (c < ' ' || c == 0x7F)
 | |
|     return true;
 | |
|   for (size_t i = 0; i < sizeof(kInvalidFileChars); ++i) {
 | |
|     if (c == kInvalidFileChars[i])
 | |
|       return true;
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| bool isAbsolutePath(const std::string& s) {
 | |
|   // Check for local paths (beginning with "c:\") and network paths
 | |
|   // (beginning with "\\").
 | |
|   return s.length() > 2 &&
 | |
|          ((isalpha(s[0]) && s[1] == ':' && s[2] == kPathSep) ||
 | |
|           (s[0] == kPathSep && s[1] == kPathSep));
 | |
| }
 | |
| 
 | |
| std::string extractAbsolutePathStart(std::string& s) {
 | |
|   if (!isAbsolutePath(s))
 | |
|     return std::string();
 | |
| 
 | |
|   std::string start;
 | |
|   if (s[0] == kPathSep) {
 | |
|     // Network path.
 | |
|     start = s.substr(0, 2);
 | |
|     s = s.substr(2);
 | |
|   } else {
 | |
|     // Local path.
 | |
|     start = s.substr(0, 3);
 | |
|     s = s.substr(3);
 | |
|   }
 | |
|   return start;
 | |
| }
 | |
| 
 | |
| std::string sanitizePathComponentPart(const std::string& s) {
 | |
|   if (s.empty())
 | |
|     return std::string();
 | |
| 
 | |
|   std::string result;
 | |
|   result.reserve(s.length());
 | |
|   for (size_t i = 0; i < s.length(); ++i) {
 | |
|     if (!isInvalidFileCharacter(s[i]))
 | |
|       result.push_back(s[i]);
 | |
|   }
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| std::string sanitizePathComponent(const std::string& s) {
 | |
|   std::string name, ext;
 | |
| 
 | |
|   // Separate name and extension, if any.
 | |
|   std::string::size_type pos = s.rfind('.');
 | |
|   if (pos != std::string::npos) {
 | |
|     name = s.substr(0, pos);
 | |
|     ext = s.substr(pos + 1);
 | |
|   } else {
 | |
|     name = s;
 | |
|   }
 | |
| 
 | |
|   // Remove invalid characters.
 | |
|   name = sanitizePathComponentPart(name);
 | |
|   ext = sanitizePathComponentPart(ext);
 | |
| 
 | |
|   // Remove a ridiculously-long extension.
 | |
|   if (ext.length() >= maxFilenameLength)
 | |
|     ext = std::string();
 | |
| 
 | |
|   // Truncate an overly-long filename, reserving one character for a dot.
 | |
|   std::string::size_type max_name_len = maxFilenameLength - ext.length() - 1;
 | |
|   if (name.length() > max_name_len)
 | |
|     name = name.substr(0, max_name_len);
 | |
| 
 | |
|   return ext.empty() ? name : name + "." + ext;
 | |
| }
 | |
| 
 | |
| std::string sanitizePath(const std::string& s) {
 | |
|   std::string path = s;
 | |
| 
 | |
|   // Extract the absolute path start component, if any (e.g. "c:\" on Windows).
 | |
|   std::string result = extractAbsolutePathStart(path);
 | |
|   result.reserve(s.length());
 | |
| 
 | |
|   std::vector<std::string> parts =
 | |
|       base::SplitString(path, std::string() + kPathSep, base::KEEP_WHITESPACE,
 | |
|                         base::SPLIT_WANT_NONEMPTY);
 | |
|   for (size_t i = 0; i < parts.size(); ++i) {
 | |
|     std::string part = parts[i];
 | |
|     if (part != "." && part != "..")
 | |
|       part = sanitizePathComponent(part);
 | |
|     if (!result.empty() && result[result.length() - 1] != kPathSep)
 | |
|       result += kPathSep;
 | |
|     result += part;
 | |
|   }
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| std::string joinPath(const std::string& s1, const std::string& s2) {
 | |
|   if (s1.empty() && s2.empty())
 | |
|     return std::string();
 | |
|   if (s1.empty())
 | |
|     return s2;
 | |
|   if (s2.empty())
 | |
|     return s1;
 | |
| 
 | |
|   // Don't try to join absolute paths on Windows.
 | |
|   // Skip this check on POSIX where it's more difficult to differentiate.
 | |
|   if (isAbsolutePath(s2))
 | |
|     return s2;
 | |
| 
 | |
|   std::string result = s1;
 | |
|   if (result[result.size() - 1] != kPathSep)
 | |
|     result += kPathSep;
 | |
|   if (s2[0] == kPathSep)
 | |
|     result += s2.substr(1);
 | |
|   else
 | |
|     result += s2;
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| // This will only be non-nullptr in the chrome_elf address space.
 | |
| CefCrashReporterClient* g_crash_reporter_client = nullptr;
 | |
| 
 | |
| #endif  // defined(OS_WIN)
 | |
| 
 | |
| const char kKeyMapDelim = ',';
 | |
| 
 | |
| std::string NormalizeCrashKey(const base::StringPiece& key) {
 | |
|   std::string str = key.as_string();
 | |
|   std::replace(str.begin(), str.end(), kKeyMapDelim, '-');
 | |
|   if (str.length() > crashpad::Annotation::kNameMaxLength) {
 | |
|     return str.substr(0, crashpad::Annotation::kNameMaxLength);
 | |
|   }
 | |
|   return str;
 | |
| }
 | |
| 
 | |
| void ParseURL(const std::string& value, std::string* url) {
 | |
|   if (value.find("http://") == 0 || value.find("https://") == 0) {
 | |
|     *url = value;
 | |
|     if (url->rfind('/') <= 8) {
 | |
|       // Make sure the URL includes a path component. Otherwise, crash
 | |
|       // upload will fail on older Windows versions due to
 | |
|       // https://crbug.com/826564.
 | |
|       *url += "/";
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool ParseBool(const std::string& value) {
 | |
|   return base::EqualsCaseInsensitiveASCII(value, "true") || value == "1";
 | |
| }
 | |
| 
 | |
| int ParseZeroBasedInt(const std::string& value) {
 | |
|   int int_val;
 | |
|   if (base::StringToInt(value, &int_val) && int_val > 0)
 | |
|     return int_val;
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| }  // namespace
 | |
| 
 | |
| #if defined(OS_WIN)
 | |
| 
 | |
| extern "C" {
 | |
| 
 | |
| // Export functions from chrome_elf that are required by crash_reporting.cc
 | |
| 
 | |
| int __declspec(dllexport) __cdecl SetCrashKeyValueImpl(const char* key,
 | |
|                                                        size_t key_size,
 | |
|                                                        const char* value,
 | |
|                                                        size_t value_size) {
 | |
|   if (g_crash_reporter_client) {
 | |
|     return g_crash_reporter_client->SetCrashKeyValue(
 | |
|         base::StringPiece(key, key_size), base::StringPiece(value, value_size));
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int __declspec(dllexport) __cdecl IsCrashReportingEnabledImpl() {
 | |
|   return g_crash_reporter_client &&
 | |
|          g_crash_reporter_client->HasCrashConfigFile();
 | |
| }
 | |
| 
 | |
| }  // extern "C"
 | |
| 
 | |
| // The below functions were deleted from chrome/install_static/install_util.cc
 | |
| // in https://crbug.com/565446#c17.
 | |
| 
 | |
| constexpr wchar_t kUserDataDirname[] = L"User Data";
 | |
| 
 | |
| // Populates |result| with the default User Data directory for the current
 | |
| // user.This may be overidden by a command line option. Returns false if all
 | |
| // attempts at locating a User Data directory fail.
 | |
| bool GetDefaultUserDataDirectory(std::wstring* result,
 | |
|                                  const std::wstring& install_sub_directory) {
 | |
|   // This environment variable should be set on Windows Vista and later
 | |
|   // (https://msdn.microsoft.com/library/windows/desktop/dd378457.aspx).
 | |
|   std::wstring user_data_dir =
 | |
|       install_static::GetEnvironmentString16(L"LOCALAPPDATA");
 | |
| 
 | |
|   if (user_data_dir.empty()) {
 | |
|     // LOCALAPPDATA was not set; fallback to the temporary files path.
 | |
|     DWORD size = ::GetTempPath(0, nullptr);
 | |
|     if (!size)
 | |
|       return false;
 | |
|     user_data_dir.resize(size + 1);
 | |
|     size = ::GetTempPath(size + 1, &user_data_dir[0]);
 | |
|     if (!size || size >= user_data_dir.size())
 | |
|       return false;
 | |
|     user_data_dir.resize(size);
 | |
|   }
 | |
| 
 | |
|   result->swap(user_data_dir);
 | |
|   if ((*result)[result->length() - 1] != L'\\')
 | |
|     result->push_back(L'\\');
 | |
|   result->append(install_sub_directory);
 | |
|   result->push_back(L'\\');
 | |
|   result->append(kUserDataDirname);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Populates |crash_dir| with the default crash dump location regardless of
 | |
| // whether DIR_USER_DATA or DIR_CRASH_DUMPS has been overridden.
 | |
| bool GetDefaultCrashDumpLocation(std::wstring* crash_dir,
 | |
|                                  const std::wstring& install_sub_directory) {
 | |
|   // In order to be able to start crash handling very early, we do not rely on
 | |
|   // chrome's PathService entries (for DIR_CRASH_DUMPS) being available on
 | |
|   // Windows. See https://crbug.com/564398.
 | |
|   if (!GetDefaultUserDataDirectory(crash_dir, install_sub_directory))
 | |
|     return false;
 | |
| 
 | |
|   // We have to make sure the user data dir exists on first run. See
 | |
|   // http://crbug.com/591504.
 | |
|   if (!install_static::RecursiveDirectoryCreate(*crash_dir))
 | |
|     return false;
 | |
|   crash_dir->append(L"\\Crashpad");
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| #endif  // OS_WIN
 | |
| 
 | |
| CefCrashReporterClient::CefCrashReporterClient() {}
 | |
| CefCrashReporterClient::~CefCrashReporterClient() {}
 | |
| 
 | |
| // Be aware that logging is not initialized at the time this method is called.
 | |
| bool CefCrashReporterClient::ReadCrashConfigFile() {
 | |
|   if (has_crash_config_file_)
 | |
|     return true;
 | |
| 
 | |
|   PathString config_path = GetCrashConfigPath();
 | |
|   if (config_path.empty())
 | |
|     return false;
 | |
| 
 | |
| #if defined(OS_WIN)
 | |
|   FILE* fp = _wfopen(config_path.c_str(), L"r");
 | |
| #else
 | |
|   FILE* fp = fopen(config_path.c_str(), "r");
 | |
| #endif
 | |
|   if (!fp)
 | |
|     return false;
 | |
| 
 | |
|   char line[1000];
 | |
| 
 | |
|   size_t small_index = 0;
 | |
|   size_t medium_index = 0;
 | |
|   size_t large_index = 0;
 | |
|   std::string map_keys;
 | |
| 
 | |
|   enum section {
 | |
|     kNoSection,
 | |
|     kConfigSection,
 | |
|     kCrashKeysSection,
 | |
|   } current_section = kNoSection;
 | |
| 
 | |
|   while (fgets(line, sizeof(line) - 1, fp) != NULL) {
 | |
|     std::string str = line;
 | |
|     base::TrimString(str, base::kWhitespaceASCII, &str);
 | |
|     if (str.empty() || str[0] == '#')
 | |
|       continue;
 | |
| 
 | |
|     if (str == "[Config]") {
 | |
|       current_section = kConfigSection;
 | |
|       continue;
 | |
|     } else if (str == "[CrashKeys]") {
 | |
|       current_section = kCrashKeysSection;
 | |
|       continue;
 | |
|     } else if (str[0] == '[') {
 | |
|       current_section = kNoSection;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (current_section == kNoSection)
 | |
|       continue;
 | |
| 
 | |
|     size_t div = str.find('=');
 | |
|     if (div == std::string::npos)
 | |
|       continue;
 | |
| 
 | |
|     std::string name_str = str.substr(0, div);
 | |
|     base::TrimString(name_str, base::kWhitespaceASCII, &name_str);
 | |
|     std::string val_str = str.substr(div + 1);
 | |
|     base::TrimString(val_str, base::kWhitespaceASCII, &val_str);
 | |
|     if (name_str.empty())
 | |
|       continue;
 | |
| 
 | |
|     if (current_section == kConfigSection) {
 | |
|       if (name_str == "ServerURL") {
 | |
|         ParseURL(val_str, &server_url_);
 | |
|       } else if (name_str == "ProductName") {
 | |
|         product_name_ = val_str;
 | |
|       } else if (name_str == "ProductVersion") {
 | |
|         product_version_ = val_str;
 | |
|       } else if (name_str == "RateLimitEnabled") {
 | |
|         rate_limit_ = ParseBool(val_str);
 | |
|       } else if (name_str == "MaxUploadsPerDay") {
 | |
|         max_uploads_ = ParseZeroBasedInt(val_str);
 | |
|       } else if (name_str == "MaxDatabaseSizeInMb") {
 | |
|         max_db_size_ = ParseZeroBasedInt(val_str);
 | |
|       } else if (name_str == "MaxDatabaseAgeInDays") {
 | |
|         max_db_age_ = ParseZeroBasedInt(val_str);
 | |
|       }
 | |
| #if defined(OS_WIN)
 | |
|       else if (name_str == "ExternalHandler") {
 | |
|         if (!val_str.empty())
 | |
|           external_handler_ = sanitizePath(val_str);
 | |
|       } else if (name_str == "AppName") {
 | |
|         if (!val_str.empty()) {
 | |
|           val_str = sanitizePathComponent(val_str);
 | |
|           if (!val_str.empty())
 | |
|             app_name_ = val_str;
 | |
|         }
 | |
|       }
 | |
| #elif defined(OS_MACOSX)
 | |
|       else if (name_str == "BrowserCrashForwardingEnabled") {
 | |
|         enable_browser_crash_forwarding_ = ParseBool(val_str);
 | |
|       }
 | |
| #endif
 | |
|     } else if (current_section == kCrashKeysSection) {
 | |
|       // Skip duplicate definitions.
 | |
|       if (!crash_keys_.empty() &&
 | |
|           crash_keys_.find(name_str) != crash_keys_.end()) {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       KeySize size;
 | |
|       size_t index;
 | |
|       char group;
 | |
|       if (val_str == "small") {
 | |
|         size = SMALL_SIZE;
 | |
|         index = small_index++;
 | |
|         group = 'S';
 | |
|       } else if (val_str == "medium") {
 | |
|         size = MEDIUM_SIZE;
 | |
|         index = medium_index++;
 | |
|         group = 'M';
 | |
|       } else if (val_str == "large") {
 | |
|         size = LARGE_SIZE;
 | |
|         index = large_index++;
 | |
|         group = 'L';
 | |
|       } else {
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       name_str = NormalizeCrashKey(name_str);
 | |
|       crash_keys_.insert(std::make_pair(name_str, std::make_pair(size, index)));
 | |
| 
 | |
|       const std::string& key =
 | |
|           std::string(1, group) + "-" + std::string(1, 'A' + index);
 | |
|       if (!map_keys.empty()) {
 | |
|         map_keys.append(std::string(1, kKeyMapDelim));
 | |
|       }
 | |
|       map_keys.append(key + "=" + name_str);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   fclose(fp);
 | |
| 
 | |
|   if (!map_keys.empty()) {
 | |
|     // Split |map_keys| across multiple Annotations if necessary.
 | |
|     // Must match the logic in crash_report_utils::FilterParameters.
 | |
|     using IDKey =
 | |
|         crash_reporter::CrashKeyString<crashpad::Annotation::kValueMaxSize>;
 | |
|     static IDKey ids[] = {
 | |
|         {"K-A", IDKey::Tag::kArray},
 | |
|         {"K-B", IDKey::Tag::kArray},
 | |
|         {"K-C", IDKey::Tag::kArray},
 | |
|     };
 | |
| 
 | |
|     // Make sure we can fit all possible name/value pairs.
 | |
|     static_assert(arraysize(ids) * crashpad::Annotation::kValueMaxSize >=
 | |
|                       3 * 26 /* sizes (small, medium, large) * slots (A to Z) */
 | |
|                           * (3 + 2 /* key size ("S-A") + delim size ("=,") */
 | |
|                              + crashpad::Annotation::kNameMaxLength),
 | |
|                   "Not enough storage for key map");
 | |
| 
 | |
|     size_t offset = 0;
 | |
|     for (size_t i = 0; i < arraysize(ids); ++i) {
 | |
|       size_t length = std::min(map_keys.size() - offset,
 | |
|                                crashpad::Annotation::kValueMaxSize);
 | |
|       ids[i].Set(base::StringPiece(map_keys.data() + offset, length));
 | |
|       offset += length;
 | |
|       if (offset >= map_keys.size())
 | |
|         break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Allow override of some values via environment variables.
 | |
|   {
 | |
|     std::unique_ptr<base::Environment> env(base::Environment::Create());
 | |
|     std::string val_str;
 | |
| 
 | |
|     if (env->GetVar("CEF_CRASH_REPORTER_SERVER_URL", &val_str)) {
 | |
|       ParseURL(val_str, &server_url_);
 | |
|     }
 | |
|     if (env->GetVar("CEF_CRASH_REPORTER_RATE_LIMIT_ENABLED", &val_str)) {
 | |
|       rate_limit_ = ParseBool(val_str);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   has_crash_config_file_ = true;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool CefCrashReporterClient::HasCrashConfigFile() const {
 | |
|   return has_crash_config_file_;
 | |
| }
 | |
| 
 | |
| #if defined(OS_WIN)
 | |
| 
 | |
| // static
 | |
| void CefCrashReporterClient::InitializeCrashReportingForProcess() {
 | |
|   if (g_crash_reporter_client)
 | |
|     return;
 | |
| 
 | |
|   g_crash_reporter_client = new CefCrashReporterClient();
 | |
|   ANNOTATE_LEAKING_OBJECT_PTR(g_crash_reporter_client);
 | |
| 
 | |
|   if (!g_crash_reporter_client->ReadCrashConfigFile())
 | |
|     return;
 | |
| 
 | |
|   std::wstring process_type = install_static::GetSwitchValueFromCommandLine(
 | |
|       ::GetCommandLineW(), install_static::kProcessType);
 | |
|   if (process_type != install_static::kCrashpadHandler) {
 | |
|     crash_reporter::SetCrashReporterClient(g_crash_reporter_client);
 | |
| 
 | |
|     // If |embedded_handler| is true then we launch another instance of the main
 | |
|     // executable as the crashpad-handler process.
 | |
|     const bool embedded_handler =
 | |
|         !g_crash_reporter_client->HasCrashExternalHandler();
 | |
|     if (embedded_handler) {
 | |
|       crash_reporter::InitializeCrashpadWithEmbeddedHandler(
 | |
|           process_type.empty(), install_static::UTF16ToUTF8(process_type),
 | |
|           std::string(), base::FilePath());
 | |
|     } else {
 | |
|       crash_reporter::InitializeCrashpad(
 | |
|           process_type.empty(), install_static::UTF16ToUTF8(process_type));
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool CefCrashReporterClient::GetAlternativeCrashDumpLocation(
 | |
|     base::string16* crash_dir) {
 | |
|   // By setting the BREAKPAD_DUMP_LOCATION environment variable, an alternate
 | |
|   // location to write breakpad crash dumps can be set.
 | |
|   *crash_dir =
 | |
|       install_static::GetEnvironmentString16(L"BREAKPAD_DUMP_LOCATION");
 | |
|   return !crash_dir->empty();
 | |
| }
 | |
| 
 | |
| void CefCrashReporterClient::GetProductNameAndVersion(
 | |
|     const base::string16& exe_path,
 | |
|     base::string16* product_name,
 | |
|     base::string16* version,
 | |
|     base::string16* special_build,
 | |
|     base::string16* channel_name) {
 | |
|   *product_name = base::ASCIIToUTF16(product_name_);
 | |
|   *version = base::ASCIIToUTF16(product_version_);
 | |
|   *special_build = base::string16();
 | |
|   *channel_name = base::string16();
 | |
| }
 | |
| 
 | |
| bool CefCrashReporterClient::GetCrashDumpLocation(base::string16* crash_dir) {
 | |
|   // By setting the BREAKPAD_DUMP_LOCATION environment variable, an alternate
 | |
|   // location to write breakpad crash dumps can be set.
 | |
|   if (GetAlternativeCrashDumpLocation(crash_dir))
 | |
|     return true;
 | |
| 
 | |
|   return GetDefaultCrashDumpLocation(crash_dir, base::UTF8ToUTF16(app_name_));
 | |
| }
 | |
| 
 | |
| bool CefCrashReporterClient::GetCrashMetricsLocation(
 | |
|     base::string16* metrics_dir) {
 | |
|   return GetDefaultUserDataDirectory(metrics_dir, base::UTF8ToUTF16(app_name_));
 | |
| }
 | |
| 
 | |
| #elif defined(OS_POSIX)
 | |
| 
 | |
| void CefCrashReporterClient::GetProductNameAndVersion(const char** product_name,
 | |
|                                                       const char** version) {
 | |
|   *product_name = product_name_.c_str();
 | |
|   *version = product_version_.c_str();
 | |
| }
 | |
| 
 | |
| void CefCrashReporterClient::GetProductNameAndVersion(std::string* product_name,
 | |
|                                                       std::string* version,
 | |
|                                                       std::string* channel) {
 | |
|   *product_name = product_name_;
 | |
|   *version = product_version_;
 | |
| }
 | |
| 
 | |
| #if !defined(OS_MACOSX)
 | |
| 
 | |
| base::FilePath CefCrashReporterClient::GetReporterLogFilename() {
 | |
|   return base::FilePath(FILE_PATH_LITERAL("uploads.log"));
 | |
| }
 | |
| 
 | |
| bool CefCrashReporterClient::EnableBreakpadForProcess(
 | |
|     const std::string& process_type) {
 | |
|   return process_type == switches::kRendererProcess ||
 | |
|          process_type == switches::kPpapiPluginProcess ||
 | |
|          process_type == service_manager::switches::kZygoteProcess ||
 | |
|          process_type == switches::kGpuProcess;
 | |
| }
 | |
| 
 | |
| #endif  // !defined(OS_MACOSX)
 | |
| 
 | |
| bool CefCrashReporterClient::GetCrashDumpLocation(base::FilePath* crash_dir) {
 | |
|   // By setting the BREAKPAD_DUMP_LOCATION environment variable, an alternate
 | |
|   // location to write breakpad crash dumps can be set.
 | |
|   std::unique_ptr<base::Environment> env(base::Environment::Create());
 | |
|   std::string alternate_crash_dump_location;
 | |
|   if (env->GetVar("BREAKPAD_DUMP_LOCATION", &alternate_crash_dump_location)) {
 | |
|     base::FilePath crash_dumps_dir_path =
 | |
|         base::FilePath::FromUTF8Unsafe(alternate_crash_dump_location);
 | |
|     base::PathService::Override(chrome::DIR_CRASH_DUMPS, crash_dumps_dir_path);
 | |
|   }
 | |
|   return base::PathService::Get(chrome::DIR_CRASH_DUMPS, crash_dir);
 | |
| }
 | |
| 
 | |
| #endif  // !defined(OS_POSIX)
 | |
| 
 | |
| bool CefCrashReporterClient::GetCollectStatsConsent() {
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool CefCrashReporterClient::GetCollectStatsInSample() {
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| #if defined(OS_WIN) || defined(OS_MACOSX)
 | |
| bool CefCrashReporterClient::ReportingIsEnforcedByPolicy(
 | |
|     bool* crashpad_enabled) {
 | |
|   *crashpad_enabled = true;
 | |
|   return true;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if defined(OS_POSIX) && !defined(OS_MACOSX)
 | |
| bool CefCrashReporterClient::IsRunningUnattended() {
 | |
|   // Crash upload will only be enabled with Breakpad on Linux if this method
 | |
|   // returns false.
 | |
|   return false;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| std::string CefCrashReporterClient::GetCrashServerURL() {
 | |
|   return server_url_;
 | |
| }
 | |
| 
 | |
| // See HandlerMain() in third_party/crashpad/crashpad/handler/handler_main.cc
 | |
| // for supported arguments.
 | |
| void CefCrashReporterClient::GetCrashOptionalArguments(
 | |
|     std::vector<std::string>* arguments) {
 | |
|   if (!rate_limit_)
 | |
|     arguments->push_back(std::string("--no-rate-limit"));
 | |
| 
 | |
|   if (max_uploads_ > 0) {
 | |
|     arguments->push_back(std::string("--max-uploads=") +
 | |
|                          base::IntToString(max_uploads_));
 | |
|   }
 | |
| 
 | |
|   if (max_db_size_ > 0) {
 | |
|     arguments->push_back(std::string("--max-db-size=") +
 | |
|                          base::IntToString(max_db_size_));
 | |
|   }
 | |
| 
 | |
|   if (max_db_age_ > 0) {
 | |
|     arguments->push_back(std::string("--max-db-age=") +
 | |
|                          base::IntToString(max_db_age_));
 | |
|   }
 | |
| }
 | |
| 
 | |
| #if defined(OS_WIN)
 | |
| 
 | |
| base::string16 CefCrashReporterClient::GetCrashExternalHandler(
 | |
|     const base::string16& exe_dir) {
 | |
|   if (external_handler_.empty())
 | |
|     return CrashReporterClient::GetCrashExternalHandler(exe_dir);
 | |
|   if (isAbsolutePath(external_handler_))
 | |
|     return base::UTF8ToUTF16(external_handler_);
 | |
|   return base::UTF8ToWide(
 | |
|       joinPath(base::UTF16ToUTF8(exe_dir), external_handler_));
 | |
| }
 | |
| 
 | |
| bool CefCrashReporterClient::HasCrashExternalHandler() const {
 | |
|   return !external_handler_.empty();
 | |
| }
 | |
| 
 | |
| #endif  // defined(OS_WIN)
 | |
| 
 | |
| #if defined(OS_MACOSX)
 | |
| bool CefCrashReporterClient::EnableBrowserCrashForwarding() {
 | |
|   return enable_browser_crash_forwarding_;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if defined(OS_POSIX) && !defined(OS_MACOSX)
 | |
| CefCrashReporterClient::ParameterMap CefCrashReporterClient::FilterParameters(
 | |
|     const ParameterMap& parameters) {
 | |
|   return crash_report_utils::FilterParameters(parameters);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| // The new Crashpad Annotation API requires that annotations be declared using
 | |
| // static storage. We work around this limitation by defining a fixed amount of
 | |
| // storage for each key size and later substituting the actual key name during
 | |
| // crash dump processing.
 | |
| 
 | |
| #define IDKEY(name) \
 | |
|   { name, IDKey::Tag::kArray }
 | |
| 
 | |
| #define IDKEY_ENTRIES(n)                                                     \
 | |
|   IDKEY(n "-A"), IDKEY(n "-B"), IDKEY(n "-C"), IDKEY(n "-D"), IDKEY(n "-E"), \
 | |
|       IDKEY(n "-F"), IDKEY(n "-G"), IDKEY(n "-H"), IDKEY(n "-I"),            \
 | |
|       IDKEY(n "-J"), IDKEY(n "-K"), IDKEY(n "-L"), IDKEY(n "-M"),            \
 | |
|       IDKEY(n "-N"), IDKEY(n "-O"), IDKEY(n "-P"), IDKEY(n "-Q"),            \
 | |
|       IDKEY(n "-R"), IDKEY(n "-S"), IDKEY(n "-T"), IDKEY(n "-U"),            \
 | |
|       IDKEY(n "-V"), IDKEY(n "-W"), IDKEY(n "-X"), IDKEY(n "-Y"),            \
 | |
|       IDKEY(n "-Z")
 | |
| 
 | |
| #define IDKEY_FUNCTION(name, size)                                           \
 | |
|   static_assert(size <= crashpad::Annotation::kValueMaxSize,                 \
 | |
|                 "Annotation size is too large.");                            \
 | |
|   bool Set##name##Annotation(size_t index, const base::StringPiece& value) { \
 | |
|     using IDKey = crash_reporter::CrashKeyString<size>;                      \
 | |
|     static IDKey ids[] = {IDKEY_ENTRIES(#name)};                             \
 | |
|     if (index < arraysize(ids)) {                                            \
 | |
|       if (value.empty()) {                                                   \
 | |
|         ids[index].Clear();                                                  \
 | |
|       } else {                                                               \
 | |
|         ids[index].Set(value);                                               \
 | |
|       }                                                                      \
 | |
|       return true;                                                           \
 | |
|     }                                                                        \
 | |
|     return false;                                                            \
 | |
|   }
 | |
| 
 | |
| // The first argument must be kept synchronized with the logic in
 | |
| // CefCrashReporterClient::ReadCrashConfigFile and
 | |
| // crash_report_utils::FilterParameters.
 | |
| IDKEY_FUNCTION(S, 64)
 | |
| IDKEY_FUNCTION(M, 256)
 | |
| IDKEY_FUNCTION(L, 1024)
 | |
| 
 | |
| bool CefCrashReporterClient::SetCrashKeyValue(const base::StringPiece& key,
 | |
|                                               const base::StringPiece& value) {
 | |
|   if (key.empty() || crash_keys_.empty())
 | |
|     return false;
 | |
| 
 | |
|   KeyMap::const_iterator it = crash_keys_.find(NormalizeCrashKey(key));
 | |
|   if (it == crash_keys_.end())
 | |
|     return false;
 | |
| 
 | |
|   const KeySize size = it->second.first;
 | |
|   const size_t index = it->second.second;
 | |
| 
 | |
|   base::AutoLock lock_scope(crash_key_lock_);
 | |
| 
 | |
|   switch (size) {
 | |
|     case SMALL_SIZE:
 | |
|       return SetSAnnotation(index, value);
 | |
|     case MEDIUM_SIZE:
 | |
|       return SetMAnnotation(index, value);
 | |
|     case LARGE_SIZE:
 | |
|       return SetLAnnotation(index, value);
 | |
|   }
 | |
| 
 | |
|   return false;
 | |
| }
 |