root/chrome/installer/launcher_support/chrome_launcher_support.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. GetClientStateValue
  2. IsProductInstalled
  3. IsAppLauncherEnabledAtLevel
  4. GetSetupExeFromRegistry
  5. FindExeRelativeToSetupExe
  6. UninstallLegacyAppLauncher
  7. GetSetupExeForInstallationLevel
  8. GetChromePathForInstallationLevel
  9. GetAppHostPathForInstallationLevel
  10. GetChromeSxSPathForInstallationLevel
  11. GetAnyChromePath
  12. GetAnyAppHostPath
  13. GetAnyChromeSxSPath
  14. IsAppHostPresent
  15. GetAppLauncherInstallationState
  16. IsAppLauncherPresent
  17. IsChromeBrowserPresent

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/installer/launcher_support/chrome_launcher_support.h"

#include <windows.h>
#include <tchar.h>

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/process/launch.h"
#include "base/strings/string16.h"
#include "base/win/registry.h"

#ifndef OFFICIAL_BUILD
#include "base/path_service.h"
#endif

namespace chrome_launcher_support {

namespace {

// TODO(huangs) Refactor the constants: http://crbug.com/148538
const wchar_t kGoogleRegClientStateKey[] =
    L"Software\\Google\\Update\\ClientState";
const wchar_t kGoogleRegClientsKey[] = L"Software\\Google\\Update\\Clients";
const wchar_t kRegVersionField[] = L"pv";

// Copied from binaries_installer_internal.cc
const wchar_t kAppHostAppId[] = L"{FDA71E6F-AC4C-4a00-8B70-9958A68906BF}";

// Copied from chrome_appid.cc.
const wchar_t kBinariesAppGuid[] = L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}";

// Copied from google_chrome_distribution.cc.
const wchar_t kBrowserAppGuid[] = L"{8A69D345-D564-463c-AFF1-A69D9E530F96}";

// Copied frome google_chrome_sxs_distribution.cc.
const wchar_t kSxSBrowserAppGuid[] = L"{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}";

// Copied from util_constants.cc.
const wchar_t kChromeAppHostExe[] = L"app_host.exe";
const char kChromeAppLauncher[] = "app-launcher";
const wchar_t kChromeExe[] = L"chrome.exe";
const wchar_t kUninstallArgumentsField[] = L"UninstallArguments";
const wchar_t kUninstallStringField[] = L"UninstallString";

// Reads a string value from the specified product's "ClientState" registry key.
// Returns true iff the value is present and successfully read.
bool GetClientStateValue(InstallationLevel level,
                         const wchar_t* app_guid,
                         const wchar_t* value_name,
                         base::string16* value) {
  HKEY root_key = (level == USER_LEVEL_INSTALLATION) ?
      HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
  base::string16 subkey(kGoogleRegClientStateKey);
  subkey.append(1, L'\\').append(app_guid);
  base::win::RegKey reg_key;
  // Google Update always uses 32bit hive.
  if (reg_key.Open(root_key, subkey.c_str(),
                   KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
    if (reg_key.ReadValue(value_name, value) == ERROR_SUCCESS) {
      return true;
    }
  }
  return false;
}

// Determines whether the specified product has a key in "Clients". This
// indicates whether the product is installed at the given level.
bool IsProductInstalled(InstallationLevel level, const wchar_t* app_guid) {
  HKEY root_key = (level == USER_LEVEL_INSTALLATION) ?
      HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
  base::string16 subkey(kGoogleRegClientsKey);
  subkey.append(1, L'\\').append(app_guid);
  base::win::RegKey reg_key;
  // Google Update always uses 32bit hive.
  return reg_key.Open(root_key, subkey.c_str(),
                      KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS &&
      reg_key.HasValue(kRegVersionField);
}

bool IsAppLauncherEnabledAtLevel(InstallationLevel level) {
  base::string16 uninstall_arguments;
  if (GetClientStateValue(level,
                          kAppHostAppId,
                          kUninstallArgumentsField,
                          &uninstall_arguments)) {
    return CommandLine::FromString(L"dummy.exe " + uninstall_arguments)
        .HasSwitch(kChromeAppLauncher) &&
        !GetAppHostPathForInstallationLevel(level).empty();
  }
  return false;
}

// Reads the path to setup.exe from the value "UninstallString" within the
// specified product's "ClientState" registry key. Returns an empty FilePath if
// an error occurs or the product is not installed at the specified level.
base::FilePath GetSetupExeFromRegistry(InstallationLevel level,
                                       const wchar_t* app_guid) {
  base::string16 uninstall;
  if (GetClientStateValue(level, app_guid, kUninstallStringField, &uninstall)) {
    base::FilePath setup_exe_path(uninstall);
    if (base::PathExists(setup_exe_path))
      return setup_exe_path;
  }
  return base::FilePath();
}

// Returns the path to an installed |exe_file| (e.g. chrome.exe, app_host.exe)
// at the specified level, given |setup_exe_path| from Omaha client state.
// Returns empty base::FilePath if none found, or if |setup_exe_path| is empty.
base::FilePath FindExeRelativeToSetupExe(const base::FilePath setup_exe_path,
                                         const wchar_t* exe_file) {
  if (!setup_exe_path.empty()) {
    // The uninstall path contains the path to setup.exe, which is two levels
    // down from |exe_file|. Move up two levels (plus one to drop the file
    // name) and look for chrome.exe from there.
    base::FilePath exe_path(
        setup_exe_path.DirName().DirName().DirName().Append(exe_file));
    if (base::PathExists(exe_path))
      return exe_path;
    // By way of mild future proofing, look up one to see if there's a
    // |exe_file| in the version directory
    exe_path = setup_exe_path.DirName().DirName().Append(exe_file);
    if (base::PathExists(exe_path))
      return exe_path;
  }
  return base::FilePath();
}

}  // namespace

void UninstallLegacyAppLauncher(InstallationLevel level) {
  base::FilePath setup_exe(GetSetupExeFromRegistry(level, kAppHostAppId));
  if (setup_exe.empty())
    return;
  base::string16 uninstall_arguments;
  if (GetClientStateValue(level,
                          kAppHostAppId,
                          kUninstallArgumentsField,
                          &uninstall_arguments)) {
    CommandLine uninstall_cmd = CommandLine::FromString(
        L"\"" + setup_exe.value() + L"\" " + uninstall_arguments);

    VLOG(1) << "Uninstalling legacy app launcher with command line: "
            << uninstall_cmd.GetCommandLineString();
    base::LaunchProcess(uninstall_cmd, base::LaunchOptions(), NULL);
  }
}

base::FilePath GetSetupExeForInstallationLevel(InstallationLevel level) {
  // Look in the registry for Chrome Binaries first.
  base::FilePath setup_exe_path(
      GetSetupExeFromRegistry(level, kBinariesAppGuid));
  // If the above fails, look in the registry for Chrome next.
  if (setup_exe_path.empty())
    setup_exe_path = GetSetupExeFromRegistry(level, kBrowserAppGuid);
  // If we fail again, then setup_exe_path would be empty.
  return setup_exe_path;
}

base::FilePath GetChromePathForInstallationLevel(InstallationLevel level) {
  return FindExeRelativeToSetupExe(
      GetSetupExeForInstallationLevel(level), kChromeExe);
}

base::FilePath GetAppHostPathForInstallationLevel(InstallationLevel level) {
  return FindExeRelativeToSetupExe(
      GetSetupExeFromRegistry(level, kAppHostAppId), kChromeAppHostExe);
}

base::FilePath GetChromeSxSPathForInstallationLevel(InstallationLevel level) {
  return FindExeRelativeToSetupExe(
      GetSetupExeFromRegistry(level, kSxSBrowserAppGuid), kChromeExe);
}

base::FilePath GetAnyChromePath() {
  base::FilePath chrome_path;
  if (chrome_path.empty())
    chrome_path = GetChromePathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION);
  if (chrome_path.empty())
    chrome_path = GetChromePathForInstallationLevel(USER_LEVEL_INSTALLATION);
  return chrome_path;
}

base::FilePath GetAnyAppHostPath() {
  base::FilePath app_host_path;
  if (app_host_path.empty()) {
    app_host_path = GetAppHostPathForInstallationLevel(
        SYSTEM_LEVEL_INSTALLATION);
  }
  if (app_host_path.empty())
    app_host_path = GetAppHostPathForInstallationLevel(USER_LEVEL_INSTALLATION);
  return app_host_path;
}

base::FilePath GetAnyChromeSxSPath() {
  base::FilePath path =
      GetChromeSxSPathForInstallationLevel(USER_LEVEL_INSTALLATION);
  if (path.empty())
    path = GetChromeSxSPathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION);
  return path;
}

bool IsAppHostPresent() {
  base::FilePath app_host_exe = GetAnyAppHostPath();
  return !app_host_exe.empty();
}

InstallationState GetAppLauncherInstallationState() {
  if (IsAppLauncherEnabledAtLevel(SYSTEM_LEVEL_INSTALLATION))
    return INSTALLED_AT_SYSTEM_LEVEL;

  if (IsAppLauncherEnabledAtLevel(USER_LEVEL_INSTALLATION))
    return INSTALLED_AT_USER_LEVEL;

  return NOT_INSTALLED;
}

bool IsAppLauncherPresent() {
  return GetAppLauncherInstallationState() != NOT_INSTALLED;
}

bool IsChromeBrowserPresent() {
  return IsProductInstalled(USER_LEVEL_INSTALLATION, kBrowserAppGuid) ||
      IsProductInstalled(SYSTEM_LEVEL_INSTALLATION, kBrowserAppGuid);
}

}  // namespace chrome_launcher_support

/* [<][>][^][v][top][bottom][index][help] */