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#ifndef CHROME_INSTALLER_UTIL_INSTALLER_STATE_H_
6#define CHROME_INSTALLER_UTIL_INSTALLER_STATE_H_
7
8#include <set>
9#include <string>
10#include <vector>
11
12#include "base/basictypes.h"
13#include "base/files/file_path.h"
14#include "base/logging.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/memory/scoped_vector.h"
17#include "base/version.h"
18#include "chrome/installer/util/browser_distribution.h"
19#include "chrome/installer/util/product.h"
20#include "chrome/installer/util/util_constants.h"
21
22#if defined(OS_WIN)
23#include <windows.h>  // NOLINT
24#endif
25
26namespace base {
27class CommandLine;
28}
29
30namespace installer {
31
32class ChannelInfo;
33class InstallationState;
34class MasterPreferences;
35
36class ProductState;
37
38typedef std::vector<Product*> Products;
39
40// Encapsulates the state of the current installation operation.  Only valid
41// for installs and upgrades (not for uninstalls or non-install commands).
42// This class interprets the command-line arguments and master preferences and
43// determines the operations to be performed. For example, the Chrome Binaries
44// are automatically added if required in multi-install mode.
45// TODO(erikwright): This is now used a fair bit during uninstall, and
46// InstallerState::Initialize() contains a lot of code for uninstall. The class
47// comment should probably be updated.
48// TODO(grt): Rename to InstallerEngine/Conductor or somesuch?
49class InstallerState {
50 public:
51  enum Level {
52    UNKNOWN_LEVEL,
53    USER_LEVEL,
54    SYSTEM_LEVEL
55  };
56
57  enum PackageType {
58    UNKNOWN_PACKAGE_TYPE,
59    SINGLE_PACKAGE,
60    MULTI_PACKAGE
61  };
62
63  enum Operation {
64    UNINITIALIZED,
65    SINGLE_INSTALL_OR_UPDATE,
66    MULTI_INSTALL,
67    MULTI_UPDATE,
68    UNINSTALL
69  };
70
71  // Constructs an uninitialized instance; see Initialize().
72  InstallerState();
73
74  // Constructs an initialized but empty instance.
75  explicit InstallerState(Level level);
76
77  // Initializes this object based on the current operation.
78  void Initialize(const base::CommandLine& command_line,
79                  const MasterPreferences& prefs,
80                  const InstallationState& machine_state);
81
82  // Adds a product constructed on the basis of |state|, setting this object's
83  // msi flag if |state| is msi-installed.  Returns the product that was added,
84  // or NULL if |state| is incompatible with this object.  Ownership is not
85  // passed to the caller.
86  Product* AddProductFromState(BrowserDistribution::Type type,
87                               const ProductState& state);
88
89  // Returns the product that was added, or NULL if |product| is incompatible
90  // with this object.  Ownership of |product| is taken by this object, while
91  // ownership of the return value is not passed to the caller.
92  Product* AddProduct(scoped_ptr<Product>* product);
93
94  // Removes |product| from the set of products to be operated on.  The object
95  // pointed to by |product| is freed.  Returns false if |product| is not
96  // present in the set.
97  bool RemoveProduct(const Product* product);
98
99  // The level (user or system) of this operation.
100  Level level() const { return level_; }
101
102  // The package type (single or multi) of this operation.
103  PackageType package_type() const { return package_type_; }
104
105  // An identifier of this operation.
106  Operation operation() const { return operation_; }
107
108  // A convenience method returning level() == SYSTEM_LEVEL.
109  // TODO(grt): Eradicate the bool in favor of the enum.
110  bool system_install() const;
111
112  // A convenience method returning package_type() == MULTI_PACKAGE.
113  // TODO(grt): Eradicate the bool in favor of the enum.
114  bool is_multi_install() const;
115
116  // A convenient method returning the presence of the
117  // --ensure-google-update-present switch.
118  bool ensure_google_update_present() const {
119    return ensure_google_update_present_;
120  }
121
122  // The full path to the place where the operand resides.
123  const base::FilePath& target_path() const { return target_path_; }
124
125  // True if the "msi" preference is set or if a product with the "msi" state
126  // flag is set is to be operated on.
127  bool is_msi() const { return msi_; }
128
129  // True if the --verbose-logging command-line flag is set or if the
130  // verbose_logging master preferences option is true.
131  bool verbose_logging() const { return verbose_logging_; }
132
133#if defined(OS_WIN)
134  HKEY root_key() const { return root_key_; }
135#endif
136
137  // The ClientState key by which we interact with Google Update.
138  const std::wstring& state_key() const { return state_key_; }
139
140  // Convenience method to return the type of the BrowserDistribution associated
141  // with the ClientState key we will be interacting with.
142  BrowserDistribution::Type state_type() const { return state_type_; }
143
144  // Returns the BrowserDistribution instance corresponding to the binaries for
145  // this run if we're operating on a multi-package product.
146  BrowserDistribution* multi_package_binaries_distribution() const {
147    DCHECK(package_type_ == MULTI_PACKAGE);
148    DCHECK(multi_package_distribution_ != NULL);
149    return multi_package_distribution_;
150  }
151
152  const Products& products() const { return products_.get(); }
153
154  // Returns the product of the desired type, or NULL if none found.
155  const Product* FindProduct(BrowserDistribution::Type distribution_type) const;
156
157  // Returns the currently installed version in |target_path|, or NULL if no
158  // products are installed.  Ownership is passed to the caller.
159  base::Version* GetCurrentVersion(
160      const InstallationState& machine_state) const;
161
162  // Returns the critical update version if all of the following are true:
163  // * --critical-update-version=CUV was specified on the command-line.
164  // * current_version == NULL or current_version < CUV.
165  // * new_version >= CUV.
166  // Otherwise, returns an invalid version.
167  base::Version DetermineCriticalVersion(
168      const base::Version* current_version,
169      const base::Version& new_version) const;
170
171  // Returns whether or not there is currently a Chrome Frame instance running.
172  // Note that there isn't a mechanism to lock Chrome Frame in place, so Chrome
173  // Frame may either exit or start up after this is called.
174  bool IsChromeFrameRunning(const InstallationState& machine_state) const;
175
176  // Returns true if any of the binaries from a multi-install Chrome Frame that
177  // has been migrated to single-install are still in use.
178  bool AreBinariesInUse(const InstallationState& machine_state) const;
179
180  // Returns the path to the installer under Chrome version folder
181  // (for example <target_path>\Google\Chrome\Application\<Version>\Installer)
182  base::FilePath GetInstallerDirectory(const base::Version& version) const;
183
184  // Try to delete all directories under |temp_path| whose versions are less
185  // than |new_version| and not equal to |existing_version|. |existing_version|
186  // may be NULL.
187  void RemoveOldVersionDirectories(const base::Version& new_version,
188                                   base::Version* existing_version,
189                                   const base::FilePath& temp_path) const;
190
191  // Adds to |com_dll_list| the list of COM DLLs that are to be registered
192  // and/or unregistered. The list may be empty.
193  void AddComDllList(std::vector<base::FilePath>* com_dll_list) const;
194
195  bool SetChannelFlags(bool set, ChannelInfo* channel_info) const;
196
197  // See InstallUtil::UpdateInstallerStage.
198  void UpdateStage(installer::InstallerStage stage) const;
199
200  // For a MULTI_INSTALL or MULTI_UPDATE operation, updates the Google Update
201  // "ap" values for all products being operated on.
202  void UpdateChannels() const;
203
204  // Sets installer result information in the registry for consumption by Google
205  // Update.  The InstallerResult value is set to 0 (SUCCESS) or 1
206  // (FAILED_CUSTOM_ERROR) depending on whether |status| maps to success or not.
207  // |status| itself is written to the InstallerError value.
208  // |string_resource_id|, if non-zero, identifies a localized string written to
209  // the InstallerResultUIString value.  |launch_cmd|, if non-NULL and
210  // non-empty, is written to the InstallerSuccessLaunchCmdLine value.
211  void WriteInstallerResult(InstallStatus status,
212                            int string_resource_id,
213                            const std::wstring* launch_cmd) const;
214
215  // Returns true if this install needs to register an Active Setup command.
216  bool RequiresActiveSetup() const;
217
218 protected:
219  // Bits for the |file_bits| argument of AnyExistsAndIsInUse.
220  enum {
221    CHROME_DLL              = 1 << 0,
222    CHROME_FRAME_DLL        = 1 << 1,
223    CHROME_FRAME_HELPER_DLL = 1 << 2,
224    CHROME_FRAME_HELPER_EXE = 1 << 3,
225    NUM_BINARIES            = 4
226  };
227
228  // Returns true if |file| exists and cannot be opened for exclusive write
229  // access.
230  static bool IsFileInUse(const base::FilePath& file);
231
232  // Clears the instance to an uninitialized state.
233  void Clear();
234
235  // Returns true if any file corresponding to a bit in |file_bits| (from the
236  // enum above) for the currently installed version exists and is in use.
237  bool AnyExistsAndIsInUse(const InstallationState& machine_state,
238                           uint32 file_bits) const;
239  base::FilePath GetDefaultProductInstallPath(BrowserDistribution* dist) const;
240  bool CanAddProduct(const Product& product,
241                     const base::FilePath* product_dir) const;
242  Product* AddProductInDirectory(const base::FilePath* product_dir,
243                                 scoped_ptr<Product>* product);
244  Product* AddProductFromPreferences(
245      BrowserDistribution::Type distribution_type,
246      const MasterPreferences& prefs,
247      const InstallationState& machine_state);
248  bool IsMultiInstallUpdate(const MasterPreferences& prefs,
249                            const InstallationState& machine_state);
250
251  // Enumerates all files named one of
252  // [chrome.exe, old_chrome.exe, new_chrome.exe] in target_path_ and
253  // returns their version numbers in a set.
254  void GetExistingExeVersions(std::set<std::string>* existing_versions) const;
255
256  // Sets this object's level and updates the root_key_ accordingly.
257  void set_level(Level level);
258
259  // Sets this object's package type and updates the multi_package_distribution_
260  // accordingly.
261  void set_package_type(PackageType type);
262
263  Operation operation_;
264  base::FilePath target_path_;
265  std::wstring state_key_;
266  BrowserDistribution::Type state_type_;
267  ScopedVector<Product> products_;
268  BrowserDistribution* multi_package_distribution_;
269  base::Version critical_update_version_;
270  Level level_;
271  PackageType package_type_;
272#if defined(OS_WIN)
273  HKEY root_key_;
274#endif
275  bool msi_;
276  bool verbose_logging_;
277  bool ensure_google_update_present_;
278
279 private:
280  DISALLOW_COPY_AND_ASSIGN(InstallerState);
281};  // class InstallerState
282
283}  // namespace installer
284
285#endif  // CHROME_INSTALLER_UTIL_INSTALLER_STATE_H_
286