// Copyright (c) 2012 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/installer/util/product.h" #include <algorithm> #include "base/command_line.h" #include "base/logging.h" #include "base/process/launch.h" #include "base/win/registry.h" #include "chrome/installer/util/chrome_app_host_operations.h" #include "chrome/installer/util/chrome_binaries_operations.h" #include "chrome/installer/util/chrome_browser_operations.h" #include "chrome/installer/util/chrome_browser_sxs_operations.h" #include "chrome/installer/util/chrome_frame_operations.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/master_preferences.h" #include "chrome/installer/util/master_preferences_constants.h" #include "chrome/installer/util/product_operations.h" using base::win::RegKey; using installer::MasterPreferences; namespace installer { Product::Product(BrowserDistribution* distribution) : distribution_(distribution) { switch (distribution->GetType()) { case BrowserDistribution::CHROME_BROWSER: operations_.reset(InstallUtil::IsChromeSxSProcess() ? new ChromeBrowserSxSOperations() : new ChromeBrowserOperations()); break; case BrowserDistribution::CHROME_FRAME: operations_.reset(new ChromeFrameOperations()); break; case BrowserDistribution::CHROME_APP_HOST: operations_.reset(new ChromeAppHostOperations()); break; case BrowserDistribution::CHROME_BINARIES: operations_.reset(new ChromeBinariesOperations()); break; default: NOTREACHED() << "Unsupported BrowserDistribution::Type: " << distribution->GetType(); } } Product::~Product() { } void Product::InitializeFromPreferences(const MasterPreferences& prefs) { operations_->ReadOptions(prefs, &options_); } void Product::InitializeFromUninstallCommand( const CommandLine& uninstall_command) { operations_->ReadOptions(uninstall_command, &options_); } void Product::GetUserDataPaths(std::vector<base::FilePath>* paths) const { GetChromeUserDataPaths(distribution_, paths); } bool Product::LaunchChrome(const base::FilePath& application_path) const { bool success = !application_path.empty(); if (success) { CommandLine cmd(application_path.Append(installer::kChromeExe)); success = base::LaunchProcess(cmd, base::LaunchOptions(), NULL); } return success; } bool Product::LaunchChromeAndWait(const base::FilePath& application_path, const CommandLine& options, int32* exit_code) const { if (application_path.empty()) return false; CommandLine cmd(application_path.Append(installer::kChromeExe)); cmd.AppendArguments(options, false); bool success = false; STARTUPINFOW si = { sizeof(si) }; PROCESS_INFORMATION pi = {0}; // Create a writable copy of the command line string, since CreateProcess may // modify the string (insert \0 to separate the program from the arguments). std::wstring writable_command_line_string(cmd.GetCommandLineString()); if (!::CreateProcess(cmd.GetProgram().value().c_str(), &writable_command_line_string[0], NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { PLOG(ERROR) << "Failed to launch: " << cmd.GetCommandLineString(); } else { ::CloseHandle(pi.hThread); DWORD ret = ::WaitForSingleObject(pi.hProcess, INFINITE); DLOG_IF(ERROR, ret != WAIT_OBJECT_0) << "Unexpected return value from WaitForSingleObject: " << ret; if (::GetExitCodeProcess(pi.hProcess, &ret)) { DCHECK(ret != STILL_ACTIVE); success = true; if (exit_code) *exit_code = ret; } else { PLOG(ERROR) << "GetExitCodeProcess failed"; } ::CloseHandle(pi.hProcess); } return success; } bool Product::SetMsiMarker(bool system_install, bool set) const { HKEY reg_root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; RegKey client_state_key; LONG result = client_state_key.Open(reg_root, distribution_->GetStateKey().c_str(), KEY_READ | KEY_WRITE); if (result == ERROR_SUCCESS) { result = client_state_key.WriteValue(google_update::kRegMSIField, set ? 1 : 0); } LOG_IF(ERROR, result != ERROR_SUCCESS) << "Failed to Open or Write MSI value" "to client state key. error: " << result; return (result == ERROR_SUCCESS); } bool Product::ShouldCreateUninstallEntry() const { return operations_->ShouldCreateUninstallEntry(options_); } void Product::AddKeyFiles(std::vector<base::FilePath>* key_files) const { operations_->AddKeyFiles(options_, key_files); } void Product::AddComDllList(std::vector<base::FilePath>* com_dll_list) const { operations_->AddComDllList(options_, com_dll_list); } void Product::AppendProductFlags(CommandLine* command_line) const { operations_->AppendProductFlags(options_, command_line); } void Product::AppendRenameFlags(CommandLine* command_line) const { operations_->AppendRenameFlags(options_, command_line); } bool Product::SetChannelFlags(bool set, ChannelInfo* channel_info) const { return operations_->SetChannelFlags(options_, set, channel_info); } void Product::AddDefaultShortcutProperties( const base::FilePath& target_exe, ShellUtil::ShortcutProperties* properties) const { return operations_->AddDefaultShortcutProperties( distribution_, target_exe, properties); } void Product::LaunchUserExperiment(const base::FilePath& setup_path, InstallStatus status, bool system_level) const { if (distribution_->HasUserExperiments()) { VLOG(1) << "LaunchUserExperiment status: " << status << " product: " << distribution_->GetDisplayName() << " system_level: " << system_level; operations_->LaunchUserExperiment( setup_path, options_, status, system_level); } } } // namespace installer