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