Commit 42ba265e authored by James Cook's avatar James Cook Committed by Commit Bot

chromeos: Create first-run field trial for SplitSettingsSync

Creates a field trial to control the SplitSettingsSync feature. The
trial is client controlled because SplitSettingsSync controls the
out-of-box experience (OOBE) sync consent dialog, which shows up
before a variations seed is available.

The trial group chosen on first run is persisted to local state prefs
and reused on subsequent runs. This keeps the in-session sync settings
UI stable between runs. Local state prefs can be reset via powerwash,
which will result in re-randomization, but this also sends the user
through the first-run flow again and they will see the appropriate
consent flow.

Bug: 1090989
Test: Went through OOBE, verified trial group is random then persists

Change-Id: I241407a47179ddeed1da06f2aa1189fac936c70f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2230771
Commit-Queue: James Cook <jamescook@chromium.org>
Reviewed-by: default avatarIlya Sherman <isherman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#775709}
parent 03103b97
......@@ -33,6 +33,7 @@
#endif
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/sync/split_settings_sync_field_trial.h"
#include "chromeos/services/multidevice_setup/public/cpp/first_run_field_trial.h"
#endif
......@@ -90,6 +91,11 @@ void ChromeBrowserFieldTrials::SetupFeatureControllingFieldTrials(
chromeos::multidevice_setup::CreateFirstRunFieldTrial(feature_list);
#endif
}
#if defined(OS_CHROMEOS)
// This trial is fully client controlled and must be configured whether or not
// a seed is available.
split_settings_sync_field_trial::Create(feature_list, local_state_);
#endif
}
void ChromeBrowserFieldTrials::RegisterSyntheticTrials() {
......
......@@ -2380,6 +2380,8 @@ source_set("chromeos") {
"sync/os_sync_util.h",
"sync/os_syncable_service_model_type_controller.cc",
"sync/os_syncable_service_model_type_controller.h",
"sync/split_settings_sync_field_trial.cc",
"sync/split_settings_sync_field_trial.h",
"sync/turn_sync_on_helper.cc",
"sync/turn_sync_on_helper.h",
"system/automatic_reboot_manager.cc",
......
......@@ -32,6 +32,7 @@
#include "chrome/browser/chromeos/login/session/user_session_manager.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/sync/split_settings_sync_field_trial.h"
#include "chrome/browser/chromeos/sync/turn_sync_on_helper.h"
#include "chrome/browser/chromeos/system/input_device_settings.h"
#include "chrome/browser/chromeos/system/timezone_resolver_manager.h"
......@@ -169,6 +170,7 @@ void Preferences::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterStringPref(::prefs::kMinimumAllowedChromeVersion, "");
ash::RegisterLocalStatePrefs(registry);
split_settings_sync_field_trial::RegisterLocalStatePrefs(registry);
}
// static
......
// Copyright 2020 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.
#include "chrome/browser/chromeos/sync/split_settings_sync_field_trial.h"
#include "base/feature_list.h"
#include "base/metrics/field_trial.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/common/channel_info.h"
#include "chromeos/constants/chromeos_features.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/variations/variations_associated_data.h"
#include "components/version_info/version_info.h"
namespace split_settings_sync_field_trial {
namespace {
// String local state preference with the name of the assigned trial group.
// Empty if no group has been assigned yet.
const char kTrialGroupPrefName[] = "split_settings_sync.trial_group";
// The field trial name.
const char kTrialName[] = "SplitSettingsSync";
// Group names for the trial.
const char kEnabledGroup[] = "Enabled";
const char kDisabledGroup[] = "Disabled";
const char kDefaultGroup[] = "Default";
// Probabilities for all field trial groups add up to kTotalProbability.
const base::FieldTrial::Probability kTotalProbability = 100;
// Creates the field trial.
scoped_refptr<base::FieldTrial> CreateFieldTrial() {
return base::FieldTrialList::FactoryGetFieldTrial(
kTrialName, kTotalProbability, kDefaultGroup,
base::FieldTrial::ONE_TIME_RANDOMIZED,
/*default_group_number=*/nullptr);
}
// Sets the feature state based on the trial group. Defaults to disabled.
void SetFeatureState(base::FeatureList* feature_list,
base::FieldTrial* trial,
const std::string& group_name) {
base::FeatureList::OverrideState feature_state =
group_name == kEnabledGroup ? base::FeatureList::OVERRIDE_ENABLE_FEATURE
: base::FeatureList::OVERRIDE_DISABLE_FEATURE;
feature_list->RegisterFieldTrialOverride(
chromeos::features::kSplitSettingsSync.name, feature_state, trial);
}
// Creates a trial for the first run (when there is no variations seed) and
// enables the feature based on the randomly selected trial group. Returns the
// group name.
std::string CreateFirstRunTrial(base::FeatureList* feature_list) {
int enabled_percent;
int disabled_percent;
int default_percent;
switch (chrome::GetChannel()) {
case version_info::Channel::UNKNOWN:
case version_info::Channel::CANARY:
case version_info::Channel::DEV:
case version_info::Channel::BETA:
enabled_percent = 50;
disabled_percent = 50;
default_percent = 0;
break;
case version_info::Channel::STABLE:
// Disabled on stable pending approval. https://crbug.com/1020731
enabled_percent = 0;
disabled_percent = 0;
default_percent = 100;
break;
}
DCHECK_EQ(kTotalProbability,
enabled_percent + disabled_percent + default_percent);
// Set up the trial and groups.
scoped_refptr<base::FieldTrial> trial = CreateFieldTrial();
trial->AppendGroup(kEnabledGroup, enabled_percent);
trial->AppendGroup(kDisabledGroup, disabled_percent);
trial->AppendGroup(kDefaultGroup, default_percent);
// Finalize the group choice and set the feature state.
const std::string& group_name = trial->GetGroupNameWithoutActivation();
SetFeatureState(feature_list, trial.get(), group_name);
return group_name;
}
// Creates a trial with a single group and sets the feature flag to the state
// for that group.
void CreateSubsequentRunTrial(base::FeatureList* feature_list,
const std::string& group_name) {
scoped_refptr<base::FieldTrial> trial = CreateFieldTrial();
trial->AppendGroup(group_name, kTotalProbability);
SetFeatureState(feature_list, trial.get(), group_name);
}
} // namespace
void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
registry->RegisterStringPref(kTrialGroupPrefName, std::string());
}
void Create(base::FeatureList* feature_list, PrefService* local_state) {
std::string trial_group = local_state->GetString(kTrialGroupPrefName);
if (trial_group.empty()) {
// No group assigned, this is the first run.
trial_group = CreateFirstRunTrial(feature_list);
// Persist the assigned group for subsequent runs.
local_state->SetString(kTrialGroupPrefName, trial_group);
} else {
// Group already assigned.
CreateSubsequentRunTrial(feature_list, trial_group);
}
}
} // namespace split_settings_sync_field_trial
// Copyright 2020 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_BROWSER_CHROMEOS_SYNC_SPLIT_SETTINGS_SYNC_FIELD_TRIAL_H_
#define CHROME_BROWSER_CHROMEOS_SYNC_SPLIT_SETTINGS_SYNC_FIELD_TRIAL_H_
class PrefRegistrySimple;
class PrefService;
namespace base {
class FeatureList;
} // namespace base
namespace split_settings_sync_field_trial {
// Registers preferences.
void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
// Creates a field trial to control the SplitSettingsSync feature. The trial is
// client controlled because SplitSettingsSync controls the out-of-box
// experience (OOBE) sync consent dialog, which shows up before a variations
// seed is available.
//
// The trial group chosen on first run is persisted to local state prefs and
// reused on subsequent runs. This keeps the in-session sync settings UI stable
// between runs. Local state prefs can be reset via powerwash, which will result
// in re-randomization, but this also sends the user through the first-run flow
// again and they will see the appropriate consent flow.
//
// Persisting the group also avoids a subtle corner case: A user could be
// randomized to SplitSettingsSync, opt-in to sync during OOBE, then turn off OS
// sync in OS settings but leave "Sync everything" enabled in browser settings.
// If they were re-randomized to non-SplitSettingsSync on a future login, then
// the OS sync data types would go back to being controlled by browser sync
// settings, and those OS types would be re-enabled even though the user had
// them disabled.
//
// Launch bug for the SplitSettingsSync feature: https://crbug.com/1020731
void Create(base::FeatureList* feature_list, PrefService* local_state);
} // namespace split_settings_sync_field_trial
#endif // CHROME_BROWSER_CHROMEOS_SYNC_SPLIT_SETTINGS_SYNC_FIELD_TRIAL_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment