Skip to content
This repository was archived by the owner on Nov 1, 2022. It is now read-only.

Commit fc09cdd

Browse files
committed
Use WorkManager for uploading glean pings
Adding a storage engine for async serialization of pings Implement tests that work with WorkManager
1 parent 2b01353 commit fc09cdd

File tree

23 files changed

+1082
-559
lines changed

23 files changed

+1082
-559
lines changed

buildSrc/src/main/java/Dependencies.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ object Versions {
3434

3535
const val mozilla_appservices = "0.15.0"
3636
const val servo = "0.0.1.20181017.aa95911"
37+
38+
const val work_testing = "1.0.0-beta05"
3739
}
3840

3941
// Synchronized dependencies used by (some) modules
@@ -90,4 +92,6 @@ object Dependencies {
9092
const val thirdparty_okhttp = "com.squareup.okhttp3:okhttp:${Versions.okhttp}"
9193
const val thirdparty_okhttp_urlconnection = "com.squareup.okhttp3:okhttp-urlconnection:${Versions.okhttp}"
9294
const val thirdparty_sentry = "io.sentry:sentry-android:${Versions.sentry}"
95+
96+
const val androidx_work_testing = "android.arch.work:work-testing:${Versions.work_testing}"
9397
}

components/service/glean/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ dependencies {
4040
implementation Dependencies.kotlin_stdlib
4141
implementation Dependencies.kotlin_coroutines
4242
implementation Dependencies.arch_lifecycle
43+
implementation Dependencies.arch_workmanager
4344

4445
implementation project(':support-ktx')
4546
implementation project(':support-base')
@@ -50,6 +51,7 @@ dependencies {
5051
testImplementation Dependencies.testing_robolectric
5152
testImplementation Dependencies.testing_mockito
5253
testImplementation Dependencies.testing_mockwebserver
54+
testImplementation Dependencies.androidx_work_testing
5355
}
5456

5557
apply from: '../../../publish.gradle'

components/service/glean/src/main/java/mozilla/components/service/glean/Glean.kt

Lines changed: 13 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -4,57 +4,35 @@
44

55
package mozilla.components.service.glean
66

7-
import android.arch.lifecycle.ProcessLifecycleOwner
87
import android.content.Context
98
import android.content.pm.PackageManager
109
import android.support.annotation.VisibleForTesting
11-
import kotlinx.coroutines.Dispatchers
12-
import kotlinx.coroutines.GlobalScope
13-
import kotlinx.coroutines.launch
14-
15-
import java.util.UUID
1610

1711
import mozilla.components.service.glean.config.Configuration
1812
import mozilla.components.service.glean.firstrun.FileFirstRunDetector
1913
import mozilla.components.service.glean.GleanMetrics.GleanInternalMetrics
20-
import mozilla.components.service.glean.net.HttpPingUploader
21-
import mozilla.components.service.glean.ping.PingMaker
22-
import mozilla.components.service.glean.scheduler.GleanLifecycleObserver
14+
import mozilla.components.service.glean.scheduler.PingScheduler
2315
import mozilla.components.service.glean.storages.ExperimentsStorageEngine
2416
import mozilla.components.service.glean.storages.StorageEngineManager
2517
import mozilla.components.service.glean.ping.BaselinePing
26-
import mozilla.components.service.glean.scheduler.MetricsPingScheduler
2718
import mozilla.components.service.glean.storages.StringsStorageEngine
2819
import mozilla.components.service.glean.storages.UuidsStorageEngine
2920
import mozilla.components.support.base.log.logger.Logger
3021
import java.io.File
22+
import java.util.UUID
3123

32-
@Suppress("TooManyFunctions")
3324
open class GleanInternalAPI internal constructor () {
3425
private val logger = Logger("glean/Glean")
3526

36-
// Include our singletons of StorageEngineManager and PingMaker
3727
private lateinit var storageEngineManager: StorageEngineManager
38-
private lateinit var pingMaker: PingMaker
3928
internal lateinit var configuration: Configuration
4029

41-
// `internal` so this can be modified for testing
42-
internal lateinit var httpPingUploader: HttpPingUploader
43-
44-
private val gleanLifecycleObserver by lazy { GleanLifecycleObserver() }
30+
internal lateinit var pingScheduler: PingScheduler
4531

4632
// `internal` so this can be modified for testing
4733
internal var initialized = false
4834
private var uploadEnabled = true
4935

50-
// The application id detected by glean to be used as part of the submission
51-
// endpoint.
52-
internal lateinit var applicationId: String
53-
54-
// This object holds data related to any persistent information about the metrics ping,
55-
// such as the last time it was sent and the store name
56-
internal lateinit var metricsPingScheduler: MetricsPingScheduler
57-
5836
// This object encapsulates initialization and information related to the baseline ping
5937
internal lateinit var baselinePing: BaselinePing
6038

@@ -63,10 +41,10 @@ open class GleanInternalAPI internal constructor () {
6341
*
6442
* This should only be initialized once by the application, and not by
6543
* libraries using glean. A message is logged to error and no changes are made
66-
* to the state if initialize is called a more than once.
44+
* to the state if initialize is called more than once.
6745
*
68-
* A LifecycleObserver will be added to send pings when the application goes
69-
* into the background.
46+
* A [PingScheduler] will be added as a [LifecycleObserver] to schedule pings when the
47+
* application goes into the background.
7048
*
7149
* @param applicationContext [Context] to access application features, such
7250
* as shared preferences
@@ -82,15 +60,12 @@ open class GleanInternalAPI internal constructor () {
8260
}
8361

8462
storageEngineManager = StorageEngineManager(applicationContext = applicationContext)
85-
pingMaker = PingMaker(storageEngineManager, applicationContext)
63+
pingScheduler = PingScheduler(applicationContext, storageEngineManager)
8664
this.configuration = configuration
87-
httpPingUploader = HttpPingUploader()
88-
initialized = true
89-
applicationId = sanitizeApplicationId(applicationContext.packageName)
9065

9166
initializeCoreMetrics(applicationContext)
9267

93-
ProcessLifecycleOwner.get().lifecycle.addObserver(gleanLifecycleObserver)
68+
initialized = true
9469
}
9570

9671
/**
@@ -154,40 +129,6 @@ open class GleanInternalAPI internal constructor () {
154129
ExperimentsStorageEngine.clearAllStores()
155130
}
156131

157-
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
158-
internal fun makePath(docType: String, uuid: UUID): String {
159-
return "/submit/$applicationId/$docType/${Glean.SCHEMA_VERSION}/$uuid"
160-
}
161-
162-
/**
163-
* Collect and assemble the ping. Asynchronously submits the assembled
164-
* payload to the designated server using [httpPingUploader] but only
165-
* if upload is enabled, and there is ping data to send.
166-
*/
167-
internal fun sendPing(store: String, docType: String) {
168-
if (!isInitialized()) {
169-
logger.error("Attempted to send ping before Glean was initialized.")
170-
return
171-
}
172-
173-
// Do not send ping if upload is disabled
174-
if (!getUploadEnabled()) {
175-
logger.debug("Attempt to send ping \"$store\" but metrics disabled, aborting send.")
176-
return
177-
}
178-
179-
// Build and send the ping on an async thread. Since the pingMaker.collect() function
180-
// returns null if there is nothing to send we can use this to avoid sending an empty ping
181-
pingMaker.collect(store)?.let { pingContent ->
182-
val uuid = UUID.randomUUID()
183-
val path = makePath(docType, uuid)
184-
// Asynchronously perform the HTTP upload off the main thread.
185-
GlobalScope.launch(Dispatchers.IO) {
186-
httpPingUploader.upload(path = path, data = pingContent, config = configuration)
187-
}
188-
}
189-
}
190-
191132
/**
192133
* Initialize the core metrics internally managed by Glean (e.g. client id).
193134
*/
@@ -238,52 +179,16 @@ open class GleanInternalAPI internal constructor () {
238179
throw AssertionError("Could not get own package info, aborting init")
239180
}
240181

241-
// Set up information and scheduling for glean owned pings
242-
metricsPingScheduler = MetricsPingScheduler(applicationContext)
182+
// Create a baseline ping to initialize the associated metrics
243183
baselinePing = BaselinePing(applicationContext)
244184
}
245185

246186
/**
247-
* Sanitizes the application id, generating a pipeline-friendly string that replaces
248-
* non alphanumeric characters with dashes.
249-
*
250-
* @param applicationId the string representing the application id
251-
*
252-
* @return the sanitized version of the application id
187+
* Helper function to force scheduling of pings immediately. Note that the 'metrics' ping
188+
* schedule is still dependent on it's internal schedule of no more than once every 24 hours.
253189
*/
254-
internal fun sanitizeApplicationId(applicationId: String): String {
255-
return applicationId.replace("[^a-zA-Z0-9]+".toRegex(), "-")
256-
}
257-
258-
/**
259-
* Handle an event and send the appropriate pings.
260-
*
261-
* Valid events are:
262-
*
263-
* - Background: When the application goes to the background.
264-
* This triggers sending of the baseline ping.
265-
* - Default: Event that triggers the default pings.
266-
*
267-
* @param pingEvent The type of the event.
268-
*/
269-
fun handleEvent(pingEvent: Glean.PingEvent) {
270-
if (!isInitialized()) {
271-
logger.error("Glean must be initialized before handling events.")
272-
return
273-
}
274-
275-
when (pingEvent) {
276-
Glean.PingEvent.Background -> {
277-
sendPing(BaselinePing.STORE_NAME, BaselinePing.STORE_NAME)
278-
sendPing("events", "events")
279-
}
280-
Glean.PingEvent.Default -> {
281-
if (metricsPingScheduler.canSendPing()) {
282-
sendPing(MetricsPingScheduler.STORE_NAME, MetricsPingScheduler.STORE_NAME)
283-
metricsPingScheduler.updateSentTimestamp()
284-
}
285-
}
286-
}
190+
fun schedulePingsNow() {
191+
pingScheduler.onEnterBackground()
287192
}
288193

289194
/**
@@ -297,19 +202,6 @@ open class GleanInternalAPI internal constructor () {
297202
}
298203

299204
object Glean : GleanInternalAPI() {
300-
/**
301-
* Enumeration of different metric lifetimes.
302-
*/
303-
enum class PingEvent {
304-
/**
305-
* When the application goes into the background
306-
*/
307-
Background,
308-
/**
309-
* A periodic event to send the default ping
310-
*/
311-
Default
312-
}
313205

314206
internal const val SCHEMA_VERSION = 2
315207

components/service/glean/src/main/java/mozilla/components/service/glean/scheduler/GleanLifecycleObserver.kt

Lines changed: 0 additions & 48 deletions
This file was deleted.

0 commit comments

Comments
 (0)