Bug 1817029 - Add the client-deduplication ping (#861)
* Bug 1817245 - new Nimbus feature for controlling client-deduplication ping This feature will enable/disable the sending of the `client-deduplication` ping that will be added in a later PR. * Bug 1817029 - Add the client-deduplication ping The `client-deduplication` ping will be used to determine if client IDs are being regenerated erroneously. This ping uses the lifecycle observers to (almost) replicate the same scheduling as the baseline ping. * Bug 1817029 - Suggested changes changelog - add `reason` for new ping - update the unit test for the new ping - add new metrics - allow for custom salt when hashing the Ad ID - move the Nimbus check to the lifecycle observer - record the new metrics * Bug 1817029 - Update fenix/.experimenter.yaml Co-authored-by: Alessio Placitelli <alessio.placitelli@gmail.com> * Bug 1817029 - remove unnecessary pass-through function * Bug 1817029 - add the GleanTestRule for tests * Bug 1817029 - Update fenix/app/src/test/java/org/mozilla/fenix/components/metrics/clientdeduplication/ClientDeduplicationPingTest.kt Co-authored-by: Travis Long <tlong@mozilla.com> * Bug 1817029 - remove unnecessary call to main thread * Bug 1817029 - update comment about hashing --------- Co-authored-by: Alessio Placitelli <alessio.placitelli@gmail.com> Co-authored-by: Travis Long <tlong@mozilla.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>pull/600/head
parent
4ab8c40fbb
commit
e8ad3c4c04
@ -0,0 +1,43 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.components.metrics.clientdeduplication
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import org.mozilla.fenix.nimbus.FxNimbus
|
||||
|
||||
/**
|
||||
* This observer allows us to mimic roughly the same schedule as the Glean SDK baseline ping.
|
||||
* https://github.com/mozilla/glean/blob/main/glean-core/android/src/main/java/mozilla/telemetry/glean/scheduler/GleanLifecycleObserver.kt
|
||||
*/
|
||||
class ClientDeduplicationLifecycleObserver(context: Context) : LifecycleEventObserver {
|
||||
private val clientDeduplicationPing = ClientDeduplicationPing(context)
|
||||
|
||||
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
|
||||
// The ping will only be sent whenever the Nimbus feature is enabled.
|
||||
if (FxNimbus.features.clientDeduplication.value().enabled) {
|
||||
when (event) {
|
||||
Lifecycle.Event.ON_STOP -> {
|
||||
clientDeduplicationPing.triggerPing(active = false)
|
||||
}
|
||||
Lifecycle.Event.ON_START -> {
|
||||
// We use ON_START here because we don't want to incorrectly count metrics in
|
||||
// ON_RESUME as pause/resume can happen when interacting with things like the
|
||||
// navigation shade which could lead to incorrectly recording the start of a
|
||||
// duration, etc.
|
||||
//
|
||||
// https://developer.android.com/reference/android/app/Activity.html#onStart()
|
||||
|
||||
clientDeduplicationPing.triggerPing(active = true)
|
||||
}
|
||||
else -> {
|
||||
// For other lifecycle events, do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.components.metrics.clientdeduplication
|
||||
|
||||
import android.content.Context
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.mozilla.fenix.GleanMetrics.Activation
|
||||
import org.mozilla.fenix.GleanMetrics.ClientDeduplication
|
||||
import org.mozilla.fenix.GleanMetrics.Pings
|
||||
import org.mozilla.fenix.components.metrics.MetricsUtils.getHashedIdentifier
|
||||
|
||||
/**
|
||||
* Class to help construct and send the `clientDeduplication` ping.
|
||||
*/
|
||||
class ClientDeduplicationPing(private val context: Context) {
|
||||
private val customHashingSalt = "bug-1813195-02-2023"
|
||||
|
||||
/**
|
||||
* Fills the metrics and triggers the 'clientDeduplication' ping.
|
||||
*/
|
||||
internal fun triggerPing(active: Boolean) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val hashedId = getHashedIdentifier(context, customHashingSalt)
|
||||
|
||||
// Record the metrics.
|
||||
if (hashedId != null) {
|
||||
// We have a valid, hashed Google Advertising ID.
|
||||
Activation.identifier.set(hashedId)
|
||||
ClientDeduplication.validAdvertisingId.set(true)
|
||||
} else {
|
||||
ClientDeduplication.validAdvertisingId.set(false)
|
||||
}
|
||||
ClientDeduplication.experimentTimeframe.set(customHashingSalt)
|
||||
|
||||
// Set the reason based on if the app is foregrounded or backgrounded.
|
||||
val reason = if (active) {
|
||||
Pings.clientDeduplicationReasonCodes.active
|
||||
} else {
|
||||
Pings.clientDeduplicationReasonCodes.inactive
|
||||
}
|
||||
|
||||
// Submit the ping.
|
||||
Pings.clientDeduplication.submit(reason)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.components.metrics.clientdeduplication
|
||||
|
||||
import mozilla.components.service.glean.testing.GleanTestRule
|
||||
import mozilla.components.support.test.robolectric.testContext
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.GleanMetrics.ClientDeduplication
|
||||
import org.mozilla.fenix.GleanMetrics.Pings
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
|
||||
// For gleanTestRule
|
||||
@RunWith(FenixRobolectricTestRunner::class)
|
||||
internal class ClientDeduplicationPingTest {
|
||||
@get:Rule
|
||||
val gleanTestRule = GleanTestRule(testContext)
|
||||
|
||||
@Test
|
||||
fun `The clientDeduplication ping is sent`() {
|
||||
// Record test data.
|
||||
ClientDeduplication.validAdvertisingId.set(true)
|
||||
|
||||
// Instruct the ping API to validate the ping data.
|
||||
var validatorRun = false
|
||||
Pings.clientDeduplication.testBeforeNextSubmit { reason ->
|
||||
assertEquals(Pings.clientDeduplicationReasonCodes.active, reason)
|
||||
assertEquals(true, ClientDeduplication.validAdvertisingId.testGetValue())
|
||||
validatorRun = true
|
||||
}
|
||||
Pings.clientDeduplication.submit(Pings.clientDeduplicationReasonCodes.active)
|
||||
|
||||
// Verify that the validator ran.
|
||||
assertTrue(validatorRun)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue