Chromium Code Reviews| 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. | |
| 14 #include "base/string_util.h" | 15 #include "base/string_util.h" |
| 15 #include "base/utf_string_conversions.h" | 16 #include "base/utf_string_conversions.h" |
| 16 #include "base/version.h" | 17 #include "base/version.h" |
| 17 #include "base/win/registry.h" | 18 #include "base/win/registry.h" |
| 18 #include "chrome/app/breakpad_win.h" | 19 #include "chrome/app/breakpad_win.h" |
| 19 #include "chrome/app/client_util.h" | 20 #include "chrome/app/client_util.h" |
| 20 #include "chrome/common/chrome_constants.h" | 21 #include "chrome/common/chrome_constants.h" |
| 21 #include "chrome/common/chrome_result_codes.h" | 22 #include "chrome/common/chrome_result_codes.h" |
| 22 #include "chrome/common/chrome_switches.h" | 23 #include "chrome/common/chrome_switches.h" |
| 23 #include "chrome/installer/util/browser_distribution.h" | 24 #include "chrome/installer/util/browser_distribution.h" |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 76 bool EnvQueryStr(const wchar_t* key_name, std::wstring* value) { | 77 bool EnvQueryStr(const wchar_t* key_name, std::wstring* value) { |
| 77 wchar_t out[128]; | 78 wchar_t out[128]; |
| 78 DWORD count = sizeof(out)/sizeof(out[0]); | 79 DWORD count = sizeof(out)/sizeof(out[0]); |
| 79 DWORD rv = ::GetEnvironmentVariableW(key_name, out, count); | 80 DWORD rv = ::GetEnvironmentVariableW(key_name, out, count); |
| 80 if ((rv == 0) || (rv >= count)) | 81 if ((rv == 0) || (rv >= count)) |
| 81 return false; | 82 return false; |
| 82 *value = out; | 83 *value = out; |
| 83 return true; | 84 return true; |
| 84 } | 85 } |
| 85 | 86 |
| 87 #if defined(OS_WIN) | |
| 88 // These constants are used by the PreRead experiment. | |
| 89 const wchar_t kPreReadRegistryValue[] = L"PreReadExperimentGroup"; | |
| 90 const int kPreReadExpiryYear = 2012; | |
| 91 const int kPreReadExpiryMonth = 1; | |
| 92 const int kPreReadExpiryDay = 1; | |
| 93 | |
| 94 bool PreReadShouldRun() { | |
| 95 base::Time::Exploded exploded = { 0 }; | |
| 96 exploded.year = kPreReadExpiryYear; | |
| 97 exploded.month = kPreReadExpiryMonth; | |
| 98 exploded.day_of_month = kPreReadExpiryDay; | |
| 99 | |
| 100 base::Time expiration_time = base::Time::FromLocalExploded(exploded); | |
| 101 | |
| 102 // Get the build time. This is copied from base::FieldTrial::GetBuildTime. | |
|
Sigurður Ásgeirsson
2011/08/25 17:44:14
MetricsLogBase::GetBuildTime() is a public static
chrisha
2011/08/25 19:39:17
Unfortunately this is in seconds-since-unix-epoch,
| |
| 103 base::Time build_time; | |
| 104 const char* kDateTime = __DATE__ " " __TIME__; | |
| 105 bool result = base::Time::FromString(kDateTime, &build_time); | |
| 106 DCHECK(result); | |
| 107 | |
| 108 // If the experiment is expired, don't run it. | |
| 109 if (build_time > expiration_time) | |
| 110 return false; | |
| 111 | |
| 112 #if defined(GOOGLE_CHROME_BUILD) | |
| 113 // The experiment should only run on canary and dev. | |
| 114 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); | |
| 115 std::wstring channel; | |
| 116 if (!dist->GetChromeChannel(&channel)) | |
| 117 return false; | |
| 118 return channel == L"canary" || channel == L"dev"; | |
|
Sigurður Ásgeirsson
2011/08/25 17:44:14
looks like the canary channel name is "canary buil
chrisha
2011/08/25 19:39:17
Looking at that file, the channel name is actually
| |
| 119 #else | |
| 120 // If we're running Chromium, we have no concept of channel so we | |
| 121 // run the experiment. | |
| 122 return true; | |
| 123 #endif | |
| 124 } | |
| 125 #endif | |
| 126 | |
| 86 // Expects that |dir| has a trailing backslash. |dir| is modified so it | 127 // Expects that |dir| has a trailing backslash. |dir| is modified so it |
| 87 // contains the full path that was tried. Caller must check for the return | 128 // contains the full path that was tried. Caller must check for the return |
| 88 // value not being null to determine if this path contains a valid dll. | 129 // value not being null to determine if this path contains a valid dll. |
| 89 HMODULE LoadChromeWithDirectory(std::wstring* dir) { | 130 HMODULE LoadChromeWithDirectory(const std::wstring& reg_key, // For PreRead. |
| 131 std::wstring* dir) { | |
| 90 ::SetCurrentDirectoryW(dir->c_str()); | 132 ::SetCurrentDirectoryW(dir->c_str()); |
| 91 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); | 133 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); |
| 92 #ifdef _WIN64 | 134 #ifdef _WIN64 |
| 93 if ((cmd_line.GetSwitchValueASCII(switches::kProcessType) == | 135 if ((cmd_line.GetSwitchValueASCII(switches::kProcessType) == |
| 94 switches::kNaClBrokerProcess) || | 136 switches::kNaClBrokerProcess) || |
| 95 (cmd_line.GetSwitchValueASCII(switches::kProcessType) == | 137 (cmd_line.GetSwitchValueASCII(switches::kProcessType) == |
| 96 switches::kNaClLoaderProcess)) { | 138 switches::kNaClLoaderProcess)) { |
| 97 // Load the 64-bit DLL when running in a 64-bit process. | 139 // Load the 64-bit DLL when running in a 64-bit process. |
| 98 dir->append(installer::kChromeNaCl64Dll); | 140 dir->append(installer::kChromeNaCl64Dll); |
| 99 } else { | 141 } else { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 131 // use the product name. | 173 // use the product name. |
| 132 base::win::RegKey key(HKEY_CURRENT_USER, L"Software\\Google\\ChromeFrame", | 174 base::win::RegKey key(HKEY_CURRENT_USER, L"Software\\Google\\ChromeFrame", |
| 133 KEY_QUERY_VALUE); | 175 KEY_QUERY_VALUE); |
| 134 if (key.Valid()) { | 176 if (key.Valid()) { |
| 135 key.ReadValueDW(L"PreReadSize", &pre_read_size); | 177 key.ReadValueDW(L"PreReadSize", &pre_read_size); |
| 136 key.ReadValueDW(L"PreReadStepSize", &pre_read_step_size); | 178 key.ReadValueDW(L"PreReadStepSize", &pre_read_step_size); |
| 137 key.ReadValueDW(L"PreRead", &pre_read); | 179 key.ReadValueDW(L"PreRead", &pre_read); |
| 138 key.Close(); | 180 key.Close(); |
| 139 } | 181 } |
| 140 | 182 |
| 183 // The PreRead experiment is unable to use the standard FieldTrial | |
| 184 // mechanism as PreReading happens in chrome.exe prior to loading | |
|
Sigurður Ásgeirsson
2011/08/25 17:44:14
PreReading -> pre-reading?
Good comment.
chrisha
2011/08/25 19:39:17
Done.
| |
| 185 // chrome.dll. As such, we use a custom approach. If the experiment is | |
| 186 // running (not expired, and we're running a version of chrome from an | |
| 187 // appropriate channel) then we look to the registry for the experiment | |
| 188 // group. If it is not found, we toss a coin and persist the result in the | |
| 189 // registry. The coin-toss value is communicated to chrome.dll via an | |
| 190 // environment variable, which indicates to chrome.dll that the experiment | |
| 191 // is running, causing it to report sub-histogram results. If the experiment | |
| 192 // is expired or not running, the registry key is removed. | |
| 193 | |
| 194 base::win::RegKey exp_key( | |
| 195 HKEY_CURRENT_USER, reg_key.c_str(), | |
| 196 KEY_CREATE_SUB_KEY | KEY_QUERY_VALUE | KEY_SET_VALUE); | |
| 197 | |
| 198 if (exp_key.Valid()) { | |
| 199 if (PreReadShouldRun()) { | |
|
Sigurður Ásgeirsson
2011/08/25 17:44:14
nit: the code would look a little cleaner with thi
chrisha
2011/08/25 19:39:17
Done.
| |
| 200 bool exp_is_live = false; | |
| 201 DWORD coin_toss = 0; | |
| 202 | |
| 203 // Coin already tossed? | |
| 204 if (exp_key.ReadValueDW(kPreReadRegistryValue, &coin_toss) == | |
| 205 ERROR_SUCCESS) { | |
| 206 exp_is_live = true; | |
| 207 } else { | |
| 208 // Coin not tossed? Toss it, and save the value to the registry. | |
| 209 coin_toss = base::RandInt(0, 1); | |
| 210 DCHECK(coin_toss == 0 || coin_toss == 1); | |
| 211 if (exp_key.WriteValue(kPreReadRegistryValue, coin_toss) == | |
| 212 ERROR_SUCCESS) { | |
| 213 exp_is_live = true; | |
| 214 } | |
| 215 } | |
| 216 | |
| 217 // If the experiment is running, indicate it to chrome.dll via an | |
| 218 // environment variable. | |
| 219 if (exp_is_live) { | |
| 220 pre_read = coin_toss; | |
| 221 scoped_ptr<base::Environment> env(base::Environment::Create()); | |
| 222 env->SetVar(chrome::kPreReadEnvironmentVariable, | |
| 223 pre_read ? "1" : "0"); | |
| 224 } | |
| 225 } else { | |
| 226 // The experiment is no longer running. Remove the registry key | |
| 227 // storing the coin toss. | |
| 228 exp_key.DeleteValue(kPreReadRegistryValue); | |
| 229 } | |
| 230 | |
| 231 exp_key.Close(); | |
| 232 } | |
| 233 | |
| 141 if (pre_read) { | 234 if (pre_read) { |
| 142 TRACE_EVENT_BEGIN_ETW("PreReadImage", 0, ""); | 235 TRACE_EVENT_BEGIN_ETW("PreReadImage", 0, ""); |
| 143 file_util::PreReadImage(dir->c_str(), pre_read_size, pre_read_step_size); | 236 file_util::PreReadImage(dir->c_str(), pre_read_size, pre_read_step_size); |
| 144 TRACE_EVENT_END_ETW("PreReadImage", 0, ""); | 237 TRACE_EVENT_END_ETW("PreReadImage", 0, ""); |
| 145 } | 238 } |
| 146 } | 239 } |
| 147 #endif // NDEBUG | 240 #endif // NDEBUG |
| 148 #endif // WIN_DISABLE_PREREAD | 241 #endif // WIN_DISABLE_PREREAD |
| 149 | 242 |
| 150 return ::LoadLibraryExW(dir->c_str(), NULL, | 243 return ::LoadLibraryExW(dir->c_str(), NULL, |
| 151 LOAD_WITH_ALTERED_SEARCH_PATH); | 244 LOAD_WITH_ALTERED_SEARCH_PATH); |
| 152 } | 245 } |
| 153 | 246 |
| 154 void RecordDidRun(const std::wstring& dll_path) { | 247 void RecordDidRun(const std::wstring& dll_path) { |
| 155 bool system_level = !InstallUtil::IsPerUserInstall(dll_path.c_str()); | 248 bool system_level = !InstallUtil::IsPerUserInstall(dll_path.c_str()); |
| 156 GoogleUpdateSettings::UpdateDidRunState(true, system_level); | 249 GoogleUpdateSettings::UpdateDidRunState(true, system_level); |
| 157 } | 250 } |
| 158 | 251 |
| 159 void ClearDidRun(const std::wstring& dll_path) { | 252 void ClearDidRun(const std::wstring& dll_path) { |
| 160 bool system_level = !InstallUtil::IsPerUserInstall(dll_path.c_str()); | 253 bool system_level = !InstallUtil::IsPerUserInstall(dll_path.c_str()); |
| 161 GoogleUpdateSettings::UpdateDidRunState(false, system_level); | 254 GoogleUpdateSettings::UpdateDidRunState(false, system_level); |
| 162 } | 255 } |
| 163 | 256 |
| 164 } | 257 } // namespace |
| 165 //============================================================================= | 258 //============================================================================= |
| 166 | 259 |
| 167 MainDllLoader::MainDllLoader() : dll_(NULL) { | 260 MainDllLoader::MainDllLoader() : dll_(NULL) { |
| 168 } | 261 } |
| 169 | 262 |
| 170 MainDllLoader::~MainDllLoader() { | 263 MainDllLoader::~MainDllLoader() { |
| 171 } | 264 } |
| 172 | 265 |
| 173 // Loading chrome is an interesting affair. First we try loading from the | 266 // Loading chrome is an interesting affair. First we try loading from the |
| 174 // current directory to support run-what-you-compile and other development | 267 // current directory to support run-what-you-compile and other development |
| 175 // scenarios. | 268 // scenarios. |
| 176 // If that fails then we look at the --chrome-version command line flag followed | 269 // If that fails then we look at the --chrome-version command line flag followed |
| 177 // by the 'CHROME_VERSION' env variable to determine if we should stick with an | 270 // by the 'CHROME_VERSION' env variable to determine if we should stick with an |
| 178 // older dll version even if a new one is available to support upgrade-in-place | 271 // older dll version even if a new one is available to support upgrade-in-place |
| 179 // scenarios. | 272 // scenarios. |
| 180 // If that fails then finally we look at the registry which should point us | 273 // If that fails then finally we look at the registry which should point us |
| 181 // to the latest version. This is the expected path for the first chrome.exe | 274 // to the latest version. This is the expected path for the first chrome.exe |
| 182 // browser instance in an installed build. | 275 // browser instance in an installed build. |
| 183 HMODULE MainDllLoader::Load(std::wstring* out_version, std::wstring* out_file) { | 276 HMODULE MainDllLoader::Load(std::wstring* out_version, std::wstring* out_file) { |
| 184 std::wstring dir(GetExecutablePath()); | 277 std::wstring dir(GetExecutablePath()); |
| 185 *out_file = dir; | 278 *out_file = dir; |
| 186 HMODULE dll = LoadChromeWithDirectory(out_file); | 279 // 'GetRegistryPath()' was added in support of PreRead experiment. |
|
Sigurður Ásgeirsson
2011/08/25 17:44:14
I don't think you particularly need to explain thi
chrisha
2011/08/25 19:39:17
Done.
| |
| 280 HMODULE dll = LoadChromeWithDirectory(GetRegistryPath(), out_file); | |
| 187 if (dll) | 281 if (dll) |
| 188 return dll; | 282 return dll; |
| 189 | 283 |
| 190 std::wstring version_string; | 284 std::wstring version_string; |
| 191 scoped_ptr<Version> version; | 285 scoped_ptr<Version> version; |
| 192 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); | 286 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); |
| 193 if (cmd_line.HasSwitch(switches::kChromeVersion)) { | 287 if (cmd_line.HasSwitch(switches::kChromeVersion)) { |
| 194 version_string = cmd_line.GetSwitchValueNative(switches::kChromeVersion); | 288 version_string = cmd_line.GetSwitchValueNative(switches::kChromeVersion); |
| 195 version.reset(Version::GetVersionFromString(WideToASCII(version_string))); | 289 version.reset(Version::GetVersionFromString(WideToASCII(version_string))); |
| 196 | 290 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 215 // this by building a Version object to avoid harming normal case startup | 309 // this by building a Version object to avoid harming normal case startup |
| 216 // time. | 310 // time. |
| 217 version_string.clear(); | 311 version_string.clear(); |
| 218 GetVersion(dir.c_str(), reg_path.c_str(), &version_string); | 312 GetVersion(dir.c_str(), reg_path.c_str(), &version_string); |
| 219 } | 313 } |
| 220 | 314 |
| 221 if (version.get() || !version_string.empty()) { | 315 if (version.get() || !version_string.empty()) { |
| 222 *out_file = dir; | 316 *out_file = dir; |
| 223 *out_version = version_string; | 317 *out_version = version_string; |
| 224 out_file->append(*out_version).append(L"\\"); | 318 out_file->append(*out_version).append(L"\\"); |
| 225 dll = LoadChromeWithDirectory(out_file); | 319 // 'GetRegistryPath()' was added in support of PreRead experiment. |
| 320 dll = LoadChromeWithDirectory(GetRegistryPath(), out_file); | |
| 226 if (!dll) { | 321 if (!dll) { |
| 227 LOG(ERROR) << "Failed to load Chrome DLL from " << out_file; | 322 LOG(ERROR) << "Failed to load Chrome DLL from " << out_file; |
| 228 } | 323 } |
| 229 return dll; | 324 return dll; |
| 230 } else { | 325 } else { |
| 231 LOG(ERROR) << "Could not get Chrome DLL version."; | 326 LOG(ERROR) << "Could not get Chrome DLL version."; |
| 232 return NULL; | 327 return NULL; |
| 233 } | 328 } |
| 234 } | 329 } |
| 235 | 330 |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 308 } | 403 } |
| 309 }; | 404 }; |
| 310 | 405 |
| 311 MainDllLoader* MakeMainDllLoader() { | 406 MainDllLoader* MakeMainDllLoader() { |
| 312 #if defined(GOOGLE_CHROME_BUILD) | 407 #if defined(GOOGLE_CHROME_BUILD) |
| 313 return new ChromeDllLoader(); | 408 return new ChromeDllLoader(); |
| 314 #else | 409 #else |
| 315 return new ChromiumDllLoader(); | 410 return new ChromiumDllLoader(); |
| 316 #endif | 411 #endif |
| 317 } | 412 } |
| OLD | NEW |