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