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

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

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

Powered by Google App Engine
This is Rietveld 408576698