blob: c822ec8495a6d7293953f60c828adc4bf8eb3f75 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 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.
[email protected]c9349d082008-08-22 21:16:474
[email protected]4512f3ac2009-11-04 03:39:225#include <windows.h>
6#include <shlwapi.h>
[email protected]c9349d082008-08-22 21:16:477
[email protected]4512f3ac2009-11-04 03:39:228#include "chrome/app/breakpad_win.h"
9#include "chrome/app/client_util.h"
[email protected]103607e2010-02-01 18:57:0910#include "chrome/common/chrome_switches.h"
[email protected]4512f3ac2009-11-04 03:39:2211#include "chrome/common/result_codes.h"
[email protected]74d1eec2009-11-04 22:18:5712#include "chrome/installer/util/browser_distribution.h"
[email protected]4512f3ac2009-11-04 03:39:2213#include "chrome/installer/util/install_util.h"
[email protected]2414e842008-11-07 01:27:5714#include "chrome/installer/util/google_update_constants.h"
[email protected]28c19692008-11-07 23:40:3815#include "chrome/installer/util/util_constants.h"
16
17namespace {
[email protected]4512f3ac2009-11-04 03:39:2218// The entry point signature of chrome.dll.
19typedef int (*DLL_MAIN)(HINSTANCE, sandbox::SandboxInterfaceInfo*, wchar_t*);
[email protected]28c19692008-11-07 23:40:3820
[email protected]3cdacd42010-04-30 18:55:5321typedef void (*RelaunchChromeBrowserWithNewCommandLineIfNeededFunc)();
22
[email protected]4512f3ac2009-11-04 03:39:2223// Not generic, we only handle strings up to 128 chars.
24bool ReadRegistryStr(HKEY key, const wchar_t* name, std::wstring* value) {
25 BYTE out[128 * sizeof(wchar_t)];
26 DWORD size = sizeof(out);
27 DWORD type = 0;
28 if (ERROR_SUCCESS != ::RegQueryValueExW(key, name, NULL, &type, out, &size))
[email protected]28c19692008-11-07 23:40:3829 return false;
[email protected]4512f3ac2009-11-04 03:39:2230 if (type != REG_SZ)
31 return false;
32 value->assign(reinterpret_cast<wchar_t*>(out));
[email protected]28c19692008-11-07 23:40:3833 return true;
34}
[email protected]c9349d082008-08-22 21:16:4735
[email protected]4512f3ac2009-11-04 03:39:2236// Gets chrome version according to the load path. |exe_path| must be the
37// backslash terminated directory of the current chrome.exe.
38bool GetVersion(const wchar_t* exe_path, const wchar_t* key_path,
39 std::wstring* version) {
[email protected]48d43872008-11-04 23:38:3240 HKEY reg_root = InstallUtil::IsPerUserInstall(exe_path) ? HKEY_CURRENT_USER :
[email protected]28c19692008-11-07 23:40:3841 HKEY_LOCAL_MACHINE;
[email protected]4512f3ac2009-11-04 03:39:2242 HKEY key;
43 if (::RegOpenKeyEx(reg_root, key_path, 0, KEY_READ, &key) != ERROR_SUCCESS)
[email protected]c9349d082008-08-22 21:16:4744 return false;
[email protected]28c19692008-11-07 23:40:3845
[email protected]4512f3ac2009-11-04 03:39:2246 // If 'new_chrome.exe' is present it means chrome was auto-updated while
47 // running. We need to consult the opv value so we can load the old dll.
48 // TODO(cpu) : This is solving the same problem as the environment variable
49 // so one of them will eventually be deprecated.
[email protected]28c19692008-11-07 23:40:3850 std::wstring new_chrome_exe(exe_path);
51 new_chrome_exe.append(installer_util::kChromeNewExe);
[email protected]4512f3ac2009-11-04 03:39:2252 if (::PathFileExistsW(new_chrome_exe.c_str()) &&
53 ReadRegistryStr(key, google_update::kRegOldVersionField, version)) {
54 ::RegCloseKey(key);
[email protected]28c19692008-11-07 23:40:3855 return true;
[email protected]2414e842008-11-07 01:27:5756 }
57
[email protected]4512f3ac2009-11-04 03:39:2258 bool ret = ReadRegistryStr(key, google_update::kRegVersionField, version);
59 ::RegCloseKey(key);
[email protected]c9349d082008-08-22 21:16:4760 return ret;
61}
62
[email protected]4512f3ac2009-11-04 03:39:2263// Gets the path of the current exe with a trailing backslash.
[email protected]604004042009-10-21 23:10:2664std::wstring GetExecutablePath() {
[email protected]4512f3ac2009-11-04 03:39:2265 wchar_t path[MAX_PATH];
66 ::GetModuleFileNameW(NULL, path, MAX_PATH);
67 if (!::PathRemoveFileSpecW(path))
68 return std::wstring();
69 std::wstring exe_path(path);
70 return exe_path.append(L"\\");
[email protected]c9349d082008-08-22 21:16:4771}
72
[email protected]4512f3ac2009-11-04 03:39:2273// Not generic, we only handle strings up to 128 chars.
74bool EnvQueryStr(const wchar_t* key_name, std::wstring* value) {
75 wchar_t out[128];
76 DWORD count = sizeof(out)/sizeof(out[0]);
77 DWORD rv = ::GetEnvironmentVariableW(key_name, out, count);
78 if ((rv == 0) || (rv >= count))
79 return false;
80 *value = out;
81 return true;
82}
83
84// Expects that |dir| has a trailing backslash. |dir| is modified so it
85// contains the full path that was tried. Caller must check for the return
86// value not being null to dermine if this path contains a valid dll.
87HMODULE LoadChromeWithDirectory(std::wstring* dir) {
88 ::SetCurrentDirectoryW(dir->c_str());
[email protected]103607e2010-02-01 18:57:0989#ifdef _WIN64
90 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
91 if ((cmd_line.GetSwitchValueASCII(switches::kProcessType) ==
92 switches::kNaClBrokerProcess) ||
93 (cmd_line.GetSwitchValueASCII(switches::kProcessType) ==
94 switches::kNaClLoaderProcess)) {
95 // Load the 64-bit DLL when running in a 64-bit process.
96 dir->append(installer_util::kChromeNaCl64Dll);
97 } else {
98 // Only NaCl broker and loader can be launched as Win64 processes.
99 NOTREACHED();
100 return NULL;
101 }
102#else
[email protected]4512f3ac2009-11-04 03:39:22103 dir->append(installer_util::kChromeDll);
[email protected]103607e2010-02-01 18:57:09104#endif
[email protected]4512f3ac2009-11-04 03:39:22105 return ::LoadLibraryExW(dir->c_str(), NULL,
106 LOAD_WITH_ALTERED_SEARCH_PATH);
107}
108
[email protected]42d7510c2009-12-19 01:48:30109// Set did_run "dr" in omaha's client state for this product.
110bool SetDidRunState(const wchar_t* guid, const wchar_t* value) {
[email protected]4512f3ac2009-11-04 03:39:22111 std::wstring key_path(google_update::kRegPathClientState);
112 key_path.append(L"\\").append(guid);
113 HKEY reg_key;
114 if (::RegCreateKeyExW(HKEY_CURRENT_USER, key_path.c_str(), 0, NULL,
115 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
116 &reg_key, NULL) == ERROR_SUCCESS) {
[email protected]203c6872010-01-30 15:59:45117 // Note that the length here must be in bytes and must account for the
118 // terminating null char.
[email protected]4512f3ac2009-11-04 03:39:22119 ::RegSetValueExW(reg_key, google_update::kRegDidRunField, 0, REG_SZ,
[email protected]203c6872010-01-30 15:59:45120 reinterpret_cast<const BYTE *>(value),
121 (::lstrlenW(value) + 1) * sizeof(wchar_t));
[email protected]4512f3ac2009-11-04 03:39:22122 ::RegCloseKey(reg_key);
123 return true;
124 }
125 return false;
126}
[email protected]42d7510c2009-12-19 01:48:30127
128bool RecordDidRun(const wchar_t* guid) {
129 return SetDidRunState(guid, L"1");
[email protected]4512f3ac2009-11-04 03:39:22130}
131
[email protected]42d7510c2009-12-19 01:48:30132bool ClearDidRun(const wchar_t* guid) {
133 return SetDidRunState(guid, L"0");
134}
135
136}
[email protected]4512f3ac2009-11-04 03:39:22137//=============================================================================
138
139MainDllLoader::MainDllLoader() : dll_(NULL) {
140}
141
142MainDllLoader::~MainDllLoader() {
143#ifdef PURIFY
144 // We should never unload the dll. There is only risk and no gain from
145 // doing so. The singleton dtors have been already run by AtExitManager.
146 ::FreeLibrary(dll_);
147#endif
148}
149
150// Loading chrome is an interesting afair. First we try loading from the current
151// directory to support run-what-you-compile and other development scenarios.
152// If that fails then we look at the 'CHROME_VERSION' env variable to determine
153// if we should stick with an older dll version even if a new one is available
154// to support upgrade-in-place scenarios, and if that fails we finally we look
155// at the registry which should point us to the latest version.
156HMODULE MainDllLoader::Load(std::wstring* version, std::wstring* file) {
157 std::wstring dir(GetExecutablePath());
158 *file = dir;
159 HMODULE dll = LoadChromeWithDirectory(file);
160 if (dll)
161 return dll;
162
163 if (!EnvQueryStr(google_update::kEnvProductVersionKey, version)) {
164 std::wstring reg_path(GetRegistryPath());
165 // Look into the registry to find the latest version.
166 if (!GetVersion(dir.c_str(), reg_path.c_str(), version))
167 return NULL;
168 }
169
170 *file = dir;
[email protected]f244388d2009-11-04 05:33:28171 file->append(*version).append(L"\\");
[email protected]4512f3ac2009-11-04 03:39:22172 return LoadChromeWithDirectory(file);
173}
174
175// Launching is a matter of loading the right dll, setting the CHROME_VERSION
176// environment variable and just calling the entry point. Derived classes can
177// add custom code in the OnBeforeLaunch callback.
178int MainDllLoader::Launch(HINSTANCE instance,
179 sandbox::SandboxInterfaceInfo* sbox_info) {
180 std::wstring version;
181 std::wstring file;
182 dll_ = Load(&version, &file);
183 if (!dll_)
184 return ResultCodes::MISSING_DATA;
185
186 ::SetEnvironmentVariableW(google_update::kEnvProductVersionKey,
187 version.c_str());
188
189 InitCrashReporterWithDllPath(file);
[email protected]4512f3ac2009-11-04 03:39:22190 OnBeforeLaunch(version);
191
192 DLL_MAIN entry_point =
193 reinterpret_cast<DLL_MAIN>(::GetProcAddress(dll_, "ChromeMain"));
194 if (!entry_point)
195 return ResultCodes::BAD_PROCESS_TYPE;
196
[email protected]42d7510c2009-12-19 01:48:30197 int rc = entry_point(instance, sbox_info, ::GetCommandLineW());
198 return OnBeforeExit(rc);
[email protected]4512f3ac2009-11-04 03:39:22199}
200
[email protected]3cdacd42010-04-30 18:55:53201void MainDllLoader::RelaunchChromeBrowserWithNewCommandLineIfNeeded() {
202 RelaunchChromeBrowserWithNewCommandLineIfNeededFunc relaunch_function =
203 reinterpret_cast<RelaunchChromeBrowserWithNewCommandLineIfNeededFunc>(
204 ::GetProcAddress(dll_,
205 "RelaunchChromeBrowserWithNewCommandLineIfNeeded"));
206 if (!relaunch_function) {
207 LOG(ERROR) << "Could not find exported function "
208 << "RelaunchChromeBrowserWithNewCommandLineIfNeeded";
209 } else {
210 relaunch_function();
211 }
212}
213
[email protected]4512f3ac2009-11-04 03:39:22214//=============================================================================
215
216class ChromeDllLoader : public MainDllLoader {
217 public:
218 virtual std::wstring GetRegistryPath() {
219 std::wstring key(google_update::kRegPathClients);
[email protected]5f2cee82009-11-05 04:59:48220 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
221 key.append(L"\\").append(dist->GetAppGuid());
[email protected]4512f3ac2009-11-04 03:39:22222 return key;
223 }
224
225 virtual void OnBeforeLaunch(const std::wstring& version) {
[email protected]5f2cee82009-11-05 04:59:48226 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
227 RecordDidRun(dist->GetAppGuid().c_str());
[email protected]4512f3ac2009-11-04 03:39:22228 }
[email protected]42d7510c2009-12-19 01:48:30229
230 virtual int OnBeforeExit(int return_code) {
231 // NORMAL_EXIT_CANCEL is used for experiments when the user cancels
232 // so we need to reset the did_run signal so omaha does not count
233 // this run as active usage.
234 if (ResultCodes::NORMAL_EXIT_CANCEL == return_code) {
235 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
236 ClearDidRun(dist->GetAppGuid().c_str());
237 }
238 return return_code;
239 }
[email protected]4512f3ac2009-11-04 03:39:22240};
241
242//=============================================================================
243
244class ChromiumDllLoader : public MainDllLoader {
245 public:
246 virtual std::wstring GetRegistryPath() {
[email protected]74d1eec2009-11-04 22:18:57247 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
248 return dist->GetVersionKey();
[email protected]4512f3ac2009-11-04 03:39:22249 }
250};
251
252MainDllLoader* MakeMainDllLoader() {
253#if defined(GOOGLE_CHROME_BUILD)
254 return new ChromeDllLoader();
255#else
256 return new ChromiumDllLoader();
257#endif
258}