Index: chrome/installer/setup/install.cc |
=================================================================== |
--- chrome/installer/setup/install.cc (revision 71434) |
+++ chrome/installer/setup/install.cc (working copy) |
@@ -18,6 +18,7 @@ |
#include "base/utf_string_conversions.h" |
#include "base/win/registry.h" |
#include "chrome/installer/setup/setup_constants.h" |
+#include "chrome/installer/setup/install_worker.h" |
#include "chrome/installer/util/browser_distribution.h" |
#include "chrome/installer/util/channel_info.h" |
#include "chrome/installer/util/chrome_frame_distribution.h" |
@@ -92,35 +93,6 @@ |
} |
} |
-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); |
-} |
- |
// 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. |
@@ -395,205 +367,7 @@ |
return ret; |
} |
-// 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); |
- } |
-} |
- |
-// 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(); |
- |
- |
- // 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, |
- REG_SZ); |
- regular_update_work_items->AddDeleteRegValueWorkItem(root, version_key, |
- google_update::kRegRenameCmdField, |
- REG_SZ); |
- } |
- |
- 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; |
-} |
- |
-// 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); |
- BOOL is64 = FALSE; |
- |
- HANDLE handle = GetCurrentProcess(); |
- HMODULE module = GetModuleHandle(L"kernel32.dll"); |
- WOW_FUNC p = reinterpret_cast<WOW_FUNC>(GetProcAddress(module, |
- "IsWow64Process")); |
- if ((p != NULL) && (!(p)(handle, &is64) || (is64 != FALSE))) { |
- return true; |
- } |
- |
- return false; |
-} |
- |
void RegisterChromeOnMachine(const Product& product, |
bool make_chrome_default) { |
DCHECK(product.is_chrome()); |
@@ -620,44 +394,6 @@ |
} |
} |
-// 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, |
- static_cast<DWORD>(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); |
- } |
- } |
-} |
- |
// This function installs a new version of Chrome to the specified location. |
// |
// setup_path: Path to the executable (setup.exe) as it will be copied |
@@ -669,7 +405,7 @@ |
// temp_dir: the path of working directory used during installation. This path |
// does not need to exist. |
// new_version: new Chrome version that needs to be installed |
-// oldest_installed_version: returns the oldest active version (if any) |
+// current_version: returns the current active version (if any) |
// |
// This function makes best effort to do installation in a transactional |
// manner. If failed it tries to rollback all changes on the file system |
@@ -691,119 +427,28 @@ |
const Package& package) { |
DCHECK(current_version); |
- const Products& products = package.products(); |
- DCHECK(products.size()); |
- |
- if (FindProduct(products, BrowserDistribution::CHROME_FRAME)) { |
- // Make sure that we don't end up deleting installed files on next reboot. |
- if (!RemoveFromMovesPendingReboot(package.path().value().c_str())) { |
- LOG(ERROR) << "Error accessing pending moves value."; |
- } |
- } |
- |
current_version->reset(package.GetCurrentVersion()); |
- |
scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList()); |
- // 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 |
+ AddInstallWorkItems(original_state, |
+ installer_state, |
+ multi_install, |
+ setup_path, |
+ archive_path, |
+ src_path, |
+ temp_dir, |
+ new_version, |
+ current_version, |
+ package, |
+ install_list.get()); |
+ |
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.get(), package); |
- |
- HKEY root = package.system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; |
- |
- for (size_t i = 0; i < products.size(); ++i) { |
- const Product* product = products[i]; |
- |
- AddUninstallShortcutWorkItems(setup_path, new_version, install_list.get(), |
- *product); |
- |
- AddVersionKeyWorkItems(root, *product, new_version, install_list.get()); |
- } |
- |
- 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.get()); |
- |
- AddGoogleUpdateWorkItems(original_state, installer_state, package, |
- install_list.get()); |
- |
- // Append the tasks that run after the installation. |
- AppendPostInstallTasks(multi_install, |
- setup_path, |
- new_chrome_exe, |
- current_version->get(), |
- new_version, |
- package, |
- install_list.get()); |
- |
if (!install_list->Do()) { |
installer::InstallStatus result = |
file_util::PathExists(new_chrome_exe) && current_version->get() && |
- new_version.Equals(**current_version) ? |
+ new_version.Equals(*current_version->get()) ? |
installer::SAME_VERSION_REPAIR_FAILED : |
installer::INSTALL_FAILED; |
LOG(ERROR) << "Install failed, rolling back... result: " << result; |
@@ -853,11 +498,24 @@ |
FilePath src_path(install_temp_path); |
src_path = src_path.Append(kInstallSourceDir).Append(kInstallSourceChromeDir); |
+ // TODO(robertshield): Removing the pending on-reboot moves should be done |
+ // elsewhere. |
+ const Products& products = install.products(); |
+ DCHECK(products.size()); |
+ if (FindProduct(products, BrowserDistribution::CHROME_FRAME)) { |
+ // Make sure that we don't end up deleting installed files on next reboot. |
+ if (!RemoveFromMovesPendingReboot(install.path().value().c_str())) { |
+ LOG(ERROR) << "Error accessing pending moves value."; |
+ } |
+ } |
+ |
scoped_ptr<Version> existing_version; |
installer::InstallStatus result = InstallNewVersion(original_state, |
installer_state, prefs.is_multi_install(), setup_path, archive_path, |
src_path, install_temp_path, new_version, &existing_version, install); |
+ // TODO(robertshield): Everything below this line should instead be captured |
+ // by WorkItems. |
if (!InstallUtil::GetInstallReturnCode(result)) { |
if (result == installer::FIRST_INSTALL_SUCCESS && !prefs_path.empty()) |
CopyPreferenceFileForFirstRun(install, prefs_path); |
@@ -910,300 +568,4 @@ |
return result; |
} |
-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 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, |
- L"DisplayIcon", chrome_icon.value(), |
- true); |
- install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, |
- L"NoModify", static_cast<DWORD>(1), |
- true); |
- install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, |
- L"NoRepair", static_cast<DWORD>(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); |
- } |
- } |
-} |
- |
-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; |
- } |
- |
- const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess(); |
- |
- BrowserDistribution* cf = BrowserDistribution::GetSpecificDistribution( |
- BrowserDistribution::CHROME_FRAME, prefs); |
- std::wstring version_key(cf->GetVersionKey()); |
- |
- // 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, |
- static_cast<int64>(install ? 1 : 0), // The value we want to set. |
- install ? false : true); // Overwrite existing value. |
- if (install) { |
- FilePath installer_path(product.package() |
- .GetInstallerDirectory(new_version).Append(setup_path.BaseName())); |
- |
- CommandLine basic_cl(installer_path); |
- basic_cl.AppendSwitch(installer::switches::kChromeFrame); |
- basic_cl.AppendSwitch(installer::switches::kMultiInstall); |
- |
- if (product.package().system_level()) |
- basic_cl.AppendSwitch(installer::switches::kSystemLevel); |
- |
- if (InstallUtil::IsChromeSxSProcess()) |
- basic_cl.AppendSwitch(installer::switches::kChromeSxS); |
- |
- CommandLine temp_opt_out(basic_cl); |
- temp_opt_out.AppendSwitch( |
- installer::switches::kChromeFrameReadyModeTempOptOut); |
- |
- CommandLine end_temp_opt_out(basic_cl); |
- end_temp_opt_out.AppendSwitch( |
- installer::switches::kChromeFrameReadyModeEndTempOptOut); |
- |
- CommandLine opt_out(installer_path); |
- AppendUninstallCommandLineFlags(&opt_out, product); |
- // Force Uninstall silences the prompt to reboot to complete uninstall. |
- opt_out.AppendSwitch(installer::switches::kForceUninstall); |
- |
- CommandLine opt_in(basic_cl); |
- opt_in.AppendSwitch( |
- installer::switches::kChromeFrameReadyModeOptIn); |
- |
- list->AddSetRegValueWorkItem(root, version_key, |
- google_update::kRegCFTempOptOutCmdField, |
- temp_opt_out.command_line_string(), true); |
- list->AddSetRegValueWorkItem(root, version_key, |
- google_update::kRegCFEndTempOptOutCmdField, |
- end_temp_opt_out.command_line_string(), |
- true); |
- list->AddSetRegValueWorkItem(root, version_key, |
- google_update::kRegCFOptOutCmdField, |
- opt_out.command_line_string(), true); |
- list->AddSetRegValueWorkItem(root, version_key, |
- google_update::kRegCFOptInCmdField, |
- opt_in.command_line_string(), true); |
- } else { |
- // 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, REG_QWORD); |
- } |
- |
- 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 (!ready_mode || !install) { |
- list->AddDeleteRegValueWorkItem(root, version_key, |
- google_update::kRegCFTempOptOutCmdField, |
- REG_SZ); |
- list->AddDeleteRegValueWorkItem(root, version_key, |
- google_update::kRegCFEndTempOptOutCmdField, |
- REG_SZ); |
- list->AddDeleteRegValueWorkItem(root, version_key, |
- google_update::kRegCFOptOutCmdField, |
- REG_SZ); |
- list->AddDeleteRegValueWorkItem(root, version_key, |
- google_update::kRegCFOptInCmdField, REG_SZ); |
- } |
- |
- 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. |
- 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()); |
- } |
-} |
- |
} // namespace installer |