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/setup/installer_state.h" | 5 #include "chrome/installer/setup/installer_state.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <algorithm> | |
10 #include <functional> | |
11 #include <memory> | |
12 #include <string> | 9 #include <string> |
13 #include <utility> | 10 #include <utility> |
14 | 11 |
15 #include "base/command_line.h" | 12 #include "base/command_line.h" |
16 #include "base/files/file_util.h" | 13 #include "base/files/file_util.h" |
17 #include "base/logging.h" | |
18 #include "base/macros.h" | |
19 #include "base/strings/utf_string_conversions.h" | |
20 #include "base/win/registry.h" | 14 #include "base/win/registry.h" |
21 #include "base/win/scoped_handle.h" | |
22 #include "chrome/installer/util/delete_tree_work_item.h" | |
23 #include "chrome/installer/util/google_update_settings.h" | 15 #include "chrome/installer/util/google_update_settings.h" |
24 #include "chrome/installer/util/helper.h" | 16 #include "chrome/installer/util/helper.h" |
25 #include "chrome/installer/util/install_util.h" | 17 #include "chrome/installer/util/install_util.h" |
26 #include "chrome/installer/util/installation_state.h" | 18 #include "chrome/installer/util/installation_state.h" |
27 #include "chrome/installer/util/master_preferences.h" | 19 #include "chrome/installer/util/master_preferences.h" |
28 #include "chrome/installer/util/master_preferences_constants.h" | 20 #include "chrome/installer/util/master_preferences_constants.h" |
29 #include "chrome/installer/util/product.h" | 21 #include "chrome/installer/util/product.h" |
30 #include "chrome/installer/util/work_item.h" | 22 #include "chrome/installer/util/work_item.h" |
31 #include "chrome/installer/util/work_item_list.h" | 23 #include "chrome/installer/util/work_item_list.h" |
32 | 24 |
33 namespace installer { | 25 namespace installer { |
34 | 26 |
35 bool InstallerState::IsMultiInstallUpdate( | |
36 const MasterPreferences& prefs, | |
37 const InstallationState& machine_state) { | |
38 // First, are the binaries present? | |
39 const ProductState* binaries = | |
40 machine_state.GetProductState(level_ == SYSTEM_LEVEL, | |
41 BrowserDistribution::CHROME_BINARIES); | |
42 if (binaries == NULL) { | |
43 // The multi-install binaries have not been installed, so they certainly | |
44 // aren't being updated. | |
45 return false; | |
46 } | |
47 | |
48 if (prefs.install_chrome()) { | |
49 const ProductState* product = | |
50 machine_state.GetProductState(level_ == SYSTEM_LEVEL, | |
51 BrowserDistribution::CHROME_BROWSER); | |
52 if (product == NULL) { | |
53 VLOG(2) << "It seems that chrome is being installed for the first time."; | |
54 return false; | |
55 } | |
56 if (!product->channel().Equals(binaries->channel())) { | |
57 VLOG(2) << "It seems that chrome is being over installed."; | |
58 return false; | |
59 } | |
60 } | |
61 | |
62 VLOG(2) << "It seems that the binaries are being updated."; | |
63 | |
64 return true; | |
65 } | |
66 | |
67 InstallerState::InstallerState() | 27 InstallerState::InstallerState() |
68 : operation_(UNINITIALIZED), | 28 : operation_(UNINITIALIZED), |
69 state_type_(BrowserDistribution::CHROME_BROWSER), | 29 state_type_(BrowserDistribution::CHROME_BROWSER), |
70 multi_package_distribution_(NULL), | |
71 level_(UNKNOWN_LEVEL), | 30 level_(UNKNOWN_LEVEL), |
72 package_type_(UNKNOWN_PACKAGE_TYPE), | |
73 root_key_(NULL), | 31 root_key_(NULL), |
74 msi_(false), | 32 msi_(false), |
75 background_mode_(false), | 33 background_mode_(false), |
76 verbose_logging_(false), | 34 verbose_logging_(false), |
77 is_migrating_to_single_(false) {} | 35 is_migrating_to_single_(false) {} |
78 | 36 |
79 InstallerState::InstallerState(Level level) | 37 InstallerState::InstallerState(Level level) |
80 : operation_(UNINITIALIZED), | 38 : operation_(UNINITIALIZED), |
81 state_type_(BrowserDistribution::CHROME_BROWSER), | 39 state_type_(BrowserDistribution::CHROME_BROWSER), |
82 multi_package_distribution_(NULL), | |
83 level_(UNKNOWN_LEVEL), | 40 level_(UNKNOWN_LEVEL), |
84 package_type_(UNKNOWN_PACKAGE_TYPE), | |
85 root_key_(NULL), | 41 root_key_(NULL), |
86 msi_(false), | 42 msi_(false), |
87 background_mode_(false), | 43 background_mode_(false), |
88 verbose_logging_(false), | 44 verbose_logging_(false), |
89 is_migrating_to_single_(false) { | 45 is_migrating_to_single_(false) { |
90 // Use set_level() so that root_key_ is updated properly. | 46 // Use set_level() so that root_key_ is updated properly. |
91 set_level(level); | 47 set_level(level); |
92 } | 48 } |
93 | 49 |
94 InstallerState::~InstallerState() { | 50 InstallerState::~InstallerState() { |
95 } | 51 } |
96 | 52 |
97 void InstallerState::Initialize(const base::CommandLine& command_line, | 53 void InstallerState::Initialize(const base::CommandLine& command_line, |
98 const MasterPreferences& prefs, | 54 const MasterPreferences& prefs, |
99 const InstallationState& machine_state) { | 55 const InstallationState& machine_state) { |
100 Clear(); | 56 Clear(); |
101 | 57 |
102 bool pref_bool; | 58 bool pref_bool; |
103 if (!prefs.GetBool(master_preferences::kSystemLevel, &pref_bool)) | 59 if (!prefs.GetBool(master_preferences::kSystemLevel, &pref_bool)) |
104 pref_bool = false; | 60 pref_bool = false; |
105 set_level(pref_bool ? SYSTEM_LEVEL : USER_LEVEL); | 61 set_level(pref_bool ? SYSTEM_LEVEL : USER_LEVEL); |
106 | 62 |
107 if (!prefs.GetBool(master_preferences::kVerboseLogging, &verbose_logging_)) | 63 if (!prefs.GetBool(master_preferences::kVerboseLogging, &verbose_logging_)) |
108 verbose_logging_ = false; | 64 verbose_logging_ = false; |
109 | 65 |
110 if (!prefs.GetBool(master_preferences::kMultiInstall, &pref_bool)) | |
111 pref_bool = false; | |
112 set_package_type(pref_bool ? MULTI_PACKAGE : SINGLE_PACKAGE); | |
113 | |
114 if (!prefs.GetBool(master_preferences::kMsi, &msi_)) | 66 if (!prefs.GetBool(master_preferences::kMsi, &msi_)) |
115 msi_ = false; | 67 msi_ = false; |
116 | 68 |
117 const bool is_uninstall = command_line.HasSwitch(switches::kUninstall); | 69 const bool is_uninstall = command_line.HasSwitch(switches::kUninstall); |
118 | 70 |
119 if (prefs.install_chrome()) { | 71 Product* p = AddProductFromPreferences(BrowserDistribution::CHROME_BROWSER, |
120 Product* p = AddProductFromPreferences( | 72 prefs, machine_state); |
121 BrowserDistribution::CHROME_BROWSER, prefs, machine_state); | 73 VLOG(1) << (is_uninstall ? "Uninstall" : "Install") |
122 VLOG(1) << (is_uninstall ? "Uninstall" : "Install") | 74 << " distribution: " << p->distribution()->GetDisplayName(); |
123 << " distribution: " << p->distribution()->GetDisplayName(); | |
124 } | |
125 | 75 |
126 // Binaries are only used by Chrome. | 76 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
127 if (is_multi_install() && | 77 state_key_ = dist->GetStateKey(); |
128 FindProduct(BrowserDistribution::CHROME_BROWSER)) { | 78 state_type_ = dist->GetType(); |
129 Product* p = AddProductFromPreferences( | |
130 BrowserDistribution::CHROME_BINARIES, prefs, machine_state); | |
131 VLOG(1) << (is_uninstall ? "Uninstall" : "Install") | |
132 << " distribution: " << p->distribution()->GetDisplayName(); | |
133 } | |
134 | |
135 BrowserDistribution* operand = NULL; | |
136 | 79 |
137 if (is_uninstall) { | 80 if (is_uninstall) { |
138 operation_ = UNINSTALL; | 81 operation_ = UNINSTALL; |
139 } else if (!prefs.is_multi_install()) { | 82 } else { |
140 // For a single-install, the current browser dist is the operand. | |
141 operand = BrowserDistribution::GetDistribution(); | |
142 operation_ = SINGLE_INSTALL_OR_UPDATE; | 83 operation_ = SINGLE_INSTALL_OR_UPDATE; |
143 // Is this a migration from multi-install to single-install? | 84 // Is this a migration from multi-install to single-install? |
144 const ProductState* state = | 85 const ProductState* state = |
145 machine_state.GetProductState(system_install(), operand->GetType()); | 86 machine_state.GetProductState(system_install(), state_type_); |
146 is_migrating_to_single_ = state && state->is_multi_install(); | 87 is_migrating_to_single_ = state && state->is_multi_install(); |
147 } else if (IsMultiInstallUpdate(prefs, machine_state)) { | |
148 // Updates driven by Google Update take place under the multi-installer's | |
149 // app guid. | |
150 operand = multi_package_distribution_; | |
151 operation_ = MULTI_UPDATE; | |
152 } else { | |
153 operation_ = MULTI_INSTALL; | |
154 } | 88 } |
155 | 89 |
156 // Initial, over, and un-installs will take place under Chrome or Binaries | |
157 // app guid. | |
158 if (operand == NULL) { | |
159 operand = BrowserDistribution::GetSpecificDistribution( | |
160 prefs.install_chrome() ? | |
161 BrowserDistribution::CHROME_BROWSER : | |
162 BrowserDistribution::CHROME_BINARIES); | |
163 } | |
164 | |
165 state_key_ = operand->GetStateKey(); | |
166 state_type_ = operand->GetType(); | |
167 | |
168 // Parse --critical-update-version=W.X.Y.Z | 90 // Parse --critical-update-version=W.X.Y.Z |
169 std::string critical_version_value( | 91 std::string critical_version_value( |
170 command_line.GetSwitchValueASCII(switches::kCriticalUpdateVersion)); | 92 command_line.GetSwitchValueASCII(switches::kCriticalUpdateVersion)); |
171 critical_update_version_ = base::Version(critical_version_value); | 93 critical_update_version_ = base::Version(critical_version_value); |
172 } | 94 } |
173 | 95 |
174 void InstallerState::set_level(Level level) { | 96 void InstallerState::set_level(Level level) { |
175 level_ = level; | 97 level_ = level; |
176 switch (level) { | 98 switch (level) { |
177 case USER_LEVEL: | 99 case USER_LEVEL: |
178 root_key_ = HKEY_CURRENT_USER; | 100 root_key_ = HKEY_CURRENT_USER; |
179 break; | 101 break; |
180 case SYSTEM_LEVEL: | 102 case SYSTEM_LEVEL: |
181 root_key_ = HKEY_LOCAL_MACHINE; | 103 root_key_ = HKEY_LOCAL_MACHINE; |
182 break; | 104 break; |
183 default: | 105 default: |
184 DCHECK(level == UNKNOWN_LEVEL); | 106 DCHECK(level == UNKNOWN_LEVEL); |
185 level_ = UNKNOWN_LEVEL; | 107 level_ = UNKNOWN_LEVEL; |
186 root_key_ = NULL; | 108 root_key_ = NULL; |
187 break; | 109 break; |
188 } | 110 } |
189 } | 111 } |
190 | 112 |
191 void InstallerState::set_package_type(PackageType type) { | |
192 package_type_ = type; | |
193 switch (type) { | |
194 case SINGLE_PACKAGE: | |
195 multi_package_distribution_ = NULL; | |
196 break; | |
197 case MULTI_PACKAGE: | |
198 multi_package_distribution_ = | |
199 BrowserDistribution::GetSpecificDistribution( | |
200 BrowserDistribution::CHROME_BINARIES); | |
201 break; | |
202 default: | |
203 DCHECK(type == UNKNOWN_PACKAGE_TYPE); | |
204 package_type_ = UNKNOWN_PACKAGE_TYPE; | |
205 multi_package_distribution_ = NULL; | |
206 break; | |
207 } | |
208 } | |
209 | |
210 // Returns the Chrome binaries directory for multi-install or |dist|'s directory | |
211 // otherwise. | |
212 base::FilePath InstallerState::GetDefaultProductInstallPath( | |
213 BrowserDistribution* dist) const { | |
214 DCHECK(dist); | |
215 DCHECK(package_type_ != UNKNOWN_PACKAGE_TYPE); | |
216 | |
217 if (package_type_ == SINGLE_PACKAGE) { | |
218 return GetChromeInstallPath(system_install(), dist); | |
219 } else { | |
220 return GetChromeInstallPath(system_install(), | |
221 BrowserDistribution::GetSpecificDistribution( | |
222 BrowserDistribution::CHROME_BINARIES)); | |
223 } | |
224 } | |
225 | |
226 // Evaluates a product's eligibility for participation in this operation. | 113 // Evaluates a product's eligibility for participation in this operation. |
227 // We never expect these checks to fail, hence they all terminate the process in | 114 // We never expect these checks to fail, hence they all terminate the process in |
228 // debug builds. See the log messages for details. | 115 // debug builds. See the log messages for details. |
229 bool InstallerState::CanAddProduct(const Product& product, | 116 bool InstallerState::CanAddProduct(const base::FilePath* product_dir) const { |
230 const base::FilePath* product_dir) const { | 117 if (product_) { |
231 switch (package_type_) { | 118 LOG(DFATAL) << "Cannot process more than one single-install product."; |
232 case SINGLE_PACKAGE: | 119 return false; |
233 if (!products_.empty()) { | |
234 LOG(DFATAL) << "Cannot process more than one single-install product."; | |
235 return false; | |
236 } | |
237 break; | |
238 case MULTI_PACKAGE: | |
239 if (!product.HasOption(kOptionMultiInstall)) { | |
240 LOG(DFATAL) << "Cannot process a single-install product with a " | |
241 "multi-install state."; | |
242 return false; | |
243 } | |
244 if (FindProduct(product.distribution()->GetType()) != NULL) { | |
245 LOG(DFATAL) << "Cannot process more than one product of the same type."; | |
246 return false; | |
247 } | |
248 if (!target_path_.empty()) { | |
249 base::FilePath default_dir; | |
250 if (product_dir == NULL) | |
251 default_dir = GetDefaultProductInstallPath(product.distribution()); | |
252 if (!base::FilePath::CompareEqualIgnoreCase( | |
253 (product_dir == NULL ? default_dir : *product_dir).value(), | |
254 target_path_.value())) { | |
255 LOG(DFATAL) << "Cannot process products in different directories."; | |
256 return false; | |
257 } | |
258 } | |
259 break; | |
260 default: | |
261 DCHECK_EQ(UNKNOWN_PACKAGE_TYPE, package_type_); | |
262 break; | |
263 } | 120 } |
264 return true; | 121 return true; |
265 } | 122 } |
266 | 123 |
267 // Adds |product|, installed in |product_dir| to this object's collection. If | 124 // Adds |product|, installed in |product_dir| to this object's collection. If |
268 // |product_dir| is NULL, the product's default install location is used. | 125 // |product_dir| is NULL, the product's default install location is used. |
269 // Returns NULL if |product| is incompatible with this object. Otherwise, | 126 // Returns NULL if |product| is incompatible with this object. Otherwise, |
270 // returns a pointer to the product (ownership is held by this object). | 127 // returns a pointer to the product (ownership is held by this object). |
271 Product* InstallerState::AddProductInDirectory( | 128 Product* InstallerState::AddProductInDirectory( |
272 const base::FilePath* product_dir, | 129 const base::FilePath* product_dir, |
273 std::unique_ptr<Product>* product) { | 130 std::unique_ptr<Product> product) { |
274 DCHECK(product != NULL); | 131 DCHECK(product); |
275 DCHECK(product->get() != NULL); | 132 const Product& the_product = *product; |
276 const Product& the_product = *product->get(); | 133 DCHECK(!the_product.HasOption(kOptionMultiInstall)); |
277 | 134 |
278 if (!CanAddProduct(the_product, product_dir)) | 135 if (!CanAddProduct(product_dir)) |
279 return NULL; | 136 return nullptr; |
280 | |
281 if (package_type_ == UNKNOWN_PACKAGE_TYPE) { | |
282 set_package_type(the_product.HasOption(kOptionMultiInstall) ? | |
283 MULTI_PACKAGE : SINGLE_PACKAGE); | |
284 } | |
285 | 137 |
286 if (target_path_.empty()) { | 138 if (target_path_.empty()) { |
287 target_path_ = product_dir ? *product_dir : GetDefaultProductInstallPath( | 139 target_path_ = product_dir ? *product_dir : GetChromeInstallPath( |
| 140 system_install(), |
288 the_product.distribution()); | 141 the_product.distribution()); |
289 } | 142 } |
290 | 143 |
291 if (state_key_.empty()) | 144 if (state_key_.empty()) |
292 state_key_ = the_product.distribution()->GetStateKey(); | 145 state_key_ = the_product.distribution()->GetStateKey(); |
293 | 146 |
294 products_.push_back(product->release()); | 147 product_ = std::move(product); |
295 return products_.back(); | 148 return product_.get(); |
296 } | 149 } |
297 | 150 |
298 Product* InstallerState::AddProduct(std::unique_ptr<Product>* product) { | 151 Product* InstallerState::AddProduct(std::unique_ptr<Product> product) { |
299 return AddProductInDirectory(NULL, product); | 152 return AddProductInDirectory(nullptr, std::move(product)); |
300 } | 153 } |
301 | 154 |
302 // Adds a product of type |distribution_type| constructed on the basis of | 155 // Adds a product of type |distribution_type| constructed on the basis of |
303 // |prefs|, setting this object's msi flag if the product is represented in | 156 // |prefs|, setting this object's msi flag if the product is represented in |
304 // |machine_state| and is msi-installed. Returns the product that was added, | 157 // |machine_state| and is msi-installed. Returns the product that was added, |
305 // or NULL if |state| is incompatible with this object. Ownership is not passed | 158 // or NULL if |state| is incompatible with this object. Ownership is not passed |
306 // to the caller. | 159 // to the caller. |
307 Product* InstallerState::AddProductFromPreferences( | 160 Product* InstallerState::AddProductFromPreferences( |
308 BrowserDistribution::Type distribution_type, | 161 BrowserDistribution::Type distribution_type, |
309 const MasterPreferences& prefs, | 162 const MasterPreferences& prefs, |
310 const InstallationState& machine_state) { | 163 const InstallationState& machine_state) { |
311 std::unique_ptr<Product> product_ptr(new Product( | 164 std::unique_ptr<Product> product_ptr(new Product( |
312 BrowserDistribution::GetSpecificDistribution(distribution_type))); | 165 BrowserDistribution::GetSpecificDistribution(distribution_type))); |
313 product_ptr->InitializeFromPreferences(prefs); | 166 product_ptr->InitializeFromPreferences(prefs); |
314 | 167 |
315 Product* product = AddProductInDirectory(NULL, &product_ptr); | 168 Product* product = AddProductInDirectory(nullptr, std::move(product_ptr)); |
316 | 169 |
317 if (product != NULL && !msi_) { | 170 if (product != NULL && !msi_) { |
318 const ProductState* product_state = machine_state.GetProductState( | 171 const ProductState* product_state = machine_state.GetProductState( |
319 system_install(), distribution_type); | 172 system_install(), distribution_type); |
320 if (product_state != NULL) | 173 if (product_state != NULL) |
321 msi_ = product_state->is_msi(); | 174 msi_ = product_state->is_msi(); |
322 } | 175 } |
323 | 176 |
324 return product; | 177 return product; |
325 } | 178 } |
326 | 179 |
327 Product* InstallerState::AddProductFromState( | 180 Product* InstallerState::AddProductFromState( |
328 BrowserDistribution::Type type, | 181 BrowserDistribution::Type type, |
329 const ProductState& state) { | 182 const ProductState& state) { |
330 std::unique_ptr<Product> product_ptr( | 183 std::unique_ptr<Product> product_ptr( |
331 new Product(BrowserDistribution::GetSpecificDistribution(type))); | 184 new Product(BrowserDistribution::GetSpecificDistribution(type))); |
332 product_ptr->InitializeFromUninstallCommand(state.uninstall_command()); | 185 product_ptr->InitializeFromUninstallCommand(state.uninstall_command()); |
333 | 186 |
334 // Strip off <version>/Installer/setup.exe; see GetInstallerDirectory(). | 187 // Strip off <version>/Installer/setup.exe; see GetInstallerDirectory(). |
335 base::FilePath product_dir = | 188 base::FilePath product_dir = |
336 state.GetSetupPath().DirName().DirName().DirName(); | 189 state.GetSetupPath().DirName().DirName().DirName(); |
337 | 190 |
338 Product* product = AddProductInDirectory(&product_dir, &product_ptr); | 191 Product* product = |
| 192 AddProductInDirectory(&product_dir, std::move(product_ptr)); |
339 | 193 |
340 if (product != NULL) | 194 if (product != NULL) |
341 msi_ |= state.is_msi(); | 195 msi_ |= state.is_msi(); |
342 | 196 |
343 return product; | 197 return product; |
344 } | 198 } |
345 | 199 |
346 bool InstallerState::system_install() const { | 200 bool InstallerState::system_install() const { |
347 DCHECK(level_ == USER_LEVEL || level_ == SYSTEM_LEVEL); | 201 DCHECK(level_ == USER_LEVEL || level_ == SYSTEM_LEVEL); |
348 return level_ == SYSTEM_LEVEL; | 202 return level_ == SYSTEM_LEVEL; |
349 } | 203 } |
350 | 204 |
351 bool InstallerState::is_multi_install() const { | |
352 DCHECK(package_type_ == SINGLE_PACKAGE || package_type_ == MULTI_PACKAGE); | |
353 return package_type_ != SINGLE_PACKAGE; | |
354 } | |
355 | |
356 bool InstallerState::RemoveProduct(const Product* product) { | |
357 ScopedVector<Product>::iterator it = | |
358 std::find(products_.begin(), products_.end(), product); | |
359 if (it != products_.end()) { | |
360 products_.weak_erase(it); | |
361 return true; | |
362 } | |
363 return false; | |
364 } | |
365 | |
366 const Product* InstallerState::FindProduct( | |
367 BrowserDistribution::Type distribution_type) const { | |
368 for (Products::const_iterator scan = products_.begin(), end = products_.end(); | |
369 scan != end; ++scan) { | |
370 if ((*scan)->is_type(distribution_type)) | |
371 return *scan; | |
372 } | |
373 return NULL; | |
374 } | |
375 | |
376 base::Version* InstallerState::GetCurrentVersion( | 205 base::Version* InstallerState::GetCurrentVersion( |
377 const InstallationState& machine_state) const { | 206 const InstallationState& machine_state) const { |
378 DCHECK(!products_.empty()); | 207 DCHECK(product_); |
379 std::unique_ptr<base::Version> current_version; | 208 std::unique_ptr<base::Version> current_version; |
380 // If we're doing a multi-install, the current version may be either an | 209 const ProductState* product_state = machine_state.GetProductState( |
381 // existing multi or an existing single product that is being migrated | 210 level_ == SYSTEM_LEVEL, product_->distribution()->GetType()); |
382 // in place (i.e., Chrome). In the latter case, there is no existing | |
383 // CHROME_BINARIES installation so we need to search for the product. | |
384 BrowserDistribution::Type prod_type; | |
385 if (package_type_ == MULTI_PACKAGE) { | |
386 prod_type = BrowserDistribution::CHROME_BINARIES; | |
387 if (machine_state.GetProductState(level_ == SYSTEM_LEVEL, | |
388 prod_type) == NULL) { | |
389 // Search for a product on which we're operating that is installed in our | |
390 // target directory. | |
391 Products::const_iterator end = products().end(); | |
392 for (Products::const_iterator scan = products().begin(); scan != end; | |
393 ++scan) { | |
394 BrowserDistribution::Type product_type = | |
395 (*scan)->distribution()->GetType(); | |
396 const ProductState* state = | |
397 machine_state.GetProductState(level_ == SYSTEM_LEVEL, product_type); | |
398 if (state != NULL && target_path_.IsParent(state->GetSetupPath())) { | |
399 prod_type = product_type; | |
400 break; | |
401 } | |
402 } | |
403 } | |
404 } else { | |
405 prod_type = products_[0]->distribution()->GetType(); | |
406 } | |
407 const ProductState* product_state = | |
408 machine_state.GetProductState(level_ == SYSTEM_LEVEL, prod_type); | |
409 | 211 |
410 if (product_state != NULL) { | 212 if (product_state != NULL) { |
411 const base::Version* version = NULL; | 213 const base::Version* version = NULL; |
412 | 214 |
413 // Be aware that there might be a pending "new_chrome.exe" already in the | 215 // Be aware that there might be a pending "new_chrome.exe" already in the |
414 // installation path. If so, we use old_version, which holds the version of | 216 // installation path. If so, we use old_version, which holds the version of |
415 // "chrome.exe" itself. | 217 // "chrome.exe" itself. |
416 if (base::PathExists(target_path().Append(kChromeNewExe))) | 218 if (base::PathExists(target_path().Append(kChromeNewExe))) |
417 version = product_state->old_version(); | 219 version = product_state->old_version(); |
418 | 220 |
(...skipping 13 matching lines...) Expand all Loading... |
432 DCHECK(new_version.IsValid()); | 234 DCHECK(new_version.IsValid()); |
433 if (critical_update_version_.IsValid() && | 235 if (critical_update_version_.IsValid() && |
434 (current_version == NULL || | 236 (current_version == NULL || |
435 (current_version->CompareTo(critical_update_version_) < 0)) && | 237 (current_version->CompareTo(critical_update_version_) < 0)) && |
436 new_version.CompareTo(critical_update_version_) >= 0) { | 238 new_version.CompareTo(critical_update_version_) >= 0) { |
437 return critical_update_version_; | 239 return critical_update_version_; |
438 } | 240 } |
439 return base::Version(); | 241 return base::Version(); |
440 } | 242 } |
441 | 243 |
442 bool InstallerState::IsChromeFrameRunning( | |
443 const InstallationState& machine_state) const { | |
444 return AnyExistsAndIsInUse(machine_state, CHROME_FRAME_DLL); | |
445 } | |
446 | |
447 bool InstallerState::AreBinariesInUse( | |
448 const InstallationState& machine_state) const { | |
449 return AnyExistsAndIsInUse( | |
450 machine_state, | |
451 (CHROME_FRAME_HELPER_EXE | CHROME_FRAME_HELPER_DLL | | |
452 CHROME_FRAME_DLL | CHROME_DLL)); | |
453 } | |
454 | |
455 base::FilePath InstallerState::GetInstallerDirectory( | 244 base::FilePath InstallerState::GetInstallerDirectory( |
456 const base::Version& version) const { | 245 const base::Version& version) const { |
457 return target_path().AppendASCII(version.GetString()).Append(kInstallerDir); | 246 return target_path().AppendASCII(version.GetString()).Append(kInstallerDir); |
458 } | 247 } |
459 | 248 |
460 // static | |
461 bool InstallerState::IsFileInUse(const base::FilePath& file) { | |
462 // Call CreateFile with a share mode of 0 which should cause this to fail | |
463 // with ERROR_SHARING_VIOLATION if the file exists and is in-use. | |
464 return !base::win::ScopedHandle(CreateFile(file.value().c_str(), | |
465 GENERIC_WRITE, 0, NULL, | |
466 OPEN_EXISTING, 0, 0)).IsValid(); | |
467 } | |
468 | |
469 void InstallerState::Clear() { | 249 void InstallerState::Clear() { |
470 operation_ = UNINITIALIZED; | 250 operation_ = UNINITIALIZED; |
471 target_path_.clear(); | 251 target_path_.clear(); |
472 state_key_.clear(); | 252 state_key_.clear(); |
473 state_type_ = BrowserDistribution::CHROME_BROWSER; | 253 state_type_ = BrowserDistribution::CHROME_BROWSER; |
474 products_.clear(); | 254 product_.reset(); |
475 multi_package_distribution_ = NULL; | |
476 critical_update_version_ = base::Version(); | 255 critical_update_version_ = base::Version(); |
477 level_ = UNKNOWN_LEVEL; | 256 level_ = UNKNOWN_LEVEL; |
478 package_type_ = UNKNOWN_PACKAGE_TYPE; | |
479 root_key_ = NULL; | 257 root_key_ = NULL; |
480 msi_ = false; | 258 msi_ = false; |
481 verbose_logging_ = false; | 259 verbose_logging_ = false; |
482 is_migrating_to_single_ = false; | 260 is_migrating_to_single_ = false; |
483 } | 261 } |
484 | 262 |
485 bool InstallerState::AnyExistsAndIsInUse(const InstallationState& machine_state, | |
486 uint32_t file_bits) const { | |
487 static const wchar_t* const kBinaryFileNames[] = { | |
488 kChromeDll, | |
489 kChromeFrameDll, | |
490 kChromeFrameHelperDll, | |
491 kChromeFrameHelperExe, | |
492 }; | |
493 DCHECK_NE(file_bits, 0U); | |
494 DCHECK_LT(file_bits, 1U << NUM_BINARIES); | |
495 static_assert(CHROME_DLL == 1, "binary file names and values must match"); | |
496 static_assert(CHROME_FRAME_DLL == 2, | |
497 "binary file names and values must match"); | |
498 static_assert(CHROME_FRAME_HELPER_DLL == 4, | |
499 "binary file names and values must match"); | |
500 static_assert(CHROME_FRAME_HELPER_EXE == 8, | |
501 "binary file names and values must match"); | |
502 | |
503 // Check only for the current version (i.e., the version we are upgrading | |
504 // _from_). Later versions from pending in-use updates need not be checked | |
505 // since the current version is guaranteed to be in use if any such are. | |
506 std::unique_ptr<base::Version> current_version( | |
507 GetCurrentVersion(machine_state)); | |
508 if (!current_version) | |
509 return false; | |
510 base::FilePath directory( | |
511 target_path().AppendASCII(current_version->GetString())); | |
512 for (int i = 0; i < NUM_BINARIES; ++i) { | |
513 if (!(file_bits & (1U << i))) | |
514 continue; | |
515 base::FilePath file(directory.Append(kBinaryFileNames[i])); | |
516 if (base::PathExists(file) && IsFileInUse(file)) | |
517 return true; | |
518 } | |
519 return false; | |
520 } | |
521 | |
522 void InstallerState::AddComDllList( | |
523 std::vector<base::FilePath>* com_dll_list) const { | |
524 for (auto* product : products_) | |
525 product->AddComDllList(com_dll_list); | |
526 } | |
527 | |
528 void InstallerState::SetStage(InstallerStage stage) const { | 263 void InstallerState::SetStage(InstallerStage stage) const { |
529 GoogleUpdateSettings::SetProgress(system_install(), state_key_, | 264 GoogleUpdateSettings::SetProgress(system_install(), state_key_, |
530 progress_calculator_.Calculate(stage)); | 265 progress_calculator_.Calculate(stage)); |
531 } | 266 } |
532 | 267 |
533 void InstallerState::UpdateChannels() const { | 268 void InstallerState::UpdateChannels() const { |
534 DCHECK_NE(UNINSTALL, operation_); | 269 DCHECK_NE(UNINSTALL, operation_); |
535 // Update the "ap" value for the product being installed/updated. Use the | 270 // Update the "ap" value for the product being installed/updated. Use the |
536 // current value in the registry since the InstallationState instance used by | 271 // current value in the registry since the InstallationState instance used by |
537 // the bulk of the installer does not track changes made by UpdateStage. | 272 // the bulk of the installer does not track changes made by UpdateStage. |
538 // Create the app's ClientState key if it doesn't exist. | 273 // Create the app's ClientState key if it doesn't exist. |
539 ChannelInfo channel_info; | 274 ChannelInfo channel_info; |
540 base::win::RegKey state_key; | 275 base::win::RegKey state_key; |
541 LONG result = | 276 LONG result = |
542 state_key.Create(root_key_, | 277 state_key.Create(root_key_, |
543 state_key_.c_str(), | 278 state_key_.c_str(), |
544 KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_WOW64_32KEY); | 279 KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_WOW64_32KEY); |
545 if (result == ERROR_SUCCESS) { | 280 if (result == ERROR_SUCCESS) { |
546 channel_info.Initialize(state_key); | 281 channel_info.Initialize(state_key); |
547 | 282 |
548 // This is a multi-install product. | 283 // Multi-install has been deprecated. All installs and updates are single. |
549 bool modified = channel_info.SetMultiInstall(is_multi_install()); | 284 bool modified = channel_info.SetMultiInstall(false); |
550 | 285 |
551 if (is_multi_install()) { | 286 // Remove all multi-install products from the channel name. |
552 // Add the appropriate modifiers for all products and their options. | 287 modified |= channel_info.SetChrome(false); |
553 for (auto* product : products_) | 288 modified |= channel_info.SetChromeFrame(false); |
554 modified |= product->SetChannelFlags(true, &channel_info); | 289 modified |= channel_info.SetAppLauncher(false); |
555 } else { | |
556 // Remove all multi-install products from the channel name. | |
557 modified |= channel_info.SetChrome(false); | |
558 modified |= channel_info.SetChromeFrame(false); | |
559 modified |= channel_info.SetAppLauncher(false); | |
560 } | |
561 | 290 |
562 VLOG(1) << "ap: " << channel_info.value(); | 291 VLOG(1) << "ap: " << channel_info.value(); |
563 | 292 |
564 // Write the results if needed. | 293 // Write the results if needed. |
565 if (modified) | 294 if (modified) |
566 channel_info.Write(&state_key); | 295 channel_info.Write(&state_key); |
567 | |
568 if (is_multi_install()) { | |
569 // Remove the -stage: modifier since we don't want to propagate that to | |
570 // the other app_guids. | |
571 channel_info.ClearStage(); | |
572 | |
573 // Synchronize the other products and the package with this one. | |
574 ChannelInfo other_info; | |
575 for (int i = 0; i < BrowserDistribution::NUM_TYPES; ++i) { | |
576 BrowserDistribution::Type type = | |
577 static_cast<BrowserDistribution::Type>(i); | |
578 // Skip the app_guid we started with. | |
579 if (type == state_type_) | |
580 continue; | |
581 BrowserDistribution* dist = NULL; | |
582 // Always operate on the binaries. | |
583 if (i == BrowserDistribution::CHROME_BINARIES) { | |
584 dist = multi_package_distribution_; | |
585 } else { | |
586 const Product* product = FindProduct(type); | |
587 // Skip this one if it's for a product we're not operating on. | |
588 if (product == NULL) | |
589 continue; | |
590 dist = product->distribution(); | |
591 } | |
592 result = | |
593 state_key.Create(root_key_, | |
594 dist->GetStateKey().c_str(), | |
595 KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_WOW64_32KEY); | |
596 if (result == ERROR_SUCCESS) { | |
597 other_info.Initialize(state_key); | |
598 if (!other_info.Equals(channel_info)) | |
599 channel_info.Write(&state_key); | |
600 } else { | |
601 LOG(ERROR) << "Failed opening key " << dist->GetStateKey() | |
602 << " to update app channels; result: " << result; | |
603 } | |
604 } | |
605 } | |
606 } else { | 296 } else { |
607 LOG(ERROR) << "Failed opening key " << state_key_ | 297 LOG(ERROR) << "Failed opening key " << state_key_ |
608 << " to update app channels; result: " << result; | 298 << " to update app channels; result: " << result; |
609 } | 299 } |
610 } | 300 } |
611 | 301 |
612 void InstallerState::WriteInstallerResult( | 302 void InstallerState::WriteInstallerResult( |
613 InstallStatus status, | 303 InstallStatus status, |
614 int string_resource_id, | 304 int string_resource_id, |
615 const base::string16* const launch_cmd) const { | 305 const base::string16* const launch_cmd) const { |
616 // Use a no-rollback list since this is a best-effort deal. | 306 // Use a no-rollback list since this is a best-effort deal. |
617 std::unique_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList()); | 307 std::unique_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList()); |
618 install_list->set_log_message("Write Installer Result"); | 308 install_list->set_log_message("Write Installer Result"); |
619 install_list->set_best_effort(true); | 309 install_list->set_best_effort(true); |
620 install_list->set_rollback_enabled(false); | 310 install_list->set_rollback_enabled(false); |
621 const bool system_install = this->system_install(); | 311 const bool system_install = this->system_install(); |
622 // Write the value for all products upon which we're operating. | 312 // Write the value for the product upon which we're operating. |
623 Products::const_iterator end = products().end(); | 313 InstallUtil::AddInstallerResultItems( |
624 for (Products::const_iterator scan = products().begin(); scan != end; | 314 system_install, product_->distribution()->GetStateKey(), status, |
625 ++scan) { | 315 string_resource_id, launch_cmd, install_list.get()); |
626 InstallUtil::AddInstallerResultItems( | 316 if (is_migrating_to_single() && InstallUtil::GetInstallReturnCode(status)) { |
627 system_install, (*scan)->distribution()->GetStateKey(), status, | |
628 string_resource_id, launch_cmd, install_list.get()); | |
629 } | |
630 // And for the binaries if this is a multi-install. | |
631 if (is_multi_install()) { | |
632 InstallUtil::AddInstallerResultItems( | |
633 system_install, multi_package_binaries_distribution()->GetStateKey(), | |
634 status, string_resource_id, launch_cmd, install_list.get()); | |
635 } else if (is_migrating_to_single() && | |
636 InstallUtil::GetInstallReturnCode(status)) { | |
637 #if defined(GOOGLE_CHROME_BUILD) | 317 #if defined(GOOGLE_CHROME_BUILD) |
638 // Also write to the binaries on error if this is a migration back to | 318 // Write to the binaries on error if this is a migration back to |
639 // single-install for Google Chrome builds. Skip this for Chromium builds | 319 // single-install for Google Chrome builds. Skip this for Chromium builds |
640 // because they lump the "ClientState" and "Clients" keys into a single | 320 // because they lump the "ClientState" and "Clients" keys into a single |
641 // key. As a consequence, writing this value causes Software\Chromium to be | 321 // key. As a consequence, writing this value causes Software\Chromium to be |
642 // re-created after it was deleted during the migration to single-install. | 322 // re-created after it was deleted during the migration to single-install. |
643 // Google Chrome builds don't suffer this since the two keys are distinct | 323 // Google Chrome builds don't suffer this since the two keys are distinct |
644 // and have different lifetimes. The result is only written on failure since | 324 // and have different lifetimes. The result is only written on failure since |
645 // for success, the binaries have been uninstalled and therefore the result | 325 // for success, the binaries have been uninstalled and therefore the result |
646 // will not be read by Google Update. | 326 // will not be read by Google Update. |
647 InstallUtil::AddInstallerResultItems( | 327 InstallUtil::AddInstallerResultItems( |
648 system_install, BrowserDistribution::GetSpecificDistribution( | 328 system_install, BrowserDistribution::GetSpecificDistribution( |
649 BrowserDistribution::CHROME_BINARIES) | 329 BrowserDistribution::CHROME_BINARIES) |
650 ->GetStateKey(), | 330 ->GetStateKey(), |
651 status, string_resource_id, launch_cmd, install_list.get()); | 331 status, string_resource_id, launch_cmd, install_list.get()); |
652 #endif | 332 #endif |
653 } | 333 } |
654 install_list->Do(); | 334 install_list->Do(); |
655 } | 335 } |
656 | 336 |
657 bool InstallerState::RequiresActiveSetup() const { | 337 bool InstallerState::RequiresActiveSetup() const { |
658 return system_install() && FindProduct(BrowserDistribution::CHROME_BROWSER); | 338 return system_install(); |
659 } | 339 } |
660 | 340 |
661 } // namespace installer | 341 } // namespace installer |
OLD | NEW |