product.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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_READ | KEY_WRITE | KEY_WOW64_32KEY);
121  if (result == ERROR_SUCCESS) {
122    result = client_state_key.WriteValue(google_update::kRegMSIField,
123                                         set ? 1 : 0);
124  }
125
126  LOG_IF(ERROR, result != ERROR_SUCCESS) << "Failed to Open or Write MSI value"
127      "to client state key. error: " << result;
128
129  return (result == ERROR_SUCCESS);
130}
131
132bool Product::ShouldCreateUninstallEntry() const {
133  return operations_->ShouldCreateUninstallEntry(options_);
134}
135
136void Product::AddKeyFiles(std::vector<base::FilePath>* key_files) const {
137  operations_->AddKeyFiles(options_, key_files);
138}
139
140void Product::AddComDllList(std::vector<base::FilePath>* com_dll_list) const {
141  operations_->AddComDllList(options_, com_dll_list);
142}
143
144void Product::AppendProductFlags(CommandLine* command_line) const {
145  operations_->AppendProductFlags(options_, command_line);
146}
147
148void Product::AppendRenameFlags(CommandLine* command_line) const {
149  operations_->AppendRenameFlags(options_, command_line);
150}
151
152bool Product::SetChannelFlags(bool set, ChannelInfo* channel_info) const {
153  return operations_->SetChannelFlags(options_, set, channel_info);
154}
155
156void Product::AddDefaultShortcutProperties(
157    const base::FilePath& target_exe,
158    ShellUtil::ShortcutProperties* properties) const {
159  return operations_->AddDefaultShortcutProperties(
160      distribution_, target_exe, properties);
161}
162
163void Product::LaunchUserExperiment(const base::FilePath& setup_path,
164                                   InstallStatus status,
165                                   bool system_level) const {
166  if (distribution_->HasUserExperiments()) {
167    VLOG(1) << "LaunchUserExperiment status: " << status << " product: "
168            << distribution_->GetDisplayName()
169            << " system_level: " << system_level;
170    operations_->LaunchUserExperiment(
171        setup_path, options_, status, system_level);
172  }
173}
174
175}  // namespace installer
176