• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
GetClientStateValue(InstallationLevel level,const wchar_t * app_guid,const wchar_t * value_name,base::string16 * value)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.
GetSetupExeFromRegistry(InstallationLevel level,const wchar_t * app_guid)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.
GetSetupExeForInstallationLevel(InstallationLevel level)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.
FindExeRelativeToSetupExe(const base::FilePath setup_exe_path,const wchar_t * exe_file)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 
GetChromePathForInstallationLevel(InstallationLevel level)104 base::FilePath GetChromePathForInstallationLevel(InstallationLevel level) {
105   return FindExeRelativeToSetupExe(
106       GetSetupExeForInstallationLevel(level), kChromeExe);
107 }
108 
GetAnyChromePath()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