1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // This file contains the definitions of the installer functions that build
6 // the WorkItemList used to install the application.
8 #include "chrome/installer/setup/install_worker.h"
16 #include "base/bind.h"
17 #include "base/command_line.h"
18 #include "base/files/file_path.h"
19 #include "base/files/file_util.h"
20 #include "base/logging.h"
21 #include "base/memory/scoped_ptr.h"
22 #include "base/path_service.h"
23 #include "base/strings/string_util.h"
24 #include "base/strings/utf_string_conversions.h"
25 #include "base/version.h"
26 #include "base/win/registry.h"
27 #include "base/win/scoped_comptr.h"
28 #include "base/win/windows_version.h"
29 #include "chrome/common/chrome_constants.h"
30 #include "chrome/common/chrome_switches.h"
31 #include "chrome/installer/setup/app_launcher_installer.h"
32 #include "chrome/installer/setup/install.h"
33 #include "chrome/installer/setup/setup_constants.h"
34 #include "chrome/installer/setup/setup_util.h"
35 #include "chrome/installer/setup/update_active_setup_version_work_item.h"
36 #include "chrome/installer/util/app_registration_data.h"
37 #include "chrome/installer/util/browser_distribution.h"
38 #include "chrome/installer/util/callback_work_item.h"
39 #include "chrome/installer/util/conditional_work_item_list.h"
40 #include "chrome/installer/util/create_reg_key_work_item.h"
41 #include "chrome/installer/util/firewall_manager_win.h"
42 #include "chrome/installer/util/google_update_constants.h"
43 #include "chrome/installer/util/helper.h"
44 #include "chrome/installer/util/install_util.h"
45 #include "chrome/installer/util/installation_state.h"
46 #include "chrome/installer/util/installer_state.h"
47 #include "chrome/installer/util/l10n_string_util.h"
48 #include "chrome/installer/util/product.h"
49 #include "chrome/installer/util/set_reg_value_work_item.h"
50 #include "chrome/installer/util/shell_util.h"
51 #include "chrome/installer/util/util_constants.h"
52 #include "chrome/installer/util/work_item_list.h"
54 using base::ASCIIToUTF16
;
55 using base::win::RegKey
;
61 // Although the UUID of the ChromeFrame class is used for the "current" value,
62 // this is done only as a convenience; there is no need for the GUID of the Low
63 // Rights policies to match the ChromeFrame class's GUID. Hence, it is safe to
64 // use this completely unrelated GUID for the "old" policies.
65 const wchar_t kIELowRightsPolicyOldGuid
[] =
66 L
"{6C288DD7-76FB-4721-B628-56FAC252E199}";
68 const wchar_t kElevationPolicyKeyPath
[] =
69 L
"SOFTWARE\\Microsoft\\Internet Explorer\\Low Rights\\ElevationPolicy\\";
71 void GetOldIELowRightsElevationPolicyKeyPath(base::string16
* key_path
) {
72 key_path
->assign(kElevationPolicyKeyPath
,
73 arraysize(kElevationPolicyKeyPath
) - 1);
74 key_path
->append(kIELowRightsPolicyOldGuid
,
75 arraysize(kIELowRightsPolicyOldGuid
)- 1);
78 // Local helper to call AddRegisterComDllWorkItems for all DLLs in a set of
79 // products managed by a given package.
80 // |old_version| can be NULL to indicate no Chrome is currently installed.
81 void AddRegisterComDllWorkItemsForPackage(const InstallerState
& installer_state
,
82 const Version
* old_version
,
83 const Version
& new_version
,
84 WorkItemList
* work_item_list
) {
85 // First collect the list of DLLs to be registered from each product.
86 std::vector
<base::FilePath
> com_dll_list
;
87 installer_state
.AddComDllList(&com_dll_list
);
89 // Then, if we got some, attempt to unregister the DLLs from the old
90 // version directory and then re-register them in the new one.
91 // Note that if we are migrating the install directory then we will not
92 // successfully unregister the old DLLs.
93 // TODO(robertshield): See whether we need to fix the migration case.
94 // TODO(robertshield): If we ever remove a DLL from a product, this will
95 // not unregister it on update. We should build the unregistration list from
96 // saved state instead of assuming it is the same as the registration list.
97 if (!com_dll_list
.empty()) {
99 base::FilePath
old_dll_path(installer_state
.target_path().AppendASCII(
100 old_version
->GetString()));
102 installer::AddRegisterComDllWorkItems(old_dll_path
,
104 installer_state
.system_install(),
110 base::FilePath
dll_path(installer_state
.target_path().AppendASCII(
111 new_version
.GetString()));
112 installer::AddRegisterComDllWorkItems(dll_path
,
114 installer_state
.system_install(),
116 false, // Must succeed.
121 void AddInstallerCopyTasks(const InstallerState
& installer_state
,
122 const base::FilePath
& setup_path
,
123 const base::FilePath
& archive_path
,
124 const base::FilePath
& temp_path
,
125 const Version
& new_version
,
126 WorkItemList
* install_list
) {
127 DCHECK(install_list
);
128 base::FilePath
installer_dir(
129 installer_state
.GetInstallerDirectory(new_version
));
130 install_list
->AddCreateDirWorkItem(installer_dir
);
132 base::FilePath
exe_dst(installer_dir
.Append(setup_path
.BaseName()));
134 if (exe_dst
!= setup_path
) {
135 install_list
->AddCopyTreeWorkItem(setup_path
.value(), exe_dst
.value(),
136 temp_path
.value(), WorkItem::ALWAYS
);
139 if (installer_state
.RequiresActiveSetup()) {
140 // Make a copy of setup.exe with a different name so that Active Setup
141 // doesn't require an admin on XP thanks to Application Compatibility.
142 base::FilePath
active_setup_exe(installer_dir
.Append(kActiveSetupExe
));
143 install_list
->AddCopyTreeWorkItem(
144 setup_path
.value(), active_setup_exe
.value(), temp_path
.value(),
148 base::FilePath
archive_dst(installer_dir
.Append(archive_path
.BaseName()));
149 if (archive_path
!= archive_dst
) {
150 // In the past, we copied rather than moved for system level installs so
151 // that the permissions of %ProgramFiles% would be picked up. Now that
152 // |temp_path| is in %ProgramFiles% for system level installs (and in
153 // %LOCALAPPDATA% otherwise), there is no need to do this for the archive.
154 // Setup.exe, on the other hand, is created elsewhere so it must always be
156 if (temp_path
.IsParent(archive_path
)) {
157 install_list
->AddMoveTreeWorkItem(archive_path
.value(),
160 WorkItem::ALWAYS_MOVE
);
162 // This may occur when setup is run out of an existing installation
163 // directory. We cannot remove the system-level archive.
164 install_list
->AddCopyTreeWorkItem(archive_path
.value(),
172 base::string16
GetRegCommandKey(BrowserDistribution
* dist
,
173 const wchar_t* name
) {
174 return GetRegistrationDataCommandKey(dist
->GetAppRegistrationData(), name
);
177 // A callback invoked by |work_item| that adds firewall rules for Chrome. Rules
178 // are left in-place on rollback unless |remove_on_rollback| is true. This is
179 // the case for new installs only. Updates and overinstalls leave the rule
180 // in-place on rollback since a previous install of Chrome will be used in that
182 bool AddFirewallRulesCallback(bool system_level
,
183 BrowserDistribution
* dist
,
184 const base::FilePath
& chrome_path
,
185 bool remove_on_rollback
,
186 const CallbackWorkItem
& work_item
) {
187 // There is no work to do on rollback if this is not a new install.
188 if (work_item
.IsRollback() && !remove_on_rollback
)
191 scoped_ptr
<FirewallManager
> manager
=
192 FirewallManager::Create(dist
, chrome_path
);
194 LOG(ERROR
) << "Failed creating a FirewallManager. Continuing with install.";
198 if (work_item
.IsRollback()) {
199 manager
->RemoveFirewallRules();
203 // Adding the firewall rule is expected to fail for user-level installs on
204 // Vista+. Try anyway in case the installer is running elevated.
205 if (!manager
->AddFirewallRules())
206 LOG(ERROR
) << "Failed creating a firewall rules. Continuing with install.";
208 // Don't abort installation if the firewall rule couldn't be added.
212 // Adds work items to |list| to create firewall rules.
213 void AddFirewallRulesWorkItems(const InstallerState
& installer_state
,
214 BrowserDistribution
* dist
,
216 WorkItemList
* list
) {
217 list
->AddCallbackWorkItem(
218 base::Bind(&AddFirewallRulesCallback
,
219 installer_state
.system_install(),
221 installer_state
.target_path().Append(kChromeExe
),
225 void AddProductSpecificWorkItems(const InstallationState
& original_state
,
226 const InstallerState
& installer_state
,
227 const base::FilePath
& setup_path
,
228 const Version
& new_version
,
230 bool add_language_identifier
,
231 WorkItemList
* list
) {
232 const Products
& products
= installer_state
.products();
233 for (Products::const_iterator it
= products
.begin(); it
< products
.end();
235 const Product
& p
= **it
;
237 AddOsUpgradeWorkItems(installer_state
, setup_path
, new_version
, p
,
239 AddFirewallRulesWorkItems(
240 installer_state
, p
.distribution(), is_new_install
, list
);
242 #if defined(GOOGLE_CHROME_BUILD)
243 if (!InstallUtil::IsChromeSxSProcess()) {
244 // Add items to set up the App Launcher's version key if Google Chrome
245 // is being installed or updated.
246 AddAppLauncherVersionKeyWorkItems(installer_state
.root_key(),
247 new_version
, add_language_identifier
, list
);
249 #endif // GOOGLE_CHROME_BUILD
251 if (p
.is_chrome_binaries())
252 AddQuickEnableChromeFrameWorkItems(installer_state
, list
);
256 // This is called when an MSI installation is run. It may be that a user is
257 // attempting to install the MSI on top of a non-MSI managed installation. If
258 // so, try and remove any existing "Add/Remove Programs" entry, as we want the
259 // uninstall to be managed entirely by the MSI machinery (accessible via the
260 // Add/Remove programs dialog).
261 void AddDeleteUninstallEntryForMSIWorkItems(
262 const InstallerState
& installer_state
,
263 const Product
& product
,
264 WorkItemList
* work_item_list
) {
265 DCHECK(installer_state
.is_msi())
266 << "This must only be called for MSI installations!";
268 HKEY reg_root
= installer_state
.root_key();
269 base::string16
uninstall_reg(product
.distribution()->GetUninstallRegPath());
271 WorkItem
* delete_reg_key
= work_item_list
->AddDeleteRegKeyWorkItem(
272 reg_root
, uninstall_reg
, KEY_WOW64_32KEY
);
273 delete_reg_key
->set_ignore_failure(true);
276 // Adds Chrome specific install work items to |install_list|.
277 // |current_version| can be NULL to indicate no Chrome is currently installed.
278 void AddChromeWorkItems(const InstallationState
& original_state
,
279 const InstallerState
& installer_state
,
280 const base::FilePath
& setup_path
,
281 const base::FilePath
& archive_path
,
282 const base::FilePath
& src_path
,
283 const base::FilePath
& temp_path
,
284 const Version
* current_version
,
285 const Version
& new_version
,
286 WorkItemList
* install_list
) {
287 const base::FilePath
& target_path
= installer_state
.target_path();
289 if (current_version
) {
290 // Delete the archive from an existing install to save some disk space. We
291 // make this an unconditional work item since there's no need to roll this
292 // back; if installation fails we'll be moved to the "-full" channel anyway.
293 base::FilePath
old_installer_dir(
294 installer_state
.GetInstallerDirectory(*current_version
));
295 base::FilePath
old_archive(
296 old_installer_dir
.Append(installer::kChromeArchive
));
297 // Don't delete the archive that we are actually installing from.
298 if (archive_path
!= old_archive
) {
299 install_list
->AddDeleteTreeWorkItem(old_archive
, temp_path
)->
300 set_ignore_failure(true);
304 // Delete any new_chrome.exe if present (we will end up creating a new one
305 // if required) and then copy chrome.exe
306 base::FilePath
new_chrome_exe(target_path
.Append(installer::kChromeNewExe
));
308 install_list
->AddDeleteTreeWorkItem(new_chrome_exe
, temp_path
);
310 // TODO(grt): Remove this check in M35.
311 if (installer_state
.IsChromeFrameRunning(original_state
)) {
312 VLOG(1) << "Chrome Frame in use. Copying to new_chrome.exe";
313 install_list
->AddCopyTreeWorkItem(
314 src_path
.Append(installer::kChromeExe
).value(),
315 new_chrome_exe
.value(),
319 install_list
->AddCopyTreeWorkItem(
320 src_path
.Append(installer::kChromeExe
).value(),
321 target_path
.Append(installer::kChromeExe
).value(),
323 WorkItem::NEW_NAME_IF_IN_USE
,
324 new_chrome_exe
.value());
327 // Extra executable for 64 bit systems.
328 // NOTE: We check for "not disabled" so that if the API call fails, we play it
329 // safe and copy the executable anyway.
330 // NOTE: the file wow_helper.exe is only needed for Vista and below.
331 if (base::win::OSInfo::GetInstance()->wow64_status() !=
332 base::win::OSInfo::WOW64_DISABLED
&&
333 base::win::GetVersion() <= base::win::VERSION_VISTA
) {
334 install_list
->AddMoveTreeWorkItem(
335 src_path
.Append(installer::kWowHelperExe
).value(),
336 target_path
.Append(installer::kWowHelperExe
).value(),
338 WorkItem::ALWAYS_MOVE
);
341 // Install kVisualElementsManifest if it is present in |src_path|. No need to
342 // make this a conditional work item as if the file is not there now, it will
344 if (base::PathExists(
345 src_path
.Append(installer::kVisualElementsManifest
))) {
346 install_list
->AddMoveTreeWorkItem(
347 src_path
.Append(installer::kVisualElementsManifest
).value(),
348 target_path
.Append(installer::kVisualElementsManifest
).value(),
350 WorkItem::ALWAYS_MOVE
);
352 // We do not want to have an old VisualElementsManifest pointing to an old
353 // version directory. Delete it as there wasn't a new one to replace it.
354 install_list
->AddDeleteTreeWorkItem(
355 target_path
.Append(installer::kVisualElementsManifest
),
359 // In the past, we copied rather than moved for system level installs so that
360 // the permissions of %ProgramFiles% would be picked up. Now that |temp_path|
361 // is in %ProgramFiles% for system level installs (and in %LOCALAPPDATA%
362 // otherwise), there is no need to do this.
363 // Note that we pass true for check_duplicates to avoid failing on in-use
364 // repair runs if the current_version is the same as the new_version.
365 bool check_for_duplicates
= (current_version
&&
366 current_version
->Equals(new_version
));
367 install_list
->AddMoveTreeWorkItem(
368 src_path
.AppendASCII(new_version
.GetString()).value(),
369 target_path
.AppendASCII(new_version
.GetString()).value(),
371 check_for_duplicates
? WorkItem::CHECK_DUPLICATES
:
372 WorkItem::ALWAYS_MOVE
);
374 // Delete any old_chrome.exe if present (ignore failure if it's in use).
375 install_list
->AddDeleteTreeWorkItem(
376 target_path
.Append(installer::kChromeOldExe
), temp_path
)->
377 set_ignore_failure(true);
380 // Probes COM machinery to get an instance of delegate_execute.exe's
381 // CommandExecuteImpl class. This is required so that COM purges its cache of
382 // the path to the binary, which changes on updates. This callback
383 // unconditionally returns true since an install should not be aborted if the
385 bool ProbeCommandExecuteCallback(const base::string16
& command_execute_id
,
386 const CallbackWorkItem
& work_item
) {
388 if (work_item
.IsRollback())
393 HRESULT hr
= CLSIDFromString(command_execute_id
.c_str(), &class_id
);
395 LOG(DFATAL
) << "Failed converting \"" << command_execute_id
<< "\" to "
396 "CLSID; hr=0x" << std::hex
<< hr
;
398 base::win::ScopedComPtr
<IUnknown
> command_execute_impl
;
399 hr
= command_execute_impl
.CreateInstance(class_id
, NULL
,
400 CLSCTX_LOCAL_SERVER
);
401 if (hr
!= REGDB_E_CLASSNOTREG
) {
402 LOG(ERROR
) << "Unexpected result creating CommandExecuteImpl; hr=0x"
410 void AddUninstallDelegateExecuteWorkItems(
412 const base::string16
& delegate_execute_path
,
413 WorkItemList
* list
) {
414 VLOG(1) << "Adding unregistration items for DelegateExecute verb handler in "
416 // Delete both 64 and 32 keys to handle 32->64 or 64->32 migration.
417 list
->AddDeleteRegKeyWorkItem(root
, delegate_execute_path
, KEY_WOW64_32KEY
);
419 list
->AddDeleteRegKeyWorkItem(root
, delegate_execute_path
, KEY_WOW64_64KEY
);
421 // In the past, the ICommandExecuteImpl interface and a TypeLib were both
422 // registered. Remove these since this operation may be updating a machine
423 // that had the old registrations.
424 list
->AddDeleteRegKeyWorkItem(root
,
425 L
"Software\\Classes\\Interface\\"
426 L
"{0BA0D4E9-2259-4963-B9AE-A839F7CB7544}",
428 list
->AddDeleteRegKeyWorkItem(root
,
429 L
"Software\\Classes\\TypeLib\\"
430 #if defined(GOOGLE_CHROME_BUILD)
431 L
"{4E805ED8-EBA0-4601-9681-12815A56EBFD}",
433 L
"{7779FB70-B399-454A-AA1A-BAA850032B10}",
438 // Google Chrome Canary, between 20.0.1101.0 (crrev.com/132190) and 20.0.1106.0
439 // (exclusively -- crrev.com/132596), registered a DelegateExecute class by
440 // mistake (with the same GUID as Chrome). The fix stopped registering the bad
441 // value, but didn't delete it. This is a problem for users who had installed
442 // Canary before 20.0.1106.0 and now have a system-level Chrome, as the
443 // left-behind Canary registrations in HKCU mask the HKLM registrations for the
444 // same GUID. Cleanup those registrations if they still exist and belong to this
445 // Canary (i.e., the registered delegate_execute's path is under |target_path|).
446 void CleanupBadCanaryDelegateExecuteRegistration(
447 const base::FilePath
& target_path
,
448 WorkItemList
* list
) {
449 base::string16
google_chrome_delegate_execute_path(
450 L
"Software\\Classes\\CLSID\\{5C65F4B0-3651-4514-B207-D10CB699B14B}");
451 base::string16
google_chrome_local_server_32(
452 google_chrome_delegate_execute_path
+ L
"\\LocalServer32");
454 RegKey local_server_32_key
;
455 base::string16 registered_server
;
456 if (local_server_32_key
.Open(HKEY_CURRENT_USER
,
457 google_chrome_local_server_32
.c_str(),
458 KEY_QUERY_VALUE
) == ERROR_SUCCESS
&&
459 local_server_32_key
.ReadValue(L
"ServerExecutable",
460 ®istered_server
) == ERROR_SUCCESS
&&
461 target_path
.IsParent(base::FilePath(registered_server
))) {
462 scoped_ptr
<WorkItemList
> no_rollback_list(
463 WorkItem::CreateNoRollbackWorkItemList());
464 AddUninstallDelegateExecuteWorkItems(
465 HKEY_CURRENT_USER
, google_chrome_delegate_execute_path
,
466 no_rollback_list
.get());
467 list
->AddWorkItem(no_rollback_list
.release());
468 VLOG(1) << "Added deletion items for bad Canary registrations.";
474 // This method adds work items to create (or update) Chrome uninstall entry in
475 // either the Control Panel->Add/Remove Programs list or in the Omaha client
476 // state key if running under an MSI installer.
477 void AddUninstallShortcutWorkItems(const InstallerState
& installer_state
,
478 const base::FilePath
& setup_path
,
479 const Version
& new_version
,
480 const Product
& product
,
481 WorkItemList
* install_list
) {
482 HKEY reg_root
= installer_state
.root_key();
483 BrowserDistribution
* browser_dist
= product
.distribution();
484 DCHECK(browser_dist
);
486 // When we are installed via an MSI, we need to store our uninstall strings
487 // in the Google Update client state key. We do this even for non-MSI
488 // managed installs to avoid breaking the edge case whereby an MSI-managed
489 // install is updated by a non-msi installer (which would confuse the MSI
490 // machinery if these strings were not also updated). The UninstallString
491 // value placed in the client state key is also used by the mini_installer to
492 // locate the setup.exe instance used for binary patching.
493 // Do not quote the command line for the MSI invocation.
494 base::FilePath
install_path(installer_state
.target_path());
495 base::FilePath
installer_path(
496 installer_state
.GetInstallerDirectory(new_version
));
497 installer_path
= installer_path
.Append(setup_path
.BaseName());
499 base::CommandLine
uninstall_arguments(base::CommandLine::NO_PROGRAM
);
500 AppendUninstallCommandLineFlags(installer_state
, product
,
501 &uninstall_arguments
);
503 base::string16
update_state_key(browser_dist
->GetStateKey());
504 install_list
->AddCreateRegKeyWorkItem(
505 reg_root
, update_state_key
, KEY_WOW64_32KEY
);
506 install_list
->AddSetRegValueWorkItem(reg_root
,
509 installer::kUninstallStringField
,
510 installer_path
.value(),
512 install_list
->AddSetRegValueWorkItem(
516 installer::kUninstallArgumentsField
,
517 uninstall_arguments
.GetCommandLineString(),
520 // MSI installations will manage their own uninstall shortcuts.
521 if (!installer_state
.is_msi() && product
.ShouldCreateUninstallEntry()) {
522 // We need to quote the command line for the Add/Remove Programs dialog.
523 base::CommandLine
quoted_uninstall_cmd(installer_path
);
524 DCHECK_EQ(quoted_uninstall_cmd
.GetCommandLineString()[0], '"');
525 quoted_uninstall_cmd
.AppendArguments(uninstall_arguments
, false);
527 base::string16 uninstall_reg
= browser_dist
->GetUninstallRegPath();
528 install_list
->AddCreateRegKeyWorkItem(
529 reg_root
, uninstall_reg
, KEY_WOW64_32KEY
);
530 install_list
->AddSetRegValueWorkItem(reg_root
,
533 installer::kUninstallDisplayNameField
,
534 browser_dist
->GetDisplayName(),
536 install_list
->AddSetRegValueWorkItem(
540 installer::kUninstallStringField
,
541 quoted_uninstall_cmd
.GetCommandLineString(),
543 install_list
->AddSetRegValueWorkItem(reg_root
,
547 install_path
.value(),
550 BrowserDistribution
* dist
= product
.distribution();
551 base::string16 chrome_icon
= ShellUtil::FormatIconLocation(
552 install_path
.Append(dist
->GetIconFilename()),
553 dist
->GetIconIndex(BrowserDistribution::SHORTCUT_CHROME
));
554 install_list
->AddSetRegValueWorkItem(reg_root
,
560 install_list
->AddSetRegValueWorkItem(reg_root
,
564 static_cast<DWORD
>(1),
566 install_list
->AddSetRegValueWorkItem(reg_root
,
570 static_cast<DWORD
>(1),
573 install_list
->AddSetRegValueWorkItem(reg_root
,
577 browser_dist
->GetPublisherName(),
579 install_list
->AddSetRegValueWorkItem(reg_root
,
583 ASCIIToUTF16(new_version
.GetString()),
585 install_list
->AddSetRegValueWorkItem(reg_root
,
589 ASCIIToUTF16(new_version
.GetString()),
591 // TODO(wfh): Ensure that this value is preserved in the 64-bit hive when
592 // 64-bit installs place the uninstall information into the 64-bit registry.
593 install_list
->AddSetRegValueWorkItem(reg_root
,
597 InstallUtil::GetCurrentDate(),
600 const std::vector
<uint32_t>& version_components
= new_version
.components();
601 if (version_components
.size() == 4) {
602 // Our version should be in major.minor.build.rev.
603 install_list
->AddSetRegValueWorkItem(
608 static_cast<DWORD
>(version_components
[2]),
610 install_list
->AddSetRegValueWorkItem(
615 static_cast<DWORD
>(version_components
[3]),
621 // Create Version key for a product (if not already present) and sets the new
622 // product version as the last step.
623 void AddVersionKeyWorkItems(HKEY root
,
624 const base::string16
& version_key
,
625 const base::string16
& product_name
,
626 const Version
& new_version
,
627 bool add_language_identifier
,
628 WorkItemList
* list
) {
629 list
->AddCreateRegKeyWorkItem(root
, version_key
, KEY_WOW64_32KEY
);
631 list
->AddSetRegValueWorkItem(root
,
634 google_update::kRegNameField
,
636 true); // overwrite name also
637 list
->AddSetRegValueWorkItem(root
,
640 google_update::kRegOopcrashesField
,
641 static_cast<DWORD
>(1),
642 false); // set during first install
643 if (add_language_identifier
) {
644 // Write the language identifier of the current translation. Omaha's set of
645 // languages is a superset of Chrome's set of translations with this one
646 // exception: what Chrome calls "en-us", Omaha calls "en". sigh.
647 base::string16
language(GetCurrentTranslation());
648 if (base::LowerCaseEqualsASCII(language
, "en-us"))
650 list
->AddSetRegValueWorkItem(root
,
653 google_update::kRegLangField
,
655 false); // do not overwrite language
657 list
->AddSetRegValueWorkItem(root
,
660 google_update::kRegVersionField
,
661 ASCIIToUTF16(new_version
.GetString()),
662 true); // overwrite version
665 // Mirror oeminstall the first time anything is installed multi. There is no
666 // need to update the value on future install/update runs since this value never
667 // changes. Note that the value is removed by Google Update after EULA
668 // acceptance is processed.
669 void AddOemInstallWorkItems(const InstallationState
& original_state
,
670 const InstallerState
& installer_state
,
671 WorkItemList
* install_list
) {
672 DCHECK(installer_state
.is_multi_install());
673 const bool system_install
= installer_state
.system_install();
674 if (!original_state
.GetProductState(system_install
,
675 BrowserDistribution::CHROME_BINARIES
)) {
676 const HKEY root_key
= installer_state
.root_key();
677 base::string16
multi_key(
678 installer_state
.multi_package_binaries_distribution()->GetStateKey());
680 // Copy the value from Chrome unless Chrome isn't installed or being
682 BrowserDistribution::Type source_type
;
683 if (installer_state
.FindProduct(BrowserDistribution::CHROME_BROWSER
)) {
684 source_type
= BrowserDistribution::CHROME_BROWSER
;
685 } else if (!installer_state
.products().empty()) {
686 // Pick a product, any product.
687 source_type
= installer_state
.products()[0]->distribution()->GetType();
689 // Nothing is being installed? Entirely unexpected, so do no harm.
690 LOG(ERROR
) << "No products found in AddOemInstallWorkItems";
693 const ProductState
* source_product
=
694 original_state
.GetNonVersionedProductState(system_install
, source_type
);
696 base::string16 oem_install
;
697 if (source_product
->GetOemInstall(&oem_install
)) {
698 VLOG(1) << "Mirroring oeminstall=\"" << oem_install
<< "\" from "
699 << BrowserDistribution::GetSpecificDistribution(source_type
)->
701 install_list
->AddCreateRegKeyWorkItem(
702 root_key
, multi_key
, KEY_WOW64_32KEY
);
703 // Always overwrite an old value.
704 install_list
->AddSetRegValueWorkItem(root_key
,
707 google_update::kRegOemInstallField
,
711 // Clear any old value.
712 install_list
->AddDeleteRegValueWorkItem(
716 google_update::kRegOemInstallField
);
721 // Mirror eulaaccepted the first time anything is installed multi. There is no
722 // need to update the value on future install/update runs since
723 // GoogleUpdateSettings::SetEULAConsent will modify the value for both the
724 // relevant product and for the binaries.
725 void AddEulaAcceptedWorkItems(const InstallationState
& original_state
,
726 const InstallerState
& installer_state
,
727 WorkItemList
* install_list
) {
728 DCHECK(installer_state
.is_multi_install());
729 const bool system_install
= installer_state
.system_install();
730 if (!original_state
.GetProductState(system_install
,
731 BrowserDistribution::CHROME_BINARIES
)) {
732 const HKEY root_key
= installer_state
.root_key();
733 base::string16
multi_key(
734 installer_state
.multi_package_binaries_distribution()->GetStateKey());
736 // Copy the value from the product with the greatest value.
737 bool have_eula_accepted
= false;
738 BrowserDistribution::Type product_type
= BrowserDistribution::NUM_TYPES
;
739 DWORD eula_accepted
= 0;
740 const Products
& products
= installer_state
.products();
741 for (Products::const_iterator it
= products
.begin(); it
< products
.end();
743 const Product
& product
= **it
;
744 if (product
.is_chrome_binaries())
746 DWORD dword_value
= 0;
747 BrowserDistribution::Type this_type
= product
.distribution()->GetType();
748 const ProductState
* product_state
=
749 original_state
.GetNonVersionedProductState(
750 system_install
, this_type
);
751 if (product_state
->GetEulaAccepted(&dword_value
) &&
752 (!have_eula_accepted
|| dword_value
> eula_accepted
)) {
753 have_eula_accepted
= true;
754 eula_accepted
= dword_value
;
755 product_type
= this_type
;
759 if (have_eula_accepted
) {
760 VLOG(1) << "Mirroring eulaaccepted=" << eula_accepted
<< " from "
761 << BrowserDistribution::GetSpecificDistribution(product_type
)->
763 install_list
->AddCreateRegKeyWorkItem(
764 root_key
, multi_key
, KEY_WOW64_32KEY
);
765 install_list
->AddSetRegValueWorkItem(root_key
,
768 google_update::kRegEULAAceptedField
,
772 // Clear any old value.
773 install_list
->AddDeleteRegValueWorkItem(
777 google_update::kRegEULAAceptedField
);
782 // Adds work items that make registry adjustments for Google Update.
783 void AddGoogleUpdateWorkItems(const InstallationState
& original_state
,
784 const InstallerState
& installer_state
,
785 WorkItemList
* install_list
) {
786 // Is a multi-install product being installed or over-installed?
787 if (installer_state
.operation() != InstallerState::MULTI_INSTALL
&&
788 installer_state
.operation() != InstallerState::MULTI_UPDATE
) {
789 VLOG(1) << "AddGoogleUpdateWorkItems noop: " << installer_state
.operation();
793 const bool system_install
= installer_state
.system_install();
794 const HKEY root_key
= installer_state
.root_key();
795 base::string16
multi_key(
796 installer_state
.multi_package_binaries_distribution()->GetStateKey());
798 // For system-level installs, make sure the ClientStateMedium key for the
800 if (system_install
) {
801 install_list
->AddCreateRegKeyWorkItem(
803 installer_state
.multi_package_binaries_distribution()
804 ->GetStateMediumKey()
809 // Creating the ClientState key for binaries, if we're migrating to multi then
810 // copy over Chrome's brand code if it has one.
811 if (installer_state
.state_type() != BrowserDistribution::CHROME_BINARIES
) {
812 const ProductState
* chrome_product_state
=
813 original_state
.GetNonVersionedProductState(
814 system_install
, BrowserDistribution::CHROME_BROWSER
);
816 const base::string16
& brand(chrome_product_state
->brand());
817 if (!brand
.empty()) {
818 install_list
->AddCreateRegKeyWorkItem(
819 root_key
, multi_key
, KEY_WOW64_32KEY
);
820 // Write Chrome's brand code to the multi key. Never overwrite the value
821 // if one is already present (although this shouldn't happen).
822 install_list
->AddSetRegValueWorkItem(root_key
,
825 google_update::kRegBrandField
,
831 AddOemInstallWorkItems(original_state
, installer_state
, install_list
);
832 AddEulaAcceptedWorkItems(original_state
, installer_state
, install_list
);
833 AddUsageStatsWorkItems(original_state
, installer_state
, install_list
);
835 // TODO(grt): check for other keys/values we should put in the package's
836 // ClientState and/or Clients key.
839 void AddUsageStatsWorkItems(const InstallationState
& original_state
,
840 const InstallerState
& installer_state
,
841 WorkItemList
* install_list
) {
842 DCHECK(installer_state
.operation() == InstallerState::MULTI_INSTALL
||
843 installer_state
.operation() == InstallerState::MULTI_UPDATE
);
845 HKEY root_key
= installer_state
.root_key();
846 bool value_found
= false;
847 DWORD usagestats
= 0;
848 const Products
& products
= installer_state
.products();
850 // Search for an existing usagestats value for any product.
851 for (Products::const_iterator scan
= products
.begin(), end
= products
.end();
852 !value_found
&& scan
!= end
; ++scan
) {
853 if ((*scan
)->is_chrome_binaries())
855 BrowserDistribution
* dist
= (*scan
)->distribution();
856 const ProductState
* product_state
=
857 original_state
.GetNonVersionedProductState(
858 installer_state
.system_install(), dist
->GetType());
859 value_found
= product_state
->GetUsageStats(&usagestats
);
862 // If a value was found, write it in the appropriate location for the
863 // binaries and remove all values from the products.
865 base::string16
state_key(
866 installer_state
.multi_package_binaries_distribution()->GetStateKey());
867 install_list
->AddCreateRegKeyWorkItem(root_key
, state_key
, KEY_WOW64_32KEY
);
868 // Overwrite any existing value so that overinstalls (where Omaha writes a
869 // new value into a product's state key) pick up the correct value.
870 install_list
->AddSetRegValueWorkItem(root_key
,
873 google_update::kRegUsageStatsField
,
877 for (Products::const_iterator scan
= products
.begin(), end
= products
.end();
878 scan
!= end
; ++scan
) {
879 if ((*scan
)->is_chrome_binaries())
881 BrowserDistribution
* dist
= (*scan
)->distribution();
882 if (installer_state
.system_install()) {
883 install_list
->AddDeleteRegValueWorkItem(
885 dist
->GetStateMediumKey(),
887 google_update::kRegUsageStatsField
);
888 // Previous versions of Chrome also wrote a value in HKCU even for
889 // system-level installs, so clean that up.
890 install_list
->AddDeleteRegValueWorkItem(
894 google_update::kRegUsageStatsField
);
896 install_list
->AddDeleteRegValueWorkItem(
900 google_update::kRegUsageStatsField
);
905 // Migrates the usagestats value from the binaries to Chrome when migrating
906 // multi-install Chrome to single-install.
907 void AddMigrateUsageStatesWorkItems(const InstallationState
& original_state
,
908 const InstallerState
& installer_state
,
909 WorkItemList
* install_list
) {
910 // Ensure that a non-multi install or update is being processed (i.e.,
911 // no "--multi-install" on the command line).
912 if (installer_state
.is_multi_install())
915 // This operation doesn't apply to SxS Chrome.
916 if (InstallUtil::IsChromeSxSProcess())
919 // Ensure that Chrome is the product being installed or updated (there are no
920 // other products, so it is especially unexpected for this to fail).
921 const Product
* chrome_product
=
922 installer_state
.FindProduct(BrowserDistribution::CHROME_BROWSER
);
923 if (!chrome_product
) {
924 LOG(DFATAL
) << "Not operating on Chrome while migrating to single-install.";
928 const ProductState
* chrome_state
= original_state
.GetProductState(
929 installer_state
.system_install(),
930 BrowserDistribution::CHROME_BROWSER
);
931 // Bail out if there is not an existing multi-install Chrome that is being
933 if (!chrome_state
|| !chrome_state
->is_multi_install()) {
934 VLOG(1) << "No multi-install Chrome found to migrate to single-install.";
938 const ProductState
* binaries_state
= original_state
.GetProductState(
939 installer_state
.system_install(),
940 BrowserDistribution::CHROME_BINARIES
);
942 // There is nothing to be done if the binaries do not have stats.
943 DWORD usagestats
= 0;
944 if (!binaries_state
|| !binaries_state
->GetUsageStats(&usagestats
)) {
945 VLOG(1) << "No usagestats value found to migrate to single-install.";
949 VLOG(1) << "Migrating usagestats value from multi-install to single-install.";
951 // Write the value that was read to Chrome's ClientState key.
952 install_list
->AddSetRegValueWorkItem(
953 installer_state
.root_key(),
954 chrome_product
->distribution()->GetStateKey(),
956 google_update::kRegUsageStatsField
,
961 bool AppendPostInstallTasks(const InstallerState
& installer_state
,
962 const base::FilePath
& setup_path
,
963 const Version
* current_version
,
964 const Version
& new_version
,
965 WorkItemList
* post_install_task_list
) {
966 DCHECK(post_install_task_list
);
968 HKEY root
= installer_state
.root_key();
969 const Products
& products
= installer_state
.products();
970 base::FilePath
new_chrome_exe(
971 installer_state
.target_path().Append(installer::kChromeNewExe
));
973 // Append work items that will only be executed if this was an update.
974 // We update the 'opv' value with the current version that is active,
975 // the 'cpv' value with the critical update version (if present), and the
976 // 'cmd' value with the rename command to run.
978 scoped_ptr
<WorkItemList
> in_use_update_work_items(
979 WorkItem::CreateConditionalWorkItemList(
980 new ConditionRunIfFileExists(new_chrome_exe
)));
981 in_use_update_work_items
->set_log_message("InUseUpdateWorkItemList");
983 // |critical_version| will be valid only if this in-use update includes a
984 // version considered critical relative to the version being updated.
985 Version
critical_version(installer_state
.DetermineCriticalVersion(
986 current_version
, new_version
));
987 base::FilePath
installer_path(
988 installer_state
.GetInstallerDirectory(new_version
).Append(
989 setup_path
.BaseName()));
991 base::CommandLine
rename(installer_path
);
992 rename
.AppendSwitch(switches::kRenameChromeExe
);
993 if (installer_state
.system_install())
994 rename
.AppendSwitch(switches::kSystemLevel
);
996 if (installer_state
.verbose_logging())
997 rename
.AppendSwitch(switches::kVerboseLogging
);
999 base::string16 version_key
;
1000 for (size_t i
= 0; i
< products
.size(); ++i
) {
1001 BrowserDistribution
* dist
= products
[i
]->distribution();
1002 version_key
= dist
->GetVersionKey();
1004 if (current_version
) {
1005 in_use_update_work_items
->AddSetRegValueWorkItem(
1009 google_update::kRegOldVersionField
,
1010 ASCIIToUTF16(current_version
->GetString()),
1013 if (critical_version
.IsValid()) {
1014 in_use_update_work_items
->AddSetRegValueWorkItem(
1018 google_update::kRegCriticalVersionField
,
1019 ASCIIToUTF16(critical_version
.GetString()),
1022 in_use_update_work_items
->AddDeleteRegValueWorkItem(
1026 google_update::kRegCriticalVersionField
);
1029 // Adding this registry entry for all products (but the binaries) is
1030 // overkill. However, as it stands, we don't have a way to know which
1031 // product will check the key and run the command, so we add it for all.
1032 // The first to run it will perform the operation and clean up the other
1034 if (dist
->GetType() != BrowserDistribution::CHROME_BINARIES
) {
1035 base::CommandLine
product_rename_cmd(rename
);
1036 products
[i
]->AppendRenameFlags(&product_rename_cmd
);
1037 in_use_update_work_items
->AddSetRegValueWorkItem(
1041 google_update::kRegRenameCmdField
,
1042 product_rename_cmd
.GetCommandLineString(),
1047 post_install_task_list
->AddWorkItem(in_use_update_work_items
.release());
1050 // Append work items that will be executed if this was NOT an in-use update.
1052 scoped_ptr
<WorkItemList
> regular_update_work_items(
1053 WorkItem::CreateConditionalWorkItemList(
1054 new Not(new ConditionRunIfFileExists(new_chrome_exe
))));
1055 regular_update_work_items
->set_log_message("RegularUpdateWorkItemList");
1057 // Since this was not an in-use-update, delete 'opv', 'cpv', and 'cmd' keys.
1058 for (size_t i
= 0; i
< products
.size(); ++i
) {
1059 BrowserDistribution
* dist
= products
[i
]->distribution();
1060 base::string16
version_key(dist
->GetVersionKey());
1061 regular_update_work_items
->AddDeleteRegValueWorkItem(
1065 google_update::kRegOldVersionField
);
1066 regular_update_work_items
->AddDeleteRegValueWorkItem(
1070 google_update::kRegCriticalVersionField
);
1071 regular_update_work_items
->AddDeleteRegValueWorkItem(
1075 google_update::kRegRenameCmdField
);
1078 post_install_task_list
->AddWorkItem(regular_update_work_items
.release());
1081 AddRegisterComDllWorkItemsForPackage(installer_state
, current_version
,
1082 new_version
, post_install_task_list
);
1084 // If we're told that we're an MSI install, make sure to set the marker
1085 // in the client state key so that future updates do the right thing.
1086 if (installer_state
.is_msi()) {
1087 for (size_t i
= 0; i
< products
.size(); ++i
) {
1088 const Product
* product
= products
[i
];
1089 AddSetMsiMarkerWorkItem(installer_state
, product
->distribution(), true,
1090 post_install_task_list
);
1092 // We want MSI installs to take over the Add/Remove Programs entry. Make a
1093 // best-effort attempt to delete any entry left over from previous non-MSI
1094 // installations for the same type of install (system or per user).
1095 if (product
->ShouldCreateUninstallEntry()) {
1096 AddDeleteUninstallEntryForMSIWorkItems(installer_state
, *product
,
1097 post_install_task_list
);
1105 void AddInstallWorkItems(const InstallationState
& original_state
,
1106 const InstallerState
& installer_state
,
1107 const base::FilePath
& setup_path
,
1108 const base::FilePath
& archive_path
,
1109 const base::FilePath
& src_path
,
1110 const base::FilePath
& temp_path
,
1111 const Version
* current_version
,
1112 const Version
& new_version
,
1113 WorkItemList
* install_list
) {
1114 DCHECK(install_list
);
1116 const base::FilePath
& target_path
= installer_state
.target_path();
1118 // A temp directory that work items need and the actual install directory.
1119 install_list
->AddCreateDirWorkItem(temp_path
);
1120 install_list
->AddCreateDirWorkItem(target_path
);
1122 if (installer_state
.FindProduct(BrowserDistribution::CHROME_BROWSER
) ||
1123 installer_state
.FindProduct(BrowserDistribution::CHROME_BINARIES
)) {
1124 AddChromeWorkItems(original_state
,
1135 #if defined(GOOGLE_CHROME_BUILD)
1136 // For Chrome, unconditionally remove the legacy app_host.exe.
1137 if (!InstallUtil::IsChromeSxSProcess())
1138 AddRemoveLegacyAppHostExeWorkItems(target_path
, temp_path
, install_list
);
1139 #endif // GOOGLE_CHROME_BUILD
1141 // Copy installer in install directory
1142 AddInstallerCopyTasks(installer_state
, setup_path
, archive_path
, temp_path
,
1143 new_version
, install_list
);
1145 const HKEY root
= installer_state
.root_key();
1146 // Only set "lang" for user-level installs since for system-level, the install
1147 // language may not be related to a given user's runtime language.
1148 const bool add_language_identifier
= !installer_state
.system_install();
1150 const Products
& products
= installer_state
.products();
1151 for (Products::const_iterator it
= products
.begin(); it
< products
.end();
1153 const Product
& product
= **it
;
1155 AddUninstallShortcutWorkItems(installer_state
, setup_path
, new_version
,
1156 product
, install_list
);
1158 BrowserDistribution
* dist
= product
.distribution();
1159 AddVersionKeyWorkItems(root
,
1160 dist
->GetVersionKey(),
1161 dist
->GetDisplayName(),
1163 add_language_identifier
,
1166 AddDelegateExecuteWorkItems(installer_state
, target_path
, new_version
,
1167 product
, install_list
);
1169 AddActiveSetupWorkItems(installer_state
, new_version
, product
,
1173 // Ensure that the Clients key for the binaries is gone for single installs
1174 // (but not for SxS Chrome).
1175 if (!installer_state
.is_multi_install() &&
1176 !InstallUtil::IsChromeSxSProcess()) {
1177 BrowserDistribution
* binaries_dist
=
1178 BrowserDistribution::GetSpecificDistribution(
1179 BrowserDistribution::CHROME_BINARIES
);
1180 install_list
->AddDeleteRegKeyWorkItem(root
,
1181 binaries_dist
->GetVersionKey(),
1185 #if defined(GOOGLE_CHROME_BUILD)
1186 if (!InstallUtil::IsChromeSxSProcess())
1187 AddRemoveLegacyAppCommandsWorkItems(installer_state
, install_list
);
1188 #endif // GOOGLE_CHROME_BUILD
1190 // Add any remaining work items that involve special settings for
1192 AddProductSpecificWorkItems(original_state
,
1196 current_version
== NULL
,
1197 add_language_identifier
,
1200 // Copy over brand, usagestats, and other values.
1201 AddGoogleUpdateWorkItems(original_state
, installer_state
, install_list
);
1203 // Migrate usagestats back to Chrome.
1204 AddMigrateUsageStatesWorkItems(original_state
, installer_state
, install_list
);
1206 // Append the tasks that run after the installation.
1207 AppendPostInstallTasks(installer_state
,
1214 void AddRegisterComDllWorkItems(const base::FilePath
& dll_folder
,
1215 const std::vector
<base::FilePath
>& dll_list
,
1218 bool ignore_failures
,
1219 WorkItemList
* work_item_list
) {
1220 DCHECK(work_item_list
);
1221 if (dll_list
.empty()) {
1222 VLOG(1) << "No COM DLLs to register";
1224 std::vector
<base::FilePath
>::const_iterator
dll_iter(dll_list
.begin());
1225 for (; dll_iter
!= dll_list
.end(); ++dll_iter
) {
1226 base::FilePath dll_path
= dll_folder
.Append(*dll_iter
);
1227 WorkItem
* work_item
= work_item_list
->AddSelfRegWorkItem(
1228 dll_path
.value(), do_register
, !system_level
);
1230 work_item
->set_ignore_failure(ignore_failures
);
1235 void AddSetMsiMarkerWorkItem(const InstallerState
& installer_state
,
1236 BrowserDistribution
* dist
,
1238 WorkItemList
* work_item_list
) {
1239 DCHECK(work_item_list
);
1240 DWORD msi_value
= set
? 1 : 0;
1241 WorkItem
* set_msi_work_item
=
1242 work_item_list
->AddSetRegValueWorkItem(installer_state
.root_key(),
1243 dist
->GetStateKey(),
1245 google_update::kRegMSIField
,
1248 DCHECK(set_msi_work_item
);
1249 set_msi_work_item
->set_ignore_failure(true);
1250 set_msi_work_item
->set_log_message("Could not write MSI marker!");
1253 void AddDelegateExecuteWorkItems(const InstallerState
& installer_state
,
1254 const base::FilePath
& target_path
,
1255 const Version
& new_version
,
1256 const Product
& product
,
1257 WorkItemList
* list
) {
1258 base::string16 handler_class_uuid
;
1259 BrowserDistribution
* dist
= product
.distribution();
1260 if (!dist
->GetCommandExecuteImplClsid(&handler_class_uuid
)) {
1261 if (InstallUtil::IsChromeSxSProcess()) {
1262 CleanupBadCanaryDelegateExecuteRegistration(target_path
, list
);
1264 VLOG(1) << "No DelegateExecute verb handler processing to do for "
1265 << dist
->GetDisplayName();
1270 HKEY root
= installer_state
.root_key();
1271 base::string16
delegate_execute_path(L
"Software\\Classes\\CLSID\\");
1272 delegate_execute_path
.append(handler_class_uuid
);
1274 // Unconditionally remove registration regardless of whether or not it is
1275 // needed since builds after r132190 included it when it wasn't strictly
1276 // necessary. Do this removal before adding in the new key to ensure that
1277 // the COM probe/flush below does its job.
1278 AddUninstallDelegateExecuteWorkItems(root
, delegate_execute_path
, list
);
1280 // Add work items to register the handler iff it is present.
1281 // See also shell_util.cc's GetProgIdEntries.
1282 if (installer_state
.operation() != InstallerState::UNINSTALL
) {
1283 VLOG(1) << "Adding registration items for DelegateExecute verb handler.";
1285 // Force COM to flush its cache containing the path to the old handler.
1286 list
->AddCallbackWorkItem(base::Bind(&ProbeCommandExecuteCallback
,
1287 handler_class_uuid
));
1289 // The path to the exe (in the version directory).
1290 base::FilePath
delegate_execute(target_path
);
1291 if (new_version
.IsValid())
1292 delegate_execute
= delegate_execute
.AppendASCII(new_version
.GetString());
1293 delegate_execute
= delegate_execute
.Append(kDelegateExecuteExe
);
1295 // Command-line featuring the quoted path to the exe.
1296 base::string16
command(1, L
'"');
1297 command
.append(delegate_execute
.value()).append(1, L
'"');
1299 // Register the CommandExecuteImpl class in Software\Classes\CLSID\...
1300 list
->AddCreateRegKeyWorkItem(
1301 root
, delegate_execute_path
, WorkItem::kWow64Default
);
1302 list
->AddSetRegValueWorkItem(root
,
1303 delegate_execute_path
,
1304 WorkItem::kWow64Default
,
1306 L
"CommandExecuteImpl Class",
1308 base::string16
subkey(delegate_execute_path
);
1309 subkey
.append(L
"\\LocalServer32");
1310 list
->AddCreateRegKeyWorkItem(root
, subkey
, WorkItem::kWow64Default
);
1311 list
->AddSetRegValueWorkItem(
1312 root
, subkey
, WorkItem::kWow64Default
, L
"", command
, true);
1313 list
->AddSetRegValueWorkItem(root
,
1315 WorkItem::kWow64Default
,
1316 L
"ServerExecutable",
1317 delegate_execute
.value(),
1320 subkey
.assign(delegate_execute_path
).append(L
"\\Programmable");
1321 list
->AddCreateRegKeyWorkItem(root
, subkey
, WorkItem::kWow64Default
);
1325 void AddActiveSetupWorkItems(const InstallerState
& installer_state
,
1326 const Version
& new_version
,
1327 const Product
& product
,
1328 WorkItemList
* list
) {
1329 DCHECK(installer_state
.operation() != InstallerState::UNINSTALL
);
1330 BrowserDistribution
* dist
= product
.distribution();
1332 if (!product
.is_chrome() || !installer_state
.system_install()) {
1333 const char* install_level
=
1334 installer_state
.system_install() ? "system" : "user";
1335 VLOG(1) << "No Active Setup processing to do for " << install_level
1336 << "-level " << dist
->GetDisplayName();
1339 DCHECK(installer_state
.RequiresActiveSetup());
1341 const HKEY root
= HKEY_LOCAL_MACHINE
;
1342 const base::string16
active_setup_path(InstallUtil::GetActiveSetupPath(dist
));
1344 VLOG(1) << "Adding registration items for Active Setup.";
1345 list
->AddCreateRegKeyWorkItem(
1346 root
, active_setup_path
, WorkItem::kWow64Default
);
1347 list
->AddSetRegValueWorkItem(root
,
1349 WorkItem::kWow64Default
,
1351 dist
->GetDisplayName(),
1354 base::FilePath
active_setup_exe(installer_state
.GetInstallerDirectory(
1355 new_version
).Append(kActiveSetupExe
));
1356 base::CommandLine
cmd(active_setup_exe
);
1357 cmd
.AppendSwitch(installer::switches::kConfigureUserSettings
);
1358 cmd
.AppendSwitch(installer::switches::kVerboseLogging
);
1359 cmd
.AppendSwitch(installer::switches::kSystemLevel
);
1360 product
.AppendProductFlags(&cmd
);
1361 list
->AddSetRegValueWorkItem(root
,
1363 WorkItem::kWow64Default
,
1365 cmd
.GetCommandLineString(),
1368 // TODO(grt): http://crbug.com/75152 Write a reference to a localized
1370 list
->AddSetRegValueWorkItem(root
,
1372 WorkItem::kWow64Default
,
1374 dist
->GetDisplayName(),
1377 list
->AddSetRegValueWorkItem(root
,
1379 WorkItem::kWow64Default
,
1381 static_cast<DWORD
>(1U),
1384 list
->AddWorkItem(new UpdateActiveSetupVersionWorkItem(
1385 active_setup_path
, UpdateActiveSetupVersionWorkItem::UPDATE
));
1388 void AddDeleteOldIELowRightsPolicyWorkItems(
1389 const InstallerState
& installer_state
,
1390 WorkItemList
* install_list
) {
1391 DCHECK(install_list
);
1393 base::string16 key_path
;
1394 GetOldIELowRightsElevationPolicyKeyPath(&key_path
);
1395 install_list
->AddDeleteRegKeyWorkItem(
1396 installer_state
.root_key(), key_path
, WorkItem::kWow64Default
);
1399 void AppendUninstallCommandLineFlags(const InstallerState
& installer_state
,
1400 const Product
& product
,
1401 base::CommandLine
* uninstall_cmd
) {
1402 DCHECK(uninstall_cmd
);
1404 uninstall_cmd
->AppendSwitch(installer::switches::kUninstall
);
1406 // Append the product-specific uninstall flags.
1407 product
.AppendProductFlags(uninstall_cmd
);
1408 if (installer_state
.is_msi())
1409 uninstall_cmd
->AppendSwitch(installer::switches::kMsi
);
1410 if (installer_state
.system_install())
1411 uninstall_cmd
->AppendSwitch(installer::switches::kSystemLevel
);
1412 if (installer_state
.verbose_logging())
1413 uninstall_cmd
->AppendSwitch(installer::switches::kVerboseLogging
);
1416 void RefreshElevationPolicy() {
1417 const wchar_t kIEFrameDll
[] = L
"ieframe.dll";
1418 const char kIERefreshPolicy
[] = "IERefreshElevationPolicy";
1420 HMODULE ieframe
= LoadLibrary(kIEFrameDll
);
1422 typedef HRESULT (__stdcall
*IERefreshPolicy
)();
1423 IERefreshPolicy ie_refresh_policy
= reinterpret_cast<IERefreshPolicy
>(
1424 GetProcAddress(ieframe
, kIERefreshPolicy
));
1426 if (ie_refresh_policy
) {
1427 ie_refresh_policy();
1429 VLOG(1) << kIERefreshPolicy
<< " not supported.";
1432 FreeLibrary(ieframe
);
1434 VLOG(1) << "Cannot load " << kIEFrameDll
;
1438 void AddOsUpgradeWorkItems(const InstallerState
& installer_state
,
1439 const base::FilePath
& setup_path
,
1440 const Version
& new_version
,
1441 const Product
& product
,
1442 WorkItemList
* install_list
) {
1443 const HKEY root_key
= installer_state
.root_key();
1444 base::string16
cmd_key(
1445 GetRegCommandKey(product
.distribution(), kCmdOnOsUpgrade
));
1447 if (installer_state
.operation() == InstallerState::UNINSTALL
) {
1448 install_list
->AddDeleteRegKeyWorkItem(root_key
, cmd_key
, KEY_WOW64_32KEY
)
1449 ->set_log_message("Removing OS upgrade command");
1451 // Register with Google Update to have setup.exe --on-os-upgrade called on
1453 base::CommandLine
cmd_line(
1454 installer_state
.GetInstallerDirectory(new_version
)
1455 .Append(setup_path
.BaseName()));
1456 // Add the main option to indicate OS upgrade flow.
1457 cmd_line
.AppendSwitch(installer::switches::kOnOsUpgrade
);
1458 // Add product-specific options.
1459 product
.AppendProductFlags(&cmd_line
);
1460 if (installer_state
.system_install())
1461 cmd_line
.AppendSwitch(installer::switches::kSystemLevel
);
1462 // Log everything for now.
1463 cmd_line
.AppendSwitch(installer::switches::kVerboseLogging
);
1465 AppCommand
cmd(cmd_line
.GetCommandLineString());
1466 cmd
.set_is_auto_run_on_os_upgrade(true);
1467 cmd
.AddWorkItems(installer_state
.root_key(), cmd_key
, install_list
);
1471 void AddQuickEnableChromeFrameWorkItems(const InstallerState
& installer_state
,
1472 WorkItemList
* work_item_list
) {
1473 DCHECK(work_item_list
);
1475 base::string16
cmd_key(
1476 GetRegCommandKey(BrowserDistribution::GetSpecificDistribution(
1477 BrowserDistribution::CHROME_BINARIES
),
1478 kCmdQuickEnableCf
));
1480 // Unconditionally remove the legacy Quick Enable command from the binaries.
1481 // Do this even if multi-install Chrome isn't installed to ensure that it is
1482 // not left behind in any case.
1483 work_item_list
->AddDeleteRegKeyWorkItem(
1484 installer_state
.root_key(), cmd_key
, KEY_WOW64_32KEY
)
1485 ->set_log_message("removing " + base::UTF16ToASCII(kCmdQuickEnableCf
) +
1489 } // namespace installer