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 
      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