Revision control

Copy as Markdown

# Telemetry
For clients that have "send anonymous usage data" enabled Firefox for Fire TV sends a "core" ping, an "event" ping and "pocket" ping to Mozilla's telemetry service. Sending telemetry can be disabled in the app's settings. Builds of "Firefox for Fire TV" have telemetry enabled by default ("opt-out").
## Baseline ping
Firefox for Fire TV creates and tries to send a "baseline" ping when the app goes to the background. This baseline ping is defined by the [Glean](https://github.com/mozilla-mobile/android-components/tree/master/components/service/glean) component and [documented in the Android Components repository](https://github.com/mozilla-mobile/android-components/blob/master/components/service/glean/docs/baseline.md).
# Core ping
Firefox for Fire TV creates and tries to send a "core" ping whenever the app goes to the background. This core ping uses the same format as Firefox for Android and is [documented on firefox-source-docs.mozilla.org](https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/data/core-ping.html).
## Experiments
We run A/B tests using [Fretboard](https://github.com/mozilla-mobile/android-components/blob/master/components/service/fretboard/README.md#android-components--service--fretboard), with a Kinto backend as the experiment source. As part of the core ping, we send the names of the experiments that the user is part of, in order to measure experiment results.
Fretboard does not currently support experiments with multiple branches, so to handle this use case we create an experiment config for each branch in the split test. Experiment names follow the format
`experimentName-XXXX:branch`
where `XXXX` is the related GitHub issue and `branch` is a letter with **A always representing the control branch**.
# Event ping
In addition to the core ping an event ping for UI telemetry is generated and sent as soon as the app is sent to the background.
# Pocket ping
Similarly to event ping, pocket ping for Pocket feed is generated and sent whenever the app goes to the background. Pocket ping maintains its own unique id that has no direct association with core ping or event ping.
## Settings
As part of the event ping the most recent state of the user's setting is sent (default values in **bold**):
| Setting | Key | Value
|---------------------------------|---------------------------------|----------------------
| Turbo mode currently enabled? | tracking_protection_enabled | **true**/false
| Total home tile count | total_home_tile_count | `<int>`
| Custom home tile count | custom_home_tile_count | `<int>`
| Remote control name | remote_control_name | `<string>`
| App ID | app_id | `<string>`*
(*) This is the public, published app ID, and does not contain any user information
## Events
The event ping contains a list of events ([see event format on readthedocs.io](https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/collection/events.html)) for the following actions:
### Sessions
| Event | category | method | object | value |
|------------------------------------------|----------|------------|--------|--------|
| Start session (App is in the foreground) | action | foreground | app | |
| Stop session (App is in the background) | action | background | app | |
### General
| Event | category | method | object | value | extra. |
|------------------------------------------------------|------------|-------------------------|-------------------|------------|------------|
| Pocket channel: unique videos clicked per session | aggregate | click | pocket_video | `<int>` | |
| App opened from view intent | action | view_intent | app | | |
| Opening the overlay forced a video out of fullscreen | action | programmatically_closed | full_screen_video | | |
| Show Fxa onboarding screen* | action | user_show | fxa | fxa_show_onboarding | |
| Received tab(s) (via FxA send tab feature)\*\* | action | received_tab | fxa | | `device_type`\*\*\* / `total`\*\*\*\* |
(*) Fxa onboarding screen shown when the user first successfully authenticates or when linked to from the accounts page.
(\*) This event is sent at the end of every session.
(\*\*) If a user's tab appears in the UI, this event is sent. If we receive a tab push event that the user does not see
because it does not pass validation (e.g. it contains blank URLs), we record the error in Sentry instead.
(\*\*\*) `device_type` is the type of the device that sent the tabs. These can currently be:
- `desktop`
- `mobile`
- `tablet`
- `tv`
- `vr`
- `unknown`
(\*\*\*\*) In a single send tab event, the server can send multiple tabs from a single device: `total` is the number of tabs received in this event.
### Browser Overlay
| Event | category | method | object | value | extra. |
|----------------------------------------|----------|-----------------------|--------------|--------------------------|---------------|
| Browser: back clicked | action | click | menu | back | |
| Browser: forward clicked | action | click | menu | forward | |
| Browser: refresh clicked | action | click | menu | refresh | |
| Turbo mode switch clicked | action | change | turbo_mode | on/off (the new value) | |
| Pin site switch clicked | action | change | pin_page | on/off (the new value) | desktop_mode* |
| Desktop mode switch clicked | action | change | desktop_mode | on/off (the new value) | |
| Tile clicked | action | click | home_tile | bundled/custom/pocket/youtube_tile** | tile_id*** |
| Tile removed | action | remove | home_tile | bundled/custom | |
| Unique tiles clicked per session | aggregate| click | home_tile | `<int>` | |
| Menu opened by menu key † | action | user_show | menu | | |
| ~~Menu hidden by user~~ † |~~action~~| ~~user_hide~~ | ~~menu~~ | | |
| No menu action taken †† | aggregate| no_action_taken | menu | | |
| Exit Firefox clicked | action | click | menu | exit | |
| Fxa login clicked | action | click | fxa | fxa_login_button | |
| Fxa reauthenticate button clicked | action | click | fxa | fxa_reauthenticate_button | |
| Fxa show profile screen | action | click | fxa | fxa_show_profile_button | |
| Fxa profile get tabs clicked | action | click | fxa | fxa_get_tabs_button | |
| Fxa profile sign out clicked | action | click | fxa | fxa_sign_out_button | |
| Fxa profile back button clicked | action | click | fxa | fxa_go_back_button | |
| Fxa needs reauthentication **** | action | change | fxa | fxa_needs_reauthentication | boolean |
| Fxa logged in state | action | change | fxa | fxa_logged_in | |
| Fxa logged out state | action | change | fxa | fxa_logged_out | |
| Fxa preboarding not now button click | action | click | fxa | fxa_preboarding_not_now2 ††† | |
| Fxa preboarding sign in button click | action | click | fxa | fxa_preboarding_sign_in | |
(*)When the pin site switch is clicked, the state (on/off) of the desktop mode switch is also sent.
(**)YouTube tile clicks are a sub-category of bundled tile clicks- each click will count towards both values.
This value existed from v3.2+, but is intended for removal. For versions after v3.8, the tile_id is included as an extra.
(***)The tile_id is only collected for bundled tiles.
(****)This probe is sent any time the user's FxA sign in state changes (debounced to avoid sending redundant
pings). `boolean` will be `true` if the FxA repo state is `AccountState.NeedsReauthentication`. If it is any
other state, `boolean` will be `false`
(†) This probe was broken starting in the v3.6 release. It was fixed in the v3.9 release. At this time, it was determined
the "No menu action taken" probe was redundant to the "Menu hidden by user" probe so the latter was removed. This probe
does not count if the overlay is opened by the user pressing "back" through their history stack.
(††) This probe was broken in an unknown release; it was fixed in v3.9. This probe does not count if the users exit the
overlay (without taking an action) _and the app_ by pressing the back button when the overlay is opened.
(†††) There was a bug in the implementation of `fxa_preboarding_not_now` (#2843) that caused it to be sent too frequently.
When the bug was fixed, it was updated to `fxa_preboarding_not_now2`. The previous ping is now deprecated.
### Browsing
| Event | category | method | object | value | extra. |
|-----------------------------------------|----------|-----------------------|------------|--------|------------|
| URL start loading (via url bar) | action | type_url | search_bar | | `url`* |
| Search query start loading (via url bar)| action | type_query | search_bar | | `query`* |
| Remote: back pressed ** | action | page | browser | back | `back`* |
| Video opened from YouTube Casting | action | youtube_cast | browser | | |
(*) `query` is a JSON map containing the url bar location:
```js
{
"source": "home"/"menu"
}
```
(*) `url` is a JSON map containing the same map as `query` and the autocomplete details:
```js
{
// Includes "source" above
"autocomplete": true, // Was the URL autocompleted?
"autocompl_src": "default", // Which autocomplete list was used ("default" or "custom")? (Only present if autocomplete is true)
"total": 25 // Total number of items in the used autocomplete list (Only present if autocomplete is true)
}
```
(**) This event fires only when the browser travels back in history, i.e. this event will not fire if:
- The browser is on the last page in history and back is pressed, returning to home/settings or closing the app
- Back is pressed on youtube.com/tv, where we override a back with ESC in order to exit fullscreen mode
(*) `back` is a JSON map containing a hard-coded "controller" string:
```javascript
{
"source": "controller"
}
```
#### Media playback
| Event | category | method | object | value |
|--------------------------------------------|----------|----------------|---------------|----------------|
| MediaSession: play | action | click_or_voice | media_session | play |
| MediaSession: pause | action | click_or_voice | media_session | pause |
| MediaSession: next item | action | click_or_voice | media_session | next |
| MediaSession: previous item | action | click_or_voice | media_session | prev |
| MediaSession: seek | action | click_or_voice | media_session | seek |
| MediaSession: play/pause remote button | action | click | media_session | play_pause_btn |
Fire OS controls media (e.g. videos, audio) playback with a `MediaSession`. MediaSession probes are sent when the user interacts with media through Fire OS (e.g. hardware media buttons, voice commands) **but not** when they interact through web content (e.g. pressing pause with the dpad Cursor). Right now, MediaSession **only supports video** ([#935](https://github.com/mozilla-mobile/firefox-tv/issues/935) is to add audio support).
MediaSession doesn't distinguish between hardware buttons and voice commands. If you want to calculate how often voice commands are used for a given command, you should subtract the number of hardware buttons used for a command (if applicable) from the total number of invocations for that command, e.g.: `play_pause_voice_commands = play + pause - play_pause_btn`. The only media button that interacts with MediaSession on a standard Fire TV remote is the play/pause button.
To elaborate on these events:
- "Next/previous item" is intended to go to the next video/song in a playlist. We send the corresponding key event to the page which must support this functionality (it works on YouTube).
- "Seek" aggregates the "fast-forward", "rewind", and "restart" commands ([#988](https://github.com/mozilla-mobile/firefox-tv/issues/988) is to split up this telemetry)
### Pocket Channel
| Event | category | method | object | value |
|--------------------------------------------|----------|----------------|---------------|----------------|
| Pocket video click | action | click | video_id | `<int>` |
| Pocket video impression* | action | impression | video_id | `<int>` |
(*) Video impressions are aggregated by the user initiating focus on the videos in the Pocket feed and do not represent "impression" in the traditional sense: see #2251 for further discussion.
### Settings Channel
| Event | category | method | object | value |
|---------------------------------------------|------------|-------------|---------------|----------------|
| Confirms clear data dialog | action | change | setting | clear_data |
| Clear cookies and data tile clicked | action | click | setting | clear_data_tile|
| Send usage data tile clicked | action | click | setting | send_data_tile |
| About tile clicked | action | click | setting | about_tile |
| Privacy Notice tile clicked | action | click | setting | privacy_tile |
## Limits
* An event ping will contain up to but no more than 500 events
* No more than 40 pings per type (core/event) are stored on disk for upload at a later time
* No more than 100 pings are sent per day
# Implementation notes
* Event pings are generated (and stored on disk) whenever the onStop() callback of the main activity is triggered. This happens whenever the main screen of the app is no longer visible (The app is in the background or another screen is displayed on top of the app).
* Whenever we are storing pings we are also scheduling an upload. We are using Android’s JobScheduler API for that. This allows the system to run the background task whenever it is convenient and certain criterias are met. The only criteria we are specifying is that we require an active network connection. In most cases this job is executed immediately after the app is in the background.
* Whenever an upload fails we are scheduling a retry. The first retry will happen after 30 seconds (or later if there’s no active network connection at this time). For further retries a exponential backoff policy is used: [30 seconds] * 2 ^ (num_failures - 1)
* An earlier retry of the upload can happen whenever the app is coming to the foreground and sent to the background again (the previous scheduled job is reset and we are starting all over again).