OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 <vector> | 10 #include <vector> |
(...skipping 15 matching lines...) Expand all Loading... |
26 namespace { | 26 namespace { |
27 | 27 |
28 const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\"; | 28 const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\"; |
29 const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices"; | 29 const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices"; |
30 | 30 |
31 // This is the well known SID for the system principal. | 31 // This is the well known SID for the system principal. |
32 const wchar_t kSystemPrincipalSid[] =L"S-1-5-18"; | 32 const wchar_t kSystemPrincipalSid[] =L"S-1-5-18"; |
33 | 33 |
34 google_breakpad::ExceptionHandler* g_breakpad = NULL; | 34 google_breakpad::ExceptionHandler* g_breakpad = NULL; |
35 | 35 |
36 std::vector<wchar_t*>* g_url_chunks = NULL; | 36 // A pointer to the custom entries that we send in the event of a crash. We need |
37 | 37 // this pointer, along with the offsets into it below, so that we can keep the |
38 // A string containing the user's unique metric services id. We send this | 38 // data updated as the state of the browser changes. |
39 // in the crash report. | 39 static std::vector<google_breakpad::CustomInfoEntry>* g_custom_entries = NULL; |
40 wchar_t* g_client_id = NULL; | 40 static size_t g_url_chunks_offset; |
| 41 static size_t g_extension_ids_offset; |
| 42 static size_t g_client_id_offset; |
41 | 43 |
42 // Dumps the current process memory. | 44 // Dumps the current process memory. |
43 extern "C" void __declspec(dllexport) __cdecl DumpProcess() { | 45 extern "C" void __declspec(dllexport) __cdecl DumpProcess() { |
44 if (g_breakpad) | 46 if (g_breakpad) |
45 g_breakpad->WriteMinidump(); | 47 g_breakpad->WriteMinidump(); |
46 } | 48 } |
47 | 49 |
48 // Reduces the size of the string |str| to a max of 64 chars. Required because | 50 // Reduces the size of the string |str| to a max of 64 chars. Required because |
49 // breakpad's CustomInfoEntry raises an invalid_parameter error if the string | 51 // breakpad's CustomInfoEntry raises an invalid_parameter error if the string |
50 // we want to set is longer. | 52 // we want to set is longer. |
(...skipping 16 matching lines...) Expand all Loading... |
67 product = version_info->product_short_name(); | 69 product = version_info->product_short_name(); |
68 version = version_info->product_version(); | 70 version = version_info->product_version(); |
69 if (!version_info->is_official_build()) | 71 if (!version_info->is_official_build()) |
70 version.append(L"-devel"); | 72 version.append(L"-devel"); |
71 } else { | 73 } else { |
72 // No version info found. Make up the values. | 74 // No version info found. Make up the values. |
73 product = L"Chrome"; | 75 product = L"Chrome"; |
74 version = L"0.0.0.0-devel"; | 76 version = L"0.0.0.0-devel"; |
75 } | 77 } |
76 | 78 |
77 // Common entries. | 79 // We only expect this method to be called once per process. |
78 google_breakpad::CustomInfoEntry ver_entry(L"ver", version.c_str()); | 80 DCHECK(!g_custom_entries); |
79 google_breakpad::CustomInfoEntry prod_entry(L"prod", product.c_str()); | 81 g_custom_entries = new std::vector<google_breakpad::CustomInfoEntry>; |
80 google_breakpad::CustomInfoEntry plat_entry(L"plat", L"Win32"); | 82 |
81 google_breakpad::CustomInfoEntry type_entry(L"ptype", type.c_str()); | 83 // Common g_custom_entries. |
| 84 g_custom_entries->push_back( |
| 85 google_breakpad::CustomInfoEntry(L"ver", version.c_str())); |
| 86 g_custom_entries->push_back( |
| 87 google_breakpad::CustomInfoEntry(L"plat", L"Win32")); |
| 88 g_custom_entries->push_back( |
| 89 google_breakpad::CustomInfoEntry(L"ptype", type.c_str())); |
| 90 |
| 91 g_extension_ids_offset = g_custom_entries->size(); |
| 92 for (int i = 0; i < kMaxReportedActiveExtensions; ++i) { |
| 93 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( |
| 94 StringPrintf(L"extension-%i", i + 1).c_str(), L"")); |
| 95 } |
82 | 96 |
83 // Read the id from registry. If reporting has never been enabled | 97 // Read the id from registry. If reporting has never been enabled |
84 // the result will be empty string. Its OK since when user enables reporting | 98 // the result will be empty string. Its OK since when user enables reporting |
85 // we will insert the new value at this location. | 99 // we will insert the new value at this location. |
86 std::wstring guid; | 100 std::wstring guid; |
87 GoogleUpdateSettings::GetMetricsId(&guid); | 101 GoogleUpdateSettings::GetMetricsId(&guid); |
88 google_breakpad::CustomInfoEntry guid_entry(L"guid", guid.c_str()); | 102 g_client_id_offset = g_custom_entries->size(); |
| 103 g_custom_entries->push_back( |
| 104 google_breakpad::CustomInfoEntry(L"guid", guid.c_str())); |
89 | 105 |
90 if (type == L"renderer" || type == L"plugin") { | 106 if (type == L"renderer" || type == L"plugin") { |
91 // Create entries for the URL. Currently we only allow each chunk to be 64 | 107 // Create entries for the URL. Currently we only allow each chunk to be 64 |
92 // characters, which isn't enough for a URL. As a hack we create 8 entries | 108 // characters, which isn't enough for a URL. As a hack we create 8 entries |
93 // and split the URL across the entries. | 109 // and split the URL across the g_custom_entries. |
94 google_breakpad::CustomInfoEntry url1(L"url-chunk-1", L""); | 110 g_url_chunks_offset = g_custom_entries->size(); |
95 google_breakpad::CustomInfoEntry url2(L"url-chunk-2", L""); | 111 for (int i = 0; i < kMaxUrlChunks; ++i) { |
96 google_breakpad::CustomInfoEntry url3(L"url-chunk-3", L""); | 112 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( |
97 google_breakpad::CustomInfoEntry url4(L"url-chunk-4", L""); | 113 StringPrintf(L"url-chunk-%i", i + 1).c_str(), L"")); |
98 google_breakpad::CustomInfoEntry url5(L"url-chunk-5", L""); | 114 } |
99 google_breakpad::CustomInfoEntry url6(L"url-chunk-6", L""); | 115 } else { |
100 google_breakpad::CustomInfoEntry url7(L"url-chunk-7", L""); | 116 // Browser-specific g_custom_entries. |
101 google_breakpad::CustomInfoEntry url8(L"url-chunk-8", L""); | 117 google_breakpad::CustomInfoEntry switch1(L"switch-1", L""); |
| 118 google_breakpad::CustomInfoEntry switch2(L"switch-2", L""); |
102 | 119 |
103 static google_breakpad::CustomInfoEntry entries[] = | 120 // Get the first two command line switches if they exist. The CommandLine |
104 { ver_entry, prod_entry, plat_entry, type_entry, guid_entry, | 121 // class does not allow to enumerate the switches so we do it by hand. |
105 url1, url2, url3, url4, url5, url6, url7, url8 }; | 122 int num_args = 0; |
| 123 wchar_t** args = ::CommandLineToArgvW(::GetCommandLineW(), &num_args); |
| 124 if (args) { |
| 125 if (num_args > 1) |
| 126 switch1.set_value(TrimToBreakpadMax(args[1]).c_str()); |
| 127 if (num_args > 2) |
| 128 switch2.set_value(TrimToBreakpadMax(args[2]).c_str()); |
| 129 } |
106 | 130 |
107 std::vector<wchar_t*>* tmp_url_chunks = new std::vector<wchar_t*>(8); | 131 g_custom_entries->push_back(switch1); |
108 for (size_t i = 0; i < 8; ++i) | 132 g_custom_entries->push_back(switch2); |
109 (*tmp_url_chunks)[i] = entries[5 + i].value; | |
110 g_url_chunks = tmp_url_chunks; | |
111 | |
112 g_client_id = entries[4].value; | |
113 | |
114 static google_breakpad::CustomClientInfo custom_info_renderer | |
115 = {entries, arraysize(entries)}; | |
116 return &custom_info_renderer; | |
117 } | 133 } |
118 | 134 |
119 // Browser-specific entries. | 135 static google_breakpad::CustomClientInfo custom_client_info; |
120 google_breakpad::CustomInfoEntry switch1(L"switch-1", L""); | 136 custom_client_info.entries = &g_custom_entries->front(); |
121 google_breakpad::CustomInfoEntry switch2(L"switch-2", L""); | 137 custom_client_info.count = g_custom_entries->size(); |
122 | 138 |
123 // Get the first two command line switches if they exist. The CommandLine | 139 return &custom_client_info; |
124 // class does not allow to enumerate the switches so we do it by hand. | |
125 int num_args = 0; | |
126 wchar_t** args = ::CommandLineToArgvW(::GetCommandLineW(), &num_args); | |
127 if (args) { | |
128 if (num_args > 1) | |
129 switch1.set_value(TrimToBreakpadMax(args[1]).c_str()); | |
130 if (num_args > 2) | |
131 switch2.set_value(TrimToBreakpadMax(args[2]).c_str()); | |
132 } | |
133 | |
134 static google_breakpad::CustomInfoEntry entries[] = | |
135 {ver_entry, prod_entry, plat_entry, type_entry, guid_entry, | |
136 switch1, switch2}; | |
137 g_client_id = entries[4].value; | |
138 static google_breakpad::CustomClientInfo custom_info_browser = | |
139 {entries, arraysize(entries)}; | |
140 return &custom_info_browser; | |
141 } | 140 } |
142 | 141 |
143 // Contains the information needed by the worker thread. | 142 // Contains the information needed by the worker thread. |
144 struct CrashReporterInfo { | 143 struct CrashReporterInfo { |
145 google_breakpad::CustomClientInfo* custom_info; | 144 google_breakpad::CustomClientInfo* custom_info; |
146 std::wstring dll_path; | 145 std::wstring dll_path; |
147 std::wstring process_type; | 146 std::wstring process_type; |
148 }; | 147 }; |
149 | 148 |
150 // This callback is executed when the browser process has crashed, after | 149 // This callback is executed when the browser process has crashed, after |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
206 | 205 |
207 if (previous_filter) | 206 if (previous_filter) |
208 return previous_filter(info); | 207 return previous_filter(info); |
209 | 208 |
210 return EXCEPTION_EXECUTE_HANDLER; | 209 return EXCEPTION_EXECUTE_HANDLER; |
211 } | 210 } |
212 | 211 |
213 extern "C" void __declspec(dllexport) __cdecl SetActiveURL( | 212 extern "C" void __declspec(dllexport) __cdecl SetActiveURL( |
214 const wchar_t* url_cstring) { | 213 const wchar_t* url_cstring) { |
215 DCHECK(url_cstring); | 214 DCHECK(url_cstring); |
216 if (!g_url_chunks) | |
217 return; | |
218 | 215 |
219 std::wstring url(url_cstring); | 216 std::wstring url(url_cstring); |
220 size_t num_chunks = g_url_chunks->size(); | |
221 size_t chunk_index = 0; | 217 size_t chunk_index = 0; |
222 size_t url_size = url.size(); | 218 size_t url_size = url.size(); |
223 | 219 |
224 // Split the url across all the chunks. | 220 // Split the url across all the chunks. |
225 for (size_t url_offset = 0; | 221 for (size_t url_offset = 0; |
226 chunk_index < num_chunks && url_offset < url_size; ++chunk_index) { | 222 chunk_index < kMaxUrlChunks && url_offset < url_size; ++chunk_index) { |
227 size_t current_chunk_size = std::min(url_size - url_offset, | 223 size_t current_chunk_size = std::min(url_size - url_offset, |
228 static_cast<size_t>( | 224 static_cast<size_t>( |
229 google_breakpad::CustomInfoEntry::kValueMaxLength - 1)); | 225 google_breakpad::CustomInfoEntry::kValueMaxLength - 1)); |
230 url._Copy_s((*g_url_chunks)[chunk_index], | 226 |
| 227 wchar_t* entry_value = |
| 228 (*g_custom_entries)[g_url_chunks_offset + chunk_index].value; |
| 229 url._Copy_s(entry_value, |
231 google_breakpad::CustomInfoEntry::kValueMaxLength, | 230 google_breakpad::CustomInfoEntry::kValueMaxLength, |
232 current_chunk_size, url_offset); | 231 current_chunk_size, url_offset); |
233 (*g_url_chunks)[chunk_index][current_chunk_size] = L'\0'; | 232 entry_value[current_chunk_size] = L'\0'; |
234 url_offset += current_chunk_size; | 233 url_offset += current_chunk_size; |
235 } | 234 } |
236 | 235 |
237 // And null terminate any unneeded chunks. | 236 // And null terminate any unneeded chunks. |
238 for (; chunk_index < num_chunks; ++chunk_index) | 237 for (; chunk_index < kMaxUrlChunks; ++chunk_index) |
239 (*g_url_chunks)[chunk_index][0] = L'\0'; | 238 (*g_custom_entries)[g_url_chunks_offset + chunk_index].value[0] = L'\0'; |
240 } | 239 } |
241 | 240 |
242 extern "C" void __declspec(dllexport) __cdecl SetClientId( | 241 extern "C" void __declspec(dllexport) __cdecl SetClientId( |
243 const wchar_t* client_id) { | 242 const wchar_t* client_id) { |
244 if (client_id == NULL) | 243 if (client_id == NULL) |
245 return; | 244 return; |
246 | 245 |
247 wcscpy_s(g_client_id, | 246 wcscpy_s((*g_custom_entries)[g_client_id_offset].value, |
248 google_breakpad::CustomInfoEntry::kValueMaxLength, | 247 google_breakpad::CustomInfoEntry::kValueMaxLength, |
249 client_id); | 248 client_id); |
250 } | 249 } |
251 | 250 |
| 251 extern "C" void __declspec(dllexport) __cdecl SetExtensionID( |
| 252 int index, const wchar_t* id) { |
| 253 DCHECK(id); |
| 254 DCHECK(index < kMaxReportedActiveExtensions); |
| 255 |
| 256 wcscpy_s((*g_custom_entries)[g_extension_ids_offset + index].value, |
| 257 google_breakpad::CustomInfoEntry::kValueMaxLength, |
| 258 id); |
| 259 } |
| 260 |
252 } // namespace | 261 } // namespace |
253 | 262 |
254 // This function is executed by the child process that DumpDoneCallback() | 263 // This function is executed by the child process that DumpDoneCallback() |
255 // spawned and basically just shows the 'chrome has crashed' dialog if | 264 // spawned and basically just shows the 'chrome has crashed' dialog if |
256 // the CHROME_CRASHED environment variable is present. | 265 // the CHROME_CRASHED environment variable is present. |
257 bool ShowRestartDialogIfCrashed(bool* exit_now) { | 266 bool ShowRestartDialogIfCrashed(bool* exit_now) { |
258 if (!::GetEnvironmentVariableW(env_vars::kShowRestart, NULL, 0)) | 267 if (!::GetEnvironmentVariableW(env_vars::kShowRestart, NULL, 0)) |
259 return false; | 268 return false; |
260 | 269 |
261 DWORD len = ::GetEnvironmentVariableW(env_vars::kRestartInfo, NULL, 0); | 270 DWORD len = ::GetEnvironmentVariableW(env_vars::kRestartInfo, NULL, 0); |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
405 if (QueueUserWorkItem( | 414 if (QueueUserWorkItem( |
406 &InitCrashReporterThread, | 415 &InitCrashReporterThread, |
407 info.release(), | 416 info.release(), |
408 WT_EXECUTELONGFUNCTION) == 0) { | 417 WT_EXECUTELONGFUNCTION) == 0) { |
409 // We failed to queue to the worker pool, initialize in this thread. | 418 // We failed to queue to the worker pool, initialize in this thread. |
410 InitCrashReporterThread(info.release()); | 419 InitCrashReporterThread(info.release()); |
411 } | 420 } |
412 } | 421 } |
413 } | 422 } |
414 } | 423 } |
OLD | NEW |