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"
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/strings/string16.h"
12 #include "base/win/registry.h"
14 namespace chrome_launcher_support
{
18 // TODO(huangs) Refactor the constants: http://crbug.com/148538
19 #if defined(GOOGLE_CHROME_BUILD)
20 const wchar_t kInstallationRegKey
[] =
21 L
"Software\\Google\\Update\\ClientState";
23 // Copied from chrome_appid.cc.
24 const wchar_t kBinariesAppGuid
[] = L
"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}";
26 // Copied from google_chrome_distribution.cc.
27 const wchar_t kBrowserAppGuid
[] = L
"{8A69D345-D564-463c-AFF1-A69D9E530F96}";
29 // Copied frome google_chrome_sxs_distribution.cc.
30 const wchar_t kSxSBrowserAppGuid
[] = L
"{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}";
32 const wchar_t kInstallationRegKey
[] = L
"Software\\Chromium";
35 // Copied from util_constants.cc.
36 const wchar_t kChromeExe
[] = L
"chrome.exe";
37 const wchar_t kUninstallStringField
[] = L
"UninstallString";
39 // Reads a string value from the specified product's registry key. Returns true
40 // iff the value is present and successfully read.
41 bool GetClientStateValue(InstallationLevel level
,
42 const wchar_t* app_guid
,
43 const wchar_t* value_name
,
44 base::string16
* value
) {
45 HKEY root_key
= (level
== USER_LEVEL_INSTALLATION
) ?
46 HKEY_CURRENT_USER
: HKEY_LOCAL_MACHINE
;
47 base::string16
subkey(kInstallationRegKey
);
49 subkey
.append(1, L
'\\').append(app_guid
);
50 base::win::RegKey reg_key
;
51 // Google Update always uses 32bit hive.
52 if (reg_key
.Open(root_key
, subkey
.c_str(),
53 KEY_QUERY_VALUE
| KEY_WOW64_32KEY
) == ERROR_SUCCESS
) {
54 if (reg_key
.ReadValue(value_name
, value
) == ERROR_SUCCESS
) {
61 // Reads the path to setup.exe from the value "UninstallString" within the
62 // specified product's registry key. Returns an empty FilePath if an error
63 // occurs or the product is not installed at the specified level.
64 base::FilePath
GetSetupExeFromRegistry(InstallationLevel level
,
65 const wchar_t* app_guid
) {
66 base::string16 uninstall
;
67 if (GetClientStateValue(level
, app_guid
, kUninstallStringField
, &uninstall
)) {
68 base::FilePath
setup_exe_path(uninstall
);
69 if (base::PathExists(setup_exe_path
))
70 return setup_exe_path
;
72 return base::FilePath();
75 // Returns the path to an existing setup.exe at the specified level, if it can
76 // be found via the registry.
77 base::FilePath
GetSetupExeForInstallationLevel(InstallationLevel level
) {
78 base::FilePath setup_exe_path
;
79 #if defined(GOOGLE_CHROME_BUILD)
80 // Look in the registry for Chrome Binaries first.
81 setup_exe_path
= GetSetupExeFromRegistry(level
, kBinariesAppGuid
);
82 // If the above fails, look in the registry for Chrome next.
83 if (setup_exe_path
.empty())
84 setup_exe_path
= GetSetupExeFromRegistry(level
, kBrowserAppGuid
);
85 // If we fail again, then setup_exe_path would be empty.
87 // For Chromium, there are no GUIDs. Just look in the Chromium registry key.
88 setup_exe_path
= GetSetupExeFromRegistry(level
, nullptr);
91 return setup_exe_path
;
94 // Returns the path to an installed |exe_file| (e.g. chrome.exe) at the
95 // specified level, given |setup_exe_path| from the registry. Returns empty
96 // base::FilePath if none found, or if |setup_exe_path| is empty.
97 base::FilePath
FindExeRelativeToSetupExe(const base::FilePath setup_exe_path
,
98 const wchar_t* exe_file
) {
99 if (!setup_exe_path
.empty()) {
100 // The uninstall path contains the path to setup.exe, which is two levels
101 // down from |exe_file|. Move up two levels (plus one to drop the file
102 // name) and look for chrome.exe from there.
103 base::FilePath
exe_path(
104 setup_exe_path
.DirName().DirName().DirName().Append(exe_file
));
105 if (base::PathExists(exe_path
))
107 // By way of mild future proofing, look up one to see if there's a
108 // |exe_file| in the version directory
109 exe_path
= setup_exe_path
.DirName().DirName().Append(exe_file
);
110 if (base::PathExists(exe_path
))
113 return base::FilePath();
116 // Returns the path to an installed SxS chrome.exe at the specified level, if
117 // it can be found via the registry.
118 base::FilePath
GetChromeSxSPathForInstallationLevel(InstallationLevel level
) {
119 #if defined(GOOGLE_CHROME_BUILD)
120 return FindExeRelativeToSetupExe(
121 GetSetupExeFromRegistry(level
, kSxSBrowserAppGuid
), kChromeExe
);
123 // There is no SxS build for Chromium.
124 return base::FilePath();
130 base::FilePath
GetChromePathForInstallationLevel(InstallationLevel level
) {
131 return FindExeRelativeToSetupExe(
132 GetSetupExeForInstallationLevel(level
), kChromeExe
);
135 base::FilePath
GetAnyChromePath() {
136 base::FilePath chrome_path
;
137 if (chrome_path
.empty())
138 chrome_path
= GetChromePathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION
);
139 if (chrome_path
.empty())
140 chrome_path
= GetChromePathForInstallationLevel(USER_LEVEL_INSTALLATION
);
144 base::FilePath
GetAnyChromeSxSPath() {
145 base::FilePath path
=
146 GetChromeSxSPathForInstallationLevel(USER_LEVEL_INSTALLATION
);
148 path
= GetChromeSxSPathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION
);
152 } // namespace chrome_launcher_support