google_update_util.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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/google_update_util.h"
6
7#include "base/command_line.h"
8#include "base/file_path.h"
9#include "base/file_util.h"
10#include "base/logging.h"
11#include "base/process_util.h"
12#include "base/string16.h"
13#include "base/time.h"
14#include "base/win/registry.h"
15#include "base/win/scoped_handle.h"
16#include "chrome/installer/launcher_support/chrome_launcher_support.h"
17#include "chrome/installer/util/google_update_constants.h"
18#include "chrome/installer/util/google_update_settings.h"
19
20using base::win::RegKey;
21
22namespace google_update {
23
24namespace {
25
26const int kGoogleUpdateTimeoutMs = 20 * 1000;
27
28// Returns true if Google Update is present at the given level.
29bool IsGoogleUpdatePresent(bool system_install) {
30  // Using the existence of version key in the registry to decide.
31  return GoogleUpdateSettings::GetGoogleUpdateVersion(system_install).IsValid();
32}
33
34// Returns GoogleUpdateSetup.exe's executable path at specified level.
35// or an empty path if none is found.
36FilePath GetGoogleUpdateSetupExe(bool system_install) {
37  const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
38  RegKey update_key;
39
40  if (update_key.Open(root_key, kRegPathGoogleUpdate, KEY_QUERY_VALUE) ==
41          ERROR_SUCCESS) {
42    string16 path_str;
43    string16 version_str;
44    if ((update_key.ReadValue(kRegPathField, &path_str) == ERROR_SUCCESS) &&
45        (update_key.ReadValue(kRegGoogleUpdateVersion, &version_str) ==
46             ERROR_SUCCESS)) {
47      return FilePath(path_str).DirName().Append(version_str).
48          Append(kGoogleUpdateSetupExe);
49    }
50  }
51  return FilePath();
52}
53
54// If Google Update is present at system-level, sets |cmd_string| to the command
55// line to install Google Update at user-level and returns true.
56// Otherwise, clears |cmd_string| and returns false.
57bool GetUserLevelGoogleUpdateInstallCommandLine(string16* cmd_string) {
58  cmd_string->clear();
59  FilePath google_update_setup(GetGoogleUpdateSetupExe(true));  // system-level.
60  if (!google_update_setup.empty()) {
61    CommandLine cmd(google_update_setup);
62    // Appends parameter "/install runtime=true&needsadmin=false /silent"
63    // Constants are found in code.google.com/p/omaha/common/const_cmd_line.h.
64    cmd.AppendArg("/install");
65    // The "&" can be used in base::LaunchProcess() without quotation
66    // (this is problematic only if run from command prompt).
67    cmd.AppendArg("runtime=true&needsadmin=false");
68    cmd.AppendArg("/silent");
69    *cmd_string = cmd.GetCommandLineString();
70  }
71  return !cmd_string->empty();
72}
73
74// Launches command |cmd_string|, and waits for |timeout| milliseconds before
75// timing out.  To wait indefinitely, one can set
76// |timeout| to be base::TimeDelta::FromMilliseconds(INFINITE).
77// Returns true if this executes successfully.
78// Returns false if command execution fails to execute, or times out.
79bool LaunchProcessAndWaitWithTimeout(const string16& cmd_string,
80                                     base::TimeDelta timeout) {
81  bool success = false;
82  base::win::ScopedHandle process;
83  int exit_code = 0;
84  LOG(INFO) << "Launching: " << cmd_string;
85  if (!base::LaunchProcess(cmd_string, base::LaunchOptions(),
86                           process.Receive())) {
87    PLOG(ERROR) << "Failed to launch (" << cmd_string << ")";
88  } else if (!base::WaitForExitCodeWithTimeout(process, &exit_code, timeout)) {
89    // The GetExitCodeProcess failed or timed-out.
90    LOG(ERROR) <<"Command (" << cmd_string << ") is taking more than "
91               << timeout.InMilliseconds() << " milliseconds to complete.";
92  } else if (exit_code != 0) {
93    LOG(ERROR) << "Command (" << cmd_string << ") exited with code "
94               << exit_code;
95  } else {
96    success = true;
97  }
98  return success;
99}
100
101}  // namespace
102
103bool EnsureUserLevelGoogleUpdatePresent() {
104  LOG(INFO) << "Ensuring Google Update is present at user-level.";
105
106  bool success = false;
107  if (IsGoogleUpdatePresent(false)) {
108    success = true;
109  } else {
110    string16 cmd_string;
111    if (!GetUserLevelGoogleUpdateInstallCommandLine(&cmd_string)) {
112      LOG(ERROR) << "Cannot find Google Update at system-level.";
113    } else {
114      success = LaunchProcessAndWaitWithTimeout(cmd_string,
115          base::TimeDelta::FromMilliseconds(INFINITE));
116    }
117  }
118  return success;
119}
120
121bool UninstallGoogleUpdate(bool system_install) {
122  bool success = false;
123  string16 cmd_string(
124      GoogleUpdateSettings::GetUninstallCommandLine(system_install));
125  if (cmd_string.empty()) {
126    success = true;  // Nothing to; vacuous success.
127  } else {
128    success = LaunchProcessAndWaitWithTimeout(cmd_string,
129        base::TimeDelta::FromMilliseconds(kGoogleUpdateTimeoutMs));
130  }
131  return success;
132}
133
134}  // namespace google_update
135