Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 369 std::vector<StringType> tokens; | 377 std::vector<StringType> tokens; |
| 370 std::basic_istringstream<typename StringType::value_type> buffer(str); | 378 std::basic_istringstream<typename StringType::value_type> buffer(str); |
| 371 for (StringType token; std::getline(buffer, token, delimiter);) { | 379 for (StringType token; std::getline(buffer, token, delimiter);) { |
| 372 if (trim_spaces) | 380 if (trim_spaces) |
| 373 TrimT<StringType>(&token); | 381 TrimT<StringType>(&token); |
| 374 tokens.push_back(token); | 382 tokens.push_back(token); |
| 375 } | 383 } |
| 376 return tokens; | 384 return tokens; |
| 377 } | 385 } |
| 378 | 386 |
| 387 // Checks if the key exists in the given hive and expands any string variables. | |
| 388 bool LoadUserDataDirPolicyFromRegistry(nt::ROOT_KEY hive, | |
| 389 const wchar_t* key_name, | |
| 390 std::wstring* dir) { | |
| 391 std::wstring value; | |
| 392 bool result = false; | |
| 393 HANDLE key; | |
| 394 if (nt::OpenRegKey(hive, kRegistryChromePolicyKey, KEY_READ, &key, nullptr)) { | |
| 395 if (nt::QueryRegValueSZ(key, key_name, &value)) { | |
| 396 *dir = install_static::ExpandPathVariables(value); | |
| 397 result = true; | |
| 398 } | |
| 399 nt::CloseRegKey(key); | |
|
Mark Mentovai
2016/11/10 22:06:17
I’m surprised that OpenRegKey doesn’t return a key
scottmg
2016/11/15 23:23:15
Agreed. Filed https://bugs.chromium.org/p/chromium
| |
| 400 } | |
| 401 return result; | |
| 402 } | |
| 403 | |
| 404 void CheckUserDataDirPolicy(std::wstring* user_data_dir) { | |
| 405 assert(user_data_dir); | |
| 406 // Policy from the HKLM hive has precedence over HKCU. | |
| 407 if (!LoadUserDataDirPolicyFromRegistry(nt::HKLM, kUserDataDirRegKey, | |
| 408 user_data_dir)) { | |
| 409 LoadUserDataDirPolicyFromRegistry(nt::HKCU, kUserDataDirRegKey, | |
| 410 user_data_dir); | |
| 411 } | |
| 412 } | |
| 413 | |
| 379 } // namespace | 414 } // namespace |
| 380 | 415 |
| 381 bool IsSxSChrome(const wchar_t* exe_path) { | 416 bool IsSxSChrome(const wchar_t* exe_path) { |
| 382 return ::wcsstr(exe_path, L"Chrome SxS\\Application") != nullptr; | 417 return ::wcsstr(exe_path, L"Chrome SxS\\Application") != nullptr; |
| 383 } | 418 } |
| 384 | 419 |
| 385 bool IsSystemInstall(const wchar_t* exe_path) { | 420 bool IsSystemInstall(const wchar_t* exe_path) { |
| 386 wchar_t program_dir[MAX_PATH] = {}; | 421 wchar_t program_dir[MAX_PATH] = {}; |
| 387 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, MAX_PATH); | 422 DWORD ret = ::GetEnvironmentVariable(L"PROGRAMFILES", program_dir, MAX_PATH); |
| 388 if (ret && ret < MAX_PATH && !::wcsnicmp(exe_path, program_dir, ret)) { | 423 if (ret && ret < MAX_PATH && !::wcsnicmp(exe_path, program_dir, ret)) { |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 489 } | 524 } |
| 490 | 525 |
| 491 bool IsNonBrowserProcess() { | 526 bool IsNonBrowserProcess() { |
| 492 assert(g_process_type != ProcessType::UNINITIALIZED); | 527 assert(g_process_type != ProcessType::UNINITIALIZED); |
| 493 return g_process_type == ProcessType::NON_BROWSER_PROCESS; | 528 return g_process_type == ProcessType::NON_BROWSER_PROCESS; |
| 494 } | 529 } |
| 495 | 530 |
| 496 bool GetDefaultUserDataDirectory(std::wstring* result) { | 531 bool GetDefaultUserDataDirectory(std::wstring* result) { |
| 497 static const wchar_t kLocalAppData[] = L"%LOCALAPPDATA%"; | 532 static const wchar_t kLocalAppData[] = L"%LOCALAPPDATA%"; |
| 498 | 533 |
| 499 std::unique_ptr<wchar_t> user_data_dir_path; | 534 std::unique_ptr<wchar_t> user_data_dir_path; |
|
Mark Mentovai
2016/11/10 22:06:17
This gets a new wchar_t[], so it should be a uniqu
scottmg
2016/11/15 23:23:15
Done.
| |
| 500 | 535 |
| 501 // This environment variable should be set on Windows 7 and up. | 536 // 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 | 537 // If we fail to find this variable then we default to the temporary files |
| 503 // path. | 538 // path. |
| 504 DWORD size = ::ExpandEnvironmentStrings(kLocalAppData, nullptr, 0); | 539 DWORD size = ::ExpandEnvironmentStrings(kLocalAppData, nullptr, 0); |
| 505 if (size) { | 540 if (size) { |
| 506 user_data_dir_path.reset(new wchar_t[size]); | 541 user_data_dir_path.reset(new wchar_t[size]); |
| 507 if (::ExpandEnvironmentStrings(kLocalAppData, user_data_dir_path.get(), | 542 if (::ExpandEnvironmentStrings(kLocalAppData, user_data_dir_path.get(), |
| 508 size) != size) { | 543 size) != size) { |
| 509 user_data_dir_path.reset(); | 544 user_data_dir_path.reset(); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 524 | 559 |
| 525 *result = user_data_dir_path.get(); | 560 *result = user_data_dir_path.get(); |
| 526 if ((*result)[result->length() - 1] != L'\\') | 561 if ((*result)[result->length() - 1] != L'\\') |
| 527 result->append(L"\\"); | 562 result->append(L"\\"); |
| 528 result->append(install_sub_directory); | 563 result->append(install_sub_directory); |
| 529 result->append(L"\\"); | 564 result->append(L"\\"); |
| 530 result->append(kUserDataDirname); | 565 result->append(kUserDataDirname); |
| 531 return true; | 566 return true; |
| 532 } | 567 } |
| 533 | 568 |
| 534 bool GetDefaultCrashDumpLocation(std::wstring* crash_dir) { | 569 bool GetUserDataDirectory(std::wstring* result) { |
| 535 // In order to be able to start crash handling very early, we do not rely on | 570 // WARNING! This has to mirror the logic in chrome/app/chrome_main_delegate.cc |
| 536 // chrome's PathService entries (for DIR_CRASH_DUMPS) being available on | 571 // in InitializeUserDataDir(). This function derives the path in the same way, |
| 537 // Windows. See https://crbug.com/564398. | 572 // but without using base, nor reporting on failure as the Chrome |
| 538 if (!GetDefaultUserDataDirectory(crash_dir)) | 573 // implementation does. |
| 574 std::wstring user_data_dir = GetSwitchValueFromCommandLine( | |
| 575 ::GetCommandLine(), install_static::kUserDataDirSwitch); | |
| 576 | |
| 577 CheckUserDataDirPolicy(&user_data_dir); | |
| 578 | |
| 579 // On Windows, trailing separators leave Chrome in a bad state. See | |
| 580 // crbug.com/464616. | |
| 581 while (!user_data_dir.empty() && | |
| 582 (user_data_dir.back() == '\\' || user_data_dir.back() == '/')) { | |
| 583 user_data_dir = user_data_dir.substr(0, user_data_dir.size() - 1); | |
|
Mark Mentovai
2016/11/10 22:06:17
If C++11 is guaranteed (and it’s 2016, it should b
scottmg
2016/11/15 23:23:15
Done.
| |
| 584 } | |
| 585 | |
| 586 const bool specified_directory_was_invalid = | |
|
Mark Mentovai
2016/11/10 22:06:17
This says: If user_data_dir is empty, stop and set
scottmg
2016/11/11 00:24:46
Yeah, you're right. I just copied and adapted the
scottmg
2016/11/15 23:23:15
I think the behaviour is semi-rational now.
| |
| 587 !user_data_dir.empty() && !RecursiveDirectoryCreate(user_data_dir); | |
| 588 | |
| 589 if (specified_directory_was_invalid) { | |
| 590 if (!GetDefaultUserDataDirectory(&user_data_dir)) { | |
|
Mark Mentovai
2016/11/10 22:06:17
This can be folded into the if that contains it.
scottmg
2016/11/15 23:23:15
Done.
| |
| 591 // The Chrome implementation CHECKs() here in the browser process. We | |
| 592 // don't as this function is used to initialize crash reporting, so | |
| 593 // we would get no report of this failure. | |
| 594 assert(false); | |
| 595 return false; | |
| 596 } | |
| 597 } | |
| 598 | |
| 599 *result = user_data_dir; | |
| 600 return true; | |
| 601 } | |
| 602 | |
| 603 bool GetCrashDumpLocation(std::wstring* crash_dir) { | |
| 604 // In order to be able to start crash handling very early and in chrome_elf, | |
| 605 // we cannot rely on chrome's PathService entries (for DIR_CRASH_DUMPS) being | |
| 606 // available on Windows. See https://crbug.com/564398. | |
| 607 if (!GetUserDataDirectory(crash_dir)) | |
| 539 return false; | 608 return false; |
| 540 | 609 |
| 541 // We have to make sure the user data dir exists on first run. See | 610 // We have to make sure the user data dir exists on first run. See |
| 542 // http://crbug.com/591504. | 611 // http://crbug.com/591504. |
| 543 if (!RecursiveDirectoryCreate(crash_dir->c_str())) | 612 if (!RecursiveDirectoryCreate(crash_dir->c_str())) |
| 544 return false; | 613 return false; |
| 545 crash_dir->append(L"\\Crashpad"); | 614 crash_dir->append(L"\\Crashpad"); |
| 546 return true; | 615 return true; |
| 547 } | 616 } |
| 548 | 617 |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 837 *result = -1; | 906 *result = -1; |
| 838 return true; | 907 return true; |
| 839 } | 908 } |
| 840 } | 909 } |
| 841 } | 910 } |
| 842 // Here it means that both versions are equal. | 911 // Here it means that both versions are equal. |
| 843 *result = 0; | 912 *result = 0; |
| 844 return true; | 913 return true; |
| 845 } | 914 } |
| 846 | 915 |
| 847 std::string GetSwitchValueFromCommandLine(const std::string& command_line, | 916 std::wstring GetSwitchValueFromCommandLine(const std::wstring& command_line, |
| 848 const std::string& switch_name) { | 917 const std::wstring& switch_name) { |
| 849 assert(!command_line.empty()); | 918 assert(!command_line.empty()); |
| 850 assert(!switch_name.empty()); | 919 assert(!switch_name.empty()); |
| 851 | 920 |
| 852 std::string command_line_copy = command_line; | 921 std::wstring command_line_copy = command_line; |
| 853 // Remove leading and trailing spaces. | 922 // Remove leading and trailing spaces. |
| 854 TrimT<std::string>(&command_line_copy); | 923 TrimT<std::wstring>(&command_line_copy); |
| 855 | 924 |
| 856 // Find the switch in the command line. If we don't find the switch, return | 925 // Find the switch in the command line. If we don't find the switch, return |
| 857 // an empty string. | 926 // an empty string. |
| 858 std::string switch_token = "--"; | 927 std::wstring switch_token = L"--"; |
| 859 switch_token += switch_name; | 928 switch_token += switch_name; |
| 860 switch_token += "="; | 929 switch_token += L"="; |
| 861 size_t switch_offset = command_line_copy.find(switch_token); | 930 size_t switch_offset = command_line_copy.find(switch_token); |
| 862 if (switch_offset == std::string::npos) | 931 if (switch_offset == std::string::npos) |
| 863 return std::string(); | 932 return std::wstring(); |
| 864 | 933 |
| 865 // The format is "--<switch name>=blah". Look for a space after the | 934 // 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 | 935 // "--<switch name>=" string. If we don't find a space assume that the switch |
| 867 // value ends at the end of the command line. | 936 // value ends at the end of the command line. |
| 868 size_t switch_value_start_offset = switch_offset + switch_token.length(); | 937 size_t switch_value_start_offset = switch_offset + switch_token.length(); |
| 869 if (std::string(kWhiteSpaces).find( | 938 if (std::wstring(kWhiteSpaces16).find( |
| 870 command_line_copy[switch_value_start_offset]) != std::string::npos) { | 939 command_line_copy[switch_value_start_offset]) != std::wstring::npos) { |
| 871 switch_value_start_offset = command_line_copy.find_first_not_of( | 940 switch_value_start_offset = command_line_copy.find_first_not_of( |
| 872 GetWhiteSpacesForType<std::string>(), switch_value_start_offset); | 941 GetWhiteSpacesForType<std::wstring>(), switch_value_start_offset); |
| 873 if (switch_value_start_offset == std::string::npos) | 942 if (switch_value_start_offset == std::wstring::npos) |
| 874 return std::string(); | 943 return std::wstring(); |
| 875 } | 944 } |
| 876 size_t switch_value_end_offset = | 945 size_t switch_value_end_offset = |
| 877 command_line_copy.find_first_of(GetWhiteSpacesForType<std::string>(), | 946 command_line_copy.find_first_of(GetWhiteSpacesForType<std::wstring>(), |
| 878 switch_value_start_offset); | 947 switch_value_start_offset); |
| 879 if (switch_value_end_offset == std::string::npos) | 948 if (switch_value_end_offset == std::wstring::npos) |
| 880 switch_value_end_offset = command_line_copy.length(); | 949 switch_value_end_offset = command_line_copy.length(); |
| 881 | 950 |
| 882 std::string switch_value = command_line_copy.substr( | 951 std::wstring switch_value = command_line_copy.substr( |
| 883 switch_value_start_offset, | 952 switch_value_start_offset, |
| 884 switch_value_end_offset - (switch_offset + switch_token.length())); | 953 switch_value_end_offset - (switch_offset + switch_token.length())); |
| 885 TrimT<std::string>(&switch_value); | 954 TrimT<std::wstring>(&switch_value); |
| 886 return switch_value; | 955 return switch_value; |
| 887 } | 956 } |
| 888 | 957 |
| 889 } // namespace install_static | 958 } // namespace install_static |
| OLD | NEW |