blob: 0a5fed1b3de43d78e20a3010cf82e807869ba0e7 [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]85286b52010-07-03 06:14:458#include "base/file_util.h"
[email protected]4512f3ac2009-11-04 03:39:229#include "chrome/app/breakpad_win.h"
10#include "chrome/app/client_util.h"
[email protected]103607e2010-02-01 18:57:0911#include "chrome/common/chrome_switches.h"
[email protected]4512f3ac2009-11-04 03:39:2212#include "chrome/common/result_codes.h"
[email protected]74d1eec2009-11-04 22:18:5713#include "chrome/installer/util/browser_distribution.h"
[email protected]4512f3ac2009-11-04 03:39:2214#include "chrome/installer/util/install_util.h"
[email protected]2414e842008-11-07 01:27:5715#include "chrome/installer/util/google_update_constants.h"
[email protected]28c19692008-11-07 23:40:3816#include "chrome/installer/util/util_constants.h"
17
18namespace {
[email protected]4512f3ac2009-11-04 03:39:2219// The entry point signature of chrome.dll.
20typedef int (*DLL_MAIN)(HINSTANCE, sandbox::SandboxInterfaceInfo*, wchar_t*);
[email protected]28c19692008-11-07 23:40:3821
[email protected]3cdacd42010-04-30 18:55:5322typedef void (*RelaunchChromeBrowserWithNewCommandLineIfNeededFunc)();
23
[email protected]4512f3ac2009-11-04 03:39:2224// Not generic, we only handle strings up to 128 chars.
25bool ReadRegistryStr(HKEY key, const wchar_t* name, std::wstring* value) {
26 BYTE out[128 * sizeof(wchar_t)];
27 DWORD size = sizeof(out);
28 DWORD type = 0;
29 if (ERROR_SUCCESS != ::RegQueryValueExW(key, name, NULL, &type, out, &size))
[email protected]28c19692008-11-07 23:40:3830 return false;
[email protected]4512f3ac2009-11-04 03:39:2231 if (type != REG_SZ)
32 return false;
33 value->assign(reinterpret_cast<wchar_t*>(out));
[email protected]28c19692008-11-07 23:40:3834 return true;
35}
[email protected]c9349d082008-08-22 21:16:4736
[email protected]4512f3ac2009-11-04 03:39:2237// Gets chrome version according to the load path. |exe_path| must be the
38// backslash terminated directory of the current chrome.exe.
39bool GetVersion(const wchar_t* exe_path, const wchar_t* key_path,
40 std::wstring* version) {
[email protected]48d43872008-11-04 23:38:3241 HKEY reg_root = InstallUtil::IsPerUserInstall(exe_path) ? HKEY_CURRENT_USER :
[email protected]28c19692008-11-07 23:40:3842 HKEY_LOCAL_MACHINE;
[email protected]4512f3ac2009-11-04 03:39:2243 HKEY key;
44 if (::RegOpenKeyEx(reg_root, key_path, 0, KEY_READ, &key) != ERROR_SUCCESS)
[email protected]c9349d082008-08-22 21:16:4745 return false;
[email protected]28c19692008-11-07 23:40:3846
[email protected]4512f3ac2009-11-04 03:39:2247 // If 'new_chrome.exe' is present it means chrome was auto-updated while
48 // running. We need to consult the opv value so we can load the old dll.
49 // TODO(cpu) : This is solving the same problem as the environment variable
50 // so one of them will eventually be deprecated.
[email protected]28c19692008-11-07 23:40:3851 std::wstring new_chrome_exe(exe_path);
52 new_chrome_exe.append(installer_util::kChromeNewExe);
[email protected]4512f3ac2009-11-04 03:39:2253 if (::PathFileExistsW(new_chrome_exe.c_str()) &&
54 ReadRegistryStr(key, google_update::kRegOldVersionField, version)) {
55 ::RegCloseKey(key);
[email protected]28c19692008-11-07 23:40:3856 return true;
[email protected]2414e842008-11-07 01:27:5757 }
58
[email protected]4512f3ac2009-11-04 03:39:2259 bool ret = ReadRegistryStr(key, google_update::kRegVersionField, version);
60 ::RegCloseKey(key);
[email protected]c9349d082008-08-22 21:16:4761 return ret;
62}
63
[email protected]4512f3ac2009-11-04 03:39:2264// Gets the path of the current exe with a trailing backslash.
[email protected]604004042009-10-21 23:10:2665std::wstring GetExecutablePath() {
[email protected]4512f3ac2009-11-04 03:39:2266 wchar_t path[MAX_PATH];
67 ::GetModuleFileNameW(NULL, path, MAX_PATH);
68 if (!::PathRemoveFileSpecW(path))
69 return std::wstring();
70 std::wstring exe_path(path);
71 return exe_path.append(L"\\");
[email protected]c9349d082008-08-22 21:16:4772}
73
[email protected]4512f3ac2009-11-04 03:39:2274// Not generic, we only handle strings up to 128 chars.
75bool EnvQueryStr(const wchar_t* key_name, std::wstring* value) {
76 wchar_t out[128];
77 DWORD count = sizeof(out)/sizeof(out[0]);
78 DWORD rv = ::GetEnvironmentVariableW(key_name, out, count);
79 if ((rv == 0) || (rv >= count))
80 return false;
81 *value = out;
82 return true;
83}
84
85// Expects that |dir| has a trailing backslash. |dir| is modified so it
86// contains the full path that was tried. Caller must check for the return
87// value not being null to dermine if this path contains a valid dll.
88HMODULE LoadChromeWithDirectory(std::wstring* dir) {
89 ::SetCurrentDirectoryW(dir->c_str());
[email protected]103607e2010-02-01 18:57:0990 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
[email protected]7b1bf812010-06-21 21:15:5391#ifdef _WIN64
[email protected]103607e2010-02-01 18:57:0992 if ((cmd_line.GetSwitchValueASCII(switches::kProcessType) ==
93 switches::kNaClBrokerProcess) ||
94 (cmd_line.GetSwitchValueASCII(switches::kProcessType) ==
95 switches::kNaClLoaderProcess)) {
96 // Load the 64-bit DLL when running in a 64-bit process.
97 dir->append(installer_util::kChromeNaCl64Dll);
98 } else {
99 // Only NaCl broker and loader can be launched as Win64 processes.
100 NOTREACHED();
101 return NULL;
102 }
103#else
[email protected]4512f3ac2009-11-04 03:39:22104 dir->append(installer_util::kChromeDll);
[email protected]103607e2010-02-01 18:57:09105#endif
[email protected]00b73412010-06-21 21:01:36106
[email protected]58ac0242010-07-09 18:31:15107#ifdef NDEBUG
[email protected]00b73412010-06-21 21:01:36108 // Experimental pre-reading optimization
109 // The idea is to pre read significant portion of chrome.dll in advance
110 // so that subsequent hard page faults are avoided.
[email protected]bdf411b2010-07-13 22:21:59111 if (!cmd_line.HasSwitch(switches::kProcessType)) {
[email protected]85286b52010-07-03 06:14:45112 // The kernel brings in 8 pages for the code section at a time and 4 pages
113 // for other sections. We can skip over these pages to avoid a soft page
114 // fault which may not occur during code execution. However skipping 4K at
115 // a time still has better performance over 32K and 16K according to data.
116 // TODO(ananta)
117 // Investigate this and tune.
118 const size_t kStepSize = 4 * 1024;
119
120 DWORD pre_read_size = 0;
121 DWORD pre_read_step_size = kStepSize;
122 DWORD pre_read = 1;
123
[email protected]00b73412010-06-21 21:01:36124 HKEY key = NULL;
125 if (::RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Google\\ChromeFrame",
126 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) {
[email protected]85286b52010-07-03 06:14:45127 DWORD unused = sizeof(pre_read_size);
128 RegQueryValueEx(key, L"PreReadSize", NULL, NULL,
129 reinterpret_cast<LPBYTE>(&pre_read_size), &unused);
130 RegQueryValueEx(key, L"PreReadStepSize", NULL, NULL,
131 reinterpret_cast<LPBYTE>(&pre_read_step_size), &unused);
132 RegQueryValueEx(key, L"PreRead", NULL, NULL,
133 reinterpret_cast<LPBYTE>(&pre_read), &unused);
[email protected]00b73412010-06-21 21:01:36134 RegCloseKey(key);
135 key = NULL;
[email protected]00b73412010-06-21 21:01:36136 }
[email protected]85286b52010-07-03 06:14:45137 if (pre_read) {
138 file_util::PreReadImage(dir->c_str(), pre_read_size, pre_read_step_size);
[email protected]00b73412010-06-21 21:01:36139 }
140 }
[email protected]58ac0242010-07-09 18:31:15141#endif // NDEBUG
[email protected]00b73412010-06-21 21:01:36142
[email protected]4512f3ac2009-11-04 03:39:22143 return ::LoadLibraryExW(dir->c_str(), NULL,
144 LOAD_WITH_ALTERED_SEARCH_PATH);
145}
146
[email protected]42d7510c2009-12-19 01:48:30147// Set did_run "dr" in omaha's client state for this product.
148bool SetDidRunState(const wchar_t* guid, const wchar_t* value) {
[email protected]4512f3ac2009-11-04 03:39:22149 std::wstring key_path(google_update::kRegPathClientState);
150 key_path.append(L"\\").append(guid);
151 HKEY reg_key;
152 if (::RegCreateKeyExW(HKEY_CURRENT_USER, key_path.c_str(), 0, NULL,
153 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
154 &reg_key, NULL) == ERROR_SUCCESS) {
[email protected]203c6872010-01-30 15:59:45155 // Note that the length here must be in bytes and must account for the
156 // terminating null char.
[email protected]4512f3ac2009-11-04 03:39:22157 ::RegSetValueExW(reg_key, google_update::kRegDidRunField, 0, REG_SZ,
[email protected]203c6872010-01-30 15:59:45158 reinterpret_cast<const BYTE *>(value),
159 (::lstrlenW(value) + 1) * sizeof(wchar_t));
[email protected]4512f3ac2009-11-04 03:39:22160 ::RegCloseKey(reg_key);
161 return true;
162 }
163 return false;
164}
[email protected]42d7510c2009-12-19 01:48:30165
166bool RecordDidRun(const wchar_t* guid) {
167 return SetDidRunState(guid, L"1");
[email protected]4512f3ac2009-11-04 03:39:22168}
169
[email protected]42d7510c2009-12-19 01:48:30170bool ClearDidRun(const wchar_t* guid) {
171 return SetDidRunState(guid, L"0");
172}
173
174}
[email protected]4512f3ac2009-11-04 03:39:22175//=============================================================================
176
177MainDllLoader::MainDllLoader() : dll_(NULL) {
178}
179
180MainDllLoader::~MainDllLoader() {
181#ifdef PURIFY
182 // We should never unload the dll. There is only risk and no gain from
183 // doing so. The singleton dtors have been already run by AtExitManager.
184 ::FreeLibrary(dll_);
185#endif
186}
187
188// Loading chrome is an interesting afair. First we try loading from the current
189// directory to support run-what-you-compile and other development scenarios.
190// If that fails then we look at the 'CHROME_VERSION' env variable to determine
191// if we should stick with an older dll version even if a new one is available
192// to support upgrade-in-place scenarios, and if that fails we finally we look
193// at the registry which should point us to the latest version.
194HMODULE MainDllLoader::Load(std::wstring* version, std::wstring* file) {
195 std::wstring dir(GetExecutablePath());
196 *file = dir;
197 HMODULE dll = LoadChromeWithDirectory(file);
198 if (dll)
199 return dll;
200
[email protected]9bfc86d2010-05-19 00:06:23201 if (!EnvQueryStr(
202 BrowserDistribution::GetDistribution()->GetEnvVersionKey().c_str(),
203 version)) {
[email protected]4512f3ac2009-11-04 03:39:22204 std::wstring reg_path(GetRegistryPath());
205 // Look into the registry to find the latest version.
206 if (!GetVersion(dir.c_str(), reg_path.c_str(), version))
207 return NULL;
208 }
209
210 *file = dir;
[email protected]f244388d2009-11-04 05:33:28211 file->append(*version).append(L"\\");
[email protected]4512f3ac2009-11-04 03:39:22212 return LoadChromeWithDirectory(file);
213}
214
215// Launching is a matter of loading the right dll, setting the CHROME_VERSION
216// environment variable and just calling the entry point. Derived classes can
217// add custom code in the OnBeforeLaunch callback.
218int MainDllLoader::Launch(HINSTANCE instance,
219 sandbox::SandboxInterfaceInfo* sbox_info) {
220 std::wstring version;
221 std::wstring file;
222 dll_ = Load(&version, &file);
223 if (!dll_)
224 return ResultCodes::MISSING_DATA;
225
[email protected]9bfc86d2010-05-19 00:06:23226 ::SetEnvironmentVariableW(
227 BrowserDistribution::GetDistribution()->GetEnvVersionKey().c_str(),
228 version.c_str());
[email protected]4512f3ac2009-11-04 03:39:22229
230 InitCrashReporterWithDllPath(file);
[email protected]4512f3ac2009-11-04 03:39:22231 OnBeforeLaunch(version);
232
233 DLL_MAIN entry_point =
234 reinterpret_cast<DLL_MAIN>(::GetProcAddress(dll_, "ChromeMain"));
235 if (!entry_point)
236 return ResultCodes::BAD_PROCESS_TYPE;
237
[email protected]42d7510c2009-12-19 01:48:30238 int rc = entry_point(instance, sbox_info, ::GetCommandLineW());
239 return OnBeforeExit(rc);
[email protected]4512f3ac2009-11-04 03:39:22240}
241
[email protected]3cdacd42010-04-30 18:55:53242void MainDllLoader::RelaunchChromeBrowserWithNewCommandLineIfNeeded() {
243 RelaunchChromeBrowserWithNewCommandLineIfNeededFunc relaunch_function =
244 reinterpret_cast<RelaunchChromeBrowserWithNewCommandLineIfNeededFunc>(
245 ::GetProcAddress(dll_,
246 "RelaunchChromeBrowserWithNewCommandLineIfNeeded"));
247 if (!relaunch_function) {
248 LOG(ERROR) << "Could not find exported function "
249 << "RelaunchChromeBrowserWithNewCommandLineIfNeeded";
250 } else {
251 relaunch_function();
252 }
253}
254
[email protected]4512f3ac2009-11-04 03:39:22255//=============================================================================
256
257class ChromeDllLoader : public MainDllLoader {
258 public:
259 virtual std::wstring GetRegistryPath() {
260 std::wstring key(google_update::kRegPathClients);
[email protected]5f2cee82009-11-05 04:59:48261 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
262 key.append(L"\\").append(dist->GetAppGuid());
[email protected]4512f3ac2009-11-04 03:39:22263 return key;
264 }
265
266 virtual void OnBeforeLaunch(const std::wstring& version) {
[email protected]5f2cee82009-11-05 04:59:48267 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
268 RecordDidRun(dist->GetAppGuid().c_str());
[email protected]4512f3ac2009-11-04 03:39:22269 }
[email protected]42d7510c2009-12-19 01:48:30270
271 virtual int OnBeforeExit(int return_code) {
272 // NORMAL_EXIT_CANCEL is used for experiments when the user cancels
273 // so we need to reset the did_run signal so omaha does not count
274 // this run as active usage.
275 if (ResultCodes::NORMAL_EXIT_CANCEL == return_code) {
276 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
277 ClearDidRun(dist->GetAppGuid().c_str());
278 }
279 return return_code;
280 }
[email protected]4512f3ac2009-11-04 03:39:22281};
282
283//=============================================================================
284
285class ChromiumDllLoader : public MainDllLoader {
286 public:
287 virtual std::wstring GetRegistryPath() {
[email protected]74d1eec2009-11-04 22:18:57288 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
289 return dist->GetVersionKey();
[email protected]4512f3ac2009-11-04 03:39:22290 }
291};
292
293MainDllLoader* MakeMainDllLoader() {
294#if defined(GOOGLE_CHROME_BUILD)
295 return new ChromeDllLoader();
296#else
297 return new ChromiumDllLoader();
298#endif
299}