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

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 <assert.h>
8 #include <stdlib.h>
9 #include <string.h>
7 #include <windows.h> 10 #include <windows.h>
grt (UTC plus 2) 2016/11/21 10:29:54 nit: i think we generally include windows.h first
scottmg 2016/11/21 19:34:00 Done.
8 #include <assert.h>
9 #include <string.h>
10 11
11 #include <algorithm> 12 #include <algorithm>
12 #include <memory> 13 #include <memory>
13 #include <sstream> 14 #include <sstream>
14 15
15 #include "chrome/install_static/install_details.h" 16 #include "chrome/install_static/install_details.h"
16 #include "chrome/install_static/install_modes.h" 17 #include "chrome/install_static/install_modes.h"
18 #include "chrome/install_static/policy_path_parser.h"
17 #include "chrome_elf/nt_registry/nt_registry.h" 19 #include "chrome_elf/nt_registry/nt_registry.h"
18 20
19 namespace install_static { 21 namespace install_static {
20 22
21 ProcessType g_process_type = ProcessType::UNINITIALIZED; 23 ProcessType g_process_type = ProcessType::UNINITIALIZED;
22 24
23 const wchar_t kRegValueChromeStatsSample[] = L"UsageStatsInSample"; 25 const wchar_t kRegValueChromeStatsSample[] = L"UsageStatsInSample";
24 26
25 // TODO(ananta) 27 // TODO(ananta)
26 // http://crbug.com/604923 28 // http://crbug.com/604923
27 // The constants defined in this file are also defined in chrome/installer and 29 // The constants defined in this file are also defined in chrome/installer and
28 // other places. we need to unify them. 30 // other places. we need to unify them.
29 const wchar_t kHeadless[] = L"CHROME_HEADLESS"; 31 const wchar_t kHeadless[] = L"CHROME_HEADLESS";
30 const wchar_t kShowRestart[] = L"CHROME_CRASHED"; 32 const wchar_t kShowRestart[] = L"CHROME_CRASHED";
31 const wchar_t kRestartInfo[] = L"CHROME_RESTART"; 33 const wchar_t kRestartInfo[] = L"CHROME_RESTART";
32 const wchar_t kRtlLocale[] = L"RIGHT_TO_LEFT"; 34 const wchar_t kRtlLocale[] = L"RIGHT_TO_LEFT";
33 35
34 const char kGpuProcess[] = "gpu-process"; 36 const wchar_t kCrashpadHandler[] = L"crashpad-handler";
35 const char kPpapiPluginProcess[] = "ppapi"; 37 const wchar_t kProcessType[] = L"type";
36 const char kRendererProcess[] = "renderer"; 38 const wchar_t kUserDataDirSwitch[] = L"user-data-dir";
37 const char kUtilityProcess[] = "utility"; 39 const wchar_t kUtilityProcess[] = L"utility";
38 const char kProcessType[] = "type"; 40
39 const char kCrashpadHandler[] = "crashpad-handler"; 41 #if defined(GOOGLE_CHROME_BUILD)
42 const wchar_t kRegistryChromePolicyKey[] =
grt (UTC plus 2) 2016/11/21 10:29:54 please follow the strategy in ReportingIsEnforcedB
scottmg 2016/11/21 19:34:01 Done.
43 L"SOFTWARE\\Policies\\Google\\Chrome";
44 #else
45 const wchar_t kRegistryChromePolicyKey[] =
46 L"SOFTWARE\\Policies\\Chromium";
47 #endif
48 const wchar_t kUserDataDirRegKey[] = L"UserDataDir";
40 49
41 namespace { 50 namespace {
42 51
43 // TODO(ananta) 52 // TODO(ananta)
44 // http://crbug.com/604923 53 // http://crbug.com/604923
45 // The constants defined in this file are also defined in chrome/installer and 54 // The constants defined in this file are also defined in chrome/installer and
46 // other places. we need to unify them. 55 // other places. we need to unify them.
47 // Chrome channel display names. 56 // Chrome channel display names.
48 constexpr wchar_t kChromeChannelDev[] = L"dev"; 57 constexpr wchar_t kChromeChannelDev[] = L"dev";
49 constexpr wchar_t kChromeChannelBeta[] = L"beta"; 58 constexpr wchar_t kChromeChannelBeta[] = L"beta";
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
144 uint32_t size = 0; 153 uint32_t size = 0;
145 BOOL r = ::VerQueryValueW(version_resource, sub_block, &value, &size); 154 BOOL r = ::VerQueryValueW(version_resource, sub_block, &value, &size);
146 if (r && value) { 155 if (r && value) {
147 value_str->assign(static_cast<wchar_t*>(value)); 156 value_str->assign(static_cast<wchar_t*>(value));
148 return true; 157 return true;
149 } 158 }
150 } 159 }
151 return false; 160 return false;
152 } 161 }
153 162
163 std::wstring MakeAbsoluteFilePath(const std::wstring& input) {
164 wchar_t file_path[MAX_PATH];
165 if (!_wfullpath(file_path, input.c_str(), _countof(file_path)))
166 return std::wstring();
167 return file_path;
168 }
169
170 bool DirectoryExists(const std::wstring& path) {
171 DWORD file_attributes = ::GetFileAttributes(path.c_str());
172 if (file_attributes == INVALID_FILE_ATTRIBUTES)
173 return false;
174 return (file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
175 }
176
154 bool RecursiveDirectoryCreate(const std::wstring& full_path) { 177 bool RecursiveDirectoryCreate(const std::wstring& full_path) {
155 // If the path exists, we've succeeded if it's a directory, failed otherwise. 178 // If the path exists, we've succeeded if it's a directory, failed otherwise.
156 const wchar_t* full_path_str = full_path.c_str(); 179 const wchar_t* full_path_str = full_path.c_str();
157 DWORD file_attributes = ::GetFileAttributes(full_path_str); 180 DWORD file_attributes = ::GetFileAttributes(full_path_str);
158 if (file_attributes != INVALID_FILE_ATTRIBUTES) { 181 if (file_attributes != INVALID_FILE_ATTRIBUTES) {
159 if ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { 182 if ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
160 Trace(L"%hs( %ls directory exists )\n", __func__, full_path_str); 183 Trace(L"%hs( %ls directory exists )\n", __func__, full_path_str);
161 return true; 184 return true;
162 } 185 }
163 Trace(L"%hs( %ls directory conflicts with an existing file. )\n", __func__, 186 Trace(L"%hs( %ls directory conflicts with an existing file. )\n", __func__,
(...skipping 10 matching lines...) Expand all
174 std::size_t pos = full_path.find_last_of(L"/\\"); 197 std::size_t pos = full_path.find_last_of(L"/\\");
175 if (pos != std::wstring::npos) { 198 if (pos != std::wstring::npos) {
176 parent_path = full_path.substr(0, pos); 199 parent_path = full_path.substr(0, pos);
177 if (!RecursiveDirectoryCreate(parent_path)) { 200 if (!RecursiveDirectoryCreate(parent_path)) {
178 Trace(L"Failed to create one of the parent directories"); 201 Trace(L"Failed to create one of the parent directories");
179 return false; 202 return false;
180 } 203 }
181 } 204 }
182 if (!::CreateDirectory(full_path_str, nullptr)) { 205 if (!::CreateDirectory(full_path_str, nullptr)) {
183 DWORD error_code = ::GetLastError(); 206 DWORD error_code = ::GetLastError();
184 if (error_code == ERROR_ALREADY_EXISTS) { 207 if (error_code == ERROR_ALREADY_EXISTS && DirectoryExists(full_path_str)) {
185 DWORD file_attributes = ::GetFileAttributes(full_path_str); 208 // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we
186 if ((file_attributes != INVALID_FILE_ATTRIBUTES) && 209 // were racing with someone creating the same directory, or a file
187 ((file_attributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) { 210 // with the same path. If the directory exists, we lost the
188 // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we 211 // race to create the same directory.
189 // were racing with someone creating the same directory, or a file 212 return true;
190 // with the same path. If the directory exists, we lost the 213 } else {
191 // race to create the same directory. 214 Trace(L"Failed to create directory %ls, last error is %d\n",
192 return true; 215 full_path_str, error_code);
193 } else { 216 return false;
194 Trace(L"Failed to create directory %ls, last error is %d\n",
195 full_path_str, error_code);
196 return false;
197 }
198 } 217 }
199 } 218 }
200 return true; 219 return true;
201 } 220 }
202 221
203 // Appends "[kCompanyPathName\]kProductPathName[install_suffix]" to |path|, 222 // Appends "[kCompanyPathName\]kProductPathName[install_suffix]" to |path|,
204 // returning a reference to |path|. 223 // returning a reference to |path|.
205 std::wstring& AppendChromeInstallSubDirectory(std::wstring* path, 224 std::wstring& AppendChromeInstallSubDirectory(std::wstring* path,
206 bool include_suffix) { 225 bool include_suffix) {
207 if (*kCompanyPathName) { 226 if (*kCompanyPathName) {
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 // rules in the update configs. ChannelInfo::GetChannelName painstakingly 371 // rules in the update configs. ChannelInfo::GetChannelName painstakingly
353 // strips off known modifiers (e.g., "-multi-full") to see if the empty string 372 // strips off known modifiers (e.g., "-multi-full") to see if the empty string
354 // remains, returning channel "unknown" if not. This differs here in that some 373 // remains, returning channel "unknown" if not. This differs here in that some
355 // clients will tag crashes as "stable" rather than "unknown" via this 374 // clients will tag crashes as "stable" rather than "unknown" via this
356 // codepath, but it is an accurate reflection of which update channel the 375 // codepath, but it is an accurate reflection of which update channel the
357 // client is on according to the server-side rules. 376 // client is on according to the server-side rules.
358 377
359 return channel_name; 378 return channel_name;
360 } 379 }
361 380
381 // Checks if the key exists in the given hive and expands any string variables.
382 bool LoadUserDataDirPolicyFromRegistry(nt::ROOT_KEY hive,
383 const wchar_t* key_name,
384 std::wstring* dir) {
385 std::wstring value;
386 bool result = false;
387 HANDLE key;
388 if (nt::OpenRegKey(hive, kRegistryChromePolicyKey, KEY_READ, &key, nullptr)) {
grt (UTC plus 2) 2016/11/21 10:29:54 nit: if (nt::QueryRegValueSZ(hive, nt::NONE, pol
scottmg 2016/11/21 19:34:01 Done.
389 if (nt::QueryRegValueSZ(key, key_name, &value)) {
390 *dir = install_static::ExpandPathVariables(value);
grt (UTC plus 2) 2016/11/21 10:29:54 nit: omit "install_static::"
scottmg 2016/11/21 19:34:00 Done.
391 result = true;
392 }
393 nt::CloseRegKey(key);
394 }
395 return result;
396 }
397
398 void CheckUserDataDirPolicy(std::wstring* user_data_dir) {
grt (UTC plus 2) 2016/11/21 10:29:54 please document this. the caller assumes that |use
scottmg 2016/11/21 19:34:00 Done.
399 assert(user_data_dir);
400 // Policy from the HKLM hive has precedence over HKCU.
grt (UTC plus 2) 2016/11/21 10:29:54 i don't think it would be a bad thing for this to
scottmg 2016/11/21 19:34:01 Done.
401 if (!LoadUserDataDirPolicyFromRegistry(nt::HKLM, kUserDataDirRegKey,
402 user_data_dir)) {
403 LoadUserDataDirPolicyFromRegistry(nt::HKCU, kUserDataDirRegKey,
404 user_data_dir);
405 }
406 }
407
362 } // namespace 408 } // namespace
363 409
364 bool IsSystemInstall() { 410 bool IsSystemInstall() {
365 return InstallDetails::Get().system_level(); 411 return InstallDetails::Get().system_level();
366 } 412 }
367 413
368 bool IsMultiInstall() { 414 bool IsMultiInstall() {
369 return InstallDetails::Get().multi_install(); 415 return InstallDetails::Get().multi_install();
370 } 416 }
371 417
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
492 538
493 result->swap(user_data_dir); 539 result->swap(user_data_dir);
494 if ((*result)[result->length() - 1] != L'\\') 540 if ((*result)[result->length() - 1] != L'\\')
495 result->push_back(L'\\'); 541 result->push_back(L'\\');
496 AppendChromeInstallSubDirectory(result, true /* include_suffix */); 542 AppendChromeInstallSubDirectory(result, true /* include_suffix */);
497 result->push_back(L'\\'); 543 result->push_back(L'\\');
498 result->append(kUserDataDirname); 544 result->append(kUserDataDirname);
499 return true; 545 return true;
500 } 546 }
501 547
502 bool GetDefaultCrashDumpLocation(std::wstring* crash_dir) { 548 bool GetUserDataDirectory(const std::wstring& user_data_dir_from_command_line,
grt (UTC plus 2) 2016/11/21 10:29:54 if i'm not mistaken, the only codepath for GetUser
scottmg 2016/11/21 19:34:00 Done. It's bit ugly to have to pass the partial In
503 // In order to be able to start crash handling very early, we do not rely on 549 std::wstring* result,
504 // chrome's PathService entries (for DIR_CRASH_DUMPS) being available on 550 std::wstring* invalid_supplied_directory) {
505 // Windows. See https://crbug.com/564398. 551 std::wstring user_data_dir = user_data_dir_from_command_line;
506 if (!GetDefaultUserDataDirectory(crash_dir)) 552
553 CheckUserDataDirPolicy(&user_data_dir);
554
555 // On Windows, trailing separators leave Chrome in a bad state. See
556 // crbug.com/464616.
557 while (!user_data_dir.empty() &&
558 (user_data_dir.back() == '\\' || user_data_dir.back() == '/')) {
559 user_data_dir.pop_back();
560 }
561
562 bool got_valid_directory =
563 !user_data_dir.empty() && RecursiveDirectoryCreate(user_data_dir);
564 if (!got_valid_directory) {
565 *invalid_supplied_directory = user_data_dir;
566 got_valid_directory = GetDefaultUserDataDirectory(&user_data_dir);
567 }
568
569 // The Chrome implementation CHECKs() here in the browser process. We
570 // don't as this function is used to initialize crash reporting, so
571 // we would get no report of this failure.
572 assert(got_valid_directory);
573 if (!got_valid_directory)
507 return false; 574 return false;
508 575
509 // We have to make sure the user data dir exists on first run. See 576 *result = MakeAbsoluteFilePath(user_data_dir);
510 // http://crbug.com/591504. 577 return true;
511 if (!RecursiveDirectoryCreate(*crash_dir)) 578 }
512 return false; 579
580 bool GetUserDataDirectoryUsingProcessCommandLine(
581 std::wstring* result,
582 std::wstring* invalid_supplied_directory) {
583 return GetUserDataDirectory(
584 GetSwitchValueFromCommandLine(::GetCommandLine(),
585 install_static::kUserDataDirSwitch),
grt (UTC plus 2) 2016/11/21 10:29:54 nit: omit "install_static::"
scottmg 2016/11/21 19:34:01 Done.
586 result, invalid_supplied_directory);
587 }
588
589 bool GetCrashDumpLocation(std::wstring* crash_dir) {
590 // In order to be able to start crash handling very early and in chrome_elf,
591 // we cannot rely on chrome's PathService entries (for DIR_CRASH_DUMPS) being
592 // available on Windows. See https://crbug.com/564398.
593 *crash_dir = install_static::InstallDetails::Get().user_data_dir();
grt (UTC plus 2) 2016/11/21 10:29:54 nit: omit "install_static::"
scottmg 2016/11/21 19:34:00 Done.
513 crash_dir->append(L"\\Crashpad"); 594 crash_dir->append(L"\\Crashpad");
514 return true; 595 return true;
515 } 596 }
516 597
517 std::string GetEnvironmentString(const std::string& variable_name) { 598 std::string GetEnvironmentString(const std::string& variable_name) {
518 return UTF16ToUTF8( 599 return UTF16ToUTF8(
519 GetEnvironmentString16(UTF8ToUTF16(variable_name).c_str())); 600 GetEnvironmentString16(UTF8ToUTF16(variable_name).c_str()));
520 } 601 }
521 602
522 std::wstring GetEnvironmentString16(const wchar_t* variable_name) { 603 std::wstring GetEnvironmentString16(const wchar_t* variable_name) {
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
644 bool trim_spaces) { 725 bool trim_spaces) {
645 return TokenizeStringT<std::string>(str, delimiter, trim_spaces); 726 return TokenizeStringT<std::string>(str, delimiter, trim_spaces);
646 } 727 }
647 728
648 std::vector<std::wstring> TokenizeString16(const std::wstring& str, 729 std::vector<std::wstring> TokenizeString16(const std::wstring& str,
649 wchar_t delimiter, 730 wchar_t delimiter,
650 bool trim_spaces) { 731 bool trim_spaces) {
651 return TokenizeStringT<std::wstring>(str, delimiter, trim_spaces); 732 return TokenizeStringT<std::wstring>(str, delimiter, trim_spaces);
652 } 733 }
653 734
654 std::string GetSwitchValueFromCommandLine(const std::string& command_line, 735 std::wstring GetSwitchValueFromCommandLine(const std::wstring& command_line,
655 const std::string& switch_name) { 736 const std::wstring& switch_name) {
656 assert(!command_line.empty()); 737 assert(!command_line.empty());
657 assert(!switch_name.empty()); 738 assert(!switch_name.empty());
658 739
659 std::string command_line_copy = command_line; 740 std::wstring command_line_copy = command_line;
660 // Remove leading and trailing spaces. 741 // Remove leading and trailing spaces.
661 TrimT<std::string>(&command_line_copy); 742 TrimT<std::wstring>(&command_line_copy);
662 743
663 // Find the switch in the command line. If we don't find the switch, return 744 // Find the switch in the command line. If we don't find the switch, return
664 // an empty string. 745 // an empty string.
665 std::string switch_token = "--"; 746 std::wstring switch_token = L"--";
666 switch_token += switch_name; 747 switch_token += switch_name;
667 switch_token += "="; 748 switch_token += L"=";
668 size_t switch_offset = command_line_copy.find(switch_token); 749 size_t switch_offset = command_line_copy.find(switch_token);
669 if (switch_offset == std::string::npos) 750 if (switch_offset == std::string::npos)
670 return std::string(); 751 return std::wstring();
671 752
672 // The format is "--<switch name>=blah". Look for a space after the 753 // The format is "--<switch name>=blah". Look for a space after the
673 // "--<switch name>=" string. If we don't find a space assume that the switch 754 // "--<switch name>=" string. If we don't find a space assume that the switch
674 // value ends at the end of the command line. 755 // value ends at the end of the command line.
675 size_t switch_value_start_offset = switch_offset + switch_token.length(); 756 size_t switch_value_start_offset = switch_offset + switch_token.length();
676 if (std::string(kWhiteSpaces).find( 757 if (std::wstring(kWhiteSpaces16).find(
677 command_line_copy[switch_value_start_offset]) != std::string::npos) { 758 command_line_copy[switch_value_start_offset]) != std::wstring::npos) {
678 switch_value_start_offset = command_line_copy.find_first_not_of( 759 switch_value_start_offset = command_line_copy.find_first_not_of(
679 GetWhiteSpacesForType<std::string>(), switch_value_start_offset); 760 GetWhiteSpacesForType<std::wstring>(), switch_value_start_offset);
680 if (switch_value_start_offset == std::string::npos) 761 if (switch_value_start_offset == std::wstring::npos)
681 return std::string(); 762 return std::wstring();
682 } 763 }
683 size_t switch_value_end_offset = 764 size_t switch_value_end_offset =
684 command_line_copy.find_first_of(GetWhiteSpacesForType<std::string>(), 765 command_line_copy.find_first_of(GetWhiteSpacesForType<std::wstring>(),
685 switch_value_start_offset); 766 switch_value_start_offset);
686 if (switch_value_end_offset == std::string::npos) 767 if (switch_value_end_offset == std::wstring::npos)
687 switch_value_end_offset = command_line_copy.length(); 768 switch_value_end_offset = command_line_copy.length();
688 769
689 std::string switch_value = command_line_copy.substr( 770 std::wstring switch_value = command_line_copy.substr(
690 switch_value_start_offset, 771 switch_value_start_offset,
691 switch_value_end_offset - (switch_offset + switch_token.length())); 772 switch_value_end_offset - (switch_offset + switch_token.length()));
692 TrimT<std::string>(&switch_value); 773 TrimT<std::wstring>(&switch_value);
693 return switch_value; 774 return switch_value;
694 } 775 }
695 776
696 // This function takes these inputs rather than accessing the module's 777 // This function takes these inputs rather than accessing the module's
697 // InstallDetails instance since it is used to bootstrap InstallDetails. 778 // InstallDetails instance since it is used to bootstrap InstallDetails.
698 std::wstring DetermineChannel(const InstallConstants& mode, 779 std::wstring DetermineChannel(const InstallConstants& mode,
699 bool system_level, 780 bool system_level,
700 bool multi_install) { 781 bool multi_install) {
701 if (!kUseGoogleUpdateIntegration) 782 if (!kUseGoogleUpdateIntegration)
702 return std::wstring(); 783 return std::wstring();
703 784
704 switch (mode.channel_strategy) { 785 switch (mode.channel_strategy) {
705 case ChannelStrategy::UNSUPPORTED: 786 case ChannelStrategy::UNSUPPORTED:
706 assert(false); 787 assert(false);
707 break; 788 break;
708 case ChannelStrategy::ADDITIONAL_PARAMETERS: 789 case ChannelStrategy::ADDITIONAL_PARAMETERS:
709 return ChannelFromAdditionalParameters(mode, system_level, multi_install); 790 return ChannelFromAdditionalParameters(mode, system_level, multi_install);
710 case ChannelStrategy::FIXED: 791 case ChannelStrategy::FIXED:
711 return mode.default_channel_name; 792 return mode.default_channel_name;
712 } 793 }
713 794
714 return std::wstring(); 795 return std::wstring();
715 } 796 }
716 797
717 } // namespace install_static 798 } // namespace install_static
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698