chrome_launcher_support.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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#include "base/file_path.h"
10#include "base/file_util.h"
11#include "base/logging.h"
12#include "base/string16.h"
13#include "base/win/registry.h"
14
15#ifndef OFFICIAL_BUILD
16#include "base/path_service.h"
17#endif
18
19namespace chrome_launcher_support {
20
21namespace {
22
23// TODO(huangs) Refactor the constants: http://crbug.com/148538
24const wchar_t kGoogleRegClientStateKey[] =
25    L"Software\\Google\\Update\\ClientState";
26
27// Copied from binaries_installer_internal.cc
28const wchar_t kAppHostAppId[] = L"{FDA71E6F-AC4C-4a00-8B70-9958A68906BF}";
29
30// Copied from chrome_appid.cc.
31const wchar_t kBinariesAppGuid[] = L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}";
32
33// Copied from google_chrome_distribution.cc.
34const wchar_t kBrowserAppGuid[] = L"{8A69D345-D564-463c-AFF1-A69D9E530F96}";
35
36// Copied from util_constants.cc.
37const wchar_t kChromeAppHostExe[] = L"app_host.exe";
38const wchar_t kChromeExe[] = L"chrome.exe";
39const wchar_t kUninstallStringField[] = L"UninstallString";
40
41#ifndef OFFICIAL_BUILD
42FilePath GetDevelopmentExe(const wchar_t* exe_file) {
43  FilePath current_directory;
44  if (PathService::Get(base::DIR_EXE, &current_directory)) {
45    FilePath chrome_exe_path(current_directory.Append(exe_file));
46    if (file_util::PathExists(chrome_exe_path))
47      return chrome_exe_path;
48  }
49  return FilePath();
50}
51#endif
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.
56FilePath GetSetupExeFromRegistry(InstallationLevel level,
57                                 const wchar_t* app_guid) {
58  HKEY root_key = (level == USER_LEVEL_INSTALLATION) ?
59      HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
60  string16 subkey(kGoogleRegClientStateKey);
61  subkey.append(1, L'\\').append(app_guid);
62  base::win::RegKey reg_key;
63  if (reg_key.Open(root_key, subkey.c_str(),
64                   KEY_QUERY_VALUE) == ERROR_SUCCESS) {
65    string16 uninstall;
66    if (reg_key.ReadValue(kUninstallStringField, &uninstall) == ERROR_SUCCESS) {
67      FilePath setup_exe_path(uninstall);
68      if (file_util::PathExists(setup_exe_path))
69        return setup_exe_path;
70    }
71  }
72  return FilePath();
73}
74
75// Returns the path to an installed |exe_file| (e.g. chrome.exe, app_host.exe)
76// at the specified level, given |setup_exe_path| from Omaha client state.
77// Returns empty FilePath if none found, or if |setup_exe_path| is empty.
78FilePath FindExeRelativeToSetupExe(const FilePath setup_exe_path,
79                                   const wchar_t* exe_file) {
80  if (!setup_exe_path.empty()) {
81    // The uninstall path contains the path to setup.exe, which is two levels
82    // down from |exe_file|. Move up two levels (plus one to drop the file
83    // name) and look for chrome.exe from there.
84    FilePath exe_path(
85        setup_exe_path.DirName().DirName().DirName().Append(exe_file));
86    if (file_util::PathExists(exe_path))
87      return exe_path;
88    // By way of mild future proofing, look up one to see if there's a
89    // |exe_file| in the version directory
90    exe_path = setup_exe_path.DirName().DirName().Append(exe_file);
91    if (file_util::PathExists(exe_path))
92      return exe_path;
93  }
94  return FilePath();
95}
96
97}  // namespace
98
99FilePath GetSetupExeForInstallationLevel(InstallationLevel level) {
100  // Look in the registry for Chrome Binaries first.
101  FilePath setup_exe_path(GetSetupExeFromRegistry(level, kBinariesAppGuid));
102  // If the above fails, look in the registry for Chrome next.
103  if (setup_exe_path.empty())
104    setup_exe_path = GetSetupExeFromRegistry(level, kBrowserAppGuid);
105  // If we fail again, then setup_exe_path would be empty.
106  return setup_exe_path;
107}
108
109FilePath GetChromePathForInstallationLevel(InstallationLevel level) {
110  return FindExeRelativeToSetupExe(
111      GetSetupExeForInstallationLevel(level), kChromeExe);
112}
113
114FilePath GetAppHostPathForInstallationLevel(InstallationLevel level) {
115  return FindExeRelativeToSetupExe(
116      GetSetupExeFromRegistry(level, kAppHostAppId), kChromeAppHostExe);
117}
118
119FilePath GetAnyChromePath() {
120  FilePath chrome_path;
121#ifndef OFFICIAL_BUILD
122  // For development mode, chrome.exe should be in same dir as the stub.
123  chrome_path = GetDevelopmentExe(kChromeExe);
124#endif
125  if (chrome_path.empty())
126    chrome_path = GetChromePathForInstallationLevel(SYSTEM_LEVEL_INSTALLATION);
127  if (chrome_path.empty())
128    chrome_path = GetChromePathForInstallationLevel(USER_LEVEL_INSTALLATION);
129  return chrome_path;
130}
131
132FilePath GetAnyAppHostPath() {
133  FilePath app_host_path;
134#ifndef OFFICIAL_BUILD
135  // For development mode, app_host.exe should be in same dir as chrome.exe.
136  app_host_path = GetDevelopmentExe(kChromeAppHostExe);
137#endif
138  if (app_host_path.empty()) {
139    app_host_path = GetAppHostPathForInstallationLevel(
140        SYSTEM_LEVEL_INSTALLATION);
141  }
142  if (app_host_path.empty())
143    app_host_path = GetAppHostPathForInstallationLevel(USER_LEVEL_INSTALLATION);
144  return app_host_path;
145}
146
147bool IsAppHostPresent() {
148  FilePath app_host_exe = GetAnyAppHostPath();
149  return !app_host_exe.empty();
150}
151
152}  // namespace chrome_launcher_support
153