blob: d5b6ea37fc11ec73f76f7fb41936c315dff89d1b [file] [log] [blame]
[email protected]a21d8082012-01-12 19:23:201// Copyright (c) 2012 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"
[email protected]3b63f8f42011-03-28 01:54:1513#include "base/memory/scoped_ptr.h"
[email protected]28f576f2011-08-26 20:46:5514#include "base/rand_util.h" // For PreRead experiment.
[email protected]5bca9ee2011-09-03 00:18:4215#include "base/sha1.h" // For PreRead experiment.
[email protected]36ee0322010-12-23 21:27:1216#include "base/string_util.h"
[email protected]48078e52012-02-09 00:02:2617#include "base/stringprintf.h"
[email protected]ae0f0772010-08-13 04:54:1018#include "base/utf_string_conversions.h"
[email protected]85769352010-11-16 14:24:3019#include "base/version.h"
[email protected]85acecb2011-08-05 05:28:0520#include "base/win/registry.h"
[email protected]4512f3ac2009-11-04 03:39:2221#include "chrome/app/breakpad_win.h"
22#include "chrome/app/client_util.h"
[email protected]6bb2628d2012-02-03 19:55:1123#include "chrome/app/image_pre_reader_win.h"
[email protected]03d21b82010-12-07 19:37:2224#include "chrome/common/chrome_constants.h"
[email protected]1fcfb202011-07-19 19:53:1425#include "chrome/common/chrome_result_codes.h"
[email protected]103607e2010-02-01 18:57:0926#include "chrome/common/chrome_switches.h"
[email protected]74d1eec2009-11-04 22:18:5727#include "chrome/installer/util/browser_distribution.h"
[email protected]2544a7a2011-03-14 18:25:1928#include "chrome/installer/util/channel_info.h"
[email protected]4512f3ac2009-11-04 03:39:2229#include "chrome/installer/util/install_util.h"
[email protected]2414e842008-11-07 01:27:5730#include "chrome/installer/util/google_update_constants.h"
[email protected]fd59f822011-05-12 18:07:1831#include "chrome/installer/util/google_update_settings.h"
[email protected]28c19692008-11-07 23:40:3832#include "chrome/installer/util/util_constants.h"
33
34namespace {
[email protected]4512f3ac2009-11-04 03:39:2235// The entry point signature of chrome.dll.
[email protected]d85d6702011-09-01 15:51:5336typedef int (*DLL_MAIN)(HINSTANCE, sandbox::SandboxInterfaceInfo*);
[email protected]28c19692008-11-07 23:40:3837
[email protected]3cdacd42010-04-30 18:55:5338typedef void (*RelaunchChromeBrowserWithNewCommandLineIfNeededFunc)();
39
[email protected]4512f3ac2009-11-04 03:39:2240// Gets chrome version according to the load path. |exe_path| must be the
41// backslash terminated directory of the current chrome.exe.
42bool GetVersion(const wchar_t* exe_path, const wchar_t* key_path,
43 std::wstring* version) {
[email protected]48d43872008-11-04 23:38:3244 HKEY reg_root = InstallUtil::IsPerUserInstall(exe_path) ? HKEY_CURRENT_USER :
[email protected]28c19692008-11-07 23:40:3845 HKEY_LOCAL_MACHINE;
[email protected]2544a7a2011-03-14 18:25:1946 bool success = false;
[email protected]28c19692008-11-07 23:40:3847
[email protected]2544a7a2011-03-14 18:25:1948 base::win::RegKey key(reg_root, key_path, KEY_QUERY_VALUE);
49 if (key.Valid()) {
50 // If 'new_chrome.exe' is present it means chrome was auto-updated while
51 // running. We need to consult the opv value so we can load the old dll.
52 // TODO(cpu) : This is solving the same problem as the environment variable
53 // so one of them will eventually be deprecated.
54 std::wstring new_chrome_exe(exe_path);
55 new_chrome_exe.append(installer::kChromeNewExe);
56 if (::PathFileExistsW(new_chrome_exe.c_str()) &&
57 key.ReadValue(google_update::kRegOldVersionField,
58 version) == ERROR_SUCCESS) {
59 success = true;
60 } else {
61 success = (key.ReadValue(google_update::kRegVersionField,
62 version) == ERROR_SUCCESS);
63 }
[email protected]2414e842008-11-07 01:27:5764 }
65
[email protected]2544a7a2011-03-14 18:25:1966 return success;
[email protected]c9349d082008-08-22 21:16:4767}
68
[email protected]4512f3ac2009-11-04 03:39:2269// Gets the path of the current exe with a trailing backslash.
[email protected]604004042009-10-21 23:10:2670std::wstring GetExecutablePath() {
[email protected]4512f3ac2009-11-04 03:39:2271 wchar_t path[MAX_PATH];
72 ::GetModuleFileNameW(NULL, path, MAX_PATH);
73 if (!::PathRemoveFileSpecW(path))
74 return std::wstring();
75 std::wstring exe_path(path);
76 return exe_path.append(L"\\");
[email protected]c9349d082008-08-22 21:16:4777}
78
[email protected]bae4e382010-08-22 04:44:0579// Not generic, we only handle strings up to 128 chars.
80bool EnvQueryStr(const wchar_t* key_name, std::wstring* value) {
81 wchar_t out[128];
82 DWORD count = sizeof(out)/sizeof(out[0]);
83 DWORD rv = ::GetEnvironmentVariableW(key_name, out, count);
84 if ((rv == 0) || (rv >= count))
85 return false;
86 *value = out;
87 return true;
88}
89
[email protected]28f576f2011-08-26 20:46:5590#if defined(OS_WIN)
[email protected]5bca9ee2011-09-03 00:18:4291#if defined(GOOGLE_CHROME_BUILD)
[email protected]28f576f2011-08-26 20:46:5592// These constants are used by the PreRead experiment.
93const wchar_t kPreReadRegistryValue[] = L"PreReadExperimentGroup";
94const int kPreReadExpiryYear = 2012;
[email protected]a21d8082012-01-12 19:23:2095const int kPreReadExpiryMonth = 7;
[email protected]28f576f2011-08-26 20:46:5596const int kPreReadExpiryDay = 1;
97
[email protected]48078e52012-02-09 00:02:2698// These are control values.
99const DWORD kPreReadExperimentFull = 100;
100const DWORD kPreReadExperimentNone = 0;
101
102// Modulate these for different experiments. These values should be a multiple
103// of 5 between 0 and 100, exclusive.
104const DWORD kPreReadExperimentA = 25;
105const DWORD kPreReadExperimentB = 40;
106
107void StaticAssertions() {
108 COMPILE_ASSERT(
109 kPreReadExperimentA <= 100, kPreReadExperimentA_exceeds_100);
110 COMPILE_ASSERT(
111 kPreReadExperimentA % 5 == 0, kPreReadExperimentA_is_not_a_multiple_of_5);
112 COMPILE_ASSERT(
113 kPreReadExperimentB <= 100, kPreReadExperimentB_exceeds_100);
114 COMPILE_ASSERT(
115 kPreReadExperimentB % 5 == 0, kPreReadExperimentB_is_not_a_multiple_of_5);
116}
117
118bool PreReadExperimentShouldRun() {
[email protected]28f576f2011-08-26 20:46:55119 base::Time::Exploded exploded = { 0 };
120 exploded.year = kPreReadExpiryYear;
121 exploded.month = kPreReadExpiryMonth;
122 exploded.day_of_month = kPreReadExpiryDay;
123
124 base::Time expiration_time = base::Time::FromLocalExploded(exploded);
125
126 // Get the build time. This code is copied from
127 // base::FieldTrial::GetBuildTime. We can't use MetricsLogBase::GetBuildTime
128 // because that's in seconds since Unix epoch, which base::Time can't use.
129 base::Time build_time;
130 const char* kDateTime = __DATE__ " " __TIME__;
131 bool result = base::Time::FromString(kDateTime, &build_time);
132 DCHECK(result);
133
134 // If the experiment is expired, don't run it.
[email protected]48078e52012-02-09 00:02:26135 return (build_time <= expiration_time);
[email protected]28f576f2011-08-26 20:46:55136}
137
[email protected]48078e52012-02-09 00:02:26138// For channels with small populations we just divide the population evenly
139// across the 4 buckets.
140DWORD GetSmallPopulationPreReadBucket(double rand_unit) {
141 DCHECK_GE(rand_unit, 0.0);
142 DCHECK_LT(rand_unit, 1.0);
143 if (rand_unit < 0.25 || rand_unit > 1.0)
144 return kPreReadExperimentFull; // The default pre-read amount.
145 if (rand_unit < 0.50)
146 return kPreReadExperimentA;
147 if (rand_unit < 0.75)
148 return kPreReadExperimentB;
149 return kPreReadExperimentNone;
150}
[email protected]28f576f2011-08-26 20:46:55151
[email protected]48078e52012-02-09 00:02:26152// For channels with large populations, we allocate a small percentage of the
153// population to each of the experimental buckets, and the rest to the current
154// default pre-read behaviour
155DWORD GetLargePopulationPreReadBucket(double rand_unit) {
156 DCHECK_GE(rand_unit, 0.0);
157 DCHECK_LT(rand_unit, 1.0);
158 if (rand_unit < 0.97 || rand_unit > 1.0)
159 return kPreReadExperimentFull; // The default pre-read amount.
160 if (rand_unit < 0.98)
161 return kPreReadExperimentA;
162 if (rand_unit < 0.99)
163 return kPreReadExperimentB;
164 return kPreReadExperimentNone;
165}
166
167// Returns true and the |pre_read_percentage| IFF the experiment should run.
168// Otherwise, returns false and |pre_read_percentage| is not modified.
169bool GetPreReadExperimentGroup(DWORD* pre_read_percentage) {
170 DCHECK(pre_read_percentage != NULL);
171
172 // Check if the experiment has expired.
173 if (!PreReadExperimentShouldRun())
[email protected]28f576f2011-08-26 20:46:55174 return false;
[email protected]28f576f2011-08-26 20:46:55175
[email protected]5bca9ee2011-09-03 00:18:42176 // Get the MetricsId of the installation. This is only set if the user has
177 // opted in to reporting. Doing things this way ensures that we only enable
178 // the experiment if its results are actually going to be reported.
179 std::wstring metrics_id;
180 if (!GoogleUpdateSettings::GetMetricsId(&metrics_id) || metrics_id.empty())
181 return false;
[email protected]28f576f2011-08-26 20:46:55182
[email protected]5bca9ee2011-09-03 00:18:42183 // We use the same technique as FieldTrial::HashClientId.
[email protected]b13b9bd2011-09-28 21:15:27184 unsigned char sha1_hash[base::kSHA1Length];
[email protected]5bca9ee2011-09-03 00:18:42185 base::SHA1HashBytes(
186 reinterpret_cast<const unsigned char*>(metrics_id.c_str()),
187 metrics_id.size() * sizeof(metrics_id[0]),
188 sha1_hash);
189 COMPILE_ASSERT(sizeof(uint64) < sizeof(sha1_hash), need_more_data);
190 uint64* bits = reinterpret_cast<uint64*>(&sha1_hash[0]);
191 double rand_unit = base::BitsToOpenEndedUnitInterval(*bits);
[email protected]28f576f2011-08-26 20:46:55192
[email protected]48078e52012-02-09 00:02:26193 // We carve up the bucket sizes based on the population of the channel.
194 const string16 channel(
195 GoogleUpdateSettings::GetChromeChannel(
196 GoogleUpdateSettings::IsSystemInstall()));
197
198 // For our purposes, Stable has a large population, everything else is small.
199 *pre_read_percentage = (channel == installer::kChromeChannelStable ?
200 GetLargePopulationPreReadBucket(rand_unit) :
201 GetSmallPopulationPreReadBucket(rand_unit));
[email protected]5bca9ee2011-09-03 00:18:42202
203 return true;
[email protected]28f576f2011-08-26 20:46:55204}
[email protected]5bca9ee2011-09-03 00:18:42205#endif // if defined(GOOGLE_CHROME_BUILD)
[email protected]28f576f2011-08-26 20:46:55206#endif // if defined(OS_WIN)
207
[email protected]4512f3ac2009-11-04 03:39:22208// Expects that |dir| has a trailing backslash. |dir| is modified so it
209// contains the full path that was tried. Caller must check for the return
[email protected]85769352010-11-16 14:24:30210// value not being null to determine if this path contains a valid dll.
[email protected]5bca9ee2011-09-03 00:18:42211HMODULE LoadChromeWithDirectory(std::wstring* dir) {
[email protected]4512f3ac2009-11-04 03:39:22212 ::SetCurrentDirectoryW(dir->c_str());
[email protected]103607e2010-02-01 18:57:09213 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
[email protected]74ca0442010-12-15 14:44:50214 dir->append(installer::kChromeDll);
[email protected]00b73412010-06-21 21:01:36215
[email protected]88ca34a2011-07-19 12:57:58216#ifndef WIN_DISABLE_PREREAD
[email protected]58ac0242010-07-09 18:31:15217#ifdef NDEBUG
[email protected]00b73412010-06-21 21:01:36218 // Experimental pre-reading optimization
[email protected]88ca34a2011-07-19 12:57:58219 // The idea is to pre-read a significant portion of chrome.dll in advance
[email protected]00b73412010-06-21 21:01:36220 // so that subsequent hard page faults are avoided.
[email protected]88ca34a2011-07-19 12:57:58221 //
222 // Pre-read may be disabled at compile time by defining WIN_DISABLE_PREREAD,
223 // but by default it is enabled in release builds. The ability to disable it
224 // is useful for evaluating competing optimization techniques.
[email protected]bdf411b2010-07-13 22:21:59225 if (!cmd_line.HasSwitch(switches::kProcessType)) {
[email protected]85286b52010-07-03 06:14:45226 // The kernel brings in 8 pages for the code section at a time and 4 pages
227 // for other sections. We can skip over these pages to avoid a soft page
228 // fault which may not occur during code execution. However skipping 4K at
229 // a time still has better performance over 32K and 16K according to data.
[email protected]88ca34a2011-07-19 12:57:58230 // TODO(ananta): Investigate this and tune.
[email protected]85286b52010-07-03 06:14:45231 const size_t kStepSize = 4 * 1024;
232
[email protected]6bb2628d2012-02-03 19:55:11233 // We hypothesize that pre-reading only the bytes actually touched during
234 // startup should improve startup time. The Syzygy toolchain attempts to
235 // optimize the binary layout of chrome.dll, rearranging the code and data
236 // blocks such that temporally related blocks (i.e., code and data used in
237 // startup, browser, renderer, etc) are grouped together, and that blocks
238 // used early in the process lifecycle occur earlier in their sections.
[email protected]48078e52012-02-09 00:02:26239 DWORD pre_read_percentage = 100;
[email protected]85286b52010-07-03 06:14:45240 DWORD pre_read_step_size = kStepSize;
[email protected]48078e52012-02-09 00:02:26241 bool is_eligible_for_experiment = true;
[email protected]85286b52010-07-03 06:14:45242
[email protected]85acecb2011-08-05 05:28:05243 // TODO(chrisha): This path should not be ChromeFrame specific, and it
244 // should not be hard-coded with 'Google' in the path. Rather, it should
245 // use the product name.
[email protected]48078e52012-02-09 00:02:26246 base::win::RegKey key(HKEY_CURRENT_USER,
247 L"Software\\Google\\ChromeFrame",
[email protected]2544a7a2011-03-14 18:25:19248 KEY_QUERY_VALUE);
[email protected]48078e52012-02-09 00:02:26249
250 // Check if there are any pre-read settings in the registry. If so, then
251 // the pre-read settings have been forcibly set and this instance is not
252 // eligible for the pre-read experiment.
[email protected]2544a7a2011-03-14 18:25:19253 if (key.Valid()) {
[email protected]48078e52012-02-09 00:02:26254 DWORD value = 0;
255 if (key.ReadValueDW(L"PreRead", &value) == ERROR_SUCCESS) {
256 is_eligible_for_experiment = false;
257 pre_read_percentage = (value != 0) ? 100 : 0;
258 }
259
260 if (key.ReadValueDW(L"PreReadPercentage", &value) == ERROR_SUCCESS) {
261 is_eligible_for_experiment = false;
262 pre_read_percentage = value;
263 }
264
265 if (key.ReadValueDW(L"PreReadStepSize", &value) == ERROR_SUCCESS) {
266 is_eligible_for_experiment = false;
267 pre_read_step_size = value;
[email protected]6bb2628d2012-02-03 19:55:11268 }
[email protected]2544a7a2011-03-14 18:25:19269 key.Close();
[email protected]00b73412010-06-21 21:01:36270 }
[email protected]85acecb2011-08-05 05:28:05271
[email protected]5bca9ee2011-09-03 00:18:42272#if defined(OS_WIN)
273#if defined(GOOGLE_CHROME_BUILD)
[email protected]28f576f2011-08-26 20:46:55274 // The PreRead experiment is unable to use the standard FieldTrial
275 // mechanism as pre-reading happens in chrome.exe prior to loading
276 // chrome.dll. As such, we use a custom approach. If the experiment is
[email protected]48078e52012-02-09 00:02:26277 // running (not expired) then we look to the registry for the BreakPad/UMA
278 // metricsid. We use this to seed a random unit, and select a bucket
279 // (percentage to pre-read) for the experiment. The selected bucket is
280 // communicated to chrome.dll via an environment variable, which alerts
281 // chrome.dll that the experiment is running, causing it to report
282 // sub-histogram results.
[email protected]6bb2628d2012-02-03 19:55:11283 //
284 // If we've read pre-read settings from the registry, then someone has
[email protected]48078e52012-02-09 00:02:26285 // specifically forced their pre-read options and is not participating in
[email protected]6bb2628d2012-02-03 19:55:11286 // the experiment.
287 //
[email protected]5bca9ee2011-09-03 00:18:42288 // If the experiment is running, indicate it to chrome.dll via an
[email protected]48078e52012-02-09 00:02:26289 // environment variable that contains the percentage of chrome that
290 // was pre-read. Allowable values are all multiples of 5 between
291 // 0 and 100, inclusive.
292 if (is_eligible_for_experiment &&
293 GetPreReadExperimentGroup(&pre_read_percentage)) {
294 DCHECK_LE(pre_read_percentage, 100U);
295 DCHECK_EQ(pre_read_percentage % 5, 0U);
[email protected]5bca9ee2011-09-03 00:18:42296 scoped_ptr<base::Environment> env(base::Environment::Create());
297 env->SetVar(chrome::kPreReadEnvironmentVariable,
[email protected]48078e52012-02-09 00:02:26298 base::StringPrintf("%d", pre_read_percentage));
[email protected]28f576f2011-08-26 20:46:55299 }
[email protected]5bca9ee2011-09-03 00:18:42300#endif // if defined(GOOGLE_CHROME_BUILD)
301#endif // if defined(OS_WIN)
[email protected]28f576f2011-08-26 20:46:55302
[email protected]6bb2628d2012-02-03 19:55:11303 // Clamp the DWORD percentage to fit into a uint8 that's <= 100.
[email protected]48078e52012-02-09 00:02:26304 pre_read_percentage = std::min(pre_read_percentage, 100UL);
[email protected]6bb2628d2012-02-03 19:55:11305
306 // Perform the full or partial pre-read.
307 TRACE_EVENT_BEGIN_ETW("PreReadImage", 0, "");
308 ImagePreReader::PartialPreReadImage(dir->c_str(),
[email protected]48078e52012-02-09 00:02:26309 static_cast<uint8>(pre_read_percentage),
[email protected]6bb2628d2012-02-03 19:55:11310 pre_read_step_size);
311 TRACE_EVENT_END_ETW("PreReadImage", 0, "");
[email protected]00b73412010-06-21 21:01:36312 }
[email protected]58ac0242010-07-09 18:31:15313#endif // NDEBUG
[email protected]88ca34a2011-07-19 12:57:58314#endif // WIN_DISABLE_PREREAD
[email protected]00b73412010-06-21 21:01:36315
[email protected]4512f3ac2009-11-04 03:39:22316 return ::LoadLibraryExW(dir->c_str(), NULL,
317 LOAD_WITH_ALTERED_SEARCH_PATH);
318}
319
[email protected]2544a7a2011-03-14 18:25:19320void RecordDidRun(const std::wstring& dll_path) {
[email protected]2544a7a2011-03-14 18:25:19321 bool system_level = !InstallUtil::IsPerUserInstall(dll_path.c_str());
[email protected]fd59f822011-05-12 18:07:18322 GoogleUpdateSettings::UpdateDidRunState(true, system_level);
[email protected]4512f3ac2009-11-04 03:39:22323}
324
[email protected]2544a7a2011-03-14 18:25:19325void ClearDidRun(const std::wstring& dll_path) {
[email protected]2544a7a2011-03-14 18:25:19326 bool system_level = !InstallUtil::IsPerUserInstall(dll_path.c_str());
[email protected]fd59f822011-05-12 18:07:18327 GoogleUpdateSettings::UpdateDidRunState(false, system_level);
[email protected]2544a7a2011-03-14 18:25:19328}
[email protected]fd59f822011-05-12 18:07:18329
[email protected]28f576f2011-08-26 20:46:55330} // namespace
[email protected]4512f3ac2009-11-04 03:39:22331//=============================================================================
332
333MainDllLoader::MainDllLoader() : dll_(NULL) {
334}
335
336MainDllLoader::~MainDllLoader() {
[email protected]4512f3ac2009-11-04 03:39:22337}
338
[email protected]85769352010-11-16 14:24:30339// Loading chrome is an interesting affair. First we try loading from the
340// current directory to support run-what-you-compile and other development
341// scenarios.
342// If that fails then we look at the --chrome-version command line flag followed
343// by the 'CHROME_VERSION' env variable to determine if we should stick with an
344// older dll version even if a new one is available to support upgrade-in-place
345// scenarios.
346// If that fails then finally we look at the registry which should point us
347// to the latest version. This is the expected path for the first chrome.exe
348// browser instance in an installed build.
349HMODULE MainDllLoader::Load(std::wstring* out_version, std::wstring* out_file) {
[email protected]4512f3ac2009-11-04 03:39:22350 std::wstring dir(GetExecutablePath());
[email protected]85769352010-11-16 14:24:30351 *out_file = dir;
[email protected]5bca9ee2011-09-03 00:18:42352 HMODULE dll = LoadChromeWithDirectory(out_file);
[email protected]4512f3ac2009-11-04 03:39:22353 if (dll)
354 return dll;
355
[email protected]36ee0322010-12-23 21:27:12356 std::wstring version_string;
[email protected]85769352010-11-16 14:24:30357 scoped_ptr<Version> version;
358 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
359 if (cmd_line.HasSwitch(switches::kChromeVersion)) {
[email protected]36ee0322010-12-23 21:27:12360 version_string = cmd_line.GetSwitchValueNative(switches::kChromeVersion);
361 version.reset(Version::GetVersionFromString(WideToASCII(version_string)));
[email protected]85769352010-11-16 14:24:30362
363 if (!version.get()) {
364 // If a bogus command line flag was given, then abort.
365 LOG(ERROR) << "Invalid version string received on command line: "
[email protected]36ee0322010-12-23 21:27:12366 << version_string;
[email protected]4512f3ac2009-11-04 03:39:22367 return NULL;
[email protected]85769352010-11-16 14:24:30368 }
[email protected]4512f3ac2009-11-04 03:39:22369 }
370
[email protected]85769352010-11-16 14:24:30371 if (!version.get()) {
[email protected]03d21b82010-12-07 19:37:22372 if (EnvQueryStr(ASCIIToWide(chrome::kChromeVersionEnvVar).c_str(),
[email protected]36ee0322010-12-23 21:27:12373 &version_string)) {
374 version.reset(Version::GetVersionFromString(WideToASCII(version_string)));
[email protected]85769352010-11-16 14:24:30375 }
376 }
377
378 if (!version.get()) {
379 std::wstring reg_path(GetRegistryPath());
380 // Look into the registry to find the latest version. We don't validate
381 // this by building a Version object to avoid harming normal case startup
382 // time.
[email protected]36ee0322010-12-23 21:27:12383 version_string.clear();
384 GetVersion(dir.c_str(), reg_path.c_str(), &version_string);
[email protected]85769352010-11-16 14:24:30385 }
386
[email protected]36ee0322010-12-23 21:27:12387 if (version.get() || !version_string.empty()) {
[email protected]85769352010-11-16 14:24:30388 *out_file = dir;
[email protected]36ee0322010-12-23 21:27:12389 *out_version = version_string;
[email protected]85769352010-11-16 14:24:30390 out_file->append(*out_version).append(L"\\");
[email protected]5bca9ee2011-09-03 00:18:42391 dll = LoadChromeWithDirectory(out_file);
[email protected]3e092a572011-05-02 20:47:08392 if (!dll) {
393 LOG(ERROR) << "Failed to load Chrome DLL from " << out_file;
394 }
395 return dll;
[email protected]85769352010-11-16 14:24:30396 } else {
[email protected]3e092a572011-05-02 20:47:08397 LOG(ERROR) << "Could not get Chrome DLL version.";
[email protected]85769352010-11-16 14:24:30398 return NULL;
399 }
[email protected]4512f3ac2009-11-04 03:39:22400}
401
402// Launching is a matter of loading the right dll, setting the CHROME_VERSION
403// environment variable and just calling the entry point. Derived classes can
404// add custom code in the OnBeforeLaunch callback.
405int MainDllLoader::Launch(HINSTANCE instance,
406 sandbox::SandboxInterfaceInfo* sbox_info) {
407 std::wstring version;
408 std::wstring file;
409 dll_ = Load(&version, &file);
410 if (!dll_)
[email protected]1fcfb202011-07-19 19:53:14411 return chrome::RESULT_CODE_MISSING_DATA;
[email protected]4512f3ac2009-11-04 03:39:22412
[email protected]ae0f0772010-08-13 04:54:10413 scoped_ptr<base::Environment> env(base::Environment::Create());
[email protected]03d21b82010-12-07 19:37:22414 env->SetVar(chrome::kChromeVersionEnvVar, WideToUTF8(version));
[email protected]4512f3ac2009-11-04 03:39:22415
416 InitCrashReporterWithDllPath(file);
[email protected]2544a7a2011-03-14 18:25:19417 OnBeforeLaunch(file);
[email protected]4512f3ac2009-11-04 03:39:22418
419 DLL_MAIN entry_point =
420 reinterpret_cast<DLL_MAIN>(::GetProcAddress(dll_, "ChromeMain"));
421 if (!entry_point)
[email protected]1fcfb202011-07-19 19:53:14422 return chrome::RESULT_CODE_BAD_PROCESS_TYPE;
[email protected]4512f3ac2009-11-04 03:39:22423
[email protected]d85d6702011-09-01 15:51:53424 int rc = entry_point(instance, sbox_info);
[email protected]2544a7a2011-03-14 18:25:19425 return OnBeforeExit(rc, file);
[email protected]4512f3ac2009-11-04 03:39:22426}
427
[email protected]3cdacd42010-04-30 18:55:53428void MainDllLoader::RelaunchChromeBrowserWithNewCommandLineIfNeeded() {
429 RelaunchChromeBrowserWithNewCommandLineIfNeededFunc relaunch_function =
430 reinterpret_cast<RelaunchChromeBrowserWithNewCommandLineIfNeededFunc>(
431 ::GetProcAddress(dll_,
432 "RelaunchChromeBrowserWithNewCommandLineIfNeeded"));
433 if (!relaunch_function) {
434 LOG(ERROR) << "Could not find exported function "
435 << "RelaunchChromeBrowserWithNewCommandLineIfNeeded";
436 } else {
437 relaunch_function();
438 }
439}
440
[email protected]4512f3ac2009-11-04 03:39:22441//=============================================================================
442
443class ChromeDllLoader : public MainDllLoader {
444 public:
445 virtual std::wstring GetRegistryPath() {
446 std::wstring key(google_update::kRegPathClients);
[email protected]5f2cee82009-11-05 04:59:48447 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
448 key.append(L"\\").append(dist->GetAppGuid());
[email protected]4512f3ac2009-11-04 03:39:22449 return key;
450 }
451
[email protected]2544a7a2011-03-14 18:25:19452 virtual void OnBeforeLaunch(const std::wstring& dll_path) {
453 RecordDidRun(dll_path);
[email protected]4512f3ac2009-11-04 03:39:22454 }
[email protected]42d7510c2009-12-19 01:48:30455
[email protected]2544a7a2011-03-14 18:25:19456 virtual int OnBeforeExit(int return_code, const std::wstring& dll_path) {
[email protected]42d7510c2009-12-19 01:48:30457 // NORMAL_EXIT_CANCEL is used for experiments when the user cancels
458 // so we need to reset the did_run signal so omaha does not count
459 // this run as active usage.
[email protected]1fcfb202011-07-19 19:53:14460 if (chrome::RESULT_CODE_NORMAL_EXIT_CANCEL == return_code) {
[email protected]2544a7a2011-03-14 18:25:19461 ClearDidRun(dll_path);
[email protected]42d7510c2009-12-19 01:48:30462 }
463 return return_code;
464 }
[email protected]4512f3ac2009-11-04 03:39:22465};
466
467//=============================================================================
468
469class ChromiumDllLoader : public MainDllLoader {
470 public:
471 virtual std::wstring GetRegistryPath() {
[email protected]74d1eec2009-11-04 22:18:57472 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
473 return dist->GetVersionKey();
[email protected]4512f3ac2009-11-04 03:39:22474 }
475};
476
477MainDllLoader* MakeMainDllLoader() {
478#if defined(GOOGLE_CHROME_BUILD)
479 return new ChromeDllLoader();
480#else
481 return new ChromiumDllLoader();
482#endif
483}