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 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" 13 14 namespace chrome_launcher_support { 15 16 namespace { 17 18 // TODO(huangs) Refactor the constants: http://crbug.com/148538 19 const wchar_t kGoogleRegClientStateKey[] = 20 L"Software\\Google\\Update\\ClientState"; 21 22 // Copied from chrome_appid.cc. 23 const wchar_t kBinariesAppGuid[] = L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}"; 24 25 // Copied from google_chrome_distribution.cc. 26 const wchar_t kBrowserAppGuid[] = L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; 27 28 // Copied from util_constants.cc. 29 const wchar_t kChromeExe[] = L"chrome.exe"; 30 const wchar_t kUninstallStringField[] = L"UninstallString"; 31 32 // Reads a string value from the specified product's "ClientState" registry key. 33 // Returns true iff the value is present and successfully read. 34 bool GetClientStateValue(InstallationLevel level, 35 const wchar_t* app_guid, 36 const wchar_t* value_name, 37 base::string16* value) { 38 HKEY root_key = (level == USER_LEVEL_INSTALLATION) ? 39 HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; 40 base::string16 subkey(kGoogleRegClientStateKey); 41 subkey.append(1, L'\\').append(app_guid); 42 base::win::RegKey reg_key; 43 // Google Update always uses 32bit hive. 44 if (reg_key.Open(root_key, subkey.c_str(), 45 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) { 46 if (reg_key.ReadValue(value_name, value) == ERROR_SUCCESS) { 47 return true; 48 } 49 } 50 return false; 51 } 52 53 // Reads the path to setup.exe from the value "UninstallString" within the 54 // specified product's "ClientState" registry key. Returns an empty FilePath if 55 // an error occurs or the product is not installed at the specified level. 56 base::FilePath GetSetupExeFromRegistry(InstallationLevel level, 57 const wchar_t* app_guid) { 58 base::string16 uninstall; 59 if (GetClientStateValue(level, app_guid, kUninstallStringField, &uninstall)) { 60 base::FilePath setup_exe_path(uninstall); 61 if (base::PathExists(setup_exe_path)) 62 return setup_exe_path; 63 } 64 return base::FilePath(); 65 } 66 67 // Returns the path to an existing setup.exe at the specified level, if it can 68 // be found via Omaha client state. 69 base::FilePath GetSetupExeForInstallationLevel(InstallationLevel level) { 70 // Look in the registry for Chrome Binaries first. 71 base::FilePath setup_exe_path( 72 GetSetupExeFromRegistry(level, kBinariesAppGuid)); 73 // If the above fails, look in the registry for Chrome next. 74 if (setup_exe_path.empty()) 75 setup_exe_path = GetSetupExeFromRegistry(level, kBrowserAppGuid); 76 // If we fail again, then setup_exe_path would be empty. 77 return setup_exe_path; 78 } 79 80 // Returns the path to an installed |exe_file| (e.g. chrome.exe) at the 81 // specified level, given |setup_exe_path| from Omaha client state. Returns 82 // empty base::FilePath if none found, or if |setup_exe_path| is empty. 83 base::FilePath FindExeRelativeToSetupExe(const base::FilePath setup_exe_path, 84 const wchar_t* exe_file) { 85 if (!setup_exe_path.empty()) { 86 // The uninstall path contains the path to setup.exe, which is two levels 87 // down from |exe_file|. Move up two levels (plus one to drop the file 88 // name) and look for chrome.exe from there. 89 base::FilePath exe_path( 90 setup_exe_path.DirName().DirName().DirName().Append(exe_file)); 91 if (base::PathExists(exe_path)) 92 return exe_path; 93 // By way of mild future proofing, look up one to see if there's a 94 // |exe_file| in the version directory 95 exe_path = setup_exe_path.DirName().DirName().Append(exe_file); 96 if (base::PathExists(exe_path)) 97 return exe_path; 98 } 99 return base::FilePath(); 100 } 101 102 } // namespace 103 104 base::FilePath GetChromePathForInstallationLevel(InstallationLevel level) { 105 return FindExeRelativeToSetupExe( 106 GetSetupExeForInstallationLevel(level), kChromeExe); 107 } 108 109 base::FilePath GetAnyChromePath() { 110 base::FilePath chrome_path; 111 if (chrome_path.empty()) 112 chrome_path = GetChromePathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION); 113 if (chrome_path.empty()) 114 chrome_path = GetChromePathForInstallationLevel(USER_LEVEL_INSTALLATION); 115 return chrome_path; 116 } 117 118 } // namespace chrome_launcher_support 119