OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 // This file defines functions that integrate Chrome in Windows shell. These | 5 // This file defines functions that integrate Chrome in Windows shell. These |
6 // functions can be used by Chrome as well as Chrome installer. All of the | 6 // functions can be used by Chrome as well as Chrome installer. All of the |
7 // work is done by the local functions defined in anonymous namespace in | 7 // work is done by the local functions defined in anonymous namespace in |
8 // this class. | 8 // this class. |
9 | 9 |
10 #include "chrome/installer/util/shell_util.h" | 10 #include "chrome/installer/util/shell_util.h" |
(...skipping 10 matching lines...) Expand all Loading... | |
21 #include "base/memory/scoped_ptr.h" | 21 #include "base/memory/scoped_ptr.h" |
22 #include "base/path_service.h" | 22 #include "base/path_service.h" |
23 #include "base/stl_util.h" | 23 #include "base/stl_util.h" |
24 #include "base/string_number_conversions.h" | 24 #include "base/string_number_conversions.h" |
25 #include "base/string_split.h" | 25 #include "base/string_split.h" |
26 #include "base/string_util.h" | 26 #include "base/string_util.h" |
27 #include "base/utf_string_conversions.h" | 27 #include "base/utf_string_conversions.h" |
28 #include "base/values.h" | 28 #include "base/values.h" |
29 #include "base/win/registry.h" | 29 #include "base/win/registry.h" |
30 #include "base/win/scoped_comptr.h" | 30 #include "base/win/scoped_comptr.h" |
31 #include "base/win/win_util.h" | |
31 #include "base/win/windows_version.h" | 32 #include "base/win/windows_version.h" |
32 #include "chrome/common/chrome_constants.h" | 33 #include "chrome/common/chrome_constants.h" |
33 #include "chrome/common/chrome_switches.h" | 34 #include "chrome/common/chrome_switches.h" |
34 #include "chrome/installer/util/browser_distribution.h" | 35 #include "chrome/installer/util/browser_distribution.h" |
35 #include "chrome/installer/util/install_util.h" | 36 #include "chrome/installer/util/install_util.h" |
36 #include "chrome/installer/util/master_preferences.h" | 37 #include "chrome/installer/util/master_preferences.h" |
37 #include "chrome/installer/util/master_preferences_constants.h" | 38 #include "chrome/installer/util/master_preferences_constants.h" |
38 | 39 |
39 using base::win::RegKey; | 40 using base::win::RegKey; |
40 | 41 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
78 VER_SET_CONDITION(condition_mask, VER_BUILDNUMBER, VER_GREATER_EQUAL); | 79 VER_SET_CONDITION(condition_mask, VER_BUILDNUMBER, VER_GREATER_EQUAL); |
79 VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); | 80 VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); |
80 VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); | 81 VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); |
81 | 82 |
82 DWORD type_mask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER | | 83 DWORD type_mask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER | |
83 VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR; | 84 VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR; |
84 | 85 |
85 return VerifyVersionInfo(&min_version_info, type_mask, condition_mask) != 0; | 86 return VerifyVersionInfo(&min_version_info, type_mask, condition_mask) != 0; |
86 } | 87 } |
87 | 88 |
89 // Returns the current (or installed) browser's ProgId (e.g. | |
90 // "ChromeHTML|suffix|"). | |
91 // |suffix| can be the empty string. | |
92 string16 GetBrowserProgId(const string16& suffix) { | |
93 string16 chrome_html(ShellUtil::kChromeHTMLProgId); | |
94 chrome_html.append(suffix); | |
95 | |
96 // ProgIds cannot be longer than 39 characters. | |
97 // Ref: http://msdn.microsoft.com/en-us/library/aa911706.aspx. | |
98 // Make all new registrations comply with this requirement (existing | |
99 // registrations must be preserved). | |
100 // Note: since |new_style_suffix| will always be the same for this user, only | |
101 // initialize it once, re-use the derived value in subsequent calls. | |
102 static string16 new_style_suffix; | |
grt (UTC plus 2)
2012/06/27 15:47:32
this isn't threadsafe and it adds an exit-time dto
gab
2012/07/03 22:36:06
Done.
| |
103 if ((!new_style_suffix.empty() || | |
104 ShellUtil::GetNewUserSpecificRegistrySuffix(&new_style_suffix)) && | |
105 suffix.compare(new_style_suffix) == 0 && chrome_html.length() > 39) { | |
106 NOTREACHED(); | |
107 chrome_html.erase(39); | |
108 } | |
109 return chrome_html; | |
110 } | |
111 | |
88 // This class represents a single registry entry. The objective is to | 112 // This class represents a single registry entry. The objective is to |
89 // encapsulate all the registry entries required for registering Chrome at one | 113 // encapsulate all the registry entries required for registering Chrome at one |
90 // place. This class can not be instantiated outside the class and the objects | 114 // place. This class can not be instantiated outside the class and the objects |
91 // of this class type can be obtained only by calling a static method of this | 115 // of this class type can be obtained only by calling a static method of this |
92 // class. | 116 // class. |
93 class RegistryEntry { | 117 class RegistryEntry { |
94 public: | 118 public: |
95 // A bit-field enum of places to look for this key in the Windows registry. | 119 // A bit-field enum of places to look for this key in the Windows registry. |
96 enum LookForIn { | 120 enum LookForIn { |
97 LOOK_IN_HKCU = 1 << 0, | 121 LOOK_IN_HKCU = 1 << 0, |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
174 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command | 198 // <root hkey>\Software\Classes\<app_id>\.exe\shell\<verb>\command |
175 entries->push_front(new RegistryEntry(sub_path, delegate_command)); | 199 entries->push_front(new RegistryEntry(sub_path, delegate_command)); |
176 entries->push_front(new RegistryEntry( | 200 entries->push_front(new RegistryEntry( |
177 sub_path, ShellUtil::kRegDelegateExecute, delegate_guid)); | 201 sub_path, ShellUtil::kRegDelegateExecute, delegate_guid)); |
178 } | 202 } |
179 } | 203 } |
180 | 204 |
181 // File association ProgId | 205 // File association ProgId |
182 string16 chrome_html_prog_id(ShellUtil::kRegClasses); | 206 string16 chrome_html_prog_id(ShellUtil::kRegClasses); |
183 chrome_html_prog_id.push_back(FilePath::kSeparators[0]); | 207 chrome_html_prog_id.push_back(FilePath::kSeparators[0]); |
184 chrome_html_prog_id.append(ShellUtil::kChromeHTMLProgId); | 208 chrome_html_prog_id.append(GetBrowserProgId(suffix)); |
185 chrome_html_prog_id.append(suffix); | |
186 entries->push_front(new RegistryEntry( | 209 entries->push_front(new RegistryEntry( |
187 chrome_html_prog_id, ShellUtil::kChromeHTMLProgIdDesc)); | 210 chrome_html_prog_id, ShellUtil::kChromeHTMLProgIdDesc)); |
188 entries->push_front(new RegistryEntry( | 211 entries->push_front(new RegistryEntry( |
189 chrome_html_prog_id, ShellUtil::kRegUrlProtocol, L"")); | 212 chrome_html_prog_id, ShellUtil::kRegUrlProtocol, L"")); |
190 entries->push_front(new RegistryEntry( | 213 entries->push_front(new RegistryEntry( |
191 chrome_html_prog_id + ShellUtil::kRegDefaultIcon, icon_path)); | 214 chrome_html_prog_id + ShellUtil::kRegDefaultIcon, icon_path)); |
192 entries->push_front(new RegistryEntry( | 215 entries->push_front(new RegistryEntry( |
193 chrome_html_prog_id + ShellUtil::kRegShellOpen, open_cmd)); | 216 chrome_html_prog_id + ShellUtil::kRegShellOpen, open_cmd)); |
194 if (set_delegate_execute) { | 217 if (set_delegate_execute) { |
195 entries->push_front(new RegistryEntry( | 218 entries->push_front(new RegistryEntry( |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
227 } | 250 } |
228 | 251 |
229 // This method returns a list of the registry entries needed to declare a | 252 // This method returns a list of the registry entries needed to declare a |
230 // capability of handling a protocol on Windows. | 253 // capability of handling a protocol on Windows. |
231 static bool GetProtocolCapabilityEntries(BrowserDistribution* dist, | 254 static bool GetProtocolCapabilityEntries(BrowserDistribution* dist, |
232 const string16& suffix, | 255 const string16& suffix, |
233 const string16& protocol, | 256 const string16& protocol, |
234 std::list<RegistryEntry*>* entries) { | 257 std::list<RegistryEntry*>* entries) { |
235 entries->push_front(new RegistryEntry( | 258 entries->push_front(new RegistryEntry( |
236 GetCapabilitiesKey(dist, suffix).append(L"\\URLAssociations"), | 259 GetCapabilitiesKey(dist, suffix).append(L"\\URLAssociations"), |
237 protocol, string16(ShellUtil::kChromeHTMLProgId).append(suffix))); | 260 protocol, GetBrowserProgId(suffix))); |
238 return true; | 261 return true; |
239 } | 262 } |
240 | 263 |
241 // This method returns a list of all the registry entries required to fully | 264 // This method returns a list of all the registry entries required to fully |
242 // integrate Chrome with Windows (i.e. StartMenuInternet, Default Programs, | 265 // integrate Chrome with Windows (i.e. StartMenuInternet, Default Programs, |
243 // AppPaths, etc.). This entries need to be registered in HKLM prior to Win8. | 266 // AppPaths, etc.). This entries need to be registered in HKLM prior to Win8. |
244 static bool GetShellIntegrationEntries(BrowserDistribution* dist, | 267 static bool GetShellIntegrationEntries(BrowserDistribution* dist, |
245 const string16& chrome_exe, | 268 const string16& chrome_exe, |
246 const string16& suffix, | 269 const string16& suffix, |
247 std::list<RegistryEntry*>* entries) { | 270 std::list<RegistryEntry*>* entries) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
288 dist->GetLongAppDescription())); | 311 dist->GetLongAppDescription())); |
289 entries->push_front(new RegistryEntry( | 312 entries->push_front(new RegistryEntry( |
290 capabilities, ShellUtil::kRegApplicationIcon, icon_path)); | 313 capabilities, ShellUtil::kRegApplicationIcon, icon_path)); |
291 entries->push_front(new RegistryEntry( | 314 entries->push_front(new RegistryEntry( |
292 capabilities, ShellUtil::kRegApplicationName, | 315 capabilities, ShellUtil::kRegApplicationName, |
293 dist->GetAppShortCutName())); | 316 dist->GetAppShortCutName())); |
294 | 317 |
295 entries->push_front(new RegistryEntry(capabilities + L"\\Startmenu", | 318 entries->push_front(new RegistryEntry(capabilities + L"\\Startmenu", |
296 L"StartMenuInternet", reg_app_name)); | 319 L"StartMenuInternet", reg_app_name)); |
297 | 320 |
298 string16 html_prog_id(ShellUtil::kChromeHTMLProgId); | 321 string16 html_prog_id(GetBrowserProgId(suffix)); |
299 html_prog_id.append(suffix); | |
300 for (int i = 0; ShellUtil::kFileAssociations[i] != NULL; i++) { | 322 for (int i = 0; ShellUtil::kFileAssociations[i] != NULL; i++) { |
301 entries->push_front(new RegistryEntry( | 323 entries->push_front(new RegistryEntry( |
302 capabilities + L"\\FileAssociations", | 324 capabilities + L"\\FileAssociations", |
303 ShellUtil::kFileAssociations[i], html_prog_id)); | 325 ShellUtil::kFileAssociations[i], html_prog_id)); |
304 } | 326 } |
305 for (int i = 0; ShellUtil::kPotentialProtocolAssociations[i] != NULL; | 327 for (int i = 0; ShellUtil::kPotentialProtocolAssociations[i] != NULL; |
306 i++) { | 328 i++) { |
307 entries->push_front(new RegistryEntry( | 329 entries->push_front(new RegistryEntry( |
308 capabilities + L"\\URLAssociations", | 330 capabilities + L"\\URLAssociations", |
309 ShellUtil::kPotentialProtocolAssociations[i], html_prog_id)); | 331 ShellUtil::kPotentialProtocolAssociations[i], html_prog_id)); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
358 return true; | 380 return true; |
359 } | 381 } |
360 | 382 |
361 // This method returns a list of all the user level registry entries that | 383 // This method returns a list of all the user level registry entries that |
362 // are needed to make Chromium default browser. | 384 // are needed to make Chromium default browser. |
363 static bool GetUserEntries(BrowserDistribution* dist, | 385 static bool GetUserEntries(BrowserDistribution* dist, |
364 const string16& chrome_exe, | 386 const string16& chrome_exe, |
365 const string16& suffix, | 387 const string16& suffix, |
366 std::list<RegistryEntry*>* entries) { | 388 std::list<RegistryEntry*>* entries) { |
367 // File extension associations. | 389 // File extension associations. |
368 string16 html_prog_id(ShellUtil::kChromeHTMLProgId); | 390 string16 html_prog_id(GetBrowserProgId(suffix)); |
369 html_prog_id.append(suffix); | |
370 for (int i = 0; ShellUtil::kFileAssociations[i] != NULL; i++) { | 391 for (int i = 0; ShellUtil::kFileAssociations[i] != NULL; i++) { |
371 string16 ext_key(ShellUtil::kRegClasses); | 392 string16 ext_key(ShellUtil::kRegClasses); |
372 ext_key.push_back(FilePath::kSeparators[0]); | 393 ext_key.push_back(FilePath::kSeparators[0]); |
373 ext_key.append(ShellUtil::kFileAssociations[i]); | 394 ext_key.append(ShellUtil::kFileAssociations[i]); |
374 entries->push_front(new RegistryEntry(ext_key, html_prog_id)); | 395 entries->push_front(new RegistryEntry(ext_key, html_prog_id)); |
375 } | 396 } |
376 | 397 |
377 // Protocols associations. | 398 // Protocols associations. |
378 string16 chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe); | 399 string16 chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe); |
379 string16 chrome_icon = ShellUtil::GetChromeIcon(dist, chrome_exe); | 400 string16 chrome_icon = ShellUtil::GetChromeIcon(dist, chrome_exe); |
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
670 | 691 |
671 // <root hkey>\Software\Classes\<app_id> | 692 // <root hkey>\Software\Classes\<app_id> |
672 string16 key(ShellUtil::kRegClasses); | 693 string16 key(ShellUtil::kRegClasses); |
673 key.push_back(FilePath::kSeparators[0]); | 694 key.push_back(FilePath::kSeparators[0]); |
674 key.append(app_id); | 695 key.append(app_id); |
675 InstallUtil::DeleteRegistryKey(root_key, key); | 696 InstallUtil::DeleteRegistryKey(root_key, key); |
676 | 697 |
677 // <root hkey>\Software\Classes\ChromiumHTML[.user]\shell\open\command | 698 // <root hkey>\Software\Classes\ChromiumHTML[.user]\shell\open\command |
678 key = ShellUtil::kRegClasses; | 699 key = ShellUtil::kRegClasses; |
679 key.push_back(FilePath::kSeparators[0]); | 700 key.push_back(FilePath::kSeparators[0]); |
680 key.append(ShellUtil::kChromeHTMLProgId); | 701 key.append(GetBrowserProgId(installation_suffix)); |
681 key.append(installation_suffix); | |
682 key.append(ShellUtil::kRegShellOpen); | 702 key.append(ShellUtil::kRegShellOpen); |
683 InstallUtil::DeleteRegistryValue(root_key, key, | 703 InstallUtil::DeleteRegistryValue(root_key, key, |
684 ShellUtil::kRegDelegateExecute); | 704 ShellUtil::kRegDelegateExecute); |
685 } | 705 } |
686 } | 706 } |
687 | 707 |
688 // Returns true if the current install's |chrome_exe| has been registered with | 708 // Returns true if the current install's |chrome_exe| has been registered with |
689 // |suffix|. | 709 // |suffix|. |
690 // |confirmation_level| is the level of verification desired as described in | 710 // |confirmation_level| is the level of verification desired as described in |
691 // the RegistrationConfirmationLevel enum above. | 711 // the RegistrationConfirmationLevel enum above. |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
740 // Assert that |reg_key| points to |chrome_exe| in HKLM. | 760 // Assert that |reg_key| points to |chrome_exe| in HKLM. |
741 const RegKey key_hklm(HKEY_LOCAL_MACHINE, reg_key.c_str(), KEY_QUERY_VALUE); | 761 const RegKey key_hklm(HKEY_LOCAL_MACHINE, reg_key.c_str(), KEY_QUERY_VALUE); |
742 string16 hklm_value; | 762 string16 hklm_value; |
743 if (key_hklm.ReadValue(L"", &hklm_value) == ERROR_SUCCESS) { | 763 if (key_hklm.ReadValue(L"", &hklm_value) == ERROR_SUCCESS) { |
744 return InstallUtil::ProgramCompare( | 764 return InstallUtil::ProgramCompare( |
745 FilePath(chrome_exe)).Evaluate(hklm_value); | 765 FilePath(chrome_exe)).Evaluate(hklm_value); |
746 } | 766 } |
747 return false; | 767 return false; |
748 } | 768 } |
749 | 769 |
750 // Sets |suffix| to this user's username preceded by a dot. This suffix is then | 770 // Sets |suffix| to a 27 characters string that is specific to this user on |
grt (UTC plus 2)
2012/06/27 15:47:32
characters -> character
gab
2012/07/03 22:36:06
Done.
| |
751 // meant to be added to all registration that may conflict with another | 771 // this machine, on user-level installs, preferably. |
grt (UTC plus 2)
2012/06/27 15:47:32
i don't understand "on user-level installs, prefer
gab
2012/07/03 22:36:06
I meant that this is not the only outcome, but the
| |
752 // user-level Chrome install. | |
753 // Returns true unless the OS call to retrieve the username fails. | |
754 bool GetUserSpecificRegistrySuffix(string16* suffix) { | |
755 wchar_t user_name[256]; | |
756 DWORD size = arraysize(user_name); | |
757 if (::GetUserName(user_name, &size) == 0 || size < 1) { | |
758 PLOG(DFATAL) << "GetUserName failed"; | |
759 return false; | |
760 } | |
761 suffix->reserve(size); | |
762 suffix->assign(1, L'.'); | |
763 suffix->append(user_name, size - 1); | |
764 return true; | |
765 } | |
766 | |
767 // Sets |suffix| to the current user's username, preceded by a dot, on | |
768 // user-level installs. | |
769 // To support old-style user-level installs however, |suffix| is cleared if | 772 // To support old-style user-level installs however, |suffix| is cleared if |
770 // the user currently owns the non-suffixed HKLM registrations. | 773 // the user currently owns the non-suffixed HKLM registrations. |
771 // |suffix| is also cleared on system-level installs. | 774 // |suffix| can also be set to the user's username if the current install |
775 // is suffixed as per the old-style registrations. | |
776 // |suffix| is cleared on system-level installs. | |
772 // |suffix| should then be appended to all Chrome properties that may conflict | 777 // |suffix| should then be appended to all Chrome properties that may conflict |
773 // with other Chrome user-level installs. | 778 // with other Chrome user-level installs. |
774 // Returns true unless one of the underlying calls fails. | 779 // Returns true unless one of the underlying calls fails. |
775 bool GetInstallationSpecificSuffix(BrowserDistribution* dist, | 780 bool GetInstallationSpecificSuffix(BrowserDistribution* dist, |
776 const string16& chrome_exe, | 781 const string16& chrome_exe, |
777 string16* suffix) { | 782 string16* suffix) { |
778 if (!InstallUtil::IsPerUserInstall(chrome_exe.c_str()) || | 783 if (!InstallUtil::IsPerUserInstall(chrome_exe.c_str()) || |
779 QuickIsChromeRegistered(dist, chrome_exe, string16(), | 784 QuickIsChromeRegistered(dist, chrome_exe, string16(), |
780 CONFIRM_SHELL_REGISTRATION)) { | 785 CONFIRM_SHELL_REGISTRATION)) { |
781 // No suffix on system-level installs and user-level installs already | 786 // No suffix on system-level installs and user-level installs already |
782 // registered with no suffix. | 787 // registered with no suffix. |
783 suffix->clear(); | 788 suffix->clear(); |
784 return true; | 789 return true; |
785 } else { | |
786 return GetUserSpecificRegistrySuffix(suffix); | |
787 } | 790 } |
791 | |
792 string16 old_suffix; | |
grt (UTC plus 2)
2012/06/27 15:47:32
why not use the caller-provided string here rather
gab
2012/07/03 22:36:06
Done.
gab
2012/07/03 22:36:06
Done.
| |
793 // Get the |old_suffix| for the check below. | |
794 if (!ShellUtil::GetOldUserSpecificRegistrySuffix(&old_suffix)) { | |
795 NOTREACHED(); | |
796 return false; | |
797 } | |
798 if (QuickIsChromeRegistered(dist, chrome_exe, old_suffix, | |
799 CONFIRM_SHELL_REGISTRATION)) { | |
800 // Username suffix for installs that are suffixed as per the old-style. | |
801 suffix->assign(old_suffix); | |
802 return true; | |
803 } | |
804 | |
805 return ShellUtil::GetNewUserSpecificRegistrySuffix(suffix); | |
788 } | 806 } |
789 | 807 |
790 // Returns the root registry key (HKLM or HKCU) into which shell integration | 808 // Returns the root registry key (HKLM or HKCU) into which shell integration |
791 // registration for default protocols must be placed. As of Windows 8 everything | 809 // registration for default protocols must be placed. As of Windows 8 everything |
792 // can go in HKCU for per-user installs. | 810 // can go in HKCU for per-user installs. |
793 HKEY DetermineShellIntegrationRoot(bool is_per_user) { | 811 HKEY DetermineShellIntegrationRoot(bool is_per_user) { |
794 return is_per_user && base::win::GetVersion() >= base::win::VERSION_WIN8 ? | 812 return is_per_user && base::win::GetVersion() >= base::win::VERSION_WIN8 ? |
795 HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; | 813 HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; |
796 } | 814 } |
797 | 815 |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1053 key.ReadValue(kReinstallCommand, &command) == ERROR_SUCCESS && | 1071 key.ReadValue(kReinstallCommand, &command) == ERROR_SUCCESS && |
1054 !command.empty()) { | 1072 !command.empty()) { |
1055 (*browsers)[name] = command; | 1073 (*browsers)[name] = command; |
1056 } | 1074 } |
1057 } | 1075 } |
1058 } | 1076 } |
1059 } | 1077 } |
1060 | 1078 |
1061 string16 ShellUtil::GetCurrentInstallationSuffix(BrowserDistribution* dist, | 1079 string16 ShellUtil::GetCurrentInstallationSuffix(BrowserDistribution* dist, |
1062 const string16& chrome_exe) { | 1080 const string16& chrome_exe) { |
1081 // This method is somewhat the opposite of GetInstallationSpecificSuffix(). | |
1082 // In this case we are not trying to determine the current suffix for the | |
1083 // upcoming installation (i.e. not trying to stick to a currently bad | |
1084 // registration style if one is present). | |
1085 // Here we want to determine which suffix we should use at run-time. | |
1086 // In order of preference, we prefer (for user-level installs): | |
1087 // 1) Base 32 encoding of the md5 hash of the username (new-style). | |
1088 // 2) Username (old-style). | |
1089 // 3) Unsuffixed (even worse). | |
1063 string16 tested_suffix; | 1090 string16 tested_suffix; |
1064 if (!InstallUtil::IsPerUserInstall(chrome_exe.c_str()) || | 1091 if (InstallUtil::IsPerUserInstall(chrome_exe.c_str()) && |
1065 !GetUserSpecificRegistrySuffix(&tested_suffix) || | 1092 (!GetNewUserSpecificRegistrySuffix(&tested_suffix) || |
1066 !QuickIsChromeRegistered(dist, chrome_exe, tested_suffix, | 1093 !QuickIsChromeRegistered(dist, chrome_exe, tested_suffix, |
1067 CONFIRM_PROGID_REGISTRATION)) { | 1094 CONFIRM_PROGID_REGISTRATION)) && |
1068 return string16(); | 1095 (!GetOldUserSpecificRegistrySuffix(&tested_suffix) || |
1096 !QuickIsChromeRegistered(dist, chrome_exe, tested_suffix, | |
1097 CONFIRM_PROGID_REGISTRATION)) && | |
1098 (tested_suffix.clear(), | |
grt (UTC plus 2)
2012/06/27 15:47:32
ugh, comma. how about just:
!QuickIsChromeRegist
gab
2012/07/03 22:36:06
Oh nice, erase()! I had looked at .clear(), but it
| |
1099 !QuickIsChromeRegistered(dist, chrome_exe, tested_suffix, | |
1100 CONFIRM_PROGID_REGISTRATION))) { | |
1101 // If Chrome is not registered under any of the possible suffixes (e.g. | |
1102 // tests, Canary, etc.): use the new-style suffix at run-time. | |
1103 if (!GetNewUserSpecificRegistrySuffix(&tested_suffix)) | |
1104 NOTREACHED(); | |
1069 } | 1105 } |
1070 return tested_suffix; | 1106 return tested_suffix; |
1071 } | 1107 } |
1072 | 1108 |
1073 string16 ShellUtil::GetApplicationName(BrowserDistribution* dist, | 1109 string16 ShellUtil::GetApplicationName(BrowserDistribution* dist, |
1074 const string16& chrome_exe) { | 1110 const string16& chrome_exe) { |
1075 string16 app_name = dist->GetBaseAppName(); | 1111 string16 app_name = dist->GetBaseAppName(); |
1076 app_name += GetCurrentInstallationSuffix(dist, chrome_exe); | 1112 app_name += GetCurrentInstallationSuffix(dist, chrome_exe); |
1077 return app_name; | 1113 return app_name; |
1078 } | 1114 } |
1079 | 1115 |
1080 string16 ShellUtil::GetBrowserModelId(BrowserDistribution* dist, | 1116 string16 ShellUtil::GetBrowserModelId(BrowserDistribution* dist, |
1081 const string16& chrome_exe) { | 1117 const string16& chrome_exe) { |
1082 string16 app_id(dist->GetBaseAppId()); | 1118 string16 app_id(dist->GetBaseAppId()); |
1083 string16 suffix; | 1119 string16 suffix; |
1084 if (InstallUtil::IsPerUserInstall(chrome_exe.c_str()) && | 1120 if (InstallUtil::IsPerUserInstall(chrome_exe.c_str()) && |
1085 !GetUserSpecificRegistrySuffix(&suffix)) { | 1121 !GetNewUserSpecificRegistrySuffix(&suffix)) { |
1086 NOTREACHED(); | 1122 NOTREACHED(); |
1087 } | 1123 } |
1088 // There is only one component (i.e. the suffixed appid) in this case, but it | 1124 // There is only one component (i.e. the suffixed appid) in this case, but it |
1089 // is still necessary to go through the appid constructor to make sure the | 1125 // is still necessary to go through the appid constructor to make sure the |
1090 // returned appid is truncated if necessary. | 1126 // returned appid is truncated if necessary. |
1091 std::vector<string16> components(1, app_id.append(suffix)); | 1127 std::vector<string16> components(1, app_id.append(suffix)); |
1092 return BuildAppModelId(components); | 1128 return BuildAppModelId(components); |
1093 } | 1129 } |
1094 | 1130 |
1095 string16 ShellUtil::BuildAppModelId( | 1131 string16 ShellUtil::BuildAppModelId( |
(...skipping 418 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1514 chrome_exe.c_str(), | 1550 chrome_exe.c_str(), |
1515 shortcut.c_str(), | 1551 shortcut.c_str(), |
1516 chrome_path.value().c_str(), | 1552 chrome_path.value().c_str(), |
1517 arguments.c_str(), | 1553 arguments.c_str(), |
1518 description.c_str(), | 1554 description.c_str(), |
1519 icon_path.c_str(), | 1555 icon_path.c_str(), |
1520 icon_index, | 1556 icon_index, |
1521 app_id.c_str(), | 1557 app_id.c_str(), |
1522 ConvertShellUtilShortcutOptionsToFileUtil(options)); | 1558 ConvertShellUtilShortcutOptionsToFileUtil(options)); |
1523 } | 1559 } |
1560 | |
1561 // Sets |suffix| to the base 32 encoding of the md5 hash of this user's username | |
1562 // preceded by a dot. | |
1563 // This is guaranteed to be unique on the machine and 27 characters long | |
1564 // (including the '.'). | |
1565 // This suffix is then meant to be added to all registration that may conflict | |
1566 // with another user-level Chrome install. | |
1567 // Note that prior to Chrome 21, the suffix registered used to be the user's | |
1568 // username (see GetOldUserSpecificRegistrySuffix() below). We still honor old | |
1569 // installs registered that way, but it was wrong because some of the characters | |
1570 // allowed in a username are not allowed in a ProgId. | |
1571 // Returns true unless the OS call to retrieve the username fails. | |
1572 bool ShellUtil::GetNewUserSpecificRegistrySuffix(string16* suffix) { | |
grt (UTC plus 2)
2012/06/27 15:47:32
I'm not in love with "New" and "Old" in the method
gab
2012/07/03 22:36:06
Done.
| |
1573 wchar_t user_name[256]; | |
1574 DWORD size = arraysize(user_name); | |
1575 if (::GetUserName(user_name, &size) == 0 || size < 1) { | |
1576 NOTREACHED(); | |
1577 return false; | |
1578 } | |
1579 base::MD5Digest md5_digest; | |
1580 base::MD5Sum(user_name, size, &md5_digest); | |
1581 const string16 base32_md5(ShellUtil::MD5DigestToBase32(md5_digest)); | |
1582 // The value returned by the base32 algorithm above must never change and must | |
1583 // always be 26 characters long (i.e. if someone ever moves this to base and | |
1584 // implements the full base32 algorithm (i.e. with appended '=' signs in the | |
1585 // output), they must provide a flag to allow this method to still request | |
1586 // the output with no appended '=' signs). | |
1587 DCHECK_EQ(base32_md5.length(), 26U); | |
1588 suffix->reserve(27); | |
grt (UTC plus 2)
2012/06/27 15:47:32
27 -> base32_md5.size() + 1
gab
2012/07/03 22:36:06
Done.
| |
1589 suffix->assign(1, L'.'); | |
1590 suffix->append(base32_md5); | |
1591 return true; | |
1592 } | |
1593 | |
1594 // Sets |suffix| to this user's username preceded by a dot. This suffix is then | |
1595 // meant to be added to all registration that may conflict with another | |
grt (UTC plus 2)
2012/06/27 15:47:32
this comment is incorrect, no? this suffix should
gab
2012/07/03 22:36:06
Done.
| |
1596 // user-level Chrome install. | |
1597 // Returns true unless the OS call to retrieve the username fails. | |
1598 bool ShellUtil::GetOldUserSpecificRegistrySuffix(string16* suffix) { | |
1599 wchar_t user_name[256]; | |
1600 DWORD size = arraysize(user_name); | |
1601 if (::GetUserName(user_name, &size) == 0 || size < 1) { | |
1602 NOTREACHED(); | |
1603 return false; | |
1604 } | |
1605 suffix->reserve(size); | |
1606 suffix->assign(1, L'.'); | |
1607 suffix->append(user_name, size - 1); | |
1608 return true; | |
1609 } | |
1610 | |
1611 string16 ShellUtil::MD5DigestToBase32(const base::MD5Digest& digest) { | |
grt (UTC plus 2)
2012/06/27 15:47:32
why is this function needed? GetNewUserSpecificRe
gab
2012/07/03 22:36:06
Good point, moved the very little bit logic remain
| |
1612 COMPILE_ASSERT(sizeof(base::MD5Digest) == 16, size_of_MD5_not_as_expected_); | |
1613 string16 encoding(ByteArrayToBase32(digest.a, 16)); | |
grt (UTC plus 2)
2012/06/27 15:47:32
16 -> arraysize(digest.a)
gab
2012/07/03 22:36:06
Done.
| |
1614 // This must always remain 26 characters as callers which write to solid | |
1615 // state depend on this. | |
1616 DCHECK_EQ(encoding.length(), 26U); | |
1617 return encoding; | |
1618 } | |
1619 | |
1620 string16 ShellUtil::ByteArrayToBase32(const unsigned char bytes[], int size) { | |
grt (UTC plus 2)
2012/06/27 15:47:32
const unsigned char bytes[] -> const uint8* bytes
gab
2012/07/03 22:36:06
I thought style-guide also said to avoid using siz
grt (UTC plus 2)
2012/07/05 20:00:19
it says to avoid using unsigned types just for the
gab
2012/07/05 21:19:53
Ah ok got it, thanks for clarifying :)!
| |
1621 static char const kEncoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; | |
grt (UTC plus 2)
2012/06/27 15:47:32
char const -> const char
gab
2012/07/03 22:36:06
Done.
gab
2012/07/03 22:36:06
Done.
| |
1622 | |
1623 // Eliminate special cases first. | |
1624 if (size == 0) { | |
1625 return string16(); | |
1626 } else if (size == 1) { | |
1627 string16 ret; | |
1628 ret.push_back(kEncoding[(bytes[0] & 0xf8) >> 3]); | |
1629 ret.push_back(kEncoding[(bytes[0] & 0x07) << 2]); | |
1630 return ret; | |
1631 } | |
grt (UTC plus 2)
2012/06/27 15:47:32
else if (size >= std::numeric_limits<size_t>::max(
gab
2012/07/03 22:36:06
Done.
| |
1632 | |
1633 // Overestimate the number of bits in the string by 4 so that dividing by 5 | |
1634 // is the equivalent of rounding up the actual number of bits divided by 5. | |
1635 const int kEncodedLength = (size * 8 + 4) / 5; | |
grt (UTC plus 2)
2012/06/27 15:47:32
kEncodedLength -> encoded_length (it isn't a compi
gab
2012/07/03 22:36:06
Done.
| |
1636 | |
1637 string16 ret; | |
1638 ret.reserve(kEncodedLength); | |
1639 | |
1640 // A bit stream which will be read from the left and appended to from the | |
1641 // right as it's emptied. | |
1642 uint16 bit_stream = (bytes[0] << 8) + bytes[1]; | |
1643 int next_byte_index = 2; | |
1644 int free_bits = 0; | |
1645 while (free_bits < 16) { | |
1646 // Extract the 5 leftmost bits in the stream | |
1647 ret.push_back(kEncoding[(bit_stream & 0xf800) >> 11]); | |
1648 bit_stream <<= 5; | |
1649 free_bits += 5; | |
1650 | |
1651 // If there is enough room in the bit stream, inject another byte (if there | |
1652 // are any left...). | |
1653 if (free_bits >= 8 && next_byte_index < size) { | |
1654 free_bits -= 8; | |
1655 bit_stream += bytes[next_byte_index++] << free_bits; | |
1656 } | |
1657 } | |
1658 | |
1659 DCHECK_EQ(ret.length(), static_cast<size_t>(kEncodedLength)); | |
1660 return ret; | |
1661 } | |
OLD | NEW |