Home | History | Annotate | Download | only in launcher_support
      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/process/launch.h"
     15 #include "base/strings/string16.h"
     16 #include "base/win/registry.h"
     17 
     18 #ifndef OFFICIAL_BUILD
     19 #include "base/path_service.h"
     20 #endif
     21 
     22 namespace chrome_launcher_support {
     23 
     24 namespace {
     25 
     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";
     31 
     32 // Copied from binaries_installer_internal.cc
     33 const wchar_t kAppHostAppId[] = L"{FDA71E6F-AC4C-4a00-8B70-9958A68906BF}";
     34 
     35 // Copied from chrome_appid.cc.
     36 const wchar_t kBinariesAppGuid[] = L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}";
     37 
     38 // Copied from google_chrome_distribution.cc.
     39 const wchar_t kBrowserAppGuid[] = L"{8A69D345-D564-463c-AFF1-A69D9E530F96}";
     40 
     41 // Copied frome google_chrome_sxs_distribution.cc.
     42 const wchar_t kSxSBrowserAppGuid[] = L"{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}";
     43 
     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";
     50 
     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;
     67     }
     68   }
     69   return false;
     70 }
     71 
     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);
     84 }
     85 
     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();
     95   }
     96   return false;
     97 }
     98 
     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;
    109   }
    110   return base::FilePath();
    111 }
    112 
    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;
    131   }
    132   return base::FilePath();
    133 }
    134 
    135 }  // namespace
    136 
    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);
    148 
    149     VLOG(1) << "Uninstalling legacy app launcher with command line: "
    150             << uninstall_cmd.GetCommandLineString();
    151     base::LaunchProcess(uninstall_cmd, base::LaunchOptions(), NULL);
    152   }
    153 }
    154 
    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;
    164 }
    165 
    166 base::FilePath GetChromePathForInstallationLevel(InstallationLevel level) {
    167   return FindExeRelativeToSetupExe(
    168       GetSetupExeForInstallationLevel(level), kChromeExe);
    169 }
    170 
    171 base::FilePath GetAppHostPathForInstallationLevel(InstallationLevel level) {
    172   return FindExeRelativeToSetupExe(
    173       GetSetupExeFromRegistry(level, kAppHostAppId), kChromeAppHostExe);
    174 }
    175 
    176 base::FilePath GetChromeSxSPathForInstallationLevel(InstallationLevel level) {
    177   return FindExeRelativeToSetupExe(
    178       GetSetupExeFromRegistry(level, kSxSBrowserAppGuid), kChromeExe);
    179 }
    180 
    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;
    188 }
    189 
    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);
    195   }
    196   if (app_host_path.empty())
    197     app_host_path = GetAppHostPathForInstallationLevel(USER_LEVEL_INSTALLATION);
    198   return app_host_path;
    199 }
    200 
    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;
    207 }
    208 
    209 bool IsAppHostPresent() {
    210   base::FilePath app_host_exe = GetAnyAppHostPath();
    211   return !app_host_exe.empty();
    212 }
    213 
    214 InstallationState GetAppLauncherInstallationState() {
    215   if (IsAppLauncherEnabledAtLevel(SYSTEM_LEVEL_INSTALLATION))
    216     return INSTALLED_AT_SYSTEM_LEVEL;
    217 
    218   if (IsAppLauncherEnabledAtLevel(USER_LEVEL_INSTALLATION))
    219     return INSTALLED_AT_USER_LEVEL;
    220 
    221   return NOT_INSTALLED;
    222 }
    223 
    224 bool IsAppLauncherPresent() {
    225   return GetAppLauncherInstallationState() != NOT_INSTALLED;
    226 }
    227 
    228 bool IsChromeBrowserPresent() {
    229   return IsProductInstalled(USER_LEVEL_INSTALLATION, kBrowserAppGuid) ||
    230       IsProductInstalled(SYSTEM_LEVEL_INSTALLATION, kBrowserAppGuid);
    231 }
    232 
    233 }  // namespace chrome_launcher_support
    234