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.
5 #include "chrome/installer/launcher_support/chrome_launcher_support.h"
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"
18 #ifndef OFFICIAL_BUILD
19 #include "base/path_service.h"
22 namespace chrome_launcher_support
{
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";
32 // Copied from binaries_installer_internal.cc
33 const wchar_t kAppHostAppId
[] = L
"{FDA71E6F-AC4C-4a00-8B70-9958A68906BF}";
35 // Copied from chrome_appid.cc.
36 const wchar_t kBinariesAppGuid
[] = L
"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}";
38 // Copied from google_chrome_distribution.cc.
39 const wchar_t kBrowserAppGuid
[] = L
"{8A69D345-D564-463c-AFF1-A69D9E530F96}";
41 // Copied frome google_chrome_sxs_distribution.cc.
42 const wchar_t kSxSBrowserAppGuid
[] = L
"{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}";
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";
51 // Reads a string value from the specified product's "ClientState" registry key.
52 // Returns true iff the value is present and successfully read.
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
) {
72 // Determines whether the specified product has a key in "Clients". This
73 // indicates whether the product is installed at the given level.
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
);
86 bool IsAppLauncherEnabledAtLevel(InstallationLevel level
) {
87 base::string16 uninstall_arguments
;
88 if (GetClientStateValue(level
,
90 kUninstallArgumentsField
,
91 &uninstall_arguments
)) {
92 return CommandLine::FromString(L
"dummy.exe " + uninstall_arguments
)
93 .HasSwitch(kChromeAppLauncher
) &&
94 !GetAppHostPathForInstallationLevel(level
).empty();
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.
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
;
110 return base::FilePath();
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.
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
))
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
))
132 return base::FilePath();
137 void UninstallLegacyAppLauncher(InstallationLevel level
) {
138 base::FilePath
setup_exe(GetSetupExeFromRegistry(level
, kAppHostAppId
));
139 if (setup_exe
.empty())
141 base::string16 uninstall_arguments
;
142 if (GetClientStateValue(level
,
144 kUninstallArgumentsField
,
145 &uninstall_arguments
)) {
146 CommandLine uninstall_cmd
= CommandLine::FromString(
147 L
"\"" + setup_exe
.value() + L
"\" " + uninstall_arguments
);
149 VLOG(1) << "Uninstalling legacy app launcher with command line: "
150 << uninstall_cmd
.GetCommandLineString();
151 base::LaunchProcess(uninstall_cmd
, base::LaunchOptions(), NULL
);
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
;
166 base::FilePath
GetChromePathForInstallationLevel(InstallationLevel level
) {
167 return FindExeRelativeToSetupExe(
168 GetSetupExeForInstallationLevel(level
), kChromeExe
);
171 base::FilePath
GetAppHostPathForInstallationLevel(InstallationLevel level
) {
172 return FindExeRelativeToSetupExe(
173 GetSetupExeFromRegistry(level
, kAppHostAppId
), kChromeAppHostExe
);
176 base::FilePath
GetChromeSxSPathForInstallationLevel(InstallationLevel level
) {
177 return FindExeRelativeToSetupExe(
178 GetSetupExeFromRegistry(level
, kSxSBrowserAppGuid
), kChromeExe
);
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
);
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
);
196 if (app_host_path
.empty())
197 app_host_path
= GetAppHostPathForInstallationLevel(USER_LEVEL_INSTALLATION
);
198 return app_host_path
;
201 base::FilePath
GetAnyChromeSxSPath() {
202 base::FilePath path
=
203 GetChromeSxSPathForInstallationLevel(USER_LEVEL_INSTALLATION
);
205 path
= GetChromeSxSPathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION
);
209 bool IsAppHostPresent() {
210 base::FilePath app_host_exe
= GetAnyAppHostPath();
211 return !app_host_exe
.empty();
214 InstallationState
GetAppLauncherInstallationState() {
215 if (IsAppLauncherEnabledAtLevel(SYSTEM_LEVEL_INSTALLATION
))
216 return INSTALLED_AT_SYSTEM_LEVEL
;
218 if (IsAppLauncherEnabledAtLevel(USER_LEVEL_INSTALLATION
))
219 return INSTALLED_AT_USER_LEVEL
;
221 return NOT_INSTALLED
;
224 bool IsAppLauncherPresent() {
225 return GetAppLauncherInstallationState() != NOT_INSTALLED
;
228 bool IsChromeBrowserPresent() {
229 return IsProductInstalled(USER_LEVEL_INSTALLATION
, kBrowserAppGuid
) ||
230 IsProductInstalled(SYSTEM_LEVEL_INSTALLATION
, kBrowserAppGuid
);
233 } // namespace chrome_launcher_support