diff --git a/app/metrics.yaml b/app/metrics.yaml
index 5be5c59efd..77cf05dbd3 100644
--- a/app/metrics.yaml
+++ b/app/metrics.yaml
@@ -2291,6 +2291,26 @@ metrics:
metadata:
tags:
- Notifications
+ shared_prefs_uuid:
+ type: uuid
+ lifetime: ping
+ description: |
+ A UUID stored in Shared Preferences used to analyze technical differences
+ between storage mechanisms in Android, specifically the Glean DB and
+ Shared Preferences.
+ send_in_pings:
+ - metrics
+ notification_emails:
+ - android-probes@mozilla.com
+ - raphael@mozilla.com
+ - fbertsch@mozilla.com
+ bugs:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1822119
+ data_reviews:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1822119
+ data_sensitivity:
+ - technical
+ expires: 116
customize_home:
most_visited_sites:
diff --git a/app/src/main/java/org/mozilla/fenix/FenixApplication.kt b/app/src/main/java/org/mozilla/fenix/FenixApplication.kt
index 2c3768b581..1e83a54b09 100644
--- a/app/src/main/java/org/mozilla/fenix/FenixApplication.kt
+++ b/app/src/main/java/org/mozilla/fenix/FenixApplication.kt
@@ -726,6 +726,12 @@ open class FenixApplication : LocaleAwareApplication(), Provider {
searchWidgetInstalled.set(settings.searchWidgetInstalled)
+ if (settings.sharedPrefsUUID.isEmpty()) {
+ settings.sharedPrefsUUID = sharedPrefsUuid.generateAndSet().toString()
+ } else {
+ sharedPrefsUuid.set(UUID.fromString(settings.sharedPrefsUUID))
+ }
+
val openTabsCount = settings.openTabsCount
hasOpenTabs.set(openTabsCount > 0)
if (openTabsCount > 0) {
diff --git a/app/src/main/java/org/mozilla/fenix/settings/DataChoicesFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/DataChoicesFragment.kt
index 6aa832f475..1ad63871b5 100644
--- a/app/src/main/java/org/mozilla/fenix/settings/DataChoicesFragment.kt
+++ b/app/src/main/java/org/mozilla/fenix/settings/DataChoicesFragment.kt
@@ -32,6 +32,11 @@ class DataChoicesFragment : PreferenceFragmentCompat() {
context.components.analytics.metrics.start(MetricServiceType.Data)
} else {
context.components.analytics.metrics.stop(MetricServiceType.Data)
+
+ // Reset the Shared Prefs UUID on opt-out since we're investigating cases of
+ // unexpected client ID regeneration. Telemetry data collection opt-out is
+ // expected to reset the client ID.
+ context.settings().sharedPrefsUUID = ""
}
// Reset experiment identifiers on both opt-in and opt-out; it's likely
// that in future we will need to pass in the new telemetry client_id
diff --git a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt
index 01bb3217f4..6bc1ce49c5 100644
--- a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt
+++ b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt
@@ -191,6 +191,16 @@ class Settings(private val appContext: Context) : PreferencesHolder {
default = "",
)
+ /**
+ * A UUID stored in Shared Preferences used to analyze technical differences
+ * between storage mechanisms in Android, specifically the Glean DB and
+ * Shared Preferences.
+ */
+ var sharedPrefsUUID by stringPreference(
+ appContext.getPreferenceKey(R.string.pref_key_shared_prefs_uuid),
+ default = "",
+ )
+
var currentWallpaperName by stringPreference(
appContext.getPreferenceKey(R.string.pref_key_current_wallpaper),
default = Wallpaper.Default.name,
diff --git a/app/src/main/res/values/preference_keys.xml b/app/src/main/res/values/preference_keys.xml
index 96f7942c25..d076012da5 100644
--- a/app/src/main/res/values/preference_keys.xml
+++ b/app/src/main/res/values/preference_keys.xml
@@ -328,6 +328,7 @@
pref_key_custom_sponsored_stories_site_id
pref_key_custom_sponsored_stories_country
pref_key_custom_sponsored_stories_city
+ pref_key_shared_prefs_uuid
pref_key_growth_set_as_default
diff --git a/app/src/test/java/org/mozilla/fenix/FenixApplicationTest.kt b/app/src/test/java/org/mozilla/fenix/FenixApplicationTest.kt
index 4069d7a659..73f8c71d6f 100644
--- a/app/src/test/java/org/mozilla/fenix/FenixApplicationTest.kt
+++ b/app/src/test/java/org/mozilla/fenix/FenixApplicationTest.kt
@@ -148,6 +148,9 @@ class FenixApplicationTest {
assertTrue(settings.contileContextId.isEmpty())
assertNull(TopSites.contextId.testGetValue())
+ assertTrue(settings.sharedPrefsUUID.isEmpty())
+ assertNull(Metrics.sharedPrefsUuid.testGetValue())
+
application.setStartupMetrics(browserStore, settings, browsersCache, mozillaProductDetector)
// Verify that browser defaults metrics are set.
@@ -192,6 +195,14 @@ class FenixApplicationTest {
assertNotNull(TopSites.contextId.testGetValue())
assertEquals(contextId, settings.contileContextId)
+ // Verify that setStartupMetrics() creates `the Metrics.sharedPrefsUuid`
+ // Glean metric and that it stores the value in shared preferences at
+ // settings.sharedPrefsUUID. Subsequent calls load the UUID value from
+ // shared preferences rather than generating a new one.
+ val sharedPrefsUUIDMetricValue = Metrics.sharedPrefsUuid.testGetValue()!!.toString()
+ assertNotNull(Metrics.sharedPrefsUuid.testGetValue())
+ assertEquals(sharedPrefsUUIDMetricValue, settings.sharedPrefsUUID)
+
// Verify that search engine defaults are NOT set. This test does
// not mock most of the objects telemetry is collected from.
assertNull(SearchDefaultEngine.code.testGetValue())
@@ -202,6 +213,9 @@ class FenixApplicationTest {
assertEquals(contextId, TopSites.contextId.testGetValue()!!.toString())
assertEquals(contextId, settings.contileContextId)
+
+ assertEquals(sharedPrefsUUIDMetricValue, Metrics.sharedPrefsUuid.testGetValue()!!.toString())
+ assertEquals(sharedPrefsUUIDMetricValue, settings.sharedPrefsUUID)
}
@Test