Chromium Code Reviews| 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 #include "chrome/installer/mini_installer/configuration.h" | 5 #include "chrome/installer/mini_installer/configuration.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <shellapi.h> // NOLINT | 8 #include <shellapi.h> // NOLINT |
| 9 #include <stddef.h> | 9 #include <stddef.h> |
| 10 | 10 |
| 11 #include "chrome/installer/mini_installer/appid.h" | 11 #include "chrome/installer/mini_installer/appid.h" |
| 12 #include "chrome/installer/mini_installer/mini_installer_constants.h" | 12 #include "chrome/installer/mini_installer/mini_installer_constants.h" |
| 13 #include "chrome/installer/mini_installer/mini_installer_resource.h" | 13 #include "chrome/installer/mini_installer/mini_installer_resource.h" |
| 14 #include "chrome/installer/mini_installer/mini_string.h" | |
| 14 #include "chrome/installer/mini_installer/regkey.h" | 15 #include "chrome/installer/mini_installer/regkey.h" |
| 15 | 16 |
| 16 namespace mini_installer { | 17 namespace mini_installer { |
| 17 | 18 |
| 18 namespace { | 19 namespace { |
| 19 | 20 |
| 20 // Returns true if GoogleUpdateIsMachine=1 is present in the environment. | 21 // Returns true if GoogleUpdateIsMachine=1 is present in the environment. |
| 21 bool GetGoogleUpdateIsMachineEnvVar() { | 22 bool GetGoogleUpdateIsMachineEnvVar() { |
| 22 const DWORD kBufferSize = 2; | 23 const DWORD kBufferSize = 2; |
| 23 StackString<kBufferSize> value; | 24 StackString<kBufferSize> value; |
| 24 DWORD length = ::GetEnvironmentVariableW(L"GoogleUpdateIsMachine", | 25 DWORD length = ::GetEnvironmentVariableW(L"GoogleUpdateIsMachine", |
| 25 value.get(), kBufferSize); | 26 value.get(), kBufferSize); |
| 26 return length == 1 && *value.get() == L'1'; | 27 return length == 1 && *value.get() == L'1'; |
| 27 } | 28 } |
| 28 | 29 |
| 29 } // namespace | 30 } // namespace |
| 30 | 31 |
| 31 Configuration::Configuration() : args_(NULL) { | 32 Configuration::Configuration() : args_(NULL) { |
| 32 Clear(); | 33 Clear(); |
| 33 } | 34 } |
| 34 | 35 |
| 35 Configuration::~Configuration() { | 36 Configuration::~Configuration() { |
| 36 Clear(); | 37 Clear(); |
| 37 } | 38 } |
| 38 | 39 |
| 39 // When multi_install is true, we are potentially: | 40 bool Configuration::Initialize(HMODULE module) { |
| 40 // 1. Performing a multi-install of some product(s) on a clean machine. | 41 Clear(); |
| 41 // Neither the product(s) nor the multi-installer will have a | 42 ReadResources(module); |
| 42 // ClientState key in the registry, so there is no key to be modified. | 43 return ParseCommandLine(::GetCommandLine()); |
| 43 // 2. Upgrading an existing multi-install. The multi-installer will have | |
| 44 // a ClientState key in the registry. Only it need be modified. | |
| 45 // 3. Migrating a single-install into a multi-install. The product will | |
| 46 // have a ClientState key in the registry. Only it need be modified. | |
| 47 // To handle all cases, we inspect the product's ClientState to see if it | |
| 48 // exists and its "ap" value does not contain "-multi". This is case 3, | |
| 49 // so we modify the product's ClientState. Otherwise, we check the | |
| 50 // multi-installer's ClientState and modify it if it exists. | |
| 51 // TODO(bcwhite): Write a unit test for this that uses registry virtualization. | |
| 52 void Configuration::SetChromeAppGuid() { | |
| 53 const HKEY root_key = | |
| 54 is_system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | |
| 55 const wchar_t* app_guid = | |
| 56 has_chrome_frame_ ? | |
| 57 google_update::kChromeFrameAppGuid : | |
| 58 is_side_by_side_ ? google_update::kSxSAppGuid | |
| 59 : google_update::kAppGuid; | |
| 60 | |
| 61 // This is the value for single-install and case 3. | |
| 62 chrome_app_guid_ = app_guid; | |
| 63 | |
| 64 if (is_multi_install_) { | |
| 65 ValueString value; | |
| 66 LONG ret = ERROR_SUCCESS; | |
| 67 if (ReadClientStateRegistryValue(root_key, app_guid, &ret, value)) { | |
| 68 // The product has a client state key. See if it's a single-install. | |
| 69 if (ret == ERROR_FILE_NOT_FOUND || | |
| 70 (ret == ERROR_SUCCESS && | |
| 71 !FindTagInStr(value.get(), kMultiInstallTag, NULL))) { | |
| 72 // yes -- case 3: use the existing key. | |
| 73 return; | |
| 74 } | |
| 75 } | |
| 76 // error, case 1, or case 2: modify the multi-installer's key. | |
| 77 chrome_app_guid_ = google_update::kMultiInstallAppGuid; | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 bool Configuration::ReadClientStateRegistryValue( | |
| 82 const HKEY root_key, const wchar_t* app_guid, | |
| 83 LONG* retval, ValueString& value) { | |
| 84 RegKey key; | |
| 85 if (!OpenClientStateKey(root_key, app_guid, KEY_QUERY_VALUE, &key)) | |
| 86 return false; | |
| 87 *retval = key.ReadSZValue(kApRegistryValue, value.get(), value.capacity()); | |
| 88 return true; | |
| 89 } | 44 } |
| 90 | 45 |
| 91 const wchar_t* Configuration::program() const { | 46 const wchar_t* Configuration::program() const { |
| 92 return args_ == NULL || argument_count_ < 1 ? NULL : args_[0]; | 47 return args_ == NULL || argument_count_ < 1 ? NULL : args_[0]; |
| 93 } | 48 } |
| 94 | 49 |
| 95 void Configuration::Clear() { | 50 void Configuration::Clear() { |
| 96 if (args_ != NULL) { | 51 if (args_ != NULL) { |
| 97 ::LocalFree(args_); | 52 ::LocalFree(args_); |
| 98 args_ = NULL; | 53 args_ = NULL; |
| 99 } | 54 } |
| 100 chrome_app_guid_ = google_update::kAppGuid; | 55 chrome_app_guid_ = google_update::kAppGuid; |
| 101 command_line_ = NULL; | 56 command_line_ = NULL; |
| 102 operation_ = INSTALL_PRODUCT; | 57 operation_ = INSTALL_PRODUCT; |
| 103 argument_count_ = 0; | 58 argument_count_ = 0; |
| 104 has_chrome_ = false; | |
| 105 has_chrome_frame_ = false; | |
| 106 is_multi_install_ = false; | |
| 107 is_system_level_ = false; | 59 is_system_level_ = false; |
| 108 is_side_by_side_ = false; | 60 is_side_by_side_ = false; |
| 61 is_updating_multi_chrome_ = false; | |
| 109 previous_version_ = NULL; | 62 previous_version_ = NULL; |
| 110 } | 63 } |
| 111 | 64 |
| 112 bool Configuration::Initialize(HMODULE module) { | |
| 113 Clear(); | |
| 114 ReadResources(module); | |
| 115 return ParseCommandLine(::GetCommandLine()); | |
| 116 } | |
| 117 | |
| 118 // |command_line| is shared with this instance in the sense that this | 65 // |command_line| is shared with this instance in the sense that this |
| 119 // instance may refer to it at will throughout its lifetime, yet it will | 66 // instance may refer to it at will throughout its lifetime, yet it will |
| 120 // not release it. | 67 // not release it. |
| 121 bool Configuration::ParseCommandLine(const wchar_t* command_line) { | 68 bool Configuration::ParseCommandLine(const wchar_t* command_line) { |
| 122 command_line_ = command_line; | 69 command_line_ = command_line; |
| 123 args_ = ::CommandLineToArgvW(command_line_, &argument_count_); | 70 args_ = ::CommandLineToArgvW(command_line_, &argument_count_); |
| 124 if (args_ != NULL) { | 71 if (!args_) |
| 125 for (int i = 1; i < argument_count_; ++i) { | 72 return false; |
| 126 if (0 == ::lstrcmpi(args_[i], L"--chrome-sxs")) | |
| 127 is_side_by_side_ = true; | |
| 128 else if (0 == ::lstrcmpi(args_[i], L"--chrome")) | |
| 129 has_chrome_ = true; | |
| 130 else if (0 == ::lstrcmpi(args_[i], L"--chrome-frame")) | |
| 131 has_chrome_frame_ = true; | |
| 132 else if (0 == ::lstrcmpi(args_[i], L"--multi-install")) | |
| 133 is_multi_install_ = true; | |
| 134 else if (0 == ::lstrcmpi(args_[i], L"--system-level")) | |
| 135 is_system_level_ = true; | |
| 136 else if (0 == ::lstrcmpi(args_[i], L"--cleanup")) | |
| 137 operation_ = CLEANUP; | |
| 138 } | |
| 139 | 73 |
| 140 if (!is_system_level_) | 74 for (int i = 1; i < argument_count_; ++i) { |
| 141 is_system_level_ = GetGoogleUpdateIsMachineEnvVar(); | 75 if (0 == ::lstrcmpi(args_[i], L"--system-level")) { |
| 142 SetChromeAppGuid(); | 76 is_system_level_ = true; |
| 143 if (!is_multi_install_) { | 77 #if defined(GOOGLE_CHROME_BUILD) |
| 144 has_chrome_ = !has_chrome_frame_; | 78 } else if (0 == ::lstrcmpi(args_[i], L"--chrome-sxs")) { |
| 79 is_side_by_side_ = true; | |
| 80 chrome_app_guid_ = google_update::kSxSAppGuid; | |
| 81 #endif | |
| 82 } else if (0 == ::lstrcmpi(args_[i], L"--cleanup")) { | |
| 83 operation_ = CLEANUP; | |
| 145 } | 84 } |
| 146 } | 85 } |
| 147 | 86 |
| 148 return args_ != NULL; | 87 if (!is_system_level_) |
| 88 is_system_level_ = GetGoogleUpdateIsMachineEnvVar(); | |
| 89 | |
| 90 is_updating_multi_chrome_ = IsUpdatingMultiChrome(); | |
| 91 | |
| 92 return true; | |
| 149 } | 93 } |
| 150 | 94 |
| 151 void Configuration::ReadResources(HMODULE module) { | 95 void Configuration::ReadResources(HMODULE module) { |
| 152 HRSRC resource_info_block = | 96 HRSRC resource_info_block = |
| 153 FindResource(module, MAKEINTRESOURCE(ID_PREVIOUS_VERSION), RT_RCDATA); | 97 FindResource(module, MAKEINTRESOURCE(ID_PREVIOUS_VERSION), RT_RCDATA); |
| 154 if (!resource_info_block) | 98 if (!resource_info_block) |
| 155 return; | 99 return; |
| 156 | 100 |
| 157 HGLOBAL data_handle = LoadResource(module, resource_info_block); | 101 HGLOBAL data_handle = LoadResource(module, resource_info_block); |
| 158 if (!data_handle) | 102 if (!data_handle) |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 170 const wchar_t* version_string = reinterpret_cast<wchar_t*>(version_data); | 114 const wchar_t* version_string = reinterpret_cast<wchar_t*>(version_data); |
| 171 size_t version_len = version_size / sizeof(wchar_t); | 115 size_t version_len = version_size / sizeof(wchar_t); |
| 172 | 116 |
| 173 // The string must be terminated. | 117 // The string must be terminated. |
| 174 if (version_string[version_len - 1]) | 118 if (version_string[version_len - 1]) |
| 175 return; | 119 return; |
| 176 | 120 |
| 177 previous_version_ = version_string; | 121 previous_version_ = version_string; |
| 178 } | 122 } |
| 179 | 123 |
| 124 bool Configuration::IsUpdatingMultiChrome() const { | |
| 125 #if defined(GOOGLE_CHROME_BUILD) | |
| 126 // SxS/canary does not support multi-install. | |
| 127 if (is_side_by_side_) | |
| 128 return false; | |
| 129 | |
| 130 // Is Chrome already installed as multi-install? | |
| 131 const HKEY root = is_system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | |
| 132 StackString<128> value; | |
| 133 RegKey key; | |
| 134 return (OpenClientsKey(root, google_update::kAppGuid, KEY_QUERY_VALUE, | |
|
huangs
2017/01/31 17:40:04
I'd prefer using |chrome_app_guid_| instead of goo
grt (UTC plus 2)
2017/02/02 08:17:15
Done.
| |
| 135 &key) == ERROR_SUCCESS && | |
| 136 key.ReadSZValue(kPvRegistryValue, value.get(), value.capacity()) == | |
| 137 ERROR_SUCCESS && | |
| 138 value.length() != 0 && | |
| 139 OpenClientStateKey(root, google_update::kAppGuid, KEY_QUERY_VALUE, | |
| 140 &key) == ERROR_SUCCESS && | |
| 141 key.ReadSZValue(kUninstallArgumentsRegistryValue, value.get(), | |
| 142 value.capacity()) == ERROR_SUCCESS && | |
| 143 value.findi(L"--multi-install") != nullptr); | |
| 144 #else | |
| 145 return false; | |
| 146 #endif | |
| 147 } | |
| 148 | |
| 180 } // namespace mini_installer | 149 } // namespace mini_installer |
| OLD | NEW |