Skip to content

Commit

Permalink
Fix bug where provisional client ID was being cleared on iOS
Browse files Browse the repository at this point in the history
-----------------

Context:
For Finch studies, generally, the client ID determines what group a
certain client will fall under for a specific study. A client ID only
exists when metrics reporting (UMA) is enabled.

We have logic for a "provisional client ID" -- basically, it's a
temporary client ID for first runs. On the first run, at the beginning, UMA is disabled, so theoretically there is no client ID,
and hence trial assignment would be done with no client ID. If the user accepts metrics reporting during the welcome flow, then they
would now have a client ID, and next time they run Chrome, they
would be assigned to Finch studies differently. We address this
issue by using a provisional client ID, with which the trial
assignment is done in the first run. If the user accepts (enables)
metrics reporting during the welcome flow, then that provisional
client ID is promoted to be the real client ID. That way, the trial
assignment in their first session and follow up sessions will be
the same. If they refuse (disable) metrics reporting during the
welcome flow, then we simply discard that provisional client ID.

Note that the provisional client ID is stored in Local State pref.
The reason for that is that the user might quit during the welcome
flow. Then, when they re-open Chrome, they will again be in the
welcome flow. We store the provisional client ID so that the
provisional will remain the same across these welcome flows. And,
again, the provisional client ID pref is cleared when 1) the user
enables UMA, since it gets promoted to the client ID, or 2) when the
user disables UMA.

-----------------

What this CL fixes:
So there's a bug on iOS where if the user lingers a little too long on
the welcome screen, the provisional client ID gets cleared. This is
because "onPreferenceChanged" manually gets called after setting up
the Local State pref observer bridge (since the initialization of
this bridge is delayed, and not done immediately on start up). What
happens is that if the user has yet to accept/refuse UMA, then when
"onPreferenceChanged" gets manually called, it will think that UMA
is disabled, so the provisional client ID gets cleared. Then, say the
user eventually accepts (enables) UMA, we will create a new client ID
since there is no provisional client ID to promote. What that means is
that trial assignment will be different from the first run. In
particular, they used the provisional client ID for Finch trial
assignment for their first run, but will use a different client ID for
follow up sessions.

Bug: b/241651416
Change-Id: I399bb1ab64240eff28b372328ec70c0b6d7f500a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3840809
Reviewed-by: Sylvain Defresne <sdefresne@chromium.org>
Commit-Queue: Luc Nguyen <lucnguyen@google.com>
Cr-Commit-Position: refs/heads/main@{#1037815}
  • Loading branch information
Luc Nguyen authored and Chromium LUCI CQ committed Aug 22, 2022
1 parent 0c6b2e9 commit e3c2cbf
Showing 1 changed file with 19 additions and 5 deletions.
24 changes: 19 additions & 5 deletions ios/chrome/app/main_controller.mm
Original file line number Diff line number Diff line change
Expand Up @@ -869,16 +869,30 @@ - (void)schedulePrefObserverInitialization {

- (void)initializePrefObservers {
// Track changes to local state prefs.
_localStatePrefChangeRegistrar.Init(GetApplicationContext()->GetLocalState());
PrefService* localState = GetApplicationContext()->GetLocalState();
_localStatePrefChangeRegistrar.Init(localState);
_localStatePrefObserverBridge = std::make_unique<PrefObserverBridge>(self);
_localStatePrefObserverBridge->ObserveChangesForPreference(
metrics::prefs::kMetricsReportingEnabled,
&_localStatePrefChangeRegistrar);

// Calls the onPreferenceChanged function in case there was
// a change to the observed preferences before the observer
// bridge was set up.
[self onPreferenceChanged:metrics::prefs::kMetricsReportingEnabled];
// Calls the onPreferenceChanged function in case there was a change to the
// observed preferences before the observer bridge was set up. However, if the
// metrics reporting pref is still unset (has default value), then do not
// call. This likely means that the user is still on the welcome screen during
// the first run experience (FRE), and calling onPreferenceChanged here would
// clear the provisional client ID (in
// MetricsMediator::updateMetricsPrefsOnPermissionChange). The provisional
// client ID is crucial for field trial assignment consistency between the
// first session and follow-up sessions, and is promoted to be the real client
// ID if the user enables metrics reporting in the FRE. Otherwise, it is
// discarded, as would happen here if onPreferenceChanged was called while the
// user was still on the welcome screen and did yet enable/disable metrics
// reporting.
if (!localState->FindPreference(metrics::prefs::kMetricsReportingEnabled)
->IsDefaultValue()) {
[self onPreferenceChanged:metrics::prefs::kMetricsReportingEnabled];
}

// Track changes to default search engine.
TemplateURLService* service =
Expand Down

0 comments on commit e3c2cbf

Please sign in to comment.