product.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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_util.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
65void Product::GetUserDataPaths(std::vector<base::FilePath>* paths) const {
66  GetChromeUserDataPaths(distribution_, paths);
67}
68
69bool Product::LaunchChrome(const base::FilePath& application_path) const {
70  bool success = !application_path.empty();
71  if (success) {
72    CommandLine cmd(application_path.Append(installer::kChromeExe));
73    success = base::LaunchProcess(cmd, base::LaunchOptions(), NULL);
74  }
75  return success;
76}
77
78bool Product::LaunchChromeAndWait(const base::FilePath& application_path,
79                                  const CommandLine& options,
80                                  int32* exit_code) const {
81  if (application_path.empty())
82    return false;
83
84  CommandLine cmd(application_path.Append(installer::kChromeExe));
85  cmd.AppendArguments(options, false);
86
87  bool success = false;
88  STARTUPINFOW si = { sizeof(si) };
89  PROCESS_INFORMATION pi = {0};
90  // Create a writable copy of the command line string, since CreateProcess may
91  // modify the string (insert \0 to separate the program from the arguments).
92  std::wstring writable_command_line_string(cmd.GetCommandLineString());
93  if (!::CreateProcess(cmd.GetProgram().value().c_str(),
94                       &writable_command_line_string[0],
95                       NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL,
96                       &si, &pi)) {
97    PLOG(ERROR) << "Failed to launch: " << cmd.GetCommandLineString();
98  } else {
99    ::CloseHandle(pi.hThread);
100
101    DWORD ret = ::WaitForSingleObject(pi.hProcess, INFINITE);
102    DLOG_IF(ERROR, ret != WAIT_OBJECT_0)
103        << "Unexpected return value from WaitForSingleObject: " << ret;
104    if (::GetExitCodeProcess(pi.hProcess, &ret)) {
105      DCHECK(ret != STILL_ACTIVE);
106      success = true;
107      if (exit_code)
108        *exit_code = ret;
109    } else {
110      PLOG(ERROR) << "GetExitCodeProcess failed";
111    }
112
113    ::CloseHandle(pi.hProcess);
114  }
115
116  return success;
117}
118
119bool Product::SetMsiMarker(bool system_install, bool set) const {
120  HKEY reg_root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
121  RegKey client_state_key;
122  LONG result = client_state_key.Open(reg_root,
123      distribution_->GetStateKey().c_str(), KEY_READ | KEY_WRITE);
124  if (result == ERROR_SUCCESS) {
125    result = client_state_key.WriteValue(google_update::kRegMSIField,
126                                         set ? 1 : 0);
127  }
128
129  LOG_IF(ERROR, result != ERROR_SUCCESS) << "Failed to Open or Write MSI value"
130      "to client state key. error: " << result;
131
132  return (result == ERROR_SUCCESS);
133}
134
135bool Product::ShouldCreateUninstallEntry() const {
136  return operations_->ShouldCreateUninstallEntry(options_);
137}
138
139void Product::AddKeyFiles(std::vector<base::FilePath>* key_files) const {
140  operations_->AddKeyFiles(options_, key_files);
141}
142
143void Product::AddComDllList(std::vector<base::FilePath>* com_dll_list) const {
144  operations_->AddComDllList(options_, com_dll_list);
145}
146
147void Product::AppendProductFlags(CommandLine* command_line) const {
148  operations_->AppendProductFlags(options_, command_line);
149}
150
151void Product::AppendRenameFlags(CommandLine* command_line) const {
152  operations_->AppendRenameFlags(options_, command_line);
153}
154
155bool Product::SetChannelFlags(bool set, ChannelInfo* channel_info) const {
156  return operations_->SetChannelFlags(options_, set, channel_info);
157}
158
159void Product::AddDefaultShortcutProperties(
160    const base::FilePath& target_exe,
161    ShellUtil::ShortcutProperties* properties) const {
162  return operations_->AddDefaultShortcutProperties(
163      distribution_, target_exe, properties);
164}
165
166void Product::LaunchUserExperiment(const base::FilePath& setup_path,
167                                   InstallStatus status,
168                                   bool system_level) const {
169  if (distribution_->HasUserExperiments()) {
170    VLOG(1) << "LaunchUserExperiment status: " << status << " product: "
171            << distribution_->GetAppShortCutName()
172            << " system_level: " << system_level;
173    operations_->LaunchUserExperiment(
174        setup_path, options_, status, system_level);
175  }
176}
177
178}  // namespace installer
179