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

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

Issue 2487783002: Make Crashpad use the user data dir, rather than always default location (Closed)
Patch Set: . Created 4 years, 1 month 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 <windows.h> 7 #include <windows.h>
8 #include <assert.h> 8 #include <assert.h>
9 #include <algorithm> 9 #include <algorithm>
10 #include <iostream> 10 #include <iostream>
11 #include <iterator> 11 #include <iterator>
12 #include <memory> 12 #include <memory>
13 #include <sstream> 13 #include <sstream>
14 14
15 #include "chrome/install_static/policy_path_parser.h"
15 #include "chrome_elf/nt_registry/nt_registry.h" 16 #include "chrome_elf/nt_registry/nt_registry.h"
16 17
17 namespace install_static { 18 namespace install_static {
18 19
19 ProcessType g_process_type = ProcessType::UNINITIALIZED; 20 ProcessType g_process_type = ProcessType::UNINITIALIZED;
20 21
21 // TODO(ananta) 22 // TODO(ananta)
22 // http://crbug.com/604923 23 // http://crbug.com/604923
23 // The constants defined in this file are also defined in chrome/installer and 24 // The constants defined in this file are also defined in chrome/installer and
24 // other places. we need to unify them. 25 // other places. we need to unify them.
(...skipping 29 matching lines...) Expand all
54 const wchar_t kAppGuidGoogleChrome[] = 55 const wchar_t kAppGuidGoogleChrome[] =
55 L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; 56 L"{8A69D345-D564-463c-AFF1-A69D9E530F96}";
56 const wchar_t kAppGuidGoogleBinaries[] = 57 const wchar_t kAppGuidGoogleBinaries[] =
57 L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}"; 58 L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}";
58 59
59 const wchar_t kHeadless[] = L"CHROME_HEADLESS"; 60 const wchar_t kHeadless[] = L"CHROME_HEADLESS";
60 const wchar_t kShowRestart[] = L"CHROME_CRASHED"; 61 const wchar_t kShowRestart[] = L"CHROME_CRASHED";
61 const wchar_t kRestartInfo[] = L"CHROME_RESTART"; 62 const wchar_t kRestartInfo[] = L"CHROME_RESTART";
62 const wchar_t kRtlLocale[] = L"RIGHT_TO_LEFT"; 63 const wchar_t kRtlLocale[] = L"RIGHT_TO_LEFT";
63 64
64 const char kGpuProcess[] = "gpu-process"; 65 const wchar_t kCrashpadHandler[] = L"crashpad-handler";
65 const char kPpapiPluginProcess[] = "ppapi"; 66 const wchar_t kProcessType[] = L"type";
66 const char kRendererProcess[] = "renderer"; 67 const wchar_t kUserDataDirSwitch[] = L"user-data-dir";
grt (UTC plus 2) 2016/11/16 13:24:52 nit: either use "Swtich" on all of these constants
scottmg 2016/11/16 21:01:18 Hrm, I don't like "Switch" on there, but there's 3
67 const char kUtilityProcess[] = "utility"; 68 const wchar_t kUtilityProcess[] = L"utility";
68 const char kProcessType[] = "type"; 69
69 const char kCrashpadHandler[] = "crashpad-handler"; 70 #if defined(GOOGLE_CHROME_BUILD)
71 const wchar_t kRegistryChromePolicyKey[] =
72 L"SOFTWARE\\Policies\\Google\\Chrome";
73 #else
74 const wchar_t kRegistryChromePolicyKey[] =
75 L"SOFTWARE\\Policies\\Chromium";
76 #endif
77 const wchar_t kUserDataDirRegKey[] = L"UserDataDir";
70 78
71 namespace { 79 namespace {
72 80
73 // TODO(ananta) 81 // TODO(ananta)
74 // http://crbug.com/604923 82 // http://crbug.com/604923
75 // These constants are defined in the chrome/installer directory as well. We 83 // These constants are defined in the chrome/installer directory as well. We
76 // need to unify them. 84 // need to unify them.
77 #if defined(GOOGLE_CHROME_BUILD) 85 #if defined(GOOGLE_CHROME_BUILD)
78 const wchar_t kSxSSuffix[] = L" SxS"; 86 const wchar_t kSxSSuffix[] = L" SxS";
79 const wchar_t kGoogleChromeInstallSubDir1[] = L"Google"; 87 const wchar_t kGoogleChromeInstallSubDir1[] = L"Google";
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 } 187 }
180 188
181 // Returns the executable path for the current process. 189 // Returns the executable path for the current process.
182 std::wstring GetCurrentProcessExePath() { 190 std::wstring GetCurrentProcessExePath() {
183 wchar_t exe_path[MAX_PATH]; 191 wchar_t exe_path[MAX_PATH];
184 if (::GetModuleFileName(nullptr, exe_path, MAX_PATH) == 0) 192 if (::GetModuleFileName(nullptr, exe_path, MAX_PATH) == 0)
185 return std::wstring(); 193 return std::wstring();
186 return exe_path; 194 return exe_path;
187 } 195 }
188 196
197 std::wstring MakeAbsoluteFilePath(const std::wstring& input) {
198 wchar_t file_path[MAX_PATH];
199 if (!_wfullpath(file_path, input.c_str(), MAX_PATH))
grt (UTC plus 2) 2016/11/16 13:24:52 #include <stdlib.h> for _wfullpath
grt (UTC plus 2) 2016/11/16 13:24:52 nit: MAX_PATH -> _countof(file_path)
scottmg 2016/11/16 21:01:18 Done.
scottmg 2016/11/16 21:01:18 Done.
200 return std::wstring();
201 return file_path;
202 }
203
204 bool DirectoryExists(const std::wstring& path) {
205 DWORD file_attributes = ::GetFileAttributes(path.c_str());
206 if (file_attributes != INVALID_FILE_ATTRIBUTES)
grt (UTC plus 2) 2016/11/16 13:24:52 uber nit: either handle failure with an early retu
scottmg 2016/11/16 21:01:18 Done.
207 return (file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
208 return false;
209 }
210
189 bool RecursiveDirectoryCreate(const std::wstring& full_path) { 211 bool RecursiveDirectoryCreate(const std::wstring& full_path) {
190 // If the path exists, we've succeeded if it's a directory, failed otherwise. 212 // If the path exists, we've succeeded if it's a directory, failed otherwise.
191 const wchar_t* full_path_str = full_path.c_str(); 213 const wchar_t* full_path_str = full_path.c_str();
192 DWORD file_attributes = ::GetFileAttributes(full_path_str); 214 DWORD file_attributes = ::GetFileAttributes(full_path_str);
193 if (file_attributes != INVALID_FILE_ATTRIBUTES) { 215 if (file_attributes != INVALID_FILE_ATTRIBUTES) {
194 if ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { 216 if ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
195 Trace(L"%hs( %ls directory exists )\n", __func__, full_path_str); 217 Trace(L"%hs( %ls directory exists )\n", __func__, full_path_str);
196 return true; 218 return true;
197 } 219 }
198 Trace(L"%hs( %ls directory conflicts with an existing file. )\n", __func__, 220 Trace(L"%hs( %ls directory conflicts with an existing file. )\n", __func__,
(...skipping 10 matching lines...) Expand all
209 std::size_t pos = full_path.find_last_of(L"/\\"); 231 std::size_t pos = full_path.find_last_of(L"/\\");
210 if (pos != std::wstring::npos) { 232 if (pos != std::wstring::npos) {
211 parent_path = full_path.substr(0, pos); 233 parent_path = full_path.substr(0, pos);
212 if (!RecursiveDirectoryCreate(parent_path)) { 234 if (!RecursiveDirectoryCreate(parent_path)) {
213 Trace(L"Failed to create one of the parent directories"); 235 Trace(L"Failed to create one of the parent directories");
214 return false; 236 return false;
215 } 237 }
216 } 238 }
217 if (!::CreateDirectory(full_path_str, nullptr)) { 239 if (!::CreateDirectory(full_path_str, nullptr)) {
218 DWORD error_code = ::GetLastError(); 240 DWORD error_code = ::GetLastError();
219 if (error_code == ERROR_ALREADY_EXISTS) { 241 if (error_code == ERROR_ALREADY_EXISTS && DirectoryExists(full_path_str)) {
220 DWORD file_attributes = ::GetFileAttributes(full_path_str); 242 // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we
221 if ((file_attributes != INVALID_FILE_ATTRIBUTES) && 243 // were racing with someone creating the same directory, or a file
222 ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) { 244 // with the same path. If the directory exists, we lost the
223 // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we 245 // race to create the same directory.
224 // were racing with someone creating the same directory, or a file 246 return true;
225 // with the same path. If the directory exists, we lost the 247 } else {
226 // race to create the same directory. 248 Trace(L"Failed to create directory %ls, last error is %d\n",
227 return true; 249 full_path_str, error_code);
228 } else { 250 return false;
229 Trace(L"Failed to create directory %ls, last error is %d\n",
230 full_path_str, error_code);
231 return false;
232 }
233 } 251 }
234 } 252 }
235 return true; 253 return true;
236 } 254 }
237 255
238 std::wstring GetChromeInstallRegistryPath() { 256 std::wstring GetChromeInstallRegistryPath() {
239 std::wstring registry_path = L"Software\\"; 257 std::wstring registry_path = L"Software\\";
240 registry_path += GetChromeInstallSubDirectory(); 258 registry_path += GetChromeInstallSubDirectory();
241 return registry_path; 259 return registry_path;
242 } 260 }
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 std::vector<StringType> tokens; 387 std::vector<StringType> tokens;
370 std::basic_istringstream<typename StringType::value_type> buffer(str); 388 std::basic_istringstream<typename StringType::value_type> buffer(str);
371 for (StringType token; std::getline(buffer, token, delimiter);) { 389 for (StringType token; std::getline(buffer, token, delimiter);) {
372 if (trim_spaces) 390 if (trim_spaces)
373 TrimT<StringType>(&token); 391 TrimT<StringType>(&token);
374 tokens.push_back(token); 392 tokens.push_back(token);
375 } 393 }
376 return tokens; 394 return tokens;
377 } 395 }
378 396
397 // Checks if the key exists in the given hive and expands any string variables.
398 bool LoadUserDataDirPolicyFromRegistry(nt::ROOT_KEY hive,
399 const wchar_t* key_name,
400 std::wstring* dir) {
401 std::wstring value;
402 bool result = false;
403 HANDLE key;
404 if (nt::OpenRegKey(hive, kRegistryChromePolicyKey, KEY_READ, &key, nullptr)) {
405 if (nt::QueryRegValueSZ(key, key_name, &value)) {
406 *dir = install_static::ExpandPathVariables(value);
407 result = true;
408 }
409 nt::CloseRegKey(key);
410 }
411 return result;
412 }
413
414 void CheckUserDataDirPolicy(std::wstring* user_data_dir) {
415 assert(user_data_dir);
416 // Policy from the HKLM hive has precedence over HKCU.
417 if (!LoadUserDataDirPolicyFromRegistry(nt::HKLM, kUserDataDirRegKey,
418 user_data_dir)) {
419 LoadUserDataDirPolicyFromRegistry(nt::HKCU, kUserDataDirRegKey,
420 user_data_dir);
421 }
422 }
423
379 } // namespace 424 } // namespace
380 425
381 bool IsSxSChrome(const wchar_t* exe_path) { 426 bool IsSxSChrome(const wchar_t* exe_path) {
382 return ::wcsstr(exe_path, L"Chrome SxS\\Application") != nullptr; 427 return ::wcsstr(exe_path, L"Chrome SxS\\Application") != nullptr;
383 } 428 }
384 429
385 bool IsSystemInstall(const wchar_t* exe_path) { 430 bool IsSystemInstall(const wchar_t* exe_path) {
386 wchar_t program_dir[MAX_PATH] = {}; 431 wchar_t program_dir[MAX_PATH] = {};
387 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, MAX_PATH); 432 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, MAX_PATH);
388 if (ret && ret < MAX_PATH && !::wcsnicmp(exe_path, program_dir, ret)) { 433 if (ret && ret < MAX_PATH && !::wcsnicmp(exe_path, program_dir, ret)) {
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
489 } 534 }
490 535
491 bool IsNonBrowserProcess() { 536 bool IsNonBrowserProcess() {
492 assert(g_process_type != ProcessType::UNINITIALIZED); 537 assert(g_process_type != ProcessType::UNINITIALIZED);
493 return g_process_type == ProcessType::NON_BROWSER_PROCESS; 538 return g_process_type == ProcessType::NON_BROWSER_PROCESS;
494 } 539 }
495 540
496 bool GetDefaultUserDataDirectory(std::wstring* result) { 541 bool GetDefaultUserDataDirectory(std::wstring* result) {
497 static const wchar_t kLocalAppData[] = L"%LOCALAPPDATA%"; 542 static const wchar_t kLocalAppData[] = L"%LOCALAPPDATA%";
498 543
499 std::unique_ptr<wchar_t> user_data_dir_path; 544 std::unique_ptr<wchar_t[]> user_data_dir_path;
500 545
501 // This environment variable should be set on Windows 7 and up. 546 // This environment variable should be set on Windows 7 and up.
502 // If we fail to find this variable then we default to the temporary files 547 // If we fail to find this variable then we default to the temporary files
503 // path. 548 // path.
504 DWORD size = ::ExpandEnvironmentStrings(kLocalAppData, nullptr, 0); 549 DWORD size = ::ExpandEnvironmentStrings(kLocalAppData, nullptr, 0);
505 if (size) { 550 if (size) {
506 user_data_dir_path.reset(new wchar_t[size]); 551 user_data_dir_path.reset(new wchar_t[size]);
507 if (::ExpandEnvironmentStrings(kLocalAppData, user_data_dir_path.get(), 552 if (::ExpandEnvironmentStrings(kLocalAppData, user_data_dir_path.get(),
508 size) != size) { 553 size) != size) {
509 user_data_dir_path.reset(); 554 user_data_dir_path.reset();
(...skipping 14 matching lines...) Expand all
524 569
525 *result = user_data_dir_path.get(); 570 *result = user_data_dir_path.get();
526 if ((*result)[result->length() - 1] != L'\\') 571 if ((*result)[result->length() - 1] != L'\\')
527 result->append(L"\\"); 572 result->append(L"\\");
528 result->append(install_sub_directory); 573 result->append(install_sub_directory);
529 result->append(L"\\"); 574 result->append(L"\\");
530 result->append(kUserDataDirname); 575 result->append(kUserDataDirname);
531 return true; 576 return true;
532 } 577 }
533 578
534 bool GetDefaultCrashDumpLocation(std::wstring* crash_dir) { 579 bool GetUserDataDirectory(const std::wstring& user_data_dir_from_command_line,
535 // In order to be able to start crash handling very early, we do not rely on 580 std::wstring* result) {
536 // chrome's PathService entries (for DIR_CRASH_DUMPS) being available on 581 // WARNING! This has to mirror the logic in chrome/app/chrome_main_delegate.cc
537 // Windows. See https://crbug.com/564398. 582 // in InitializeUserDataDir(). This function derives the path in the same way,
538 if (!GetDefaultUserDataDirectory(crash_dir)) 583 // but without using base, nor reporting on failure as the Chrome
584 // implementation does.
585 std::wstring user_data_dir = user_data_dir_from_command_line;
586
587 CheckUserDataDirPolicy(&user_data_dir);
588
589 // On Windows, trailing separators leave Chrome in a bad state. See
590 // crbug.com/464616.
591 while (!user_data_dir.empty() &&
592 (user_data_dir.back() == '\\' || user_data_dir.back() == '/')) {
593 user_data_dir.pop_back();
594 }
595
596 bool have_valid_directory =
grt (UTC plus 2) 2016/11/16 13:24:52 i gently prefer this, but it's your call: bool h
scottmg 2016/11/16 21:01:18 Done.
597 !user_data_dir.empty() && RecursiveDirectoryCreate(user_data_dir);
598
599 if (!have_valid_directory && !GetDefaultUserDataDirectory(&user_data_dir)) {
600 // The Chrome implementation CHECKs() here in the browser process. We
601 // don't as this function is used to initialize crash reporting, so
602 // we would get no report of this failure.
603 assert(false);
539 return false; 604 return false;
605 }
606
607 *result = MakeAbsoluteFilePath(user_data_dir);
608 return true;
609 }
610
611 bool GetUserDataDirectoryUsingProcessCommandLine(std::wstring* result) {
612 return GetUserDataDirectory(
613 GetSwitchValueFromCommandLine(::GetCommandLine(),
614 install_static::kUserDataDirSwitch),
615 result);
616 }
617
618 bool GetCrashDumpLocation(std::wstring* crash_dir) {
619 // In order to be able to start crash handling very early and in chrome_elf,
620 // we cannot rely on chrome's PathService entries (for DIR_CRASH_DUMPS)
621 // being
grt (UTC plus 2) 2016/11/16 13:24:52 nit: wrap
scottmg 2016/11/16 21:01:18 Done.
622 // available on Windows. See https://crbug.com/564398.
623 if (!GetUserDataDirectoryUsingProcessCommandLine(crash_dir)) {
grt (UTC plus 2) 2016/11/16 13:24:52 nit: omit braces
scottmg 2016/11/16 21:01:18 Done.
624 return false;
625 }
540 626
541 // We have to make sure the user data dir exists on first run. See 627 // We have to make sure the user data dir exists on first run. See
542 // http://crbug.com/591504. 628 // http://crbug.com/591504.
543 if (!RecursiveDirectoryCreate(crash_dir->c_str())) 629 if (!RecursiveDirectoryCreate(crash_dir->c_str()))
544 return false; 630 return false;
545 crash_dir->append(L"\\Crashpad"); 631 crash_dir->append(L"\\Crashpad");
546 return true; 632 return true;
547 } 633 }
548 634
549 std::string GetEnvironmentString(const std::string& variable_name) { 635 std::string GetEnvironmentString(const std::string& variable_name) {
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after
837 *result = -1; 923 *result = -1;
838 return true; 924 return true;
839 } 925 }
840 } 926 }
841 } 927 }
842 // Here it means that both versions are equal. 928 // Here it means that both versions are equal.
843 *result = 0; 929 *result = 0;
844 return true; 930 return true;
845 } 931 }
846 932
847 std::string GetSwitchValueFromCommandLine(const std::string& command_line, 933 std::wstring GetSwitchValueFromCommandLine(const std::wstring& command_line,
848 const std::string& switch_name) { 934 const std::wstring& switch_name) {
849 assert(!command_line.empty()); 935 assert(!command_line.empty());
850 assert(!switch_name.empty()); 936 assert(!switch_name.empty());
851 937
852 std::string command_line_copy = command_line; 938 std::wstring command_line_copy = command_line;
853 // Remove leading and trailing spaces. 939 // Remove leading and trailing spaces.
854 TrimT<std::string>(&command_line_copy); 940 TrimT<std::wstring>(&command_line_copy);
855 941
856 // Find the switch in the command line. If we don't find the switch, return 942 // Find the switch in the command line. If we don't find the switch, return
857 // an empty string. 943 // an empty string.
858 std::string switch_token = "--"; 944 std::wstring switch_token = L"--";
859 switch_token += switch_name; 945 switch_token += switch_name;
860 switch_token += "="; 946 switch_token += L"=";
861 size_t switch_offset = command_line_copy.find(switch_token); 947 size_t switch_offset = command_line_copy.find(switch_token);
862 if (switch_offset == std::string::npos) 948 if (switch_offset == std::string::npos)
863 return std::string(); 949 return std::wstring();
864 950
865 // The format is "--<switch name>=blah". Look for a space after the 951 // The format is "--<switch name>=blah". Look for a space after the
866 // "--<switch name>=" string. If we don't find a space assume that the switch 952 // "--<switch name>=" string. If we don't find a space assume that the switch
867 // value ends at the end of the command line. 953 // value ends at the end of the command line.
868 size_t switch_value_start_offset = switch_offset + switch_token.length(); 954 size_t switch_value_start_offset = switch_offset + switch_token.length();
869 if (std::string(kWhiteSpaces).find( 955 if (std::wstring(kWhiteSpaces16).find(
870 command_line_copy[switch_value_start_offset]) != std::string::npos) { 956 command_line_copy[switch_value_start_offset]) != std::wstring::npos) {
871 switch_value_start_offset = command_line_copy.find_first_not_of( 957 switch_value_start_offset = command_line_copy.find_first_not_of(
872 GetWhiteSpacesForType<std::string>(), switch_value_start_offset); 958 GetWhiteSpacesForType<std::wstring>(), switch_value_start_offset);
873 if (switch_value_start_offset == std::string::npos) 959 if (switch_value_start_offset == std::wstring::npos)
874 return std::string(); 960 return std::wstring();
875 } 961 }
876 size_t switch_value_end_offset = 962 size_t switch_value_end_offset =
877 command_line_copy.find_first_of(GetWhiteSpacesForType<std::string>(), 963 command_line_copy.find_first_of(GetWhiteSpacesForType<std::wstring>(),
878 switch_value_start_offset); 964 switch_value_start_offset);
879 if (switch_value_end_offset == std::string::npos) 965 if (switch_value_end_offset == std::wstring::npos)
880 switch_value_end_offset = command_line_copy.length(); 966 switch_value_end_offset = command_line_copy.length();
881 967
882 std::string switch_value = command_line_copy.substr( 968 std::wstring switch_value = command_line_copy.substr(
883 switch_value_start_offset, 969 switch_value_start_offset,
884 switch_value_end_offset - (switch_offset + switch_token.length())); 970 switch_value_end_offset - (switch_offset + switch_token.length()));
885 TrimT<std::string>(&switch_value); 971 TrimT<std::wstring>(&switch_value);
886 return switch_value; 972 return switch_value;
887 } 973 }
888 974
889 } // namespace install_static 975 } // namespace install_static
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698