OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <windows.h> | 5 #include <windows.h> |
6 #include <shlwapi.h> | 6 #include <shlwapi.h> |
7 | 7 |
8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
9 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
10 #include "base/environment.h" | 10 #include "base/environment.h" |
11 #include "base/file_util.h" | 11 #include "base/file_util.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/memory/scoped_ptr.h" | 13 #include "base/memory/scoped_ptr.h" |
14 #include "base/rand_util.h" // For PreRead experiment. | |
15 #include "base/string_util.h" | 14 #include "base/string_util.h" |
16 #include "base/utf_string_conversions.h" | 15 #include "base/utf_string_conversions.h" |
17 #include "base/version.h" | 16 #include "base/version.h" |
18 #include "base/win/registry.h" | 17 #include "base/win/registry.h" |
19 #include "chrome/app/breakpad_win.h" | 18 #include "chrome/app/breakpad_win.h" |
20 #include "chrome/app/client_util.h" | 19 #include "chrome/app/client_util.h" |
21 #include "chrome/common/chrome_constants.h" | 20 #include "chrome/common/chrome_constants.h" |
22 #include "chrome/common/chrome_result_codes.h" | 21 #include "chrome/common/chrome_result_codes.h" |
23 #include "chrome/common/chrome_switches.h" | 22 #include "chrome/common/chrome_switches.h" |
24 #include "chrome/installer/util/browser_distribution.h" | 23 #include "chrome/installer/util/browser_distribution.h" |
25 #include "chrome/installer/util/channel_info.h" | 24 #include "chrome/installer/util/channel_info.h" |
26 #include "chrome/installer/util/install_util.h" | 25 #include "chrome/installer/util/install_util.h" |
27 #include "chrome/installer/util/google_chrome_sxs_distribution.h" // PreRead. | |
28 #include "chrome/installer/util/google_update_constants.h" | 26 #include "chrome/installer/util/google_update_constants.h" |
29 #include "chrome/installer/util/google_update_settings.h" | 27 #include "chrome/installer/util/google_update_settings.h" |
30 #include "chrome/installer/util/util_constants.h" | 28 #include "chrome/installer/util/util_constants.h" |
31 | 29 |
32 namespace { | 30 namespace { |
33 // The entry point signature of chrome.dll. | 31 // The entry point signature of chrome.dll. |
34 typedef int (*DLL_MAIN)(HINSTANCE, sandbox::SandboxInterfaceInfo*, wchar_t*); | 32 typedef int (*DLL_MAIN)(HINSTANCE, sandbox::SandboxInterfaceInfo*, wchar_t*); |
35 | 33 |
36 typedef void (*RelaunchChromeBrowserWithNewCommandLineIfNeededFunc)(); | 34 typedef void (*RelaunchChromeBrowserWithNewCommandLineIfNeededFunc)(); |
37 | 35 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 bool EnvQueryStr(const wchar_t* key_name, std::wstring* value) { | 76 bool EnvQueryStr(const wchar_t* key_name, std::wstring* value) { |
79 wchar_t out[128]; | 77 wchar_t out[128]; |
80 DWORD count = sizeof(out)/sizeof(out[0]); | 78 DWORD count = sizeof(out)/sizeof(out[0]); |
81 DWORD rv = ::GetEnvironmentVariableW(key_name, out, count); | 79 DWORD rv = ::GetEnvironmentVariableW(key_name, out, count); |
82 if ((rv == 0) || (rv >= count)) | 80 if ((rv == 0) || (rv >= count)) |
83 return false; | 81 return false; |
84 *value = out; | 82 *value = out; |
85 return true; | 83 return true; |
86 } | 84 } |
87 | 85 |
88 #if defined(OS_WIN) | |
89 // These constants are used by the PreRead experiment. | |
90 const wchar_t kPreReadRegistryValue[] = L"PreReadExperimentGroup"; | |
91 const int kPreReadExpiryYear = 2012; | |
92 const int kPreReadExpiryMonth = 1; | |
93 const int kPreReadExpiryDay = 1; | |
94 | |
95 bool PreReadShouldRun() { | |
96 base::Time::Exploded exploded = { 0 }; | |
97 exploded.year = kPreReadExpiryYear; | |
98 exploded.month = kPreReadExpiryMonth; | |
99 exploded.day_of_month = kPreReadExpiryDay; | |
100 | |
101 base::Time expiration_time = base::Time::FromLocalExploded(exploded); | |
102 | |
103 // Get the build time. This code is copied from | |
104 // base::FieldTrial::GetBuildTime. We can't use MetricsLogBase::GetBuildTime | |
105 // because that's in seconds since Unix epoch, which base::Time can't use. | |
106 base::Time build_time; | |
107 const char* kDateTime = __DATE__ " " __TIME__; | |
108 bool result = base::Time::FromString(kDateTime, &build_time); | |
109 DCHECK(result); | |
110 | |
111 // If the experiment is expired, don't run it. | |
112 if (build_time > expiration_time) | |
113 return false; | |
114 | |
115 #if defined(GOOGLE_CHROME_BUILD) | |
116 // The experiment should only run on canary and dev. | |
117 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | |
118 std::wstring channel; | |
119 if (!dist->GetChromeChannel(&channel)) | |
120 return false; | |
121 return channel == GoogleChromeSxSDistribution::GetChannel() || | |
122 channel == L"dev"; | |
123 #else | |
124 // If we're running Chromium, we have no concept of channel so we | |
125 // run the experiment. | |
126 return true; | |
127 #endif | |
128 } | |
129 | |
130 // Checks to see if the experiment is running. If so, either tosses a coin | |
131 // and persists it, or gets the already persistent coin-toss value. Returns | |
132 // the coin-toss via |pre_read|. Returns true if the experiment is running and | |
133 // pre_read has been written, false otherwise. |pre_read| is only written to | |
134 // when this function returns true. |key| must be open with read-write access, | |
135 // and be valid. | |
136 bool GetPreReadExperimentGroup(base::win::RegKey* key, | |
137 DWORD* pre_read) { | |
138 DCHECK(key != NULL); | |
139 DCHECK(pre_read != NULL); | |
140 | |
141 if (!PreReadShouldRun()) { | |
142 // The experiment is no longer running. Remove the registry key | |
143 // storing the coin toss. | |
144 key->DeleteValue(kPreReadRegistryValue); | |
145 return false; | |
146 } | |
147 | |
148 // Coin already tossed? | |
149 DWORD coin_toss = 0; | |
150 if (key->ReadValueDW(kPreReadRegistryValue, &coin_toss) == ERROR_SUCCESS) { | |
151 *pre_read = coin_toss; | |
152 return true; | |
153 } | |
154 | |
155 // Coin not tossed? Toss it, and save the value to the registry. | |
156 coin_toss = base::RandInt(0, 1); | |
157 DCHECK(coin_toss == 0 || coin_toss == 1); | |
158 if (key->WriteValue(kPreReadRegistryValue, coin_toss) == ERROR_SUCCESS) { | |
159 *pre_read = coin_toss; | |
160 return true; | |
161 } | |
162 | |
163 return false; | |
164 } | |
165 #endif // if defined(OS_WIN) | |
166 | |
167 // Expects that |dir| has a trailing backslash. |dir| is modified so it | 86 // Expects that |dir| has a trailing backslash. |dir| is modified so it |
168 // contains the full path that was tried. Caller must check for the return | 87 // contains the full path that was tried. Caller must check for the return |
169 // value not being null to determine if this path contains a valid dll. | 88 // value not being null to determine if this path contains a valid dll. |
170 HMODULE LoadChromeWithDirectory(const std::wstring& reg_key, // For PreRead. | 89 HMODULE LoadChromeWithDirectory(std::wstring* dir) { |
171 std::wstring* dir) { | |
172 ::SetCurrentDirectoryW(dir->c_str()); | 90 ::SetCurrentDirectoryW(dir->c_str()); |
173 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); | 91 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); |
174 #ifdef _WIN64 | 92 #ifdef _WIN64 |
175 if ((cmd_line.GetSwitchValueASCII(switches::kProcessType) == | 93 if ((cmd_line.GetSwitchValueASCII(switches::kProcessType) == |
176 switches::kNaClBrokerProcess) || | 94 switches::kNaClBrokerProcess) || |
177 (cmd_line.GetSwitchValueASCII(switches::kProcessType) == | 95 (cmd_line.GetSwitchValueASCII(switches::kProcessType) == |
178 switches::kNaClLoaderProcess)) { | 96 switches::kNaClLoaderProcess)) { |
179 // Load the 64-bit DLL when running in a 64-bit process. | 97 // Load the 64-bit DLL when running in a 64-bit process. |
180 dir->append(installer::kChromeNaCl64Dll); | 98 dir->append(installer::kChromeNaCl64Dll); |
181 } else { | 99 } else { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 // use the product name. | 131 // use the product name. |
214 base::win::RegKey key(HKEY_CURRENT_USER, L"Software\\Google\\ChromeFrame", | 132 base::win::RegKey key(HKEY_CURRENT_USER, L"Software\\Google\\ChromeFrame", |
215 KEY_QUERY_VALUE); | 133 KEY_QUERY_VALUE); |
216 if (key.Valid()) { | 134 if (key.Valid()) { |
217 key.ReadValueDW(L"PreReadSize", &pre_read_size); | 135 key.ReadValueDW(L"PreReadSize", &pre_read_size); |
218 key.ReadValueDW(L"PreReadStepSize", &pre_read_step_size); | 136 key.ReadValueDW(L"PreReadStepSize", &pre_read_step_size); |
219 key.ReadValueDW(L"PreRead", &pre_read); | 137 key.ReadValueDW(L"PreRead", &pre_read); |
220 key.Close(); | 138 key.Close(); |
221 } | 139 } |
222 | 140 |
223 // The PreRead experiment is unable to use the standard FieldTrial | |
224 // mechanism as pre-reading happens in chrome.exe prior to loading | |
225 // chrome.dll. As such, we use a custom approach. If the experiment is | |
226 // running (not expired, and we're running a version of chrome from an | |
227 // appropriate channel) then we look to the registry for the experiment | |
228 // group. If it is not found, we toss a coin and persist the result in the | |
229 // registry. The coin-toss value is communicated to chrome.dll via an | |
230 // environment variable, which indicates to chrome.dll that the experiment | |
231 // is running, causing it to report sub-histogram results. If the experiment | |
232 // is expired or not running, the registry key is removed. | |
233 | |
234 base::win::RegKey exp_key( | |
235 HKEY_CURRENT_USER, reg_key.c_str(), | |
236 KEY_CREATE_SUB_KEY | KEY_QUERY_VALUE | KEY_SET_VALUE); | |
237 | |
238 if (exp_key.Valid()) { | |
239 // If the experiment is running, indicate it to chrome.dll via an | |
240 // environment variable. | |
241 if (GetPreReadExperimentGroup(&exp_key, &pre_read)) { | |
242 scoped_ptr<base::Environment> env(base::Environment::Create()); | |
243 env->SetVar(chrome::kPreReadEnvironmentVariable, | |
244 pre_read ? "1" : "0"); | |
245 } | |
246 exp_key.Close(); | |
247 } | |
248 | |
249 if (pre_read) { | 141 if (pre_read) { |
250 TRACE_EVENT_BEGIN_ETW("PreReadImage", 0, ""); | 142 TRACE_EVENT_BEGIN_ETW("PreReadImage", 0, ""); |
251 file_util::PreReadImage(dir->c_str(), pre_read_size, pre_read_step_size); | 143 file_util::PreReadImage(dir->c_str(), pre_read_size, pre_read_step_size); |
252 TRACE_EVENT_END_ETW("PreReadImage", 0, ""); | 144 TRACE_EVENT_END_ETW("PreReadImage", 0, ""); |
253 } | 145 } |
254 } | 146 } |
255 #endif // NDEBUG | 147 #endif // NDEBUG |
256 #endif // WIN_DISABLE_PREREAD | 148 #endif // WIN_DISABLE_PREREAD |
257 | 149 |
258 return ::LoadLibraryExW(dir->c_str(), NULL, | 150 return ::LoadLibraryExW(dir->c_str(), NULL, |
259 LOAD_WITH_ALTERED_SEARCH_PATH); | 151 LOAD_WITH_ALTERED_SEARCH_PATH); |
260 } | 152 } |
261 | 153 |
262 void RecordDidRun(const std::wstring& dll_path) { | 154 void RecordDidRun(const std::wstring& dll_path) { |
263 bool system_level = !InstallUtil::IsPerUserInstall(dll_path.c_str()); | 155 bool system_level = !InstallUtil::IsPerUserInstall(dll_path.c_str()); |
264 GoogleUpdateSettings::UpdateDidRunState(true, system_level); | 156 GoogleUpdateSettings::UpdateDidRunState(true, system_level); |
265 } | 157 } |
266 | 158 |
267 void ClearDidRun(const std::wstring& dll_path) { | 159 void ClearDidRun(const std::wstring& dll_path) { |
268 bool system_level = !InstallUtil::IsPerUserInstall(dll_path.c_str()); | 160 bool system_level = !InstallUtil::IsPerUserInstall(dll_path.c_str()); |
269 GoogleUpdateSettings::UpdateDidRunState(false, system_level); | 161 GoogleUpdateSettings::UpdateDidRunState(false, system_level); |
270 } | 162 } |
271 | 163 |
272 } // namespace | 164 } |
273 //============================================================================= | 165 //============================================================================= |
274 | 166 |
275 MainDllLoader::MainDllLoader() : dll_(NULL) { | 167 MainDllLoader::MainDllLoader() : dll_(NULL) { |
276 } | 168 } |
277 | 169 |
278 MainDllLoader::~MainDllLoader() { | 170 MainDllLoader::~MainDllLoader() { |
279 } | 171 } |
280 | 172 |
281 // Loading chrome is an interesting affair. First we try loading from the | 173 // Loading chrome is an interesting affair. First we try loading from the |
282 // current directory to support run-what-you-compile and other development | 174 // current directory to support run-what-you-compile and other development |
283 // scenarios. | 175 // scenarios. |
284 // If that fails then we look at the --chrome-version command line flag followed | 176 // If that fails then we look at the --chrome-version command line flag followed |
285 // by the 'CHROME_VERSION' env variable to determine if we should stick with an | 177 // by the 'CHROME_VERSION' env variable to determine if we should stick with an |
286 // older dll version even if a new one is available to support upgrade-in-place | 178 // older dll version even if a new one is available to support upgrade-in-place |
287 // scenarios. | 179 // scenarios. |
288 // If that fails then finally we look at the registry which should point us | 180 // If that fails then finally we look at the registry which should point us |
289 // to the latest version. This is the expected path for the first chrome.exe | 181 // to the latest version. This is the expected path for the first chrome.exe |
290 // browser instance in an installed build. | 182 // browser instance in an installed build. |
291 HMODULE MainDllLoader::Load(std::wstring* out_version, std::wstring* out_file) { | 183 HMODULE MainDllLoader::Load(std::wstring* out_version, std::wstring* out_file) { |
292 std::wstring dir(GetExecutablePath()); | 184 std::wstring dir(GetExecutablePath()); |
293 *out_file = dir; | 185 *out_file = dir; |
294 HMODULE dll = LoadChromeWithDirectory(GetRegistryPath(), out_file); | 186 HMODULE dll = LoadChromeWithDirectory(out_file); |
295 if (dll) | 187 if (dll) |
296 return dll; | 188 return dll; |
297 | 189 |
298 std::wstring version_string; | 190 std::wstring version_string; |
299 scoped_ptr<Version> version; | 191 scoped_ptr<Version> version; |
300 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); | 192 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); |
301 if (cmd_line.HasSwitch(switches::kChromeVersion)) { | 193 if (cmd_line.HasSwitch(switches::kChromeVersion)) { |
302 version_string = cmd_line.GetSwitchValueNative(switches::kChromeVersion); | 194 version_string = cmd_line.GetSwitchValueNative(switches::kChromeVersion); |
303 version.reset(Version::GetVersionFromString(WideToASCII(version_string))); | 195 version.reset(Version::GetVersionFromString(WideToASCII(version_string))); |
304 | 196 |
(...skipping 18 matching lines...) Expand all Loading... |
323 // this by building a Version object to avoid harming normal case startup | 215 // this by building a Version object to avoid harming normal case startup |
324 // time. | 216 // time. |
325 version_string.clear(); | 217 version_string.clear(); |
326 GetVersion(dir.c_str(), reg_path.c_str(), &version_string); | 218 GetVersion(dir.c_str(), reg_path.c_str(), &version_string); |
327 } | 219 } |
328 | 220 |
329 if (version.get() || !version_string.empty()) { | 221 if (version.get() || !version_string.empty()) { |
330 *out_file = dir; | 222 *out_file = dir; |
331 *out_version = version_string; | 223 *out_version = version_string; |
332 out_file->append(*out_version).append(L"\\"); | 224 out_file->append(*out_version).append(L"\\"); |
333 dll = LoadChromeWithDirectory(GetRegistryPath(), out_file); | 225 dll = LoadChromeWithDirectory(out_file); |
334 if (!dll) { | 226 if (!dll) { |
335 LOG(ERROR) << "Failed to load Chrome DLL from " << out_file; | 227 LOG(ERROR) << "Failed to load Chrome DLL from " << out_file; |
336 } | 228 } |
337 return dll; | 229 return dll; |
338 } else { | 230 } else { |
339 LOG(ERROR) << "Could not get Chrome DLL version."; | 231 LOG(ERROR) << "Could not get Chrome DLL version."; |
340 return NULL; | 232 return NULL; |
341 } | 233 } |
342 } | 234 } |
343 | 235 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 } | 308 } |
417 }; | 309 }; |
418 | 310 |
419 MainDllLoader* MakeMainDllLoader() { | 311 MainDllLoader* MakeMainDllLoader() { |
420 #if defined(GOOGLE_CHROME_BUILD) | 312 #if defined(GOOGLE_CHROME_BUILD) |
421 return new ChromeDllLoader(); | 313 return new ChromeDllLoader(); |
422 #else | 314 #else |
423 return new ChromiumDllLoader(); | 315 return new ChromiumDllLoader(); |
424 #endif | 316 #endif |
425 } | 317 } |
OLD | NEW |