| // 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. |
| |
| #include "chrome/test/mini_installer_test/chrome_mini_installer.h" |
| |
| #include <algorithm> |
| |
| #include "base/command_line.h" |
| #include "base/file_util.h" |
| #include "base/path_service.h" |
| #include "base/process.h" |
| #include "base/process_util.h" |
| #include "base/string_number_conversions.h" |
| #include "base/string_util.h" |
| #include "base/stringprintf.h" |
| #include "base/threading/platform_thread.h" |
| #include "base/win/registry.h" |
| #include "chrome/installer/util/google_update_constants.h" |
| #include "chrome/installer/util/helper.h" |
| #include "chrome/installer/util/install_util.h" |
| #include "chrome/installer/util/installation_validation_helper.h" |
| #include "chrome/installer/util/util_constants.h" |
| #include "chrome/test/base/chrome_process_util.h" |
| #include "chrome/test/mini_installer_test/mini_installer_test_constants.h" |
| #include "chrome/test/mini_installer_test/mini_installer_test_util.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using base::win::RegKey; |
| using installer::InstallationValidator; |
| |
| namespace { |
| |
| struct FilePathInfo { |
| file_util::FileEnumerator::FindInfo info; |
| FilePath path; |
| }; |
| |
| bool CompareDate(const FilePathInfo& a, |
| const FilePathInfo& b) { |
| #if defined(OS_POSIX) |
| return a.info.stat.st_mtime > b.info.stat.st_mtime; |
| #elif defined(OS_WIN) |
| if (a.info.ftLastWriteTime.dwHighDateTime == |
| b.info.ftLastWriteTime.dwHighDateTime) { |
| return a.info.ftLastWriteTime.dwLowDateTime > |
| b.info.ftLastWriteTime.dwLowDateTime; |
| } else { |
| return a.info.ftLastWriteTime.dwHighDateTime > |
| b.info.ftLastWriteTime.dwHighDateTime; |
| } |
| #endif |
| } |
| |
| // Get list of file |type| matching |pattern| in |root|. |
| // The list is sorted in last modified date order. |
| // Return true if files/directories are found. |
| bool FindMatchingFiles(const FilePath& root, |
| const std::string& pattern, |
| file_util::FileEnumerator::FileType type, |
| std::vector<FilePath>* paths) { |
| file_util::FileEnumerator files(root, false, type, |
| FilePath().AppendASCII(pattern).value()); |
| std::vector<FilePathInfo> matches; |
| for (FilePath current = files.Next(); !current.empty(); |
| current = files.Next()) { |
| FilePathInfo entry; |
| files.GetFindInfo(&entry.info); |
| entry.path = current; |
| matches.push_back(entry); |
| } |
| |
| if (matches.empty()) |
| return false; |
| |
| std::sort(matches.begin(), matches.end(), CompareDate); |
| std::vector<FilePathInfo>::iterator current; |
| for (current = matches.begin(); current != matches.end(); ++current) { |
| paths->push_back(current->path); |
| } |
| return true; |
| } |
| |
| bool FindNewestMatchingFile(const FilePath& root, |
| const std::string& pattern, |
| file_util::FileEnumerator::FileType type, |
| FilePath* path) { |
| std::vector<FilePath> paths; |
| if (FindMatchingFiles(root, pattern, type, &paths)) { |
| *path = paths[0]; |
| return true; |
| } |
| return false; |
| } |
| } // namespace |
| |
| ChromeMiniInstaller::ChromeMiniInstaller(bool system_install, |
| bool is_chrome_frame) |
| : is_chrome_frame_(is_chrome_frame), |
| system_install_(system_install) {} |
| |
| void ChromeMiniInstaller::SetBuildUnderTest(const std::string& build) { |
| build_ = build; |
| FilePath full_installer; |
| FilePath previous_installer; |
| if (!GetFullInstaller(&full_installer) || |
| !GetPreviousInstaller(&previous_installer)) |
| return; |
| |
| current_build_ = |
| full_installer.DirName().DirName().BaseName().MaybeAsASCII(); |
| previous_build_ = |
| previous_installer.DirName().DirName().BaseName().MaybeAsASCII(); |
| } |
| |
| // Installs Chrome. |
| void ChromeMiniInstaller::Install() { |
| FilePath mini_installer; |
| ASSERT_TRUE(GetMiniInstaller(&mini_installer)); |
| InstallMiniInstaller(false, mini_installer); |
| } |
| |
| // This method will get the previous latest full installer from |
| // nightly location, install it and over install with specified install_type. |
| void ChromeMiniInstaller::OverInstallOnFullInstaller( |
| const std::wstring& install_type, bool should_start_ie) { |
| FilePath full_installer; |
| FilePath diff_installer; |
| FilePath previous_installer; |
| ASSERT_TRUE(GetFullInstaller(&full_installer) && |
| GetDiffInstaller(&diff_installer) && |
| GetPreviousInstaller(&previous_installer)); |
| |
| if (should_start_ie) |
| LaunchIE(L"http://www.google.com"); |
| |
| InstallMiniInstaller(false, previous_installer); |
| |
| std::string got_prev_version; |
| ASSERT_TRUE(GetChromeVersionFromRegistry(&got_prev_version)); |
| |
| if (install_type == mini_installer_constants::kDiffInstall) { |
| LOG(INFO) << "Over installing with latest differential installer: " |
| << diff_installer.value(); |
| InstallMiniInstaller(true, diff_installer); |
| |
| } else if (install_type == mini_installer_constants::kFullInstall) { |
| LOG(INFO) << "Over installing with latest full installer: " |
| << full_installer.value(); |
| InstallMiniInstaller(true, full_installer); |
| } |
| |
| std::string got_curr_version; |
| ASSERT_TRUE(GetChromeVersionFromRegistry(&got_curr_version)); |
| |
| if (got_prev_version == previous_build_ && |
| got_curr_version == current_build_) { |
| LOG(INFO) << "The over install was successful.\n" |
| << "Full installer: " << previous_build_; |
| LOG(INFO) << "Diff installer: " << current_build_; |
| } else { |
| LOG(INFO) << "The over install was not successful.\n" |
| << "Expected full installer value: " << previous_build_; |
| LOG(INFO) << "Actual value is: " << got_prev_version; |
| LOG(INFO) << "Expected diff: " << current_build_ |
| << "Actual value is: " << got_curr_version; |
| FAIL(); |
| } |
| } |
| |
| // This method will get the latest full installer from nightly location |
| // and installs it. |
| void ChromeMiniInstaller::InstallFullInstaller(bool over_install) { |
| FilePath full_installer; |
| ASSERT_TRUE(GetFullInstaller(&full_installer)); |
| InstallMiniInstaller(over_install, full_installer); |
| } |
| |
| // Installs the Chrome mini-installer, checks the registry and shortcuts. |
| void ChromeMiniInstaller::InstallMiniInstaller(bool over_install, |
| const FilePath& path) { |
| LOG(INFO) << "Install level is: " |
| << (system_install_ ? "system" : "user"); |
| RunInstaller(CommandLine(path)); |
| |
| std::string version; |
| ASSERT_TRUE(GetChromeVersionFromRegistry(&version)) |
| << "Install failed: unable to get version."; |
| VerifyInstall(over_install); |
| } |
| |
| void ChromeMiniInstaller::InstallUsingMultiInstall() { |
| FilePath mini_installer; |
| ASSERT_TRUE(GetMiniInstaller(&mini_installer)); |
| CommandLine cmd(mini_installer); |
| cmd.AppendSwitch(installer::switches::kMultiInstall); |
| cmd.AppendSwitch(installer::switches::kChrome); |
| RunInstaller(cmd); |
| |
| // Verify installation. |
| InstallationValidator::InstallationType type = |
| installer::ExpectValidInstallation(system_install_); |
| BrowserDistribution* dist = GetCurrentBrowserDistribution(); |
| ASSERT_TRUE(InstallUtil::IsMultiInstall(dist, system_install_)); |
| if (is_chrome_frame_) { |
| EXPECT_TRUE(type & InstallationValidator::ProductBits::CHROME_FRAME_MULTI); |
| VerifyChromeFrameInstall(); |
| } else { |
| EXPECT_TRUE(type & InstallationValidator::ProductBits::CHROME_MULTI); |
| } |
| FindChromeShortcut(); |
| LaunchChrome(false); |
| } |
| |
| // This method tests the standalone installer by verifying the steps listed at: |
| // https://sites.google.com/a/google.com/chrome-pmo/ |
| // standalone-installers/testing-standalone-installers |
| // This method applies appropriate tags to standalone installer and deletes |
| // old installer before running the new tagged installer. It also verifies |
| // that the installed version is correct. |
| void ChromeMiniInstaller::InstallStandaloneInstaller() { |
| file_util::Delete(mini_installer_constants::kStandaloneInstaller, true); |
| CommandLine tag_installer_command = |
| ChromeMiniInstaller::GetCommandForTagging(); |
| ASSERT_FALSE(tag_installer_command.GetCommandLineString().empty()); |
| base::LaunchOptions options; |
| options.wait = true; |
| base::LaunchProcess(tag_installer_command, options, NULL); |
| FilePath installer_path = MiniInstallerTestUtil::GetFilePath( |
| mini_installer_constants::kStandaloneInstaller); |
| InstallMiniInstaller(false, installer_path); |
| ASSERT_TRUE(VerifyStandaloneInstall()); |
| file_util::Delete(mini_installer_constants::kStandaloneInstaller, true); |
| } |
| |
| CommandLine ChromeMiniInstaller::GetCommandForTagging() { |
| FilePath tagged_installer = MiniInstallerTestUtil::GetFilePath( |
| mini_installer_constants::kStandaloneInstaller); |
| FilePath standalone_installer; |
| if (!GetStandaloneInstaller(&standalone_installer)) |
| return CommandLine::FromString(L""); |
| CommandLine command = CommandLine::FromString( |
| base::StringPrintf(L"%ls %ls %ls %ls", |
| mini_installer_constants::kChromeApplyTagExe, |
| standalone_installer.value().c_str(), |
| tagged_installer.value().c_str(), |
| mini_installer_constants::kChromeApplyTagParameters)); |
| LOG(INFO) << "Tagging command: " << command.GetCommandLineString(); |
| return command; |
| } |
| |
| // Installs chromesetup.exe, waits for the install to finish and then |
| // checks the registry and shortcuts. |
| void ChromeMiniInstaller::InstallMetaInstaller() { |
| // Install Google Chrome through meta installer. |
| CommandLine installer(FilePath::FromWStringHack( |
| mini_installer_constants::kChromeMetaInstallerExe)); |
| RunInstaller(installer); |
| ASSERT_TRUE(MiniInstallerTestUtil::VerifyProcessClose( |
| mini_installer_constants::kChromeMetaInstallerExecutable)); |
| |
| std::wstring chrome_google_update_state_key( |
| google_update::kRegPathClients); |
| chrome_google_update_state_key.append(L"\\"); |
| |
| BrowserDistribution* dist = GetCurrentBrowserDistribution(); |
| chrome_google_update_state_key.append(dist->GetAppGuid()); |
| |
| ASSERT_TRUE(CheckRegistryKey(chrome_google_update_state_key)); |
| ASSERT_TRUE(CheckRegistryKey(dist->GetVersionKey())); |
| FindChromeShortcut(); |
| LaunchChrome(true); |
| } |
| |
| // If the build type is Google Chrome, then it first installs meta installer |
| // and then over installs with mini_installer. It also verifies if Chrome can |
| // be launched successfully after overinstall. |
| void ChromeMiniInstaller::OverInstall() { |
| InstallMetaInstaller(); |
| std::string reg_key_value_returned; |
| // gets the registry key value before overinstall. |
| ASSERT_TRUE(GetChromeVersionFromRegistry(®_key_value_returned)); |
| printf("\n\nPreparing to overinstall...\n"); |
| InstallFullInstaller(true); |
| std::string reg_key_value_after_overinstall; |
| // Get the registry key value after over install |
| ASSERT_TRUE(GetChromeVersionFromRegistry(®_key_value_after_overinstall)); |
| ASSERT_TRUE(VerifyOverInstall(reg_key_value_returned, |
| reg_key_value_after_overinstall)); |
| } |
| |
| // This method will first install Chrome. Deletes either registry or |
| // folder based on the passed argument, then tries to launch Chrome. |
| // Then installs Chrome again to repair. |
| void ChromeMiniInstaller::Repair( |
| ChromeMiniInstaller::RepairChrome repair_type) { |
| InstallFullInstaller(false); |
| if (is_chrome_frame_) { |
| MiniInstallerTestUtil::CloseProcesses( |
| mini_installer_constants::kIEProcessName); |
| } else { |
| MiniInstallerTestUtil::CloseProcesses(installer::kNaClExe); |
| } |
| MiniInstallerTestUtil::CloseProcesses(installer::kChromeExe); |
| if (repair_type == ChromeMiniInstaller::VERSION_FOLDER) { |
| std::string build_number; |
| ASSERT_TRUE(GetChromeVersionFromRegistry(&build_number)); |
| FilePath install_path; |
| ASSERT_TRUE(GetChromeInstallDirectoryLocation(&install_path)); |
| install_path = install_path.AppendASCII(build_number); |
| ASSERT_TRUE(file_util::Delete(install_path, true)); |
| } else if (repair_type == ChromeMiniInstaller::REGISTRY) { |
| DeletePvRegistryKey(); |
| printf("Deleted registry. Now trying to launch chrome\n"); |
| } |
| FilePath current_path; |
| ASSERT_TRUE(MiniInstallerTestUtil::ChangeCurrentDirectory(¤t_path)); |
| LaunchChrome(false); |
| LOG(INFO) << "Installing Chrome again to see if it can be repaired."; |
| InstallFullInstaller(true); |
| LOG(INFO) << "Chrome repair successful."; |
| // Set the current directory back to original path. |
| file_util::SetCurrentDirectory(current_path); |
| } |
| |
| // This method first checks if Chrome is running. |
| // If yes, will close all the processes. |
| // Then will find and spawn uninstall path. |
| // Handles uninstall confirm dialog. |
| // Waits until setup.exe ends. |
| // Checks if registry key exist even after uninstall. |
| // Deletes App dir. |
| // Closes feedback form. |
| void ChromeMiniInstaller::UnInstall() { |
| BrowserDistribution* dist = GetCurrentBrowserDistribution(); |
| std::string version; |
| std::string result; |
| |
| if (!GetChromeVersionFromRegistry(&version)) |
| return; |
| |
| // Close running products. |
| if (is_chrome_frame_) { |
| MiniInstallerTestUtil::CloseProcesses( |
| mini_installer_constants::kIEProcessName); |
| } else { |
| MiniInstallerTestUtil::CloseProcesses(installer::kNaClExe); |
| } |
| MiniInstallerTestUtil::CloseProcesses(installer::kChromeExe); |
| // Get uninstall command. |
| CommandLine cmd = InstallUtil::GetChromeUninstallCmd( |
| system_install_, dist->GetType()); |
| |
| LOG(INFO) << "Uninstall command: " << cmd.GetCommandLineString(); |
| ASSERT_TRUE(file_util::PathExists(cmd.GetProgram())) |
| << "Uninstall executable does not exist."; |
| |
| cmd.AppendSwitch(installer::switches::kUninstall); |
| cmd.AppendSwitch(installer::switches::kForceUninstall); |
| if (is_chrome_frame_) |
| cmd.AppendSwitch(installer::switches::kChromeFrame); |
| if (system_install_) |
| cmd.AppendSwitch(installer::switches::kSystemLevel); |
| |
| base::ProcessHandle setup_handle; |
| ASSERT_TRUE(base::LaunchProcess(cmd, base::LaunchOptions(), &setup_handle)) |
| << "Failed to launch uninstall command."; |
| |
| if (is_chrome_frame_) |
| ASSERT_TRUE(CloseUninstallWindow()); |
| ASSERT_TRUE(MiniInstallerTestUtil::VerifyProcessHandleClosed(setup_handle)); |
| ASSERT_FALSE(CheckRegistryKeyOnUninstall(dist->GetVersionKey())) |
| << "It appears Chrome was not completely uninstalled."; |
| |
| DeleteUserDataFolder(); |
| // Close IE survey window that gets launched on uninstall. |
| if (!is_chrome_frame_) { |
| FindChromeShortcut(); |
| MiniInstallerTestUtil::CloseProcesses( |
| mini_installer_constants::kIEExecutable); |
| ASSERT_EQ(0, |
| base::GetProcessCount(mini_installer_constants::kIEExecutable, NULL)); |
| } |
| } |
| |
| void ChromeMiniInstaller::UnInstallChromeFrameWithIERunning() { |
| BrowserDistribution* dist = GetCurrentBrowserDistribution(); |
| std::wstring product_name = |
| mini_installer_constants::kChromeFrameProductName; |
| if (!CheckRegistryKey(dist->GetVersionKey())) { |
| printf("%ls is not installed.\n", product_name.c_str()); |
| return; |
| } |
| |
| MiniInstallerTestUtil::CloseProcesses(installer::kChromeExe); |
| |
| CommandLine cmd = InstallUtil::GetChromeUninstallCmd( |
| system_install_, dist->GetType()); |
| |
| if (cmd.GetProgram().empty()) { |
| LOG(ERROR) << "Unable to get uninstall command."; |
| CleanChromeInstall(); |
| } |
| |
| ASSERT_TRUE(file_util::PathExists(cmd.GetProgram())); |
| |
| cmd.AppendSwitch(installer::switches::kUninstall); |
| cmd.AppendSwitch(installer::switches::kForceUninstall); |
| cmd.AppendSwitch(installer::switches::kChromeFrame); |
| |
| if (system_install_) |
| cmd.AppendSwitch(installer::switches::kSystemLevel); |
| |
| base::ProcessHandle setup_handle; |
| base::LaunchProcess(cmd, base::LaunchOptions(), &setup_handle); |
| |
| ASSERT_TRUE(CloseUninstallWindow()); |
| ASSERT_TRUE(MiniInstallerTestUtil::VerifyProcessHandleClosed(setup_handle)); |
| ASSERT_FALSE(CheckRegistryKeyOnUninstall(dist->GetVersionKey())); |
| |
| DeleteUserDataFolder(); |
| MiniInstallerTestUtil::CloseProcesses( |
| mini_installer_constants::kIEProcessName); |
| } |
| |
| // Will clean up the machine if Chrome install is messed up. |
| void ChromeMiniInstaller::CleanChromeInstall() { |
| DeletePvRegistryKey(); |
| FilePath install_path; |
| ASSERT_TRUE(GetChromeInstallDirectoryLocation(&install_path)); |
| ASSERT_TRUE(file_util::Delete(install_path, true)); |
| } |
| |
| bool ChromeMiniInstaller::CloseUninstallWindow() { |
| HWND hndl = NULL; |
| int timer = 0; |
| std::wstring window_name; |
| if (is_chrome_frame_) |
| window_name = mini_installer_constants::kChromeFrameAppName; |
| else |
| window_name = mini_installer_constants::kChromeUninstallDialogName; |
| while (hndl == NULL && timer < 5000) { |
| hndl = FindWindow(NULL, window_name.c_str()); |
| base::PlatformThread::Sleep(200); |
| timer = timer + 200; |
| } |
| |
| if (!is_chrome_frame_) { |
| if (hndl == NULL) |
| hndl = FindWindow(NULL, mini_installer_constants::kChromeBuildType); |
| |
| if (hndl == NULL) |
| return false; |
| |
| SetForegroundWindow(hndl); |
| MiniInstallerTestUtil::SendEnterKeyToWindow(); |
| } |
| return true; |
| } |
| |
| // Closes Chrome browser. |
| bool ChromeMiniInstaller::CloseChromeBrowser() { |
| int timer = 0; |
| HWND handle = NULL; |
| // This loop iterates through all of the top-level Windows |
| // named Chrome_WidgetWin_0 and closes them |
| while ((base::GetProcessCount(installer::kChromeExe, NULL) > 0) && |
| (timer < 40000)) { |
| // Chrome may have been launched, but the window may not have appeared |
| // yet. Wait for it to appear for 10 seconds, but exit if it takes longer |
| // than that. |
| while (!handle && timer < 10000) { |
| handle = FindWindowEx(NULL, handle, L"Chrome_WidgetWin_0", NULL); |
| if (!handle) { |
| base::PlatformThread::Sleep(100); |
| timer = timer + 100; |
| } |
| } |
| if (!handle) |
| return false; |
| SetForegroundWindow(handle); |
| LRESULT _result = SendMessage(handle, WM_CLOSE, 1, 0); |
| if (_result != 0) |
| return false; |
| base::PlatformThread::Sleep(1000); |
| timer = timer + 1000; |
| } |
| if (base::GetProcessCount(installer::kChromeExe, NULL) > 0) { |
| printf("Chrome.exe is still running even after closing all windows\n"); |
| return false; |
| } |
| if (base::GetProcessCount(installer::kNaClExe, NULL) > 0) { |
| printf("NaCl.exe is still running even after closing all windows\n"); |
| return false; |
| } |
| return true; |
| } |
| |
| // Checks for Chrome registry keys. |
| bool ChromeMiniInstaller::CheckRegistryKey(const std::wstring& key_path) { |
| RegKey key; |
| LONG ret = key.Open(GetRootRegistryKey(), key_path.c_str(), KEY_ALL_ACCESS); |
| if (ret != ERROR_SUCCESS) { |
| printf("Cannot open reg key. error: %d\n", ret); |
| return false; |
| } |
| std::string reg_key_value_returned; |
| if (!GetChromeVersionFromRegistry(®_key_value_returned)) |
| return false; |
| return true; |
| } |
| |
| // Checks for Chrome registry keys on uninstall. |
| bool ChromeMiniInstaller::CheckRegistryKeyOnUninstall( |
| const std::wstring& key_path) { |
| RegKey key; |
| int timer = 0; |
| while ((key.Open(GetRootRegistryKey(), key_path.c_str(), |
| KEY_ALL_ACCESS) == ERROR_SUCCESS) && |
| (timer < 20000)) { |
| base::PlatformThread::Sleep(200); |
| timer = timer + 200; |
| } |
| return CheckRegistryKey(key_path); |
| } |
| |
| // Will delete user data profile. |
| void ChromeMiniInstaller::DeleteUserDataFolder() { |
| FilePath path = GetUserDataDirPath(); |
| if (file_util::PathExists(path)) |
| ASSERT_TRUE(file_util::Delete(path, true)); |
| } |
| |
| // Gets user data directory path |
| FilePath ChromeMiniInstaller::GetUserDataDirPath() { |
| FilePath path; |
| PathService::Get(base::DIR_LOCAL_APP_DATA, &path); |
| FilePath profile_path = path; |
| if (is_chrome_frame_) { |
| profile_path = profile_path.Append( |
| mini_installer_constants::kChromeFrameAppDir); |
| } else { |
| profile_path = profile_path.Append( |
| mini_installer_constants::kChromeAppDir); |
| } |
| profile_path = profile_path.DirName(); |
| profile_path = profile_path.Append( |
| mini_installer_constants::kChromeUserDataDir); |
| return profile_path; |
| } |
| |
| // Deletes pv key from Clients. |
| void ChromeMiniInstaller::DeletePvRegistryKey() { |
| std::wstring pv_key(google_update::kRegPathClients); |
| pv_key.append(L"\\"); |
| |
| BrowserDistribution* dist = GetCurrentBrowserDistribution(); |
| pv_key.append(dist->GetAppGuid()); |
| |
| RegKey key; |
| if (key.Open(GetRootRegistryKey(), pv_key.c_str(), KEY_ALL_ACCESS) == |
| ERROR_SUCCESS) |
| ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(L"pv")); |
| printf("Deleted %ls key\n", pv_key.c_str()); |
| } |
| |
| // Verifies if Chrome shortcut exists. |
| void ChromeMiniInstaller::FindChromeShortcut() { |
| bool return_val = false; |
| FilePath uninstall_lnk; |
| FilePath path = GetStartMenuShortcutPath(); |
| path = path.Append(mini_installer_constants::kChromeBuildType); |
| // Verify if path exists. |
| if (file_util::PathExists(path)) { |
| return_val = true; |
| uninstall_lnk = path; |
| path = path.Append(mini_installer_constants::kChromeLaunchShortcut); |
| uninstall_lnk = uninstall_lnk.Append( |
| mini_installer_constants::kChromeUninstallShortcut); |
| ASSERT_TRUE(file_util::PathExists(path)); |
| ASSERT_TRUE(file_util::PathExists(uninstall_lnk)); |
| } |
| if (return_val) { |
| LOG(INFO) << "Found Chrome shortcuts:\n" |
| << path.value() << "\n" |
| << uninstall_lnk.value(); |
| } else { |
| LOG(INFO) << "No Chrome shortcuts found."; |
| } |
| } |
| |
| bool ChromeMiniInstaller::GetChromeInstallDirectoryLocation(FilePath* path) { |
| BrowserDistribution* dist = GetCurrentBrowserDistribution(); |
| *path = installer::GetChromeInstallPath(system_install_, dist); |
| FilePath parent; |
| if (system_install_) { |
| PathService::Get(base::DIR_PROGRAM_FILES, &parent); |
| return file_util::ContainsPath(parent, *path); |
| } else { |
| PathService::Get(base::DIR_LOCAL_APP_DATA, &parent); |
| return file_util::ContainsPath(parent, *path); |
| } |
| } |
| |
| FilePath ChromeMiniInstaller::GetStartMenuShortcutPath() { |
| FilePath path_name; |
| if (system_install_) |
| PathService::Get(base::DIR_COMMON_START_MENU, &path_name); |
| else |
| PathService::Get(base::DIR_START_MENU, &path_name); |
| return path_name; |
| } |
| |
| // Returns Chrome pv registry key value |
| bool ChromeMiniInstaller::GetChromeVersionFromRegistry( |
| std::string* build_key_value) { |
| BrowserDistribution* dist = GetCurrentBrowserDistribution(); |
| RegKey key(GetRootRegistryKey(), dist->GetVersionKey().c_str(), KEY_READ); |
| std::wstring value; |
| LONG result = key.ReadValue(L"pv", &value); |
| if (result != ERROR_SUCCESS) { |
| LOG(WARNING) << "Registry read for Chrome version error: " << result; |
| return false; |
| } |
| *build_key_value = WideToASCII(value); |
| LOG(INFO) << "Build key value is " << build_key_value; |
| return true; |
| } |
| |
| // Get HKEY based on install type. |
| HKEY ChromeMiniInstaller::GetRootRegistryKey() { |
| HKEY type = HKEY_CURRENT_USER; |
| if (system_install_) |
| type = HKEY_LOCAL_MACHINE; |
| return type; |
| } |
| |
| // Launches the chrome installer and waits for it to end. |
| void ChromeMiniInstaller::RunInstaller(const CommandLine& command) { |
| ASSERT_TRUE(file_util::PathExists(command.GetProgram())); |
| CommandLine installer(command); |
| if (is_chrome_frame_) { |
| installer.AppendSwitch(installer::switches::kDoNotCreateShortcuts); |
| installer.AppendSwitch(installer::switches::kDoNotLaunchChrome); |
| installer.AppendSwitch(installer::switches::kDoNotRegisterForUpdateLaunch); |
| installer.AppendSwitch(installer::switches::kChromeFrame); |
| } |
| if (system_install_) { |
| installer.AppendSwitch(installer::switches::kSystemLevel); |
| } |
| |
| LOG(INFO) << "Running installer command: " |
| << installer.GetCommandLineString(); |
| base::ProcessHandle app_handle; |
| ASSERT_TRUE( |
| base::LaunchProcess(installer, base::LaunchOptions(), &app_handle)) |
| << "Installer failed."; |
| ASSERT_TRUE(base::WaitForSingleProcess(app_handle, 60 * 1000)) |
| << "Installer did not complete."; |
| } |
| |
| void ChromeMiniInstaller::LaunchChrome(bool kill) { |
| MiniInstallerTestUtil::CloseProcesses(installer::kChromeExe); |
| |
| FilePath install_path; |
| ASSERT_TRUE(GetChromeInstallDirectoryLocation(&install_path)); |
| install_path = install_path.Append(installer::kChromeExe); |
| CommandLine browser(install_path); |
| |
| FilePath exe = browser.GetProgram(); |
| LOG(INFO) << "Browser launch command: " << browser.GetCommandLineString(); |
| base::ProcessHandle chrome; |
| ASSERT_TRUE(base::LaunchProcess(browser, base::LaunchOptions(), &chrome)) |
| << "Could not launch process: " << exe.value(); |
| |
| if (kill) { |
| ASSERT_TRUE(base::KillProcess(chrome, 0, true)) |
| << "Failed to kill chrome.exe"; |
| } |
| } |
| |
| // Verifies Chrome/Chrome Frame install. |
| void ChromeMiniInstaller::VerifyInstall(bool over_install) { |
| InstallationValidator::InstallationType type = |
| installer::ExpectValidInstallation(system_install_); |
| if (is_chrome_frame_) { |
| EXPECT_NE(0, |
| type & InstallationValidator::ProductBits::CHROME_FRAME_SINGLE); |
| } else { |
| EXPECT_NE(0, type & InstallationValidator::ProductBits::CHROME_SINGLE); |
| } |
| |
| if (is_chrome_frame_) |
| VerifyChromeFrameInstall(); |
| else if (!system_install_ && !over_install) |
| MiniInstallerTestUtil::VerifyProcessLaunch(installer::kChromeExe, true); |
| |
| base::PlatformThread::Sleep(800); |
| FindChromeShortcut(); |
| LaunchChrome(true); |
| } |
| |
| // This method will verify if ChromeFrame installed successfully. It will |
| // launch IE with cf:about:version, then check if |
| // chrome.exe process got spawned. |
| void ChromeMiniInstaller::VerifyChromeFrameInstall() { |
| // Launch IE |
| LaunchIE(L"gcf:about:version"); |
| |
| // Check if Chrome process got spawned. |
| MiniInstallerTestUtil::VerifyProcessLaunch(installer::kChromeExe, true); |
| } |
| |
| void ChromeMiniInstaller::LaunchIE(const std::wstring& navigate_url) { |
| FilePath browser_path; |
| PathService::Get(base::DIR_PROGRAM_FILES, &browser_path); |
| browser_path = browser_path.Append(mini_installer_constants::kIELocation); |
| browser_path = browser_path.Append(mini_installer_constants::kIEProcessName); |
| |
| CommandLine cmd_line(browser_path); |
| cmd_line.AppendArgNative(navigate_url); |
| |
| base::LaunchProcess(cmd_line, base::LaunchOptions(), NULL); |
| } |
| |
| // This method compares the registry keys after overinstall. |
| bool ChromeMiniInstaller::VerifyOverInstall( |
| const std::string& value_before_overinstall, |
| const std::string& value_after_overinstall) { |
| int64 reg_key_value_before_overinstall; |
| base::StringToInt64(value_before_overinstall, |
| ®_key_value_before_overinstall); |
| int64 reg_key_value_after_overinstall; |
| base::StringToInt64(value_after_overinstall, |
| ®_key_value_after_overinstall); |
| |
| // Compare to see if the version is less. |
| LOG(INFO) << "Reg Key value before overinstall is: " |
| << value_before_overinstall; |
| LOG(INFO) << "Reg Key value after overinstall is: " |
| << value_after_overinstall; |
| if (reg_key_value_before_overinstall > reg_key_value_after_overinstall) { |
| LOG(ERROR) << "FAIL: Overinstalled a lower version of Chrome."; |
| return false; |
| } |
| return true; |
| } |
| |
| // This method will verify if the installed build is correct. |
| bool ChromeMiniInstaller::VerifyStandaloneInstall() { |
| std::string reg_key_value_returned; |
| if (!GetChromeVersionFromRegistry(®_key_value_returned)) |
| return false; |
| if (current_build_.compare(reg_key_value_returned) == 0) |
| return true; |
| else |
| return false; |
| } |
| |
| BrowserDistribution* ChromeMiniInstaller::GetCurrentBrowserDistribution() { |
| return BrowserDistribution::GetSpecificDistribution( |
| is_chrome_frame_ ? |
| BrowserDistribution::CHROME_FRAME : |
| BrowserDistribution::CHROME_BROWSER); |
| } |
| |
| bool ChromeMiniInstaller::GetFullInstaller(FilePath* path) { |
| std::string full_installer_pattern("*_chrome_installer*"); |
| return GetInstaller(full_installer_pattern, path); |
| } |
| |
| bool ChromeMiniInstaller::GetDiffInstaller(FilePath* path) { |
| std::string diff_installer_pattern("*_from_*"); |
| return GetInstaller(diff_installer_pattern, path); |
| } |
| |
| bool ChromeMiniInstaller::GetMiniInstaller(FilePath* path) { |
| // Use local copy of installer, else fall back to filer. |
| FilePath mini_installer = MiniInstallerTestUtil::GetFilePath(
|
| mini_installer_constants::kChromeMiniInstallerExecutable); |
| if (file_util::PathExists(mini_installer)) { |
| *path = mini_installer; |
| return true; |
| } |
| std::string mini_installer_pattern("mini_installer.exe"); |
| return GetInstaller(mini_installer_pattern, path); |
| } |
| |
| bool ChromeMiniInstaller::GetPreviousInstaller(FilePath* path) { |
| std::string diff_installer_pattern("*_from_*"); |
| std::string full_installer_pattern("*_chrome_installer*"); |
| FilePath diff_installer; |
| if (!GetInstaller(diff_installer_pattern, &diff_installer)) |
| return false; |
| |
| FilePath previous_installer; |
| std::vector<std::string> tokenized_name; |
| Tokenize(diff_installer.BaseName().MaybeAsASCII(), |
| "_", &tokenized_name); |
| std::string build_pattern = base::StringPrintf( |
| "*%s", tokenized_name[2].c_str()); |
| std::vector<FilePath> previous_build; |
| if (FindMatchingFiles(diff_installer.DirName().DirName().DirName(), |
| build_pattern, file_util::FileEnumerator::DIRECTORIES, |
| &previous_build)) { |
| FilePath windir = previous_build.at(0).Append( |
| mini_installer_constants::kWinFolder); |
| FindNewestMatchingFile(windir, full_installer_pattern, |
| file_util::FileEnumerator::FILES, &previous_installer); |
| } |
| |
| if (previous_installer.empty()) |
| return false; |
| *path = previous_installer; |
| return true; |
| } |
| |
| bool ChromeMiniInstaller::GetStandaloneInstaller(FilePath* path) { |
| // Get standalone installer. |
| FilePath standalone_installer( |
| mini_installer_constants::kChromeStandAloneInstallerLocation); |
| |
| // Get the file name. |
| std::vector<std::string> tokenizedBuildNumber; |
| Tokenize(current_build_, ".", &tokenizedBuildNumber); |
| std::string standalone_installer_filename = base::StringPrintf( |
| "%s%s_%s.exe", |
| FilePath(mini_installer_constants::kUntaggedInstallerPattern) |
| .MaybeAsASCII().c_str(), |
| tokenizedBuildNumber[2].c_str(), |
| tokenizedBuildNumber[3].c_str()); |
| standalone_installer = standalone_installer.AppendASCII(current_build_) |
| .Append(mini_installer_constants::kWinFolder) |
| .AppendASCII(standalone_installer_filename); |
| *path = standalone_installer; |
| return file_util::PathExists(standalone_installer); |
| } |
| |
| bool ChromeMiniInstaller::GetInstaller(const std::string& pattern, |
| FilePath* path) { |
| FilePath installer; |
| |
| // Search directory where current exe is located. |
| FilePath dir_exe; |
| if (PathService::Get(base::DIR_EXE, &dir_exe) && |
| FindNewestMatchingFile(dir_exe, pattern, |
| file_util::FileEnumerator::FILES, &installer)) { |
| *path = installer; |
| return true; |
| } |
| // Fall back to filer. |
| FilePath root(mini_installer_constants::kChromeInstallersLocation); |
| std::vector<FilePath> paths; |
| if (!FindMatchingFiles(root, build_, |
| file_util::FileEnumerator::DIRECTORIES, &paths)) { |
| return false; |
| } |
| |
| std::vector<FilePath>::const_iterator dir; |
| for (dir = paths.begin(); dir != paths.end(); ++dir) { |
| FilePath windir = dir->Append( |
| mini_installer_constants::kWinFolder); |
| if (FindNewestMatchingFile(windir, pattern, |
| file_util::FileEnumerator::FILES, &installer)) { |
| break; |
| } |
| } |
| |
| if (installer.empty()) { |
| LOG(WARNING) << "Failed to find installer with pattern: " << pattern; |
| return false; |
| } |
| |
| *path = installer; |
| return true; |
| } |