1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/installer/util/product.h" 6 7#include <algorithm> 8 9#include "base/command_line.h" 10#include "base/logging.h" 11#include "base/process/launch.h" 12#include "base/win/registry.h" 13#include "chrome/installer/util/chrome_app_host_operations.h" 14#include "chrome/installer/util/chrome_binaries_operations.h" 15#include "chrome/installer/util/chrome_browser_operations.h" 16#include "chrome/installer/util/chrome_browser_sxs_operations.h" 17#include "chrome/installer/util/chrome_frame_operations.h" 18#include "chrome/installer/util/google_update_constants.h" 19#include "chrome/installer/util/helper.h" 20#include "chrome/installer/util/install_util.h" 21#include "chrome/installer/util/master_preferences.h" 22#include "chrome/installer/util/master_preferences_constants.h" 23#include "chrome/installer/util/product_operations.h" 24 25using base::win::RegKey; 26using installer::MasterPreferences; 27 28namespace installer { 29 30Product::Product(BrowserDistribution* distribution) 31 : distribution_(distribution) { 32 switch (distribution->GetType()) { 33 case BrowserDistribution::CHROME_BROWSER: 34 operations_.reset(InstallUtil::IsChromeSxSProcess() ? 35 new ChromeBrowserSxSOperations() : 36 new ChromeBrowserOperations()); 37 break; 38 case BrowserDistribution::CHROME_FRAME: 39 operations_.reset(new ChromeFrameOperations()); 40 break; 41 case BrowserDistribution::CHROME_APP_HOST: 42 operations_.reset(new ChromeAppHostOperations()); 43 break; 44 case BrowserDistribution::CHROME_BINARIES: 45 operations_.reset(new ChromeBinariesOperations()); 46 break; 47 default: 48 NOTREACHED() << "Unsupported BrowserDistribution::Type: " 49 << distribution->GetType(); 50 } 51} 52 53Product::~Product() { 54} 55 56void Product::InitializeFromPreferences(const MasterPreferences& prefs) { 57 operations_->ReadOptions(prefs, &options_); 58} 59 60void Product::InitializeFromUninstallCommand( 61 const CommandLine& uninstall_command) { 62 operations_->ReadOptions(uninstall_command, &options_); 63} 64 65bool Product::LaunchChrome(const base::FilePath& application_path) const { 66 bool success = !application_path.empty(); 67 if (success) { 68 CommandLine cmd(application_path.Append(installer::kChromeExe)); 69 success = base::LaunchProcess(cmd, base::LaunchOptions(), NULL); 70 } 71 return success; 72} 73 74bool Product::LaunchChromeAndWait(const base::FilePath& application_path, 75 const CommandLine& options, 76 int32* exit_code) const { 77 if (application_path.empty()) 78 return false; 79 80 CommandLine cmd(application_path.Append(installer::kChromeExe)); 81 cmd.AppendArguments(options, false); 82 83 bool success = false; 84 STARTUPINFOW si = { sizeof(si) }; 85 PROCESS_INFORMATION pi = {0}; 86 // Create a writable copy of the command line string, since CreateProcess may 87 // modify the string (insert \0 to separate the program from the arguments). 88 std::wstring writable_command_line_string(cmd.GetCommandLineString()); 89 if (!::CreateProcess(cmd.GetProgram().value().c_str(), 90 &writable_command_line_string[0], 91 NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, 92 &si, &pi)) { 93 PLOG(ERROR) << "Failed to launch: " << cmd.GetCommandLineString(); 94 } else { 95 ::CloseHandle(pi.hThread); 96 97 DWORD ret = ::WaitForSingleObject(pi.hProcess, INFINITE); 98 DLOG_IF(ERROR, ret != WAIT_OBJECT_0) 99 << "Unexpected return value from WaitForSingleObject: " << ret; 100 if (::GetExitCodeProcess(pi.hProcess, &ret)) { 101 DCHECK(ret != STILL_ACTIVE); 102 success = true; 103 if (exit_code) 104 *exit_code = ret; 105 } else { 106 PLOG(ERROR) << "GetExitCodeProcess failed"; 107 } 108 109 ::CloseHandle(pi.hProcess); 110 } 111 112 return success; 113} 114 115bool Product::SetMsiMarker(bool system_install, bool set) const { 116 HKEY reg_root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 117 RegKey client_state_key; 118 LONG result = client_state_key.Open(reg_root, 119 distribution_->GetStateKey().c_str(), 120 KEY_SET_VALUE | KEY_WOW64_32KEY); 121 if (result == ERROR_SUCCESS) { 122 result = client_state_key.WriteValue(google_update::kRegMSIField, 123 set ? 1 : 0); 124 } 125 if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) { 126 LOG(ERROR) 127 << "Failed to Open or Write MSI value to client state key. error: " 128 << result; 129 return false; 130 } 131 return true; 132} 133 134bool Product::ShouldCreateUninstallEntry() const { 135 return operations_->ShouldCreateUninstallEntry(options_); 136} 137 138void Product::AddKeyFiles(std::vector<base::FilePath>* key_files) const { 139 operations_->AddKeyFiles(options_, key_files); 140} 141 142void Product::AddComDllList(std::vector<base::FilePath>* com_dll_list) const { 143 operations_->AddComDllList(options_, com_dll_list); 144} 145 146void Product::AppendProductFlags(CommandLine* command_line) const { 147 operations_->AppendProductFlags(options_, command_line); 148} 149 150void Product::AppendRenameFlags(CommandLine* command_line) const { 151 operations_->AppendRenameFlags(options_, command_line); 152} 153 154bool Product::SetChannelFlags(bool set, ChannelInfo* channel_info) const { 155 return operations_->SetChannelFlags(options_, set, channel_info); 156} 157 158void Product::AddDefaultShortcutProperties( 159 const base::FilePath& target_exe, 160 ShellUtil::ShortcutProperties* properties) const { 161 return operations_->AddDefaultShortcutProperties( 162 distribution_, target_exe, properties); 163} 164 165void Product::LaunchUserExperiment(const base::FilePath& setup_path, 166 InstallStatus status, 167 bool system_level) const { 168 if (distribution_->HasUserExperiments()) { 169 VLOG(1) << "LaunchUserExperiment status: " << status << " product: " 170 << distribution_->GetDisplayName() 171 << " system_level: " << system_level; 172 operations_->LaunchUserExperiment( 173 setup_path, options_, status, system_level); 174 } 175} 176 177} // namespace installer 178