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

Side by Side Diff: chrome/installer/setup/install_worker.cc

Issue 6288009: More installer refactoring in the interest of fixing some bugs and cleaning t... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 contains the definitions of the installer functions that build 5 // This file contains the definitions of the installer functions that build
6 // the WorkItemList used to install the application. 6 // the WorkItemList used to install the application.
7 7
8 #include "chrome/installer/setup/install_worker.h" 8 #include "chrome/installer/setup/install_worker.h"
9 9
10 #include <shlobj.h> 10 #include <shlobj.h>
11 #include <time.h> 11 #include <time.h>
12 #include <vector> 12 #include <vector>
13 13
14 #include "base/command_line.h" 14 #include "base/command_line.h"
15 #include "base/file_path.h" 15 #include "base/file_path.h"
16 #include "base/logging.h" 16 #include "base/logging.h"
17 #include "base/path_service.h" 17 #include "base/path_service.h"
18 #include "base/string_util.h" 18 #include "base/string_util.h"
19 #include "base/utf_string_conversions.h" 19 #include "base/utf_string_conversions.h"
20 #include "base/version.h" 20 #include "base/version.h"
21 #include "base/win/registry.h" 21 #include "base/win/registry.h"
22 #include "chrome/installer/setup/install.h" 22 #include "chrome/installer/setup/install.h"
23 #include "chrome/installer/setup/setup_constants.h" 23 #include "chrome/installer/setup/setup_constants.h"
24 #include "chrome/installer/util/chrome_frame_distribution.h"
25 #include "chrome/installer/util/conditional_work_item_list.h" 24 #include "chrome/installer/util/conditional_work_item_list.h"
26 #include "chrome/installer/util/create_reg_key_work_item.h" 25 #include "chrome/installer/util/create_reg_key_work_item.h"
27 #include "chrome/installer/util/google_update_constants.h" 26 #include "chrome/installer/util/google_update_constants.h"
28 #include "chrome/installer/util/helper.h" 27 #include "chrome/installer/util/helper.h"
29 #include "chrome/installer/util/installation_state.h" 28 #include "chrome/installer/util/installation_state.h"
30 #include "chrome/installer/util/installer_state.h" 29 #include "chrome/installer/util/installer_state.h"
31 #include "chrome/installer/util/install_util.h" 30 #include "chrome/installer/util/install_util.h"
32 #include "chrome/installer/util/master_preferences.h"
33 #include "chrome/installer/util/master_preferences_constants.h"
34 #include "chrome/installer/util/package.h"
35 #include "chrome/installer/util/package_properties.h"
36 #include "chrome/installer/util/product.h" 31 #include "chrome/installer/util/product.h"
37 #include "chrome/installer/util/set_reg_value_work_item.h" 32 #include "chrome/installer/util/set_reg_value_work_item.h"
38 #include "chrome/installer/util/shell_util.h" 33 #include "chrome/installer/util/shell_util.h"
39 #include "chrome/installer/util/util_constants.h" 34 #include "chrome/installer/util/util_constants.h"
40 #include "chrome/installer/util/work_item_list.h" 35 #include "chrome/installer/util/work_item_list.h"
41 36
42 using base::win::RegKey; 37 using base::win::RegKey;
43 38
44 namespace { 39 namespace {
45 40
(...skipping 10 matching lines...) Expand all
56 return (is_wow64 != NULL) && 51 return (is_wow64 != NULL) &&
57 (!(is_wow64)(GetCurrentProcess(), &is_64) || (is_64 != FALSE)); 52 (!(is_wow64)(GetCurrentProcess(), &is_64) || (is_64 != FALSE));
58 } 53 }
59 54
60 } // namespace 55 } // namespace
61 56
62 namespace installer { 57 namespace installer {
63 58
64 // Local helper to call AddRegisterComDllWorkItems for all DLLs in a set of 59 // Local helper to call AddRegisterComDllWorkItems for all DLLs in a set of
65 // products managed by a given package. 60 // products managed by a given package.
66 void AddRegisterComDllWorkItemsForPackage(const Package& package, 61 void AddRegisterComDllWorkItemsForPackage(const InstallerState& installer_state,
67 const Version* old_version, 62 const Version* old_version,
68 const Version& new_version, 63 const Version& new_version,
69 WorkItemList* work_item_list) { 64 WorkItemList* work_item_list) {
70 // First collect the list of DLLs to be registered from each product. 65 // First collect the list of DLLs to be registered from each product.
71 const Products& products = package.products();
72 Products::const_iterator product_iter(products.begin());
73 std::vector<FilePath> com_dll_list; 66 std::vector<FilePath> com_dll_list;
74 for (; product_iter != products.end(); ++product_iter) { 67 installer_state.AddComDllList(&com_dll_list);
75 BrowserDistribution* dist = product_iter->get()->distribution();
76 std::vector<FilePath> dist_dll_list(dist->GetComDllList());
77 com_dll_list.insert(com_dll_list.end(), dist_dll_list.begin(),
78 dist_dll_list.end());
79 }
80 68
81 // Then, if we got some, attempt to unregister the DLLs from the old 69 // Then, if we got some, attempt to unregister the DLLs from the old
82 // version directory and then re-register them in the new one. 70 // version directory and then re-register them in the new one.
83 // Note that if we are migrating the install directory then we will not 71 // Note that if we are migrating the install directory then we will not
84 // successfully unregister the old DLLs. 72 // successfully unregister the old DLLs.
85 // TODO(robertshield): See whether we need to fix the migration case. 73 // TODO(robertshield): See whether we need to fix the migration case.
86 // TODO(robertshield): If we ever remove a DLL from a product, this will 74 // TODO(robertshield): If we ever remove a DLL from a product, this will
87 // not unregister it on update. We should build the unregistration list from 75 // not unregister it on update. We should build the unregistration list from
88 // saved state instead of assuming it is the same as the registration list. 76 // saved state instead of assuming it is the same as the registration list.
89 if (!com_dll_list.empty()) { 77 if (!com_dll_list.empty()) {
90 if (old_version) { 78 if (old_version) {
91 FilePath old_dll_path( 79 FilePath old_dll_path(installer_state.target_path().Append(
92 package.path().Append(UTF8ToWide(old_version->GetString()))); 80 UTF8ToWide(old_version->GetString())));
93 81
94 installer::AddRegisterComDllWorkItems(old_dll_path, 82 installer::AddRegisterComDllWorkItems(old_dll_path,
95 com_dll_list, 83 com_dll_list,
96 package.system_level(), 84 installer_state.system_install(),
97 false, // Unregister 85 false, // Unregister
98 true, // May fail 86 true, // May fail
99 work_item_list); 87 work_item_list);
100 } 88 }
101 89
102 FilePath dll_path( 90 FilePath dll_path(installer_state.target_path().Append(
103 package.path().Append(UTF8ToWide(new_version.GetString()))); 91 UTF8ToWide(new_version.GetString())));
104 installer::AddRegisterComDllWorkItems(dll_path, 92 installer::AddRegisterComDllWorkItems(dll_path,
105 com_dll_list, 93 com_dll_list,
106 package.system_level(), 94 installer_state.system_install(),
107 true, // Register 95 true, // Register
108 false, // Must succeed. 96 false, // Must succeed.
109 work_item_list); 97 work_item_list);
110 } 98 }
111 } 99 }
112 100
113 void AddInstallerCopyTasks(const FilePath& setup_path, 101 void AddInstallerCopyTasks(const InstallerState& installer_state,
102 const FilePath& setup_path,
114 const FilePath& archive_path, 103 const FilePath& archive_path,
115 const FilePath& temp_path, 104 const FilePath& temp_path,
116 const Version& new_version, 105 const Version& new_version,
117 WorkItemList* install_list, 106 WorkItemList* install_list) {
118 const Package& package) {
119 DCHECK(install_list); 107 DCHECK(install_list);
120 FilePath installer_dir(package.GetInstallerDirectory(new_version)); 108 FilePath installer_dir(installer_state.GetInstallerDirectory(new_version));
121 install_list->AddCreateDirWorkItem(installer_dir); 109 install_list->AddCreateDirWorkItem(installer_dir);
122 110
123 FilePath exe_dst(installer_dir.Append(setup_path.BaseName())); 111 FilePath exe_dst(installer_dir.Append(setup_path.BaseName()));
124 FilePath archive_dst(installer_dir.Append(archive_path.BaseName())); 112 FilePath archive_dst(installer_dir.Append(archive_path.BaseName()));
125 113
126 install_list->AddCopyTreeWorkItem(setup_path.value(), exe_dst.value(), 114 install_list->AddCopyTreeWorkItem(setup_path.value(), exe_dst.value(),
127 temp_path.value(), WorkItem::ALWAYS); 115 temp_path.value(), WorkItem::ALWAYS);
128 if (package.system_level()) { 116 if (installer_state.system_install()) {
129 install_list->AddCopyTreeWorkItem(archive_path.value(), archive_dst.value(), 117 install_list->AddCopyTreeWorkItem(archive_path.value(), archive_dst.value(),
130 temp_path.value(), WorkItem::ALWAYS); 118 temp_path.value(), WorkItem::ALWAYS);
131 } else { 119 } else {
132 install_list->AddMoveTreeWorkItem(archive_path.value(), archive_dst.value(), 120 install_list->AddMoveTreeWorkItem(archive_path.value(), archive_dst.value(),
133 temp_path.value()); 121 temp_path.value());
134 } 122 }
135 } 123 }
136 124
137 // This method adds work items to create (or update) Chrome uninstall entry in 125 // This method adds work items to create (or update) Chrome uninstall entry in
138 // either the Control Panel->Add/Remove Programs list or in the Omaha client 126 // either the Control Panel->Add/Remove Programs list or in the Omaha client
139 // state key if running under an MSI installer. 127 // state key if running under an MSI installer.
140 void AddUninstallShortcutWorkItems(const FilePath& setup_path, 128 void AddUninstallShortcutWorkItems(const InstallerState& installer_state,
129 const FilePath& setup_path,
141 const Version& new_version, 130 const Version& new_version,
142 WorkItemList* install_list, 131 WorkItemList* install_list,
143 const Product& product) { 132 const Product& product) {
144 HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE : 133 HKEY reg_root = installer_state.root_key();
145 HKEY_CURRENT_USER;
146 BrowserDistribution* browser_dist = product.distribution(); 134 BrowserDistribution* browser_dist = product.distribution();
147 DCHECK(browser_dist); 135 DCHECK(browser_dist);
148 136
149 // When we are installed via an MSI, we need to store our uninstall strings 137 // When we are installed via an MSI, we need to store our uninstall strings
150 // in the Google Update client state key. We do this even for non-MSI 138 // in the Google Update client state key. We do this even for non-MSI
151 // managed installs to avoid breaking the edge case whereby an MSI-managed 139 // managed installs to avoid breaking the edge case whereby an MSI-managed
152 // install is updated by a non-msi installer (which would confuse the MSI 140 // install is updated by a non-msi installer (which would confuse the MSI
153 // machinery if these strings were not also updated). 141 // machinery if these strings were not also updated).
154 // Do not quote the command line for the MSI invocation. 142 // Do not quote the command line for the MSI invocation.
155 FilePath install_path(product.package().path()); 143 FilePath install_path(installer_state.target_path());
156 FilePath installer_path( 144 FilePath installer_path(installer_state.GetInstallerDirectory(new_version));
157 product.package().GetInstallerDirectory(new_version));
158 installer_path = installer_path.Append(setup_path.BaseName()); 145 installer_path = installer_path.Append(setup_path.BaseName());
159 146
160 CommandLine uninstall_arguments(CommandLine::NO_PROGRAM); 147 CommandLine uninstall_arguments(CommandLine::NO_PROGRAM);
161 AppendUninstallCommandLineFlags(&uninstall_arguments, product); 148 AppendUninstallCommandLineFlags(installer_state, product,
149 &uninstall_arguments);
162 150
163 if (product.is_chrome()) { 151 // The Chrome uninstallation command serves as the master uninstall command
164 // The Chrome uninstallation command serves as the master uninstall 152 // for Chrome + all other products (i.e. Chrome Frame) that do not have an
165 // command for Chrome + all other products (i.e. Chrome Frame) that do 153 // uninstall entry in the Add/Remove Programs dialog. We skip this processing
166 // not have an uninstall entry in the Add/Remove Programs dialog. 154 // in case of uninstall since this means that Chrome Frame is being
167 const Products& products = product.package().products(); 155 // uninstalled, so there's no need to do any looping.
156 if (product.is_chrome() &&
157 (installer_state.operation() != InstallerState::UNINSTALL)) {
158 const Products& products = installer_state.products();
168 for (size_t i = 0; i < products.size(); ++i) { 159 for (size_t i = 0; i < products.size(); ++i) {
169 const Product& p = *products[i]; 160 const Product& p = *products[i];
170 if (!p.is_chrome() && !p.ShouldCreateUninstallEntry()) { 161 if (!p.is_chrome() && !p.ShouldCreateUninstallEntry())
171 p.distribution()->AppendUninstallCommandLineFlags(&uninstall_arguments); 162 p.AppendProductFlags(&uninstall_arguments);
172 }
173 } 163 }
174 } 164 }
175 165
176 std::wstring update_state_key(browser_dist->GetStateKey()); 166 std::wstring update_state_key(browser_dist->GetStateKey());
177 install_list->AddCreateRegKeyWorkItem(reg_root, update_state_key); 167 install_list->AddCreateRegKeyWorkItem(reg_root, update_state_key);
178 install_list->AddSetRegValueWorkItem(reg_root, update_state_key, 168 install_list->AddSetRegValueWorkItem(reg_root, update_state_key,
179 installer::kUninstallStringField, installer_path.value(), true); 169 installer::kUninstallStringField, installer_path.value(), true);
180 install_list->AddSetRegValueWorkItem(reg_root, update_state_key, 170 install_list->AddSetRegValueWorkItem(reg_root, update_state_key,
181 installer::kUninstallArgumentsField, 171 installer::kUninstallArgumentsField,
182 uninstall_arguments.command_line_string(), true); 172 uninstall_arguments.command_line_string(), true);
183 173
184 if (product.ShouldCreateUninstallEntry()) { 174 // MSI installations will manage their own uninstall shortcuts.
175 if (!installer_state.msi() && product.ShouldCreateUninstallEntry()) {
185 // We need to quote the command line for the Add/Remove Programs dialog. 176 // We need to quote the command line for the Add/Remove Programs dialog.
186 CommandLine quoted_uninstall_cmd(installer_path); 177 CommandLine quoted_uninstall_cmd(installer_path);
187 DCHECK_EQ(quoted_uninstall_cmd.command_line_string()[0], '"'); 178 DCHECK_EQ(quoted_uninstall_cmd.command_line_string()[0], '"');
188 quoted_uninstall_cmd.AppendArguments(uninstall_arguments, false); 179 quoted_uninstall_cmd.AppendArguments(uninstall_arguments, false);
189 180
190 std::wstring uninstall_reg = browser_dist->GetUninstallRegPath(); 181 std::wstring uninstall_reg = browser_dist->GetUninstallRegPath();
191 install_list->AddCreateRegKeyWorkItem(reg_root, uninstall_reg); 182 install_list->AddCreateRegKeyWorkItem(reg_root, uninstall_reg);
192 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, 183 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
193 installer::kUninstallDisplayNameField, 184 installer::kUninstallDisplayNameField,
194 browser_dist->GetAppShortCutName(), true); 185 browser_dist->GetAppShortCutName(), true);
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, 225 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
235 L"InstallDate", 226 L"InstallDate",
236 buffer, false); 227 buffer, false);
237 } 228 }
238 } 229 }
239 } 230 }
240 231
241 // Create Version key for a product (if not already present) and sets the new 232 // Create Version key for a product (if not already present) and sets the new
242 // product version as the last step. 233 // product version as the last step.
243 void AddVersionKeyWorkItems(HKEY root, 234 void AddVersionKeyWorkItems(HKEY root,
244 const Product& product, 235 BrowserDistribution* dist,
245 const Version& new_version, 236 const Version& new_version,
246 WorkItemList* list) { 237 WorkItemList* list) {
247 // Create Version key for each distribution (if not already present) and set 238 // Create Version key for each distribution (if not already present) and set
248 // the new product version as the last step. 239 // the new product version as the last step.
249 std::wstring version_key(product.distribution()->GetVersionKey()); 240 std::wstring version_key(dist->GetVersionKey());
250 list->AddCreateRegKeyWorkItem(root, version_key); 241 list->AddCreateRegKeyWorkItem(root, version_key);
251 242
252 std::wstring product_name(product.distribution()->GetAppShortCutName()); 243 std::wstring product_name(dist->GetAppShortCutName());
253 list->AddSetRegValueWorkItem(root, version_key, google_update::kRegNameField, 244 list->AddSetRegValueWorkItem(root, version_key, google_update::kRegNameField,
254 product_name, true); // overwrite name also 245 product_name, true); // overwrite name also
255 list->AddSetRegValueWorkItem(root, version_key, 246 list->AddSetRegValueWorkItem(root, version_key,
256 google_update::kRegOopcrashesField, 247 google_update::kRegOopcrashesField,
257 static_cast<DWORD>(1), 248 static_cast<DWORD>(1),
258 false); // set during first install 249 false); // set during first install
259 list->AddSetRegValueWorkItem(root, version_key, 250 list->AddSetRegValueWorkItem(root, version_key,
260 google_update::kRegVersionField, 251 google_update::kRegVersionField,
261 UTF8ToWide(new_version.GetString()), 252 UTF8ToWide(new_version.GetString()),
262 true); // overwrite version 253 true); // overwrite version
263 } 254 }
264 255
265 void AddProductSpecificWorkItems(bool install, 256 void AddProductSpecificWorkItems(const InstallationState& original_state,
257 const InstallerState& installer_state,
266 const FilePath& setup_path, 258 const FilePath& setup_path,
267 const Version& new_version, 259 const Version& new_version,
268 const Package& package,
269 WorkItemList* list) { 260 WorkItemList* list) {
270 const Products& products = package.products(); 261 const Products& products = installer_state.products();
271 for (size_t i = 0; i < products.size(); ++i) { 262 for (size_t i = 0; i < products.size(); ++i) {
272 const Product& p = *products[i]; 263 const Product& p = *products[i];
273 if (p.is_chrome_frame()) { 264 if (p.is_chrome_frame()) {
274 AddChromeFrameWorkItems(install, setup_path, new_version, p, list); 265 AddChromeFrameWorkItems(original_state, installer_state, setup_path,
266 new_version, p, list);
275 } 267 }
276 } 268 }
277 } 269 }
278 270
279 // Adds work items that make registry adjustments for Google Update. When a 271 // Adds work items that make registry adjustments for Google Update. When a
280 // product is installed (including overinstall), Google Update will write the 272 // product is installed (including overinstall), Google Update will write the
281 // channel ("ap") value into either Chrome or Chrome Frame's ClientState key. 273 // channel ("ap") value into either Chrome or Chrome Frame's ClientState key.
282 // In the multi-install case, this value is used as the basis upon which the 274 // In the multi-install case, this value is used as the basis upon which the
283 // package's channel value is built (by adding the ordered list of installed 275 // package's channel value is built (by adding the ordered list of installed
284 // products and their options). 276 // products and their options).
285 void AddGoogleUpdateWorkItems(const InstallationState& original_state, 277 void AddGoogleUpdateWorkItems(const InstallerState& installer_state,
286 const InstallerState& installer_state,
287 const Package& package,
288 WorkItemList* install_list) { 278 WorkItemList* install_list) {
289 // Is a multi-install product being installed or over-installed? 279 // Is a multi-install product being installed or over-installed?
290 if (installer_state.operation() != InstallerState::MULTI_INSTALL) 280 if (installer_state.operation() != InstallerState::MULTI_INSTALL)
291 return; 281 return;
292 282
293 const HKEY reg_root = package.system_level() ? HKEY_LOCAL_MACHINE : 283 const HKEY reg_root = installer_state.root_key();
294 HKEY_CURRENT_USER;
295 const std::wstring key_path = installer_state.state_key(); 284 const std::wstring key_path = installer_state.state_key();
296 ChannelInfo channel_info; 285 ChannelInfo channel_info;
297 286
298 // Update the "ap" value for the product being installed/updated. 287 // Update the "ap" value for the product being installed/updated.
299 // It is completely acceptable for there to be no "ap" value or even no 288 // It is completely acceptable for there to be no "ap" value or even no
300 // ClientState key. Note that we check the registry rather than 289 // ClientState key. Note that we check the registry rather than an
301 // original_state since on a fresh install the "ap" value will be present 290 // InstallationState instance since on a fresh install the "ap" value will be
302 // sans "pv" value. 291 // present sans "pv" value.
303 channel_info.Initialize(RegKey(reg_root, key_path.c_str(), KEY_QUERY_VALUE)); 292 channel_info.Initialize(RegKey(reg_root, key_path.c_str(), KEY_QUERY_VALUE));
304 293
305 // This is a multi-install product. 294 // This is a multi-install product.
306 bool modified = channel_info.SetMultiInstall(true); 295 bool modified = channel_info.SetMultiInstall(true);
307 296
308 // Add the appropriate modifiers for all products and their options. 297 // Add the appropriate modifiers for all products and their options.
309 Products::const_iterator scan = package.products().begin(); 298 modified |= installer_state.SetChannelFlags(true, &channel_info);
310 const Products::const_iterator end = package.products().end();
311 for (; scan != end; ++scan) {
312 modified |= scan->get()->distribution()->SetChannelFlags(true,
313 &channel_info);
314 }
315 299
316 // Write the results if needed. 300 // Write the results if needed.
317 if (modified) { 301 if (modified) {
318 install_list->AddSetRegValueWorkItem(reg_root, key_path, 302 install_list->AddSetRegValueWorkItem(reg_root, key_path,
319 google_update::kRegApField, 303 google_update::kRegApField,
320 channel_info.value(), true); 304 channel_info.value(), true);
321 } 305 }
322 306
323 // Synchronize the other products and the package with this one. 307 // Synchronize the other products and the package with this one.
324 std::wstring other_key; 308 std::wstring other_key;
325 std::vector<std::wstring> keys; 309 std::vector<std::wstring> keys;
326 310
327 keys.reserve(package.products().size()); 311 keys.reserve(installer_state.products().size());
328 other_key = package.properties()->GetStateKey(); 312 other_key =
313 installer_state.multi_package_binaries_distribution()->GetStateKey();
329 if (other_key != key_path) 314 if (other_key != key_path)
330 keys.push_back(other_key); 315 keys.push_back(other_key);
331 scan = package.products().begin(); 316 Products::const_iterator scan = installer_state.products().begin();
317 Products::const_iterator end = installer_state.products().end();
332 for (; scan != end; ++scan) { 318 for (; scan != end; ++scan) {
333 other_key = scan->get()->distribution()->GetStateKey(); 319 other_key = (*scan)->distribution()->GetStateKey();
334 if (other_key != key_path) 320 if (other_key != key_path)
335 keys.push_back(other_key); 321 keys.push_back(other_key);
336 } 322 }
337 323
338 RegKey key; 324 RegKey key;
339 ChannelInfo other_info; 325 ChannelInfo other_info;
340 std::vector<std::wstring>::const_iterator kscan = keys.begin(); 326 std::vector<std::wstring>::const_iterator kscan = keys.begin();
341 std::vector<std::wstring>::const_iterator kend = keys.end(); 327 std::vector<std::wstring>::const_iterator kend = keys.end();
342 for (; kscan != kend; ++kscan) { 328 for (; kscan != kend; ++kscan) {
343 // Handle the case where the ClientState key doesn't exist by creating it. 329 // Handle the case where the ClientState key doesn't exist by creating it.
(...skipping 13 matching lines...) Expand all
357 } 343 }
358 // TODO(grt): check for other keys/values we should put in the package's 344 // TODO(grt): check for other keys/values we should put in the package's
359 // ClientState and/or Clients key. 345 // ClientState and/or Clients key.
360 } 346 }
361 347
362 // This is called when an MSI installation is run. It may be that a user is 348 // This is called when an MSI installation is run. It may be that a user is
363 // attempting to install the MSI on top of a non-MSI managed installation. 349 // attempting to install the MSI on top of a non-MSI managed installation.
364 // If so, try and remove any existing uninstallation shortcuts, as we want the 350 // If so, try and remove any existing uninstallation shortcuts, as we want the
365 // uninstall to be managed entirely by the MSI machinery (accessible via the 351 // uninstall to be managed entirely by the MSI machinery (accessible via the
366 // Add/Remove programs dialog). 352 // Add/Remove programs dialog).
367 void AddDeleteUninstallShortcutsForMSIWorkItems(const Product& product, 353 void AddDeleteUninstallShortcutsForMSIWorkItems(
368 WorkItemList* work_item_list) { 354 const InstallerState& installer_state,
369 DCHECK(product.IsMsi()) << "This must only be called for MSI installations!"; 355 const Product& product,
356 WorkItemList* work_item_list) {
357 DCHECK(installer_state.msi())
358 << "This must only be called for MSI installations!";
370 359
371 // First attempt to delete the old installation's ARP dialog entry. 360 // First attempt to delete the old installation's ARP dialog entry.
372 HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE : 361 HKEY reg_root = installer_state.root_key();
373 HKEY_CURRENT_USER;
374 base::win::RegKey root_key(reg_root, L"", KEY_ALL_ACCESS);
375 std::wstring uninstall_reg(product.distribution()->GetUninstallRegPath()); 362 std::wstring uninstall_reg(product.distribution()->GetUninstallRegPath());
376 363
377 WorkItem* delete_reg_key = work_item_list->AddDeleteRegKeyWorkItem( 364 WorkItem* delete_reg_key = work_item_list->AddDeleteRegKeyWorkItem(
378 reg_root, uninstall_reg); 365 reg_root, uninstall_reg);
379 delete_reg_key->set_ignore_failure(true); 366 delete_reg_key->set_ignore_failure(true);
380 367
381 // Then attempt to delete the old installation's start menu shortcut. 368 // Then attempt to delete the old installation's start menu shortcut.
382 FilePath uninstall_link; 369 FilePath uninstall_link;
383 if (product.system_level()) { 370 if (installer_state.system_install()) {
384 PathService::Get(base::DIR_COMMON_START_MENU, &uninstall_link); 371 PathService::Get(base::DIR_COMMON_START_MENU, &uninstall_link);
385 } else { 372 } else {
386 PathService::Get(base::DIR_START_MENU, &uninstall_link); 373 PathService::Get(base::DIR_START_MENU, &uninstall_link);
387 } 374 }
388 375
389 if (uninstall_link.empty()) { 376 if (uninstall_link.empty()) {
390 LOG(ERROR) << "Failed to get location for shortcut."; 377 LOG(ERROR) << "Failed to get location for shortcut.";
391 } else { 378 } else {
392 uninstall_link = uninstall_link.Append( 379 uninstall_link = uninstall_link.Append(
393 product.distribution()->GetAppShortCutName()); 380 product.distribution()->GetAppShortCutName());
(...skipping 11 matching lines...) Expand all
405 392
406 // After a successful copying of all the files, this function is called to 393 // After a successful copying of all the files, this function is called to
407 // do a few post install tasks: 394 // do a few post install tasks:
408 // - Handle the case of in-use-update by updating "opv" (old version) key or 395 // - Handle the case of in-use-update by updating "opv" (old version) key or
409 // deleting it if not required. 396 // deleting it if not required.
410 // - Register any new dlls and unregister old dlls. 397 // - Register any new dlls and unregister old dlls.
411 // - If this is an MSI install, ensures that the MSI marker is set, and sets 398 // - If this is an MSI install, ensures that the MSI marker is set, and sets
412 // it if not. 399 // it if not.
413 // If these operations are successful, the function returns true, otherwise 400 // If these operations are successful, the function returns true, otherwise
414 // false. 401 // false.
415 bool AppendPostInstallTasks(bool multi_install, 402 bool AppendPostInstallTasks(const InstallerState& installer_state,
416 const FilePath& setup_path, 403 const FilePath& setup_path,
417 const FilePath& new_chrome_exe, 404 const FilePath& new_chrome_exe,
418 const Version* current_version, 405 const Version* current_version,
419 const Version& new_version, 406 const Version& new_version,
420 const Package& package,
421 WorkItemList* post_install_task_list) { 407 WorkItemList* post_install_task_list) {
422 DCHECK(post_install_task_list); 408 DCHECK(post_install_task_list);
423 HKEY root = package.system_level() ? HKEY_LOCAL_MACHINE :
424 HKEY_CURRENT_USER;
425 const Products& products = package.products();
426 409
410 HKEY root = installer_state.root_key();
411 const Products& products = installer_state.products();
412 BrowserDistribution* dist = installer_state.multi_install() ?
413 installer_state.multi_package_binaries_distribution() :
414 products[0]->distribution();
415 std::wstring version_key(dist->GetVersionKey());
427 416
428 // Append work items that will only be executed if this was an update. 417 // Append work items that will only be executed if this was an update.
429 // We update the 'opv' key with the current version that is active and 'cmd' 418 // We update the 'opv' key with the current version that is active and 'cmd'
430 // key with the rename command to run. 419 // key with the rename command to run.
431 { 420 {
432 scoped_ptr<WorkItemList> in_use_update_work_items( 421 scoped_ptr<WorkItemList> in_use_update_work_items(
433 WorkItem::CreateConditionalWorkItemList( 422 WorkItem::CreateConditionalWorkItemList(
434 new ConditionRunIfFileExists(new_chrome_exe))); 423 new ConditionRunIfFileExists(new_chrome_exe)));
435 in_use_update_work_items->set_log_message("InUseUpdateWorkItemList"); 424 in_use_update_work_items->set_log_message("InUseUpdateWorkItemList");
436 425
437 FilePath installer_path(package.GetInstallerDirectory(new_version) 426 FilePath installer_path(installer_state.GetInstallerDirectory(new_version)
438 .Append(setup_path.BaseName())); 427 .Append(setup_path.BaseName()));
439 428
440 CommandLine rename(installer_path); 429 CommandLine rename(installer_path);
441 rename.AppendSwitch(installer::switches::kRenameChromeExe); 430 rename.AppendSwitch(installer::switches::kRenameChromeExe);
442 if (package.system_level()) 431 if (installer_state.system_install())
443 rename.AppendSwitch(installer::switches::kSystemLevel); 432 rename.AppendSwitch(installer::switches::kSystemLevel);
444 433
445 if (InstallUtil::IsChromeSxSProcess()) 434 if (InstallUtil::IsChromeSxSProcess())
446 rename.AppendSwitch(installer::switches::kChromeSxS); 435 rename.AppendSwitch(installer::switches::kChromeSxS);
447 436
448 if (multi_install) 437 if (installer_state.multi_install())
449 rename.AppendSwitch(installer::switches::kMultiInstall); 438 rename.AppendSwitch(installer::switches::kMultiInstall);
450 439
451 std::wstring version_key; 440 if (current_version != NULL) {
452 for (size_t i = 0; i < products.size(); ++i) { 441 in_use_update_work_items->AddSetRegValueWorkItem(root, version_key,
453 BrowserDistribution* dist = products[i]->distribution(); 442 google_update::kRegOldVersionField,
454 version_key = dist->GetVersionKey(); 443 UTF8ToWide(current_version->GetString()), true);
455
456 if (current_version != NULL) {
457 in_use_update_work_items->AddSetRegValueWorkItem(root, version_key,
458 google_update::kRegOldVersionField,
459 UTF8ToWide(current_version->GetString()), true);
460 }
461
462 // Adding this registry entry for all products is overkill.
463 // However, as it stands, we don't have a way to know which distribution
464 // will check the key and run the command, so we add it for all.
465 // After the first run, the subsequent runs should just be noops.
466 // (see Upgrade::SwapNewChromeExeIfPresent).
467 in_use_update_work_items->AddSetRegValueWorkItem(
468 root,
469 version_key,
470 google_update::kRegRenameCmdField,
471 rename.command_line_string(),
472 true);
473 } 444 }
474 445
475 if (multi_install) { 446 in_use_update_work_items->AddSetRegValueWorkItem(
476 PackageProperties* props = package.properties(); 447 root,
477 if (props->ReceivesUpdates() && current_version != NULL) { 448 version_key,
478 in_use_update_work_items->AddSetRegValueWorkItem( 449 google_update::kRegRenameCmdField,
479 root, 450 rename.command_line_string(),
480 props->GetVersionKey(), 451 true);
481 google_update::kRegOldVersionField, 452
482 UTF8ToWide(current_version->GetString()), 453 // Unconditionally delete the "opv" and "cmd" values from all product keys
483 true); 454 // so that we clean up from any migrations from single- to multi-install.
484 // TODO(tommi): We should move the rename command here. We also need to 455 if (installer_state.multi_install()) {
485 // update Upgrade::SwapNewChromeExeIfPresent. 456 Products::const_iterator scan = products.begin();
457 const Products::const_iterator end = products.end();
458 for (; scan != end; ++scan) {
459 BrowserDistribution* dist = (*scan)->distribution();
460 version_key = dist->GetVersionKey();
461 in_use_update_work_items->AddDeleteRegValueWorkItem(root, version_key,
462 google_update::kRegOldVersionField);
463 in_use_update_work_items->AddDeleteRegValueWorkItem(root, version_key,
464 google_update::kRegRenameCmdField);
486 } 465 }
487 } 466 }
488 467
489 post_install_task_list->AddWorkItem(in_use_update_work_items.release()); 468 post_install_task_list->AddWorkItem(in_use_update_work_items.release());
490 } 469 }
491 470
471
492 // Append work items that will be executed if this was NOT an in-use update. 472 // Append work items that will be executed if this was NOT an in-use update.
493 { 473 {
494 scoped_ptr<WorkItemList> regular_update_work_items( 474 scoped_ptr<WorkItemList> regular_update_work_items(
495 WorkItem::CreateConditionalWorkItemList( 475 WorkItem::CreateConditionalWorkItemList(
496 new Not(new ConditionRunIfFileExists(new_chrome_exe)))); 476 new Not(new ConditionRunIfFileExists(new_chrome_exe))));
497 regular_update_work_items->set_log_message( 477 regular_update_work_items->set_log_message("RegularUpdateWorkItemList");
498 "RegularUpdateWorkItemList");
499 478
500 // Since this was not an in-use-update, delete 'opv' and 'cmd' keys. 479 // Since this was not an in-use-update, delete 'opv' and 'cmd' keys.
480 // Delete from all products to handle migration from single- to multi-
481 std::wstring version_key;
501 for (size_t i = 0; i < products.size(); ++i) { 482 for (size_t i = 0; i < products.size(); ++i) {
502 BrowserDistribution* dist = products[i]->distribution(); 483 BrowserDistribution* dist = products[i]->distribution();
503 std::wstring version_key(dist->GetVersionKey()); 484 version_key = dist->GetVersionKey();
485 regular_update_work_items->AddDeleteRegValueWorkItem(root, version_key,
486 google_update::kRegOldVersionField);
487 regular_update_work_items->AddDeleteRegValueWorkItem(root, version_key,
488 google_update::kRegRenameCmdField);
489 }
490 if (installer_state.multi_install()) {
491 version_key =
492 installer_state.multi_package_binaries_distribution()->GetVersionKey();
504 regular_update_work_items->AddDeleteRegValueWorkItem(root, version_key, 493 regular_update_work_items->AddDeleteRegValueWorkItem(root, version_key,
505 google_update::kRegOldVersionField); 494 google_update::kRegOldVersionField);
506 regular_update_work_items->AddDeleteRegValueWorkItem(root, version_key, 495 regular_update_work_items->AddDeleteRegValueWorkItem(root, version_key,
507 google_update::kRegRenameCmdField); 496 google_update::kRegRenameCmdField);
508 } 497 }
509 498
510 post_install_task_list->AddWorkItem(regular_update_work_items.release()); 499 post_install_task_list->AddWorkItem(regular_update_work_items.release());
511 } 500 }
512 501
513 AddRegisterComDllWorkItemsForPackage(package, current_version, new_version, 502 AddRegisterComDllWorkItemsForPackage(installer_state, current_version,
514 post_install_task_list); 503 new_version, post_install_task_list);
515 504
516 for (size_t i = 0; i < products.size(); ++i) { 505 // If we're told that we're an MSI install, make sure to set the marker
517 const Product* product = products[i]; 506 // in the client state key so that future updates do the right thing.
518 // If we're told that we're an MSI install, make sure to set the marker 507 if (installer_state.msi()) {
519 // in the client state key so that future updates do the right thing. 508 for (size_t i = 0; i < products.size(); ++i) {
520 if (product->IsMsi()) { 509 const Product* product = products[i];
521 AddSetMsiMarkerWorkItem(*product, true, post_install_task_list); 510 AddSetMsiMarkerWorkItem(installer_state, product->distribution(), true,
511 post_install_task_list);
522 512
523 // We want MSI installs to take over the Add/Remove Programs shortcut. 513 // We want MSI installs to take over the Add/Remove Programs shortcut.
524 // Make a best-effort attempt to delete any shortcuts left over from 514 // Make a best-effort attempt to delete any shortcuts left over from
525 // previous non-MSI installations for the same type of install (system or 515 // previous non-MSI installations for the same type of install (system or
526 // per user). 516 // per user).
527 AddDeleteUninstallShortcutsForMSIWorkItems(*product, 517 AddDeleteUninstallShortcutsForMSIWorkItems(installer_state, *product,
528 post_install_task_list); 518 post_install_task_list);
529 } 519 }
520 if (installer_state.multi_install()) {
521 AddSetMsiMarkerWorkItem(installer_state,
522 installer_state.multi_package_binaries_distribution(), true,
523 post_install_task_list);
524 }
530 } 525 }
531 526
532 return true; 527 return true;
533 } 528 }
534 529
535 void AddInstallWorkItems(const InstallationState& original_state, 530 void AddInstallWorkItems(const InstallationState& original_state,
536 const InstallerState& installer_state, 531 const InstallerState& installer_state,
537 bool multi_install,
538 const FilePath& setup_path, 532 const FilePath& setup_path,
539 const FilePath& archive_path, 533 const FilePath& archive_path,
540 const FilePath& src_path, 534 const FilePath& src_path,
541 const FilePath& temp_dir, 535 const FilePath& temp_dir,
542 const Version& new_version, 536 const Version& new_version,
543 scoped_ptr<Version>* current_version, 537 scoped_ptr<Version>* current_version,
544 const Package& package,
545 WorkItemList* install_list) { 538 WorkItemList* install_list) {
546 DCHECK(install_list); 539 DCHECK(install_list);
547 540
541 const FilePath& target_path = installer_state.target_path();
542
548 // A temp directory that work items need and the actual install directory. 543 // A temp directory that work items need and the actual install directory.
549 install_list->AddCreateDirWorkItem(temp_dir); 544 install_list->AddCreateDirWorkItem(temp_dir);
550 install_list->AddCreateDirWorkItem(package.path()); 545 install_list->AddCreateDirWorkItem(target_path);
551 546
552 // Delete any new_chrome.exe if present (we will end up creating a new one 547 // Delete any new_chrome.exe if present (we will end up creating a new one
553 // if required) and then copy chrome.exe 548 // if required) and then copy chrome.exe
554 FilePath new_chrome_exe( 549 FilePath new_chrome_exe(
555 package.path().Append(installer::kChromeNewExe)); 550 target_path.Append(installer::kChromeNewExe));
556 551
557 install_list->AddDeleteTreeWorkItem(new_chrome_exe); 552 install_list->AddDeleteTreeWorkItem(new_chrome_exe);
558 install_list->AddCopyTreeWorkItem( 553 install_list->AddCopyTreeWorkItem(
559 src_path.Append(installer::kChromeExe).value(), 554 src_path.Append(installer::kChromeExe).value(),
560 package.path().Append(installer::kChromeExe).value(), 555 target_path.Append(installer::kChromeExe).value(),
561 temp_dir.value(), WorkItem::NEW_NAME_IF_IN_USE, new_chrome_exe.value()); 556 temp_dir.value(), WorkItem::NEW_NAME_IF_IN_USE, new_chrome_exe.value());
562 557
563 // Extra executable for 64 bit systems. 558 // Extra executable for 64 bit systems.
564 if (Is64bit()) { 559 if (Is64bit()) {
565 install_list->AddCopyTreeWorkItem( 560 install_list->AddCopyTreeWorkItem(
566 src_path.Append(installer::kWowHelperExe).value(), 561 src_path.Append(installer::kWowHelperExe).value(),
567 package.path().Append(installer::kWowHelperExe).value(), 562 target_path.Append(installer::kWowHelperExe).value(),
568 temp_dir.value(), WorkItem::ALWAYS); 563 temp_dir.value(), WorkItem::ALWAYS);
569 } 564 }
570 565
571 // If it is system level install copy the version folder (since we want to 566 // If it is system level install copy the version folder (since we want to
572 // take the permissions of %ProgramFiles% folder) otherwise just move it. 567 // take the permissions of %ProgramFiles% folder) otherwise just move it.
573 if (package.system_level()) { 568 if (installer_state.system_install()) {
574 install_list->AddCopyTreeWorkItem( 569 install_list->AddCopyTreeWorkItem(
575 src_path.Append(UTF8ToWide(new_version.GetString())).value(), 570 src_path.Append(UTF8ToWide(new_version.GetString())).value(),
576 package.path().Append(UTF8ToWide(new_version.GetString())).value(), 571 target_path.Append(UTF8ToWide(new_version.GetString())).value(),
577 temp_dir.value(), WorkItem::ALWAYS); 572 temp_dir.value(), WorkItem::ALWAYS);
578 } else { 573 } else {
579 install_list->AddMoveTreeWorkItem( 574 install_list->AddMoveTreeWorkItem(
580 src_path.Append(UTF8ToWide(new_version.GetString())).value(), 575 src_path.Append(UTF8ToWide(new_version.GetString())).value(),
581 package.path().Append(UTF8ToWide(new_version.GetString())).value(), 576 target_path.Append(UTF8ToWide(new_version.GetString())).value(),
582 temp_dir.value()); 577 temp_dir.value());
583 } 578 }
584 579
585 // Copy the default Dictionaries only if the folder doesn't exist already. 580 // Copy the default Dictionaries only if the folder doesn't exist already.
586 install_list->AddCopyTreeWorkItem( 581 install_list->AddCopyTreeWorkItem(
587 src_path.Append(installer::kDictionaries).value(), 582 src_path.Append(installer::kDictionaries).value(),
588 package.path().Append(installer::kDictionaries).value(), 583 target_path.Append(installer::kDictionaries).value(),
589 temp_dir.value(), WorkItem::IF_NOT_PRESENT); 584 temp_dir.value(), WorkItem::IF_NOT_PRESENT);
590 585
591 // Delete any old_chrome.exe if present. 586 // Delete any old_chrome.exe if present.
592 install_list->AddDeleteTreeWorkItem( 587 install_list->AddDeleteTreeWorkItem(
593 package.path().Append(installer::kChromeOldExe)); 588 target_path.Append(installer::kChromeOldExe));
594 589
595 // Copy installer in install directory and 590 // Copy installer in install directory and
596 // add shortcut in Control Panel->Add/Remove Programs. 591 // add shortcut in Control Panel->Add/Remove Programs.
597 AddInstallerCopyTasks(setup_path, archive_path, temp_dir, new_version, 592 AddInstallerCopyTasks(installer_state, setup_path, archive_path, temp_dir,
598 install_list, package); 593 new_version, install_list);
599 594
600 HKEY root = package.system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 595 const HKEY root = installer_state.root_key();
601 596
602 const Products& products = package.products(); 597 const Products& products = installer_state.products();
603 for (size_t i = 0; i < products.size(); ++i) { 598 for (size_t i = 0; i < products.size(); ++i) {
604 const Product* product = products[i]; 599 const Product* product = products[i];
605 600
606 AddUninstallShortcutWorkItems(setup_path, new_version, install_list, 601 AddUninstallShortcutWorkItems(installer_state, setup_path, new_version,
607 *product); 602 install_list, *product);
608 603
609 AddVersionKeyWorkItems(root, *product, new_version, install_list); 604 AddVersionKeyWorkItems(root, product->distribution(), new_version,
605 install_list);
610 } 606 }
611 607
612 if (multi_install) { 608 if (installer_state.multi_install()) {
613 PackageProperties* props = package.properties(); 609 AddVersionKeyWorkItems(root,
614 if (props->ReceivesUpdates()) { 610 installer_state.multi_package_binaries_distribution(), new_version,
615 std::wstring version_key(props->GetVersionKey()); 611 install_list);
616 install_list->AddCreateRegKeyWorkItem(root, version_key);
617 install_list->AddSetRegValueWorkItem(root, version_key,
618 google_update::kRegVersionField,
619 UTF8ToWide(new_version.GetString()),
620 true); // overwrite version
621 install_list->AddSetRegValueWorkItem(root, version_key,
622 google_update::kRegNameField,
623 ASCIIToWide(installer::PackageProperties::kPackageProductName),
624 true); // overwrite name also
625 }
626 } 612 }
627 613
628 // Add any remaining work items that involve special settings for 614 // Add any remaining work items that involve special settings for
629 // each product. 615 // each product.
630 AddProductSpecificWorkItems(true, setup_path, new_version, package, 616 AddProductSpecificWorkItems(original_state, installer_state, setup_path,
631 install_list); 617 new_version, install_list);
632 618
633 AddGoogleUpdateWorkItems(original_state, installer_state, package, 619 AddGoogleUpdateWorkItems(installer_state, install_list);
634 install_list);
635 620
636 // Append the tasks that run after the installation. 621 // Append the tasks that run after the installation.
637 AppendPostInstallTasks(multi_install, 622 AppendPostInstallTasks(installer_state,
638 setup_path, 623 setup_path,
639 new_chrome_exe, 624 new_chrome_exe,
640 current_version->get(), 625 current_version->get(),
641 new_version, 626 new_version,
642 package,
643 install_list); 627 install_list);
644 } 628 }
645 629
646 void AddRegisterComDllWorkItems(const FilePath& dll_folder, 630 void AddRegisterComDllWorkItems(const FilePath& dll_folder,
647 const std::vector<FilePath>& dll_list, 631 const std::vector<FilePath>& dll_list,
648 bool system_level, 632 bool system_level,
649 bool do_register, 633 bool do_register,
650 bool ignore_failures, 634 bool ignore_failures,
651 WorkItemList* work_item_list) { 635 WorkItemList* work_item_list) {
652 DCHECK(work_item_list); 636 DCHECK(work_item_list);
653 if (dll_list.empty()) { 637 if (dll_list.empty()) {
654 VLOG(1) << "No COM DLLs to register"; 638 VLOG(1) << "No COM DLLs to register";
655 } else { 639 } else {
656 std::vector<FilePath>::const_iterator dll_iter(dll_list.begin()); 640 std::vector<FilePath>::const_iterator dll_iter(dll_list.begin());
657 for (; dll_iter != dll_list.end(); ++dll_iter) { 641 for (; dll_iter != dll_list.end(); ++dll_iter) {
658 FilePath dll_path = dll_folder.Append(*dll_iter); 642 FilePath dll_path = dll_folder.Append(*dll_iter);
659 WorkItem* work_item = work_item_list->AddSelfRegWorkItem( 643 WorkItem* work_item = work_item_list->AddSelfRegWorkItem(
660 dll_path.value(), do_register, !system_level); 644 dll_path.value(), do_register, !system_level);
661 DCHECK(work_item); 645 DCHECK(work_item);
662 work_item->set_ignore_failure(ignore_failures); 646 work_item->set_ignore_failure(ignore_failures);
663 } 647 }
664 } 648 }
665 } 649 }
666 650
667 void AddSetMsiMarkerWorkItem(const Product& product, 651 void AddSetMsiMarkerWorkItem(const InstallerState& installer_state,
652 BrowserDistribution* dist,
668 bool set, 653 bool set,
669 WorkItemList* work_item_list) { 654 WorkItemList* work_item_list) {
670 DCHECK(work_item_list); 655 DCHECK(work_item_list);
671 BrowserDistribution* dist = product.distribution();
672 HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE :
673 HKEY_CURRENT_USER;
674 DWORD msi_value = set ? 1 : 0; 656 DWORD msi_value = set ? 1 : 0;
675 WorkItem* set_msi_work_item = work_item_list->AddSetRegValueWorkItem( 657 WorkItem* set_msi_work_item = work_item_list->AddSetRegValueWorkItem(
676 reg_root, dist->GetStateKey(), google_update::kRegMSIField, 658 installer_state.root_key(), dist->GetStateKey(),
677 msi_value, true); 659 google_update::kRegMSIField, msi_value, true);
678 DCHECK(set_msi_work_item); 660 DCHECK(set_msi_work_item);
679 set_msi_work_item->set_ignore_failure(true); 661 set_msi_work_item->set_ignore_failure(true);
680 set_msi_work_item->set_log_message("Could not write MSI marker!"); 662 set_msi_work_item->set_log_message("Could not write MSI marker!");
681 } 663 }
682 664
683 void AddChromeFrameWorkItems(bool install, 665 void AddChromeFrameWorkItems(const InstallationState& original_state,
666 const InstallerState& installer_state,
684 const FilePath& setup_path, 667 const FilePath& setup_path,
685 const Version& new_version, 668 const Version& new_version,
686 const Product& product, 669 const Product& product,
687 WorkItemList* list) { 670 WorkItemList* list) {
688 DCHECK(product.is_chrome_frame()); 671 DCHECK(product.is_chrome_frame());
689 if (!product.package().multi_install()) { 672 if (!installer_state.multi_install()) {
690 VLOG(1) << "Not adding GCF specific work items for single install."; 673 VLOG(1) << "Not adding GCF specific work items for single install.";
691 return; 674 return;
692 } 675 }
693 676
694 const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess(); 677 std::wstring version_key(product.distribution()->GetVersionKey());
695 678 bool ready_mode = product.HasOption(kOptionReadyMode);
696 BrowserDistribution* cf = BrowserDistribution::GetSpecificDistribution( 679 HKEY root = installer_state.root_key();
697 BrowserDistribution::CHROME_FRAME, prefs); 680 const bool is_install =
698 std::wstring version_key(cf->GetVersionKey()); 681 (installer_state.operation() != InstallerState::UNINSTALL);
robertshield 2011/01/20 22:06:06 indent
grt (UTC plus 2) 2011/01/21 05:27:51 Done.
699
700 // TODO(tommi): This assumes we know exactly how ShouldCreateUninstallEntry
701 // is implemented. Since there is logic in ChromeFrameDistribution for how
702 // to determine when this is enabled, this is how we have to figure out if
703 // this feature is enabled right now, but it's a hack and we need a cleaner
704 // way to figure this out.
705 // Note that we cannot just check the master preferences for
706 // kChromeFrameReadyMode, since there are other things that need to be correct
707 // in the environment in order to enable this feature.
708 bool ready_mode = !product.distribution()->ShouldCreateUninstallEntry();
709
710 HKEY root = product.package().system_level() ? HKEY_LOCAL_MACHINE :
711 HKEY_CURRENT_USER;
712 bool update_chrome_uninstall_command = false; 682 bool update_chrome_uninstall_command = false;
683 BrowserDistribution* dist =
684 installer_state.multi_package_binaries_distribution();
713 if (ready_mode) { 685 if (ready_mode) {
714 // If GCF is being installed in ready mode, we write an entry to the 686 // If GCF is being installed in ready mode, we write an entry to the
715 // multi-install state key. If the value already exists, we will not 687 // multi-install state key. If the value already exists, we will not
716 // overwrite it since the user might have opted out. 688 // overwrite it since the user might have opted out.
717 list->AddCreateRegKeyWorkItem(root, 689 list->AddCreateRegKeyWorkItem(root, dist->GetStateKey());
718 product.package().properties()->GetStateKey()); 690 list->AddSetRegValueWorkItem(root, dist->GetStateKey(),
719 list->AddSetRegValueWorkItem(root, 691 kChromeFrameReadyModeField,
720 product.package().properties()->GetStateKey(), 692 static_cast<int64>(is_install ? 1 : 0), // The value we want to set.
721 installer::kChromeFrameReadyModeField, 693 is_install ? false : true); // Overwrite existing value.
722 static_cast<int64>(install ? 1 : 0), // The value we want to set. 694 if (is_install) {
723 install ? false : true); // Overwrite existing value. 695 FilePath installer_path(installer_state
724 if (install) {
725 FilePath installer_path(product.package()
726 .GetInstallerDirectory(new_version).Append(setup_path.BaseName())); 696 .GetInstallerDirectory(new_version).Append(setup_path.BaseName()));
727 697
728 CommandLine basic_cl(installer_path); 698 CommandLine basic_cl(installer_path);
729 basic_cl.AppendSwitch(installer::switches::kChromeFrame); 699 basic_cl.AppendSwitch(switches::kChromeFrame);
730 basic_cl.AppendSwitch(installer::switches::kMultiInstall); 700 basic_cl.AppendSwitch(switches::kMultiInstall);
731 701
732 if (product.package().system_level()) 702 if (installer_state.system_install())
733 basic_cl.AppendSwitch(installer::switches::kSystemLevel); 703 basic_cl.AppendSwitch(switches::kSystemLevel);
734
735 if (InstallUtil::IsChromeSxSProcess())
736 basic_cl.AppendSwitch(installer::switches::kChromeSxS);
737 704
738 CommandLine temp_opt_out(basic_cl); 705 CommandLine temp_opt_out(basic_cl);
739 temp_opt_out.AppendSwitch( 706 temp_opt_out.AppendSwitch(switches::kChromeFrameReadyModeTempOptOut);
740 installer::switches::kChromeFrameReadyModeTempOptOut);
741 707
742 CommandLine end_temp_opt_out(basic_cl); 708 CommandLine end_temp_opt_out(basic_cl);
743 end_temp_opt_out.AppendSwitch( 709 end_temp_opt_out.AppendSwitch(
744 installer::switches::kChromeFrameReadyModeEndTempOptOut); 710 switches::kChromeFrameReadyModeEndTempOptOut);
745 711
746 CommandLine opt_out(installer_path); 712 CommandLine opt_out(installer_path);
747 AppendUninstallCommandLineFlags(&opt_out, product); 713 AppendUninstallCommandLineFlags(installer_state, product, &opt_out);
748 // Force Uninstall silences the prompt to reboot to complete uninstall. 714 // Force Uninstall silences the prompt to reboot to complete uninstall.
749 opt_out.AppendSwitch(installer::switches::kForceUninstall); 715 opt_out.AppendSwitch(switches::kForceUninstall);
750 716
751 CommandLine opt_in(basic_cl); 717 CommandLine opt_in(basic_cl);
752 opt_in.AppendSwitch( 718 opt_in.AppendSwitch(switches::kChromeFrameReadyModeOptIn);
753 installer::switches::kChromeFrameReadyModeOptIn);
754 719
755 list->AddSetRegValueWorkItem(root, version_key, 720 list->AddSetRegValueWorkItem(root, version_key,
756 google_update::kRegCFTempOptOutCmdField, 721 google_update::kRegCFTempOptOutCmdField,
757 temp_opt_out.command_line_string(), true); 722 temp_opt_out.command_line_string(), true);
758 list->AddSetRegValueWorkItem(root, version_key, 723 list->AddSetRegValueWorkItem(root, version_key,
759 google_update::kRegCFEndTempOptOutCmdField, 724 google_update::kRegCFEndTempOptOutCmdField,
760 end_temp_opt_out.command_line_string(), 725 end_temp_opt_out.command_line_string(),
761 true); 726 true);
762 list->AddSetRegValueWorkItem(root, version_key, 727 list->AddSetRegValueWorkItem(root, version_key,
763 google_update::kRegCFOptOutCmdField, 728 google_update::kRegCFOptOutCmdField,
764 opt_out.command_line_string(), true); 729 opt_out.command_line_string(), true);
765 list->AddSetRegValueWorkItem(root, version_key, 730 list->AddSetRegValueWorkItem(root, version_key,
766 google_update::kRegCFOptInCmdField, 731 google_update::kRegCFOptInCmdField,
767 opt_in.command_line_string(), true); 732 opt_in.command_line_string(), true);
768 } else { 733 } else {
769 // If Chrome is not also being uninstalled, we need to update its command 734 // If Chrome is not also being uninstalled, we need to update its command
770 // line so that it doesn't include uninstalling Chrome Frame now. 735 // line so that it doesn't include uninstalling Chrome Frame now.
771 update_chrome_uninstall_command = 736 update_chrome_uninstall_command =
772 (installer::FindProduct(product.package().products(), 737 (installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER) ==
773 BrowserDistribution::CHROME_BROWSER) == NULL); 738 NULL);
774 } 739 }
775 } else { 740 } else {
776 // It doesn't matter here if we're installing or uninstalling Chrome Frame. 741 // It doesn't matter here if we're installing or uninstalling Chrome Frame.
777 // If ready mode isn't specified on the command line for installs, we need 742 // If ready mode isn't specified on the command line for installs, we need
778 // to delete the ready mode flag from the registry if it exists - this 743 // to delete the ready mode flag from the registry if it exists - this
779 // constitutes an opt-in for the user. If we're uninstalling CF and ready 744 // constitutes an opt-in for the user. If we're uninstalling CF and ready
780 // mode isn't specified on the command line, that means that CF wasn't 745 // mode isn't specified on the command line, that means that CF wasn't
781 // installed with ready mode enabled (the --ready-mode switch should be set 746 // installed with ready mode enabled (the --ready-mode switch should be set
782 // in the registry) so deleting the value should have no effect. 747 // in the registry) so deleting the value should have no effect.
783 // In both cases (install/uninstall), we need to make sure that Chrome's 748 // In both cases (install/uninstall), we need to make sure that Chrome's
784 // uninstallation command line does not include the --chrome-frame switch 749 // uninstallation command line does not include the --chrome-frame switch
785 // so that uninstalling Chrome will no longer uninstall Chrome Frame. 750 // so that uninstalling Chrome will no longer uninstall Chrome Frame.
786 751
787 if (RegKey(root, product.package().properties()->GetStateKey().c_str(), 752 list->AddDeleteRegValueWorkItem(root, dist->GetStateKey(),
788 KEY_QUERY_VALUE).Valid()) { 753 kChromeFrameReadyModeField);
789 list->AddDeleteRegValueWorkItem(root,
790 product.package().properties()->GetStateKey(),
791 installer::kChromeFrameReadyModeField);
792 }
793 754
794 const Product* chrome = installer::FindProduct(product.package().products(), 755 const Product* chrome =
795 BrowserDistribution::CHROME_BROWSER); 756 installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER);
796 if (chrome) { 757 if (chrome) {
797 // Chrome is already a part of this installation run, so we can assume 758 // Chrome is already a part of this installation run, so we can assume
798 // that the uninstallation arguments will be updated correctly. 759 // that the uninstallation arguments will be updated correctly.
799 } else { 760 } else {
800 // Chrome is not a part of this installation run, so we have to explicitly 761 // Chrome is not a part of this installation run, so we have to explicitly
801 // check if Chrome is installed, and if so, update its uninstallation 762 // check if Chrome is installed, and if so, update its uninstallation
802 // command lines. 763 // command lines.
803 BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution( 764 const ProductState* chrome_state = original_state.GetProductState(
804 BrowserDistribution::CHROME_BROWSER, 765 installer_state.system_install(),
805 MasterPreferences::ForCurrentProcess()); 766 BrowserDistribution::CHROME_BROWSER);
806 update_chrome_uninstall_command = 767 update_chrome_uninstall_command =
807 IsInstalledAsMulti(product.system_level(), dist); 768 (chrome_state != NULL) && chrome_state->multi_install();
808 } 769 }
809 } 770 }
810 771
811 if (!ready_mode || !install) { 772 if (!ready_mode || !is_install) {
812 list->AddDeleteRegValueWorkItem(root, version_key, 773 list->AddDeleteRegValueWorkItem(root, version_key,
813 google_update::kRegCFTempOptOutCmdField); 774 google_update::kRegCFTempOptOutCmdField);
814 list->AddDeleteRegValueWorkItem(root, version_key, 775 list->AddDeleteRegValueWorkItem(root, version_key,
815 google_update::kRegCFEndTempOptOutCmdField); 776 google_update::kRegCFEndTempOptOutCmdField);
816 list->AddDeleteRegValueWorkItem(root, version_key, 777 list->AddDeleteRegValueWorkItem(root, version_key,
817 google_update::kRegCFOptOutCmdField); 778 google_update::kRegCFOptOutCmdField);
818 list->AddDeleteRegValueWorkItem(root, version_key, 779 list->AddDeleteRegValueWorkItem(root, version_key,
819 google_update::kRegCFOptInCmdField); 780 google_update::kRegCFOptInCmdField);
820 } 781 }
821 782
822 if (update_chrome_uninstall_command) { 783 if (update_chrome_uninstall_command) {
823 // Chrome is not a part of this installation run, so we have to explicitly 784 // Chrome is not a part of this installation run, so we have to explicitly
824 // check if Chrome is installed, and if so, update its uninstallation 785 // check if Chrome is installed, and if so, update its uninstallation
825 // command lines. 786 // command lines.
826 BrowserDistribution* chrome_dist = 787 const ProductState* chrome_state = original_state.GetProductState(
827 BrowserDistribution::GetSpecificDistribution( 788 installer_state.system_install(),
828 BrowserDistribution::CHROME_BROWSER, prefs); 789 BrowserDistribution::CHROME_BROWSER);
829 const Package& pack = product.package(); 790 if (chrome_state != NULL) {
830 scoped_refptr<Package> package(new Package(pack.multi_install(), 791 DCHECK(chrome_state->multi_install());
831 pack.system_level(), pack.path(), pack.properties())); 792 Product chrome(BrowserDistribution::GetSpecificDistribution(
832 scoped_refptr<Product> chrome_product(new Product(chrome_dist, package)); 793 BrowserDistribution::CHROME_BROWSER));
833 AddUninstallShortcutWorkItems(setup_path, new_version, list, 794 chrome.InitializeFromUninstallCommand(chrome_state->uninstall_command());
834 *chrome_product.get()); 795 AddUninstallShortcutWorkItems(installer_state, setup_path,
796 chrome_state->version(), list, chrome);
797 } else {
798 NOTREACHED() << "What happened to Chrome?";
799 }
835 } 800 }
836 } 801 }
837 802
838 void AppendUninstallCommandLineFlags(CommandLine* uninstall_cmd, 803 void AppendUninstallCommandLineFlags(const InstallerState& installer_state,
839 const Product& product) { 804 const Product& product,
805 CommandLine* uninstall_cmd) {
840 DCHECK(uninstall_cmd); 806 DCHECK(uninstall_cmd);
841 807
842 uninstall_cmd->AppendSwitch(installer::switches::kUninstall); 808 uninstall_cmd->AppendSwitch(installer::switches::kUninstall);
843 809
844 // Append the product-specific uninstall flags. 810 // Append the product-specific uninstall flags.
845 product.distribution()->AppendUninstallCommandLineFlags(uninstall_cmd); 811 product.AppendProductFlags(uninstall_cmd);
846 if (product.IsMsi()) { 812 if (installer_state.msi()) {
847 uninstall_cmd->AppendSwitch(installer::switches::kMsi); 813 uninstall_cmd->AppendSwitch(installer::switches::kMsi);
848 // See comment in uninstall.cc where we check for the kDeleteProfile switch. 814 // See comment in uninstall.cc where we check for the kDeleteProfile switch.
849 if (product.is_chrome_frame()) { 815 if (product.is_chrome_frame()) {
850 uninstall_cmd->AppendSwitch(installer::switches::kDeleteProfile); 816 uninstall_cmd->AppendSwitch(installer::switches::kDeleteProfile);
851 } 817 }
852 } 818 }
853 if (product.system_level()) 819 if (installer_state.system_install())
854 uninstall_cmd->AppendSwitch(installer::switches::kSystemLevel); 820 uninstall_cmd->AppendSwitch(installer::switches::kSystemLevel);
855 821 if (installer_state.verbose_logging())
856 // Propagate switches obtained from preferences as well.
857 const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
858 if (prefs.is_multi_install()) {
859 uninstall_cmd->AppendSwitch(installer::switches::kMultiInstall);
860 }
861 bool value = false;
862 if (prefs.GetBool(installer::master_preferences::kVerboseLogging,
863 &value) && value)
864 uninstall_cmd->AppendSwitch(installer::switches::kVerboseLogging); 822 uninstall_cmd->AppendSwitch(installer::switches::kVerboseLogging);
865 } 823 }
866 824
867 } // namespace installer 825 } // namespace installer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698