Chromium Code Reviews| Index: chrome/app/client_util.cc |
| =================================================================== |
| --- chrome/app/client_util.cc (revision 98219) |
| +++ chrome/app/client_util.cc (working copy) |
| @@ -11,6 +11,7 @@ |
| #include "base/file_util.h" |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| +#include "base/rand_util.h" // For PreRead experiment. |
| #include "base/string_util.h" |
| #include "base/utf_string_conversions.h" |
| #include "base/version.h" |
| @@ -83,10 +84,51 @@ |
| return true; |
| } |
| +#if defined(OS_WIN) |
| +// These constants are used by the PreRead experiment. |
| +const wchar_t kPreReadRegistryValue[] = L"PreReadExperimentGroup"; |
| +const int kPreReadExpiryYear = 2012; |
| +const int kPreReadExpiryMonth = 1; |
| +const int kPreReadExpiryDay = 1; |
| + |
| +bool PreReadShouldRun() { |
| + base::Time::Exploded exploded = { 0 }; |
| + exploded.year = kPreReadExpiryYear; |
| + exploded.month = kPreReadExpiryMonth; |
| + exploded.day_of_month = kPreReadExpiryDay; |
| + |
| + base::Time expiration_time = base::Time::FromLocalExploded(exploded); |
| + |
| + // 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,
|
| + base::Time build_time; |
| + const char* kDateTime = __DATE__ " " __TIME__; |
| + bool result = base::Time::FromString(kDateTime, &build_time); |
| + DCHECK(result); |
| + |
| + // If the experiment is expired, don't run it. |
| + if (build_time > expiration_time) |
| + return false; |
| + |
| +#if defined(GOOGLE_CHROME_BUILD) |
| + // The experiment should only run on canary and dev. |
| + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); |
| + std::wstring channel; |
| + if (!dist->GetChromeChannel(&channel)) |
| + return false; |
| + 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
|
| +#else |
| + // If we're running Chromium, we have no concept of channel so we |
| + // run the experiment. |
| + return true; |
| +#endif |
| +} |
| +#endif |
| + |
| // Expects that |dir| has a trailing backslash. |dir| is modified so it |
| // contains the full path that was tried. Caller must check for the return |
| // value not being null to determine if this path contains a valid dll. |
| -HMODULE LoadChromeWithDirectory(std::wstring* dir) { |
| +HMODULE LoadChromeWithDirectory(const std::wstring& reg_key, // For PreRead. |
| + std::wstring* dir) { |
| ::SetCurrentDirectoryW(dir->c_str()); |
| const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); |
| #ifdef _WIN64 |
| @@ -138,6 +180,57 @@ |
| key.Close(); |
| } |
| + // The PreRead experiment is unable to use the standard FieldTrial |
| + // 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.
|
| + // chrome.dll. As such, we use a custom approach. If the experiment is |
| + // running (not expired, and we're running a version of chrome from an |
| + // appropriate channel) then we look to the registry for the experiment |
| + // group. If it is not found, we toss a coin and persist the result in the |
| + // registry. The coin-toss value is communicated to chrome.dll via an |
| + // environment variable, which indicates to chrome.dll that the experiment |
| + // is running, causing it to report sub-histogram results. If the experiment |
| + // is expired or not running, the registry key is removed. |
| + |
| + base::win::RegKey exp_key( |
| + HKEY_CURRENT_USER, reg_key.c_str(), |
| + KEY_CREATE_SUB_KEY | KEY_QUERY_VALUE | KEY_SET_VALUE); |
| + |
| + if (exp_key.Valid()) { |
| + 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.
|
| + bool exp_is_live = false; |
| + DWORD coin_toss = 0; |
| + |
| + // Coin already tossed? |
| + if (exp_key.ReadValueDW(kPreReadRegistryValue, &coin_toss) == |
| + ERROR_SUCCESS) { |
| + exp_is_live = true; |
| + } else { |
| + // Coin not tossed? Toss it, and save the value to the registry. |
| + coin_toss = base::RandInt(0, 1); |
| + DCHECK(coin_toss == 0 || coin_toss == 1); |
| + if (exp_key.WriteValue(kPreReadRegistryValue, coin_toss) == |
| + ERROR_SUCCESS) { |
| + exp_is_live = true; |
| + } |
| + } |
| + |
| + // If the experiment is running, indicate it to chrome.dll via an |
| + // environment variable. |
| + if (exp_is_live) { |
| + pre_read = coin_toss; |
| + scoped_ptr<base::Environment> env(base::Environment::Create()); |
| + env->SetVar(chrome::kPreReadEnvironmentVariable, |
| + pre_read ? "1" : "0"); |
| + } |
| + } else { |
| + // The experiment is no longer running. Remove the registry key |
| + // storing the coin toss. |
| + exp_key.DeleteValue(kPreReadRegistryValue); |
| + } |
| + |
| + exp_key.Close(); |
| + } |
| + |
| if (pre_read) { |
| TRACE_EVENT_BEGIN_ETW("PreReadImage", 0, ""); |
| file_util::PreReadImage(dir->c_str(), pre_read_size, pre_read_step_size); |
| @@ -161,7 +254,7 @@ |
| GoogleUpdateSettings::UpdateDidRunState(false, system_level); |
| } |
| -} |
| +} // namespace |
| //============================================================================= |
| MainDllLoader::MainDllLoader() : dll_(NULL) { |
| @@ -183,7 +276,8 @@ |
| HMODULE MainDllLoader::Load(std::wstring* out_version, std::wstring* out_file) { |
| std::wstring dir(GetExecutablePath()); |
| *out_file = dir; |
| - HMODULE dll = LoadChromeWithDirectory(out_file); |
| + // '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.
|
| + HMODULE dll = LoadChromeWithDirectory(GetRegistryPath(), out_file); |
| if (dll) |
| return dll; |
| @@ -222,7 +316,8 @@ |
| *out_file = dir; |
| *out_version = version_string; |
| out_file->append(*out_version).append(L"\\"); |
| - dll = LoadChromeWithDirectory(out_file); |
| + // 'GetRegistryPath()' was added in support of PreRead experiment. |
| + dll = LoadChromeWithDirectory(GetRegistryPath(), out_file); |
| if (!dll) { |
| LOG(ERROR) << "Failed to load Chrome DLL from " << out_file; |
| } |