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

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
« no previous file with comments | « chrome/install_static/install_util.h ('k') | chrome/install_static/install_util_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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";
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))
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)
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
scottmg 2016/11/15 23:23:15 The "else" was at the wrong level (no error was re
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 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 =
597 !user_data_dir.empty() && RecursiveDirectoryCreate(user_data_dir);
598
599 if (!have_valid_directory) {
600 if (!GetDefaultUserDataDirectory(&user_data_dir)) {
601 // The Chrome implementation CHECKs() here in the browser process. We
602 // don't as this function is used to initialize crash reporting, so
603 // we would get no report of this failure.
604 assert(false);
605 return false;
606 }
607 }
608
609 *result = MakeAbsoluteFilePath(user_data_dir);
610 return true;
611 }
612
613 bool GetUserDataDirectoryUsingProcessCommandLine(std::wstring* result) {
614 return GetUserDataDirectory(
615 GetSwitchValueFromCommandLine(::GetCommandLine(),
616 install_static::kUserDataDirSwitch),
617 result);
618 }
619
620 bool GetCrashDumpLocation(std::wstring* crash_dir) {
621 // In order to be able to start crash handling very early and in chrome_elf,
622 // we cannot rely on chrome's PathService entries (for DIR_CRASH_DUMPS)
623 // being
624 // available on Windows. See https://crbug.com/564398.
625 if (!GetUserDataDirectoryUsingProcessCommandLine(crash_dir)) {
539 return false; 626 return false;
627 }
540 628
541 // We have to make sure the user data dir exists on first run. See 629 // We have to make sure the user data dir exists on first run. See
542 // http://crbug.com/591504. 630 // http://crbug.com/591504.
543 if (!RecursiveDirectoryCreate(crash_dir->c_str())) 631 if (!RecursiveDirectoryCreate(crash_dir->c_str()))
544 return false; 632 return false;
545 crash_dir->append(L"\\Crashpad"); 633 crash_dir->append(L"\\Crashpad");
546 return true; 634 return true;
547 } 635 }
548 636
549 std::string GetEnvironmentString(const std::string& variable_name) { 637 std::string GetEnvironmentString(const std::string& variable_name) {
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after
837 *result = -1; 925 *result = -1;
838 return true; 926 return true;
839 } 927 }
840 } 928 }
841 } 929 }
842 // Here it means that both versions are equal. 930 // Here it means that both versions are equal.
843 *result = 0; 931 *result = 0;
844 return true; 932 return true;
845 } 933 }
846 934
847 std::string GetSwitchValueFromCommandLine(const std::string& command_line, 935 std::wstring GetSwitchValueFromCommandLine(const std::wstring& command_line,
848 const std::string& switch_name) { 936 const std::wstring& switch_name) {
849 assert(!command_line.empty()); 937 assert(!command_line.empty());
850 assert(!switch_name.empty()); 938 assert(!switch_name.empty());
851 939
852 std::string command_line_copy = command_line; 940 std::wstring command_line_copy = command_line;
853 // Remove leading and trailing spaces. 941 // Remove leading and trailing spaces.
854 TrimT<std::string>(&command_line_copy); 942 TrimT<std::wstring>(&command_line_copy);
855 943
856 // Find the switch in the command line. If we don't find the switch, return 944 // Find the switch in the command line. If we don't find the switch, return
857 // an empty string. 945 // an empty string.
858 std::string switch_token = "--"; 946 std::wstring switch_token = L"--";
859 switch_token += switch_name; 947 switch_token += switch_name;
860 switch_token += "="; 948 switch_token += L"=";
861 size_t switch_offset = command_line_copy.find(switch_token); 949 size_t switch_offset = command_line_copy.find(switch_token);
862 if (switch_offset == std::string::npos) 950 if (switch_offset == std::string::npos)
863 return std::string(); 951 return std::wstring();
864 952
865 // The format is "--<switch name>=blah". Look for a space after the 953 // 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 954 // "--<switch name>=" string. If we don't find a space assume that the switch
867 // value ends at the end of the command line. 955 // value ends at the end of the command line.
868 size_t switch_value_start_offset = switch_offset + switch_token.length(); 956 size_t switch_value_start_offset = switch_offset + switch_token.length();
869 if (std::string(kWhiteSpaces).find( 957 if (std::wstring(kWhiteSpaces16).find(
870 command_line_copy[switch_value_start_offset]) != std::string::npos) { 958 command_line_copy[switch_value_start_offset]) != std::wstring::npos) {
871 switch_value_start_offset = command_line_copy.find_first_not_of( 959 switch_value_start_offset = command_line_copy.find_first_not_of(
872 GetWhiteSpacesForType<std::string>(), switch_value_start_offset); 960 GetWhiteSpacesForType<std::wstring>(), switch_value_start_offset);
873 if (switch_value_start_offset == std::string::npos) 961 if (switch_value_start_offset == std::wstring::npos)
874 return std::string(); 962 return std::wstring();
875 } 963 }
876 size_t switch_value_end_offset = 964 size_t switch_value_end_offset =
877 command_line_copy.find_first_of(GetWhiteSpacesForType<std::string>(), 965 command_line_copy.find_first_of(GetWhiteSpacesForType<std::wstring>(),
878 switch_value_start_offset); 966 switch_value_start_offset);
879 if (switch_value_end_offset == std::string::npos) 967 if (switch_value_end_offset == std::wstring::npos)
880 switch_value_end_offset = command_line_copy.length(); 968 switch_value_end_offset = command_line_copy.length();
881 969
882 std::string switch_value = command_line_copy.substr( 970 std::wstring switch_value = command_line_copy.substr(
883 switch_value_start_offset, 971 switch_value_start_offset,
884 switch_value_end_offset - (switch_offset + switch_token.length())); 972 switch_value_end_offset - (switch_offset + switch_token.length()));
885 TrimT<std::string>(&switch_value); 973 TrimT<std::wstring>(&switch_value);
886 return switch_value; 974 return switch_value;
887 } 975 }
888 976
889 } // namespace install_static 977 } // namespace install_static
OLDNEW
« no previous file with comments | « chrome/install_static/install_util.h ('k') | chrome/install_static/install_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698