Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / installer / util / google_update_util.cc
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/files/file_path.h"
9 #include "base/files/file_util.h"
10 #include "base/logging.h"
11 #include "base/path_service.h"
12 #include "base/process/kill.h"
13 #include "base/process/launch.h"
14 #include "base/strings/string16.h"
15 #include "base/time/time.h"
16 #include "base/win/registry.h"
17 #include "base/win/scoped_handle.h"
18 #include "base/win/win_util.h"
19 #include "base/win/windows_version.h"
20 #include "chrome/installer/util/browser_distribution.h"
21 #include "chrome/installer/util/google_update_constants.h"
22 #include "chrome/installer/util/google_update_settings.h"
23 #include "chrome/installer/util/install_util.h"
24 #include "chrome/installer/util/installation_state.h"
25 #include "chrome/installer/util/product.h"
26
27 using base::win::RegKey;
28
29 namespace google_update {
30
31 namespace {
32
33 const int kGoogleUpdateTimeoutMs = 20 * 1000;
34
35 // Returns true if Google Update is present at the given level.
36 bool IsGoogleUpdatePresent(bool system_install) {
37   // Using the existence of version key in the registry to decide.
38   return GoogleUpdateSettings::GetGoogleUpdateVersion(system_install).IsValid();
39 }
40
41 // Returns GoogleUpdateSetup.exe's executable path at specified level.
42 // or an empty path if none is found.
43 base::FilePath GetGoogleUpdateSetupExe(bool system_install) {
44   const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
45   RegKey update_key;
46
47   if (update_key.Open(root_key, kRegPathGoogleUpdate, KEY_QUERY_VALUE) ==
48           ERROR_SUCCESS) {
49     base::string16 path_str;
50     base::string16 version_str;
51     if ((update_key.ReadValue(kRegPathField, &path_str) == ERROR_SUCCESS) &&
52         (update_key.ReadValue(kRegGoogleUpdateVersion, &version_str) ==
53              ERROR_SUCCESS)) {
54       return base::FilePath(path_str).DirName().Append(version_str).
55           Append(kGoogleUpdateSetupExe);
56     }
57   }
58   return base::FilePath();
59 }
60
61 // If Google Update is present at system-level, sets |cmd_string| to the command
62 // line to install Google Update at user-level and returns true.
63 // Otherwise, clears |cmd_string| and returns false.
64 bool GetUserLevelGoogleUpdateInstallCommandLine(base::string16* cmd_string) {
65   cmd_string->clear();
66   base::FilePath google_update_setup(
67       GetGoogleUpdateSetupExe(true));  // system-level.
68   if (!google_update_setup.empty()) {
69     CommandLine cmd(google_update_setup);
70     // Appends "/install runtime=true&needsadmin=false /silent /nomitag".
71     // NB: /nomitag needs to be at the end.
72     // Constants are found in code.google.com/p/omaha/common/const_cmd_line.h.
73     cmd.AppendArg("/install");
74     // The "&" can be used in base::LaunchProcess() without quotation
75     // (this is problematic only if run from command prompt).
76     cmd.AppendArg("runtime=true&needsadmin=false");
77     cmd.AppendArg("/silent");
78     cmd.AppendArg("/nomitag");
79     *cmd_string = cmd.GetCommandLineString();
80   }
81   return !cmd_string->empty();
82 }
83
84 // Launches command |cmd_string|, and waits for |timeout| milliseconds before
85 // timing out.  To wait indefinitely, one can set
86 // |timeout| to be base::TimeDelta::FromMilliseconds(INFINITE).
87 // Returns true if this executes successfully.
88 // Returns false if command execution fails to execute, or times out.
89 bool LaunchProcessAndWaitWithTimeout(const base::string16& cmd_string,
90                                      base::TimeDelta timeout) {
91   bool success = false;
92   base::win::ScopedHandle process;
93   int exit_code = 0;
94   VLOG(0) << "Launching: " << cmd_string;
95   if (!base::LaunchProcess(cmd_string, base::LaunchOptions(),
96                            &process)) {
97     PLOG(ERROR) << "Failed to launch (" << cmd_string << ")";
98   } else if (!base::WaitForExitCodeWithTimeout(process.Get(), &exit_code,
99                                                timeout)) {
100     // The GetExitCodeProcess failed or timed-out.
101     LOG(ERROR) <<"Command (" << cmd_string << ") is taking more than "
102                << timeout.InMilliseconds() << " milliseconds to complete.";
103   } else if (exit_code != 0) {
104     LOG(ERROR) << "Command (" << cmd_string << ") exited with code "
105                << exit_code;
106   } else {
107     success = true;
108   }
109   return success;
110 }
111
112 }  // namespace
113
114 bool EnsureUserLevelGoogleUpdatePresent() {
115   VLOG(0) << "Ensuring Google Update is present at user-level.";
116
117   bool success = false;
118   if (IsGoogleUpdatePresent(false)) {
119     success = true;
120   } else {
121     base::string16 cmd_string;
122     if (!GetUserLevelGoogleUpdateInstallCommandLine(&cmd_string)) {
123       LOG(ERROR) << "Cannot find Google Update at system-level.";
124       // Ideally we should return false. However, this case should not be
125       // encountered by regular users, and developers (who often installs
126       // Chrome without Google Update) may be unduly impeded by this case.
127       // Therefore we return true.
128       success = true;
129     } else {
130       success = LaunchProcessAndWaitWithTimeout(cmd_string,
131           base::TimeDelta::FromMilliseconds(INFINITE));
132     }
133   }
134   return success;
135 }
136
137 bool UninstallGoogleUpdate(bool system_install) {
138   bool success = false;
139   base::string16 cmd_string(
140       GoogleUpdateSettings::GetUninstallCommandLine(system_install));
141   if (cmd_string.empty()) {
142     success = true;  // Nothing to; vacuous success.
143   } else {
144     success = LaunchProcessAndWaitWithTimeout(cmd_string,
145         base::TimeDelta::FromMilliseconds(kGoogleUpdateTimeoutMs));
146   }
147   return success;
148 }
149
150 void ElevateIfNeededToReenableUpdates() {
151   base::FilePath chrome_exe;
152   if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
153     NOTREACHED();
154     return;
155   }
156   installer::ProductState product_state;
157   BrowserDistribution* dist = BrowserDistribution::GetDistribution();
158   const bool system_install = !InstallUtil::IsPerUserInstall(
159       chrome_exe.value().c_str());
160   if (!product_state.Initialize(system_install, dist))
161     return;
162   base::FilePath exe_path(product_state.GetSetupPath());
163   if (exe_path.empty() || !base::PathExists(exe_path)) {
164     LOG(ERROR) << "Could not find setup.exe to reenable updates.";
165     return;
166   }
167
168   CommandLine cmd(exe_path);
169   cmd.AppendSwitch(installer::switches::kReenableAutoupdates);
170   installer::Product product(dist);
171   product.InitializeFromUninstallCommand(product_state.uninstall_command());
172   product.AppendProductFlags(&cmd);
173   if (system_install)
174     cmd.AppendSwitch(installer::switches::kSystemLevel);
175   if (product_state.uninstall_command().HasSwitch(
176           installer::switches::kVerboseLogging)) {
177     cmd.AppendSwitch(installer::switches::kVerboseLogging);
178   }
179
180   base::LaunchOptions launch_options;
181   launch_options.force_breakaway_from_job_ = true;
182
183   if (base::win::GetVersion() >= base::win::VERSION_VISTA &&
184       base::win::UserAccountControlIsEnabled()) {
185     base::LaunchElevatedProcess(cmd, launch_options, NULL);
186   } else {
187     base::LaunchProcess(cmd, launch_options, NULL);
188   }
189 }
190
191 }  // namespace google_update