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

Unified 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: '' 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 side-by-side diff with in-line comments
Download patch
Index: chrome/installer/setup/install_worker.cc
===================================================================
--- chrome/installer/setup/install_worker.cc (revision 0)
+++ chrome/installer/setup/install_worker.cc (revision 0)
@@ -0,0 +1,816 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This file contains the definitions of the installer functions that build
+// the WorkItemList used to install the application.
+
+#include "chrome/installer/setup/install_worker.h"
+
+#include <shlobj.h>
+#include <time.h>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "base/version.h"
+#include "base/win/registry.h"
+#include "chrome/installer/setup/install.h"
+#include "chrome/installer/setup/setup_constants.h"
+#include "chrome/installer/util/chrome_frame_distribution.h"
+#include "chrome/installer/util/conditional_work_item_list.h"
+#include "chrome/installer/util/create_reg_key_work_item.h"
+#include "chrome/installer/util/google_update_constants.h"
+#include "chrome/installer/util/helper.h"
+#include "chrome/installer/util/installation_state.h"
+#include "chrome/installer/util/installer_state.h"
+#include "chrome/installer/util/install_util.h"
+#include "chrome/installer/util/master_preferences.h"
+#include "chrome/installer/util/master_preferences_constants.h"
+#include "chrome/installer/util/package.h"
+#include "chrome/installer/util/package_properties.h"
+#include "chrome/installer/util/product.h"
+#include "chrome/installer/util/set_reg_value_work_item.h"
+#include "chrome/installer/util/shell_util.h"
+#include "chrome/installer/util/util_constants.h"
+#include "chrome/installer/util/work_item_list.h"
+
+using base::win::RegKey;
+
+namespace {
+
+// This method tells if we are running on 64 bit platform so that we can copy
+// one extra exe. If the API call to determine 64 bit fails, we play it safe
+// and return true anyway so that the executable can be copied.
+bool Is64bit() {
+ typedef BOOL (WINAPI *WOW_FUNC)(HANDLE, PBOOL);
tommi (sloooow) - chröme 2011/01/12 19:02:49 BOOL* instead of PBOOL.
robertshield 2011/01/13 17:06:32 Done.
+ BOOL is64 = FALSE;
amit 2011/01/12 17:41:22 nit: is_64bit :)
robertshield 2011/01/13 17:06:32 Done.
+
+ HANDLE handle = GetCurrentProcess();
tommi (sloooow) - chröme 2011/01/12 19:02:49 'handle' is less descriptive than just calling Get
robertshield 2011/01/13 17:06:32 Done. (In case it wasn't clear, this code is copy
+ HMODULE module = GetModuleHandle(L"kernel32.dll");
+ WOW_FUNC p = reinterpret_cast<WOW_FUNC>(GetProcAddress(module,
tommi (sloooow) - chröme 2011/01/12 19:02:49 nit: is_wow_64 instead of p
robertshield 2011/01/13 17:06:32 Done.
+ "IsWow64Process"));
+ if ((p != NULL) && (!(p)(handle, &is64) || (is64 != FALSE))) {
tommi (sloooow) - chröme 2011/01/12 19:02:49 You don't really need the if and two return statem
robertshield 2011/01/13 17:06:32 Done.
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace
+
+namespace installer {
+
erikwright (departed) 2011/01/12 16:31:49 I assume these are identical to the originals?
tommi (sloooow) - chröme 2011/01/12 19:02:49 +1 (to save on review time)
robertshield 2011/01/13 17:06:32 Yes, copy/pasted.
robertshield 2011/01/13 17:06:32 Done.
+// Local helper to call AddRegisterComDllWorkItems for all DLLs in a set of
+// products managed by a given package.
+void AddRegisterComDllWorkItemsForPackage(const Package& package,
+ const Version* old_version,
+ const Version& new_version,
+ WorkItemList* work_item_list) {
+ // First collect the list of DLLs to be registered from each product.
+ const Products& products = package.products();
+ Products::const_iterator product_iter(products.begin());
+ std::vector<FilePath> com_dll_list;
+ for (; product_iter != products.end(); ++product_iter) {
+ BrowserDistribution* dist = product_iter->get()->distribution();
+ std::vector<FilePath> dist_dll_list(dist->GetComDllList());
+ com_dll_list.insert(com_dll_list.end(), dist_dll_list.begin(),
+ dist_dll_list.end());
+ }
+
+ // Then, if we got some, attempt to unregister the DLLs from the old
+ // version directory and then re-register them in the new one.
+ // Note that if we are migrating the install directory then we will not
+ // successfully unregister the old DLLs.
+ // TODO(robertshield): See whether we need to fix the migration case.
+ // TODO(robertshield): If we ever remove a DLL from a product, this will
+ // not unregister it on update. We should build the unregistration list from
+ // saved state instead of assuming it is the same as the registration list.
+ if (!com_dll_list.empty()) {
+ if (old_version) {
+ FilePath old_dll_path(
+ package.path().Append(UTF8ToWide(old_version->GetString())));
+
+ installer::AddRegisterComDllWorkItems(old_dll_path,
+ com_dll_list,
+ package.system_level(),
+ false, // Unregister
+ true, // May fail
+ work_item_list);
+ }
+
+ FilePath dll_path(
+ package.path().Append(UTF8ToWide(new_version.GetString())));
+ installer::AddRegisterComDllWorkItems(dll_path,
+ com_dll_list,
+ package.system_level(),
+ true, // Register
+ false, // Must succeed.
+ work_item_list);
+ }
+}
+
+void AddInstallerCopyTasks(const FilePath& setup_path,
+ const FilePath& archive_path,
+ const FilePath& temp_path,
+ const Version& new_version,
+ WorkItemList* install_list,
+ const Package& package) {
+ DCHECK(install_list);
+ FilePath installer_dir(package.GetInstallerDirectory(new_version));
+ install_list->AddCreateDirWorkItem(installer_dir);
+
+ FilePath exe_dst(installer_dir.Append(setup_path.BaseName()));
+ FilePath archive_dst(installer_dir.Append(archive_path.BaseName()));
+
+ install_list->AddCopyTreeWorkItem(setup_path.value(), exe_dst.value(),
+ temp_path.value(), WorkItem::ALWAYS);
+ if (package.system_level()) {
+ install_list->AddCopyTreeWorkItem(archive_path.value(), archive_dst.value(),
+ temp_path.value(), WorkItem::ALWAYS);
+ } else {
+ install_list->AddMoveTreeWorkItem(archive_path.value(), archive_dst.value(),
+ temp_path.value());
+ }
+}
+
+// This method adds work items to create (or update) Chrome uninstall entry in
+// either the Control Panel->Add/Remove Programs list or in the Omaha client
+// state key if running under an MSI installer.
+void AddUninstallShortcutWorkItems(const FilePath& setup_path,
+ const Version& new_version,
+ WorkItemList* install_list,
+ const Product& product) {
+ HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE :
+ HKEY_CURRENT_USER;
+ BrowserDistribution* browser_dist = product.distribution();
+ DCHECK(browser_dist);
+
+ // When we are installed via an MSI, we need to store our uninstall strings
+ // in the Google Update client state key. We do this even for non-MSI
+ // managed installs to avoid breaking the edge case whereby an MSI-managed
+ // install is updated by a non-msi installer (which would confuse the MSI
+ // machinery if these strings were not also updated).
+ // Do not quote the command line for the MSI invocation.
+ FilePath install_path(product.package().path());
+ FilePath installer_path(
+ product.package().GetInstallerDirectory(new_version));
+ installer_path = installer_path.Append(setup_path.BaseName());
+
+ CommandLine uninstall_arguments(CommandLine::NO_PROGRAM);
+ AppendUninstallCommandLineFlags(&uninstall_arguments, product);
+
+ if (product.is_chrome()) {
+ // The Chrome uninstallation command serves as the master uninstall
+ // command for Chrome + all other products (i.e. Chrome Frame) that do
+ // not have an uninstall entry in the Add/Remove Programs dialog.
+ const Products& products = product.package().products();
+ for (size_t i = 0; i < products.size(); ++i) {
+ const Product& p = *products[i];
+ if (!p.is_chrome() && !p.ShouldCreateUninstallEntry()) {
+ p.distribution()->AppendUninstallCommandLineFlags(&uninstall_arguments);
+ }
+ }
+ }
+
+ std::wstring update_state_key(browser_dist->GetStateKey());
+ install_list->AddCreateRegKeyWorkItem(reg_root, update_state_key);
+ install_list->AddSetRegValueWorkItem(reg_root, update_state_key,
+ installer::kUninstallStringField, installer_path.value(), true);
+ install_list->AddSetRegValueWorkItem(reg_root, update_state_key,
+ installer::kUninstallArgumentsField,
+ uninstall_arguments.command_line_string(), true);
+
+ if (product.ShouldCreateUninstallEntry()) {
+ // We need to quote the command line for the Add/Remove Programs dialog.
+ CommandLine quoted_uninstall_cmd(installer_path);
+ DCHECK_EQ(quoted_uninstall_cmd.command_line_string()[0], '"');
+ quoted_uninstall_cmd.AppendArguments(uninstall_arguments, false);
+
+ std::wstring uninstall_reg = browser_dist->GetUninstallRegPath();
+ install_list->AddCreateRegKeyWorkItem(reg_root, uninstall_reg);
+ install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
+ installer::kUninstallDisplayNameField,
+ browser_dist->GetAppShortCutName(), true);
+ install_list->AddSetRegValueWorkItem(reg_root,
+ uninstall_reg, installer::kUninstallStringField,
+ quoted_uninstall_cmd.command_line_string(), true);
+ install_list->AddSetRegValueWorkItem(reg_root,
+ uninstall_reg,
+ L"InstallLocation",
+ install_path.value(),
+ true);
+
+ // DisplayIcon, NoModify and NoRepair
+ FilePath chrome_icon(install_path.Append(installer::kChromeExe));
+ ShellUtil::GetChromeIcon(product.distribution(), chrome_icon.value());
+ install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
tommi (sloooow) - chröme 2011/01/12 19:02:49 observation - we should factor out all these facto
robertshield 2011/01/13 17:06:32 I'm mocking the WorkItemList at the moment which a
+ L"DisplayIcon", chrome_icon.value(),
+ true);
+ install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
+ L"NoModify", 1, true);
+ install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
+ L"NoRepair", 1, true);
+
+ install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
+ L"Publisher",
+ browser_dist->GetPublisherName(),
+ true);
+ install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
+ L"Version",
+ UTF8ToWide(new_version.GetString()),
+ true);
+ install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
+ L"DisplayVersion",
+ UTF8ToWide(new_version.GetString()),
+ true);
+ time_t rawtime = time(NULL);
+ struct tm timeinfo = {0};
+ localtime_s(&timeinfo, &rawtime);
+ wchar_t buffer[9];
+ if (wcsftime(buffer, 9, L"%Y%m%d", &timeinfo) == 8) {
+ install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
+ L"InstallDate",
+ buffer, false);
+ }
+ }
+}
+
+
tommi (sloooow) - chröme 2011/01/12 19:02:49 one empty line
robertshield 2011/01/13 17:06:32 Done.
+
+// Create Version key for a product (if not already present) and sets the new
+// product version as the last step.
+void AddVersionKeyWorkItems(HKEY root,
+ const Product& product,
+ const Version& new_version,
+ WorkItemList* list) {
+ // Create Version key for each distribution (if not already present) and set
+ // the new product version as the last step.
+ std::wstring version_key(product.distribution()->GetVersionKey());
+ list->AddCreateRegKeyWorkItem(root, version_key);
+
+ std::wstring product_name(product.distribution()->GetAppShortCutName());
+ list->AddSetRegValueWorkItem(root, version_key, google_update::kRegNameField,
+ product_name, true); // overwrite name also
+ list->AddSetRegValueWorkItem(root, version_key,
+ google_update::kRegOopcrashesField, 1,
+ false); // set during first install
+ list->AddSetRegValueWorkItem(root, version_key,
+ google_update::kRegVersionField,
+ UTF8ToWide(new_version.GetString()),
+ true); // overwrite version
+}
+
+void AddProductSpecificWorkItems(bool install,
+ const FilePath& setup_path,
+ const Version& new_version,
+ const Package& package,
+ WorkItemList* list) {
+ const Products& products = package.products();
+ for (size_t i = 0; i < products.size(); ++i) {
+ const Product& p = *products[i];
+ if (p.is_chrome_frame()) {
+ AddChromeFrameWorkItems(install, setup_path, new_version, p, list);
+ }
+ }
+}
+
tommi (sloooow) - chröme 2011/01/12 19:02:49 one empty line
robertshield 2011/01/13 17:06:32 Done.
+
+// Adds work items that make registry adjustments for Google Update. When a
+// product is installed (including overinstall), Google Update will write the
+// channel ("ap") value into either Chrome or Chrome Frame's ClientState key.
+// In the multi-install case, this value is used as the basis upon which the
+// package's channel value is built (by adding the ordered list of installed
+// products and their options).
+void AddGoogleUpdateWorkItems(const InstallationState& original_state,
+ const InstallerState& installer_state,
+ const Package& package,
+ WorkItemList* install_list) {
+ // Is a multi-install product being installed or over-installed?
+ if (installer_state.operation() != InstallerState::MULTI_INSTALL)
+ return;
+
+ const HKEY reg_root = package.system_level() ? HKEY_LOCAL_MACHINE :
+ HKEY_CURRENT_USER;
+ const std::wstring key_path = installer_state.state_key();
+ ChannelInfo channel_info;
+
+ // Update the "ap" value for the product being installed/updated.
+ // It is completely acceptable for there to be no "ap" value or even no
+ // ClientState key. Note that we check the registry rather than
+ // original_state since on a fresh install the "ap" value will be present
+ // sans "pv" value.
+ channel_info.Initialize(RegKey(reg_root, key_path.c_str(), KEY_QUERY_VALUE));
+
+ // This is a multi-install product.
+ bool modified = channel_info.SetMultiInstall(true);
+
+ // Add the appropriate modifiers for all products and their options.
+ Products::const_iterator scan = package.products().begin();
+ const Products::const_iterator end = package.products().end();
+ for (; scan != end; ++scan) {
+ modified |= scan->get()->distribution()->SetChannelFlags(true,
+ &channel_info);
+ }
+
+ // Write the results if needed.
+ if (modified) {
+ install_list->AddSetRegValueWorkItem(reg_root, key_path,
+ google_update::kRegApField,
+ channel_info.value(), true);
+ }
+
+ // Synchronize the other products and the package with this one.
+ std::wstring other_key;
+ std::vector<std::wstring> keys;
+
+ keys.reserve(package.products().size());
+ other_key = package.properties()->GetStateKey();
+ if (other_key != key_path)
+ keys.push_back(other_key);
+ scan = package.products().begin();
+ for (; scan != end; ++scan) {
+ other_key = scan->get()->distribution()->GetStateKey();
+ if (other_key != key_path)
+ keys.push_back(other_key);
+ }
+
+ RegKey key;
+ ChannelInfo other_info;
+ std::vector<std::wstring>::const_iterator kscan = keys.begin();
+ std::vector<std::wstring>::const_iterator kend = keys.end();
+ for (; kscan != kend; ++kscan) {
+ // Handle the case where the ClientState key doesn't exist by creating it.
+ // This takes care of the multi-installer's package key, which is not
+ // created by Google Update for us.
+ if (!key.Open(reg_root, kscan->c_str(), KEY_QUERY_VALUE) ||
+ !other_info.Initialize(key)) {
+ other_info.set_value(std::wstring());
+ }
+ if (!other_info.Equals(channel_info)) {
+ if (!key.Valid())
+ install_list->AddCreateRegKeyWorkItem(reg_root, *kscan);
+ install_list->AddSetRegValueWorkItem(reg_root, *kscan,
+ google_update::kRegApField,
+ channel_info.value(), true);
+ }
+ }
+ // TODO(grt): check for other keys/values we should put in the package's
+ // ClientState and/or Clients key.
+}
+
+// This is called when an MSI installation is run. It may be that a user is
+// attempting to install the MSI on top of a non-MSI managed installation.
+// If so, try and remove any existing uninstallation shortcuts, as we want the
+// uninstall to be managed entirely by the MSI machinery (accessible via the
+// Add/Remove programs dialog).
+void AddDeleteUninstallShortcutsForMSIWorkItems(const Product& product,
+ WorkItemList* work_item_list) {
+ DCHECK(product.IsMsi()) << "This must only be called for MSI installations!";
+
+ // First attempt to delete the old installation's ARP dialog entry.
+ HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE :
+ HKEY_CURRENT_USER;
+ base::win::RegKey root_key(reg_root, L"", KEY_ALL_ACCESS);
+ std::wstring uninstall_reg(product.distribution()->GetUninstallRegPath());
+
+ WorkItem* delete_reg_key = work_item_list->AddDeleteRegKeyWorkItem(
+ reg_root, uninstall_reg);
+ delete_reg_key->set_ignore_failure(true);
+
+ // Then attempt to delete the old installation's start menu shortcut.
+ FilePath uninstall_link;
+ if (product.system_level()) {
+ PathService::Get(base::DIR_COMMON_START_MENU, &uninstall_link);
+ } else {
+ PathService::Get(base::DIR_START_MENU, &uninstall_link);
+ }
+
+ if (uninstall_link.empty()) {
+ LOG(ERROR) << "Failed to get location for shortcut.";
+ } else {
+ uninstall_link = uninstall_link.Append(
+ product.distribution()->GetAppShortCutName());
+ uninstall_link = uninstall_link.Append(
+ product.distribution()->GetUninstallLinkName() + L".lnk");
+ VLOG(1) << "Deleting old uninstall shortcut (if present): "
+ << uninstall_link.value();
+ WorkItem* delete_link = work_item_list->AddDeleteTreeWorkItem(
+ uninstall_link);
+ delete_link->set_ignore_failure(true);
+ delete_link->set_log_message(
+ "Failed to delete old uninstall shortcut.");
+ }
+}
+
tommi (sloooow) - chröme 2011/01/12 19:02:49 one empty line (and throughout)
robertshield 2011/01/13 17:06:32 Done.
+
+// After a successful copying of all the files, this function is called to
+// do a few post install tasks:
+// - Handle the case of in-use-update by updating "opv" (old version) key or
+// deleting it if not required.
+// - Register any new dlls and unregister old dlls.
+// - If this is an MSI install, ensures that the MSI marker is set, and sets
+// it if not.
+// If these operations are successful, the function returns true, otherwise
+// false.
+bool AppendPostInstallTasks(bool multi_install,
+ const FilePath& setup_path,
+ const FilePath& new_chrome_exe,
+ const Version* current_version,
+ const Version& new_version,
+ const Package& package,
+ WorkItemList* post_install_task_list) {
+ DCHECK(post_install_task_list);
+ HKEY root = package.system_level() ? HKEY_LOCAL_MACHINE :
+ HKEY_CURRENT_USER;
+ const Products& products = package.products();
+
tommi (sloooow) - chröme 2011/01/12 19:02:49 here too :)
robertshield 2011/01/13 17:06:32 Done.
+
+ // Append work items that will only be executed if this was an update.
+ // We update the 'opv' key with the current version that is active and 'cmd'
+ // key with the rename command to run.
+ {
+ scoped_ptr<WorkItemList> in_use_update_work_items(
+ WorkItem::CreateConditionalWorkItemList(
+ new ConditionRunIfFileExists(new_chrome_exe)));
+ in_use_update_work_items->set_log_message("InUseUpdateWorkItemList");
+
+ FilePath installer_path(package.GetInstallerDirectory(new_version)
+ .Append(setup_path.BaseName()));
+
+ CommandLine rename(installer_path);
+ rename.AppendSwitch(installer::switches::kRenameChromeExe);
+ if (package.system_level())
+ rename.AppendSwitch(installer::switches::kSystemLevel);
+
+ if (InstallUtil::IsChromeSxSProcess())
+ rename.AppendSwitch(installer::switches::kChromeSxS);
+
+ if (multi_install)
+ rename.AppendSwitch(installer::switches::kMultiInstall);
+
+ std::wstring version_key;
+ for (size_t i = 0; i < products.size(); ++i) {
+ BrowserDistribution* dist = products[i]->distribution();
+ version_key = dist->GetVersionKey();
+
+ if (current_version != NULL) {
+ in_use_update_work_items->AddSetRegValueWorkItem(root, version_key,
+ google_update::kRegOldVersionField,
+ UTF8ToWide(current_version->GetString()), true);
+ }
+
+ // Adding this registry entry for all products is overkill.
+ // However, as it stands, we don't have a way to know which distribution
+ // will check the key and run the command, so we add it for all.
+ // After the first run, the subsequent runs should just be noops.
+ // (see Upgrade::SwapNewChromeExeIfPresent).
+ in_use_update_work_items->AddSetRegValueWorkItem(
+ root,
+ version_key,
+ google_update::kRegRenameCmdField,
+ rename.command_line_string(),
+ true);
+ }
+
+ if (multi_install) {
+ PackageProperties* props = package.properties();
+ if (props->ReceivesUpdates() && current_version != NULL) {
+ in_use_update_work_items->AddSetRegValueWorkItem(
+ root,
+ props->GetVersionKey(),
+ google_update::kRegOldVersionField,
+ UTF8ToWide(current_version->GetString()),
+ true);
+ // TODO(tommi): We should move the rename command here. We also need to
+ // update Upgrade::SwapNewChromeExeIfPresent.
+ }
+ }
+
+ post_install_task_list->AddWorkItem(in_use_update_work_items.release());
+ }
+
+
+ // Append work items that will be executed if this was NOT an in-use update.
+ {
+ scoped_ptr<WorkItemList> regular_update_work_items(
+ WorkItem::CreateConditionalWorkItemList(
+ new Not(new ConditionRunIfFileExists(new_chrome_exe))));
+ regular_update_work_items->set_log_message(
+ "RegularUpdateWorkItemList");
+
+ // Since this was not an in-use-update, delete 'opv' and 'cmd' keys.
+ for (size_t i = 0; i < products.size(); ++i) {
+ BrowserDistribution* dist = products[i]->distribution();
+ std::wstring version_key(dist->GetVersionKey());
+ regular_update_work_items->AddDeleteRegValueWorkItem(root, version_key,
+ google_update::kRegOldVersionField,
+ true);
+ regular_update_work_items->AddDeleteRegValueWorkItem(root, version_key,
+ google_update::kRegRenameCmdField,
+ true);
+ }
+
+ post_install_task_list->AddWorkItem(regular_update_work_items.release());
+ }
+
+ AddRegisterComDllWorkItemsForPackage(package, current_version, new_version,
+ post_install_task_list);
+
+ for (size_t i = 0; i < products.size(); ++i) {
+ const Product* product = products[i];
+ // If we're told that we're an MSI install, make sure to set the marker
+ // in the client state key so that future updates do the right thing.
+ if (product->IsMsi()) {
+ AddSetMsiMarkerWorkItem(*product, true, post_install_task_list);
+
+ // We want MSI installs to take over the Add/Remove Programs shortcut.
+ // Make a best-effort attempt to delete any shortcuts left over from
+ // previous non-MSI installations for the same type of install (system or
+ // per user).
+ AddDeleteUninstallShortcutsForMSIWorkItems(*product,
+ post_install_task_list);
+ }
+ }
+
+ return true;
+}
+
+void AddInstallWorkItems(const InstallationState& original_state,
+ const InstallerState& installer_state,
+ bool multi_install,
+ const FilePath& setup_path,
+ const FilePath& archive_path,
+ const FilePath& src_path,
+ const FilePath& temp_dir,
+ const Version& new_version,
+ scoped_ptr<Version>* current_version,
+ const Package& package,
+ WorkItemList* install_list) {
+ DCHECK(install_list);
+
+ // A temp directory that work items need and the actual install directory.
+ install_list->AddCreateDirWorkItem(temp_dir);
+ install_list->AddCreateDirWorkItem(package.path());
+
+ // Delete any new_chrome.exe if present (we will end up creating a new one
+ // if required) and then copy chrome.exe
+ FilePath new_chrome_exe(
+ package.path().Append(installer::kChromeNewExe));
+
+ install_list->AddDeleteTreeWorkItem(new_chrome_exe);
+ install_list->AddCopyTreeWorkItem(
+ src_path.Append(installer::kChromeExe).value(),
+ package.path().Append(installer::kChromeExe).value(),
+ temp_dir.value(), WorkItem::NEW_NAME_IF_IN_USE, new_chrome_exe.value());
+
+ // Extra executable for 64 bit systems.
+ if (Is64bit()) {
+ install_list->AddCopyTreeWorkItem(
+ src_path.Append(installer::kWowHelperExe).value(),
+ package.path().Append(installer::kWowHelperExe).value(),
+ temp_dir.value(), WorkItem::ALWAYS);
+ }
+
+ // If it is system level install copy the version folder (since we want to
+ // take the permissions of %ProgramFiles% folder) otherwise just move it.
+ if (package.system_level()) {
+ install_list->AddCopyTreeWorkItem(
+ src_path.Append(UTF8ToWide(new_version.GetString())).value(),
+ package.path().Append(UTF8ToWide(new_version.GetString())).value(),
+ temp_dir.value(), WorkItem::ALWAYS);
+ } else {
+ install_list->AddMoveTreeWorkItem(
+ src_path.Append(UTF8ToWide(new_version.GetString())).value(),
+ package.path().Append(UTF8ToWide(new_version.GetString())).value(),
+ temp_dir.value());
+ }
+
+ // Copy the default Dictionaries only if the folder doesn't exist already.
+ install_list->AddCopyTreeWorkItem(
+ src_path.Append(installer::kDictionaries).value(),
+ package.path().Append(installer::kDictionaries).value(),
+ temp_dir.value(), WorkItem::IF_NOT_PRESENT);
+
+ // Delete any old_chrome.exe if present.
+ install_list->AddDeleteTreeWorkItem(
+ package.path().Append(installer::kChromeOldExe));
+
+ // Copy installer in install directory and
+ // add shortcut in Control Panel->Add/Remove Programs.
+ AddInstallerCopyTasks(setup_path, archive_path, temp_dir, new_version,
+ install_list, package);
+
+ HKEY root = package.system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+
+ const Products& products = package.products();
+ for (size_t i = 0; i < products.size(); ++i) {
+ const Product* product = products[i];
+
+ AddUninstallShortcutWorkItems(setup_path, new_version, install_list,
+ *product);
+
+ AddVersionKeyWorkItems(root, *product, new_version, install_list);
+ }
+
+ if (multi_install) {
+ PackageProperties* props = package.properties();
+ if (props->ReceivesUpdates()) {
+ std::wstring version_key(props->GetVersionKey());
+ install_list->AddCreateRegKeyWorkItem(root, version_key);
+ install_list->AddSetRegValueWorkItem(root, version_key,
+ google_update::kRegVersionField,
+ UTF8ToWide(new_version.GetString()),
+ true); // overwrite version
+ install_list->AddSetRegValueWorkItem(root, version_key,
+ google_update::kRegNameField,
+ ASCIIToWide(installer::PackageProperties::kPackageProductName),
+ true); // overwrite name also
+ }
+ }
+
+ // Add any remaining work items that involve special settings for
+ // each product.
+ AddProductSpecificWorkItems(true, setup_path, new_version, package,
+ install_list);
+
+ AddGoogleUpdateWorkItems(original_state, installer_state, package,
+ install_list);
+
+ // Append the tasks that run after the installation.
+ AppendPostInstallTasks(multi_install,
+ setup_path,
+ new_chrome_exe,
+ current_version->get(),
+ new_version,
+ package,
+ install_list);
+}
+
+
+void AddRegisterComDllWorkItems(const FilePath& dll_folder,
+ const std::vector<FilePath>& dll_list,
+ bool system_level,
+ bool do_register,
+ bool ignore_failures,
+ WorkItemList* work_item_list) {
+ DCHECK(work_item_list);
+ if (dll_list.empty()) {
+ VLOG(1) << "No COM DLLs to register";
+ } else {
+ std::vector<FilePath>::const_iterator dll_iter(dll_list.begin());
+ for (; dll_iter != dll_list.end(); ++dll_iter) {
+ FilePath dll_path = dll_folder.Append(*dll_iter);
+ WorkItem* work_item = work_item_list->AddSelfRegWorkItem(
+ dll_path.value(), do_register, !system_level);
+ DCHECK(work_item);
+ work_item->set_ignore_failure(ignore_failures);
+ }
+ }
+}
+
+void AddSetMsiMarkerWorkItem(const Product& product,
+ bool set,
+ WorkItemList* work_item_list) {
+ DCHECK(work_item_list);
+ BrowserDistribution* dist = product.distribution();
+ HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE :
+ HKEY_CURRENT_USER;
+ DWORD msi_value = set ? 1 : 0;
+ WorkItem* set_msi_work_item = work_item_list->AddSetRegValueWorkItem(
+ reg_root, dist->GetStateKey(), google_update::kRegMSIField,
+ msi_value, true);
+ DCHECK(set_msi_work_item);
+ set_msi_work_item->set_ignore_failure(true);
+ set_msi_work_item->set_log_message("Could not write MSI marker!");
+}
+
+void AddChromeFrameWorkItems(bool install,
+ const FilePath& setup_path,
+ const Version& new_version,
+ const Product& product,
+ WorkItemList* list) {
+ DCHECK(product.is_chrome_frame());
+ if (!product.package().multi_install()) {
+ VLOG(1) << "Not adding GCF specific work items for single install.";
+ return;
+ }
+
+ // TODO(tommi): This assumes we know exactly how ShouldCreateUninstallEntry
+ // is implemented. Since there is logic in ChromeFrameDistribution for how
+ // to determine when this is enabled, this is how we have to figure out if
+ // this feature is enabled right now, but it's a hack and we need a cleaner
+ // way to figure this out.
+ // Note that we cannot just check the master preferences for
+ // kChromeFrameReadyMode, since there are other things that need to be correct
+ // in the environment in order to enable this feature.
+ bool ready_mode = !product.distribution()->ShouldCreateUninstallEntry();
+
+ HKEY root = product.package().system_level() ? HKEY_LOCAL_MACHINE :
+ HKEY_CURRENT_USER;
+ bool update_chrome_uninstall_command = false;
+ if (ready_mode) {
+ // If GCF is being installed in ready mode, we write an entry to the
+ // multi-install state key. If the value already exists, we will not
+ // overwrite it since the user might have opted out.
+ list->AddCreateRegKeyWorkItem(root,
+ product.package().properties()->GetStateKey());
+ list->AddSetRegValueWorkItem(root,
+ product.package().properties()->GetStateKey(),
+ installer::kChromeFrameReadyModeField,
+ install ? 1 : 0, // The value we want to set.
+ install ? false : true); // Overwrite existing value.
+ if (!install) {
+ // If Chrome is not also being uninstalled, we need to update its command
+ // line so that it doesn't include uninstalling Chrome Frame now.
+ update_chrome_uninstall_command =
+ (installer::FindProduct(product.package().products(),
+ BrowserDistribution::CHROME_BROWSER) == NULL);
+ }
+ } else {
+ // It doesn't matter here if we're installing or uninstalling Chrome Frame.
+ // If ready mode isn't specified on the command line for installs, we need
+ // to delete the ready mode flag from the registry if it exists - this
+ // constitutes an opt-in for the user. If we're uninstalling CF and ready
+ // mode isn't specified on the command line, that means that CF wasn't
+ // installed with ready mode enabled (the --ready-mode switch should be set
+ // in the registry) so deleting the value should have no effect.
+ // In both cases (install/uninstall), we need to make sure that Chrome's
+ // uninstallation command line does not include the --chrome-frame switch
+ // so that uninstalling Chrome will no longer uninstall Chrome Frame.
+
+ if (RegKey(root, product.package().properties()->GetStateKey().c_str(),
+ KEY_QUERY_VALUE).Valid()) {
+ list->AddDeleteRegValueWorkItem(root,
+ product.package().properties()->GetStateKey(),
+ installer::kChromeFrameReadyModeField, false);
+ }
+
+ const Product* chrome = installer::FindProduct(product.package().products(),
+ BrowserDistribution::CHROME_BROWSER);
+ if (chrome) {
+ // Chrome is already a part of this installation run, so we can assume
+ // that the uninstallation arguments will be updated correctly.
+ } else {
+ // Chrome is not a part of this installation run, so we have to explicitly
+ // check if Chrome is installed, and if so, update its uninstallation
+ // command lines.
+ BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BROWSER,
+ MasterPreferences::ForCurrentProcess());
+ update_chrome_uninstall_command =
+ IsInstalledAsMulti(product.system_level(), dist);
+ }
+ }
+
+ if (update_chrome_uninstall_command) {
+ // Chrome is not a part of this installation run, so we have to explicitly
+ // check if Chrome is installed, and if so, update its uninstallation
+ // command lines.
+ const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
+ BrowserDistribution* chrome_dist =
+ BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BROWSER, prefs);
+ const Package& pack = product.package();
+ scoped_refptr<Package> package(new Package(pack.multi_install(),
+ pack.system_level(), pack.path(), pack.properties()));
+ scoped_refptr<Product> chrome_product(new Product(chrome_dist, package));
+ AddUninstallShortcutWorkItems(setup_path, new_version, list,
+ *chrome_product.get());
+ }
+}
+
+void AppendUninstallCommandLineFlags(CommandLine* uninstall_cmd,
+ const Product& product) {
+ DCHECK(uninstall_cmd);
+
+ uninstall_cmd->AppendSwitch(installer::switches::kUninstall);
+
+ // Append the product-specific uninstall flags.
+ product.distribution()->AppendUninstallCommandLineFlags(uninstall_cmd);
+ if (product.IsMsi()) {
+ uninstall_cmd->AppendSwitch(installer::switches::kMsi);
+ // See comment in uninstall.cc where we check for the kDeleteProfile switch.
+ if (product.is_chrome_frame()) {
+ uninstall_cmd->AppendSwitch(installer::switches::kDeleteProfile);
+ }
+ }
+ if (product.system_level())
+ uninstall_cmd->AppendSwitch(installer::switches::kSystemLevel);
+
+ // Propagate switches obtained from preferences as well.
+ const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
+ if (prefs.is_multi_install()) {
+ uninstall_cmd->AppendSwitch(installer::switches::kMultiInstall);
+ }
+ bool value = false;
+ if (prefs.GetBool(installer::master_preferences::kVerboseLogging,
+ &value) && value)
+ uninstall_cmd->AppendSwitch(installer::switches::kVerboseLogging);
+}
+
+} // namespace installer
Property changes on: chrome\installer\setup\install_worker.cc
___________________________________________________________________
Added: svn:eol-style
+ LF

Powered by Google App Engine
This is Rietveld 408576698