diff options
-rw-r--r-- | chrome/installer/setup/install.cc | 97 | ||||
-rw-r--r-- | chrome/installer/setup/setup_main.cc | 2 | ||||
-rw-r--r-- | chrome/installer/setup/uninstall.cc | 8 | ||||
-rw-r--r-- | chrome/installer/util/google_update_constants.cc | 1 | ||||
-rw-r--r-- | chrome/installer/util/google_update_constants.h | 1 | ||||
-rw-r--r-- | chrome/installer/util/install_util.cc | 82 | ||||
-rw-r--r-- | chrome/installer/util/install_util.h | 19 | ||||
-rw-r--r-- | chrome/installer/util/master_preferences.cc | 4 | ||||
-rw-r--r-- | chrome/installer/util/master_preferences_constants.cc | 1 | ||||
-rw-r--r-- | chrome/installer/util/master_preferences_constants.h | 2 |
10 files changed, 160 insertions, 57 deletions
diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc index 71ad8ae..cdeb22b 100644 --- a/chrome/installer/setup/install.cc +++ b/chrome/installer/setup/install.cc @@ -99,7 +99,7 @@ void AppendUninstallCommandLineFlags(std::wstring* uninstall_cmd_line, uninstall_cmd_line->append(installer_util::switches::kChromeSxS); } - if (InstallUtil::IsMSIProcess()) { + if (InstallUtil::IsMSIProcess(is_system)) { uninstall_cmd_line->append(L" --"); uninstall_cmd_line->append(installer_util::switches::kMsi); } @@ -126,25 +126,23 @@ void AddUninstallShortcutWorkItems(HKEY reg_root, const std::wstring& product_name, const std::wstring& new_version, WorkItemList* install_list) { - std::wstring uninstall_cmd(L"\""); - uninstall_cmd.append(installer::GetInstallerPathUnderChrome(install_path, - new_version)); - file_util::AppendToPath(&uninstall_cmd, - file_util::GetFilenameFromPath(exe_path)); - uninstall_cmd.append(L"\""); - BrowserDistribution* dist = BrowserDistribution::GetDistribution(); const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - // 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. + std::wstring uninstall_cmd( + installer::GetInstallerPathUnderChrome(install_path, new_version)); + file_util::AppendToPath(&uninstall_cmd, + file_util::GetFilenameFromPath(exe_path)); std::wstring uninstall_arguments; AppendUninstallCommandLineFlags(&uninstall_arguments, reg_root == HKEY_LOCAL_MACHINE); + std::wstring update_state_key = dist->GetStateKey(); install_list->AddCreateRegKeyWorkItem(reg_root, update_state_key); install_list->AddSetRegValueWorkItem(reg_root, update_state_key, @@ -153,8 +151,13 @@ void AddUninstallShortcutWorkItems(HKEY reg_root, installer_util::kUninstallArgumentsField, uninstall_arguments, true); // MSI installations will manage their own uninstall shortcuts. - if (!InstallUtil::IsMSIProcess()) { - AppendUninstallCommandLineFlags(&uninstall_cmd, + if (!InstallUtil::IsMSIProcess(reg_root == HKEY_LOCAL_MACHINE)) { + // We need to quote the command line for the Add/Remove Programs dialog. + std::wstring quoted_uninstall_cmd(L"\""); + quoted_uninstall_cmd += uninstall_cmd; + quoted_uninstall_cmd += L"\""; + + AppendUninstallCommandLineFlags("ed_uninstall_cmd, reg_root == HKEY_LOCAL_MACHINE); std::wstring uninstall_reg = dist->GetUninstallRegPath(); install_list->AddCreateRegKeyWorkItem(reg_root, uninstall_reg); @@ -163,7 +166,8 @@ void AddUninstallShortcutWorkItems(HKEY reg_root, install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, installer_util::kUninstallStringField, - uninstall_cmd, true); + quoted_uninstall_cmd, + true); install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg, L"InstallLocation", @@ -282,31 +286,37 @@ bool CreateOrUpdateChromeShortcuts(const std::wstring& exe_path, product_desc, false); } - // Create/update uninstall link - FilePath uninstall_link(shortcut_path); // Uninstall Chrome link - uninstall_link = uninstall_link.Append( - dist->GetUninstallLinkName() + L".lnk"); - if ((install_status == installer_util::FIRST_INSTALL_SUCCESS) || - (install_status == installer_util::INSTALL_REPAIRED) || - (file_util::PathExists(uninstall_link))) { - if (!file_util::PathExists(shortcut_path)) - file_util::CreateDirectoryW(shortcut_path); - std::wstring setup_exe(installer::GetInstallerPathUnderChrome(install_path, - new_version)); - file_util::AppendToPath(&setup_exe, - file_util::GetFilenameFromPath(exe_path)); - - std::wstring arguments; - AppendUninstallCommandLineFlags(&arguments, system_install); - - LOG(INFO) << "Creating/updating uninstall link at " - << uninstall_link.value(); - ret = ret && file_util::CreateShortcutLink(setup_exe.c_str(), - uninstall_link.value().c_str(), - NULL, - arguments.c_str(), - NULL, setup_exe.c_str(), 0, - NULL); + // Create/update uninstall link if we are not an MSI install. MSI + // installations are, for the time being, managed only through the + // Add/Remove Programs dialog. + // TODO(robertshield): We could add a shortcut to msiexec /X {GUID} here. + if (!InstallUtil::IsMSIProcess(system_install)) { + FilePath uninstall_link(shortcut_path); // Uninstall Chrome link + uninstall_link = uninstall_link.Append( + dist->GetUninstallLinkName() + L".lnk"); + if ((install_status == installer_util::FIRST_INSTALL_SUCCESS) || + (install_status == installer_util::INSTALL_REPAIRED) || + (file_util::PathExists(uninstall_link))) { + if (!file_util::PathExists(shortcut_path)) + file_util::CreateDirectoryW(shortcut_path); + std::wstring setup_exe(installer::GetInstallerPathUnderChrome( + install_path, new_version)); + file_util::AppendToPath(&setup_exe, + file_util::GetFilenameFromPath(exe_path)); + + std::wstring arguments; + AppendUninstallCommandLineFlags(&arguments, system_install); + LOG(INFO) << "Creating/updating uninstall link at " + << uninstall_link.value(); + ret = ret && file_util::CreateShortcutLink(setup_exe.c_str(), + uninstall_link.value().c_str(), + NULL, + arguments.c_str(), + NULL, + setup_exe.c_str(), + 0, + NULL); + } } // Update Desktop and Quick Launch shortcuts. If --create-new-shortcuts @@ -334,6 +344,8 @@ bool CreateOrUpdateChromeShortcuts(const std::wstring& exe_path, // - Handle the case of in-use-update by updating "opv" 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 DoPostInstallTasks(HKEY reg_root, @@ -345,6 +357,8 @@ bool DoPostInstallTasks(HKEY reg_root, BrowserDistribution* dist = BrowserDistribution::GetDistribution(); std::wstring version_key = dist->GetVersionKey(); + bool is_system_install = (reg_root == HKEY_LOCAL_MACHINE); + if (file_util::PathExists(FilePath::FromWStringHack(new_chrome_exe))) { // Looks like this was in use update. So make sure we update the 'opv' key // with the current version that is active and 'cmd' key with the rename @@ -366,7 +380,7 @@ bool DoPostInstallTasks(HKEY reg_root, file_util::GetFilenameFromPath(exe_path)); rename_cmd = L"\"" + rename_cmd + L"\" --" + installer_util::switches::kRenameChromeExe; - if (reg_root == HKEY_LOCAL_MACHINE) + if (is_system_install) rename_cmd = rename_cmd + L" --" + installer_util::switches::kSystemLevel; if (InstallUtil::IsChromeFrameProcess()) { @@ -441,6 +455,13 @@ bool DoPostInstallTasks(HKEY reg_root, } } + // 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 (InstallUtil::IsMSIProcess(is_system_install)) { + if (!InstallUtil::SetMSIMarker(is_system_install, true)) + return false; + } + return true; } diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc index 6b039ed..53d0918 100644 --- a/chrome/installer/setup/setup_main.cc +++ b/chrome/installer/setup/setup_main.cc @@ -722,7 +722,7 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, // MSI demands that custom actions always return 0 (ERROR_SUCCESS) or it will // rollback the action. If we're uninstalling we want to avoid this, so always // report success, squashing any more informative return codes. - if (!(InstallUtil::IsMSIProcess() && + if (!(InstallUtil::IsMSIProcess(system_install) && parsed_command_line.HasSwitch(installer_util::switches::kUninstall))) { // Note that we allow the status installer_util::UNINSTALL_REQUIRES_REBOOT // to pass through, since this is only returned on uninstall which is never diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc index 3ce98d6..79ccdbe 100644 --- a/chrome/installer/setup/uninstall.cc +++ b/chrome/installer/setup/uninstall.cc @@ -339,14 +339,16 @@ installer_util::InstallStatus IsChromeActiveOrUserCancelled( } bool ShouldDeleteProfile(const CommandLine& cmd_line, - installer_util::InstallStatus status) { + installer_util::InstallStatus status, + bool system_uninstall) { bool should_delete = false; // Chrome Frame uninstallations always want to delete the profile (we have no // UI to prompt otherwise and the profile stores no useful data anyway) // unless they are managed by MSI. MSI uninstalls will explicitly include // the --delete-profile flag to distinguish them from MSI upgrades. - if (InstallUtil::IsChromeFrameProcess() && !InstallUtil::IsMSIProcess()) { + if (InstallUtil::IsChromeFrameProcess() && + !InstallUtil::IsMSIProcess(system_uninstall)) { should_delete = true; } else { should_delete = @@ -569,7 +571,7 @@ installer_util::InstallStatus installer_setup::UninstallChrome( // Finally delete all the files from Chrome folder after moving setup.exe // and the user's Local State to a temp location. - bool delete_profile = ShouldDeleteProfile(cmd_line, status); + bool delete_profile = ShouldDeleteProfile(cmd_line, status, system_uninstall); std::wstring local_state_path; ret = installer_util::UNINSTALL_SUCCESSFUL; diff --git a/chrome/installer/util/google_update_constants.cc b/chrome/installer/util/google_update_constants.cc index 496c530..a904a74 100644 --- a/chrome/installer/util/google_update_constants.cc +++ b/chrome/installer/util/google_update_constants.cc @@ -21,6 +21,7 @@ const wchar_t kRegDidRunField[] = L"dr"; const wchar_t kRegLangField[] = L"lang"; const wchar_t kRegLastCheckedField[] = L"LastChecked"; const wchar_t kRegMetricsId[] = L"metricsid"; +const wchar_t kRegMSIField[] = L"msi"; const wchar_t kRegNameField[] = L"name"; const wchar_t kRegOldVersionField[] = L"opv"; const wchar_t kRegRenameCmdField[] = L"cmd"; diff --git a/chrome/installer/util/google_update_constants.h b/chrome/installer/util/google_update_constants.h index 4479d66..79100a6 100644 --- a/chrome/installer/util/google_update_constants.h +++ b/chrome/installer/util/google_update_constants.h @@ -31,6 +31,7 @@ extern const wchar_t kRegDidRunField[]; extern const wchar_t kRegLangField[]; extern const wchar_t kRegLastCheckedField[]; extern const wchar_t kRegMetricsId[]; +extern const wchar_t kRegMSIField[]; extern const wchar_t kRegNameField[]; extern const wchar_t kRegOldVersionField[]; extern const wchar_t kRegRenameCmdField[]; diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc index a3f32d1..6d87869 100644 --- a/chrome/installer/util/install_util.cc +++ b/chrome/installer/util/install_util.cc @@ -136,14 +136,20 @@ bool InstallUtil::IsChromeFrameProcess() { DCHECK(command_line) << "IsChromeFrameProcess() called before ComamandLine::Init()"; - // Also assume this to be a ChromeFrame process if we are running inside - // the Chrome Frame DLL. FilePath module_path; PathService::Get(base::FILE_MODULE, &module_path); std::wstring module_name(module_path.BaseName().value()); - return command_line->HasSwitch(installer_util::switches::kChromeFrame) || - module_name == installer_util::kChromeFrameDll; + scoped_ptr<DictionaryValue> prefs(installer_util::GetInstallPreferences( + *command_line)); + DCHECK(prefs.get()); + bool is_cf = false; + installer_util::GetDistroBooleanPreference(prefs.get(), + installer_util::master_preferences::kChromeFrame, &is_cf); + + // Also assume this to be a ChromeFrame process if we are running inside + // the Chrome Frame DLL. + return is_cf || module_name == installer_util::kChromeFrameDll; } bool InstallUtil::IsChromeSxSProcess() { @@ -164,18 +170,72 @@ bool InstallUtil::IsChromeSxSProcess() { chrome_sxs_dir); } -bool InstallUtil::IsMSIProcess() { +bool InstallUtil::IsMSIProcess(bool system_level) { + // Initialize the static msi flags. + static bool is_msi_ = false; + static bool msi_checked_ = false; + CommandLine* command_line = CommandLine::ForCurrentProcess(); CHECK(command_line); - scoped_ptr<DictionaryValue> prefs(installer_util::GetInstallPreferences( - *command_line)); - bool value = false; - return (installer_util::GetDistroBooleanPreference(prefs.get(), - installer_util::master_preferences::kMsi, &value) && - value); + if (!msi_checked_) { + msi_checked_ = true; + + scoped_ptr<DictionaryValue> prefs(installer_util::GetInstallPreferences( + *command_line)); + DCHECK(prefs.get()); + bool is_msi = false; + installer_util::GetDistroBooleanPreference(prefs.get(), + installer_util::master_preferences::kMsi, &is_msi); + + if (!is_msi) { + // We didn't find it in the preferences, try looking in the registry. + HKEY reg_root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + RegKey key; + DWORD msi_value; + + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); + DCHECK(dist); + + bool success = false; + std::wstring reg_key(dist->GetStateKey()); + if (key.Open(reg_root, reg_key.c_str(), KEY_READ | KEY_WRITE)) { + if (key.ReadValueDW(google_update::kRegMSIField, &msi_value)) { + is_msi = (msi_value == 1); + } + } + } + + is_msi_ = is_msi; + } + + return is_msi_; +} + +bool InstallUtil::SetMSIMarker(bool system_level, bool set) { + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); + DCHECK(dist); + std::wstring client_state_path(dist->GetStateKey()); + + bool success = false; + HKEY reg_root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + RegKey client_state_key; + if (client_state_key.Open(reg_root, client_state_path.c_str(), + KEY_READ | KEY_WRITE)) { + DWORD msi_value = set ? 1 : 0; + if (client_state_key.WriteValue(google_update::kRegMSIField, msi_value)) { + success = true; + } else { + LOG(ERROR) << "Could not write msi value to client state key."; + } + } else { + LOG(ERROR) << "Could not open client state key!"; + } + + return success; } + bool InstallUtil::BuildDLLRegistrationList(const std::wstring& install_path, const wchar_t** const dll_names, int dll_names_count, diff --git a/chrome/installer/util/install_util.h b/chrome/installer/util/install_util.h index 8a2854a..f2ccb42 100644 --- a/chrome/installer/util/install_util.h +++ b/chrome/installer/util/install_util.h @@ -57,7 +57,8 @@ class InstallUtil { // Returns true if this is a Chrome Frame installation (as indicated by the // presence of --chrome-frame on the command line) or if this is running - // inside of the Chrome Frame dll. + // inside of the Chrome Frame dll. Also returns true if a master.preferences + // file containing chrome_frame: true is specified on the command line. static bool IsChromeFrameProcess(); // Returns true if this is running setup process for Chrome SxS (as @@ -67,9 +68,19 @@ class InstallUtil { static bool IsChromeSxSProcess(); // Returns true if this setup process is running as an install managed by an - // MSI wrapper. This is indicated by the presence of --msi on the command line - // or the presence of "msi": true in the master preferences file. - static bool IsMSIProcess(); + // MSI wrapper. There are three things that are checked: + // 1) the presence of --msi on the command line + // 2) the presence of "msi": true in the master preferences file + // 3) the presence of a DWORD value in the ClientState key called msi with + // value 1 + // NOTE: This method is NOT thread safe. + static bool IsMSIProcess(bool system_level); + + + // Sets the boolean MSI marker for this installation if set is true or clears + // it otherwise. The MSI marker is stored in the registry under the + // ClientState key. + static bool SetMSIMarker(bool system_level, bool set); // Adds all DLLs in install_path whose names are given by dll_names to a // work item list containing registration or unregistration actions. diff --git a/chrome/installer/util/master_preferences.cc b/chrome/installer/util/master_preferences.cc index e78872e..053dc45 100644 --- a/chrome/installer/util/master_preferences.cc +++ b/chrome/installer/util/master_preferences.cc @@ -114,6 +114,10 @@ DictionaryValue* GetInstallPreferences(const CommandLine& cmd_line) { if (!prefs) prefs = new DictionaryValue(); + if (cmd_line.HasSwitch(installer_util::switches::kChromeFrame)) + installer_util::SetDistroBooleanPreference( + prefs, installer_util::master_preferences::kChromeFrame, true); + if (cmd_line.HasSwitch(installer_util::switches::kCreateAllShortcuts)) installer_util::SetDistroBooleanPreference( prefs, installer_util::master_preferences::kCreateAllShortcuts, true); diff --git a/chrome/installer/util/master_preferences_constants.cc b/chrome/installer/util/master_preferences_constants.cc index 77c60d9..aa7c900 100644 --- a/chrome/installer/util/master_preferences_constants.cc +++ b/chrome/installer/util/master_preferences_constants.cc @@ -8,6 +8,7 @@ namespace installer_util { namespace master_preferences { const wchar_t kAltFirstRunBubble[] = L"oem_bubble"; const wchar_t kAltShortcutText[] = L"alternate_shortcut_text"; + const wchar_t kChromeFrame[] = L"chrome_frame"; const wchar_t kChromeShortcutIconIndex[] = L"chrome_shortcut_icon_index"; const wchar_t kCreateAllShortcuts[] = L"create_all_shortcuts"; const wchar_t kDistroImportBookmarksPref[] = L"import_bookmarks"; diff --git a/chrome/installer/util/master_preferences_constants.h b/chrome/installer/util/master_preferences_constants.h index e08d1e4..6c5843a 100644 --- a/chrome/installer/util/master_preferences_constants.h +++ b/chrome/installer/util/master_preferences_constants.h @@ -19,6 +19,8 @@ namespace master_preferences { extern const wchar_t kAltShortcutText[]; // Boolean. Use alternate smaller first run info bubble. extern const wchar_t kAltFirstRunBubble[]; +// Boolean. This is to be a Chrome Frame install. +extern const wchar_t kChromeFrame[]; // Integer. Icon index from chrome.exe to use for shortcuts. extern const wchar_t kChromeShortcutIconIndex[]; // Boolean. Create Desktop and QuickLaunch shortcuts. Cmd line override present. |