 Chromium Code Reviews
 Chromium Code Reviews Issue 11776040:
  Add Windows implementation for base/debug/crash_logging.h.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 11776040:
  Add Windows implementation for base/debug/crash_logging.h.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| OLD | NEW | 
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "chrome/app/breakpad_win.h" | 5 #include "chrome/app/breakpad_win.h" | 
| 6 | 6 | 
| 7 #include <windows.h> | 7 #include <windows.h> | 
| 8 #include <shellapi.h> | 8 #include <shellapi.h> | 
| 9 #include <tchar.h> | 9 #include <tchar.h> | 
| 10 #include <userenv.h> | 10 #include <userenv.h> | 
| 11 | 11 | 
| 12 #include <algorithm> | 12 #include <algorithm> | 
| 13 #include <vector> | 13 #include <vector> | 
| 14 | 14 | 
| 15 #include "base/base_switches.h" | 15 #include "base/base_switches.h" | 
| 16 #include "base/command_line.h" | 16 #include "base/command_line.h" | 
| 17 #include "base/debug/crash_logging.h" | |
| 17 #include "base/environment.h" | 18 #include "base/environment.h" | 
| 18 #include "base/file_util.h" | 19 #include "base/file_util.h" | 
| 19 #include "base/file_version_info.h" | 20 #include "base/file_version_info.h" | 
| 20 #include "base/memory/scoped_ptr.h" | 21 #include "base/memory/scoped_ptr.h" | 
| 21 #include "base/string_split.h" | 22 #include "base/string_split.h" | 
| 22 #include "base/string_util.h" | 23 #include "base/string_util.h" | 
| 23 #include "base/string16.h" | 24 #include "base/string16.h" | 
| 24 #include "base/stringprintf.h" | 25 #include "base/stringprintf.h" | 
| 25 #include "base/utf_string_conversions.h" | 26 #include "base/utf_string_conversions.h" | 
| 26 #include "base/win/registry.h" | 27 #include "base/win/registry.h" | 
| 27 #include "base/win/win_util.h" | 28 #include "base/win/win_util.h" | 
| 28 #include "breakpad/src/client/windows/handler/exception_handler.h" | 29 #include "breakpad/src/client/windows/handler/exception_handler.h" | 
| 29 #include "chrome/app/breakpad_field_trial_win.h" | 30 #include "chrome/app/breakpad_field_trial_win.h" | 
| 30 #include "chrome/app/crash_analysis_win.h" | 31 #include "chrome/app/crash_analysis_win.h" | 
| 31 #include "chrome/app/hard_error_handler_win.h" | 32 #include "chrome/app/hard_error_handler_win.h" | 
| 32 #include "chrome/common/child_process_logging.h" | 33 #include "chrome/common/child_process_logging.h" | 
| 33 #include "chrome/common/chrome_result_codes.h" | 34 #include "chrome/common/chrome_result_codes.h" | 
| 34 #include "chrome/common/chrome_switches.h" | 35 #include "chrome/common/chrome_switches.h" | 
| 36 #include "chrome/common/crash_keys.h" | |
| 35 #include "chrome/common/env_vars.h" | 37 #include "chrome/common/env_vars.h" | 
| 36 #include "chrome/installer/util/google_chrome_sxs_distribution.h" | 38 #include "chrome/installer/util/google_chrome_sxs_distribution.h" | 
| 37 #include "chrome/installer/util/google_update_settings.h" | 39 #include "chrome/installer/util/google_update_settings.h" | 
| 38 #include "chrome/installer/util/install_util.h" | 40 #include "chrome/installer/util/install_util.h" | 
| 39 #include "policy/policy_constants.h" | 41 #include "policy/policy_constants.h" | 
| 40 | 42 | 
| 41 // userenv.dll is required for GetProfileType(). | 43 // userenv.dll is required for GetProfileType(). | 
| 42 #pragma comment(lib, "userenv.lib") | 44 #pragma comment(lib, "userenv.lib") | 
| 43 | 45 | 
| 44 namespace breakpad_win { | 46 namespace breakpad_win { | 
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 96 | 98 | 
| 97 static size_t g_url_chunks_offset = 0; | 99 static size_t g_url_chunks_offset = 0; | 
| 98 static size_t g_num_of_extensions_offset = 0; | 100 static size_t g_num_of_extensions_offset = 0; | 
| 99 static size_t g_extension_ids_offset = 0; | 101 static size_t g_extension_ids_offset = 0; | 
| 100 static size_t g_client_id_offset = 0; | 102 static size_t g_client_id_offset = 0; | 
| 101 static size_t g_gpu_info_offset = 0; | 103 static size_t g_gpu_info_offset = 0; | 
| 102 static size_t g_printer_info_offset = 0; | 104 static size_t g_printer_info_offset = 0; | 
| 103 static size_t g_num_of_views_offset = 0; | 105 static size_t g_num_of_views_offset = 0; | 
| 104 static size_t g_num_switches_offset = 0; | 106 static size_t g_num_switches_offset = 0; | 
| 105 static size_t g_switches_offset = 0; | 107 static size_t g_switches_offset = 0; | 
| 108 static size_t g_dynamic_keys_offset = 0; | |
| 109 typedef std::map<std::string, google_breakpad::CustomInfoEntry*> | |
| 110 DynamicEntriesMap; | |
| 111 DynamicEntriesMap* g_dynamic_entries = NULL; | |
| 
Nico
2013/01/24 18:01:14
nit: Why is this not static too?
(I realize it's
 | |
| 112 static size_t g_dynamic_entries_count = 0; | |
| 106 | 113 | 
| 107 // Maximum length for plugin path to include in plugin crash reports. | 114 // Maximum length for plugin path to include in plugin crash reports. | 
| 108 const size_t kMaxPluginPathLength = 256; | 115 const size_t kMaxPluginPathLength = 256; | 
| 109 | 116 | 
| 110 // Dumps the current process memory. | 117 // Dumps the current process memory. | 
| 111 extern "C" void __declspec(dllexport) __cdecl DumpProcess() { | 118 extern "C" void __declspec(dllexport) __cdecl DumpProcess() { | 
| 112 if (g_breakpad) | 119 if (g_breakpad) | 
| 113 g_breakpad->WriteMinidump(); | 120 g_breakpad->WriteMinidump(); | 
| 114 } | 121 } | 
| 115 | 122 | 
| (...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 457 // We depend on this in UpdateExperiments... | 464 // We depend on this in UpdateExperiments... | 
| 458 DCHECK_NE(0UL, g_experiment_chunks_offset); | 465 DCHECK_NE(0UL, g_experiment_chunks_offset); | 
| 459 // And the test code depends on this. | 466 // And the test code depends on this. | 
| 460 DCHECK_EQ(g_num_of_experiments_offset + 1, g_experiment_chunks_offset); | 467 DCHECK_EQ(g_num_of_experiments_offset + 1, g_experiment_chunks_offset); | 
| 461 // one-based index for the name suffix. | 468 // one-based index for the name suffix. | 
| 462 for (int i = 1; i <= kMaxReportedVariationChunks; ++i) { | 469 for (int i = 1; i <= kMaxReportedVariationChunks; ++i) { | 
| 463 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( | 470 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( | 
| 464 base::StringPrintf(L"experiment-chunk-%i", i).c_str(), L"")); | 471 base::StringPrintf(L"experiment-chunk-%i", i).c_str(), L"")); | 
| 465 } | 472 } | 
| 466 | 473 | 
| 474 // Create space for dynamic ad-hoc keys. The names and values are set using | |
| 475 // the API defined in base/debug/crash_logging.h. | |
| 476 g_dynamic_entries_count = crash_keys::RegisterChromeCrashKeys(); | |
| 477 g_dynamic_keys_offset = g_custom_entries->size(); | |
| 478 for (size_t i = 0; i < g_dynamic_entries_count; ++i) { | |
| 479 g_custom_entries->push_back(google_breakpad::CustomInfoEntry()); | |
| 480 } | |
| 481 g_dynamic_entries = new DynamicEntriesMap; | |
| 482 | |
| 467 static google_breakpad::CustomClientInfo custom_client_info; | 483 static google_breakpad::CustomClientInfo custom_client_info; | 
| 468 custom_client_info.entries = &g_custom_entries->front(); | 484 custom_client_info.entries = &g_custom_entries->front(); | 
| 469 custom_client_info.count = g_custom_entries->size(); | 485 custom_client_info.count = g_custom_entries->size(); | 
| 470 | 486 | 
| 471 return &custom_client_info; | 487 return &custom_client_info; | 
| 472 } | 488 } | 
| 473 | 489 | 
| 474 // This callback is used when we want to get a dump without crashing the | 490 // This callback is used when we want to get a dump without crashing the | 
| 475 // process. | 491 // process. | 
| 476 bool DumpDoneCallbackWhenNoCrash(const wchar_t*, const wchar_t*, void*, | 492 bool DumpDoneCallbackWhenNoCrash(const wchar_t*, const wchar_t*, void*, | 
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 658 info[i].c_str(), | 674 info[i].c_str(), | 
| 659 google_breakpad::CustomInfoEntry::kValueMaxLength); | 675 google_breakpad::CustomInfoEntry::kValueMaxLength); | 
| 660 } | 676 } | 
| 661 } | 677 } | 
| 662 | 678 | 
| 663 extern "C" void __declspec(dllexport) __cdecl SetNumberOfViews( | 679 extern "C" void __declspec(dllexport) __cdecl SetNumberOfViews( | 
| 664 int number_of_views) { | 680 int number_of_views) { | 
| 665 SetIntegerValue(g_num_of_views_offset, number_of_views); | 681 SetIntegerValue(g_num_of_views_offset, number_of_views); | 
| 666 } | 682 } | 
| 667 | 683 | 
| 684 void SetCrashKeyValue(const base::StringPiece& key, | |
| 685 const base::StringPiece& value) { | |
| 686 std::string key_string = key.as_string(); | |
| 687 | |
| 688 DynamicEntriesMap::iterator it = g_dynamic_entries->find(key_string); | |
| 689 google_breakpad::CustomInfoEntry* entry = NULL; | |
| 690 if (it == g_dynamic_entries->end()) { | |
| 
eroman
2013/01/24 00:47:13
There is nothing to stop callers from inserting a
 
Robert Sesek
2013/01/24 01:03:45
For now, yes. The base::debug API will prevent thi
 | |
| 691 if (g_dynamic_keys_offset >= g_dynamic_entries_count) | |
| 692 return; | |
| 693 entry = &(*g_custom_entries)[g_dynamic_keys_offset++]; | |
| 694 g_dynamic_entries->insert(std::make_pair(key_string, entry)); | |
| 695 } else { | |
| 696 entry = it->second; | |
| 697 } | |
| 698 | |
| 699 entry->set(UTF8ToWide(key).data(), UTF8ToWide(value).data()); | |
| 700 } | |
| 701 | |
| 702 void ClearCrashKeyValue(const base::StringPiece& key) { | |
| 703 DynamicEntriesMap::iterator it = g_dynamic_entries->find(key.as_string()); | |
| 704 if (it == g_dynamic_entries->end()) | |
| 705 return; | |
| 706 | |
| 707 it->second->set(NULL, NULL); | |
| 708 } | |
| 709 | |
| 668 } // namespace | 710 } // namespace | 
| 669 | 711 | 
| 670 namespace testing { | 712 namespace testing { | 
| 671 | 713 | 
| 672 // Access to namespace protected functions for testing purposes. | 714 // Access to namespace protected functions for testing purposes. | 
| 673 void InitCustomInfoEntries() { | 715 void InitCustomInfoEntries() { | 
| 674 GetCustomInfo(L"", L"", L""); | 716 GetCustomInfo(L"", L"", L""); | 
| 675 } | 717 } | 
| 676 | 718 | 
| 677 } // namespace testing | 719 } // namespace testing | 
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 859 wchar_t exe_path[MAX_PATH]; | 901 wchar_t exe_path[MAX_PATH]; | 
| 860 exe_path[0] = 0; | 902 exe_path[0] = 0; | 
| 861 GetModuleFileNameW(NULL, exe_path, MAX_PATH); | 903 GetModuleFileNameW(NULL, exe_path, MAX_PATH); | 
| 862 | 904 | 
| 863 bool is_per_user_install = InstallUtil::IsPerUserInstall(exe_path); | 905 bool is_per_user_install = InstallUtil::IsPerUserInstall(exe_path); | 
| 864 | 906 | 
| 865 std::wstring channel_string; | 907 std::wstring channel_string; | 
| 866 GoogleUpdateSettings::GetChromeChannelAndModifiers(!is_per_user_install, | 908 GoogleUpdateSettings::GetChromeChannelAndModifiers(!is_per_user_install, | 
| 867 &channel_string); | 909 &channel_string); | 
| 868 | 910 | 
| 911 base::debug::SetCrashKeyReportingFunctions( | |
| 912 &SetCrashKeyValue, &ClearCrashKeyValue); | |
| 913 | |
| 869 google_breakpad::CustomClientInfo* custom_info = | 914 google_breakpad::CustomClientInfo* custom_info = | 
| 870 GetCustomInfo(exe_path, process_type, channel_string); | 915 GetCustomInfo(exe_path, process_type, channel_string); | 
| 871 | 916 | 
| 872 google_breakpad::ExceptionHandler::MinidumpCallback callback = NULL; | 917 google_breakpad::ExceptionHandler::MinidumpCallback callback = NULL; | 
| 873 LPTOP_LEVEL_EXCEPTION_FILTER default_filter = NULL; | 918 LPTOP_LEVEL_EXCEPTION_FILTER default_filter = NULL; | 
| 874 // We install the post-dump callback only for the browser and service | 919 // We install the post-dump callback only for the browser and service | 
| 875 // processes. It spawns a new browser/service process. | 920 // processes. It spawns a new browser/service process. | 
| 876 if (process_type == L"browser") { | 921 if (process_type == L"browser") { | 
| 877 callback = &DumpDoneCallback; | 922 callback = &DumpDoneCallback; | 
| 878 default_filter = &ChromeExceptionFilter; | 923 default_filter = &ChromeExceptionFilter; | 
| 879 } else if (process_type == L"service") { | 924 } else if (process_type == L"service") { | 
| 880 callback = &DumpDoneCallback; | 925 callback = &DumpDoneCallback; | 
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 956 previous_filter = SetUnhandledExceptionFilter(filter); | 1001 previous_filter = SetUnhandledExceptionFilter(filter); | 
| 957 } | 1002 } | 
| 958 | 1003 | 
| 959 void StringVectorToCStringVector(const std::vector<std::wstring>& wstrings, | 1004 void StringVectorToCStringVector(const std::vector<std::wstring>& wstrings, | 
| 960 std::vector<const wchar_t*>* cstrings) { | 1005 std::vector<const wchar_t*>* cstrings) { | 
| 961 cstrings->clear(); | 1006 cstrings->clear(); | 
| 962 cstrings->reserve(wstrings.size()); | 1007 cstrings->reserve(wstrings.size()); | 
| 963 for (size_t i = 0; i < wstrings.size(); ++i) | 1008 for (size_t i = 0; i < wstrings.size(); ++i) | 
| 964 cstrings->push_back(wstrings[i].c_str()); | 1009 cstrings->push_back(wstrings[i].c_str()); | 
| 965 } | 1010 } | 
| OLD | NEW |