Commit 12163f1f authored by Alessio Placitelli's avatar Alessio Placitelli
Browse files

Use the Rust implementation of the Glean SDK

This removes the Kotlin implementation from this repository
and introduces type aliases that point to the Rust implementation,
which is now a new dependency.
parent 321d4997
......@@ -29,6 +29,8 @@ object Versions {
const val mozilla_appservices = "0.42.0"
const val mozilla_glean = "19.0.0"
const val material = "1.0.0"
object AndroidX {
......@@ -120,6 +122,8 @@ object Dependencies {
const val mozilla_fxa = "org.mozilla.appservices:fxaclient:${Versions.mozilla_appservices}"
const val mozilla_glean_forUnitTests = "org.mozilla.telemetry:glean-forUnitTests:${Versions.mozilla_glean}"
const val mozilla_sync_logins = "org.mozilla.appservices:logins:${Versions.mozilla_appservices}"
const val mozilla_places = "org.mozilla.appservices:places:${Versions.mozilla_appservices}"
const val mozilla_sync_manager = "org.mozilla.appservices:syncmanager:${Versions.mozilla_appservices}"
......
......@@ -55,6 +55,7 @@ dependencies {
testImplementation Dependencies.testing_mockito
testImplementation Dependencies.testing_coroutines
testImplementation Dependencies.testing_mockwebserver
testImplementation Dependencies.mozilla_glean_forUnitTests
}
ext.gleanGenerateMarkdownDocs = true
......
......@@ -41,6 +41,7 @@ dependencies {
testImplementation Dependencies.kotlin_reflect
testImplementation Dependencies.androidx_work_testing
testImplementation Dependencies.androidx_espresso_core
testImplementation Dependencies.mozilla_glean_forUnitTests
testImplementation project(':support-test')
testImplementation project(':lib-fetch-httpurlconnection')
......
......@@ -14,6 +14,7 @@ import androidx.work.testing.WorkManagerTestInitHelper
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import mozilla.components.service.glean.Glean
import mozilla.components.service.glean.testing.GleanTestRule
import mozilla.components.support.test.any
import mozilla.components.support.test.eq
import mozilla.components.support.test.mock
......@@ -25,6 +26,7 @@ import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.assertNotNull
import org.junit.Rule
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
......@@ -49,6 +51,9 @@ class ExperimentsTest {
private val EXAMPLE_CLIENT_ID = "c641eacf-c30c-4171-b403-f077724e848a"
@get:Rule
val gleanRule = GleanTestRule(context)
private val experimentsList = listOf(
createDefaultExperiment(
id = "first-id",
......
......@@ -2,30 +2,15 @@
* 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/. */
plugins {
id "com.jetbrains.python.envs" version "0.0.26"
}
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
/*
* This defines the location of the JSON schema used to validate the pings
* created during unit testing.
* This uses a specific version of the schema identified by a git commit hash.
*/
String GLEAN_PING_SCHEMA_GIT_HASH = "c566160"
String GLEAN_PING_SCHEMA_URL = "https://raw.githubusercontent.com/mozilla-services/mozilla-pipeline-schemas/$GLEAN_PING_SCHEMA_GIT_HASH/schemas/glean/baseline/baseline.1.schema.json"
android {
compileSdkVersion config.compileSdkVersion
defaultConfig {
minSdkVersion config.minSdkVersion
targetSdkVersion config.targetSdkVersion
buildConfigField("String", "LIBRARY_VERSION", "\"" + config.componentsVersion + "\"")
buildConfigField("String", "GLEAN_PING_SCHEMA_URL", "\"" + GLEAN_PING_SCHEMA_URL + "\"")
}
buildTypes {
......@@ -36,11 +21,34 @@ android {
}
}
configurations {
// There's an interaction between Gradle's resolution of dependencies with different types
// (@jar, @aar) for `implementation` and `testImplementation` and with Android Studio's built-in
// JUnit test runner. The runtime classpath in the built-in JUnit test runner gets the
// dependency from the `implementation`, which is type @aar, and therefore the JNA dependency
// doesn't provide the JNI dispatch libraries in the correct Java resource directories. I think
// what's happening is that @aar type in `implementation` resolves to the @jar type in
// `testImplementation`, and that it wins the dependency resolution battle.
//
// A workaround is to add a new configuration which depends on the @jar type and to reference
// the underlying JAR file directly in `testImplementation`. This JAR file doesn't resolve to
// the @aar type in `implementation`. This works when invoked via `gradle`, but also sets the
// correct runtime classpath when invoked with Android Studio's built-in JUnit test runner.
// Success!
jnaForTest
}
// Define library names and version constants.
String GLEAN_LIBRARY = "org.mozilla.telemetry:glean:${Versions.mozilla_glean}"
String GLEAN_LIBRARY_FORUNITTESTS = "org.mozilla.telemetry:glean-forUnitTests:${Versions.mozilla_glean}"
dependencies {
implementation Dependencies.kotlin_stdlib
implementation Dependencies.kotlin_coroutines
implementation Dependencies.androidx_lifecycle_extensions
implementation Dependencies.androidx_work_runtime
api GLEAN_LIBRARY
implementation project(':support-ktx')
implementation project(':support-base')
......@@ -48,15 +56,6 @@ dependencies {
implementation project(':lib-fetch-httpurlconnection')
implementation project(':support-utils')
// We need a compileOnly dependency on the following block of testing
// libraries in order to expose the GleanTestRule to applications/libraries
// using the Glean SDK.
// We can't simply create a separate package otherwise we would need
// to provide a public API for the testing package to access the
// Glean internals, which is something we would not want to do.
compileOnly Dependencies.testing_junit
compileOnly Dependencies.androidx_work_testing
testImplementation Dependencies.androidx_test_core
testImplementation Dependencies.testing_junit
......@@ -67,9 +66,9 @@ dependencies {
testImplementation project(':support-test')
testImplementation project(':lib-fetch-okhttp')
testImplementation GLEAN_LIBRARY_FORUNITTESTS
}
apply from: '../../../publish.gradle'
ext.configurePublish(config.componentsGroupId, archivesBaseName, project.ext.description)
apply from: './scripts/sdk_generator.gradle'
# 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/.
# This file defines the metrics that are recorded by Glean telemetry. They are
# automatically converted to Kotlin code at build time using the `glean_parser`
# PyPI package.
$schema: moz://mozilla.org/schemas/glean/metrics/1-0-0
glean.baseline:
duration:
type: timespan
description: |
The duration of the last foreground session.
time_unit: second
send_in_pings:
- baseline
bugs:
- https://bugzilla.mozilla.org/1497894
- https://bugzilla.mozilla.org/1519120
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1512938#c3
notification_emails:
- telemetry-client-dev@mozilla.com
expires: never
locale:
type: string
lifetime: application
send_in_pings:
- baseline
description: |
The locale of the application (e.g. "es-ES").
bugs:
- https://bugzilla.mozilla.org/1512938
- https://bugzilla.mozilla.org/1525540
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1512938#c3
notification_emails:
- telemetry-client-dev@mozilla.com
expires: never
glean.internal.metrics:
os:
type: string
lifetime: application
send_in_pings:
- glean_client_info
description: |
The name of the operating system.
bugs:
- https://bugzilla.mozilla.org/1497894
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1512938#c3
notification_emails:
- telemetry-client-dev@mozilla.com
expires: never
os_version:
type: string
lifetime: application
send_in_pings:
- glean_client_info
description: |
The user-visible version of the operating system (e.g. "1.2.3").
bugs:
- https://bugzilla.mozilla.org/1497894
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1512938#c3
notification_emails:
- telemetry-client-dev@mozilla.com
expires: never
android_sdk_version:
type: string
lifetime: application
send_in_pings:
- glean_client_info
description: |
The optional Android specific SDK version of the software running on this hardware device.
bugs:
- https://bugzilla.mozilla.org/1525606
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1525606#c14
notification_emails:
- telemetry-client-dev@mozilla.com
expires: never
device_manufacturer:
type: string
lifetime: application
send_in_pings:
- glean_client_info
description: |
The manufacturer of the device the application is running on.
bugs:
- https://bugzilla.mozilla.org/1522552
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1512938#c3
notification_emails:
- telemetry-client-dev@mozilla.com
expires: never
device_model:
type: string
lifetime: application
send_in_pings:
- glean_client_info
description: |
The model of the device the application is running on.
bugs:
- https://bugzilla.mozilla.org/1522552
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1512938#c3
notification_emails:
- telemetry-client-dev@mozilla.com
expires: never
architecture:
type: string
lifetime: application
send_in_pings:
- glean_client_info
description: |
The architecture of the device, (e.g. "arm", "x86").
bugs:
- https://bugzilla.mozilla.org/1497894
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1512938#c3
notification_emails:
- telemetry-client-dev@mozilla.com
expires: never
client_id:
type: uuid
description:
A UUID uniquely identifying the client.
send_in_pings:
- glean_client_info
lifetime: user
bugs:
- https://bugzilla.mozilla.org/1497894
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1512938#c3
notification_emails:
- telemetry-client-dev@mozilla.com
expires: never
app_build:
type: string
lifetime: application
send_in_pings:
- glean_client_info
description: |
The build identifier generated by the CI system (e.g. "1234/A").
bugs:
- https://bugzilla.mozilla.org/1508305
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1512938#c3
notification_emails:
- telemetry-client-dev@mozilla.com
expires: never
app_display_version:
type: string
lifetime: application
send_in_pings:
- glean_client_info
description: |
The user visible version string (e.g. "1.0.3").
bugs:
- https://bugzilla.mozilla.org/1508305
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1508305#c9
notification_emails:
- telemetry-client-dev@mozilla.com
expires: never
app_channel:
type: string
lifetime: application
send_in_pings:
- glean_client_info
description: |
The channel the application is being distributed on.
bugs:
- https://bugzilla.mozilla.org/1520741
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1520741#c18
notification_emails:
- telemetry-client-dev@mozilla.com
expires: never
first_run_date:
type: datetime
lifetime: user
send_in_pings:
- glean_client_info
time_unit: day
description: |
The date of the first run of the application.
bugs:
- https://bugzilla.mozilla.org/1525045
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1525045#c18
notification_emails:
- telemetry-client-dev@mozilla.com
expires: never
glean.error:
invalid_value:
type: labeled_counter
send_in_pings:
- all_pings
description:
Counts the number of times a metric was set to an invalid value.
The labels are the `category.name` identifier of the metric.
bugs:
- https://bugzilla.mozilla.org/1499761
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1499761#c5
notification_emails:
- telemetry-client-dev@mozilla.com
expires: never
no_lint:
- COMMON_PREFIX
invalid_label:
type: labeled_counter
send_in_pings:
- all_pings
description:
Counts the number of times a metric was set with an invalid label.
The labels are the `category.name` identifier of the metric.
bugs:
- https://bugzilla.mozilla.org/1499761
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1499761#c5
notification_emails:
- telemetry-client-dev@mozilla.com
expires: never
no_lint:
- COMMON_PREFIX
# 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/.
# This file defines the built-in pings that are recorded by glean telemetry. They are
# automatically converted to Kotlin code at build time using the `glean_parser`
# PyPI package.
$schema: moz://mozilla.org/schemas/glean/pings/1-0-0
baseline:
description: >
This ping is intended to provide metrics that are managed by the library
itself, and not explicitly set by the application or included in the
application's `metrics.yaml` file.
The `baseline` ping is automatically sent when the application is moved to
the background.
include_client_id: true
bugs:
- https://bugzilla.mozilla.org/1512938
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1512938#c3
notification_emails:
- telemetry-client-dev@mozilla.com
metrics:
description: >
The `metrics` ping is intended for all of the metrics that are explicitly
set by the application or are included in the application's `metrics.yaml`
file (except events).
The reported data is tied to the ping's *measurement window*, which is the
time between the collection of two `metrics` ping. Ideally, this window is
expected to be about 24 hours, given that the collection is scheduled daily
at 4AM. Data in the `ping_info` section of the ping can be used to infer the
length of this window.
include_client_id: true
bugs:
- https://bugzilla.mozilla.org/1512938
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1512938#c3
notification_emails:
- telemetry-client-dev@mozilla.com
events:
description: >
The events ping's purpose is to transport all of the event metric information.
The `events` ping is automatically sent when the application is moved to
the background.
include_client_id: true
bugs:
- https://bugzilla.mozilla.org/1512938
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1512938#c3
notification_emails:
- telemetry-client-dev@mozilla.com
......@@ -2,9 +2,4 @@
- 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/. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="mozilla.components.service.glean" >
<application>
<activity android:name=".debug.GleanDebugActivity"
android:exported="true" />
</application>
</manifest>
package="mozilla.components.service.glean" />
/* 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 mozilla.components.service.glean
import androidx.annotation.VisibleForTesting
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.ObsoleteCoroutinesApi
import kotlinx.coroutines.launch
import kotlinx.coroutines.newSingleThreadContext
import kotlinx.coroutines.runBlocking
import mozilla.components.support.base.log.logger.Logger
import java.util.concurrent.ConcurrentLinkedQueue
@ObsoleteCoroutinesApi
internal object Dispatchers {
class WaitableCoroutineScope(val coroutineScope: CoroutineScope) {
// When true, jobs will be run synchronously
internal var testingMode = false
// When true, jobs will be queued and not ran until triggered by calling
// flushQueuedInitialTasks()
@Volatile
private var queueInitialTasks = true
// Use a [ConcurrentLinkedQueue] to take advantage of it's thread safety and no locking
internal val taskQueue: ConcurrentLinkedQueue<() -> Unit> = ConcurrentLinkedQueue()
private val logger = Logger("glean/Dispatchers")
companion object {
// This value was chosen in order to allow several tasks to be queued for execution but
// still be conservative of memory. This queue size is important for cases where
// setUploadEnabled(false) is not called so that we don't continue to queue tasks and
// waste memory.
const val MAX_QUEUE_SIZE = 100
}
/**
* Launch a block of work asynchronously.
*
* If [queueInitialTasks] is true, then the work will be queued and executed when
* [flushQueuedInitialTasks] is called.
*
* If [setTestingMode] has enabled testing mode, the work will run synchronously. This is
* true regardless of whether [queueInitialTasks] is true or not.
*
* @return [Job], or null if queued or run synchronously.
*/
fun launch(
block: suspend CoroutineScope.() -> Unit
): Job? {
return when {
queueInitialTasks -> {
addTaskToQueue(block)
null
}
else -> executeTask(block)
}
}
/**
* Helper function to ensure Glean is being used in testing mode and async
* jobs are being run synchronously. This should be called from every method
* in the testing API to make sure that the results of the main API can be
* tested as expected.
*/
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
fun assertInTestingMode() {
assert(
testingMode
) {
"To use the testing API, Glean must be in testing mode by calling " +
"Glean.enableTestingMode() (for example, in a @Before method)."
}
}
/**
* Enable testing mode, which makes all of the Glean public API synchronous.
*
* @param enabled whether or not to enable the testing mode
*/
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
fun setTestingMode(enabled: Boolean) {
testingMode = enabled
}
/**
* Enable queueing mode, which causes tasks to be queued until launched by calling
* [flushQueuedInitialTasks].
*
* @param enabled whether or not to enable the testing mode
*/
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
fun setTaskQueueing(enabled: Boolean) {
queueInitialTasks = enabled
}
/**
* Stops queueing tasks and processes any tasks in the queue. Since [queueInitialTasks] is
* set to false prior to processing the queue, newly launched tasks should be executed
* on the couroutine scope rather than added to the queue.
*/
internal fun flushQueuedInitialTasks() {
// Setting this to false first should cause any new tasks to just be executed (see
// launch() above) making it safer to process the queue.
//
// NOTE: This has the potential for causing a task to execute out of order in certain
// situations. If a library or thread that runs before init happens to record
// between when the queueInitialTasks is set to false and the taskQueue finishing
// launching, then that task could be executed out of the queued order. See the bugzilla
// bug tracking this for more info: https://bugzilla.mozilla.org/show_bug.cgi?id=1568503
queueInitialTasks = false
taskQueue.forEach { task ->
task.invoke()
}
taskQueue.clear()
}
/**
* Helper function to add task to queue as either a synchronous or asynchronous operation,
* depending on whether [testingMode] is true.
*/
private fun addTaskToQueue(block: suspend CoroutineScope.() -> Unit) {
if (taskQueue.size >= MAX_QUEUE_SIZE) {
logger.error("Exceeded maximum queue size, discarding task")
return
}
if (testingMode) {
logger.info("Task queued for execution in test mode")
taskQueue.add {
runBlocking {
block()
}
}
} else {
logger.info("Task queued for execution and delayed until flushed")
taskQueue.add {
coroutineScope.launch(block