blob: 1741cb615ebfbbafb691f6f450515e4ae2acf980 [file] [log] [blame]
[email protected]ae0f0772010-08-13 04:54:101// Copyright (c) 2010 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// 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]5d91c9e2010-07-28 17:25:288#include "base/command_line.h"
[email protected]58580352010-10-26 04:07:509#include "base/debug/trace_event.h"
[email protected]ae0f0772010-08-13 04:54:1010#include "base/environment.h"
[email protected]85286b52010-07-03 06:14:4511#include "base/file_util.h"
[email protected]ae0f0772010-08-13 04:54:1012#include "base/logging.h"
13#include "base/scoped_ptr.h"
14#include "base/utf_string_conversions.h"
[email protected]4512f3ac2009-11-04 03:39:2215#include "chrome/app/breakpad_win.h"
16#include "chrome/app/client_util.h"
[email protected]103607e2010-02-01 18:57:0917#include "chrome/common/chrome_switches.h"
[email protected]4512f3ac2009-11-04 03:39:2218#include "chrome/common/result_codes.h"
[email protected]74d1eec2009-11-04 22:18:5719#include "chrome/installer/util/browser_distribution.h"
[email protected]4512f3ac2009-11-04 03:39:2220#include "chrome/installer/util/install_util.h"
[email protected]2414e842008-11-07 01:27:5721#include "chrome/installer/util/google_update_constants.h"
[email protected]28c19692008-11-07 23:40:3822#include "chrome/installer/util/util_constants.h"
23
24namespace {
[email protected]4512f3ac2009-11-04 03:39:2225// The entry point signature of chrome.dll.
26typedef int (*DLL_MAIN)(HINSTANCE, sandbox::SandboxInterfaceInfo*, wchar_t*);
[email protected]28c19692008-11-07 23:40:3827
[email protected]3cdacd42010-04-30 18:55:5328typedef void (*RelaunchChromeBrowserWithNewCommandLineIfNeededFunc)();
29
[email protected]4512f3ac2009-11-04 03:39:2230// Not generic, we only handle strings up to 128 chars.
31bool ReadRegistryStr(HKEY key, const wchar_t* name, std::wstring* value) {
32 BYTE out[128 * sizeof(wchar_t)];
33 DWORD size = sizeof(out);
34 DWORD type = 0;
35 if (ERROR_SUCCESS != ::RegQueryValueExW(key, name, NULL, &type, out, &size))
[email protected]28c19692008-11-07 23:40:3836 return false;
[email protected]4512f3ac2009-11-04 03:39:2237 if (type != REG_SZ)
38 return false;
39 value->assign(reinterpret_cast<wchar_t*>(out));
[email protected]28c19692008-11-07 23:40:3840 return true;
41}
[email protected]c9349d082008-08-22 21:16:4742
[email protected]4512f3ac2009-11-04 03:39:2243// Gets chrome version according to the load path. |exe_path| must be the
44// backslash terminated directory of the current chrome.exe.
45bool GetVersion(const wchar_t* exe_path, const wchar_t* key_path,
46 std::wstring* version) {
[email protected]48d43872008-11-04 23:38:3247 HKEY reg_root = InstallUtil::IsPerUserInstall(exe_path) ? HKEY_CURRENT_USER :
[email protected]28c19692008-11-07 23:40:3848 HKEY_LOCAL_MACHINE;
[email protected]4512f3ac2009-11-04 03:39:2249 HKEY key;
50 if (::RegOpenKeyEx(reg_root, key_path, 0, KEY_READ, &key) != ERROR_SUCCESS)
[email protected]c9349d082008-08-22 21:16:4751 return false;
[email protected]28c19692008-11-07 23:40:3852
[email protected]4512f3ac2009-11-04 03:39:2253 // If 'new_chrome.exe' is present it means chrome was auto-updated while
54 // running. We need to consult the opv value so we can load the old dll.
55 // TODO(cpu) : This is solving the same problem as the environment variable
56 // so one of them will eventually be deprecated.
[email protected]28c19692008-11-07 23:40:3857 std::wstring new_chrome_exe(exe_path);
58 new_chrome_exe.append(installer_util::kChromeNewExe);
[email protected]4512f3ac2009-11-04 03:39:2259 if (::PathFileExistsW(new_chrome_exe.c_str()) &&
60 ReadRegistryStr(key, google_update::kRegOldVersionField, version)) {
61 ::RegCloseKey(key);
[email protected]28c19692008-11-07 23:40:3862 return true;
[email protected]2414e842008-11-07 01:27:5763 }
64
[email protected]4512f3ac2009-11-04 03:39:2265 bool ret = ReadRegistryStr(key, google_update::kRegVersionField, version);
66 ::RegCloseKey(key);
[email protected]c9349d082008-08-22 21:16:4767 return ret;
68}
69
[email protected]4512f3ac2009-11-04 03:39:2270// Gets the path of the current exe with a trailing backslash.
[email protected]604004042009-10-21 23:10:2671std::wstring GetExecutablePath() {
[email protected]4512f3ac2009-11-04 03:39:2272 wchar_t path[MAX_PATH];
73 ::GetModuleFileNameW(NULL, path, MAX_PATH);
74 if (!::PathRemoveFileSpecW(path))
75 return std::wstring();
76 std::wstring exe_path(path);
77 return exe_path.append(L"\\");
[email protected]c9349d082008-08-22 21:16:4778}
79
[email protected]bae4e382010-08-22 04:44:0580// Not generic, we only handle strings up to 128 chars.
81bool EnvQueryStr(const wchar_t* key_name, std::wstring* value) {
82 wchar_t out[128];
83 DWORD count = sizeof(out)/sizeof(out[0]);
84 DWORD rv = ::GetEnvironmentVariableW(key_name, out, count);
85 if ((rv == 0) || (rv >= count))
86 return false;
87 *value = out;
88 return true;
89}
90
[email protected]4512f3ac2009-11-04 03:39:2291// Expects that |dir| has a trailing backslash. |dir| is modified so it
92// contains the full path that was tried. Caller must check for the return
93// value not being null to dermine if this path contains a valid dll.
94HMODULE LoadChromeWithDirectory(std::wstring* dir) {
95 ::SetCurrentDirectoryW(dir->c_str());
[email protected]103607e2010-02-01 18:57:0996 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
[email protected]7b1bf812010-06-21 21:15:5397#ifdef _WIN64
[email protected]103607e2010-02-01 18:57:0998 if ((cmd_line.GetSwitchValueASCII(switches::kProcessType) ==
99 switches::kNaClBrokerProcess) ||
100 (cmd_line.GetSwitchValueASCII(switches::kProcessType) ==
101 switches::kNaClLoaderProcess)) {
102 // Load the 64-bit DLL when running in a 64-bit process.
103 dir->append(installer_util::kChromeNaCl64Dll);
104 } else {
105 // Only NaCl broker and loader can be launched as Win64 processes.
106 NOTREACHED();
107 return NULL;
108 }
109#else
[email protected]4512f3ac2009-11-04 03:39:22110 dir->append(installer_util::kChromeDll);
[email protected]103607e2010-02-01 18:57:09111#endif
[email protected]00b73412010-06-21 21:01:36112
[email protected]58ac0242010-07-09 18:31:15113#ifdef NDEBUG
[email protected]00b73412010-06-21 21:01:36114 // Experimental pre-reading optimization
115 // The idea is to pre read significant portion of chrome.dll in advance
116 // so that subsequent hard page faults are avoided.
[email protected]bdf411b2010-07-13 22:21:59117 if (!cmd_line.HasSwitch(switches::kProcessType)) {
[email protected]85286b52010-07-03 06:14:45118 // The kernel brings in 8 pages for the code section at a time and 4 pages
119 // for other sections. We can skip over these pages to avoid a soft page
120 // fault which may not occur during code execution. However skipping 4K at
121 // a time still has better performance over 32K and 16K according to data.
122 // TODO(ananta)
123 // Investigate this and tune.
124 const size_t kStepSize = 4 * 1024;
125
126 DWORD pre_read_size = 0;
127 DWORD pre_read_step_size = kStepSize;
128 DWORD pre_read = 1;
129
[email protected]00b73412010-06-21 21:01:36130 HKEY key = NULL;
131 if (::RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Google\\ChromeFrame",
132 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) {
[email protected]85286b52010-07-03 06:14:45133 DWORD unused = sizeof(pre_read_size);
134 RegQueryValueEx(key, L"PreReadSize", NULL, NULL,
135 reinterpret_cast<LPBYTE>(&pre_read_size), &unused);
136 RegQueryValueEx(key, L"PreReadStepSize", NULL, NULL,
137 reinterpret_cast<LPBYTE>(&pre_read_step_size), &unused);
138 RegQueryValueEx(key, L"PreRead", NULL, NULL,
139 reinterpret_cast<LPBYTE>(&pre_read), &unused);
[email protected]00b73412010-06-21 21:01:36140 RegCloseKey(key);
141 key = NULL;
[email protected]00b73412010-06-21 21:01:36142 }
[email protected]85286b52010-07-03 06:14:45143 if (pre_read) {
[email protected]eb64b402010-08-12 01:37:35144 TRACE_EVENT_BEGIN("PreReadImage", 0, "");
[email protected]85286b52010-07-03 06:14:45145 file_util::PreReadImage(dir->c_str(), pre_read_size, pre_read_step_size);
[email protected]eb64b402010-08-12 01:37:35146 TRACE_EVENT_END("PreReadImage", 0, "");
[email protected]00b73412010-06-21 21:01:36147 }
148 }
[email protected]58ac0242010-07-09 18:31:15149#endif // NDEBUG
[email protected]00b73412010-06-21 21:01:36150
[email protected]4512f3ac2009-11-04 03:39:22151 return ::LoadLibraryExW(dir->c_str(), NULL,
152 LOAD_WITH_ALTERED_SEARCH_PATH);
153}
154
[email protected]42d7510c2009-12-19 01:48:30155// Set did_run "dr" in omaha's client state for this product.
156bool SetDidRunState(const wchar_t* guid, const wchar_t* value) {
[email protected]4512f3ac2009-11-04 03:39:22157 std::wstring key_path(google_update::kRegPathClientState);
158 key_path.append(L"\\").append(guid);
159 HKEY reg_key;
160 if (::RegCreateKeyExW(HKEY_CURRENT_USER, key_path.c_str(), 0, NULL,
161 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
162 &reg_key, NULL) == ERROR_SUCCESS) {
[email protected]203c6872010-01-30 15:59:45163 // Note that the length here must be in bytes and must account for the
164 // terminating null char.
[email protected]4512f3ac2009-11-04 03:39:22165 ::RegSetValueExW(reg_key, google_update::kRegDidRunField, 0, REG_SZ,
[email protected]203c6872010-01-30 15:59:45166 reinterpret_cast<const BYTE *>(value),
167 (::lstrlenW(value) + 1) * sizeof(wchar_t));
[email protected]4512f3ac2009-11-04 03:39:22168 ::RegCloseKey(reg_key);
169 return true;
170 }
171 return false;
172}
[email protected]42d7510c2009-12-19 01:48:30173
174bool RecordDidRun(const wchar_t* guid) {
175 return SetDidRunState(guid, L"1");
[email protected]4512f3ac2009-11-04 03:39:22176}
177
[email protected]42d7510c2009-12-19 01:48:30178bool ClearDidRun(const wchar_t* guid) {
179 return SetDidRunState(guid, L"0");
180}
181
182}
[email protected]4512f3ac2009-11-04 03:39:22183//=============================================================================
184
185MainDllLoader::MainDllLoader() : dll_(NULL) {
186}
187
188MainDllLoader::~MainDllLoader() {
189#ifdef PURIFY
190 // We should never unload the dll. There is only risk and no gain from
191 // doing so. The singleton dtors have been already run by AtExitManager.
192 ::FreeLibrary(dll_);
193#endif
194}
195
196// Loading chrome is an interesting afair. First we try loading from the current
197// directory to support run-what-you-compile and other development scenarios.
198// If that fails then we look at the 'CHROME_VERSION' env variable to determine
199// if we should stick with an older dll version even if a new one is available
200// to support upgrade-in-place scenarios, and if that fails we finally we look
201// at the registry which should point us to the latest version.
202HMODULE MainDllLoader::Load(std::wstring* version, std::wstring* file) {
203 std::wstring dir(GetExecutablePath());
204 *file = dir;
205 HMODULE dll = LoadChromeWithDirectory(file);
206 if (dll)
207 return dll;
208
[email protected]bae4e382010-08-22 04:44:05209 if (!EnvQueryStr(
210 BrowserDistribution::GetDistribution()->GetEnvVersionKey().c_str(),
211 version)) {
[email protected]4512f3ac2009-11-04 03:39:22212 std::wstring reg_path(GetRegistryPath());
213 // Look into the registry to find the latest version.
214 if (!GetVersion(dir.c_str(), reg_path.c_str(), version))
215 return NULL;
216 }
217
218 *file = dir;
[email protected]f244388d2009-11-04 05:33:28219 file->append(*version).append(L"\\");
[email protected]4512f3ac2009-11-04 03:39:22220 return LoadChromeWithDirectory(file);
221}
222
223// Launching is a matter of loading the right dll, setting the CHROME_VERSION
224// environment variable and just calling the entry point. Derived classes can
225// add custom code in the OnBeforeLaunch callback.
226int MainDllLoader::Launch(HINSTANCE instance,
227 sandbox::SandboxInterfaceInfo* sbox_info) {
228 std::wstring version;
229 std::wstring file;
230 dll_ = Load(&version, &file);
231 if (!dll_)
232 return ResultCodes::MISSING_DATA;
233
[email protected]ae0f0772010-08-13 04:54:10234 scoped_ptr<base::Environment> env(base::Environment::Create());
235 env->SetVar(WideToUTF8(
236 BrowserDistribution::GetDistribution()->GetEnvVersionKey()).c_str(),
237 WideToUTF8(version));
[email protected]4512f3ac2009-11-04 03:39:22238
239 InitCrashReporterWithDllPath(file);
[email protected]4512f3ac2009-11-04 03:39:22240 OnBeforeLaunch(version);
241
242 DLL_MAIN entry_point =
243 reinterpret_cast<DLL_MAIN>(::GetProcAddress(dll_, "ChromeMain"));
244 if (!entry_point)
245 return ResultCodes::BAD_PROCESS_TYPE;
246
[email protected]42d7510c2009-12-19 01:48:30247 int rc = entry_point(instance, sbox_info, ::GetCommandLineW());
248 return OnBeforeExit(rc);
[email protected]4512f3ac2009-11-04 03:39:22249}
250
[email protected]3cdacd42010-04-30 18:55:53251void MainDllLoader::RelaunchChromeBrowserWithNewCommandLineIfNeeded() {
252 RelaunchChromeBrowserWithNewCommandLineIfNeededFunc relaunch_function =
253 reinterpret_cast<RelaunchChromeBrowserWithNewCommandLineIfNeededFunc>(
254 ::GetProcAddress(dll_,
255 "RelaunchChromeBrowserWithNewCommandLineIfNeeded"));
256 if (!relaunch_function) {
257 LOG(ERROR) << "Could not find exported function "
258 << "RelaunchChromeBrowserWithNewCommandLineIfNeeded";
259 } else {
260 relaunch_function();
261 }
262}
263
[email protected]4512f3ac2009-11-04 03:39:22264//=============================================================================
265
266class ChromeDllLoader : public MainDllLoader {
267 public:
268 virtual std::wstring GetRegistryPath() {
269 std::wstring key(google_update::kRegPathClients);
[email protected]5f2cee82009-11-05 04:59:48270 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
271 key.append(L"\\").append(dist->GetAppGuid());
[email protected]4512f3ac2009-11-04 03:39:22272 return key;
273 }
274
275 virtual void OnBeforeLaunch(const std::wstring& version) {
[email protected]5f2cee82009-11-05 04:59:48276 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
277 RecordDidRun(dist->GetAppGuid().c_str());
[email protected]4512f3ac2009-11-04 03:39:22278 }
[email protected]42d7510c2009-12-19 01:48:30279
280 virtual int OnBeforeExit(int return_code) {
281 // NORMAL_EXIT_CANCEL is used for experiments when the user cancels
282 // so we need to reset the did_run signal so omaha does not count
283 // this run as active usage.
284 if (ResultCodes::NORMAL_EXIT_CANCEL == return_code) {
285 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
286 ClearDidRun(dist->GetAppGuid().c_str());
287 }
288 return return_code;
289 }
[email protected]4512f3ac2009-11-04 03:39:22290};
291
292//=============================================================================
293
294class ChromiumDllLoader : public MainDllLoader {
295 public:
296 virtual std::wstring GetRegistryPath() {
[email protected]74d1eec2009-11-04 22:18:57297 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
298 return dist->GetVersionKey();
[email protected]4512f3ac2009-11-04 03:39:22299 }
300};
301
302MainDllLoader* MakeMainDllLoader() {
303#if defined(GOOGLE_CHROME_BUILD)
304 return new ChromeDllLoader();
305#else
306 return new ChromiumDllLoader();
307#endif
308}