Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: chrome/install_static/install_util.cc

Issue 1913943003: Remove dependencies on chrome\installer from the ChromeCrashReporterClient class on Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address review comments Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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/install_static/install_util.h" 5 #include "chrome/install_static/install_util.h"
6 6
7 #include <assert.h> 7 #include <assert.h>
8 #include <shlobj.h>
9 #include <stddef.h>
10 #include <memory>
8 #include <windows.h> 11 #include <windows.h>
9 #include <stddef.h>
10 12
13 #include "base/files/file_util.h"
11 #include "base/macros.h" 14 #include "base/macros.h"
12 #include "base/strings/string16.h" 15 #include "base/memory/scoped_ptr.h"
16 #include "base/strings/pattern.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/win/scoped_co_mem.h"
20 #include "build/build_config.h"
21
22 namespace install_static {
13 23
14 ProcessType g_process_type = ProcessType::UNINITIALIZED; 24 ProcessType g_process_type = ProcessType::UNINITIALIZED;
15 25
26 // Chrome channel display names.
27 // TODO(ananta)
28 // These constants are defined in the chrome/installer directory as well. We
29 // need to unify them.
30 const wchar_t kChromeChannelUnknown[] = L"unknown";
31 const wchar_t kChromeChannelCanary[] = L"canary";
32 const wchar_t kChromeChannelDev[] = L"dev";
33 const wchar_t kChromeChannelBeta[] = L"beta";
34 const wchar_t kChromeChannelStable[] = L"";
35 const wchar_t kChromeChannelStableExplicit[] = L"stable";
36
16 namespace { 37 namespace {
17 38
18 const wchar_t kRegPathClientState[] = L"Software\\Google\\Update\\ClientState"; 39 const wchar_t kRegPathClientState[] = L"Software\\Google\\Update\\ClientState";
19 const wchar_t kRegPathClientStateMedium[] = 40 const wchar_t kRegPathClientStateMedium[] =
20 L"Software\\Google\\Update\\ClientStateMedium"; 41 L"Software\\Google\\Update\\ClientStateMedium";
21 #if defined(GOOGLE_CHROME_BUILD) 42 #if defined(GOOGLE_CHROME_BUILD)
22 const wchar_t kRegPathChromePolicy[] = L"SOFTWARE\\Policies\\Google\\Chrome"; 43 const wchar_t kRegPathChromePolicy[] = L"SOFTWARE\\Policies\\Google\\Chrome";
23 #else 44 #else
24 const wchar_t kRegPathChromePolicy[] = L"SOFTWARE\\Policies\\Chromium"; 45 const wchar_t kRegPathChromePolicy[] = L"SOFTWARE\\Policies\\Chromium";
25 #endif // defined(GOOGLE_CHROME_BUILD) 46 #endif // defined(GOOGLE_CHROME_BUILD)
26 47
27 const wchar_t kRegValueUsageStats[] = L"usagestats"; 48 const wchar_t kRegValueUsageStats[] = L"usagestats";
28 const wchar_t kUninstallArgumentsField[] = L"UninstallArguments"; 49 const wchar_t kUninstallArgumentsField[] = L"UninstallArguments";
29 const wchar_t kMetricsReportingEnabled[] = L"MetricsReportingEnabled"; 50 const wchar_t kMetricsReportingEnabled[] = L"MetricsReportingEnabled";
30 51
52 const wchar_t kRegPathGoogleUpdate[] = L"Software\\Google\\Update";
53 const wchar_t kRegGoogleUpdateVersion[] = L"version";
54
31 const wchar_t kAppGuidCanary[] = 55 const wchar_t kAppGuidCanary[] =
32 L"{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}"; 56 L"{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}";
33 const wchar_t kAppGuidGoogleChrome[] = 57 const wchar_t kAppGuidGoogleChrome[] =
34 L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; 58 L"{8A69D345-D564-463c-AFF1-A69D9E530F96}";
35 const wchar_t kAppGuidGoogleBinaries[] = 59 const wchar_t kAppGuidGoogleBinaries[] =
36 L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}"; 60 L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}";
37 61
62 // TODO(ananta)
63 // These constants are defined in the chrome/installer directory as well. We
64 // need to unify them.
65 const wchar_t kSxSSuffix[] = L" SxS";
66 const wchar_t kGoogleChromeInstallSubDir1[] = L"Google";
67 const wchar_t kGoogleChromeInstallSubDir2[] = L"Chrome";
68 const wchar_t kChromiumInstallSubDir[] = L"Chromium";
69 const wchar_t kUserDataDirname[] = L"User Data";
70 const wchar_t kRegApField[] = L"ap";
71 const wchar_t kBrowserCrashDumpMetricsSubKey[] = L"\\BrowserCrashDumpAttempts";
72
38 bool ReadKeyValueString(bool system_install, const wchar_t* key_path, 73 bool ReadKeyValueString(bool system_install, const wchar_t* key_path,
39 const wchar_t* guid, const wchar_t* value_to_read, 74 const wchar_t* guid, const wchar_t* value_to_read,
40 base::string16* value_out) { 75 base::string16* value_out) {
41 HKEY key = NULL; 76 HKEY key = NULL;
42 value_out->clear(); 77 value_out->clear();
43 78
44 base::string16 full_key_path(key_path); 79 base::string16 full_key_path(key_path);
45 full_key_path.append(1, L'\\'); 80 if (wcslen(guid) > 0) {
46 full_key_path.append(guid); 81 full_key_path.append(1, L'\\');
82 full_key_path.append(guid);
83 }
47 84
48 if (::RegOpenKeyEx(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, 85 if (::RegOpenKeyEx(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
49 full_key_path.c_str(), 0, 86 full_key_path.c_str(), 0,
50 KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key) != 87 KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key) !=
51 ERROR_SUCCESS) { 88 ERROR_SUCCESS) {
52 return false; 89 return false;
53 } 90 }
54 91
55 const size_t kMaxStringLength = 1024; 92 const size_t kMaxStringLength = 1024;
56 wchar_t raw_value[kMaxStringLength] = {}; 93 wchar_t raw_value[kMaxStringLength] = {};
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 DWORD size = sizeof(*value_out); 137 DWORD size = sizeof(*value_out);
101 DWORD type = REG_DWORD; 138 DWORD type = REG_DWORD;
102 LONG result = ::RegQueryValueEx(key, value_to_read, 0, &type, 139 LONG result = ::RegQueryValueEx(key, value_to_read, 0, &type,
103 reinterpret_cast<BYTE*>(value_out), &size); 140 reinterpret_cast<BYTE*>(value_out), &size);
104 141
105 ::RegCloseKey(key); 142 ::RegCloseKey(key);
106 143
107 return result == ERROR_SUCCESS && size == sizeof(*value_out); 144 return result == ERROR_SUCCESS && size == sizeof(*value_out);
108 } 145 }
109 146
147 struct LanguageAndCodePage {
148 WORD language;
149 WORD code_page;
150 };
151
152 bool GetLanguageAndCodePageFromVersionResource(const char* version_resource,
153 WORD* language,
154 WORD* code_page) {
155 if (!version_resource)
156 return false;
157
158 LanguageAndCodePage* translation_info = nullptr;
159 uint32_t page_count = 0;
160 BOOL query_result = VerQueryValue(version_resource,
161 L"\\VarFileInfo\\Translation",
162 reinterpret_cast<void**>(&translation_info),
163 &page_count);
164 if (!query_result)
165 return false;
166
167 *language = translation_info->language;
168 *code_page = translation_info->code_page;
169 return true;
170 }
171
172 bool GetValueFromVersionResource(const char* version_resource,
173 const base::string16& name,
174 base::string16* value_str) {
175 DCHECK(value_str);
176
177 WORD language = 0;
178 WORD code_page = 0;
179 if (!GetLanguageAndCodePageFromVersionResource(version_resource,
180 &language,
181 &code_page)) {
182 return false;
183 }
184
185 WORD lang_codepage[8] = {};
186 size_t i = 0;
187 // Use the language and codepage
188 lang_codepage[i++] = language;
189 lang_codepage[i++] = code_page;
190 // Use the default language and codepage from the resource.
191 lang_codepage[i++] = ::GetUserDefaultLangID();
192 lang_codepage[i++] = code_page;
193 // Use the language from the resource and Latin codepage (most common).
194 lang_codepage[i++] = language;
195 lang_codepage[i++] = 1252;
196 // Use the default language and Latin codepage (most common).
197 lang_codepage[i++] = ::GetUserDefaultLangID();
198 lang_codepage[i++] = 1252;
199
200 static_assert((arraysize(lang_codepage) % 2) == 0,
201 "Language code page size should be a multiple of 2");
202
203 i = 0;
204 while (i < arraysize(lang_codepage)) {
205 wchar_t sub_block[MAX_PATH] = {};
206 WORD language = lang_codepage[i++];
207 WORD code_page = lang_codepage[i++];
208 _snwprintf_s(sub_block, MAX_PATH, MAX_PATH,
209 L"\\StringFileInfo\\%04x%04x\\%ls", language, code_page, name.c_str());
210 void* value = NULL;
211 uint32_t size = 0;
212 BOOL r = ::VerQueryValue(version_resource, sub_block, &value, &size);
213 if (r && value) {
214 value_str->assign(static_cast<wchar_t*>(value));
215 return true;
216 }
217 }
218 return false;
219 }
220
221 // Returns the executable path for the current process.
222 base::string16 GetCurrentProcessExePath() {
223 wchar_t exe_path[MAX_PATH] = {};
224 if (GetModuleFileName(NULL, exe_path, arraysize(exe_path)) == 0)
225 return base::string16();
226 return exe_path;
227 }
228
110 } // namespace 229 } // namespace
111 230
112 bool IsCanary(const wchar_t* exe_path) { 231 bool IsCanary(const wchar_t* exe_path) {
113 return wcsstr(exe_path, L"Chrome SxS\\Application") != NULL; 232 return wcsstr(exe_path, L"Chrome SxS\\Application") != NULL;
114 } 233 }
115 234
116 bool IsSystemInstall(const wchar_t* exe_path) { 235 bool IsSystemInstall(const wchar_t* exe_path) {
117 wchar_t program_dir[MAX_PATH] = {}; 236 wchar_t program_dir[MAX_PATH] = {};
118 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, 237 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir,
119 arraysize(program_dir)); 238 arraysize(program_dir));
(...skipping 11 matching lines...) Expand all
131 bool IsMultiInstall(bool is_system_install) { 250 bool IsMultiInstall(bool is_system_install) {
132 base::string16 args; 251 base::string16 args;
133 if (!ReadKeyValueString(is_system_install, kRegPathClientState, 252 if (!ReadKeyValueString(is_system_install, kRegPathClientState,
134 kAppGuidGoogleChrome, kUninstallArgumentsField, 253 kAppGuidGoogleChrome, kUninstallArgumentsField,
135 &args)) { 254 &args)) {
136 return false; 255 return false;
137 } 256 }
138 return args.find(L"--multi-install") != base::string16::npos; 257 return args.find(L"--multi-install") != base::string16::npos;
139 } 258 }
140 259
141 bool AreUsageStatsEnabled(const wchar_t* exe_path) { 260 bool GetCollectStatsConsent() {
142 bool enabled = true; 261 bool enabled = true;
143 bool controlled_by_policy = ReportingIsEnforcedByPolicy(&enabled); 262 bool controlled_by_policy = ReportingIsEnforcedByPolicy(&enabled);
144 263
145 if (controlled_by_policy && !enabled) 264 if (controlled_by_policy && !enabled)
146 return false; 265 return false;
147 266
148 bool system_install = IsSystemInstall(exe_path); 267 base::string16 exe_path = GetCurrentProcessExePath();
268
269 bool system_install = IsSystemInstall(exe_path.c_str());
149 base::string16 app_guid; 270 base::string16 app_guid;
150 271
151 if (IsCanary(exe_path)) { 272 if (IsCanary(exe_path.c_str())) {
152 app_guid = kAppGuidCanary; 273 app_guid = kAppGuidCanary;
153 } else { 274 } else {
154 app_guid = IsMultiInstall(system_install) ? kAppGuidGoogleBinaries : 275 app_guid = IsMultiInstall(system_install) ? kAppGuidGoogleBinaries :
155 kAppGuidGoogleChrome; 276 kAppGuidGoogleChrome;
156 } 277 }
157 278
158 DWORD out_value = 0; 279 DWORD out_value = 0;
159 if (system_install && 280 if (system_install &&
160 ReadKeyValueDW(system_install, kRegPathClientStateMedium, app_guid, 281 ReadKeyValueDW(system_install, kRegPathClientStateMedium, app_guid,
161 kRegValueUsageStats, &out_value)) { 282 kRegValueUsageStats, &out_value)) {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 return; 336 return;
216 } 337 }
217 338
218 g_process_type = ProcessType::BROWSER_PROCESS; 339 g_process_type = ProcessType::BROWSER_PROCESS;
219 } 340 }
220 341
221 bool IsNonBrowserProcess() { 342 bool IsNonBrowserProcess() {
222 assert(g_process_type != ProcessType::UNINITIALIZED); 343 assert(g_process_type != ProcessType::UNINITIALIZED);
223 return g_process_type == ProcessType::NON_BROWSER_PROCESS; 344 return g_process_type == ProcessType::NON_BROWSER_PROCESS;
224 } 345 }
346
347 bool GetDefaultUserDataDirectory(base::FilePath* result) {
348 scoped_ptr<wchar_t> user_data_dir_path;
349
350 // This environment variable should be set on Windows 7 and up.
351 // If we fail to find this variable then we default to the temporary files
352 // path.
353 DWORD size = ::ExpandEnvironmentStrings(L"%LOCALAPPDATA%", nullptr, 0);
354 if (size) {
355 user_data_dir_path.reset(new wchar_t[size]);
356 if (!::ExpandEnvironmentStrings(L"%LOCALAPPDATA%",
357 user_data_dir_path.get(),
358 size)) {
scottmg 2016/04/26 20:44:47 Confirm that the return value was == size.
ananta 2016/04/26 21:33:08 Done.
359 user_data_dir_path.reset(nullptr);
360 }
361 }
362 // We failed to find the %LOCALAPPDATA% folder. Fallback to the temporary
363 // files path. If we fail to find this we bail.
364 if (!user_data_dir_path.get()) {
365 size = ::GetTempPath(0, nullptr);
366 if (!size)
367 return false;
368 user_data_dir_path.reset(new wchar_t[size + 1]);
369 if (!GetTempPath(size + 1, user_data_dir_path.get()))
scottmg 2016/04/26 20:44:46 nit; ::GetTempPath() to match above.
ananta 2016/04/26 21:33:08 Done.
370 return false;
371 }
372
373 base::string16 install_sub_directory = GetChromeInstallSubDirectory();
374
375 *result = base::FilePath(user_data_dir_path.get()).Append(
376 install_sub_directory).Append(kUserDataDirname);
377 return true;
378 }
379
380 bool GetDefaultCrashDumpLocation(base::FilePath* crash_dir) {
381 // In order to be able to start crash handling very early, we do not rely on
382 // chrome's PathService entries (for DIR_CRASH_DUMPS) being available on
383 // Windows. See https://crbug.com/564398.
384 if (!GetDefaultUserDataDirectory(crash_dir))
385 return false;
386 // We have to make sure the user data dir exists on first run. See
387 // http://crbug.com/591504.
388 // TODO(ananta)
389 // Avoid using base file helpers here.
390 if (!base::PathExists(*crash_dir) && !base::CreateDirectory(*crash_dir))
391 return false;
392 *crash_dir = crash_dir->Append(FILE_PATH_LITERAL("Crashpad"));
393 return true;
394 }
395
396
397 std::string GetEnvironmentString(const std::string& variable_name) {
398 DWORD value_length = ::GetEnvironmentVariable(
399 base::UTF8ToWide(variable_name).c_str(), NULL, 0);
400 if (value_length == 0)
401 return std::string();
402 std::unique_ptr<wchar_t[]> value(new wchar_t[value_length]);
403 ::GetEnvironmentVariable(base::UTF8ToWide(variable_name).c_str(),
404 value.get(), value_length);
405 return base::WideToUTF8(value.get());
406 }
407
408 bool SetEnvironmentString(const std::string& variable_name,
409 const std::string& new_value) {
410 return !!SetEnvironmentVariable(base::UTF8ToWide(variable_name).c_str(),
411 base::UTF8ToWide(new_value).c_str());
412 }
413
414 bool HasEnvironmentVariable(const std::string& variable_name) {
415 return !!::GetEnvironmentVariable(base::UTF8ToWide(variable_name).c_str(),
416 NULL, 0);
417 }
418
419 bool GetExecutableVersionDetails(const base::string16& exe_path,
420 base::string16* product_name,
421 base::string16* version,
422 base::string16* special_build,
423 base::string16* channel_name) {
424 DCHECK(product_name);
425 DCHECK(version);
426 DCHECK(special_build);
427 DCHECK(channel_name);
428
429 // Default values in case we don't find a version resource.
430 *product_name = L"Chrome";
431 *version = L"0.0.0.0-devel";
scottmg 2016/04/26 20:44:46 special_build and channel_name still need to be in
ananta 2016/04/26 21:33:08 Done.
432
433 DWORD dummy = 0;
434 DWORD length = ::GetFileVersionInfoSize(exe_path.c_str(), &dummy);
435 if (length) {
436 scoped_ptr<char> data(new char[length]);
437 if (::GetFileVersionInfo(exe_path.c_str(), dummy, length,
438 data.get())) {
439 GetValueFromVersionResource(data.get(), L"ProductVersion", version);
440
441 base::string16 official_build;
442 GetValueFromVersionResource(data.get(), L"Official Build",
443 &official_build);
444 if (official_build == L"1")
445 version->append(L"-devel");
446 GetValueFromVersionResource(data.get(), L"ProductShortName",
447 product_name);
448 GetValueFromVersionResource(data.get(), L"SpecialBuild", special_build);
449 }
450 }
451 GetChromeChannelName(!IsSystemInstall(exe_path.c_str()), channel_name);
452 return true;
453 }
454
455 void GetChromeChannelName(bool is_per_user_install,
456 base::string16* channel_name) {
457 #if !defined(GOOGLE_CHROME_BUILD)
458 *channel_name = kChromeChannelUnknown;
459 return;
460 #else
461 channel_name->erase(channel_name->begin(), channel_name->end());
462 // TODO(ananta)
463 // Unify this with the chrome/installer/util/channel_info.h/.cc.
464 if (IsCanary(GetCurrentProcessExePath().c_str())) {
465 *channel_name = L"canary";
466 } else {
467 base::string16 value;
468 if (ReadKeyValueString(!is_per_user_install,
469 kRegPathClientState,
470 kAppGuidGoogleChrome,
471 kRegApField,
472 &value)) {
473 static const wchar_t kChromeChannelBetaPattern[] = L"1?1-";
474 static const wchar_t kChromeChannelBetaX64Pattern[] = L"*x64-beta*";
475 static const wchar_t kChromeChannelDevPattern[] = L"2?0-d";
476 static const wchar_t kChromeChannelDevX64Pattern[] = L"x64-dev";
477 static const wchar_t kChromeStableMultiInstallPattern[] = L"*multi*";
478
479 value = base::ToLowerASCII(value);
480
481 // Channel names containing stable should be reported as an empty string.
482 if (value.find(kChromeChannelStableExplicit) !=
483 base::string16::npos) {
484 return;
485 }
486
487 if (base::MatchPattern(value, kChromeChannelDevPattern) ||
488 base::MatchPattern(value, kChromeChannelDevX64Pattern)) {
489 channel_name->assign(kChromeChannelDev);
490 }
491
492 if (base::MatchPattern(value, kChromeChannelBetaPattern) ||
493 base::MatchPattern(value, kChromeChannelBetaPattern)) {
494 channel_name->assign(kChromeChannelBeta);
495 }
496
497 if (value.find(kChromeStableMultiInstallPattern) !=
498 base::string16::npos) {
499 *channel_name = L"-m";
500 }
501
502 // If we fail to find any matching pattern in the channel name then we
503 // default to empty which means stable. Not sure if this is ok.
504 // TODO(ananta)
505 // Check if this is ok.
506 } else {
507 *channel_name = kChromeChannelUnknown;
508 }
509 }
510 #endif // GOOGLE_CHROME_BUILD
511 }
512
513 base::Version GetGoogleUpdateVersion() {
514 base::string16 update_version;
515 if (ReadKeyValueString(IsSystemInstall(GetCurrentProcessExePath().c_str()),
516 kRegPathGoogleUpdate,
517 L"",
518 kRegGoogleUpdateVersion,
519 &update_version)) {
520 return base::Version(base::UTF16ToUTF8(update_version));
521 }
522 return base::Version();
523 }
524
525 base::string16 GetChromeInstallSubDirectory() {
526 base::FilePath result;
527 #if defined(GOOGLE_CHROME_BUILD)
528 base::string16 sub_directory = kGoogleChromeInstallSubDir1;
529 sub_directory += L"\\";
530 sub_directory += kGoogleChromeInstallSubDir2;
531 if (IsCanary(GetCurrentProcessExePath().c_str()))
532 sub_directory += kSxSSuffix;
533 result = result.Append(sub_directory);
534 #else
535 result = result.Append(kChromiumInstallSubDir);
536 #endif
537 return result.value();
538 }
539
540 base::string16 GetBrowserCrashDumpAttemptsRegistryPath() {
541 base::string16 registry_path = L"Software";
542 base::string16 install_sub_directory = GetChromeInstallSubDirectory();
543 registry_path += install_sub_directory;
544 registry_path += kBrowserCrashDumpMetricsSubKey;
545 return registry_path;
546 }
547
548 } // namespace install_static
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698