Add a function to create a bookmark app from a WebApplicationInfo.
[chromium-blink-merge.git] / chrome / installer / launcher_support / chrome_launcher_support.cc
blobfdac65c6584d16e075ab45fde5671434282b83ae
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"
7 #include <windows.h>
8 #include <tchar.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"
20 #endif
22 namespace chrome_launcher_support {
24 namespace {
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) {
66 return true;
69 return false;
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,
89 kAppHostAppId,
90 kUninstallArgumentsField,
91 &uninstall_arguments)) {
92 return CommandLine::FromString(L"dummy.exe " + uninstall_arguments)
93 .HasSwitch(kChromeAppLauncher) &&
94 !GetAppHostPathForInstallationLevel(level).empty();
96 return false;
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))
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;
132 return base::FilePath();
135 } // namespace
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);
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);
187 return chrome_path;
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);
204 if (path.empty())
205 path = GetChromeSxSPathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION);
206 return path;
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