summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfinnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-23 10:40:15 +0000
committerfinnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-23 10:40:15 +0000
commit0d2fbd5c215bad61dc97b819b746cba55c4c1ea8 (patch)
tree557ec6a5fd9e15faaf2f537d4107fd1dc143ccc8
parent3f6900c9fee2a9ef8d50b2f85307a18f01652d1f (diff)
downloadchromium_src-0d2fbd5c215bad61dc97b819b746cba55c4c1ea8.zip
chromium_src-0d2fbd5c215bad61dc97b819b746cba55c4c1ea8.tar.gz
chromium_src-0d2fbd5c215bad61dc97b819b746cba55c4c1ea8.tar.bz2
Toasting by brand code.
Add the ability to have different experiments based on brand code. BUG=76594 TEST=For the en-US locale, take an old build and a build that includes this fix. Install the old build, set the brand code in the registry to SKPN and set the clock forward by more than a month. Install the new build and make sure you get a toast that references Skype. Change the brand code to anything else, ABCD for example, and make sure you get the generic toast (there are four possible). Then try with locale 'ja' and make sure you get a Japanese toast. Please test this also with system-install of Chrome (enough to just do Skype brand code, I guess). Review URL: http://codereview.chromium.org/6712015 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@79110 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/chromium_strings.grd3
-rw-r--r--chrome/app/google_chrome_strings.grd3
-rw-r--r--chrome/browser/first_run/first_run_win.cc26
-rw-r--r--chrome/chrome_common.gypi1
-rw-r--r--chrome/common/attrition_experiments.h31
-rw-r--r--chrome/installer/setup/setup_main.cc8
-rw-r--r--chrome/installer/util/browser_distribution.cc6
-rw-r--r--chrome/installer/util/browser_distribution.h29
-rw-r--r--chrome/installer/util/chrome_frame_distribution.h34
-rw-r--r--chrome/installer/util/chromium_binaries_distribution.h36
-rw-r--r--chrome/installer/util/google_chrome_distribution.cc183
-rw-r--r--chrome/installer/util/google_chrome_distribution.h56
-rw-r--r--chrome/installer/util/google_chrome_distribution_dummy.cc7
-rw-r--r--chrome/installer/util/util_constants.cc3
-rw-r--r--chrome/installer/util/util_constants.h3
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