diff options
-rw-r--r-- | chrome/app/chromium_strings.grd | 3 | ||||
-rw-r--r-- | chrome/app/google_chrome_strings.grd | 3 | ||||
-rw-r--r-- | chrome/browser/first_run/first_run_win.cc | 26 | ||||
-rw-r--r-- | chrome/chrome_common.gypi | 1 | ||||
-rw-r--r-- | chrome/common/attrition_experiments.h | 31 | ||||
-rw-r--r-- | chrome/installer/setup/setup_main.cc | 8 | ||||
-rw-r--r-- | chrome/installer/util/browser_distribution.cc | 6 | ||||
-rw-r--r-- | chrome/installer/util/browser_distribution.h | 29 | ||||
-rw-r--r-- | chrome/installer/util/chrome_frame_distribution.h | 34 | ||||
-rw-r--r-- | chrome/installer/util/chromium_binaries_distribution.h | 36 | ||||
-rw-r--r-- | chrome/installer/util/google_chrome_distribution.cc | 183 | ||||
-rw-r--r-- | chrome/installer/util/google_chrome_distribution.h | 56 | ||||
-rw-r--r-- | chrome/installer/util/google_chrome_distribution_dummy.cc | 7 | ||||
-rw-r--r-- | chrome/installer/util/util_constants.cc | 3 | ||||
-rw-r--r-- | chrome/installer/util/util_constants.h | 3 |
15 files changed, 295 insertions, 134 deletions
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd index 2729f0b..d304a72 100644 --- a/chrome/app/chromium_strings.grd +++ b/chrome/app/chromium_strings.grd @@ -474,6 +474,9 @@ be available for now. --> <message name="IDS_TRY_TOAST_HEADING4" desc="Top line of the try-chrome-again dialog"> Chromium has been updated, but you haven't used it for at least 30 days. </message> + <message name="IDS_TRY_TOAST_HEADING_SKYPE" desc="Top line of the try-chrome-again dialog"> + Chromium lets you click a phone number on the web and call it with Skype! + </message> <message name="IDS_TRY_TOAST_TRY_OPT" desc="First option radio button on the dialog to try chrome"> Try it out (already installed) </message> diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd index de3b6c0..717d958 100644 --- a/chrome/app/google_chrome_strings.grd +++ b/chrome/app/google_chrome_strings.grd @@ -480,6 +480,9 @@ Chrome supports. --> <message name="IDS_TRY_TOAST_HEADING4" desc="Top line of the try-chrome-again dialog"> Google Chrome has been updated, but you haven't used it for at least 30 days. </message> + <message name="IDS_TRY_TOAST_HEADING_SKYPE" desc="Top line of the try-chrome-again dialog"> + Google Chrome lets you click a phone number on the web and call it with Skype! + </message> <message name="IDS_TRY_TOAST_TRY_OPT" desc="First option radio button on the dialog to try chrome"> Try it out (already installed) </message> diff --git a/chrome/browser/first_run/first_run_win.cc b/chrome/browser/first_run/first_run_win.cc index db6d03b..8e8628f 100644 --- a/chrome/browser/first_run/first_run_win.cc +++ b/chrome/browser/first_run/first_run_win.cc @@ -660,20 +660,20 @@ class TryChromeDialog : public views::ButtonListener, // First row views. layout->StartRow(0, 0); layout->AddView(icon); - // The heading has two flavors of text, the alt one features extensions but - // we only use it in the US until some international issues are fixed. - const std::string app_locale = g_browser_process->GetApplicationLocale(); - int heading_id; - switch (version_) { - case 0: heading_id = IDS_TRY_TOAST_HEADING; break; - case 1: heading_id = IDS_TRY_TOAST_HEADING2; break; - case 2: heading_id = IDS_TRY_TOAST_HEADING3; break; - case 3: heading_id = IDS_TRY_TOAST_HEADING4; break; - default: - NOTREACHED() << "Cannot determine which headline to show."; - return Upgrade::TD_DIALOG_ERROR; + + // Find out what experiment we are conducting. + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); + if (!dist) { + NOTREACHED() << "Cannot determine browser distribution"; + return Upgrade::TD_DIALOG_ERROR; + } + BrowserDistribution::UserExperiment experiment; + if (!dist->GetExperimentDetails(&experiment, version_) || + !experiment.heading) { + NOTREACHED() << "Cannot determine which headline to show."; + return Upgrade::TD_DIALOG_ERROR; } - string16 heading = l10n_util::GetStringUTF16(heading_id); + string16 heading = l10n_util::GetStringUTF16(experiment.heading); views::Label* label = new views::Label(heading); label->SetFont(rb.GetFont(ResourceBundle::MediumBoldFont)); label->SetMultiLine(true); diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index 84b38e3..4e7dd6b 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi @@ -27,6 +27,7 @@ 'common/about_handler.h', 'common/app_mode_common_mac.h', 'common/app_mode_common_mac.mm', + 'common/attrition_experiments.h', 'common/auto_start_linux.cc', 'common/auto_start_linux.h', 'common/autofill_messages.h', diff --git a/chrome/common/attrition_experiments.h b/chrome/common/attrition_experiments.h new file mode 100644 index 0000000..7595588 --- /dev/null +++ b/chrome/common/attrition_experiments.h @@ -0,0 +1,31 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_COMMON_ATTRITION_EXPERIMENTS_H_ +#define CHROME_COMMON_ATTRITION_EXPERIMENTS_H_ +#pragma once + +#include "grit/chromium_strings.h" + +namespace attrition_experiments { + +// A list of all the IDs we use for the attrition experiments. +enum Experiment { + kEnUs1 = IDS_TRY_TOAST_HEADING, + kEnUs2 = IDS_TRY_TOAST_HEADING2, + kEnUs3 = IDS_TRY_TOAST_HEADING3, + kEnUs4 = IDS_TRY_TOAST_HEADING4, + kSkype1 = IDS_TRY_TOAST_HEADING_SKYPE, +}; + +// This is used to match against locale and brands, and represents any +// locale/brand. +const wchar_t kAll[] = L"*"; + +// A comma-separated list of brand codes that are associated with Skype. +const wchar_t kSkype[] = L"SKPC,SKPG,SKPH,SKPI,SKPL,SKPM,SKPN"; + +} // namespace + +#endif // CHROME_COMMON_ATTRITION_EXPERIMENTS_H_ diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc index f773614..b5dcbc0 100644 --- a/chrome/installer/setup/setup_main.cc +++ b/chrome/installer/setup/setup_main.cc @@ -637,6 +637,7 @@ installer::InstallStatus InstallProductsHelper( } } } + // There might be an experiment (for upgrade usually) that needs to happen. // An experiment's outcome can include chrome's uninstallation. If that is // the case we would not do that directly at this point but in another @@ -882,6 +883,8 @@ bool HandleNonInstallCmdLineOptions(const InstallationState& original_state, int flavor = -1; base::StringToInt(cmd_line.GetSwitchValueNative( installer::switches::kInactiveUserToast), &flavor); + std::string experiment_group = + cmd_line.GetSwitchValueASCII(installer::switches::kExperimentGroup); DCHECK_NE(-1, flavor); if (flavor == -1) { *exit_code = installer::UNKNOWN_STATUS; @@ -890,8 +893,9 @@ bool HandleNonInstallCmdLineOptions(const InstallationState& original_state, for (size_t i = 0; i < products.size(); ++i) { const Product* product = products[i]; BrowserDistribution* browser_dist = product->distribution(); - browser_dist->InactiveUserToastExperiment(flavor, *product, - installer_state->target_path()); + browser_dist->InactiveUserToastExperiment(flavor, + ASCIIToUTF16(experiment_group), + *product, installer_state->target_path()); } } } else if (cmd_line.HasSwitch(installer::switches::kSystemLevelToast)) { diff --git a/chrome/installer/util/browser_distribution.cc b/chrome/installer/util/browser_distribution.cc index 95c0139..8a1ed71 100644 --- a/chrome/installer/util/browser_distribution.cc +++ b/chrome/installer/util/browser_distribution.cc @@ -220,6 +220,11 @@ void BrowserDistribution::UpdateInstallStatus(bool system_install, installer::InstallStatus install_status) { } +bool BrowserDistribution::GetExperimentDetails( + UserExperiment* experiment, int flavor) { + return false; +} + void BrowserDistribution::LaunchUserExperiment( const FilePath& setup_path, installer::InstallStatus status, const Version& version, const installer::Product& installation, @@ -228,6 +233,7 @@ void BrowserDistribution::LaunchUserExperiment( void BrowserDistribution::InactiveUserToastExperiment(int flavor, + const std::wstring& experiment_group, const installer::Product& installation, const FilePath& application_path) { } diff --git a/chrome/installer/util/browser_distribution.h b/chrome/installer/util/browser_distribution.h index c20888b..c766a8a 100644 --- a/chrome/installer/util/browser_distribution.h +++ b/chrome/installer/util/browser_distribution.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -39,6 +39,19 @@ class BrowserDistribution { NUM_TYPES }; + // A struct for communicating what a UserExperiment contains. In these + // experiments we show toasts to the user if they are inactive for a certain + // amount of time. + struct UserExperiment { + std::wstring prefix; // The experiment code prefix for this experiment, + // also known as the 'TV' part in 'TV80'. + int flavor; // The flavor index for this experiment. + int heading; // The heading resource ID to use for this experiment. + int control_group; // Size of the control group (in percentages). Control + // group is the group that qualifies for the + // experiment but does not participate. + }; + static BrowserDistribution* GetDistribution(); static BrowserDistribution* GetSpecificDistribution(Type type); @@ -95,17 +108,25 @@ class BrowserDistribution { installer::ArchiveType archive_type, installer::InstallStatus install_status); + // Gets the experiment details for a given language-brand combo. If |flavor| + // is -1, then a flavor will be selected at random. |experiment| is the struct + // you want to write the experiment information to. Returns false if no + // experiment details could be gathered. + virtual bool GetExperimentDetails(UserExperiment* experiment, int flavor); + // After an install or upgrade the user might qualify to participate in an // experiment. This function determines if the user qualifies and if so it // sets the wheels in motion or in simple cases does the experiment itself. virtual void LaunchUserExperiment(const FilePath& setup_path, - installer::InstallStatus status, - const Version& version, const installer::Product& installation, - bool system_level); + installer::InstallStatus status, + const Version& version, + const installer::Product& installation, + bool system_level); // The user has qualified for the inactive user toast experiment and this // function just performs it. virtual void InactiveUserToastExperiment(int flavor, + const std::wstring& experiment_group, const installer::Product& installation, const FilePath& application_path); diff --git a/chrome/installer/util/chrome_frame_distribution.h b/chrome/installer/util/chrome_frame_distribution.h index 8f6150e..dca7086 100644 --- a/chrome/installer/util/chrome_frame_distribution.h +++ b/chrome/installer/util/chrome_frame_distribution.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -21,39 +21,39 @@ class MasterPreferences; class ChromeFrameDistribution : public BrowserDistribution { public: - virtual std::wstring GetAppGuid(); + virtual std::wstring GetAppGuid() OVERRIDE; - virtual std::wstring GetApplicationName(); + virtual std::wstring GetApplicationName() OVERRIDE; - virtual std::wstring GetAlternateApplicationName(); + virtual std::wstring GetAlternateApplicationName() OVERRIDE; - virtual std::wstring GetInstallSubDir(); + virtual std::wstring GetInstallSubDir() OVERRIDE; - virtual std::wstring GetPublisherName(); + virtual std::wstring GetPublisherName() OVERRIDE; - virtual std::wstring GetAppDescription(); + virtual std::wstring GetAppDescription() OVERRIDE; - virtual std::wstring GetLongAppDescription(); + virtual std::wstring GetLongAppDescription() OVERRIDE; - virtual std::string GetSafeBrowsingName(); + virtual std::string GetSafeBrowsingName() OVERRIDE; - virtual std::wstring GetStateKey(); + virtual std::wstring GetStateKey() OVERRIDE; - virtual std::wstring GetStateMediumKey(); + virtual std::wstring GetStateMediumKey() OVERRIDE; - virtual std::wstring GetStatsServerURL(); + virtual std::wstring GetStatsServerURL() OVERRIDE; - virtual std::wstring GetUninstallLinkName(); + virtual std::wstring GetUninstallLinkName() OVERRIDE; - virtual std::wstring GetUninstallRegPath(); + virtual std::wstring GetUninstallRegPath() OVERRIDE; - virtual std::wstring GetVersionKey(); + virtual std::wstring GetVersionKey() OVERRIDE; - virtual bool CanSetAsDefault(); + virtual bool CanSetAsDefault() OVERRIDE; virtual void UpdateInstallStatus(bool system_install, installer::ArchiveType archive_type, - installer::InstallStatus install_status); + installer::InstallStatus install_status) OVERRIDE; protected: friend class BrowserDistribution; diff --git a/chrome/installer/util/chromium_binaries_distribution.h b/chrome/installer/util/chromium_binaries_distribution.h index 6ee0c4f..9fe7095 100644 --- a/chrome/installer/util/chromium_binaries_distribution.h +++ b/chrome/installer/util/chromium_binaries_distribution.h @@ -14,41 +14,41 @@ class ChromiumBinariesDistribution : public BrowserDistribution { public: - virtual std::wstring GetAppGuid(); + virtual std::wstring GetAppGuid() OVERRIDE; - virtual std::wstring GetApplicationName(); + virtual std::wstring GetApplicationName() OVERRIDE; - virtual std::wstring GetAppShortCutName(); + virtual std::wstring GetAppShortCutName() OVERRIDE; - virtual std::wstring GetAlternateApplicationName(); + virtual std::wstring GetAlternateApplicationName() OVERRIDE; - virtual std::wstring GetBrowserAppId(); + virtual std::wstring GetBrowserAppId() OVERRIDE; - virtual std::wstring GetInstallSubDir(); + virtual std::wstring GetInstallSubDir() OVERRIDE; - virtual std::wstring GetPublisherName(); + virtual std::wstring GetPublisherName() OVERRIDE; - virtual std::wstring GetAppDescription(); + virtual std::wstring GetAppDescription() OVERRIDE; - virtual std::wstring GetLongAppDescription(); + virtual std::wstring GetLongAppDescription() OVERRIDE; - virtual std::string GetSafeBrowsingName(); + virtual std::string GetSafeBrowsingName() OVERRIDE; - virtual std::wstring GetStateKey(); + virtual std::wstring GetStateKey() OVERRIDE; - virtual std::wstring GetStateMediumKey(); + virtual std::wstring GetStateMediumKey() OVERRIDE; - virtual std::wstring GetUninstallLinkName(); + virtual std::wstring GetUninstallLinkName() OVERRIDE; - virtual std::wstring GetUninstallRegPath(); + virtual std::wstring GetUninstallRegPath() OVERRIDE; - virtual std::wstring GetVersionKey(); + virtual std::wstring GetVersionKey() OVERRIDE; - virtual bool CanSetAsDefault(); + virtual bool CanSetAsDefault() OVERRIDE; - virtual int GetIconIndex(); + virtual int GetIconIndex() OVERRIDE; - virtual bool GetChromeChannel(std::wstring* channel); + virtual bool GetChromeChannel(std::wstring* channel) OVERRIDE; protected: friend class BrowserDistribution; diff --git a/chrome/installer/util/google_chrome_distribution.cc b/chrome/installer/util/google_chrome_distribution.cc index a089735..da9eef4 100644 --- a/chrome/installer/util/google_chrome_distribution.cc +++ b/chrome/installer/util/google_chrome_distribution.cc @@ -17,11 +17,13 @@ #include "base/path_service.h" #include "base/rand_util.h" #include "base/scoped_ptr.h" +#include "base/string_split.h" #include "base/string_number_conversions.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "base/win/registry.h" #include "base/win/windows_version.h" +#include "chrome/common/attrition_experiments.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/json_value_serializer.h" #include "chrome/common/pref_names.h" @@ -46,29 +48,15 @@ const wchar_t kChromeGuid[] = L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; const wchar_t kBrowserAppId[] = L"Chrome"; // The following strings are the possible outcomes of the toast experiment -// as recorded in the |client| field. Previously the groups used "TSxx" but -// the data captured is not valid. -const wchar_t kToastExpControlGroup[] = L"T%lc01"; -const wchar_t kToastExpCancelGroup[] = L"T%lc02"; -const wchar_t kToastExpUninstallGroup[] = L"T%lc04"; -const wchar_t kToastExpTriesOkGroup[] = L"T%lc18"; -const wchar_t kToastExpTriesErrorGroup[] = L"T%lc28"; -const wchar_t kToastActiveGroup[] = L"T%lc40"; -const wchar_t kToastUDDirFailure[] = L"T%lc40"; -const wchar_t kToastExpBaseGroup[] = L"T%lc80"; - -// Generates the actual group string that gets written in the registry. -// |group| is one of the above kToast* strings and |flavor| is a number -// from 0 to 3. -// -// The big experiment in Dec 2009 used TGxx and THxx. -// The big experiment in Feb 2010 used TKxx and TLxx. -// The big experiment in Apr 2010 used TMxx and TNxx. -// The big experiment in Oct 2010 (current) uses TVxx TWxx TXxx TYxx. -std::wstring GetExperimentGroup(const wchar_t* group, int flavor) { - wchar_t c = flavor < 4 ? L'V' + flavor : L'Z'; - return StringPrintf(group, c); -} +// as recorded in the |client| field. +const wchar_t kToastExpControlGroup[] = L"01"; +const wchar_t kToastExpCancelGroup[] = L"02"; +const wchar_t kToastExpUninstallGroup[] = L"04"; +const wchar_t kToastExpTriesOkGroup[] = L"18"; +const wchar_t kToastExpTriesErrorGroup[] = L"28"; +const wchar_t kToastActiveGroup[] = L"40"; +const wchar_t kToastUDDirFailure[] = L"40"; +const wchar_t kToastExpBaseGroup[] = L"80"; // Substitute the locale parameter in uninstall URL with whatever // Google Update tells us is the locale. In case we fail to find @@ -130,18 +118,14 @@ int GetDirectoryWriteAgeInHours(const wchar_t* path) { return (now_time - dir_time); } -// Launches setup.exe (located at |setup_path|) with switch --|flag|=|value|. +// Launches setup.exe (located at |setup_path|) with |cmd_line|. // If system_level_toast is true, appends --system-level-toast. // If handle to experiment result key was given at startup, re-add it. // Does not wait for the process to terminate. -bool LaunchSetup(const FilePath& setup_path, const std::string& flag, - int value, bool system_level_toast) { - CommandLine new_cmd_line(setup_path); - new_cmd_line.AppendSwitchASCII(flag, base::IntToString(value)); - +bool LaunchSetup(CommandLine cmd_line, bool system_level_toast) { // Re-add the system level toast flag. if (system_level_toast) { - new_cmd_line.AppendSwitch(installer::switches::kSystemLevelToast); + cmd_line.AppendSwitch(installer::switches::kSystemLevelToast); // Re-add the toast result key. We need to do this because Setup running as // system passes the key to Setup running as user, but that child process @@ -151,16 +135,16 @@ bool LaunchSetup(const FilePath& setup_path, const std::string& flag, std::string key(installer::switches::kToastResultsKey); std::string toast_key = current_cmd_line.GetSwitchValueASCII(key); if (!toast_key.empty()) { - new_cmd_line.AppendSwitchASCII(key, toast_key); + cmd_line.AppendSwitchASCII(key, toast_key); // Use handle inheritance to make sure the duplicated toast results key // gets inherited by the child process. return base::LaunchAppWithHandleInheritance( - new_cmd_line.command_line_string(), false, false, NULL); + cmd_line.command_line_string(), false, false, NULL); } } - return base::LaunchApp(new_cmd_line.command_line_string(), + return base::LaunchApp(cmd_line.command_line_string(), false, false, NULL); } @@ -548,6 +532,92 @@ void SetClient(std::wstring experiment_group, bool last_write) { } } +bool GoogleChromeDistribution::GetExperimentDetails( + UserExperiment* experiment, int flavor) { + // Maximum number of experiment flavors we support. + const int kMax = 4; + // This struct determines which experiment flavors we show for each locale and + // brand. + // + // The big experiment in Dec 2009 used TGxx and THxx. + // The big experiment in Feb 2010 used TKxx and TLxx. + // The big experiment in Apr 2010 used TMxx and TNxx. + // The big experiment in Oct 2010 used TVxx TWxx TXxx TYxx. + // The big experiment in Feb 2011 used SJxx SKxx SLxx SMxx. + using namespace attrition_experiments; + static const struct UserExperimentDetails { + const wchar_t* locale; // Locale to show this experiment for (* for all). + const wchar_t* brands; // Brand codes show this experiment for (* for all). + int control_group; // Size of the control group, in percentages. + const wchar_t prefix1; // The first letter for the experiment code. + const wchar_t prefix2; // The second letter for the experiment code. This + // will be incremented by one for each additional + // experiment flavor beyond the first. + int flavors; // Numbers of flavors for this experiment. Should + // always be positive and never exceed the number + // of headings (below). + int headings[kMax]; // A list of IDs per experiment. 0 == no heading. + } kExperimentFlavors[] = { + // First in this order are the brand specific ones. + {L"en-US", kSkype, 1, L'Z', L'A', 1, { kSkype1, 0, 0, 0 } }, + // And then we have catch-alls, like en-US (all brands). + {L"en-US", kAll, 1, L'T', L'V', 4, { kEnUs1, kEnUs2, kEnUs3, kEnUs4} }, + // Japan has two experiments, same IDs as en-US but translated differently. + {L"jp", kAll, 1, L'T', L'V', 2, { kEnUs1, kEnUs2, 0, 0} }, + }; + + std::wstring locale; + std::wstring brand; + + if (!GoogleUpdateSettings::GetLanguage(&locale)) + locale = L"en-US"; + if (!GoogleUpdateSettings::GetBrand(&brand)) + return false; + + for (int i = 0; i < arraysize(kExperimentFlavors); ++i) { + // A maximum of four flavors is supported at the moment. + DCHECK_LE(kExperimentFlavors[i].flavors, kMax); + DCHECK_GT(kExperimentFlavors[i].flavors, 0); + // Make sure each experiment has valid headings. + for (int f = 0; f < kMax; ++f) { + if (f < kExperimentFlavors[i].flavors) + DCHECK_GT(kExperimentFlavors[i].headings[f], 0); + else + DCHECK_EQ(kExperimentFlavors[i].headings[f], 0); + } + // Make sure we don't overflow on the second letter of the experiment code. + DCHECK(kExperimentFlavors[i].prefix2 + + kExperimentFlavors[i].flavors - 1 <= 'Z'); + + if (kExperimentFlavors[i].locale != locale && + kExperimentFlavors[i].locale != L"*") + continue; + + std::vector<std::wstring> brand_codes; + base::SplitString(kExperimentFlavors[i].brands, L',', &brand_codes); + if (brand_codes.empty()) + return false; + for (std::vector<std::wstring>::iterator it = brand_codes.begin(); + it != brand_codes.end(); ++it) { + if (*it != brand && *it != L"*") + continue; + + // We have found our match. + if (flavor < 0) + flavor = base::RandInt(0, kExperimentFlavors[i].flavors - 1); + experiment->flavor = flavor; + experiment->heading = kExperimentFlavors[i].headings[flavor]; + experiment->control_group = kExperimentFlavors[i].control_group; + experiment->prefix.resize(2); + experiment->prefix[0] = kExperimentFlavors[i].prefix1; + experiment->prefix[1] = kExperimentFlavors[i].prefix2 + flavor; + return true; + } + } + + return false; +} + // Currently we only have one experiment: the inactive user toast. Which only // applies for users doing upgrades. // @@ -575,19 +645,15 @@ void GoogleChromeDistribution::LaunchUserExperiment( } } - // This ends up being processed by ShowTryChromeDialog to show different - // experiments. Only run the experiment in en-US and ja. - int flavor = 0; - std::wstring language; - if (GoogleUpdateSettings::GetLanguage(&language)) { - if (language == L"en-US") { - // en-US has four different toasts. - flavor = base::RandInt(0, 3); - } else if (language == L"ja") { - // ja has three different toasts. - flavor = base::RandInt(0, 2); - } + // The |flavor| value ends up being processed by ShowTryChromeDialog to show + // different experiments. + UserExperiment experiment; + if (!GetExperimentDetails(&experiment, -1)) { + VLOG(1) << "Failed to get experiment details."; + return; } + int flavor = experiment.flavor; + std::wstring base_group = experiment.prefix; std::wstring brand; if (GoogleUpdateSettings::GetBrand(&brand) && (brand == L"CHXX")) { @@ -610,34 +676,41 @@ void GoogleChromeDistribution::LaunchUserExperiment( // This means that we failed to find the user data dir. The most likely // cause is that this user has not ever used chrome at all which can // happen in a system-level install. - SetClient(GetExperimentGroup(kToastUDDirFailure, flavor), true); + SetClient(base_group + kToastUDDirFailure, true); return; } else if (dir_age_hours < kThirtyDays) { // An active user, so it does not qualify. VLOG(1) << "Chrome used in last " << dir_age_hours << " hours"; - SetClient(GetExperimentGroup(kToastActiveGroup, flavor), true); + SetClient(base_group + kToastActiveGroup, true); return; } - // 1% are in the control group that qualifies but does not get drafted. - if (base::RandDouble() > 0.99) { - SetClient(GetExperimentGroup(kToastExpControlGroup, flavor), true); + // Check to see if this user belongs to the control group. + double control_group = 1.0 * (100 - experiment.control_group) / 100; + if (base::RandDouble() > control_group) { + SetClient(base_group + kToastExpControlGroup, true); VLOG(1) << "User is control group"; return; } } VLOG(1) << "User drafted for toast experiment " << flavor; - SetClient(GetExperimentGroup(kToastExpBaseGroup, flavor), false); + SetClient(base_group + kToastExpBaseGroup, false); // User level: The experiment needs to be performed in a different process // because google_update expects the upgrade process to be quick and nimble. // System level: We have already been relaunched, so we don't need to be // quick, but we relaunch to follow the exact same codepath. - LaunchSetup(setup_path, installer::switches::kInactiveUserToast, flavor, - system_level); + CommandLine cmd_line(setup_path); + cmd_line.AppendSwitchASCII(installer::switches::kInactiveUserToast, + base::IntToString(flavor)); + cmd_line.AppendSwitchASCII(installer::switches::kExperimentGroup, + WideToASCII(base_group)); + LaunchSetup(cmd_line, system_level); } -// User qualifies for the experiment. Launch chrome with --try-chrome=flavor. +// User qualifies for the experiment. To test, use --try-chrome-again=|flavor| +// as a parameter to chrome.exe. void GoogleChromeDistribution::InactiveUserToastExperiment(int flavor, + const std::wstring& experiment_group, const installer::Product& installation, const FilePath& application_path) { bool has_welcome_url = (flavor == 0); @@ -677,7 +750,7 @@ void GoogleChromeDistribution::InactiveUserToastExperiment(int flavor, }; // Write to the |client| key for the last time. - SetClient(GetExperimentGroup(outcome, flavor), true); + SetClient(experiment_group + outcome, true); if (outcome != kToastExpUninstallGroup) return; diff --git a/chrome/installer/util/google_chrome_distribution.h b/chrome/installer/util/google_chrome_distribution.h index 3dc3b88..5586896 100644 --- a/chrome/installer/util/google_chrome_distribution.h +++ b/chrome/installer/util/google_chrome_distribution.h @@ -29,59 +29,67 @@ class GoogleChromeDistribution : public BrowserDistribution { // distribution_data contains Google Update related data that will be // concatenated to the survey url if the file in local_data_path indicates // the user has opted in to providing anonymous usage data. - virtual void DoPostUninstallOperations(const Version& version, - const FilePath& local_data_path, - const std::wstring& distribution_data); + virtual void DoPostUninstallOperations( + const Version& version, + const FilePath& local_data_path, + const std::wstring& distribution_data) OVERRIDE; - virtual std::wstring GetAppGuid(); + virtual std::wstring GetAppGuid() OVERRIDE; - virtual std::wstring GetApplicationName(); + virtual std::wstring GetApplicationName() OVERRIDE; - virtual std::wstring GetAlternateApplicationName(); + virtual std::wstring GetAlternateApplicationName() OVERRIDE; - virtual std::wstring GetBrowserAppId(); + virtual std::wstring GetBrowserAppId() OVERRIDE; - virtual std::wstring GetInstallSubDir(); + virtual std::wstring GetInstallSubDir() OVERRIDE; - virtual std::wstring GetPublisherName(); + virtual std::wstring GetPublisherName() OVERRIDE; - virtual std::wstring GetAppDescription(); + virtual std::wstring GetAppDescription() OVERRIDE; - virtual std::string GetSafeBrowsingName(); + virtual std::string GetSafeBrowsingName() OVERRIDE; - virtual std::wstring GetStateKey(); + virtual std::wstring GetStateKey() OVERRIDE; - virtual std::wstring GetStateMediumKey(); + virtual std::wstring GetStateMediumKey() OVERRIDE; - virtual std::wstring GetStatsServerURL(); + virtual std::wstring GetStatsServerURL() OVERRIDE; // This method reads data from the Google Update ClientState key for // potential use in the uninstall survey. It must be called before the // key returned by GetVersionKey() is deleted. - virtual std::wstring GetDistributionData(HKEY root_key); + virtual std::wstring GetDistributionData(HKEY root_key) OVERRIDE; - virtual std::wstring GetUninstallLinkName(); + virtual std::wstring GetUninstallLinkName() OVERRIDE; - virtual std::wstring GetUninstallRegPath(); + virtual std::wstring GetUninstallRegPath() OVERRIDE; - virtual std::wstring GetVersionKey(); + virtual std::wstring GetVersionKey() OVERRIDE; - virtual void UpdateInstallStatus(bool system_install, + virtual void UpdateInstallStatus( + bool system_install, installer::ArchiveType archive_type, - installer::InstallStatus install_status); + installer::InstallStatus install_status) OVERRIDE; + + virtual bool GetExperimentDetails(UserExperiment* experiment, + int flavor) OVERRIDE; - virtual void LaunchUserExperiment(const FilePath& setup_path, + virtual void LaunchUserExperiment( + const FilePath& setup_path, installer::InstallStatus status, const Version& version, const installer::Product& installation, - bool system_level); + bool system_level) OVERRIDE; // Assuming that the user qualifies, this function performs the inactive user // toast experiment. It will use chrome to show the UI and it will record the // outcome in the registry. - virtual void InactiveUserToastExperiment(int flavor, + virtual void InactiveUserToastExperiment( + int flavor, + const std::wstring& experiment_group, const installer::Product& installation, - const FilePath& application_path); + const FilePath& application_path) OVERRIDE; const std::wstring& product_guid() { return product_guid_; } diff --git a/chrome/installer/util/google_chrome_distribution_dummy.cc b/chrome/installer/util/google_chrome_distribution_dummy.cc index cac5d1b..496d264 100644 --- a/chrome/installer/util/google_chrome_distribution_dummy.cc +++ b/chrome/installer/util/google_chrome_distribution_dummy.cc @@ -106,6 +106,12 @@ void GoogleChromeDistribution::UpdateInstallStatus(bool system_install, NOTREACHED(); } +bool GoogleChromeDistribution::GetExperimentDetails( + UserExperiment* experiment, int flavor) { + NOTREACHED(); + return false; +} + void GoogleChromeDistribution::LaunchUserExperiment( const FilePath& setup_path, installer::InstallStatus status, const Version& version, const installer::Product& installation, @@ -114,6 +120,7 @@ void GoogleChromeDistribution::LaunchUserExperiment( } void GoogleChromeDistribution::InactiveUserToastExperiment(int flavor, + const std::wstring& experiment_group, const installer::Product& installation, const FilePath& application_path) { NOTREACHED(); diff --git a/chrome/installer/util/util_constants.cc b/chrome/installer/util/util_constants.cc index 20b4a0c..bd92223 100644 --- a/chrome/installer/util/util_constants.cc +++ b/chrome/installer/util/util_constants.cc @@ -143,6 +143,9 @@ const char kInactiveUserToast[] = "inactive-user-toast"; // User toast experiment switch from system context to user context. const char kSystemLevelToast[] = "system-level-toast"; +// The group this experiment belongs to. +const char kExperimentGroup[] = "experiment-group"; + // A handle value of the key to write the results of the toast experiment // to. See DuplicateGoogleUpdateSystemClientKey for details. const char kToastResultsKey[] = "toast-results-key"; diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h index b7e5347..925110b 100644 --- a/chrome/installer/util/util_constants.h +++ b/chrome/installer/util/util_constants.h @@ -44,7 +44,7 @@ enum InstallStatus { RENAME_FAILED, // 24. Rename of new_chrome.exe failed EULA_REJECTED, // 25. EULA dialog was not accepted by user. EULA_ACCEPTED, // 26. EULA dialog was accepted by user. - EULA_ACCEPTED_OPT_IN, // 27. EULA accepted wtih the crash optin selected. + EULA_ACCEPTED_OPT_IN, // 27. EULA accepted with the crash option selected. INSTALL_DIR_IN_USE, // 28. Installation directory is in use by another // process UNINSTALL_REQUIRES_REBOOT, // 29. Uninstallation required a reboot. @@ -139,6 +139,7 @@ extern const char kShowEula[]; extern const char kAltDesktopShortcut[]; extern const char kInactiveUserToast[]; extern const char kSystemLevelToast[]; +extern const char kExperimentGroup[]; extern const char kToastResultsKey[]; } // namespace switches |