• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/launcher_support/chrome_launcher_support.h"
6 
7 #include <windows.h>
8 #include <tchar.h>
9 
10 #include "base/command_line.h"
11 #include "base/file_util.h"
12 #include "base/files/file_path.h"
13 #include "base/logging.h"
14 #include "base/process/launch.h"
15 #include "base/strings/string16.h"
16 #include "base/win/registry.h"
17 
18 #ifndef OFFICIAL_BUILD
19 #include "base/path_service.h"
20 #endif
21 
22 namespace chrome_launcher_support {
23 
24 namespace {
25 
26 // TODO(huangs) Refactor the constants: http://crbug.com/148538
27 const wchar_t kGoogleRegClientStateKey[] =
28     L"Software\\Google\\Update\\ClientState";
29 const wchar_t kGoogleRegClientsKey[] = L"Software\\Google\\Update\\Clients";
30 const wchar_t kRegVersionField[] = L"pv";
31 
32 // Copied from binaries_installer_internal.cc
33 const wchar_t kAppHostAppId[] = L"{FDA71E6F-AC4C-4a00-8B70-9958A68906BF}";
34 
35 // Copied from chrome_appid.cc.
36 const wchar_t kBinariesAppGuid[] = L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}";
37 
38 // Copied from google_chrome_distribution.cc.
39 const wchar_t kBrowserAppGuid[] = L"{8A69D345-D564-463c-AFF1-A69D9E530F96}";
40 
41 // Copied frome google_chrome_sxs_distribution.cc.
42 const wchar_t kSxSBrowserAppGuid[] = L"{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}";
43 
44 // Copied from util_constants.cc.
45 const wchar_t kChromeAppHostExe[] = L"app_host.exe";
46 const char kChromeAppLauncher[] = "app-launcher";
47 const wchar_t kChromeExe[] = L"chrome.exe";
48 const wchar_t kUninstallArgumentsField[] = L"UninstallArguments";
49 const wchar_t kUninstallStringField[] = L"UninstallString";
50 
51 // Reads a string value from the specified product's "ClientState" registry key.
52 // Returns true iff the value is present and successfully read.
GetClientStateValue(InstallationLevel level,const wchar_t * app_guid,const wchar_t * value_name,base::string16 * value)53 bool GetClientStateValue(InstallationLevel level,
54                          const wchar_t* app_guid,
55                          const wchar_t* value_name,
56                          base::string16* value) {
57   HKEY root_key = (level == USER_LEVEL_INSTALLATION) ?
58       HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
59   base::string16 subkey(kGoogleRegClientStateKey);
60   subkey.append(1, L'\\').append(app_guid);
61   base::win::RegKey reg_key;
62   // Google Update always uses 32bit hive.
63   if (reg_key.Open(root_key, subkey.c_str(),
64                    KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
65     if (reg_key.ReadValue(value_name, value) == ERROR_SUCCESS) {
66       return true;
67     }
68   }
69   return false;
70 }
71 
72 // Determines whether the specified product has a key in "Clients". This
73 // indicates whether the product is installed at the given level.
IsProductInstalled(InstallationLevel level,const wchar_t * app_guid)74 bool IsProductInstalled(InstallationLevel level, const wchar_t* app_guid) {
75   HKEY root_key = (level == USER_LEVEL_INSTALLATION) ?
76       HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
77   base::string16 subkey(kGoogleRegClientsKey);
78   subkey.append(1, L'\\').append(app_guid);
79   base::win::RegKey reg_key;
80   // Google Update always uses 32bit hive.
81   return reg_key.Open(root_key, subkey.c_str(),
82                       KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS &&
83       reg_key.HasValue(kRegVersionField);
84 }
85 
IsAppLauncherEnabledAtLevel(InstallationLevel level)86 bool IsAppLauncherEnabledAtLevel(InstallationLevel level) {
87   base::string16 uninstall_arguments;
88   if (GetClientStateValue(level,
89                           kAppHostAppId,
90                           kUninstallArgumentsField,
91                           &uninstall_arguments)) {
92     return CommandLine::FromString(L"dummy.exe " + uninstall_arguments)
93         .HasSwitch(kChromeAppLauncher) &&
94         !GetAppHostPathForInstallationLevel(level).empty();
95   }
96   return false;
97 }
98 
99 // Reads the path to setup.exe from the value "UninstallString" within the
100 // specified product's "ClientState" registry key. Returns an empty FilePath if
101 // an error occurs or the product is not installed at the specified level.
GetSetupExeFromRegistry(InstallationLevel level,const wchar_t * app_guid)102 base::FilePath GetSetupExeFromRegistry(InstallationLevel level,
103                                        const wchar_t* app_guid) {
104   base::string16 uninstall;
105   if (GetClientStateValue(level, app_guid, kUninstallStringField, &uninstall)) {
106     base::FilePath setup_exe_path(uninstall);
107     if (base::PathExists(setup_exe_path))
108       return setup_exe_path;
109   }
110   return base::FilePath();
111 }
112 
113 // Returns the path to an installed |exe_file| (e.g. chrome.exe, app_host.exe)
114 // at the specified level, given |setup_exe_path| from Omaha client state.
115 // Returns empty base::FilePath if none found, or if |setup_exe_path| is empty.
FindExeRelativeToSetupExe(const base::FilePath setup_exe_path,const wchar_t * exe_file)116 base::FilePath FindExeRelativeToSetupExe(const base::FilePath setup_exe_path,
117                                          const wchar_t* exe_file) {
118   if (!setup_exe_path.empty()) {
119     // The uninstall path contains the path to setup.exe, which is two levels
120     // down from |exe_file|. Move up two levels (plus one to drop the file
121     // name) and look for chrome.exe from there.
122     base::FilePath exe_path(
123         setup_exe_path.DirName().DirName().DirName().Append(exe_file));
124     if (base::PathExists(exe_path))
125       return exe_path;
126     // By way of mild future proofing, look up one to see if there's a
127     // |exe_file| in the version directory
128     exe_path = setup_exe_path.DirName().DirName().Append(exe_file);
129     if (base::PathExists(exe_path))
130       return exe_path;
131   }
132   return base::FilePath();
133 }
134 
135 }  // namespace
136 
UninstallLegacyAppLauncher(InstallationLevel level)137 void UninstallLegacyAppLauncher(InstallationLevel level) {
138   base::FilePath setup_exe(GetSetupExeFromRegistry(level, kAppHostAppId));
139   if (setup_exe.empty())
140     return;
141   base::string16 uninstall_arguments;
142   if (GetClientStateValue(level,
143                           kAppHostAppId,
144                           kUninstallArgumentsField,
145                           &uninstall_arguments)) {
146     CommandLine uninstall_cmd = CommandLine::FromString(
147         L"\"" + setup_exe.value() + L"\" " + uninstall_arguments);
148 
149     VLOG(1) << "Uninstalling legacy app launcher with command line: "
150             << uninstall_cmd.GetCommandLineString();
151     base::LaunchProcess(uninstall_cmd, base::LaunchOptions(), NULL);
152   }
153 }
154 
GetSetupExeForInstallationLevel(InstallationLevel level)155 base::FilePath GetSetupExeForInstallationLevel(InstallationLevel level) {
156   // Look in the registry for Chrome Binaries first.
157   base::FilePath setup_exe_path(
158       GetSetupExeFromRegistry(level, kBinariesAppGuid));
159   // If the above fails, look in the registry for Chrome next.
160   if (setup_exe_path.empty())
161     setup_exe_path = GetSetupExeFromRegistry(level, kBrowserAppGuid);
162   // If we fail again, then setup_exe_path would be empty.
163   return setup_exe_path;
164 }
165 
GetChromePathForInstallationLevel(InstallationLevel level)166 base::FilePath GetChromePathForInstallationLevel(InstallationLevel level) {
167   return FindExeRelativeToSetupExe(
168       GetSetupExeForInstallationLevel(level), kChromeExe);
169 }
170 
GetAppHostPathForInstallationLevel(InstallationLevel level)171 base::FilePath GetAppHostPathForInstallationLevel(InstallationLevel level) {
172   return FindExeRelativeToSetupExe(
173       GetSetupExeFromRegistry(level, kAppHostAppId), kChromeAppHostExe);
174 }
175 
GetChromeSxSPathForInstallationLevel(InstallationLevel level)176 base::FilePath GetChromeSxSPathForInstallationLevel(InstallationLevel level) {
177   return FindExeRelativeToSetupExe(
178       GetSetupExeFromRegistry(level, kSxSBrowserAppGuid), kChromeExe);
179 }
180 
GetAnyChromePath()181 base::FilePath GetAnyChromePath() {
182   base::FilePath chrome_path;
183   if (chrome_path.empty())
184     chrome_path = GetChromePathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION);
185   if (chrome_path.empty())
186     chrome_path = GetChromePathForInstallationLevel(USER_LEVEL_INSTALLATION);
187   return chrome_path;
188 }
189 
GetAnyAppHostPath()190 base::FilePath GetAnyAppHostPath() {
191   base::FilePath app_host_path;
192   if (app_host_path.empty()) {
193     app_host_path = GetAppHostPathForInstallationLevel(
194         SYSTEM_LEVEL_INSTALLATION);
195   }
196   if (app_host_path.empty())
197     app_host_path = GetAppHostPathForInstallationLevel(USER_LEVEL_INSTALLATION);
198   return app_host_path;
199 }
200 
GetAnyChromeSxSPath()201 base::FilePath GetAnyChromeSxSPath() {
202   base::FilePath path =
203       GetChromeSxSPathForInstallationLevel(USER_LEVEL_INSTALLATION);
204   if (path.empty())
205     path = GetChromeSxSPathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION);
206   return path;
207 }
208 
IsAppHostPresent()209 bool IsAppHostPresent() {
210   base::FilePath app_host_exe = GetAnyAppHostPath();
211   return !app_host_exe.empty();
212 }
213 
GetAppLauncherInstallationState()214 InstallationState GetAppLauncherInstallationState() {
215   if (IsAppLauncherEnabledAtLevel(SYSTEM_LEVEL_INSTALLATION))
216     return INSTALLED_AT_SYSTEM_LEVEL;
217 
218   if (IsAppLauncherEnabledAtLevel(USER_LEVEL_INSTALLATION))
219     return INSTALLED_AT_USER_LEVEL;
220 
221   return NOT_INSTALLED;
222 }
223 
IsAppLauncherPresent()224 bool IsAppLauncherPresent() {
225   return GetAppLauncherInstallationState() != NOT_INSTALLED;
226 }
227 
IsChromeBrowserPresent()228 bool IsChromeBrowserPresent() {
229   return IsProductInstalled(USER_LEVEL_INSTALLATION, kBrowserAppGuid) ||
230       IsProductInstalled(SYSTEM_LEVEL_INSTALLATION, kBrowserAppGuid);
231 }
232 
233 }  // namespace chrome_launcher_support
234