| // 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 |