1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/app/chrome_breakpad_client.h"
7 #include "base/atomicops.h"
8 #include "base/command_line.h"
9 #include "base/environment.h"
10 #include "base/files/file_path.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/path_service.h"
14 #include "base/strings/safe_sprintf.h"
15 #include "base/strings/string_split.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "chrome/common/chrome_constants.h"
18 #include "chrome/common/chrome_paths.h"
19 #include "chrome/common/chrome_result_codes.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/common/crash_keys.h"
22 #include "chrome/common/env_vars.h"
27 #include "base/file_version_info.h"
28 #include "base/win/registry.h"
29 #include "chrome/installer/util/google_chrome_sxs_distribution.h"
30 #include "chrome/installer/util/install_util.h"
31 #include "policy/policy_constants.h"
34 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS)
35 #include "chrome/browser/crash_upload_list.h"
36 #include "chrome/common/chrome_version_info_posix.h"
40 #include "chrome/common/dump_without_crashing.h"
43 #if defined(OS_WIN) || defined(OS_MACOSX)
44 #include "chrome/installer/util/google_update_settings.h"
47 #if defined(OS_ANDROID)
48 #include "chrome/common/descriptors_android.h"
56 // This is the minimum version of google update that is required for deferred
57 // crash uploads to work.
58 const char kMinUpdateVersion[] = "1.3.21.115";
60 // The value name prefix will be of the form {chrome-version}-{pid}-{timestamp}
61 // (i.e., "#####.#####.#####.#####-########-########") which easily fits into a
62 // 63 character buffer.
63 const char kBrowserCrashDumpPrefixTemplate[] = "%s-%08x-%08x";
64 const size_t kBrowserCrashDumpPrefixLength = 63;
65 char g_browser_crash_dump_prefix[kBrowserCrashDumpPrefixLength + 1] = {};
67 // These registry key to which we'll write a value for each crash dump attempt.
68 HKEY g_browser_crash_dump_regkey = NULL;
70 // A atomic counter to make each crash dump value name unique.
71 base::subtle::Atomic32 g_browser_crash_dump_count = 0;
76 ChromeBreakpadClient::ChromeBreakpadClient() {}
78 ChromeBreakpadClient::~ChromeBreakpadClient() {}
80 void ChromeBreakpadClient::SetClientID(const std::string& client_id) {
81 crash_keys::SetClientID(client_id);
85 bool ChromeBreakpadClient::GetAlternativeCrashDumpLocation(
86 base::FilePath* crash_dir) {
87 // By setting the BREAKPAD_DUMP_LOCATION environment variable, an alternate
88 // location to write breakpad crash dumps can be set.
89 scoped_ptr<base::Environment> env(base::Environment::Create());
90 std::string alternate_crash_dump_location;
91 if (env->GetVar("BREAKPAD_DUMP_LOCATION", &alternate_crash_dump_location)) {
92 *crash_dir = base::FilePath::FromUTF8Unsafe(alternate_crash_dump_location);
99 void ChromeBreakpadClient::GetProductNameAndVersion(
100 const base::FilePath& exe_path,
101 base::string16* product_name,
102 base::string16* version,
103 base::string16* special_build,
104 base::string16* channel_name) {
105 DCHECK(product_name);
107 DCHECK(special_build);
108 DCHECK(channel_name);
110 scoped_ptr<FileVersionInfo> version_info(
111 FileVersionInfo::CreateFileVersionInfo(exe_path));
113 if (version_info.get()) {
114 // Get the information from the file.
115 *version = version_info->product_version();
116 if (!version_info->is_official_build())
117 version->append(base::ASCIIToUTF16("-devel"));
119 const CommandLine& command = *CommandLine::ForCurrentProcess();
120 if (command.HasSwitch(switches::kChromeFrame)) {
121 *product_name = base::ASCIIToUTF16("ChromeFrame");
123 *product_name = version_info->product_short_name();
126 *special_build = version_info->special_build();
128 // No version info found. Make up the values.
129 *product_name = base::ASCIIToUTF16("Chrome");
130 *version = base::ASCIIToUTF16("0.0.0.0-devel");
133 std::wstring channel_string;
134 GoogleUpdateSettings::GetChromeChannelAndModifiers(
135 !GetIsPerUserInstall(exe_path), &channel_string);
136 *channel_name = base::WideToUTF16(channel_string);
139 bool ChromeBreakpadClient::ShouldShowRestartDialog(base::string16* title,
140 base::string16* message,
141 bool* is_rtl_locale) {
142 scoped_ptr<base::Environment> env(base::Environment::Create());
143 if (!env->HasVar(env_vars::kShowRestart) ||
144 !env->HasVar(env_vars::kRestartInfo) ||
145 env->HasVar(env_vars::kMetroConnected)) {
149 std::string restart_info;
150 env->GetVar(env_vars::kRestartInfo, &restart_info);
152 // The CHROME_RESTART var contains the dialog strings separated by '|'.
153 // See ChromeBrowserMainPartsWin::PrepareRestartOnCrashEnviroment()
155 std::vector<std::string> dlg_strings;
156 base::SplitString(restart_info, '|', &dlg_strings);
158 if (dlg_strings.size() < 3)
161 *title = base::ASCIIToUTF16(dlg_strings[0]);
162 *message = base::ASCIIToUTF16(dlg_strings[1]);
163 *is_rtl_locale = dlg_strings[2] == env_vars::kRtlLocale;
167 bool ChromeBreakpadClient::AboutToRestart() {
168 scoped_ptr<base::Environment> env(base::Environment::Create());
169 if (!env->HasVar(env_vars::kRestartInfo))
172 env->SetVar(env_vars::kShowRestart, "1");
176 bool ChromeBreakpadClient::GetDeferredUploadsSupported(
177 bool is_per_user_install) {
178 Version update_version = GoogleUpdateSettings::GetGoogleUpdateVersion(
179 !is_per_user_install);
180 if (!update_version.IsValid() ||
181 update_version.IsOlderThan(std::string(kMinUpdateVersion)))
187 bool ChromeBreakpadClient::GetIsPerUserInstall(const base::FilePath& exe_path) {
188 return InstallUtil::IsPerUserInstall(exe_path.value().c_str());
191 bool ChromeBreakpadClient::GetShouldDumpLargerDumps(bool is_per_user_install) {
192 base::string16 channel_name(base::WideToUTF16(
193 GoogleUpdateSettings::GetChromeChannel(!is_per_user_install)));
195 // Capture more detail in crash dumps for beta and dev channel builds.
196 if (channel_name == base::ASCIIToUTF16("dev") ||
197 channel_name == base::ASCIIToUTF16("beta") ||
198 channel_name == GoogleChromeSxSDistribution::ChannelName())
203 int ChromeBreakpadClient::GetResultCodeRespawnFailed() {
204 return chrome::RESULT_CODE_RESPAWN_FAILED;
207 void ChromeBreakpadClient::InitBrowserCrashDumpsRegKey() {
208 DCHECK(g_browser_crash_dump_regkey == NULL);
210 base::win::RegKey regkey;
211 if (regkey.Create(HKEY_CURRENT_USER,
212 chrome::kBrowserCrashDumpAttemptsRegistryPath,
213 KEY_ALL_ACCESS) != ERROR_SUCCESS) {
217 // We use the current process id and the current tick count as a (hopefully)
218 // unique combination for the crash dump value. There's a small chance that
219 // across a reboot we might have a crash dump signal written, and the next
220 // browser process might have the same process id and tick count, but crash
221 // before consuming the signal (overwriting the signal with an identical one).
222 // For now, we're willing to live with that risk.
223 int length = base::strings::SafeSPrintf(g_browser_crash_dump_prefix,
224 kBrowserCrashDumpPrefixTemplate,
225 chrome::kChromeVersion,
226 ::GetCurrentProcessId(),
230 g_browser_crash_dump_prefix[0] = '\0';
234 // Hold the registry key in a global for update on crash dump.
235 g_browser_crash_dump_regkey = regkey.Take();
238 void ChromeBreakpadClient::RecordCrashDumpAttempt(bool is_real_crash) {
239 // If we're not a browser (or the registry is unavailable to us for some
240 // reason) then there's nothing to do.
241 if (g_browser_crash_dump_regkey == NULL)
244 // Generate the final value name we'll use (appends the crash number to the
246 const size_t kMaxValueSize = 2 * kBrowserCrashDumpPrefixLength;
247 char value_name[kMaxValueSize + 1] = {};
248 int length = base::strings::SafeSPrintf(
251 g_browser_crash_dump_prefix,
252 base::subtle::NoBarrier_AtomicIncrement(&g_browser_crash_dump_count, 1));
255 DWORD value_dword = is_real_crash ? 1 : 0;
256 ::RegSetValueExA(g_browser_crash_dump_regkey, value_name, 0, REG_DWORD,
257 reinterpret_cast<BYTE*>(&value_dword),
258 sizeof(value_dword));
262 bool ChromeBreakpadClient::ReportingIsEnforcedByPolicy(bool* breakpad_enabled) {
263 // Determine whether configuration management allows loading the crash reporter.
264 // Since the configuration management infrastructure is not initialized at this
265 // point, we read the corresponding registry key directly. The return status
266 // indicates whether policy data was successfully read. If it is true,
267 // |breakpad_enabled| contains the value set by policy.
268 string16 key_name = UTF8ToUTF16(policy::key::kMetricsReportingEnabled);
270 base::win::RegKey hklm_policy_key(HKEY_LOCAL_MACHINE,
271 policy::kRegistryChromePolicyKey, KEY_READ);
272 if (hklm_policy_key.ReadValueDW(key_name.c_str(), &value) == ERROR_SUCCESS) {
273 *breakpad_enabled = value != 0;
277 base::win::RegKey hkcu_policy_key(HKEY_CURRENT_USER,
278 policy::kRegistryChromePolicyKey, KEY_READ);
279 if (hkcu_policy_key.ReadValueDW(key_name.c_str(), &value) == ERROR_SUCCESS) {
280 *breakpad_enabled = value != 0;
288 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS)
289 void ChromeBreakpadClient::GetProductNameAndVersion(std::string* product_name,
290 std::string* version) {
291 DCHECK(product_name);
293 #if defined(OS_ANDROID)
294 *product_name = "Chrome_Android";
295 #elif defined(OS_CHROMEOS)
296 *product_name = "Chrome_ChromeOS";
298 #if !defined(ADDRESS_SANITIZER)
299 *product_name = "Chrome_Linux";
301 *product_name = "Chrome_Linux_ASan";
305 *version = PRODUCT_VERSION;
308 base::FilePath ChromeBreakpadClient::GetReporterLogFilename() {
309 return base::FilePath(CrashUploadList::kReporterLogFilename);
313 bool ChromeBreakpadClient::GetCrashDumpLocation(base::FilePath* crash_dir) {
314 // By setting the BREAKPAD_DUMP_LOCATION environment variable, an alternate
315 // location to write breakpad crash dumps can be set.
316 scoped_ptr<base::Environment> env(base::Environment::Create());
317 std::string alternate_crash_dump_location;
318 if (env->GetVar("BREAKPAD_DUMP_LOCATION", &alternate_crash_dump_location)) {
319 base::FilePath crash_dumps_dir_path =
320 base::FilePath::FromUTF8Unsafe(alternate_crash_dump_location);
321 PathService::Override(chrome::DIR_CRASH_DUMPS, crash_dumps_dir_path);
324 return PathService::Get(chrome::DIR_CRASH_DUMPS, crash_dir);
327 #if defined(OS_POSIX)
328 void ChromeBreakpadClient::SetDumpWithoutCrashingFunction(void (*function)()) {
329 logging::SetDumpWithoutCrashingFunction(function);
333 size_t ChromeBreakpadClient::RegisterCrashKeys() {
334 // Note: This is not called on Windows because Breakpad is initialized in the
335 // EXE module, but code that uses crash keys is in the DLL module.
336 // RegisterChromeCrashKeys() will be called after the DLL is loaded.
337 return crash_keys::RegisterChromeCrashKeys();
340 bool ChromeBreakpadClient::IsRunningUnattended() {
341 scoped_ptr<base::Environment> env(base::Environment::Create());
342 return env->HasVar(env_vars::kHeadless);
345 #if defined(OS_WIN) || defined(OS_MACOSX)
346 bool ChromeBreakpadClient::GetCollectStatsConsent() {
347 return GoogleUpdateSettings::GetCollectStatsConsent();
351 #if defined(OS_ANDROID)
352 int ChromeBreakpadClient::GetAndroidMinidumpDescriptor() {
353 return kAndroidMinidumpDescriptor;
357 } // namespace chrome