summaryrefslogtreecommitdiffstats
path: root/toolkit/components/telemetry/docs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
commit0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch)
treea31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /toolkit/components/telemetry/docs
parentInitial commit. (diff)
downloadfirefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz
firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/telemetry/docs')
-rw-r--r--toolkit/components/telemetry/docs/collection/custom-pings.rst80
-rw-r--r--toolkit/components/telemetry/docs/collection/events.rst349
-rw-r--r--toolkit/components/telemetry/docs/collection/experiments.rst41
-rw-r--r--toolkit/components/telemetry/docs/collection/histograms.rst411
-rw-r--r--toolkit/components/telemetry/docs/collection/index.rst49
-rw-r--r--toolkit/components/telemetry/docs/collection/measuring-time.rst116
-rw-r--r--toolkit/components/telemetry/docs/collection/sampleHistogram.pngbin0 -> 2825 bytes
-rw-r--r--toolkit/components/telemetry/docs/collection/scalars.rst327
-rw-r--r--toolkit/components/telemetry/docs/collection/uptake.rst114
-rw-r--r--toolkit/components/telemetry/docs/collection/use-counters.rst105
-rw-r--r--toolkit/components/telemetry/docs/collection/user-interactions.rst272
-rw-r--r--toolkit/components/telemetry/docs/collection/webextension-api.rst158
-rw-r--r--toolkit/components/telemetry/docs/concepts/archiving.rst23
-rw-r--r--toolkit/components/telemetry/docs/concepts/crashes.rst25
-rw-r--r--toolkit/components/telemetry/docs/concepts/index.rst23
-rw-r--r--toolkit/components/telemetry/docs/concepts/pings.rst29
-rw-r--r--toolkit/components/telemetry/docs/concepts/sessions.rst37
-rw-r--r--toolkit/components/telemetry/docs/concepts/submission.rst42
-rw-r--r--toolkit/components/telemetry/docs/concepts/subsession_triggers.pngbin0 -> 857375 bytes
-rw-r--r--toolkit/components/telemetry/docs/data/addons-malware-ping.rst42
-rw-r--r--toolkit/components/telemetry/docs/data/anonymous-ping.rst68
-rw-r--r--toolkit/components/telemetry/docs/data/backgroundhangmonitor-ping.rst162
-rw-r--r--toolkit/components/telemetry/docs/data/common-ping.rst42
-rw-r--r--toolkit/components/telemetry/docs/data/coverage-ping.rst40
-rw-r--r--toolkit/components/telemetry/docs/data/crash-ping.rst262
-rw-r--r--toolkit/components/telemetry/docs/data/default-browser-ping.rst90
-rw-r--r--toolkit/components/telemetry/docs/data/deletion-request-ping.rst68
-rw-r--r--toolkit/components/telemetry/docs/data/downgrade-ping.rst30
-rw-r--r--toolkit/components/telemetry/docs/data/environment.rst617
-rw-r--r--toolkit/components/telemetry/docs/data/event-ping.rst92
-rw-r--r--toolkit/components/telemetry/docs/data/first-shutdown-ping.rst11
-rw-r--r--toolkit/components/telemetry/docs/data/health-ping.rst92
-rw-r--r--toolkit/components/telemetry/docs/data/heartbeat-ping.rst62
-rw-r--r--toolkit/components/telemetry/docs/data/index.rst19
-rw-r--r--toolkit/components/telemetry/docs/data/install-ping.rst234
-rw-r--r--toolkit/components/telemetry/docs/data/launcher-process-failure-ping.rst96
-rw-r--r--toolkit/components/telemetry/docs/data/main-ping.rst504
-rw-r--r--toolkit/components/telemetry/docs/data/modules-ping.rst46
-rw-r--r--toolkit/components/telemetry/docs/data/new-profile-ping.rst83
-rw-r--r--toolkit/components/telemetry/docs/data/pioneer-study.rst58
-rw-r--r--toolkit/components/telemetry/docs/data/sync-ping.rst357
-rw-r--r--toolkit/components/telemetry/docs/data/third-party-modules-ping.rst135
-rw-r--r--toolkit/components/telemetry/docs/data/uitour-ping.rst25
-rw-r--r--toolkit/components/telemetry/docs/data/uninstall-ping.rst36
-rw-r--r--toolkit/components/telemetry/docs/data/update-ping.rst79
-rw-r--r--toolkit/components/telemetry/docs/data/xfocsp-error-report-ping.rst69
-rw-r--r--toolkit/components/telemetry/docs/index.rst36
-rw-r--r--toolkit/components/telemetry/docs/internals/index.rst25
-rw-r--r--toolkit/components/telemetry/docs/internals/integration_tests/index.rst143
-rw-r--r--toolkit/components/telemetry/docs/internals/mentored-bugs.rst49
-rw-r--r--toolkit/components/telemetry/docs/internals/pingsender.rst36
-rw-r--r--toolkit/components/telemetry/docs/internals/preferences.rst280
-rw-r--r--toolkit/components/telemetry/docs/internals/review.rst144
-rw-r--r--toolkit/components/telemetry/docs/internals/tests.rst99
-rw-r--r--toolkit/components/telemetry/docs/obsolete/activation-ping.rst69
-rw-r--r--toolkit/components/telemetry/docs/obsolete/core-ping.rst510
-rw-r--r--toolkit/components/telemetry/docs/obsolete/deletion-ping.rst26
-rw-r--r--toolkit/components/telemetry/docs/obsolete/ecosystem-telemetry.rst109
-rw-r--r--toolkit/components/telemetry/docs/obsolete/fhr/architecture.rst226
-rw-r--r--toolkit/components/telemetry/docs/obsolete/fhr/dataformat.rst1998
-rw-r--r--toolkit/components/telemetry/docs/obsolete/fhr/identifiers.rst83
-rw-r--r--toolkit/components/telemetry/docs/obsolete/fhr/index.rst34
-rw-r--r--toolkit/components/telemetry/docs/obsolete/geckoview-streaming.rst26
-rw-r--r--toolkit/components/telemetry/docs/obsolete/hybrid-content.rst374
-rw-r--r--toolkit/components/telemetry/docs/obsolete/index.rst15
-rw-r--r--toolkit/components/telemetry/docs/obsolete/optout-ping.rst33
-rw-r--r--toolkit/components/telemetry/docs/obsolete/uitelemetry/index.rst146
-rw-r--r--toolkit/components/telemetry/docs/start/adding-a-new-probe.rst153
-rw-r--r--toolkit/components/telemetry/docs/start/index.rst28
-rw-r--r--toolkit/components/telemetry/docs/start/report-gecko-telemetry-in-glean.rst36
70 files changed, 10298 insertions, 0 deletions
diff --git a/toolkit/components/telemetry/docs/collection/custom-pings.rst b/toolkit/components/telemetry/docs/collection/custom-pings.rst
new file mode 100644
index 0000000000..395a23aace
--- /dev/null
+++ b/toolkit/components/telemetry/docs/collection/custom-pings.rst
@@ -0,0 +1,80 @@
+.. _submitting-customping:
+
+=======================
+Submitting custom pings
+=======================
+
+Custom pings can be submitted from JavaScript using:
+
+.. code-block:: js
+
+ TelemetryController.submitExternalPing(type, payload, options)
+
+- ``type`` - a ``string`` that is the type of the ping, limited to ``/^[a-z0-9][a-z0-9-]+[a-z0-9]$/i``.
+- ``payload`` - the actual payload data for the ping, has to be a JSON style object.
+- ``options`` - optional, an object containing additional options:
+ - ``addClientId``- whether to add the client id to the ping, defaults to ``false``
+ - ``addEnvironment`` - whether to add the environment data to the ping, defaults to ``false``
+ - ``overrideEnvironment`` - a JSON style object that overrides the environment data
+
+``TelemetryController`` will assemble a ping with the passed payload and the specified options.
+That ping will be archived locally for use with Shield and inspection in ``about:telemetry``.
+If preferences allow the upload of Telemetry pings, the ping will be uploaded at the next opportunity (this is subject to throttling, retry-on-failure, etc.).
+
+.. important::
+
+ Every new or changed data collection in Firefox needs a `data collection review <https://wiki.mozilla.org/Firefox/Data_Collection>`__ from a Data Steward.
+
+Submission constraints
+----------------------
+
+When submitting pings on shutdown, they should not be submitted after Telemetry shutdown.
+Pings should be submitted at the latest within:
+
+- the `observer notification <https://developer.mozilla.org/docs/Observer_Notifications#Application_shutdown>`_ ``"profile-before-change"``
+- the :ref:`AsyncShutdown phase <AsyncShutdown_phases>` ``sendTelemetry``
+
+There are other constraints that can lead to a ping submission getting dropped:
+
+- invalid ping type strings.
+- invalid payload types: E.g. strings instead of objects.
+- oversized payloads: We currently only drop pings >1MB, but targeting sizes of <=10KB is recommended.
+
+Tools
+=====
+
+Helpful tools for designing new pings include:
+
+- `gzipServer <https://github.com/mozilla/gzipServer>`_ - a Python script that can run locally and receives and saves Telemetry pings. Making Firefox send to it allows inspecting outgoing pings easily.
+- ``about:telemetry`` - allows inspecting submitted pings from the local archive, including all custom ones.
+
+Designing custom pings
+======================
+
+In general, creating a new custom ping means you don't benefit automatically from the existing tooling. Further work is needed to make data show up in re:dash or other analysis tools.
+
+In addition to the `data collection review <https://wiki.mozilla.org/Firefox/Data_Collection>`__, questions to guide a new ping design are:
+
+- Submission interval & triggers:
+ - What events trigger ping submission?
+ - What interval is the ping submitted in?
+ - Is there a throttling mechanism?
+ - What is the desired latency? (submitting "at least daily" still leads to certain latency tails)
+ - Are pings submitted on a clock schedule? Or based on "time since session start", "time since last ping" etc.? (I.e. will we get sharp spikes in submission volume?)
+- Size and volume:
+ - What’s the size of the submitted payload?
+ - What's the full ping size including metadata in the pipeline?
+ - What’s the target population?
+ - What's the overall estimated volume?
+- Dataset:
+ - Is it opt-out?
+ - Does it need to be opt-out?
+ - Does it need to be in a separate ping? (why can’t the data live in probes?)
+- Privacy:
+ - Is there risk to leak PII?
+ - How is that risk mitigated?
+- Data contents:
+ - Does the submitted data answer the posed product questions?
+ - Does the shape of the data allow to answer the questions efficiently?
+ - Is the data limited to what's needed to answer the questions?
+ - Does the data use common formats? (i.e. can we re-use tooling or analysis know-how)
diff --git a/toolkit/components/telemetry/docs/collection/events.rst b/toolkit/components/telemetry/docs/collection/events.rst
new file mode 100644
index 0000000000..831c40a8bc
--- /dev/null
+++ b/toolkit/components/telemetry/docs/collection/events.rst
@@ -0,0 +1,349 @@
+.. _eventtelemetry:
+
+======
+Events
+======
+
+Across the different Firefox initiatives, there is a common need for a mechanism for recording, storing, sending & analysing application usage in an event-oriented format.
+*Event Telemetry* specifies a common events data format, which allows for broader, shared usage of data processing tools.
+Adding events is supported in artifact builds and build faster workflows.
+
+For events recorded into Firefox Telemetry we also provide an API that opaquely handles storage and submission to our servers.
+
+.. important::
+
+ Every new or changed data collection in Firefox needs a `data collection review <https://wiki.mozilla.org/Firefox/Data_Collection>`__ from a Data Steward.
+
+.. _events.serializationformat:
+
+Serialization format
+====================
+
+Events are submitted in an :doc:`../data/event-ping` as an array, e.g.:
+
+.. code-block:: js
+
+ [
+ [2147, "ui", "click", "back_button"],
+ [2213, "ui", "search", "search_bar", "google"],
+ [2892, "ui", "completion", "search_bar", "yahoo",
+ {"querylen": "7", "results": "23"}],
+ [5434, "dom", "load", "frame", null,
+ {"prot": "https", "src": "script"}],
+ // ...
+ ]
+
+Each event is of the form:
+
+.. code-block:: js
+
+ [timestamp, category, method, object, value, extra]
+
+Where the individual fields are:
+
+- ``timestamp``: ``Number``, positive integer. This is the time in ms when the event was recorded, relative to the main process start time.
+- ``category``: ``String``, identifier. The category is a group name for events and helps to avoid name conflicts.
+- ``method``: ``String``, identifier. This describes the type of event that occurred, e.g. ``click``, ``keydown`` or ``focus``.
+- ``object``: ``String``, identifier. This is the object the event occurred on, e.g. ``reload_button`` or ``urlbar``.
+- ``value``: ``String``, optional, may be ``null``. This is a user defined value, providing context for the event.
+- ``extra``: ``Object``, optional, may be ``null``. This is an object of the form ``{"key": "value", ...}``, both keys and values need to be strings, keys are identifiers. This is used for events where additional richer context is needed.
+
+.. _eventlimits:
+
+Limits
+------
+
+Each ``String`` marked as an identifier (the event ``name``, ``category``, ``method``,
+``object``, and the keys of ``extra``) is restricted to be composed of alphanumeric ASCII
+characters ([a-zA-Z0-9]) plus infix underscores ('_' characters that aren't the first or last).
+``category`` is also permitted infix periods ('.' characters, so long as they aren't the
+first or last character).
+
+For the Firefox Telemetry implementation, several fields are subject to length limits:
+
+- ``category``: Max. byte length is ``30``.
+- ``method``: Max. byte length is ``20``.
+- ``object``: Max. byte length is ``20``.
+- ``value``: Max. byte length is ``80``.
+- ``extra``: Max. number of keys is ``10``.
+
+ - Each extra key name: Max. string length is ``15``.
+ - Each extra value: Max. byte length is ``80``.
+
+Only ``value`` and the values of ``extra`` will be truncated if over the specified length.
+Any other ``String`` going over its limit will be reported as an error and the operation
+aborted.
+
+.. _eventdefinition:
+
+The YAML definition file
+========================
+
+Any event recorded into Firefox Telemetry must be registered before it can be recorded.
+For any code that ships as part of Firefox that happens in `Events.yaml <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/Events.yaml>`_.
+
+The probes in the definition file are represented in a fixed-depth, three-level structure. The first level contains *category* names (grouping multiple events together), the second level contains *event* names, under which the events properties are listed. E.g.:
+
+.. code-block:: yaml
+
+ # The following is a category of events named "browser.ui".
+ browser.ui:
+ click: # This is the event named "click".
+ objects: ["reload-btn"] # List the objects for this event.
+ description: >
+ Describes this event in detail, potentially over
+ multiple lines.
+ # ... and more event properties.
+ # ... and more events.
+ # This is the "dom" category.
+ search:
+ # And the "completion" event.
+ completion:
+ # ...
+ description: Recorded when a search completion suggestion was clicked.
+ extra_keys:
+ distance: The edit distance to the current search query input.
+ loadtime: How long it took to load this completion entry.
+ # ...
+
+Category and event names are subject to the limits :ref:`specified above <eventlimits>`.
+
+The following event properties are valid:
+
+- ``methods`` *(optional, list of strings)*: The valid event methods. If not set this defaults to ``[eventName]``.
+- ``objects`` *(required, list of strings)*: The valid event objects.
+- ``description`` *(required, string)*: Description of the event and its semantics.
+- ``release_channel_collection`` *(optional, string)*: This can be set to ``opt-in`` (default) or ``opt-out``.
+- ``record_in_processes`` *(required, list of strings)*: A list of processes the event can be recorded in. Currently supported values are:
+
+ - ``main``
+ - ``content``
+ - ``gpu``
+ - ``all_children`` (record in all the child processes)
+ - ``all`` (record in all the processes).
+
+- ``bug_numbers`` *(required, list of numbers)*: A list of Bugzilla bug numbers that are relevant to this event.
+- ``notification_emails`` *(required, list of strings)*: A list of emails of owners for this event. This is used for contact for data reviews and potentially to email alerts.
+- expiry: There are two properties that can specify expiry, at least one needs to be set:
+
+ - ``expiry_version`` *(required, string)*: The version number in which the event expires, e.g. ``"50"``, or ``"never"``. A version number of type "N" is automatically converted to "N.0a1" in order to expire the event also in the development channels. For events that never expire the value ``never`` can be used.
+
+- ``extra_keys`` *(optional, object)*: An object that specifies valid keys for the ``extra`` argument and a description - see the example above.
+- ``products`` *(required, list of strings)*: A list of products the event can be recorded on. Currently supported values are:
+
+ - ``firefox`` - Collected in Firefox Desktop for submission via Firefox Telemetry.
+ - ``thunderbird`` - Collected in Thunderbird for submission via Thunderbird Telemetry.
+
+- ``operating_systems`` *(optional, list of strings)*: This field restricts recording to certain operating systems only. It defaults to ``all``. Currently supported values are:
+
+ - ``mac``
+ - ``linux``
+ - ``windows``
+ - ``android``
+ - ``unix``
+ - ``all`` (record on all operating systems)
+
+.. note::
+
+ Combinations of ``category``, ``method``, and ``object`` defined in the file must be unique.
+
+The API
+=======
+
+Public JS API
+-------------
+
+``recordEvent()``
+~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ Services.telemetry.recordEvent(category, method, object, value, extra);
+
+Record a registered event.
+
+* ``value``: Optional, may be ``null``. A string value, limited to 80 bytes.
+* ``extra``: Optional. An object with string keys & values. Key strings are limited to what was registered. Value strings are limited to 80 bytes.
+
+Throws if the combination of ``category``, ``method`` and ``object`` is unknown.
+Recording an expired event will not throw, but print a warning into the browser console.
+
+.. note::
+
+ Each ``recordEvent`` of a known non-expired combination of ``category``, ``method``, and
+ ``object``, will be :ref:`summarized <events.event-summary>`.
+
+.. warning::
+
+ Event Telemetry recording is designed to be cheap, not free. If you wish to record events in a performance-sensitive piece of code, store the events locally and record them only after the performance-sensitive piece ("hot path") has completed.
+
+Example:
+
+.. code-block:: js
+
+ Services.telemetry.recordEvent("ui", "click", "reload-btn");
+ // event: [543345, "ui", "click", "reload-btn"]
+ Services.telemetry.recordEvent("ui", "search", "search-bar", "google");
+ // event: [89438, "ui", "search", "search-bar", "google"]
+ Services.telemetry.recordEvent("ui", "completion", "search-bar", "yahoo",
+ {"querylen": "7", "results": "23"});
+ // event: [982134, "ui", "completion", "search-bar", "yahoo",
+ // {"qerylen": "7", "results": "23"}]
+
+``setEventRecordingEnabled()``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ Services.telemetry.setEventRecordingEnabled(category, enabled);
+
+Event recording is currently disabled by default for events registered in Events.yaml.
+Dynamically-registered events (those registered using ``registerEvents()``) are enabled by default, and cannot be disabled.
+Privileged add-ons and Firefox code can enable & disable recording events for specific categories using this function.
+
+Example:
+
+.. code-block:: js
+
+ Services.telemetry.setEventRecordingEnabled("ui", true);
+ // ... now events in the "ui" category will be recorded.
+ Services.telemetry.setEventRecordingEnabled("ui", false);
+ // ... now "ui" events will not be recorded anymore.
+
+.. note::
+
+ Even if your event category isn't enabled, counts of events that attempted to be recorded will
+ be :ref:`summarized <events.event-summary>`.
+
+.. _registerevents:
+
+``registerEvents()``
+~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ Services.telemetry.registerEvents(category, eventData);
+
+Register new events from add-ons.
+
+* ``category`` - *(required, string)* The category the events are in.
+* ``eventData`` - *(required, object)* An object of the form ``{eventName1: event1Data, ...}``, where each events data is an object with the entries:
+
+ * ``methods`` - *(required, list of strings)* The valid event methods.
+ * ``objects`` - *(required, list of strings)* The valid event objects.
+ * ``extra_keys`` - *(optional, list of strings)* The valid extra keys for the event.
+ * ``record_on_release`` - *(optional, bool)*
+ * ``expired`` - *(optional, bool)* Whether this event entry is expired. This allows recording it without error, but it will be discarded. Defaults to false.
+
+For events recorded from add-ons, registration happens at runtime. Any new events must first be registered through this function before they can be recorded.
+The registered categories will automatically be enabled for recording, and cannot be disabled.
+If a dynamic event uses the same category as a static event, the category will also be enabled upon registration.
+
+After registration, the events can be recorded through the ``recordEvent()`` function. They will be submitted in event pings like static events are, under the ``dynamic`` process.
+
+New events registered here are subject to the same limitations as the ones registered through ``Events.yaml``, although the naming was in parts updated to recent policy changes.
+
+When add-ons are updated, they may re-register all of their events. In that case, any changes to events that are already registered are ignored. The only exception is expiry; an event that is re-registered with ``expired: true`` will not be recorded anymore.
+
+Example:
+
+.. code-block:: js
+
+ Services.telemetry.registerEvents("myAddon.interaction", {
+ "click": {
+ methods: ["click"],
+ objects: ["red_button", "blue_button"],
+ }
+ });
+ // Now events can be recorded.
+ Services.telemetry.recordEvent("myAddon.interaction", "click", "red_button");
+
+Internal API
+------------
+
+.. code-block:: js
+
+ Services.telemetry.snapshotEvents(dataset, clear, eventLimit);
+ Services.telemetry.clearEvents();
+
+These functions are only supposed to be used by Telemetry internally or in tests.
+
+Also, the ``event-telemetry-storage-limit-reached`` topic is notified when the event ping event
+limit is reached (1000 event records).
+This is intended only for use internally or in tests.
+
+.. _events.event-summary:
+
+Event Summary
+=============
+
+Calling ``recordEvent`` on any non-expired registered event will accumulate to a
+:doc:`Scalar <scalars>` for ease of analysing uptake and usage patterns. Even if the event category
+isn't enabled.
+
+The scalar is ``telemetry.event_counts`` for statically-registered events (the ones in
+``Events.yaml``) and ``telemetry.dynamic_event_counts`` for dynamically-registered events (the ones
+registered via ``registerEvents``). These are :ref:`keyed scalars <scalars.keyed-scalars>` where
+the keys are of the form ``category#method#object`` and the values are counts of the number of
+times ``recordEvent`` was called with that combination of ``category``, ``method``, and ``object``.
+
+These two scalars have a default maximum key limit of 500 per process.
+
+Example:
+
+.. code-block:: js
+
+ // telemetry.event_counts summarizes in the same process the events were recorded
+
+ // Let us suppose in the parent process this happens:
+ Services.telemetry.recordEvent("interaction", "click", "document", "xuldoc");
+ Services.telemetry.recordEvent("interaction", "click", "document", "xuldoc-neighbour");
+
+ // And in each of child processes 1 through 4, this happens:
+ Services.telemetry.recordEvent("interaction", "click", "document", "htmldoc");
+
+In the case that ``interaction.click.document`` is statically-registered, this will result in the
+parent-process scalar ``telemetry.event_counts`` having a key ``interaction#click#document`` with
+value ``2`` and the content-process scalar ``telemetry.event_counts`` having a key
+``interaction#click#document`` with the value ``4``.
+
+All dynamically-registered events end up in the dynamic-process ``telemetry.dynamic_event_counts``
+(notice the different name) regardless of in which process the events were recorded. From the
+example above, if ``interaction.click.document`` was registered with ``registerEvents`` then
+the dynamic-process scalar ``telemetry.dynamic_event_counts`` would have a key
+``interaction#click#document`` with the value ``6``.
+
+Testing
+=======
+
+Tests involving Event Telemetry often follow this four-step form:
+
+1. ``Services.telemetry.clearEvents();`` To minimize the effects of prior code and tests.
+2. ``Services.telemetry.setEventRecordingEnabled(myCategory, true);`` To enable the collection of
+ your events. (May or may not be relevant in your case)
+3. ``runTheCode();`` This is part of the test where you call the code that's supposed to collect
+ Event Telemetry.
+4. ``TelemetryTestUtils.assertEvents(expected, filter, options);`` This will check the
+ events recorded by Event Telemetry against your provided list of expected events.
+ If you only need to check the number of events recorded, you can use
+ ``TelemetryTestUtils.assertNumberOfEvents(expectedNum, filter, options);``.
+ Both utilities have :searchfox:`helpful inline documentation <toolkit/components/telemetry/tests/utils/TelemetryTestUtils.sys.mjs>`.
+
+
+Version History
+===============
+
+- Firefox 79: ``geckoview`` support removed (see `bug 1620395 <https://bugzilla.mozilla.org/show_bug.cgi?id=1620395>`__).
+- Firefox 52: Initial event support (`bug 1302663 <https://bugzilla.mozilla.org/show_bug.cgi?id=1302663>`_).
+- Firefox 53: Event recording disabled by default (`bug 1329139 <https://bugzilla.mozilla.org/show_bug.cgi?id=1329139>`_).
+- Firefox 54: Added child process events (`bug 1313326 <https://bugzilla.mozilla.org/show_bug.cgi?id=1313326>`_).
+- Firefox 56: Added support for recording new probes from add-ons (`bug 1302681 <bug https://bugzilla.mozilla.org/show_bug.cgi?id=1302681>`_).
+- Firefox 58:
+
+ - Ignore re-registering existing events for a category instead of failing (`bug 1408975 <https://bugzilla.mozilla.org/show_bug.cgi?id=1408975>`_).
+ - Removed support for the ``expiry_date`` property, as it was unused (`bug 1414638 <https://bugzilla.mozilla.org/show_bug.cgi?id=1414638>`_).
+- Firefox 61:
+
+ - Enabled support for adding events in artifact builds and build-faster workflows (`bug 1448945 <https://bugzilla.mozilla.org/show_bug.cgi?id=1448945>`_).
+ - Added summarization of events (`bug 1440673 <https://bugzilla.mozilla.org/show_bug.cgi?id=1440673>`_).
+- Firefox 66: Replace ``cpp_guard`` with ``operating_systems`` (`bug 1482912 <https://bugzilla.mozilla.org/show_bug.cgi?id=1482912>`_)`
diff --git a/toolkit/components/telemetry/docs/collection/experiments.rst b/toolkit/components/telemetry/docs/collection/experiments.rst
new file mode 100644
index 0000000000..d9c926fcea
--- /dev/null
+++ b/toolkit/components/telemetry/docs/collection/experiments.rst
@@ -0,0 +1,41 @@
+=====================
+Experiment Annotation
+=====================
+This API allows privileged JavaScript to annotate the :doc:`../data/environment` with any experiments a client is participating in.
+
+The experiment annotations are sent with any ping that includes the :doc:`../data/environment` data.
+
+The JS API
+==========
+Privileged JavaScript code can annotate experiments using the functions exposed by ``TelemetryEnvironment.sys.mjs``.
+
+The following function adds an annotation to the environment for the provided ``id``, ``branch`` and ``options``. Calling this function repeatedly with the same ``id`` will overwrite the state and trigger new subsessions (subject to throttling).
+``options`` is an object that may contain ``type`` to tag the experiment with a specific type or ``enrollmentId`` to tag the enrollment in this experiment with an identifier.
+
+.. code-block:: js
+
+ TelemetryEnvironment.setExperimentActive(id, branch, [options={}}])
+
+This removes the annotation for the experiment with the provided ``id``.
+
+.. code-block:: js
+
+ TelemetryEnvironment.setExperimentInactive(id)
+
+This synchronously returns a dictionary containing the information for each active experiment.
+
+.. code-block:: js
+
+ TelemetryEnvironment.getActiveExperiments()
+
+.. note::
+
+ Both ``setExperimentActive`` and ``setExperimentInactive`` trigger a new subsession. However
+ the latter only does so if there was an active experiment with the provided ``id``.
+
+Limits and restrictions
+-----------------------
+To prevent abuses, the content of the experiment ``id`` and ``branch`` is limited to
+100 characters in length.
+``type`` is limited to a length of 20 characters.
+``enrollmentId`` is limited to 40 characters (chosen to be just a little longer than the 36-character long GUID text representation).
diff --git a/toolkit/components/telemetry/docs/collection/histograms.rst b/toolkit/components/telemetry/docs/collection/histograms.rst
new file mode 100644
index 0000000000..1998c6062e
--- /dev/null
+++ b/toolkit/components/telemetry/docs/collection/histograms.rst
@@ -0,0 +1,411 @@
+==========
+Histograms
+==========
+
+In Firefox, the Telemetry system collects various measures of Firefox performance, hardware, usage and customizations and submits it to Mozilla. The Telemetry data collected by a single client can be examined from the integrated ``about:telemetry`` browser page, while the aggregated reports across entire user populations are publicly available at `telemetry.mozilla.org <https://telemetry.mozilla.org>`_.
+
+.. important::
+
+ Every new or changed data collection in Firefox needs a `data collection review <https://wiki.mozilla.org/Firefox/Data_Collection>`__ from a Data Steward.
+
+The following sections explain how to add a new measurement to Telemetry.
+
+Overview
+========
+
+Telemetry histograms are an efficient way to collect numeric measurements like multiple counts or timings.
+They are collected through a common API and automatically submitted with the :doc:`main ping <../data/main-ping>`.
+
+.. hint::
+
+ Before adding a new histogram, you should consider using other collection mechanisms. For example, if the need is to track a single scalar value (e.g. number, boolean or string), you should use :doc:`scalars`.
+
+The histogram below is taken from Firefox's ``about:telemetry`` page. It shows a histogram used for tracking plugin shutdown times and the data collected over a single Firefox session. The timing data is grouped into buckets where the height of the blue bars represents the number of items in each bucket. The tallest bar, for example, indicates that there were 63 plugin shutdowns lasting between 129ms and 204ms.
+
+.. image:: sampleHistogram.png
+
+The histograms on the ``about:telemetry`` page only show the non-empty buckets in a histogram, except for the bucket to the left of the first non-empty bucket and the bucket to the right of the last non-empty bucket.
+
+.. _choosing-histogram-type:
+
+Choosing a Histogram Type
+=========================
+
+The first step to adding a new histogram is to choose the histogram type that best represents the data being measured. The sample histogram used above is an "exponential" histogram.
+
+.. note::
+
+ Only ``flag`` and ``count`` histograms have default values. All other histograms start out empty and are only submitted if a value is recorded.
+
+``boolean``
+-----------
+These histograms only record boolean values. Multiple boolean entries can be recorded in the same histogram during a single browsing session, e.g. if a histogram is measuring user choices in a dialog box with options "Yes" or "No", a new boolean value is added every time the dialog is displayed.
+
+``linear``
+----------
+Linear histograms are similar to enumerated histograms, except each bucket is associated with a range of values instead of a single enum value. The range of values covered by each bucket increases linearly from the previous bucket, e.g. one bucket might count the number of occurrences of values between 0 to 9, the next bucket would cover values 10-19, the next 20-29, etc. This bucket type is useful if there aren't orders of magnitude differences between the minimum and maximum values stored in the histogram, e.g. if the values you are storing are percentages 0-100%.
+
+.. note::
+
+ If you need a linear histogram with buckets < 0, 1, 2 ... N >, then you should declare an enumerated histogram. This restriction was added to prevent developers from making a common off-by-one mistake when specifying the number of buckets in a linear histogram.
+
+``exponential``
+---------------
+Exponential histograms are similar to linear histograms but the range of values covered by each bucket increases exponentially. As an example of its use, consider the timings of an I/O operation whose duration might normally fall in the range of 0ms-50ms but extreme cases might have durations in seconds or minutes. For such measurements, you would want finer-grained bucketing in the normal range but coarser-grained bucketing for the extremely large values. An exponential histogram fits this requirement since it has "narrow" buckets near the minimum value and significantly "wider" buckets near the maximum value.
+
+``categorical``
+---------------
+Categorical histograms are similar to enumerated histograms. However, instead of specifying ``n_buckets``, you specify an array of strings in the ``labels`` field. From JavaScript, the label values or their indices can be passed as strings to ``histogram.add()``. From C++ you can use ``AccumulateCategorical`` with passing a value from the corresponding ``Telemetry::LABEL_*`` enum, or, in exceptional cases the string values.
+
+.. note::
+
+ You can add new labels to a categorical histogram later on,
+ up to the configured maximum.
+ Categorical histograms by default support up to 50 labels,
+ but you can set it higher using the ``n_values`` property.
+ If you need to add labels beyond the maximum later,
+ you need to use a new histogram name.
+ See `Changing a Histogram`_ for details.
+
+``enumerated``
+--------------
+This histogram type is intended for storing "enum" values, when you can't specify labels and thus cannot use ``categorical`` histograms. An enumerated histogram consists of a fixed number of *buckets* (specified by ``n_values``), each of which is associated with a consecutive integer value (the bucket's *label*), `0` to `n_values`. Each bucket corresponds to an enum value and counts the number of times its particular enum value was recorded; except for the `n_values` bucket, which counts all values greater than or equal to n_values.
+
+You might use this type of histogram if, for example, you wanted to track the relative popularity of SSL handshake types. Whenever the browser started an SSL handshake, it would record one of a limited number of enum values which uniquely identifies the handshake type.
+
+.. note::
+
+ Set ``n_values`` to a slightly larger value than needed to allow for new enum values in the future. See `Changing a histogram`_ if you need to add more enums later.
+
+``flag``
+--------
+*Deprecated* (please use boolean :doc:`scalars`).
+
+This histogram type allows you to record a single value (`0` or `1`, default `0`). This type is useful if you need to track whether a feature was ever used during a Firefox session. You only need to add a single line of code which sets the flag when the feature is used because the histogram is initialized with a default value of `0`/`false` (flag not set). Thus, recording a value of `0` is not allowed and asserts.
+
+Flag histograms will ignore any changes after the flag is set, so once the flag is set, it cannot be unset.
+
+``count``
+---------
+*Deprecated* (please use uint :doc:`scalars`).
+
+This histogram type is used when you want to record a count of something. It only stores a single value and defaults to `0`.
+
+.. _histogram-type-keyed:
+
+Keyed Histograms
+----------------
+
+Keyed histograms are collections of one of the histogram types above, indexed by a string key. This is for example useful when you want to break down certain counts by a name, like how often searches happen with which search engine.
+Note that when you need to record for a small set of known keys, using separate plain histograms is more efficient.
+
+.. warning::
+
+ Keyed histograms are currently not supported in the `histogram change detector <https://alerts.telemetry.mozilla.org/index.html>`_.
+
+Declaring a Histogram
+=====================
+
+Histograms should be declared in the `Histograms.json <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/Histograms.json>`_ file. These declarations are checked for correctness at `compile time <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/gen_histogram_data.py>`_ and used to generate C++ code.
+
+The following is a sample histogram declaration from ``Histograms.json`` for a histogram named ``MEMORY_RESIDENT`` which tracks the amount of resident memory used by a process:
+
+
+.. code-block:: json
+
+ {
+ "MEMORY_RESIDENT": {
+ "record_in_processes": ["main", "content"],
+ "alert_emails": ["team@mozilla.xyz"],
+ "expires_in_version": "never",
+ "kind": "exponential",
+ "low": 32768,
+ "high": 1048576,
+ "n_buckets": 50,
+ "bug_numbers": [12345],
+ "description": "Resident memory size (KB)"
+ }
+ }
+
+Histograms which track timings in milliseconds or microseconds should suffix their names with ``"_MS"`` and ``"_US"`` respectively. Flag-type histograms should have the suffix ``"_FLAG"`` in their name.
+
+The possible fields in a histogram declaration are listed below.
+
+``record_in_processes``
+-----------------------
+Required. This field is a list of processes this histogram can be recorded in. Currently-supported values are:
+
+- ``main``
+- ``content``
+- ``gpu``
+- ``all_childs`` (record in all child processes)
+- ``all`` (record in all processes)
+
+``alert_emails``
+----------------
+Required. This field is a list of e-mail addresses that should be notified when the distribution of the histogram changes significantly from one build-id to the other. This can be useful to detect regressions. Note that all alerts will be sent automatically to mozilla.dev.telemetry-alerts.
+
+``expires_in_version``
+----------------------
+Required. The version number in which the histogram expires; e.g. a value of `"30"` will mean that the histogram stops recording from Firefox 30 on. A version number of type ``"N"`` is automatically converted to ``"N.0a1"`` in order to expire the histogram also in the development channels. For histograms that never expire the value ``"never"`` can be used as in the example above. Accumulating data into an expired histogram is effectively a non-op and will not record anything.
+
+``kind``
+--------
+Required. One of the histogram types described in the previous section. Different histogram types require different fields to be present in the declaration.
+
+``keyed``
+---------
+Optional, boolean, defaults to ``false``. Determines whether this is a *keyed histogram*.
+
+``keys``
+---------
+Optional, list of strings. Only valid for *keyed histograms*. Defines a case sensitive list of allowed keys that can be used for this histogram. The list is limited to 30 keys with a maximum length of 20 characters. When using a key that is not in the list, the accumulation is discarded and a warning is printed to the browser console.
+
+``low``
+-------
+Optional, the default value is ``1``. This field represents the minimum value expected in the histogram. Note that all histograms automatically get a bucket with label ``0`` for counting values below the ``low`` value. If a histogram does not specify a ``low`` value, it will always have a ``"0"`` bucket (for negative or zero values) and a ``"1"`` bucket (for values between ``1`` and the next bucket).
+
+
+``high``
+--------
+Required for linear and exponential histograms. The maximum value to be stored in a linear or exponential histogram. Any recorded values greater than this maximum will be counted in the last bucket.
+
+``n_buckets``
+-------------
+Required for linear and exponential histograms. The number of buckets in a linear or exponential histogram.
+
+.. note::
+
+ The maximum value for ``n_buckets`` is 100. The more buckets, the larger the storage and transfer costs borne by our users and our pipeline.
+
+``n_values``
+------------
+Required for enumerated histograms. Similar to n_buckets, it represent the number of elements in the enum.
+
+.. note::
+
+ The maximum value for ``n_values`` is 100. The more values, the larger the storage and transfer costs borne by our users and our pipeline.
+
+``labels``
+----------
+Required for categorical histograms. This is an array of strings which are the labels for different values in this histograms. The labels are restricted to a C++-friendly subset of characters (``^[a-z][a-z0-9_]+[a-z0-9]$``). This field is limited to 100 strings, each with a maximum length of 20 characters.
+
+``bug_numbers``
+---------------
+Required for all new histograms. This is an array of integers and should at least contain the bug number that added the probe and additionally other bug numbers that affected its behavior.
+
+``description``
+---------------
+Required. A description of the data tracked by the histogram, e.g. _"Resident memory size"_
+
+``cpp_guard`` (obsolete, use ``operating_systems``)
+---------------------------------------------------
+Optional. This field inserts an #ifdef directive around the histogram's C++ declaration. This is typically used for platform-specific histograms, e.g. ``"cpp_guard": "ANDROID"``
+
+``operating_systems``
+---------------------
+Optional. This field restricts recording to certain operating systems only. Use that in-place of previous ``cpp_guards`` to avoid inclusion on not-specified operating systems.
+Currently supported values are:
+
+- ``mac``
+- ``linux``
+- ``windows``
+- ``android``
+- ``unix``
+- ``all`` (record on all operating systems)
+
+If this field is left out it defaults to ``all``.
+
+``releaseChannelCollection``
+----------------------------
+Optional. This is one of:
+
+* ``"opt-in"``: (default value) This histogram is submitted by default on pre-release channels, unless the user opts out.
+* ``"opt-out"``: This histogram is submitted by default on release and pre-release channels, unless the user opts out.
+
+.. warning::
+
+ Because they are collected by default, opt-out probes need to meet a higher "user benefit" threshold than opt-in probes during data collection review.
+
+
+ Every new or changed data collection in Firefox needs a `data collection review <https://wiki.mozilla.org/Firefox/Data_Collection>`__ from a Data Steward.
+
+.. _histogram-products:
+
+``products``
+-------------
+Required. This field is a list of products this histogram can be recorded on. Currently-supported values are:
+
+- ``firefox`` - Collected in Firefox Desktop for submission via Firefox Telemetry.
+- ``geckoview_streaming`` - See :doc:`this guide <../start/report-gecko-telemetry-in-glean>` for how to stream data through geckoview to the Glean SDK.
+- ``thunderbird`` - Collected in Thunderbird for submission via Thunderbird Telemetry.
+
+``record_into_store``
+---------------------
+
+Optional. This field is a list of stores this histogram should be recorded into.
+If this field is left out it defaults to ``[main]``.
+
+Changing a histogram
+====================
+
+Changing a histogram declaration after the histogram has been released is tricky.
+Many tools
+(like `the aggregator <https://github.com/mozilla/python_mozaggregator>`_)
+assume histograms don't change.
+The current recommended procedure is to change the name of the histogram.
+
+* When changing existing histograms, the recommended pattern is to use a versioned name (``PROBE``, ``PROBE_2``, ``PROBE_3``, ...).
+* For enum histograms, it's recommended to set "n_buckets" to a slightly larger value than needed since new elements may be added to the enum in the future.
+
+The one exception is `Categorical`_ histograms.
+They can be changed by adding labels until it reaches the configured maximum
+(default of 50, or the value of ``n_values``).
+If you need to change the configured maximum,
+then you must change the histogram name as mentioned above.
+
+Histogram values
+================
+
+The values you can accumulate to Histograms are limited by their internal representation.
+
+Telemetry Histograms do not record negative values, instead clamping them to 0 before recording.
+
+Telemetry Histograms do not record values greater than 2^31, instead clamping them to INT_MAX before recording.
+
+Adding a JavaScript Probe
+=========================
+
+A Telemetry probe is the code that measures and stores values in a histogram. Probes in privileged JavaScript code can make use of the `nsITelemetry <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/nsITelemetry.idl>`_ interface to get references to histogram objects. A new value is recorded in the histogram by calling ``add`` on the histogram object:
+
+.. code-block:: js
+
+ let histogram = Services.telemetry.getHistogramById("PLACES_AUTOCOMPLETE_1ST_RESULT_TIME_MS");
+ histogram.add(measuredDuration);
+
+ let keyed = Services.telemetry.getKeyedHistogramById("TAG_SEEN_COUNTS");
+ keyed.add("blink");
+
+Note that ``nsITelemetry.getHistogramById()`` will throw an ``NS_ERROR_FAILURE`` JavaScript exception if it is called with an invalid histogram ID. The ``add()`` function will not throw if it fails, instead it prints an error in the browser console.
+
+.. warning::
+
+ Adding a new Telemetry probe is not possible with Artifact builds. A full build is needed.
+
+For histograms measuring time, TelemetryStopwatch can be used to avoid working with Dates manually:
+
+.. code-block:: js
+
+ TelemetryStopwatch.start("SEARCH_SERVICE_INIT_MS");
+ TelemetryStopwatch.finish("SEARCH_SERVICE_INIT_MS");
+
+ TelemetryStopwatch.start("FX_TAB_SWITCH_TOTAL_MS");
+ TelemetryStopwatch.cancel("FX_TAB_SWITCH_TOTAL_MS");
+
+Adding a C++ Probe
+==================
+
+Probes in native code can also use the `nsITelemetry <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/nsITelemetry.idl>`_ interface, but the helper functions declared in `Telemetry.h <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/Telemetry.h>`_ are more convenient:
+
+.. code-block:: cpp
+
+ #include "mozilla/Telemetry.h"
+
+ /**
+ * Adds sample to a histogram defined in Histograms.json
+ *
+ * @param id - histogram id
+ * @param sample - value to record.
+ */
+ void Accumulate(HistogramID id, uint32_t sample);
+
+ /**
+ * Adds samples to a histogram defined in Histograms.json
+ *
+ * @param id - histogram id
+ * @param samples - values to record.
+ */
+ void Accumulate(HistogramID id, const nsTArray<uint32_t>& samples);
+
+ /**
+ * Adds sample to a keyed histogram defined in Histograms.h
+ *
+ * @param id - keyed histogram id
+ * @param key - the string key
+ * @param sample - (optional) value to record, defaults to 1.
+ */
+ void Accumulate(HistogramID id, const nsCString& key, uint32_t sample = 1);
+
+ /**
+ * Adds time delta in milliseconds to a histogram defined in Histograms.json
+ *
+ * @param id - histogram id
+ * @param start - start time
+ * @param end - (optional) end time, defaults to TimeStamp::Now().
+ */
+ void AccumulateTimeDelta(HistogramID id, TimeStamp start, TimeStamp end = TimeStamp::Now());
+
+ /**
+ * Adds time delta in milliseconds to a keyed histogram defined in Histograms.json
+ *
+ * @param id - histogram id
+ * @param key - the string key
+ * @param start - start time
+ * @param end - (optional) end time, defaults to TimeStamp::Now().
+ */
+ void AccumulateTimeDelta(HistogramID id, const cs TimeStamp start, TimeStamp end = TimeStamp::Now());
+
+ /** Adds time delta in milliseconds to a histogram defined in TelemetryHistogramEnums.h
+ *
+ * @param id - histogram id
+ * @param key - the string key
+ * @param start - start time
+ * @param end - (optional) end time, defaults to TimeStamp::Now().
+ */
+ void AccumulateTimeDelta(HistogramID id, const nsCString& key, TimeStamp start, TimeStamp end = TimeStamp::Now());
+
+The histogram names declared in ``Histograms.json`` are translated into constants in the ``mozilla::Telemetry`` namespace:
+
+.. code-block:: cpp
+
+ mozilla::Telemetry::Accumulate(mozilla::Telemetry::STARTUP_CRASH_DETECTED, true);
+
+.. warning::
+
+ Telemetry accumulations are designed to be cheap, not free. If you wish to accumulate values in a performance-sensitive piece of code, store the accumualtions locally and accumulate after the performance-sensitive piece ("hot path") has completed.
+
+The ``Telemetry.h`` header also declares the helper classes ``AutoTimer`` and ``AutoCounter``. Objects of these types automatically record a histogram value when they go out of scope:
+
+.. code-block:: cpp
+
+ nsresult
+ nsPluginHost::StopPluginInstance(nsNPAPIPluginInstance* aInstance)
+ {
+ Telemetry::AutoTimer<Telemetry::PLUGIN_SHUTDOWN_MS> timer;
+ ...
+ return NS_OK;
+ }
+
+If the HistogramID is not known at compile time, one can use the ``RuntimeAutoTimer`` and ``RuntimeAutoCounter`` classes, which behave like the template parameterized ``AutoTimer`` and ``AutoCounter`` ones.
+
+.. code-block:: cpp
+
+ void
+ FunctionWithTiming(Telemetry::HistogramID aTelemetryID)
+ {
+ ...
+ Telemetry::RuntimeAutoTimer timer(aTelemetryID);
+ ...
+ }
+
+ int32_t
+ FunctionWithCounter(Telemetry::HistogramID aTelemetryID)
+ {
+ ...
+ Telemetry::RuntimeAutoCounter myCounter(aTelemetryID);
+ ++myCounter;
+ myCounter += 42;
+ ...
+ }
+
+Prefer using the template parameterized ``AutoTimer`` and ``AutoCounter`` on hot paths, if possible.
diff --git a/toolkit/components/telemetry/docs/collection/index.rst b/toolkit/components/telemetry/docs/collection/index.rst
new file mode 100644
index 0000000000..54cd824920
--- /dev/null
+++ b/toolkit/components/telemetry/docs/collection/index.rst
@@ -0,0 +1,49 @@
+===============
+Data collection
+===============
+
+There are different APIs and formats to collect data in Firefox, all suiting different use cases.
+
+In general, we aim to submit data in a common format where possible. This has several advantages; from common code and tooling to sharing analysis know-how.
+
+In cases where this isn't possible and more flexibility is needed, we can submit custom pings or consider adding different data formats to existing pings.
+
+*Note:* Every new data collection must go through a `data collection review <https://wiki.mozilla.org/Firefox/Data_Collection>`_.
+
+The current data collection possibilities include:
+
+* :doc:`scalars` allow recording of a single value (string, boolean, a number)
+* :doc:`histograms` can efficiently record multiple data points
+* ``environment`` data records information about the system and settings a session occurs in
+* :doc:`events` can record richer data on individual occurrences of specific actions
+* :doc:`Measuring elapsed time <measuring-time>`
+* :doc:`Custom pings <custom-pings>`
+* :doc:`Use counters <use-counters>` measure the usage of web platform features
+* :doc:`Experiment annotations <experiments>`
+* :doc:`Remote content uptake <uptake>`
+* :doc:`WebExtension API <webextension-api>` can be used in privileged webextensions
+* :doc:`User Interactions <user-interactions>` allow annotating hang report pings with information on what the user was interacting with at the time
+
+.. toctree::
+ :maxdepth: 2
+ :titlesonly:
+ :hidden:
+ :glob:
+
+ scalars
+ histograms
+ events
+ measuring-time
+ custom-pings
+ experiments
+ uptake
+ *
+
+Browser Usage Telemetry
+~~~~~~~~~~~~~~~~~~~~~~~
+For more information, see :ref:`browserusagetelemetry`.
+
+Version History
+~~~~~~~~~~~~~~~
+
+- Firefox 61: Stopped reporting Telemetry Log items (`bug 1443614 <https://bugzilla.mozilla.org/show_bug.cgi?id=1443614>`_).
diff --git a/toolkit/components/telemetry/docs/collection/measuring-time.rst b/toolkit/components/telemetry/docs/collection/measuring-time.rst
new file mode 100644
index 0000000000..c2d972b378
--- /dev/null
+++ b/toolkit/components/telemetry/docs/collection/measuring-time.rst
@@ -0,0 +1,116 @@
+======================
+Measuring elapsed time
+======================
+
+To make it easier to measure how long operations take, we have helpers for both JavaScript and C++.
+These helpers record the elapsed time into histograms, so you have to create suitable :doc:`histograms` for them first.
+
+From JavaScript
+===============
+JavaScript can measure elapsed time using TelemetryStopwatch.
+
+``TelemetryStopwatch`` is a helper that simplifies recording elapsed time (in milliseconds) into histograms (plain or keyed).
+
+API:
+
+.. code-block:: js
+
+ TelemetryStopwatch = {
+ // Start, check if running, cancel & finish recording elapsed time into a
+ // histogram.
+ // |aObject| is optional. If specified, the timer is associated with this
+ // object, so multiple time measurements can be done concurrently.
+ start(histogramId, aObject);
+ running(histogramId, aObject);
+ cancel(histogramId, aObject);
+ finish(histogramId, aObject);
+ // Start, check if running, cancel & finish recording elapsed time into a
+ // keyed histogram.
+ // |key| specifies the key to record into.
+ // |aObject| is optional and used as above.
+ startKeyed(histogramId, key, aObject);
+ runningKeyed(histogramId, key, aObject);
+ cancelKeyed(histogramId, key, aObject);
+ finishKeyed(histogramId, key, aObject);
+ };
+
+Example:
+
+.. code-block:: js
+
+ TelemetryStopwatch.start("SAMPLE_FILE_LOAD_TIME_MS");
+ // ... start loading file.
+ if (failedToOpenFile) {
+ // Cancel this if the operation failed early etc.
+ TelemetryStopwatch.cancel("SAMPLE_FILE_LOAD_TIME_MS");
+ return;
+ }
+ // ... do more work.
+ TelemetryStopwatch.finish("SAMPLE_FILE_LOAD_TIME_MS");
+
+ // Another loading attempt? Start stopwatch again if
+ // not already running.
+ if (!TelemetryStopwatch.running("SAMPLE_FILE_LOAD_TIME_MS")) {
+ TelemetryStopwatch.start("SAMPLE_FILE_LOAD_TIME_MS");
+ }
+
+ // Periodically, it's necessary to attempt to finish a
+ // TelemetryStopwatch that's already been canceled or
+ // finished. Normally, that throws a warning to the
+ // console. If the TelemetryStopwatch being possibly
+ // canceled or finished is expected behaviour, the
+ // warning can be suppressed by passing the optional
+ // aCanceledOkay argument.
+
+ // ... suppress warning on a previously finished
+ // TelemetryStopwatch
+ TelemetryStopwatch.finish("SAMPLE_FILE_LOAD_TIME_MS", null,
+ true /* aCanceledOkay */);
+
+From C++
+========
+
+API:
+
+.. code-block:: cpp
+
+ // This helper class is the preferred way to record elapsed time.
+ template<HistogramID id>
+ class AutoTimer {
+ // Record into a plain histogram.
+ explicit AutoTimer(TimeStamp aStart = TimeStamp::Now());
+ // Record into a keyed histogram, with key |aKey|.
+ explicit AutoTimer(const nsCString& aKey,
+ TimeStamp aStart = TimeStamp::Now());
+ };
+
+ // If the Histogram id is not known at compile time:
+ class RuntimeAutoTimer {
+ // Record into a plain histogram.
+ explicit RuntimeAutoTimer(Telemetry::HistogramID aId,
+ TimeStamp aStart = TimeStamp::Now());
+ // Record into a keyed histogram, with key |aKey|.
+ explicit RuntimeAutoTimer(Telemetry::HistogramID aId,
+ const nsCString& aKey,
+ TimeStamp aStart = TimeStamp::Now());
+ };
+
+ void AccumulateTimeDelta(HistogramID id, TimeStamp start, TimeStamp end = TimeStamp::Now());
+ void AccumulateTimeDelta(HistogramID id, const nsCString& key, TimeStamp start, TimeStamp end = TimeStamp::Now());
+
+Example:
+
+.. code-block:: cpp
+
+ {
+ Telemetry::AutoTimer<Telemetry::FIND_PLUGINS> telemetry;
+ // ... scan disk for plugins.
+ }
+ // When leaving the scope, AutoTimers destructor will record the time that passed.
+
+ // If the histogram id is not known at compile time.
+ {
+ Telemetry::RuntimeAutoTimer telemetry(Telemetry::FIND_PLUGINS);
+ // ... scan disk for plugins.
+ }
+ // When leaving the scope, AutoTimers destructor will record the time that passed.
diff --git a/toolkit/components/telemetry/docs/collection/sampleHistogram.png b/toolkit/components/telemetry/docs/collection/sampleHistogram.png
new file mode 100644
index 0000000000..8bb185930a
--- /dev/null
+++ b/toolkit/components/telemetry/docs/collection/sampleHistogram.png
Binary files differ
diff --git a/toolkit/components/telemetry/docs/collection/scalars.rst b/toolkit/components/telemetry/docs/collection/scalars.rst
new file mode 100644
index 0000000000..e1efd734c6
--- /dev/null
+++ b/toolkit/components/telemetry/docs/collection/scalars.rst
@@ -0,0 +1,327 @@
+=======
+Scalars
+=======
+
+A *scalar* metric can be used to track a single value. Unlike
+histograms, which collect every measurement taken, a scalar only
+tracks a single value, with later values completely replacing earlier
+ones.
+
+Historically we started to overload our histogram mechanism to also collect scalar data,
+such as flag values, counts, labels and others.
+The scalar measurement types are the suggested way to collect that kind of scalar data.
+The serialized scalar data is submitted with the :doc:`main pings <../data/main-ping>`. Adding scalars is supported in artifact builds and build faster workflows.
+
+.. important::
+
+ Every new or changed data collection in Firefox needs a `data collection review <https://wiki.mozilla.org/Firefox/Data_Collection>`__ from a Data Steward.
+
+The API
+=======
+Scalar probes can be managed either through the `nsITelemetry interface <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/core/nsITelemetry.idl>`_
+or the `C++ API <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/core/Telemetry.h>`_.
+
+JS API
+------
+Probes in privileged JavaScript code can use the following functions to manipulate scalars:
+
+.. code-block:: js
+
+ Services.telemetry.scalarAdd(aName, aValue);
+ Services.telemetry.scalarSet(aName, aValue);
+ Services.telemetry.scalarSetMaximum(aName, aValue);
+
+ Services.telemetry.keyedScalarAdd(aName, aKey, aValue);
+ Services.telemetry.keyedScalarSet(aName, aKey, aValue);
+ Services.telemetry.keyedScalarSetMaximum(aName, aKey, aValue);
+
+These functions can throw if, for example, an operation is performed on a scalar type that doesn't support it
+(e.g. calling scalarSetMaximum on a scalar of the string kind). Please look at the `code documentation <https://searchfox.org/mozilla-central/search?q=TelemetryScalar%3A%3A%28Set%7CAdd%29&path=TelemetryScalar.cpp&case=false&regexp=true>`_ for
+additional information.
+
+.. _registerscalars:
+
+``registerScalars()``
+~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ Services.telemetry.registerScalars(category, scalarData);
+
+Register new scalars from add-ons.
+
+* ``category`` - *(required, string)* The unique category the scalars are registered in (see :ref:`limitations <scalar-limitations>`).
+* ``scalarData`` - *(required, object)* An object of the form ``{scalarName1: scalar1Data, ...}`` that contains registration data for multiple scalars; ``scalarName1`` is subject to :ref:`limitations <scalar-limitations>`; each scalar is an object with the following properties:
+
+ * ``kind`` - *(required, uint)* One of the scalar types (nsITelemetry::SCALAR_TYPE_*).
+ * ``keyed`` - *(optional, bool)* Whether this is a keyed scalar or not. Defaults to false.
+ * ``record_on_release`` - *(optional, bool)* Whether to record this data on release. Defaults to false.
+ * ``expired`` - *(optional, bool)* Whether this scalar entry is expired. This allows recording it without error, but it will be discarded. Defaults to false.
+
+For scalars recorded from add-ons, registration happens at runtime. Any new scalar must first be registered through this function before they can be recorded.
+
+After registration, the scalars can be recorded through the usual scalar JS API. If the accumulation happens in a content process right after the registration and the definition still has to reach this process, it will be discarded: one way to work around the problem is to send an IPC message to the content process and start accumulating data once this message has been received. The accumulated data will be submitted in the main pings payload under ``processes.dynamic.scalars``.
+
+.. note::
+
+ Accumulating in dynamic scalars only works in content child processes and in the parent process. All the accumulations (parent and content children) are aggregated together .
+
+New scalars registered here are subject to the same :ref:`limitations <scalar-limitations>` as the ones registered through ``Scalars.yaml``, e.g. the length of the category name or the allowed characters.
+
+When add-ons are updated, they may re-register all of their scalars. In that case, any changes to scalars that are already registered are ignored. The only exception is expiry; a scalar that is re-registered with ``expired: true`` will not be recorded anymore.
+
+Example:
+
+.. code-block:: js
+
+ Services.telemetry.registerScalars("myAddon.category", {
+ "counter_scalar": {
+ kind: Ci.nsITelemetry.SCALAR_TYPE_COUNT,
+ keyed: false,
+ record_on_release: false
+ },
+ });
+ // Now scalars can be recorded.
+ Services.telemetry.scalarSet("myAddon.category.counter_scalar", 37);
+
+
+.. _scalars-c++-API:
+
+C++ API
+-------
+Probes in native code can use the more convenient helper functions declared in `Telemetry.h <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/core/Telemetry.h>`_:
+
+.. code-block:: cpp
+
+ void ScalarAdd(mozilla::Telemetry::ScalarID aId, uint32_t aValue);
+ void ScalarSet(mozilla::Telemetry::ScalarID aId, uint32_t aValue);
+ void ScalarSet(mozilla::Telemetry::ScalarID aId, const nsAString& aValue);
+ void ScalarSet(mozilla::Telemetry::ScalarID aId, bool aValue);
+ void ScalarSetMaximum(mozilla::Telemetry::ScalarID aId, uint32_t aValue);
+
+ void ScalarAdd(mozilla::Telemetry::ScalarID aId, const nsAString& aKey, uint32_t aValue);
+ void ScalarSet(mozilla::Telemetry::ScalarID aId, const nsAString& aKey, uint32_t aValue);
+ void ScalarSet(mozilla::Telemetry::ScalarID aId, const nsAString& aKey, bool aValue);
+ void ScalarSetMaximum(mozilla::Telemetry::ScalarID aId, const nsAString& aKey, uint32_t aValue);
+
+.. warning::
+
+ Scalar operations are designed to be cheap, not free. If you wish to manipulate Scalars in a performance-sensitive piece of code, store the operations locally and change the Scalar only after the performance-sensitive piece ("hot path") has completed.
+
+The YAML definition file
+========================
+Scalar probes are required to be registered, both for validation and transparency reasons,
+in the `Scalars.yaml <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/Scalars.yaml>`_
+definition file.
+
+The probes in the definition file are represented in a fixed-depth, two-level structure:
+
+.. code-block:: yaml
+
+ # The following is a category.
+ a.category.hierarchy:
+ a_probe_name:
+ kind: uint
+ ...
+ another_probe:
+ kind: string
+ ...
+ ...
+ category2:
+ probe:
+ kind: int
+ ...
+
+.. _scalar-limitations:
+
+Category and probe names need to follow a few rules:
+
+- they cannot exceed 40 characters each;
+- category names must be alphanumeric + ``.``, with no leading/trailing digit or ``.``;
+- probe names must be alphanumeric + ``_``, with no leading/trailing digit or ``_``.
+
+A probe can be defined as follows:
+
+.. code-block:: yaml
+
+ a.category.hierarchy:
+ a_scalar:
+ bug_numbers:
+ - 1276190
+ description: A nice one-line description.
+ expires: never
+ kind: uint
+ notification_emails:
+ - telemetry-client-dev@mozilla.com
+
+.. _scalars-required-fields:
+
+Required Fields
+---------------
+
+- ``bug_numbers``: A list of unsigned integers representing the number of the bugs the probe was introduced in.
+- ``description``: A single or multi-line string describing what data the probe collects and when it gets collected.
+- ``expires``: The version number in which the scalar expires, e.g. "30"; a version number of type "N" is automatically converted to "N.0a1" in order to expire the scalar also in the development channels. A telemetry probe acting on an expired scalar will print a warning into the browser console. For scalars that never expire the value ``never`` can be used.
+- ``kind``: A string representing the scalar type. Allowed values are ``uint``, ``string`` and ``boolean``.
+- ``notification_emails``: A list of email addresses to notify with alerts of expiring probes. More importantly, these are used by the data steward to verify that the probe is still useful.
+- ``products``: A list of products the scalar can be recorded on. Currently supported values are:
+
+ - ``firefox`` - Collected in Firefox Desktop for submission via Firefox Telemetry.
+ - ``geckoview_streaming`` - See :doc:`this guide <../start/report-gecko-telemetry-in-glean>` for how to stream data through geckoview to the Glean SDK.
+ - ``thunderbird`` - Collected in Thunderbird for submission via Thunderbird Telemetry.
+
+- ``record_in_processes``: A list of processes the scalar is allowed to record in. Currently supported values are:
+
+ - ``main``;
+ - ``content``;
+ - ``gpu``;
+ - ``all_children`` (record in all the child processes);
+ - ``all`` (record in all the processes).
+
+Optional Fields
+---------------
+
+- ``release_channel_collection``: This can be either ``opt-in`` (default) or ``opt-out``. With the former the scalar is submitted by default on pre-release channels, unless the user has opted out. With the latter the scalar is submitted by default on release and pre-release channels, unless the user has opted out.
+- ``keyed``: A boolean that determines whether this is a keyed scalar. It defaults to ``false``.
+- ``keys``: A string list. Only valid for *keyed scalars*. Defines a case insensitive list of allowed keys that can be used for this scalar. The list is limited to 100 keys with a maximum length of 72 characters each. When using a key that is not in the list, an error is returned.
+- ``record_into_store``: A list of stores this scalar should be recorded into. It defaults to ``[main]``.
+- ``operating_systems``: This field restricts recording to certain operating systems only. Use that in-place of previous ``cpp_guards`` to avoid inclusion on not-specified operating systems. It defaults to ``all``. Currently supported values are:
+
+ - ``mac``
+ - ``linux``
+ - ``windows``
+ - ``android``
+ - ``unix``
+ - ``all`` (record on all operating systems)
+
+String type restrictions
+------------------------
+To prevent abuses, the content of a string scalar is limited to 50 characters in length. Trying
+to set a longer string will result in an error and no string being set.
+
+.. _scalars-keyed-scalars:
+
+Keyed Scalars
+-------------
+Keyed scalars are collections of ``uint`` or ``boolean`` scalar types, indexed by a string key that can contain UTF8 characters and cannot be longer than 72 characters. Keyed scalars can contain up to 100 keys. This scalar type is for example useful when you want to break down certain counts by a name, like how often searches happen with which search engine.
+
+Keyed ``string`` scalars are not supported.
+
+Keyed scalars should only be used if the set of keys are not known beforehand. If the keys are from a known set of strings, other options are preferred if suitable, like categorical histograms or splitting measurements up into separate scalars.
+
+Multiple processes caveats
+--------------------------
+When recording data in different processes of the same type (e.g. multiple content processes), the user is responsible for preventing races between the operations on the scalars.
+Races can happen because scalar changes are sent from each child process to the parent process, and then merged into the final storage location. Since there's no synchronization between the processes, operations like ``setMaximum`` can potentially produce different results if sent from more than one child process.
+
+The processor scripts
+=====================
+The scalar definition file is processed and checked for correctness at compile time. If it
+conforms to the specification, the processor scripts generate two C++ headers files, included
+by the Telemetry C++ core.
+
+gen_scalar_data.py
+------------------
+This script is called by the build system to generate the ``TelemetryScalarData.h`` C++ header
+file out of the scalar definitions.
+This header file contains an array holding the scalar names and version strings, in addition
+to an array of ``ScalarInfo`` structures representing all the scalars.
+
+gen_scalar_enum.py
+------------------
+This script is called by the build system to generate the ``TelemetryScalarEnums.h`` C++ header
+file out of the scalar definitions.
+This header file contains an enum class with all the scalar identifiers used to access them
+from code through the C++ API.
+
+Adding a new probe
+==================
+Making a scalar measurement is a two step process:
+
+1. add the probe definition to the scalar registry;
+2. record into the scalar using the API.
+
+Registering the scalar
+----------------------
+Let's start by registering two probes in the `Scalars.yaml <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/Scalars.yaml>`_ definition file: a simple boolean scalar and a keyed unsigned scalar.
+
+.. code-block:: yaml
+
+ # The following section contains the demo scalars.
+ profile:
+ was_reset:
+ bug_numbers:
+ - 1301364
+ description: True if the profile was reset.
+ expires: "60"
+ kind: boolean
+ notification_emails:
+ - change-me@allizom.com
+ release_channel_collection: opt-out
+ record_in_processes:
+ - 'main'
+
+ ui:
+ download_button_activated:
+ bug_numbers:
+ - 1301364
+ description: >
+ The number of times the download button was activated, per
+ input type (e.g. 'mouse_click', 'touchscreen', ...).
+ expires: "60"
+ kind: uint
+ keyed: true
+ notification_emails:
+ - change-me@allizom.com
+ release_channel_collection: opt-in
+ record_in_processes:
+ - 'main'
+
+These two scalars have different collection policies and are both constrained to recording only in the main process.
+For example, the ``ui.download_button_activated`` can be recorded only by users on running pre-release builds of Firefox.
+
+Using the JS API
+----------------
+Changing the demo scalars from privileged JavaScript code is straightforward:
+
+.. code-block:: js
+
+ // Set the scalar value: trying to use a non-boolean value doesn't throw
+ // but rather prints a warning to the browser console
+ Services.telemetry.scalarSet("profile.was_reset", true);
+
+ // This call increments the value stored in "mouse_click" within the
+ // "ui.download_button_activated" scalar, by 1.
+ Services.telemetry.keyedScalarAdd("ui.download_button_activated", "mouse_click", 1);
+
+More usage examples can be found in the tests covering the `JS Scalars API <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/tests/unit/test_TelemetryScalars.js>`_ and `child processes scalars <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/tests/unit/test_ChildScalars.js>`_.
+
+Using the C++ API
+-----------------
+Native code can take advantage of Scalars as well, by including the ``Telemetry.h`` header file.
+
+.. code-block:: cpp
+
+ Telemetry::ScalarSet(Telemetry::ScalarID::PROFILE_WAS_RESET, false);
+
+ Telemetry::ScalarAdd(Telemetry::ScalarID::UI_DOWNLOAD_BUTTON_ACTIVATED,
+ u"touchscreen"_ns, 1);
+
+The ``ScalarID`` enum is automatically generated by the build process, with an example being available `here <https://searchfox.org/mozilla-central/search?q=path%3ATelemetryScalarEnums.h&redirect=false>`_ .
+
+Other examples can be found in the `test coverage <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/tests/gtest/TestScalars.cpp>`_ for the scalars C++ API.
+
+Version History
+===============
+
+- Firefox 79: ``geckoview`` support removed (see `bug 1620395 <https://bugzilla.mozilla.org/show_bug.cgi?id=1620395>`__).
+- Firefox 50: Initial scalar support (`bug 1276195 <https://bugzilla.mozilla.org/show_bug.cgi?id=1276195>`_).
+- Firefox 51: Added keyed scalars (`bug 1277806 <https://bugzilla.mozilla.org/show_bug.cgi?id=1277806>`_).
+- Firefox 53: Added child process scalars (`bug 1278556 <https://bugzilla.mozilla.org/show_bug.cgi?id=1278556>`_).
+- Firefox 58
+
+ - Added support for recording new scalars from add-ons (`bug 1393801 <bug https://bugzilla.mozilla.org/show_bug.cgi?id=1393801>`_).
+ - Ignore re-registering existing scalars for a category instead of failing (`bug 1409323 <https://bugzilla.mozilla.org/show_bug.cgi?id=1409323>`_).
+
+- Firefox 60: Enabled support for adding scalars in artifact builds and build-faster workflows (`bug 1425909 <https://bugzilla.mozilla.org/show_bug.cgi?id=1425909>`_).
+- Firefox 66: Replace ``cpp_guard`` with ``operating_systems`` (`bug 1482912 <https://bugzilla.mozilla.org/show_bug.cgi?id=1482912>`_)`
diff --git a/toolkit/components/telemetry/docs/collection/uptake.rst b/toolkit/components/telemetry/docs/collection/uptake.rst
new file mode 100644
index 0000000000..b9ee803c30
--- /dev/null
+++ b/toolkit/components/telemetry/docs/collection/uptake.rst
@@ -0,0 +1,114 @@
+.. _telemetry/collection/uptake:
+
+================
+Uptake Telemetry
+================
+
+Firefox continuously pulls data from different remote sources (eg. settings, system add-ons, …). In order to have consistent insights about the *uptake rate* of these *update sources*, our clients can use a unified Telemetry helper to report their *update status*.
+
+The helper — described below — reports predefined update status, which eventually gives a unified way to obtain:
+
+* the proportion of success among clients;
+* its evolution over time;
+* the distribution of error causes.
+
+.. note::
+
+ Examples of update sources: *remote settings, add-ons update, add-ons, gfx, and plugins blocklists, certificate revocation, certificate pinning, system add-ons delivery…*
+
+ Examples of update status: *up-to-date, success, network error, server error, signature error, server backoff, unknown error…*
+
+Every call to the UptakeTelemetry helper may send a :ref:`Telemetry Event <eventtelemetry>`. Because events are expensive, we take some measures to avoid overwhelming Mozilla systems with the flood of data that this produces. We always send events when not on release channel. On release channel, we only send events from 1% of clients.
+
+Usage
+-----
+
+.. code-block:: js
+
+ const { UptakeTelemetry } = ChromeUtils.import("resource://services-common/uptake-telemetry.js", {});
+
+ UptakeTelemetry.report(component, status, { source });
+
+- ``component``, a ``string`` that identifies the calling component (eg. ``"remotesettings"``, ``"normandy"``). Arbitrary components have to be previously declared in the :ref:`Telemetry Events definition file <eventdefinition>`.
+- ``source``, a ``string`` to distinguish what is being pulled or updated in the component (eg. ``"blocklists/addons"``, ``"recipes/33"``)
+- ``status``, one of the following status constants:
+
+ - ``UptakeTelemetry.STATUS.UP_TO_DATE``: Local content was already up-to-date with remote content.
+ - ``UptakeTelemetry.STATUS.SUCCESS``: Local content was updated successfully.
+ - ``UptakeTelemetry.STATUS.BACKOFF``: Remote server asked clients to backoff.
+ - ``UptakeTelemetry.STATUS.PREF_DISABLED``: Update is disabled in user preferences.
+ - ``UptakeTelemetry.STATUS.PARSE_ERROR``: Parsing server response has failed.
+ - ``UptakeTelemetry.STATUS.CONTENT_ERROR``: Server response has unexpected content.
+ - ``UptakeTelemetry.STATUS.CORRUPTION_ERROR``: Error related to corrupted local data.
+ - ``UptakeTelemetry.STATUS.SIGNATURE_ERROR``: Signature verification after diff-based sync has failed.
+ - ``UptakeTelemetry.STATUS.SIGNATURE_RETRY_ERROR``: Signature verification after full fetch has failed.
+ - ``UptakeTelemetry.STATUS.CONFLICT_ERROR``: Some remote changes are in conflict with local changes.
+ - ``UptakeTelemetry.STATUS.SYNC_ERROR``: Synchronization of remote changes has failed.
+ - ``UptakeTelemetry.STATUS.APPLY_ERROR``: Application of changes locally has failed.
+ - ``UptakeTelemetry.STATUS.SERVER_ERROR``: Server failed to respond.
+ - ``UptakeTelemetry.STATUS.CERTIFICATE_ERROR``: Server certificate verification has failed.
+ - ``UptakeTelemetry.STATUS.DOWNLOAD_ERROR``: Data could not be fully retrieved.
+ - ``UptakeTelemetry.STATUS.TIMEOUT_ERROR``: Server response has timed out.
+ - ``UptakeTelemetry.STATUS.NETWORK_ERROR``: Communication with server has failed.
+ - ``UptakeTelemetry.STATUS.NETWORK_OFFLINE_ERROR``: Network not available.
+ - ``UptakeTelemetry.STATUS.CLEANUP_ERROR``: Clean-up of temporary files has failed.
+ - ``UptakeTelemetry.STATUS.SHUTDOWN_ERROR``: Error occurring during shutdown.
+ - ``UptakeTelemetry.STATUS.UNKNOWN_ERROR``: Uncategorized error.
+ - ``UptakeTelemetry.STATUS.CUSTOM_1_ERROR``: Error #1 specific to this update source.
+ - ``UptakeTelemetry.STATUS.CUSTOM_2_ERROR``: Error #2 specific to this update source.
+ - ``UptakeTelemetry.STATUS.CUSTOM_3_ERROR``: Error #3 specific to this update source.
+ - ``UptakeTelemetry.STATUS.CUSTOM_4_ERROR``: Error #4 specific to this update source.
+ - ``UptakeTelemetry.STATUS.CUSTOM_5_ERROR``: Error #5 specific to this update source.
+
+Example:
+
+.. code-block:: js
+
+ const COMPONENT = "normandy";
+ const UPDATE_SOURCE = "update-monitoring";
+
+ let status;
+ try {
+ const data = await fetch(uri);
+ status = UptakeTelemetry.STATUS.SUCCESS;
+ } catch (e) {
+ status = /NetworkError/.test(e) ?
+ UptakeTelemetry.STATUS.NETWORK_ERROR :
+ UptakeTelemetry.STATUS.SERVER_ERROR ;
+ }
+ UptakeTelemetry.report(COMPONENT, status, { source: UPDATE_SOURCE });
+
+
+Additional Event Info
+'''''''''''''''''''''
+
+Events sent using the telemetry events API can contain additional information. Uptake Telemetry allows you to add the following extra fields to events by adding them to the ``options`` argument:
+
+- ``trigger``: A label to distinguish what triggered the polling/fetching of remote content (eg. ``"broadcast"``, ``"timer"``, ``"forced"``, ``"manual"``)
+- ``age``: The age of pulled data in seconds (ie. difference between publication time and fetch time).
+- ``duration``: The duration of the synchronization process in milliseconds.
+
+.. code-block:: js
+
+ UptakeTelemetry.report(component, status, { source, trigger: "timer", age: 138 });
+
+Remember that events are sampled on release channel. Those calls to uptake telemetry that do not produce events will ignore these extra fields.
+
+
+Use-cases
+---------
+
+The following remote data sources are already using this unified histogram.
+
+* remote settings changes monitoring
+* add-ons blocklist
+* gfx blocklist
+* plugins blocklist
+* certificate revocation
+* certificate pinning
+* :ref:`Normandy Recipe client <components/normandy>`
+
+Obviously, the goal is to eventually converge and avoid ad-hoc Telemetry probes for measuring uptake of remote content. Some notable potential use-cases are:
+
+* nsUpdateService
+* mozapps extensions update
diff --git a/toolkit/components/telemetry/docs/collection/use-counters.rst b/toolkit/components/telemetry/docs/collection/use-counters.rst
new file mode 100644
index 0000000000..cfa2c749c3
--- /dev/null
+++ b/toolkit/components/telemetry/docs/collection/use-counters.rst
@@ -0,0 +1,105 @@
+============
+Use Counters
+============
+
+Use counters are used to report Telemetry statistics on whether individual documents
+use a given WebIDL method or attribute (getters and setters are reported separately), CSS
+property, or deprecated DOM operation. Custom use counters can also be
+defined to test frequency of things that don't fall into one of those
+categories.
+
+As of Firefox 65 the collection of Use Counters is enabled on all channels.
+
+The API
+=======
+The process to add a new use counter is different depending on the type feature that needs
+to be measured. In general, for each defined use counter, two separate boolean histograms are generated:
+
+- one describes the use of the tracked feature for individual documents and has the ``_DOCUMENT`` suffix;
+- the other describes the use of the same thing for top-level pages (basically what we think of as a *web page*) and has the ``_PAGE`` suffix.
+
+Using two histograms is particularly suited to measure how many sites would be affected by
+removing the tracked feature.
+
+Example scenarios:
+
+- Site *X* triggers use counter *Y*. We report "used" (true) in both the ``_DOCUMENT`` and ``_PAGE`` histograms.
+- Site *X* does not trigger use counter *Y*. We report "unused" (false) in both the ``_DOCUMENT`` and ``_PAGE`` histograms.
+- Site *X* has an iframe for site *W*. Site *W* triggers use counter *Y*, but site *X* does not. We report one "used" and one "unused" in the individual ``_DOCUMENT`` histogram and one "used" in the top-level ``_PAGE`` histogram.
+
+Deprecated DOM operations
+-------------------------
+Use counters for deprecated DOM operations are declared in the `nsDeprecatedOperationList.h <https://searchfox.org/mozilla-central/source/dom/base/nsDeprecatedOperationList.h>`_ file. The counters are
+registered through the ``DEPRECATED_OPERATION(DeprecationReference)`` macro. The provided
+parameter must have the same value of the deprecation note added to the *IDL* file.
+
+See this `changeset <https://hg.mozilla.org/mozilla-central/rev/e30a357b25f1>`_ for a sample
+deprecated operation.
+
+CSS Properties
+~~~~~~~~~~~~~~
+
+Use counters for CSS properties are generated for every property Gecko supports automatically, and are counted via StyleUseCounters (`Rust code <https://searchfox.org/mozilla-central/rev/7ed8e2d3d1d7a1464ba42763a33fd2e60efcaedc/servo/components/style/use_counters/mod.rs>`_, `C++ code <https://searchfox.org/mozilla-central/rev/7ed8e2d3d1d7a1464ba42763a33fd2e60efcaedc/dom/base/Document.h#5077>`_).
+
+The UseCounters registry
+------------------------
+Use counters for WebIDL methods/attributes are registered in the `UseCounters.conf <https://searchfox.org/mozilla-central/source/dom/base/UseCounters.conf>`_ file. The format of this file is very strict. Each line can be:
+
+1. a blank line
+2. a comment, which is a line that begins with ``//``
+3. one of four possible use counter declarations:
+
+ * ``method <IDL interface name>.<IDL operation name>``
+ * ``attribute <IDL interface name>.<IDL attribute name>``
+ * ``custom <any valid identifier> <description>``
+
+Custom use counters
+~~~~~~~~~~~~~~~~~~~
+The <description> for custom counters will be appended to "When a document " or "When a page ", so phrase it appropriately. For instance, "constructs a Foo object" or "calls Document.bar('some value')". It may contain any character (including whitespace). Custom counters are incremented when SetUseCounter(eUseCounter_custom_MyName) is called on a Document object.
+
+WebIDL methods and attributes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Additionally to having a new entry added to the `UseCounters.conf <https://searchfox.org/mozilla-central/source/dom/base/UseCounters.conf>`_ file, WebIDL methods and attributes must have a ``[UseCounter]`` extended attribute in the Web IDL file in order for the counters to be incremented.
+
+Both additions are required because generating things from bindings codegen and ensuring all the dependencies are correct would have been rather difficult.
+
+The processor script
+====================
+The definition files are processed twice:
+
+- once to generate two C++ headers files, included by the web platform components (e.g. DOM) that own the features to be tracked;
+- the other time by the Telemetry component, to generate the histogram definitions that make the collection system work.
+
+.. note::
+
+ The histograms that are generated out of use counters are set to *never* expire and are collected from Firefox release. Note that before Firefox 65 they were only collected on pre-release.
+
+gen-usecounters.py
+------------------
+This script is called by the build system to generate:
+
+- the ``UseCounterList.h`` header for the WebIDL, out of the definition files.
+
+Interpreting the data
+=====================
+The histogram as accumulated on the client only puts values into the 1 bucket, meaning that
+the use counter directly reports if a feature was used but it does not directly report if
+it isn't used.
+The values accumulated within a use counter should be considered proportional to
+``CONTENT_DOCUMENTS_DESTROYED`` and ``TOP_LEVEL_CONTENT_DOCUMENTS_DESTROYED`` (see
+`here <https://searchfox.org/mozilla-central/rev/1a973762afcbc5066f73f1508b0c846872fe3952/dom/base/Document.cpp#15059-15081>`__). The difference between the values of these two histograms
+and the related use counters below tell us how many pages did *not* use the feature in question.
+For instance, if we see that a given session has destroyed 30 content documents, but a
+particular use counter shows only a count of 5, we can infer that the use counter was *not*
+used in 25 of those 30 documents.
+
+Things are done this way, rather than accumulating a boolean flag for each use counter,
+to avoid sending histograms for features that don't get widely used. Doing things in this
+fashion means smaller telemetry payloads and faster processing on the server side.
+
+Version History
+---------------
+
+- Firefox 65:
+
+ - Enable Use Counters on release channel (`bug 1477433 <https://bugzilla.mozilla.org/show_bug.cgi?id=1477433>`_)
diff --git a/toolkit/components/telemetry/docs/collection/user-interactions.rst b/toolkit/components/telemetry/docs/collection/user-interactions.rst
new file mode 100644
index 0000000000..16d1d53977
--- /dev/null
+++ b/toolkit/components/telemetry/docs/collection/user-interactions.rst
@@ -0,0 +1,272 @@
+.. _userinteractionstelemetry:
+
+=================
+User Interactions
+=================
+
+The Background Hang Reporter is a tool that collects stacks during hangs on pre-release channels.
+User Interactions are a way of annotating Background Hang Reports with additional information about what the user was doing when a hang occurs.
+This allows for grouping and prioritization of hangs based on the user interactions that they occur during.
+
+Since the built-in profiler is often the first tool that developers reach for to debug performance issues,
+User Interactions also will add profiler markers for each recording.
+
+.. important::
+
+ Every new or changed data collection in Firefox needs a `data collection review <https://wiki.mozilla.org/Firefox/Data_Collection>`__ from a Data Steward.
+
+.. _userinteractionsserializationformat:
+
+Serialization format
+====================
+
+User Interactions are submitted in a :doc:`../data/backgroundhangmonitor-ping` as a property under the `annotations` for a hang, e.g.:
+
+.. code-block:: js
+
+ ...
+ {
+ "duration": 105.547582,
+ // ...
+ "annotations": [
+ ["UserInteracting", "true"]
+ ["browser.tabs.opening", "animated"]
+ ],
+ "stack": [
+ "XREMain::XRE_main",
+ "-[GeckoNSApplication nextEventMatchingMask:untilDate:inMode:dequeue:]",
+ "nsAppShell::ProcessGeckoEvents",
+ "nsRefreshDriver::Tick",
+ "EventDispatcher::Dispatch",
+ "EventDispatcher::Dispatch",
+ "",
+ "browser/content/tabbrowser-tabs.js:1699",
+ "browser/content/tabbrowser-tabs.js:1725",
+ "browser/content/tabbrowser-tabs.js:142",
+ "browser/content/tabbrowser-tabs.js:153",
+ "(jit frame)",
+ "(unresolved)",
+ [
+ 1,
+ "418de17"
+ ],
+ [
+ 1,
+ "418de91"
+ ],
+ [
+ 1,
+ "4382e56"
+ ],
+ [
+ 8,
+ "108e3"
+ ],
+ [
+ 9,
+ "2624"
+ ],
+ [
+ 9,
+ "129f"
+ ]
+ ]
+ // ...
+ },
+
+Each User Interaction is of the form:
+
+.. code-block:: js
+
+ ["User Interaction ID", "value"]
+
+A `User Interaction ID` is its category concatenated with its name.
+For example, a User Interaction with category `browser.tabs` and name `opening` has an ID of `browser.tabs.opening`.
+
+.. _userinteractionslimits:
+
+Limits
+------
+
+Each ``String`` marked as an identifier (the User Interaction ``name``, ``category``, ``value``) is restricted to be composed of alphanumeric ASCII characters ([a-zA-Z0-9]) plus infix underscores ('_' characters that aren't the first or last).
+``category`` is also permitted infix periods ('.' characters, so long as they aren't the first or last character).
+
+Several fields are subject to length limits:
+
+- ``category``: Max. byte length is ``40``.
+- ``User Interaction`` name: Max. byte length is ``40``.
+- ``value``: A UTF-8 string with max. byte length of ``50``.
+
+Any ``String`` going over its limit will be reported as an error and the operation aborted.
+
+
+.. _userinteractionsdefinition:
+
+The YAML definition file
+========================
+
+Any User Interaction recorded into Firefox Telemetry must be registered before it can be recorded.
+For any code that ships as part of Firefox that happens in `UserInteractions.yaml <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/UserInteractions.yaml>`_.
+
+The User Interactions in the definition file are represented in a fixed-depth, three-level structure.
+The first level contains *category* names (grouping multiple User Interactions together),
+the second level contains User Interaction IDs, under which the User Interaction properties are listed. E.g.:
+
+.. code-block:: yaml
+
+ # The following is a category of User Interactions named "browser.tabs".
+ browser.tabs:
+ opening: # This is the name of the User Interaction. The ID for the
+ # User Interaction is browser.tabs.opening
+ description: >
+ Describes this User Interaction in detail, potentially over
+ multiple lines.
+ # ... and more User Interaction properties.
+ # ... and more User Interactions.
+ # This is the "browser.places" category.
+ browser.places:
+ # And the "history" search User Interaction. Its User Interaction ID is
+ # browser.places.history_async
+ history_async:
+ # ...
+ description: Session History is searched asynchronously.
+ # ... and more User Interaction properties.
+ # ...
+
+Category and User Interaction names are subject to the limits :ref:`specified above <userinteractionslimits>`.
+
+
+Profiler markers
+================
+
+The profiler markers automatically added for each User Interaction will have a starting point and ending point corresponding with the recording of the User Interaction.
+The name of the marker will be the User Interaction category plus the User Interaction ID.
+The value of the marker will be the value passed through the `UserInteraction` API, plus any additional text that is optionally added when the recording is finished.
+
+Further details on what the profiler is and what profiler markers are can be found `here <https://profiler.firefox.com/docs/#/>`_.
+
+
+The API
+=======
+
+Public JS API
+-------------
+
+This API is main-thread only, and all functions will return `false` if accessed off of the main thread.
+
+``start()``
+~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ UserInteraction.start(id, value, object);
+
+Starts recording a User Interaction.
+Any hangs that occur on the main thread while recording this User Interaction result in an annotation being added to the background hang report.
+
+If a pre-existing UserInteraction already exists with the same ``id`` and the same ``object``, that pre-existing UserInteraction will be overwritten.
+The newly created UserInteraction will include a "(clobbered)" suffix on its BHR annotation name.
+
+* ``id``: Required. A string value, limited to 80 characters. This is the category name concatenated with the User Interaction name.
+* ``value``: Required. A string value, limited to 50 characters.
+* ``object``: Optional. If specified, the User Interaction is associated with this object, so multiple recordings can be done concurrently.
+
+Example:
+
+.. code-block:: js
+
+ UserInteraction.start("browser.tabs.opening", "animated", window1);
+ UserInteraction.start("browser.tabs.opening", "animated", window2);
+
+Returns `false` and logs a message to the browser console if the recording does not start for some reason.
+
+Example:
+
+.. code-block:: js
+
+ UserInteraction.start("browser.tabs.opening", "animated", window);
+ UserInteraction.start("browser.places.history_search", "synchronous");
+
+``update()``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ UserInteraction.update(id, value, object);
+
+Updates a User Interaction that's already being recorded with a new value.
+Any hangs that occur on the main thread will be annotated using the new value.
+Updating only works for User Interactions that are already being recorded.
+
+* ``id``: Required. A string value, limited to 80 characters. This is the category name concatenated with the User Interaction name.
+* ``value``: Required. The new string value, limited to 50 characters.
+* ``object``: Optional. If specified, the User Interaction is associated with this object, so multiple recordings can be done concurrently.
+
+Returns `false` and logs a message to the browser console if the update cannot be done for some reason.
+
+
+Example:
+
+.. code-block:: js
+
+ // At this point, we don't know if the tab will open with animation
+ // or not.
+ UserInteraction.start("browser.tabs.opening", "initting", window);
+ // ...
+ if (animating) {
+ UserInteraction.update("browser.tabs.opening", "animating", window);
+ } else {
+ UserInteraction.update("browser.tabs.opening", "not-animating", window);
+ }
+
+``cancel()``
+~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ UserInteraction.cancel(id, object);
+
+Cancels a recording User Interaction.
+No profiler marker will be added in this case, and no further hangs will be annotated.
+Hangs that occurred before the User Interaction was cancelled will not, however, be expunged.
+
+* ``id``: Required. A string value, limited to 80 characters. This is the category name concatenated with the User Interaction name.
+* ``object``: Optional. If specified, the User Interaction is associated with this object, so multiple recordings can be done concurrently.
+
+Returns `false` and logs a message to the browser console if the cancellation cannot be completed for some reason.
+
+``running()``
+~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ UserInteraction.running(id, object);
+
+Checks to see if a UserInteraction is already running.
+
+* ``id``: Required. A string value, limited to 80 characters. This is the category name concatenated with the User Interaction name.
+* ``object``: Optional. If specified, the User Interaction is associated with this object, so multiple recordings can be done concurrently. If you're checking for a running timer that was started with an object, you'll need to pass in that same object here to check its running state.
+
+Returns `true` if a UserInteraction is already running.
+
+``finish()``
+~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ UserInteraction.finish(id, object, additionalText);
+
+Finishes recording the User Interaction.
+Any hangs that occur on the main thread will no longer be annotated with this User Interaction.
+A profiler marker will also be added, starting at the `UserInteraction.start` point and ending at the `UserInteraction.finish` point, along with any additional text that the author wants to include.
+
+* ``id``: Required. A string value, limited to 80 characters. This is the category name concatenated with the User Interaction name.
+* ``object``: Optional. If specified, the User Interaction is associated with this object, so multiple recordings can be done concurrently.
+* ``additionalText``: Optional. If specified, the profile marker will have this text appended to the `value`, separated with a comma.
+
+Returns `false` and logs a message to the browser console if finishing cannot be completed for some reason.
+
+Version History
+===============
+
+- Firefox 84: Initial User Interaction support (see `bug 1661304 <https://bugzilla.mozilla.org/show_bug.cgi?id=1661304>`__).
diff --git a/toolkit/components/telemetry/docs/collection/webextension-api.rst b/toolkit/components/telemetry/docs/collection/webextension-api.rst
new file mode 100644
index 0000000000..a3e73e11fa
--- /dev/null
+++ b/toolkit/components/telemetry/docs/collection/webextension-api.rst
@@ -0,0 +1,158 @@
+.. _webextension-telemetry:
+
+==============================
+WebExtension API for Telemetry
+==============================
+
+Use the ``browser.telemetry`` API to send telemetry data to the Mozilla Telemetry service. Restricted to Mozilla privileged webextensions.
+
+Types
+-----
+
+``ScalarType``
+~~~~~~~~~~~~~~
+
+Type of scalar: 'count' for numeric values, 'string' for string values, 'boolean' for boolean values. Maps to ``nsITelemetry.SCALAR_TYPE_*``.
+
+``ScalarData``
+~~~~~~~~~~~~~~
+
+Represents registration data for a Telemetry scalar.
+
+Properties:
+
+* ``kind`` - See ScalarType_.
+* ``keyed`` - *(optional, boolean)* True if this is a keyed scalar. Defaults to ``false``.
+* ``record_on_release`` - *(optional, boolean)* True if this data should be recorded on release. Defaults to ``false``.
+* ``expired`` - *(optional, boolean)* True if this scalar entry is expired. Operations on an expired scalar don't error (operations on an undefined scalar do), but the operations are no-ops. No data will be recorded. Defaults to ``false``.
+
+``EventData``
+~~~~~~~~~~~~~
+
+Represents registration data for a Telemetry event.
+
+Properties:
+
+* ``methods`` - *(array)* List of methods for this event entry.
+* ``objects`` - *(array)* List of objects for this event entry.
+* ``extra_keys`` - *(array)* List of allowed extra keys for this event entry.
+* ``record_on_release`` - *(optional, boolean)* True if this data should be recorded on release. Defaults to ``false``.
+* ``expired`` - *(optional, boolean)* True if this event entry is expired. Recording an expired event doesn't error (operations on undefined events do). No data will be recorded. Defaults to ``false``.
+
+Functions
+---------
+
+``submitPing``
+~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ browser.telemetry.submitPing(type, message, options);
+
+Submits a custom ping to the Telemetry backend. See :ref:`submitting-customping`.
+
+* ``type`` - *(string)* The type of the ping.
+* ``message`` - *(object)* The data payload for the ping.
+* ``options`` - *(optional, object)* Options object.
+
+ * ``addClientId`` - *(optional, boolean)* True if the ping should contain the client id. Defaults to ``false``.
+ * ``addEnvironment`` - *(optional, boolean)* True if the ping should contain the environment data. Defaults to ``false``.
+ * ``overrideEnvironment`` - *(optional, object)* Set to override the environment data. Default: not set.
+ * ``usePingSender`` - *(optional, boolean)* If true, send the ping using the PingSender. Defaults to ``false``.
+
+
+``canUpload``
+~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ browser.telemetry.canUpload();
+
+Checks if Telemetry upload is enabled.
+
+``scalarAdd``
+~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ browser.telemetry.scalarAdd(name, value);
+
+Adds the value to the given scalar.
+
+* ``name`` - *(string)* The scalar name.
+* ``value`` - *(integer)* The numeric value to add to the scalar. Only unsigned integers supported.
+
+``scalarSet``
+~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ browser.telemetry.scalarSet(name, value);
+
+Sets the named scalar to the given value. Throws if the value type doesn't match the scalar type.
+
+* ``name`` - *(string)* The scalar name.
+* ``value`` - *(string|boolean|integer|object)* The value to set the scalar to.
+
+``scalarSetMaximum``
+~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ browser.telemetry.scalarSetMaximum(name, value);
+
+Sets the scalar to the maximum of the current and the passed value
+
+* ``name`` - *(string)* The scalar name.
+* ``value`` - *(integer)* The numeric value to set the scalar to. Only unsigned integers supported.
+
+``recordEvent``
+~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ browser.telemetry.recordEvent(category, method, object, value, extra);
+
+Record an event in Telemetry. Throws when trying to record an unknown event.
+
+* ``category`` - *(string)* The category name.
+* ``method`` - *(string)* The method name.
+* ``object`` - *(string)* The object name.
+* ``value`` - *(optional, string)* An optional string value to record.
+* ``extra`` - *(optional, object)* An optional object of the form (string -> string). It should only contain registered extra keys.
+
+``registerScalars``
+~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ browser.telemetry.registerScalars(category, data);
+
+Register new scalars to record them from addons. See :ref:`registerscalars` for more details.
+
+* ``category`` - *(string)* The unique category the scalars are registered in.
+* ``data`` - *(object)* An object that contains registration data for multiple scalars. Each property name is the scalar name, and the corresponding property value is an object of ScalarData_ type.
+
+``registerEvents``
+~~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ browser.telemetry.registerEvents(category, data);
+
+Register new events to record them from addons. See :ref:`registerevents` for more details.
+
+* ``category`` - *(string)* The unique category the events are registered in.
+* ``data`` - *(object)* An object that contains registration data for 1+ events. Each property name is the category name, and the corresponding property value is an object of EventData_ type.
+
+``setEventRecordingEnabled``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ browser.telemetry.setEventRecordingEnabled(category, enabled);
+
+Enable recording of events in a category. Events default to recording disabled. This allows to toggle recording for all events in the specified category.
+
+* ``category`` - *(string)* The category name.
+* ``enabled`` - *(boolean)* Whether recording is enabled for events in that category.
diff --git a/toolkit/components/telemetry/docs/concepts/archiving.rst b/toolkit/components/telemetry/docs/concepts/archiving.rst
new file mode 100644
index 0000000000..0466f13769
--- /dev/null
+++ b/toolkit/components/telemetry/docs/concepts/archiving.rst
@@ -0,0 +1,23 @@
+=========
+Archiving
+=========
+
+When archiving is enabled through the relevant pref (``toolkit.telemetry.archive.enabled``), pings submitted to ``TelemetryController`` are also stored locally in the user profile directory, in ``<profile-dir>/datareporting/archived``.
+
+To allow for cheaper lookup of archived pings, storage follows a specific naming scheme for both the directory and the ping file name: `<YYYY-MM>/<timestamp>.<UUID>.<type>.jsonlz4`.
+
+* ``<YYYY-MM>`` - The subdirectory name, generated from the ping creation date.
+* ``<timestamp>`` - Timestamp of the ping creation date.
+* ``<UUID>`` - The ping identifier.
+* ``<type>`` - The ping type.
+
+Archived data can be viewed on ``about:telemetry``.
+
+Cleanup
+-------
+
+Archived pings are not kept around forever.
+After startup of Firefox and initialization of Telemetry, the archive is cleaned up if necessary.
+
+* Old ping data is removed by month if it is older than 60 days.
+* If the total size of the archive exceeds the quota of 120 MB, pings are removed to reduce the size of the archive again.
diff --git a/toolkit/components/telemetry/docs/concepts/crashes.rst b/toolkit/components/telemetry/docs/concepts/crashes.rst
new file mode 100644
index 0000000000..4ea40f89c4
--- /dev/null
+++ b/toolkit/components/telemetry/docs/concepts/crashes.rst
@@ -0,0 +1,25 @@
+=======
+Crashes
+=======
+
+There are many different kinds of crashes for Firefox, there is not a single system used to record all of them.
+
+Main process crashes
+====================
+
+If the Firefox main process dies, that should be recorded as an aborted session. We would submit a :doc:`main ping <../data/main-ping>` with the reason ``aborted-session``.
+If we have a crash dump for that crash, we should also submit a :doc:`crash ping <../data/crash-ping>`.
+
+The ``aborted-session`` information is first written to disk 60 seconds after startup, any earlier crashes will not trigger an ``aborted-session`` ping.
+Also, the ``aborted-session`` is updated at least every 5 minutes, so it may lag behind the last session state.
+
+Crashes during startup should be recorded in the next sessions main ping in the ``STARTUP_CRASH_DETECTED`` histogram.
+
+Child process crashes
+=====================
+
+If a Firefox plugin, content, gmplugin, or any other type of child process dies unexpectedly, this is recorded in the main ping's ``SUBPROCESS_ABNORMAL_ABORT`` keyed histogram.
+
+If we catch a crash report for this, then additionally the ``SUBPROCESS_CRASHES_WITH_DUMP`` keyed histogram is incremented.
+
+Some processes also generate :doc:`crash pings <../data/crash-ping>` when they crash and generate a crash dump. See `bug 1352496 <https://bugzilla.mozilla.org/show_bug.cgi?id=1352496>`_ for an example of how to allow crash pings for new process types.
diff --git a/toolkit/components/telemetry/docs/concepts/index.rst b/toolkit/components/telemetry/docs/concepts/index.rst
new file mode 100644
index 0000000000..a49466f8d0
--- /dev/null
+++ b/toolkit/components/telemetry/docs/concepts/index.rst
@@ -0,0 +1,23 @@
+========
+Concepts
+========
+
+There are common concepts used throughout Telemetry:
+
+* :doc:`pings <pings>` - the packets we use to submit data
+* :doc:`sessions & subsessions <sessions>` - how we slice a users' time in the browser
+* *measurements* - how we :doc:`collect data <../collection/index>`
+* *opt-in* & *opt-out* - the different sets of data we collect
+* :doc:`submission <submission>` - how we send data to the servers
+* :doc:`archiving <archiving>` - retaining ping data locally
+* :doc:`crashes <crashes>` - the different data crashes generate
+
+.. toctree::
+ :maxdepth: 2
+ :titlesonly:
+ :glob:
+ :hidden:
+
+ pings
+ crashes
+ *
diff --git a/toolkit/components/telemetry/docs/concepts/pings.rst b/toolkit/components/telemetry/docs/concepts/pings.rst
new file mode 100644
index 0000000000..092f7b13fa
--- /dev/null
+++ b/toolkit/components/telemetry/docs/concepts/pings.rst
@@ -0,0 +1,29 @@
+.. _telemetry_pings:
+
+=====================
+Telemetry pings
+=====================
+
+A *Telemetry ping* is the data that we send to Mozilla's Telemetry servers.
+
+The top-level structure is defined by the :doc:`common ping format <../data/common-ping>`. This is a JSON object which contains:
+
+* some basic information shared between different ping types
+* the :doc:`environment data <../data/environment>` (optional)
+* the data specific to the *ping type*, the *payload*.
+
+Ping types
+==========
+
+We send Telemetry with different ping types. The :doc:`main <../data/main-ping>` ping is the ping that contains the bulk of the Telemetry measurements for Firefox. For more specific use-cases, we send other ping types.
+
+Pings sent from code that ships with Firefox are listed in the :doc:`data documentation <../data/index>`.
+
+Important examples are:
+
+* :doc:`main <../data/main-ping>` - contains the information collected by Telemetry (Histograms, Scalars, ...)
+* :doc:`saved-session <../data/main-ping>` - has the same format as a main ping, but it contains the *"classic"* Telemetry payload with measurements covering the whole browser session. This is only a separate type to make storage of saved-session easier server-side. As of Firefox 61 this is sent on Android only.
+* :doc:`crash <../data/crash-ping>` - a ping that is captured and sent after a Firefox process crashes.
+* :doc:`new-profile <../data/new-profile-ping>` - sent on the first run of a new profile.
+* :doc:`update <../data/update-ping>` - sent right after an update is downloaded.
+* :doc:`deletion-request <../data/deletion-request-ping>` - sent when FHR upload is disabled
diff --git a/toolkit/components/telemetry/docs/concepts/sessions.rst b/toolkit/components/telemetry/docs/concepts/sessions.rst
new file mode 100644
index 0000000000..39d6df961d
--- /dev/null
+++ b/toolkit/components/telemetry/docs/concepts/sessions.rst
@@ -0,0 +1,37 @@
+========
+Sessions
+========
+
+A *session* is the time from when Firefox starts until it shuts down.
+A session can be very long-running. E.g. for users that always put their computers into sleep-mode, Firefox may run for weeks.
+We slice the sessions into smaller logical units called *subsessions*.
+
+Subsessions
+===========
+
+The first subsession starts when the browser starts. After that, we split the subsession for different reasons:
+
+* ``daily``, when crossing local midnight. This keeps latency acceptable by triggering a ping at least daily for most active users.
+* ``environment-change``, when a change to the *environment* happens. This happens for important changes to the Firefox settings and when add-ons activate or deactivate.
+
+On a subsession split, a :doc:`main ping <../data/main-ping>` with that reason will be submitted. We store the reason in the pings payload, to see what triggered it.
+
+A session always ends with a subsession with one of two reason:
+
+* ``shutdown``, when the browser was cleanly shut down. To avoid delaying shutdown, we only save this ping to disk and send it at the next opportunity (typically the next browsing session).
+* ``aborted-session``, when the browser crashed. While Firefox is active, we write the current ``main`` ping data to disk every 5 minutes. If the browser crashes, we find this data on disk on the next start and send it with this reason.
+
+.. image:: subsession_triggers.png
+
+Subsession data
+===============
+
+A subsessions data consists of:
+
+* general information: the date the subsession started, how long it lasted, etc.
+* specific measurements: histogram & scalar data, etc.
+
+This has some advantages:
+
+* Latency - Sending a ping with all the data of a subsession immediately after it ends means we get the data from installs faster. For ``main`` pings, we aim to send a ping at least daily by starting a new subsession at local midnight.
+* Correlation - By starting new subsessions when fundamental settings change (i.e. changes to the *environment*), we can better correlate a subsession's data to those settings.
diff --git a/toolkit/components/telemetry/docs/concepts/submission.rst b/toolkit/components/telemetry/docs/concepts/submission.rst
new file mode 100644
index 0000000000..6f3ba3b0f0
--- /dev/null
+++ b/toolkit/components/telemetry/docs/concepts/submission.rst
@@ -0,0 +1,42 @@
+==========
+Submission
+==========
+
+*Note:* The server-side behaviour is documented in the `HTTP Edge Server specification <https://wiki.mozilla.org/CloudServices/DataPipeline/HTTPEdgeServerSpecification>`_.
+
+Pings are submitted via a common API on ``TelemetryController``.
+If a ping fails to successfully submit to the server immediately (e.g. because
+of missing internet connection), Telemetry will store it on disk and retry to
+send it until the maximum ping age is exceeded (14 days).
+
+.. note::
+
+ The :doc:`main pings <../data/main-ping>` are kept locally even after successful submission to enable the HealthReport feature. They will be deleted after their retention period of 180 days.
+
+Submission logic
+================
+
+Sending of pending pings starts as soon as the delayed startup is finished. They are sent in batches, newest-first, with up
+to 10 persisted pings per batch plus all unpersisted pings.
+The send logic then waits for each batch to complete.
+
+If it succeeds we trigger the next send of a ping batch. This is delayed as needed to only trigger one batch send per minute.
+
+If ping sending encounters an error that means retrying later, a backoff timeout behavior is
+triggered, exponentially increasing the timeout for the next try from 1 minute up to a limit of 120 minutes.
+Any new ping submissions and "idle-daily" events reset this behavior as a safety mechanism and trigger immediate ping sending.
+
+Pingsender
+==========
+Some pings (e.g. :doc:`crash pings <../data/crash-ping>` and :doc:`main pings <../data/main-ping>` with reason `shutdown`) are submitted using the :doc:`../internals/pingsender`.
+
+The pingsender tries to send each ping once and, if it fails, no additional attempt is performed: ``TelemetrySend`` will take care of retrying using the previously described submission logic.
+
+Status codes
+============
+
+The telemetry server team is working towards `the common services status codes <https://wiki.mozilla.org/CloudServices/DataPipeline/HTTPEdgeServerSpecification#Server_Responses>`_, but for now the following logic is sufficient for Telemetry:
+
+* `2XX` - success, don't resubmit
+* `4XX` - there was some problem with the request - the client should not try to resubmit as it would just receive the same response
+* `5XX` - there was a server-side error, the client should try to resubmit later
diff --git a/toolkit/components/telemetry/docs/concepts/subsession_triggers.png b/toolkit/components/telemetry/docs/concepts/subsession_triggers.png
new file mode 100644
index 0000000000..0a1dae2c23
--- /dev/null
+++ b/toolkit/components/telemetry/docs/concepts/subsession_triggers.png
Binary files differ
diff --git a/toolkit/components/telemetry/docs/data/addons-malware-ping.rst b/toolkit/components/telemetry/docs/data/addons-malware-ping.rst
new file mode 100644
index 0000000000..18502d7489
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/addons-malware-ping.rst
@@ -0,0 +1,42 @@
+
+Add-ons malware ping
+====================
+
+This ping is generated by an add-on created by Mozilla and shipped to users on older versions of Firefox (44-46). The ping contains information about the profile that might have been altered by a third party malicious add-on.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ type: "malware-addon-states",
+ ...
+ clientId: <UUID>,
+ environment: { ... },
+ // Common ping data.
+ payload: {
+ // True if the blocklist was disabled at startup time.
+ blocklistDisabled: <bool>,
+ // True if the malicious add-on exists and is enabled. False if it
+ // exists and is disabled or null if the add-on was not found.
+ mainAddonActive: <bool | null>,
+ // A value of the malicious add-on block list state, or null if the
+ // add-on was not found.
+ mainAddonBlocked: <int | null>,
+ // True if a malicious user.js file was found in the profile.
+ foundUserJS: <bool>,
+ // If a malicious secmodd.db file was found the extension ID that the // file contained..
+ secmoddAddon: <string | null>, .
+ // A list of IDs for extensions which were hidden by malicious CSS.
+ hiddenAddons: [
+ <string>,
+ ...
+ ],
+ // A mapping of installed add-on IDs with known malicious
+ // update URL patterns to their exact update URLs.
+ updateURLs: {
+ <extensionID>: <updateURL>,
+ ...
+ }
+ }
+ }
diff --git a/toolkit/components/telemetry/docs/data/anonymous-ping.rst b/toolkit/components/telemetry/docs/data/anonymous-ping.rst
new file mode 100644
index 0000000000..53e217fc9d
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/anonymous-ping.rst
@@ -0,0 +1,68 @@
+
+"anonymous" ping
+================
+
+.. note::
+
+ This ping is no longer sent by Firefox or Fennec.
+
+This ping is only for product survey purpose and will not track/associate client ID. It's used
+to evaluate custom tab usage and see which app is using our custom tab.
+
+Submission interval & triggers
+Since this ping is used to measure the feature usage, it should be sent each time the client app uses our custom tab.
+
+Dataset:
+Only opt-in users will send out this ping.
+Since all other pings will collect client ID. We need this custom ping to not do that.
+
+Size and volume:
+The size of submitted payload is small. And this custom ping should be deprecated after it's released for 6 months.
+
+Privacy:
+We won't collect customer information so there'll be no PI leak.
+
+Data contents:
+The content of this ping will let us know which app is using our custom tab.
+Just like other feature usage measurement, we only need it for opt-in users (which consider as heavy users).
+
+Structure:
+
+.. code-block:: js
+
+ {
+ "payload": {
+ "client": <string> // The package name of the caller app.
+ }
+ type: <string>, // "anonymous", "activation", "deletion", "saved-session", ...
+ id: <UUID>, // a UUID that identifies this ping
+ creationDate: <ISO date>, // the date the ping was generated
+ version: <number>, // the version of the ping format, currently 4
+
+ application: {
+ architecture: <string>, // build architecture, e.g. x86
+ buildId: <string>, // "20141126041045"
+ name: <string>, // "Firefox"
+ version: <string>, // "35.0"
+ displayVersion: <string>, // "35.0b3"
+ vendor: <string>, // "Mozilla"
+ platformVersion: <string>, // "35.0"
+ xpcomAbi: <string>, // e.g. "x86-msvc"
+ channel: <string>, // "beta"
+ },
+ }
+
+Field details
+-------------
+
+client
+~~~~~~
+It could be ``com.example.app``, which is the identifier of the app.
+
+Version history
+---------------
+* v1: initial version - Will be shipped in `Fennec 55 <https://bugzilla.mozilla.org/show_bug.cgi?id=1329157>`_.
+
+Notes
+~~~~~
+There's no option in this custom ping since we don't collect clientId nor environment data.
diff --git a/toolkit/components/telemetry/docs/data/backgroundhangmonitor-ping.rst b/toolkit/components/telemetry/docs/data/backgroundhangmonitor-ping.rst
new file mode 100644
index 0000000000..db4a28dd8b
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/backgroundhangmonitor-ping.rst
@@ -0,0 +1,162 @@
+
+"backgroundhangmonitor" ping
+============================
+
+Whenever a thread monitored by the Background Hang Monitor hangs, a stack and
+some non-identifying information about the hang is captured. When 50 of these
+hangs are collected across all processes, or the browser exits, this ping is
+transmitted with the collected hang information.
+
+This ping is only collected in nightly builds, to avoid the high volume of pings
+which would be produced in Beta.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ "type": "backgroundhangmonitor",
+ ... // common ping data
+ "environment": { ... },
+ "payload": {
+ "timeSinceLastPing": <number>, // uptime since last backgroundhangmonitor ping (ms).
+ "modules": [
+ [
+ <string>, // Name of the file holding the debug information.
+ <string> // Breakpad ID of this module.
+ ],
+ ...
+ ],
+ "hangs": [
+ {
+ "duration": <number>, // duration of the hang in milliseconds.
+ "thread": <string>, // name of the hanging thread.
+ "runnableName": <string>, // name of the runnable executing during the hang.
+ // Runnable names are only collected for the XPCOM main thread.
+ "process": <string>, // Type of process that hung, see below for a list of types.
+ "remoteType": <string>, // Remote type of process which hung, see below.
+ "annotations": [ ... ], // A list of annotations on the hang, see below.
+ "pseudoStack": [ ... ], // List of label stack frames and js frames.
+ "stack": [ ... ], // interleaved hang stack, see below.
+ },
+ ...
+ ]
+ }
+ }
+
+.. note::
+
+ Hangs are collected whenever the current runnable takes over 128ms.
+
+Process Types
+-------------
+
+The ``process`` field is a string denoting the kind of process that hung. Hangs
+are currently sent only for the processes below:
+
++---------------+---------------------------------------------------+
+| Kind | Description |
++===============+===================================================+
+| default | Main process, also known as the browser process |
++---------------+---------------------------------------------------+
+| tab | Content process |
++---------------+---------------------------------------------------+
+| gpu | GPU process |
++---------------+---------------------------------------------------+
+
+Remote Type
+-----------
+
+The ``remoteType`` field is a string denoting the type of content process that
+hung. As such it is only non-null if ``processType`` contains the ``tab`` value.
+
+The supported ``remoteType`` values are documented in the crash ping
+documentation: :ref:`remote-process-types`.
+
+Stack Traces
+------------
+
+Each hang object contains a ``stack`` field which has been populated with an
+interleaved stack trace of the hung thread. An interleaved stack consists of a
+native backtrace with additional frames interleaved, representing chrome JS and
+label stack entries.
+
+The structure that manages the label stack and the JS stack was called
+"PseudoStack" in the past and is now called "ProfilingStack".
+
+Note that this field only contains native stack frames, label stack and chrome
+JS script frames. If native stacks can not be collected on the target platform,
+or stackwalking was not initialized, there will be no native frames present, and
+the stack will consist only of label stack and chrome JS script frames.
+
+A single frame in the stack is either a raw string, representing a label stack
+or chrome JS script frame, or a native stack frame.
+
+Label stack frames contain the static string from all insances of the
+AUTO_PROFILER_LABEL* macros. Additionally, dynamic strings are collected from
+all usages of the AUTO_PROFILER_LABEL_DYNAMIC*_NONSENSITIVE macros. The dynamic
+strings are simply appended to the static strings after a space character.
+
+Current dynamic string collections are as follows:
+
++--------------------------------------------------+-----------------------------------------+
+| Static string | Dynamic |
++==================================================+=========================================+
+| ChromeUtils::Import | Associated chrome:// or resource:// URI |
++--------------------------------------------------+-----------------------------------------+
+| nsJSContext::GarbageCollectNow | GC reason string |
++--------------------------------------------------+-----------------------------------------+
+| mozJSSubScriptLoader::DoLoadSubScriptWithOptions | Associated chrome:// or resource:// URI |
++--------------------------------------------------+-----------------------------------------+
+| PresShell::DoFlushPendingNotifications | Flush type |
++--------------------------------------------------+-----------------------------------------+
+| nsObserverService::NotifyObservers | Associated observer topic |
++--------------------------------------------------+-----------------------------------------+
+
+Native stack frames are as such:
+
+.. code-block:: js
+
+ [
+ <number>, // Index in the payload.modules list of the module description.
+ // -1 if this frame was not in a valid module.
+ <string> // Hex string (e.g. "FF0F") of the frame offset in the module.
+ ]
+
+Annotations
+-----------
+
+The annotations field is an array of key-value pairs, for example if the user
+was interacting during a hang the annotations field would look something like
+this:
+
+.. code-block:: js
+
+ [
+ [
+ "UserInteracting",
+ "true"
+ ]
+ ]
+
+The following annotations are currently present in tree:
+
++-----------------+-------------------------------------------------+
+| Name | Description |
++=================+=================================================+
+| UserInteracting | "true" if the user was actively interacting |
++-----------------+-------------------------------------------------+
+| pluginName | Name of the currently running plugin |
++-----------------+-------------------------------------------------+
+| pluginVersion | Version of the currently running plugin |
++-----------------+-------------------------------------------------+
+| HangUIShown | "true" if the hang UI was shown |
++-----------------+-------------------------------------------------+
+| HangUIContinued | "true" if continue was selected in the hang UI |
++-----------------+-------------------------------------------------+
+| HangUIDontShow | "true" if the hang UI was not shown |
++-----------------+-------------------------------------------------+
+| Unrecovered | "true" if the hang persisted until process exit |
++-----------------+-------------------------------------------------+
+
+Additional annotations can be added at run-time via :doc:`../collection/user-interactions`.
diff --git a/toolkit/components/telemetry/docs/data/common-ping.rst b/toolkit/components/telemetry/docs/data/common-ping.rst
new file mode 100644
index 0000000000..1587131808
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/common-ping.rst
@@ -0,0 +1,42 @@
+
+Common ping format
+==================
+
+This defines the top-level structure of a Telemetry ping.
+It contains basic information shared between different ping types, which enables proper storage and processing of the raw pings server-side.
+
+It also contains optional further information:
+
+* the :doc:`environment data <../data/environment>`, which contains important info to correlate the measurements against
+* the ``clientId``, a UUID identifying a profile and allowing user-oriented correlation of data
+
+*Note:* Both are not submitted with all ping types due to privacy concerns. This and the data it that can be correlated against is inspected under the `data collection policy <https://wiki.mozilla.org/Firefox/Data_Collection>`_.
+
+Finally, the structure also contains the `payload`, which is the specific data submitted for the respective *ping type*.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ type: <string>, // "main", "activation", "optout", "saved-session", ...
+ id: <UUID>, // a UUID that identifies this ping
+ creationDate: <ISO date>, // the date the ping was generated
+ version: <number>, // the version of the ping format, currently 4
+
+ application: {
+ architecture: <string>, // build architecture, e.g. x86
+ buildId: <string>, // "20141126041045"
+ name: <string>, // "Firefox"
+ version: <string>, // "35.0"
+ displayVersion: <string>, // "35.0b3"
+ vendor: <string>, // "Mozilla"
+ platformVersion: <string>, // "35.0"
+ xpcomAbi: <string>, // e.g. "x86-msvc"
+ channel: <string>, // "beta"
+ },
+
+ clientId: <UUID>, // optional
+ environment: { ... }, // optional, not all pings contain the environment
+ payload: { ... }, // the actual payload data for this ping type
+ }
diff --git a/toolkit/components/telemetry/docs/data/coverage-ping.rst b/toolkit/components/telemetry/docs/data/coverage-ping.rst
new file mode 100644
index 0000000000..3db93d9074
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/coverage-ping.rst
@@ -0,0 +1,40 @@
+
+"coverage" ping
+===============
+
+This ping is not enabled by default. When enabled, a ping is generated a total of once per profile, as a diagnostic tool
+to determine whether Telemetry is working for users.
+
+This ping contains no client id and no environment data.
+
+You can find more background information in `this blog post <https://blog.mozilla.org/data/2018/08/20/effectively-measuring-search-in-firefox/>`_.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ "appVersion": "63.0a1",
+ "appUpdateChannel": "nightly",
+ "osName": "Darwin",
+ "osVersion": "17.7.0",
+ "telemetryEnabled": 1
+ }
+
+Expected behaviours
+-------------------
+The following is a list of expected behaviours for the ``coverage`` ping:
+
+- The ping will only be sent once per ping version, per profile.
+- If sending the ping fails, it will be retried on startup.
+- A totally arbitrary UUID is generated on first run on a new profile, to use for filtering duplicates.
+- The ping is sent to a different endpoint not using existing Telemetry.
+- The ping does not honor the Telemetry enabled preference, but provides its own opt-out preference: `toolkit.coverage.opt-out`.
+- The ping is disabled by default. It is intended to be enabled for users on an experimental basis using the preference `toolkit.coverage.enabled`.
+
+Version History
+---------------
+
+- Firefox 64:
+
+ - "coverage" ping shipped (`bug 1492656 <https://bugzilla.mozilla.org/show_bug.cgi?id=1492656>`_).
diff --git a/toolkit/components/telemetry/docs/data/crash-ping.rst b/toolkit/components/telemetry/docs/data/crash-ping.rst
new file mode 100644
index 0000000000..7d25f97319
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/crash-ping.rst
@@ -0,0 +1,262 @@
+Crash ping
+==========
+
+This ping is captured after the main Firefox process crashes or after a child process
+process crashes, whether or not the crash report is submitted to
+crash-stats.mozilla.org. It includes non-identifying metadata about the crash.
+
+This ping is sent either by the ``CrashManager`` or by the crash reporter
+client. The ``CrashManager`` is responsible for sending crash pings for the
+child processes crashes, which are sent right after the crash is detected,
+as well as for main process crashes, which are sent after Firefox restarts
+successfully. The crash reporter client sends crash pings only for main process
+crashes whether or not the user also reports the crash. The crash reporter
+client will not send the crash ping if telemetry has been disabled in Firefox.
+
+The environment block that is sent with this ping varies: if Firefox was running
+long enough to record the environment block before the crash, then the environment
+at the time of the crash will be recorded and ``hasCrashEnvironment`` will be true.
+If Firefox crashed before the environment was recorded, ``hasCrashEnvironment`` will
+be false and the recorded environment will be the environment at time of submission.
+
+The client ID is submitted with this ping.
+
+The metadata field holds a subset of the crash annotations, all field values
+are stored as strings but some may be interpreted either as numbers or
+boolean values. Numbers are integral unless stated otherwise in the
+description. Boolean values are set to "1" when true, "0" when false. If
+they're absent then they should be interpreted as false.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ type: "crash",
+ ... common ping data
+ clientId: <UUID>,
+ environment: { ... },
+ payload: {
+ crashDate: "YYYY-MM-DD",
+ crashTime: <ISO Date>, // per-hour resolution
+ version: 1,
+ sessionId: <UUID>, // Telemetry ID of crashing session. May be missing for crashes that happen early in startup
+ crashId: <UUID>, // Optional, ID of the associated crash
+ minidumpSha256Hash: <hash>, // SHA256 hash of the minidump file
+ processType: <type>, // Type of process that crashed, see below for a list of types
+ stackTraces: { ... }, // Optional, see below
+ metadata: { // Annotations saved while Firefox was running. See CrashAnnotations.yaml for more information
+ ProductID: "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}",
+ ProductName: "Firefox",
+ ReleaseChannel: <channel>,
+ Version: <version number>,
+ BuildID: "YYYYMMDDHHMMSS",
+ AsyncShutdownTimeout: <json>, // Optional, present when a shutdown blocker failed to respond within a reasonable amount of time
+ AvailablePageFile: <size>, // Windows-only, available paging file in bytes
+ AvailablePhysicalMemory: <size>, // Windows-only, available physical memory in bytes
+ AvailableSwapMemory: <size>, // macOS- and Linux-only, available swap space
+ AvailableVirtualMemory: <size>, // Windows-only, available virtual memory in bytes
+ BackgroundTaskName: "task_name", // Optional, if the app was invoked in background task mode via `--backgroundtask task_name`
+ BlockedDllList: <list>, // Windows-only, see WindowsDllBlocklist.cpp for details
+ BlocklistInitFailed: "1", // Windows-only, present only if the DLL blocklist initialization failed
+ CrashTime: <time>, // Seconds since the Epoch
+ DOMFissionEnabled: "1", // Optional, if set indicates that a Fission window had been opened
+ EventLoopNestingLevel: <levels>, // Optional, present only if >0, indicates the nesting level of the event-loop
+ ExperimentalFeatures: <features>, // Optional, a comma-separated string that specifies the enabled experimental features from about:preferences#experimental
+ FontName: <name>, // Optional, the font family name that is being loaded when the crash occurred
+ GPUProcessLaunchCount: <num>, // Number of times the GPU process was launched
+ HeadlessMode: "1", // Optional, "1" if the app was invoked in headless mode via `--headless ...` or `--backgroundtask ...`
+ ipc_channel_error: <error string>, // Optional, contains the string processing error reason for an ipc-based content crash
+ IsGarbageCollecting: "1", // Optional, if set indicates that the crash occurred while the garbage collector was running
+ LowCommitSpaceEvents: <num>, // Windows-only, present only if >0, number of low commit space events detected by the available memory tracker
+ MainThreadRunnableName: <name>, // Optional, Nightly-only, name of the currently executing nsIRunnable on the main thread
+ MozCrashReason: <reason>, // Optional, contains the string passed to MOZ_CRASH()
+ OOMAllocationSize: <size>, // Size of the allocation that caused an OOM
+ ProfilerChildShutdownPhase: <string>, // Profiler shutdown phase
+ PurgeablePhysicalMemory: <size>, // macOS-only, amount of memory that can be deallocated by the OS in case of memory pressure
+ QuotaManagerShutdownTimeout: <log-string>, // Optional, contains a list of shutdown steps and status of the quota manager clients
+ RemoteType: <type>, // Optional, type of content process, see below for a list of types
+ SecondsSinceLastCrash: <duration>, // Seconds elapsed since the last crash occurred
+ ShutdownProgress: <phase>, // Optional, contains a string describing the shutdown phase in which the crash occurred
+ SystemMemoryUsePercentage: <percentage>, // Windows-only, percent of memory in use
+ StartupCrash: "1", // Optional, if set indicates that Firefox crashed during startup
+ TextureUsage: <usage>, // Optional, usage of texture memory in bytes
+ TotalPageFile: <size>, // Windows-only, paging file in use expressed in bytes
+ TotalPhysicalMemory: <size>, // Windows-only, physical memory in use expressed in bytes
+ TotalVirtualMemory: <size>, // Windows-only, virtual memory in use expressed in bytes
+ UptimeTS: <duration>, // Seconds since Firefox was started, this can have a fractional component
+ User32BeforeBlocklist: "1", // Windows-only, present only if user32.dll was loaded before the DLL blocklist has been initialized
+ WindowsErrorReporting: "1", // Windows-only, present only if the crash was intercepted by the WER runtime exception module
+ WindowsPackageFamilyName: <string>, // Windows-only, a string containing the "Package Family Name" of Firefox, if installed through an MSIX package
+ },
+ hasCrashEnvironment: bool
+ }
+ }
+
+.. note::
+
+ For "crash" pings generated by the crashreporter we are deliberately truncating the ``creationTime``
+ field to hours. See `bug 1345108 <https://bugzilla.mozilla.org/show_bug.cgi?id=1345108>`_ for context.
+
+Process Types
+-------------
+
+The ``processType`` field contains the type of process that crashed. There are
+currently multiple process types defined in ``nsICrashService`` but crash pings
+are sent only for the ones below:
+
++---------------+-------------------------------------------------------------------------------+
+| Type | Description |
++===============+===============================================================================+
+| main | :ref:`Main process <parent-process>`, also known as parent or browser process |
++---------------+-------------------------------------------------------------------------------+
+| content | :ref:`Content process <content-process>` |
++---------------+-------------------------------------------------------------------------------+
+| gmplugin | :ref:`Gecko media plugin <gecko-media-plugins-process>` |
++---------------+-------------------------------------------------------------------------------+
+| gpu | :ref:`GPU process <gpu-process>` |
++---------------+-------------------------------------------------------------------------------+
+| vr | :ref:`VR process <vr-process>` |
++---------------+-------------------------------------------------------------------------------+
+| rdd | :ref:`Data decoder process <data-decoder-process>` |
++---------------+-------------------------------------------------------------------------------+
+| socket | :ref:`Network socket process <network-socket-process>` |
++---------------+-------------------------------------------------------------------------------+
+| sandboxbroker | :ref:`Remote sandbox broker <remote-sandbox-process>` |
++---------------+-------------------------------------------------------------------------------+
+| forkserver | :ref:`Fork server <fork-server>` |
++---------------+-------------------------------------------------------------------------------+
+| utility | :ref:`Utility process <utility-process>` |
++---------------+-------------------------------------------------------------------------------+
+
+.. _remote-process-types:
+
+Remote Process Types
+--------------------
+
+The optional ``remoteType`` field contains the type of the content process that
+crashed. As such it is present only if ``processType`` contains the ``content``
+value. The following content process types are currently defined:
+
++-----------+--------------------------------------------------------+
+| Type | Description |
++===========+========================================================+
+| web | The content process was running code from a web page |
++-----------+--------------------------------------------------------+
+| file | The content process was running code from a local file |
++-----------+--------------------------------------------------------+
+| extension | The content process was running code from an extension |
++-----------+--------------------------------------------------------+
+
+Stack Traces
+------------
+
+The crash ping may contain a ``stackTraces`` field which has been populated
+with stack traces for all threads in the crashed process. The format of this
+field is similar to the one used by Socorro for representing a crash. The main
+differences are that redundant fields are not stored and that the module a
+frame belongs to is referenced by index in the module array rather than by its
+file name.
+
+Note that this field does not contain data from the application; only bare
+stack traces and module lists are stored.
+
+.. code-block:: js
+
+ {
+ status: <string>, // Status of the analysis, "OK" or an error message
+ crash_info: { // Basic crash information
+ type: <string>, // Type of crash, SIGSEGV, assertion, etc...
+ address: <addr>, // Crash address crash, hex format, see the notes below
+ crashing_thread: <index> // Index in the thread array below
+ },
+ main_module: <index>, // Index of Firefox' executable in the module list
+ modules: [{
+ base_addr: <addr>, // Base address of the module, hex format
+ end_addr: <addr>, // End address of the module, hex format
+ code_id: <string>, // Unique ID of this module, see the notes below
+ debug_file: <string>, // Name of the file holding the debug information
+ debug_id: <string>, // ID or hash of the debug information file
+ filename: <string>, // File name
+ version: <string>, // Library/executable version
+ },
+ ... // List of modules ordered by base memory address
+ ],
+ threads: [{ // Stack traces for every thread
+ frames: [{
+ module_index: <index>, // Index of the module this frame belongs to
+ ip: <ip>, // Program counter, hex format
+ trust: <string> // Trust of this frame, see the notes below
+ },
+ ... // List of frames, the first frame is the topmost
+ ]
+ }]
+ }
+
+Notes
+~~~~~
+
+Memory addresses and instruction pointers are always stored as strings in
+hexadecimal format (e.g. "0x4000"). They can be made of up to 16 characters for
+64-bit addresses.
+
+The crash type is both OS and CPU dependent and can be either a descriptive
+string (e.g. SIGSEGV, EXCEPTION_ACCESS_VIOLATION) or a raw numeric value. The
+crash address meaning depends on the type of crash. In a segmentation fault the
+crash address will be the memory address whose access caused the fault; in a
+crash triggered by an illegal instruction exception the address will be the
+instruction pointer where the invalid instruction resides.
+See `breakpad <https://chromium.googlesource.com/breakpad/breakpad/+/c99d374dde62654a024840accfb357b2851daea0/src/processor/minidump_processor.cc#675>`__'s
+relevant code for further information.
+
+Since it's not always possible to establish with certainty the address of the
+previous frame while walking the stack, every frame has a trust value that
+represents how it was found and thus how certain we are that it's a real frame.
+The trust levels are (from least trusted to most trusted):
+
++---------------+---------------------------------------------------+
+| Trust | Description |
++===============+===================================================+
+| context | Given as instruction pointer in a context |
++---------------+---------------------------------------------------+
+| prewalked | Explicitly provided by some external stack walker |
++---------------+---------------------------------------------------+
+| cfi | Derived from call frame info |
++---------------+---------------------------------------------------+
+| frame_pointer | Derived from frame pointer |
++---------------+---------------------------------------------------+
+| cfi_scan | Found while scanning stack using call frame info |
++---------------+---------------------------------------------------+
+| scan | Scanned the stack, found this |
++---------------+---------------------------------------------------+
+| none | Unknown, this is most likely not a valid frame |
++---------------+---------------------------------------------------+
+
+The ``code_id`` field holds a unique ID used to distinguish between different
+versions and builds of the same module. See `breakpad <https://chromium.googlesource.com/breakpad/breakpad/+/24f5931c5e0120982c0cbf1896641e3ef2bdd52f/src/google_breakpad/processor/code_module.h#60>`__'s
+description for further information. This field is populated only on Windows.
+
+Version History
+---------------
+
+- Firefox 58: Added ipc_channel_error (`bug 1410143 <https://bugzilla.mozilla.org/show_bug.cgi?id=1410143>`_).
+- Firefox 62: Added LowCommitSpaceEvents (`bug 1464773 <https://bugzilla.mozilla.org/show_bug.cgi?id=1464773>`_).
+- Firefox 63: Added RecordReplayError (`bug 1481009 <https://bugzilla.mozilla.org/show_bug.cgi?id=1481009>`_).
+- Firefox 64: Added MemoryErrorCorrection (`bug 1498609 <https://bugzilla.mozilla.org/show_bug.cgi?id=1498609>`_).
+- Firefox 68: Added IndexedDBShutdownTimeout and LocalStorageShutdownTimeout
+ (`bug 1539750 <https://bugzilla.mozilla.org/show_bug.cgi?id=1539750>`_).
+- Firefox 74: Added AvailableSwapMemory and PurgeablePhysicalMemory
+ (`bug 1587721 <https://bugzilla.mozilla.org/show_bug.cgi?id=1587721>`_).
+- Firefox 74: Added MainThreadRunnableName (`bug 1608158 <https://bugzilla.mozilla.org/show_bug.cgi?id=1608158>`_).
+- Firefox 76: Added DOMFissionEnabled (`bug 1602918 <https://bugzilla.mozilla.org/show_bug.cgi?id=1602918>`_).
+- Firefox 79: Added ExperimentalFeatures (`bug 1644544 <https://bugzilla.mozilla.org/show_bug.cgi?id=1644544>`_).
+- Firefox 85: Added QuotaManagerShutdownTimeout, removed IndexedDBShutdownTimeout and LocalStorageShutdownTimeout
+ (`bug 1672369 <https://bugzilla.mozilla.org/show_bug.cgi?id=1672369>`_).
+- Firefox 89: Added GPUProcessLaunchCount (`bug 1710448 <https://bugzilla.mozilla.org/show_bug.cgi?id=1710448>`_)
+ and ProfilerChildShutdownPhase (`bug 1704680 <https://bugzilla.mozilla.org/show_bug.cgi?id=1704680>`_).
+- Firefox 90: Removed MemoryErrorCorrection (`bug 1710152 <https://bugzilla.mozilla.org/show_bug.cgi?id=1710152>`_)
+ and added WindowsErrorReporting (`bug 1703761 <https://bugzilla.mozilla.org/show_bug.cgi?id=1703761>`_).
+- Firefox 95: Added HeadlessMode and BackgroundTaskName (`bug 1697875 <https://bugzilla.mozilla.org/show_bug.cgi?id=1697875>`_).
+- Firefox 96: Added WindowsPackageFamilyName (`bug 1738375 <https://bugzilla.mozilla.org/show_bug.cgi?id=1738375>`_).
+- Firefox 103: Removed ContainsMemoryReport (`bug 1776279 <https://bugzilla.mozilla.org/show_bug.cgi?id=1776279>`_).
+- Firefox 107: Added UtilityActorsName (`bug 1788596 <https://bugzilla.mozilla.org/show_bug.cgi?id=1788596>`_).
diff --git a/toolkit/components/telemetry/docs/data/default-browser-ping.rst b/toolkit/components/telemetry/docs/data/default-browser-ping.rst
new file mode 100644
index 0000000000..17eacee960
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/default-browser-ping.rst
@@ -0,0 +1,90 @@
+======================
+"default-browser" ping
+======================
+
+This opt-out ping is sent from the Default Browser Agent, which is a Windows-only program that registers itself during Firefox installation with the Windows scheduled tasks system so that it runs automatically every 24 hours, whether Firefox is running or not. The scheduled task gathers the data for this ping and then sends it by handing it off to :doc:`../internals/pingsender`.
+
+Even though this ping is generated by a binary separate from Firefox itself, opting out of telemetry does disable it; the pref value is copied to the registry so that the default browser agent can read it without needing to work with profiles. Relevant policies are consulted as well. The agent also has its own pref, ``default-agent.enabled``, which if set to false disables all agent functionality, including generating this ping.
+
+Each installation of Firefox has its own copy of the agent and its own scheduled task, so one ping will be sent every day for each installation on a given machine. This is needed because the default browser setting is per-user, and different installations may have been created by different users. If multiple operating system-level users are all using one copy of Firefox, only one scheduled task will have been created and only one ping will be sent, even though the users might have different default browser settings.
+
+The namespace this ping is in is called ``default-browser-agent``.
+
+For more information about the default browser agent itself, see :doc:`its documentation </toolkit/mozapps/defaultagent/default-browser-agent/index>`.
+
+Structure
+=========
+
+Since this ping is sent from an external binary, it's structured as its own ping document type and not in the standard Firefox telemetry format. It's also missing lots of data that would normally be present; for instance, there is no ``clientId``, because the agent does not load any profile and so has no way to find any, and no environment block because the agent doesn't contain the telemetry library code to build it.
+
+Here's the format of the ping data, with example values for each property:
+
+.. code-block:: js
+
+ {
+ build_channel: <string>, // ex. "nightly", or "beta", or "release"
+ version: <string>, // ex. "72.0.2"
+ os_version: <string>, // ex. 10.0.18363.592
+ os_locale: <string>, // ex. en-US
+ default_browser: <string>, // ex. "firefox"
+ previous_default_browser: <string>, // ex. "edge"
+ default_pdf_viewer_raw: <string>, // ex. "firefox"
+ notification_type: <string>, // ex. "initial" or "followup"
+ notification_shown: <string>, // ex. "shown", or "not-shown", or "error"
+ notification_action: <string>, // ex. "no-action" or "make-firefox-default-button"
+ previous_notification_action: <string>, // Same possible values as notification_action
+ }
+
+``build_channel``
+-----------------
+The Firefox channel.
+
+``version``
+-----------
+The Firefox version.
+
+``os_version``
+--------------
+The Windows version number. Below Windows 10, this is in the format ``[major].[minor].[build]``; for Windows 10, the format is ``10.0.[build].[UBR]``.
+
+``os_locale``
+-------------
+The locale that the user has selected for the operating system (NOT for Firefox).
+
+``default_browser``
+-------------------
+Which browser is currently set as the system default web browser. This is simply a string with the name of the browser; the possible values include "firefox", "chrome", "edge", "edge-chrome", "ie", "opera", and "brave".
+
+``previous_default_browser``
+----------------------------
+Which browser was set as the system default before it was changed to the current setting. The possible values are the same as for ``default_browser``.
+
+The OS does not keep track of previous default settings, so the agent records this information itself. That means that it will be inaccurate until the first time the default is changed after the agent task begins running. Before then, the value of ``previous_default_browser`` will be the same as ``default_browser``.
+
+This value is updated every time the Default Browser Agent runs, so when the default browser is first changed the values for ``default_browser`` and ``previous_default_browser`` will be different. But on subsequent executions of the Default Browser Agent, the two values will be the same.
+
+``default_pdf_viewer_raw``
+--------------------------
+Which pdf viewer is currently set as the system default. This is simply a string with the name of the pdf viewer.
+
+``notification_type``
+---------------------
+Which notification type was shown. There are currently two types of notifications, "initial" and "followup". The initial notification is shown first and has a "Remind me later" button. The followup notification is only shown if the "Remind me later" button is clicked and has a "Never ask again" button instead of the "Remind me later" button. Note that the value of ``notification_shown`` should be consulted to determine whether the notification type specified was actually shown.
+
+``notification_shown``
+----------------------
+Whether a notification was shown or not. Possible value include "shown", "not-shown", and "error".
+
+``notification_action``
+-----------------------
+The action that the user took in response to the notification. Possible values currently include "dismissed-by-timeout", "dismissed-to-action-center", "dismissed-by-button", "dismissed-by-application-hidden", "remind-me-later", "make-firefox-default-button", "toast-clicked", "no-action".
+
+Many of the values correspond to buttons on the notification and should be pretty self explanatory, but a few are less so. The action "no-action" will be used if and only if the value of ``notification_shown`` is not "shown" to indicate that no action was taken because no notification was displayed. The action "dismissed-to-action-center" will be used if the user clicks the arrow in the top right corner of the notification to dismiss it to the action center. The action "dismissed-by-application-hidden" is provided because that is a method of dismissal that the notification API could give but, in practice, should never be seen. The action "dismissed-by-timeout" indicates that the user did not interact with the notification and it timed out.
+
+``previous_notification_action``
+--------------------------------
+The action that the user took in response to the previous notification. Possible values are the same as those of ``notification_action``.
+
+If no notification has ever been shown, this will be "no-action". If ``notification_shown`` is "shown", this will be the action that was taken on the notification before the one that was just shown (or "no-action" if there was no previous notification). Otherwise, this will be the action that the user took the last time a notification was shown.
+
+Note that because this feature was added later, there may be people in configurations that might seem impossible, like having the combination of ``notification_type`` being "followup" with a ``previous_notification_action`` of "no-action", because the first notification action was taken before we started storing that value.
diff --git a/toolkit/components/telemetry/docs/data/deletion-request-ping.rst b/toolkit/components/telemetry/docs/data/deletion-request-ping.rst
new file mode 100644
index 0000000000..0c1c00c301
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/deletion-request-ping.rst
@@ -0,0 +1,68 @@
+"deletion-request" ping
+=======================
+
+This ping is submitted when a user opts out of sending technical and interaction data to Mozilla.
+(In other words, when the
+``datareporting.healthreport.uploadEnabled``
+:doc:`preference <../internals/preferences>` is set to ``false``.)
+
+This ping contains the client id.
+This ping does not contain any environment data.
+
+This ping is intended to communicate to the Data Pipeline that the user wishes
+to have their reported Telemetry data deleted.
+As such it attempts to send itself at the moment the user opts out of data collection,
+and continues to try and send itself.
+
+This ping contains scalars present in the "deletion-request" store.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ version: 4,
+ type: "deletion-request",
+ ... common ping data (including clientId)
+ payload: {
+ scalars: {
+ <process-type>: { // like "parent" or "content"
+ <id name>: <id>, // like "deletion.request.impression_id": "<RFC 4122 GUID>"
+ },
+ },
+ }
+ }
+
+Expected behaviours
+-------------------
+The following is a list of expected behaviours for the ``deletion-request`` ping:
+
+- Telemetry will try to send the ping even if upload is disabled.
+- Telemetry may persist this ping if it can't be immediately sent, and may try to resend it later.
+
+Analysis Gotchas
+----------------
+It is `known <https://bugzilla.mozilla.org/show_bug.cgi?id=1741252>`_ that,
+on a release week, "deletion-request" pings from the previous release version will spike in volume.
+
+There is a strong geo component to these spikes (China and Russia mostly).
+The pings behave like they're coming from real Firefox instances (one per ``client_id``).
+However, we've received no "main" pings from these clients from the previous 28 days
+(per ``clients_last_seen``) which makes them rather unusual.
+
+We suspect this is some sort of automation or pseudo-automation.
+
+Including these pings in our self-service deletion processes doesn't make them any slower,
+and ingesting them isn't breaking the bank, so at time of writing we're inclined to take a
+"document and then ignore" approach.
+
+Version History
+---------------
+
+- Firefox 72:
+
+ - "deletion-request" ping replaces the "optout" ping (`bug 1585410 <https://bugzilla.mozilla.org/show_bug.cgi?id=1585410>`_).
+
+- Firefox 73:
+
+ - Added support for subordinate ids in the "deletion-request" store (`bug 1604312 <https://bugzilla.mozilla.org/show_bug.cgi?id=1604312>`_).
diff --git a/toolkit/components/telemetry/docs/data/downgrade-ping.rst b/toolkit/components/telemetry/docs/data/downgrade-ping.rst
new file mode 100644
index 0000000000..5366255834
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/downgrade-ping.rst
@@ -0,0 +1,30 @@
+
+"downgrade" ping
+================
+
+This ping is captured when attempting to use a profile that was previously used
+with a newer version of the application.
+
+This ping is submitted directly through the ```pingsender```. The common ping
+data relates to the profile and application that the user attempted to use.
+
+The client ID is submitted with this ping. No environment block is included with
+this ping.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ type: "downgrade",
+ ... common ping data
+ clientId: <UUID>,
+ payload: {
+ lastVersion: "", // The last version of the application that ran this profile
+ hasSync: <bool>, // Whether the profile is signed in to sync
+ hasBinary: <bool>, // Whether the last version of the application is available to run
+ button: <int> // The button the user chose to click from the UI:
+ // 0 - Quit
+ // 1 - Create new profile
+ }
+ }
diff --git a/toolkit/components/telemetry/docs/data/environment.rst b/toolkit/components/telemetry/docs/data/environment.rst
new file mode 100644
index 0000000000..8b7c38ef89
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/environment.rst
@@ -0,0 +1,617 @@
+
+Environment
+===========
+
+The environment consists of data that is expected to be characteristic for performance and other behavior and not expected to change too often.
+
+Changes to most of these data points are detected (where possible and sensible) and will lead to a session split in the :doc:`main-ping`.
+The environment data may also be submitted by other ping types.
+
+*Note:* This is not submitted with all ping types due to privacy concerns. This and other data is inspected under the `data collection policy <https://wiki.mozilla.org/Firefox/Data_Collection>`_.
+
+Some parts of the environment must be fetched asynchronously at startup. We don't want other Telemetry components to block on waiting for the environment, so some items may be missing from it until the async fetching finished.
+This currently affects the following sections:
+
+- profile
+- add-ons
+- services
+
+
+Structure:
+
+.. code-block:: js
+
+ {
+ build: {
+ applicationId: <string>, // nsIXULAppInfo.ID
+ applicationName: <string>, // "Firefox"
+ architecture: <string>, // e.g. "x86", build architecture for the active build
+ buildId: <string>, // e.g. "20141126041045"
+ version: <string>, // e.g. "35.0"
+ vendor: <string>, // e.g. "Mozilla"
+ displayVersion: <string>, // e.g. "35.0b1"
+ platformVersion: <string>, // e.g. "35.0"
+ xpcomAbi: <string>, // e.g. "x86-msvc"
+ updaterAvailable: <bool>, // Whether the app was built with app update available (MOZ_UPDATER)
+ },
+ settings: {
+ addonCompatibilityCheckEnabled: <bool>, // Whether application compatibility is respected for add-ons
+ blocklistEnabled: <bool>, // true on failure
+ isDefaultBrowser: <bool>, // whether Firefox is the default browser. On Windows, this is operationalized as whether Firefox is the default HTTP protocol handler and the default HTML file handler.
+ defaultSearchEngine: <string>, // e.g. "yahoo"
+ defaultSearchEngineData: {, // data about the current default engine
+ name: <string>, // engine name, e.g. "Yahoo"; or "NONE" if no default
+ loadPath: <string>, // where the engine line is located; missing if no default
+ origin: <string>, // 'default', 'verified', 'unverified', or 'invalid'; based on the presence and validity of the engine's loadPath verification hash.
+ submissionURL: <string> // set for default engines or well known search domains
+ },
+ defaultPrivateSearchEngine: <string>, // e.g. "duckduckgo"
+ defaultPrivateSearchEngine: {,
+ // data about the current default engine for private browsing mode. Same as defaultSearchEngineData.
+ },
+ launcherProcessState: <integer>, // optional, values correspond to values of mozilla::LauncherRegistryInfo::EnabledState enum
+ e10sEnabled: <bool>, // whether e10s is on, i.e. browser tabs open by default in a different process
+ e10sMultiProcesses: <integer>, // Maximum number of processes that will be launched for regular web content
+ fissionEnabled: <bool>, // whether fission is enabled this session, and subframes can load in a different process
+ telemetryEnabled: <bool>, // false on failure
+ locale: <string>, // e.g. "it", null on failure
+ intl: {
+ requestedLocales: [ <string>, ... ], // The locales that are being requested.
+ availableLocales: [ <string>, ... ], // The locales that are available for use.
+ appLocales: [ <string>, ... ], // The negotiated locales that are being used.
+ systemLocales: [ <string>, ... ], // The locales for the OS.
+ regionalPrefsLocales: [ <string>, ... ], // The regional preferences for the OS.
+ acceptLanguages: [ <string>, ... ], // The languages for the Accept-Languages header.
+ },
+ update: {
+ channel: <string>, // e.g. "release", null on failure
+ enabled: <bool>, // true on failure
+ autoDownload: <bool>, // true on failure
+ background: <bool>, // Indicates whether updates may be installed when Firefox is not running.
+ },
+ userPrefs: {
+ // Only prefs which are changed are listed in this block
+ "pref.name.value": value // some prefs send the value
+ "pref.name.url": "<user-set>" // For some privacy-sensitive prefs
+ // only the fact that the value has been changed is recorded
+ },
+ attribution: { // optional, only present if the installation has attribution data
+ // all of these values are optional.
+ source: <string>, // referring partner domain, when install happens via a known partner
+ medium: <string>, // category of the source, such as "organic" for a search engine
+ campaign: <string>, // identifier of the particular campaign that led to the download of the product
+ content: <string>, // identifier to indicate the particular link within a campaign
+ variation: <string>, // name/id of the variation cohort used in the enrolled funnel experiment
+ experiment: <string>, // name/id of the enrolled funnel experiment
+ ua: <string>, // identifier derived from the user agent downloading the installer, e.g., chrome, Google Chrome 123
+ dltoken: <string>, // Unique token created at Firefox download time. ex: c18f86a3-f228-4d98-91bb-f90135c0aa9c
+ msstoresignedin: <boolean>, // optional, only present if the installation was done through the Microsoft Store, and was able to retrieve the "campaign ID" it was first installed with. this value is "true" if the user was signed into the Microsoft Store when they first installed, and false otherwise
+ dlsource: <string>, // identifier that indicate where installations of Firefox originate
+ },
+ sandbox: {
+ effectiveContentProcessLevel: <integer>,
+ contentWin32kLockdownState: <integer>,
+ }
+ },
+ // Optional, missing if fetching the information failed or had not yet completed.
+ services: {
+ // True if the user has a firefox account
+ accountEnabled: <bool>,
+ // True if the user has sync enabled.
+ syncEnabled: <bool>
+ },
+ profile: {
+ creationDate: <integer>, // integer days since UNIX epoch, e.g. 16446
+ resetDate: <integer>, // integer days since UNIX epoch, e.g. 16446 - optional
+ firstUseDate: <integer>, // integer days since UNIX epoch, e.g. 16446 - optional
+ },
+ partner: { // This section may not be immediately available on startup
+ distributionId: <string>, // pref "distribution.id", null on failure
+ distributionVersion: <string>, // pref "distribution.version", null on failure
+ partnerId: <string>, // pref mozilla.partner.id, null on failure
+ distributor: <string>, // pref app.distributor, null on failure
+ distributorChannel: <string>, // pref app.distributor.channel, null on failure
+ partnerNames: [
+ // list from prefs app.partner.<name>=<name>
+ ],
+ },
+ system: {
+ memoryMB: <number>,
+ virtualMaxMB: <number>, // windows-only
+ isWow64: <bool>, // windows-only
+ isWowARM64: <bool>, // windows-only
+ hasWinPackageId: <bool>, // windows-only
+ winPackageFamilyName: <string>, // windows-only
+ cpu: {
+ count: <number>, // desktop only, e.g. 8, or null on failure - logical cpus
+ cores: <number>, // desktop only, e.g., 4, or null on failure - physical cores
+ vendor: <string>, // desktop only, e.g. "GenuineIntel", or null on failure
+ name: <string>, // desktop only, e.g. "Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz",
+ // or null on failure
+ family: <number>, // desktop only, null on failure
+ model: <number, // desktop only, null on failure
+ stepping: <number>, // desktop only, null on failure
+ l2cacheKB: <number>, // L2 cache size in KB, only on windows & mac
+ l3cacheKB: <number>, // desktop only, L3 cache size in KB
+ speedMHz: <number>, // desktop only, cpu clock speed in MHz
+ extensions: [
+ <string>,
+ ...
+ // as applicable:
+ // "hasMMX", "hasSSE", "hasSSE2", "hasSSE3", "hasSSSE3",
+ // "hasSSE4A", "hasSSE4_1", "hasSSE4_2", "hasAVX", "hasAVX2",
+ // "hasAES", "hasEDSP", "hasARMv6", "hasARMv7", "hasNEON"
+ ],
+ },
+ device: { // This section is only available on mobile devices.
+ model: <string>, // the "device" from FHR, null on failure
+ manufacturer: <string>, // null on failure
+ hardware: <string>, // null on failure
+ isTablet: <bool>, // null on failure
+ },
+ os: {
+ name: <string>, // "Windows_NT" or null on failure
+ version: <string>, // e.g. "6.1", null on failure
+ kernelVersion: <string>, // android only or null on failure
+ servicePackMajor: <number>, // windows only or null on failure
+ servicePackMinor: <number>, // windows only or null on failure
+ windowsBuildNumber: <number>, // windows only or null on failure
+ windowsUBR: <number>, // windows 10 only or null on failure
+ installYear: <number>, // windows only or null on failure
+ locale: <string>, // "en" or null on failure
+ hasPrefetch: <bool>, // windows only, or null on failure
+ hasSuperfetch: <bool>, // windows only, or null on failure
+ distro: <string>, // linux only, or null on failure
+ distroVersion: <string>, // linux only, or null on failure
+ },
+ hdd: {
+ profile: { // hdd where the profile folder is located
+ model: <string>, // windows only or null on failure
+ revision: <string>, // windows only or null on failure
+ type: <string>, // "SSD" or "HDD" windows only or null on failure
+ },
+ binary: { // hdd where the application binary is located
+ model: <string>, // windows only or null on failure
+ revision: <string>, // windows only or null on failure
+ type: <string>, // "SSD" or "HDD" windows only or null on failure
+ },
+ system: { // hdd where the system files are located
+ model: <string>, // windows only or null on failure
+ revision: <string>, // windows only or null on failure
+ type: <string>, // "SSD" or "HDD" windows only or null on failure
+ },
+ },
+ gfx: {
+ D2DEnabled: <bool>, // null on failure
+ DWriteEnabled: <bool>, // null on failure
+ ContentBackend: <string> // One of "Cairo", "Skia", or "Direct2D 1.1"
+ Headless: <bool>, // null on failure
+ //DWriteVersion: <string>, // temporarily removed, pending bug 1154500
+ adapters: [
+ {
+ description: <string>, // e.g. "Intel(R) HD Graphics 4600", null on failure
+ vendorID: <string>, // null on failure
+ deviceID: <string>, // null on failure
+ subsysID: <string>, // null on failure
+ RAM: <number>, // in MB, null on failure
+ driver: <string>, // null on failure
+ driverVendor: <string>, // null on failure
+ driverVersion: <string>, // null on failure
+ driverDate: <string>, // null on failure
+ GPUActive: <bool>, // currently always true for the first adapter
+ },
+ ...
+ ],
+ // Note: currently only added on Desktop. On Linux, only a single
+ // monitor is returned for the primary screen.
+ monitors: [
+ {
+ screenWidth: <number>, // screen width in pixels
+ screenHeight: <number>, // screen height in pixels
+ refreshRate: <number>, // refresh rate in hertz (present on Windows only).
+ // (values <= 1 indicate an unknown value)
+ pseudoDisplay: <bool>, // networked screen (present on Windows only)
+ scale: <number>, // backing scale factor (present on Mac only)
+ },
+ ...
+ ],
+ features: {
+ compositor: <string>, // Layers backend for compositing (e.g. "d3d11", "none", "opengl", "webrender")
+
+ // Each the following features can have one of the following statuses:
+ // "unused" - This feature has not been requested.
+ // "unavailable" - Safe Mode or OS restriction prevents use.
+ // "blocked" - Blocked due to an internal condition such as safe mode.
+ // "blacklisted" - Blocked due to a blacklist restriction.
+ // "denied" - Blocked due to allowlist restrictions.
+ // "disabled" - User explicitly disabled this default feature.
+ // "failed" - This feature was attempted but failed to initialize.
+ // "available" - User has this feature available.
+ // The status can also include a ":" followed by a reason
+ // e.g. "FEATURE_FAILURE_WEBRENDER_VIDEO_CRASH_INTEL_23.20.16.4973"
+ d3d11: { // This feature is Windows-only.
+ status: <string>,
+ warp: <bool>, // Software rendering (WARP) mode was chosen.
+ textureSharing: <bool> // Whether or not texture sharing works.
+ version: <number>, // The D3D11 device feature level.
+ blacklisted: <bool>, // Whether D3D11 is blacklisted; use to see whether WARP
+ // was blacklist induced or driver-failure induced.
+ },
+ d2d: { // This feature is Windows-only.
+ status: <string>,
+ version: <string>, // Either "1.0" or "1.1".
+ },
+ gpuProcess: { // Out-of-process compositing ("GPU process") feature
+ status: <string>, // "Available" means currently in use
+ },
+ hwCompositing: { // hardware acceleration. i.e. whether we try using the GPU
+ status: <string>
+ },
+ wrCompositor: { // native OS compositor (CA, DComp, etc.)
+ status: <string>
+ }
+ wrSoftware: { // Software backend for WebRender, only computed when 'compositor' is 'webrender'
+ status: <string>
+ }
+ openglCompositing: { // OpenGL compositing.
+ status: <string>
+ }
+ },
+ },
+ appleModelId: <string>, // Mac only or null on failure
+ sec: { // This feature is Windows 8+ only
+ antivirus: [ <string>, ... ], // null if unavailable on platform: Product name(s) of registered antivirus programs
+ antispyware: [ <string>, ... ], // null if unavailable on platform: Product name(s) of registered antispyware programs
+ firewall: [ <string>, ... ], // null if unavailable on platform: Product name(s) of registered firewall programs
+ },
+ },
+ addons: {
+ activeAddons: { // the currently enabled add-ons
+ <addon id>: {
+ blocklisted: <bool>,
+ description: <string>, // null if not available
+ name: <string>,
+ userDisabled: <bool>,
+ appDisabled: <bool>,
+ version: <string>,
+ scope: <integer>,
+ type: <string>, // "extension", "locale", ...
+ foreignInstall: <bool>,
+ hasBinaryComponents: <bool>,
+ installDay: <number>, // days since UNIX epoch, 0 on failure
+ updateDay: <number>, // days since UNIX epoch, 0 on failure
+ signedState: <integer>, // whether the add-on is signed by AMO, only present for extensions
+ isSystem: <bool>, // true if this is a System Add-on
+ isWebExtension: <bool>, // true if this is a WebExtension
+ multiprocessCompatible: <bool>, // true if this add-on does *not* require e10s shims
+ },
+ ...
+ },
+ theme: { // the active theme
+ id: <string>,
+ blocklisted: <bool>,
+ description: <string>,
+ name: <string>,
+ userDisabled: <bool>,
+ appDisabled: <bool>,
+ version: <string>,
+ scope: <integer>,
+ foreignInstall: <bool>,
+ hasBinaryComponents: <bool>
+ installDay: <number>, // days since UNIX epoch, 0 on failure
+ updateDay: <number>, // days since UNIX epoch, 0 on failure
+ },
+ activeGMPlugins: {
+ <gmp id>: {
+ version: <string>,
+ userDisabled: <bool>,
+ applyBackgroundUpdates: <integer>,
+ },
+ ...
+ },
+ },
+ experiments: {
+ "<experiment id>": { branch: "<branch>", type: "<type>", enrollmentId: "<id>" },
+ // ...
+ }
+ }
+
+build
+-----
+
+buildId
+~~~~~~~
+Firefox builds downloaded from mozilla.org use a 14-digit buildId. Builds included in other distributions may have a different format (e.g. only 10 digits).
+
+Settings
+--------
+
+defaultSearchEngine
+~~~~~~~~~~~~~~~~~~~
+Note: Deprecated, use defaultSearchEngineData instead.
+
+Contains the string identifier or name of the default search engine provider. This will not be present in environment data collected before the Search Service initialization.
+
+The special value ``NONE`` could occur if there is no default search engine.
+
+The special value ``UNDEFINED`` could occur if a default search engine exists but its identifier could not be determined.
+
+This field's contents are ``Services.search.defaultEngine.identifier`` (if defined) or ``"other-"`` + ``Services.search.defaultEngine.name`` if not. In other words, search engines without an ``.identifier`` are prefixed with ``other-``.
+
+defaultSearchEngineData
+~~~~~~~~~~~~~~~~~~~~~~~
+Contains data identifying the engine currently set as the default.
+
+The object contains:
+
+- a ``name`` property with the name of the engine, or ``NONE`` if no
+ engine is currently set as the default.
+
+- a ``loadPath`` property: an anonymized path of the engine xml file, e.g.
+ jar:[app]/omni.ja!browser/engine.xml
+ (where 'browser' is the name of the chrome package, not a folder)
+ [profile]/searchplugins/engine.xml
+ [distribution]/searchplugins/common/engine.xml
+ [other]/engine.xml
+ [other]/addEngineWithDetails
+ [other]/addEngineWithDetails:extensionID
+ [http/https]example.com/engine-name.xml
+ [http/https]example.com/engine-name.xml:extensionID
+
+- an ``origin`` property: the value will be ``default`` for engines that are built-in or from distribution partners, ``verified`` for user-installed engines with valid verification hashes, ``unverified`` for non-default engines without verification hash, and ``invalid`` for engines with broken verification hashes.
+
+- a ``submissionURL`` property with the HTTP url we would use to search.
+ For privacy, we don't record this for user-installed engines.
+
+``loadPath`` and ``submissionURL`` are not present if ``name`` is ``NONE``.
+
+defaultPrivateSearchEngineData
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+This contains the data identifying the engine current set as the default for
+private browsing mode. This may be the same engine as set for normal browsing
+mode.
+
+This object contains the same information as ``defaultSearchEngineData``. It
+is only reported if the ``browser.search.separatePrivateDefault`` preference is
+set to ``true``.
+
+userPrefs
+~~~~~~~~~
+
+This object contains user preferences.
+
+Each key in the object is the name of a preference. A key's value depends on the policy with which the preference was collected. There are three such policies, "value", "state", and "default value". For preferences collected under the "value" policy, the value will be the preference's value. For preferences collected under the "state" policy, the value will be an opaque marker signifying only that the preference has a user value. The "state" policy is therefore used when user privacy is a concern. For preferences collected under the "default value" policy, the value will be the preference's default value, if the preference exists. If the preference does not exist, there is no key or value.
+
+The following is a partial list of `collected preferences <https://searchfox.org/mozilla-central/search?q=const+DEFAULT_ENVIRONMENT_PREFS&path=>`_.
+
+- ``browser.fixup.alternate.enabled``: Whether the browser should try to modify unknown hosts by adding a prefix (e.g. www) and a suffix (.com). Defaults to false.
+
+- ``browser.migrate.interactions.bookmarks``: True if the user has imported bookmarks from another browser before. This preference gets transferred during profile resets.
+
+- ``browser.migrate.interactions.history``: True if the user has imported history from another browser before. This preference gets transferred during profile resets.
+
+- ``browser.migrate.interactions.passwords``: True if the user has imported passwords from another browser before. This preference gets transferred during profile resets.
+
+- ``browser.search.suggest.enabled``: The "master switch" for search suggestions everywhere in Firefox (search bar, urlbar, etc.). Defaults to true.
+
+- ``browser.urlbar.autoFill``: The global preference for whether autofill in the urlbar is enabled. When false, all types of autofill are disabled.
+
+- ``browser.urlbar.autoFill.adaptiveHistory.enabled``: True if adaptive history autofill in the urlbar is enabled.
+
+- ``browser.urlbar.dnsResolveSingleWordsAfterSearch``: Controls when to DNS resolve single word search strings, after they were searched for. If the string is resolved as a valid host, show a "Did you mean to go to 'host'" prompt. 0: Never resolve, 1: Use heuristics, 2. Always resolve. Defaults to 0.
+
+- ``browser.urlbar.quicksuggest.onboardingDialogChoice``: The user's choice in the Firefox Suggest onboarding dialog. If the dialog was shown multiple times, this records the user's most recent choice. Values are the following. Empty string: The user has not made a choice (e.g., because the dialog hasn't been shown). ``accept_2`` is recorded when the user accepts the dialog and opts in, ``reject_2`` is recorded when the user rejects the dialog and opts out, ``learn_more_1`` is recorded when the user clicks "Learn more" on the introduction section (the user remains opted out), ``learn_more_2`` is recorded when the user clicks "Learn more" on the main section (the user remains opted out), ``close_1`` is recorded when the user clicks close button on the introduction section (the user remains opted out), ``not_now_2`` is recorded when the user clicks "Not now" link on main section (the user remains opted out), ``dismiss_1`` recorded when the user dismisses the dialog on the introduction section (the user remains opted out), ``dismiss_2`` recorded when the user dismisses the dialog on main (the user remains opted out).
+
+- ``browser.urlbar.quicksuggest.dataCollection.enabled``: Whether the user has opted in to data collection for Firefox Suggest. This pref is set to true when the user opts in to the Firefox Suggest onboarding dialog modal. The user can also toggle the pref using a toggle switch in the Firefox Suggest preferences UI.
+
+- ``browser.urlbar.showSearchTerms.enabled``: True if to show the search term in the urlbar while on a default search engine results page.
+
+- ``browser.urlbar.suggest.bestmatch``: True if to show best match result is enabled in the urlbar.
+
+- ``browser.urlbar.suggest.quicksuggest.nonsponsored``: True if non-sponsored Firefox Suggest suggestions are enabled in the urlbar.
+
+- ``browser.urlbar.suggest.quicksuggest.sponsored``: True if sponsored Firefox Suggest suggestions are enabled in the urlbar.
+
+- ``browser.urlbar.suggest.searches``: True if search suggestions are enabled in the urlbar. Defaults to false.
+
+- ``browser.zoom.full`` (deprecated): True if zoom is enabled for both text and images, that is if "Zoom Text Only" is not enabled. Defaults to true. This preference was collected in Firefox 50 to 52 (`Bug 979323 <https://bugzilla.mozilla.org/show_bug.cgi?id=979323>`_).
+
+- ``security.tls.version.enable-deprecated``: True if deprecated versions of TLS (1.0 and 1.1) have been enabled by the user. Defaults to false.
+
+- ``privacy.firstparty.isolate``: True if the user has changed the (unsupported, hidden) First Party Isolation preference. Defaults to false.
+
+- ``privacy.resistFingerprinting``: True if the user has changed the (unsupported, hidden) Resist Fingerprinting preference. Defaults to false.
+
+- ``toolkit.telemetry.pioneerId``: The state of the Pioneer ID. If set, then user is enrolled in Pioneer. Note that this does *not* collect the value.
+
+- ``app.normandy.test-prefs.bool``: Test pref that will help troubleshoot uneven unenrollment in experiments. Defaults to false.
+
+- ``app.normandy.test-prefs.integer``: Test pref that will help troubleshoot uneven unenrollment in experiments. Defaults to 0.
+
+- ``app.normandy.test-prefs.string``: Test pref that will help troubleshoot uneven unenrollment in experiments. Defaults to "".
+
+- ``network.trr.mode``: User-set DNS over HTTPS mode. Defaults to 0.
+
+- ``network.trr.strict_native_fallback``: Whether strict fallback mode is enabled for DoH mode 2. Defaults to true on Nightly, false elsewhere.
+
+- ``extensions.InstallTriggerImpl.enabled``: Whether the InstallTrigger implementation should be enabled (or hidden and none of its methods available).
+
+- ``extensions.InstallTrigger.enabled``: Whether the InstallTrigger implementation should be enabled (or completely hidden), separate from InstallTriggerImpl because InstallTrigger is improperly used also for UA detection.
+
+- ``extensions.eventPages.enabled``: Whether non-persistent background pages (also known as Event pages) should be enabled for `"manifest_version": 2` extensions.
+
+- ``extensions.quarantinedDomains.enabled``: Whether "Quarantined Domains" is enabled.
+
+- ``extensions.manifestV3.enabled``: Whether `"manifest_version": 3` extensions should be allowed to install successfully.
+
+- ``media.gmp-gmpopenh264.enabled``: Whether OpenH264 is enabled.
+
+- ``media.gmp-gmpopenh264.lastDownload``: When OpenH264 was last downloaded as seconds since Jan 1, 1970.
+
+- ``media.gmp-gmpopenh264.lastDownloadFailed``: When OpenH264 was last downloaded unsuccessfully as seconds since Jan 1, 1970.
+
+- ``media.gmp-gmpopenh264.lastDownloadFailReason``: The exception value when OpenH264 was last failed to downloaded.
+
+- ``media.gmp-gmpopenh264.lastInstallFailed``: When OpenH264 installation last failed as seconds since Jan 1, 1970.
+
+- ``media.gmp-gmpopenh264.lastInstallStart``: When OpenH264 installation was last started as seconds since Jan 1, 1970.
+
+- ``media.gmp-gmpopenh264.lastUpdate``: When OpenH264 was last updated as seconds since Jan 1, 1970.
+
+- ``media.gmp-gmpopenh264.visible``: Whether OpenH264 is visible.
+
+- ``media.gmp-manager.lastCheck``: When the gmp-manager last checked for updates as seconds since Jan 1, 1970.
+
+- ``media.gmp-manager.lastEmptyCheck``: When the gmp-manager last checked for updates and there was nothing to install as seconds since Jan 1, 1970.
+
+- ``nimbus.qa.pref-1``: Used to monitor the results of pref-setting test experiments.
+
+- ``nimbus.qa.pref-2``: Used to monitor the results of pref-setting test experiments.
+
+- ``signon.firefoxRelay.feature``: User choice regarding Firefox Relay integration with Firefox Password Manager. Can be one of undefined, "available", "offered", "enabled" or "disabled".
+
+attribution
+~~~~~~~~~~~
+
+This object contains the attribution data for the product installation.
+
+Attribution data is used to link installations of Firefox with the source that the user arrived at the Firefox download page from. It would indicate, for instance, when a user executed a web search for Firefox and arrived at the download page from there, directly navigated to the site, clicked on a link from a particular social media campaign, etc.
+
+The attribution data is included in some versions of the default Firefox installer for Windows (the "stub" installer) and stored as part of the installation. All platforms other than Windows and also Windows installations that did not use the stub installer do not have this data and will not include the ``attribution`` object.
+
+sandbox
+~~~~~~~
+
+This object contains data about the state of Firefox's sandbox.
+
+Specific keys are:
+
+- ``effectiveContentProcessLevel``: The meanings of the values are OS dependent. Details of the meanings can be found in the `Firefox prefs file <https://hg.mozilla.org/mozilla-central/file/tip/browser/app/profile/firefox.js>`_. The value here is the effective value, not the raw value, some platforms enforce a minimum sandbox level. If there is an error calculating this, it will be ``null``.
+- ``contentWin32kLockdownState``: The status of Win32k Lockdown for Content process.
+
+ - LockdownEnabled = 1 - After Firefox 98, this value will no longer appear in Telemetry.
+ - MissingWebRender = 2
+ - OperatingSystemNotSupported = 3
+ - PrefNotSet = 4 - After Firefox 98, this value will no longer appear in Telemetry.
+ - MissingRemoteWebGL = 5
+ - MissingNonNativeTheming = 6
+ - DisabledByEnvVar = 7 - MOZ_ENABLE_WIN32K is set
+ - DisabledBySafeMode = 8
+ - DisabledByE10S = 9 - E10S is disabled for whatever reason
+ - DisabledByUserPref = 10 - The user manually set security.sandbox.content.win32k-disable to false
+ - EnabledByUserPref = 11 - The user manually set security.sandbox.content.win32k-disable to true
+ - DisabledByControlGroup = 12 - The user is in the Control Group, so it is disabled
+ - EnabledByTreatmentGroup = 13 - The user is in the Treatment Group, so it is enabled
+ - DisabledByDefault = 14 - The default value of the pref is false
+ - EnabledByDefault = 15 - The default value of the pref is true
+ - DecodersArentRemote = 16 - Some decoder is not remoted to RDD Process (checks PDMFactory::AllDecodersAreRemote)
+ - IncompatibleMitigationPolicy = 17 - Some incompatible Windows Exploit Mitigation policies are enabled
+
+
+profile
+-------
+
+creationDate
+~~~~~~~~~~~~
+
+The assumed creation date of this client's profile.
+It's read from a file-stored timestamp from the client's profile directory.
+
+.. note::
+
+ If the timestamp file does not exist all files in the profile directory are scanned.
+ The oldest creation or modification date of the scanned files is then taken to be the profile creation date.
+ This has been shown to sometimes be inaccurate (`bug 1449739 <https://bugzilla.mozilla.org/show_bug.cgi?id=1449739>`_).
+
+resetDate
+~~~~~~~~~~~~
+
+The time of the last reset time for the profile. If the profile has never been
+reset this field will not be present.
+It's read from a file-stored timestamp from the client's profile directory.
+
+firstUseDate
+~~~~~~~~~~~~
+
+The time of the first use of profile. If this is an old profile where we can't
+determine this this field will not be present.
+It's read from a file-stored timestamp from the client's profile directory.
+
+partner
+-------
+
+If the user is using a partner repack, this contains information identifying the repack being used, otherwise "partnerNames" will be an empty array and other entries will be null. The information may be missing when the profile just becomes available. In Firefox for desktop, the information along with other customizations defined in distribution.ini are processed later in the startup phase, and will be fully applied when "distribution-customization-complete" notification is sent.
+
+Distributions are most reliably identified by the ``distributionId`` field. Partner information can be found in the `partner repacks <https://github.com/mozilla-partners>`_ (`the old one <https://hg.mozilla.org/build/partner-repacks/>`_ is deprecated): it contains one private repository per partner.
+Important values for ``distributionId`` include:
+
+- "MozillaOnline" for the Mozilla China repack.
+- "canonical", for the `Ubuntu Firefox repack <http://bazaar.launchpad.net/~mozillateam/firefox/firefox.trusty/view/head:/debian/distribution.ini>`_.
+- "yandex", for the Firefox Build by Yandex.
+
+system
+------
+
+os
+~~
+
+This object contains operating system information.
+
+- ``name``: the name of the OS.
+- ``version``: a string representing the OS version.
+- ``kernelVersion``: an Android only string representing the kernel version.
+- ``servicePackMajor``: the Windows only major version number for the installed service pack.
+- ``servicePackMinor``: the Windows only minor version number for the installed service pack.
+- ``windowsBuildNumber``: the Windows build number.
+- ``windowsUBR``: the Windows UBR number, only available for Windows >= 10. This value is incremented by Windows cumulative updates patches.
+- ``installYear``: the Windows only integer representing the year the OS was installed.
+- ``locale``: the string representing the OS locale.
+- ``hasPrefetch``: the Windows-only boolean representing whether or not the OS-based prefetch application start-up optimization is set to use the default settings.
+- ``hasSuperfetch``: the Windows-only boolean representing whether or not the OS-based superfetch application start-up optimization service is running and using the default settings.
+
+addons
+------
+
+activeAddons
+~~~~~~~~~~~~
+
+Starting from Firefox 44, the length of the following string fields: ``name``, ``description`` and ``version`` is limited to 100 characters. The same limitation applies to the same fields in ``theme``.
+
+Some of the fields in the record for each add-on are not available during startup. The fields that will always be present are ``id``, ``version``, ``type``, ``updateDate``, ``scope``, ``isSystem``, ``isWebExtension``, and ``multiprocessCompatible``. All the other fields documented above become present shortly after the ``sessionstore-windows-restored`` observer topic is notified.
+
+activeGMPPlugins
+~~~~~~~~~~~~~~~~
+
+Up-to-date information is not available immediately during startup. The field will be populated with dummy information until the blocklist is loaded. At the latest, this will happen just after the ``sessionstore-windows-restored`` observer topic is notified.
+
+experiments
+-----------
+For each experiment we collect the
+
+- ``id`` (Like ``hotfix-reset-xpi-verification-timestamp-1548973``, max length 100 characters)
+- ``branch`` (Like ``control``, max length 100 characters)
+- ``type`` (Optional. Like ``normandy-exp``, max length 20 characters)
+- ``enrollmentId`` (Optional. Like ``5bae2134-e121-46c2-aa00-232f3f5855c5``, max length 40 characters)
+
+In the event any of these fields are truncated, a warning is printed to the console
+
+Note that this list includes other types of deliveries, including Normandy rollouts and Nimbus feature defaults.
+
+Version History
+---------------
+
+- Firefox 88:
+
+ - Removed ``addons.activePlugins`` as part of removing NPAPI plugin support. (`bug 1682030 <https://bugzilla.mozilla.org/show_bug.cgi?id=1682030>`_)
+
+- Firefox 70:
+
+ - Added ``experiments.<experiment id>.enrollmentId``. (`bug 1555172 <https://bugzilla.mozilla.org/show_bug.cgi?id=1555172>`_)
+
+- Firefox 67:
+
+ - Removed ``persona``. The ``addons.activeAddons`` list should be used instead. (`bug 1525511 <https://bugzilla.mozilla.org/show_bug.cgi?id=1525511>`_)
+
+- Firefox 61:
+
+ - Removed empty ``addons.activeExperiment`` (`bug 1452935 <https://bugzilla.mozilla.org/show_bug.cgi?id=1452935>`_).
diff --git a/toolkit/components/telemetry/docs/data/event-ping.rst b/toolkit/components/telemetry/docs/data/event-ping.rst
new file mode 100644
index 0000000000..05fdd60a0f
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/event-ping.rst
@@ -0,0 +1,92 @@
+
+"event" ping
+=============
+
+This ping transmits :ref:`Telemetry Event <eventtelemetry>` records.
+
+The client id is submitted with this ping.
+The :doc:`Telemetry Environment <../data/environment>` is submitted in this ping.
+
+.. code-block:: js
+
+ {
+ "type": "event",
+ ... common ping data
+ "clientId": <UUID>,
+ "environment": { ... },
+ "payload": {
+ "reason": {periodic, max, shutdown}, // Why the ping was submitted
+ "processStartTimestamp": <UNIX Timestamp>, // Minute precision, for calculating absolute time across pings
+ "sessionId": <UUID>, // For linking to "main" pings
+ "subsessionId": <UUID>, // For linking to "main" pings
+ "lostEventsCount": <number>, // How many events we had to drop. Valid only for reasons "max" and "shutdown"
+ "events": {
+ "parent": [ // process name, one of the keys from Processes.yaml
+ [timestamp, category, method, object, value, extra],
+ ... // At most 1000
+ ]
+ }
+ }
+ }
+
+Send behavior
+-------------
+
+The ping is submitted at most once per ten minute interval, and at least once per hour in
+which an event was recorded. Upon reaching 1000 events, the ping is sent immediately
+unless it would be within ten minutes of the previous ping, in which case some event
+records may be lost. A count of these lost records is included in the ping.
+to avoid losing collected data.
+
+On shutdown, during profile-before-change, a final ping is sent with any remaining event
+records, regardless of frequency but obeying the event record limit.
+
+The 1000-record limit and one-hour and ten-minute frequencies are controlled by
+:doc:`preferences <../internals/preferences>`.
+
+Field details
+-------------
+
+reason
+~~~~~~
+The ``reason`` field contains the information about why the "event" ping was submitted:
+
+* ``periodic``: The event ping was submitted because at least one event happened in the past hour.
+* ``max``: The event ping was submitted because the 1000-record limit was reached.
+* ``shutdown``: The event ping was submitted because Firefox is shutting down and some events
+ have yet to be submitted.
+
+processStartTimestamp
+~~~~~~~~~~~~~~~~~~~~~
+The minute the user's Firefox main process was created. Event record timestamps are recorded
+relative to Firefox's main process start. This provides the basis for reconstructing a user's full
+session of events in order, as well as offering a mechanism for grouping event pings.
+
+sessionId
+~~~~~~~~~
+The id of the session that was current when the ping was sent.
+
+subsessionId
+~~~~~~~~~~~~
+The id of the subsession that was current when the ping was sent.
+
+.. note::
+
+ This may not be the same subsession that the events occurred in if a
+ :ref:`session split <sessionsplit>` happened in between.
+
+lostEventsCount
+~~~~~~~~~~~~~~~
+The number of events we had to discard because we reached the 1000-per-ping limit before
+we were able to send the ping. Should only have a non-zero value on "event" pings with
+reason set to "max" or "shutdown". Which events are missing should be calculable via the
+client's "main" pings using :ref:`Event Summary <events.event-summary>`.
+
+events
+~~~~~~
+A map from process names to arrays of event records that have been :ref:`serialized <events.serializationformat>`.
+
+Version History
+---------------
+
+- Firefox 62: Started sending the "event" ping (`bug 1460595 <https://bugzilla.mozilla.org/show_bug.cgi?id=1460595>`_).
diff --git a/toolkit/components/telemetry/docs/data/first-shutdown-ping.rst b/toolkit/components/telemetry/docs/data/first-shutdown-ping.rst
new file mode 100644
index 0000000000..fe20c5df45
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/first-shutdown-ping.rst
@@ -0,0 +1,11 @@
+
+"first-shutdown" ping
+=====================
+
+This ping is a duplicate of the main-ping sent on first shutdown. Enabling pingsender
+for first sessions will impact existing engagement metrics. The ``first-shutdown`` ping enables a
+more accurate view of users that churn after the first session. This ping exists as a
+stopgap until existing metrics are re-evaluated, allowing us to use the first session
+``main-pings`` directly.
+
+See :doc:`main-ping` for details about this payload.
diff --git a/toolkit/components/telemetry/docs/data/health-ping.rst b/toolkit/components/telemetry/docs/data/health-ping.rst
new file mode 100644
index 0000000000..e5655924e1
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/health-ping.rst
@@ -0,0 +1,92 @@
+
+"health" ping
+=============
+
+This ping is intended to provide data about problems arise when submitting other pings.
+The ping is submitted at most once per hour. On shutdown an additional ping is submitted
+to avoid losing collected data.
+
+This ping is intended to be really small.
+The client id is submitted with this ping.
+
+.. code-block:: js
+
+ {
+ "type": "health", // type
+ ... common ping data
+ "clientId": <UUID>, // client id, e.g.
+ // "c641eacf-c30c-4171-b403-f077724e848a"
+ "payload": {
+ "os": {
+ "name": <string>, // OS name
+ "version": <string> // OS version
+ },
+ "reason": <string>, // When ping was triggered, e.g. "immediate" or "shutdown".
+ "pingDiscardedForSize": {
+ "main": <number>, // Amount of occurrences for a specific ping type.
+ "core": <number>
+ ...
+ },
+ "sendFailure": {
+ "timeout": <number>, // Amount of occurrences for a specific failure.
+ "abort": <number>
+ ...
+ }
+ }
+ }
+
+Send behavior
+-------------
+
+``HealthPing.jsm`` tracks several problems:
+
+* The size of other assembled pings exceeds the ping limit.
+* Failures while sending other pings.
+
+After recording the data, a health ping will be sent:
+
+* immediately, with the reason ``immediate`` , if it is first ping in the session or it passed at least one hour from the previous submission.
+* after 1 hour minus the time passed from previous submission, with the reason ``delayed`` , if less than an hour passed from the previous submission.
+* on shutdown, with the reason ``shutdown`` using :doc:`../internals/pingsender`, if recorded data is not empty.
+
+Field details
+-------------
+
+reason
+~~~~~~
+The ``reason`` field contains the information about why the "health" ping was submitted. It presently supports three reasons:
+
+* immediate: The health ping was submitted immediately after recording a failure.
+* delayed: The health ping was submitted after a delay.
+* shutdown: The health ping was submitted on shutdown.
+
+pingDiscardedForSize
+~~~~~~~~~~~~~~~~~~~~
+The ``pingDiscardedForSize`` field contains the information about the top ten pings whose size exceeded the
+ping size limit (1 MB). This field lists the number of discarded pings per ping type.
+
+The ping type "<unknown>" is used to indicate that a pending pings size exceeded the limit. This is because we don't have the pending pings type available cheaply at the moment.
+
+This field is optional.
+
+sendFailure
+~~~~~~~~~~~
+The ``sendFailure`` field contains the information about pings, which had failures on sending.
+This field lists the number of failed pings per ping send failure type.
+
+The recorded failure types are:
+
+* "eOK" - No error.
+* "eRequest" - There was some error in the request before we started to service it.
+* "eUnreachable" - The remote server was unreachable.
+* "eChannelOpen" - The connection failed when we tried to open the channel.
+* "eRedirect" - The connection failed when being redirected.
+* "abort" - What XMLHttpRequest means by "abort" (see `MDN <https://developer.mozilla.org/en-US/docs/Web/Events/abort>`__)
+* "timeout" - What XMLHttpRequest means by "timeout" (see `MDN <https://developer.mozilla.org/en-US/docs/Web/Events/timeout>`__)
+
+This field is optional.
+
+.. note::
+
+ Although both ``pingDiscardedForSize`` and ``sendFailure`` fields are optional, the health ping will only
+ be submitted if one of this field not empty.
diff --git a/toolkit/components/telemetry/docs/data/heartbeat-ping.rst b/toolkit/components/telemetry/docs/data/heartbeat-ping.rst
new file mode 100644
index 0000000000..f1920111fd
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/heartbeat-ping.rst
@@ -0,0 +1,62 @@
+
+"heartbeat" ping
+=================
+
+This ping is submitted after a Firefox Heartbeat survey. Even if the user exits
+the browser, closes the survey window, or ignores the survey, Heartbeat will
+provide a ping to Telemetry for sending during the same session.
+
+The payload contains the user's survey response (if any) as well as timestamps
+of various Heartbeat events (survey shown, survey closed, link clicked, etc).
+
+The ping will also report the "surveyId", "surveyVersion" and "testing"
+Heartbeat survey parameters (if they are present in the survey config).
+These "meta fields" will be repeated verbatim in the payload section.
+
+The environment block and client ID are submitted with this ping.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ type: "heartbeat",
+ version: 4,
+ clientId: <UUID>,
+ environment: { /* ... */ }
+ // ... common ping data
+ payload: {
+ version: 1,
+ flowId: <string>,
+ ... timestamps below ...
+ offeredTS: <integer epoch timestamp>,
+ learnMoreTS: <integer epoch timestamp>,
+ votedTS: <integer epoch timestamp>,
+ engagedTS: <integer epoch timestamp>,
+ closedTS: <integer epoch timestamp>,
+ expiredTS: <integer epoch timestamp>,
+ windowClosedTS: <integer epoch timestamp>,
+ // ... user's rating below
+ score: <integer>,
+ // ... survey meta fields below
+ surveyId: <string>,
+ surveyVersion: <integer>,
+ testing: <boolean>
+ }
+ }
+
+Notes:
+
+* Pings will **NOT** have all possible timestamps, timestamps are only reported for events that actually occurred.
+* Timestamp meanings:
+ * offeredTS: when the survey was shown to the user
+ * learnMoreTS: when the user clicked on the "Learn More" link
+ * votedTS: when the user voted
+ * engagedTS: when the user clicked on the survey-provided button (alternative to voting feature)
+ * closedTS: when the Heartbeat notification bar was closed
+ * expiredTS: indicates that the survey expired after 2 hours of no interaction (threshold regulated by "browser.uitour.surveyDuration" pref)
+ * windowClosedTS: the user closed the entire Firefox window containing the survey, thus ending the survey. This timestamp will also be reported when the survey is ended by the browser being shut down.
+* The surveyId/surveyVersion fields identify a specific survey (like a "1040EZ" tax paper form). The flowID is a UUID that uniquely identifies a single user's interaction with the survey. Think of it as a session token.
+* The self-support page cannot include additional data in this payload. Only the the 4 flowId/surveyId/surveyVersion/testing fields are under the self-support page's control.
+
+See also: :doc:`common ping fields <common-ping>`
diff --git a/toolkit/components/telemetry/docs/data/index.rst b/toolkit/components/telemetry/docs/data/index.rst
new file mode 100644
index 0000000000..c03027d431
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/index.rst
@@ -0,0 +1,19 @@
+==================
+Data documentation
+==================
+
+.. toctree::
+ :maxdepth: 2
+ :titlesonly:
+ :glob:
+
+ common-ping
+ environment
+ main-ping
+ crash-ping
+ backgroundhangmonitor-ping
+ anonymous-ping
+ first-shutdown-ping
+ *-ping
+
+The `mozilla-pipeline-schemas repository <https://github.com/mozilla-services/mozilla-pipeline-schemas/>`_ contains schemas for some of the pings.
diff --git a/toolkit/components/telemetry/docs/data/install-ping.rst b/toolkit/components/telemetry/docs/data/install-ping.rst
new file mode 100644
index 0000000000..32bde280b5
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/install-ping.rst
@@ -0,0 +1,234 @@
+============
+Install Ping
+============
+
+The install pings contain some data about the system and the installation process, sent whenever the installer exits [#earlyexit]_.
+
+---------
+Stub Ping
+---------
+
+The :doc:`Stub Installer </browser/installer/windows/installer/StubInstaller>` sends a ping just before it exits, in function SendPing of `stub.nsi <https://searchfox.org/mozilla-central/source/browser/installer/windows/nsis/stub.nsi>`_. This is sent as an HTTP GET request to DSMO (download-stats.mozilla.org).
+
+Ingestion is handled in `gcp-ingestion <https://mozilla.github.io/gcp-ingestion/>`_ at class StubUri within `ParseUri <https://github.com/mozilla/gcp-ingestion/blob/master/ingestion-beam/src/main/java/com/mozilla/telemetry/decoder/ParseUri.java>`_. Several of the fields are codes which are broken out into multiple boolean columns in the database table.
+
+-----------------
+Full Install Ping
+-----------------
+
+The :doc:`Full Installer </browser/installer/windows/installer/FullInstaller>` sends a ping just before it exits, in function SendPing of `installer.nsi <https://searchfox.org/mozilla-central/source/browser/installer/windows/nsis/installer.nsi>`_. This is an HTTP POST request with a JSON document, sent to the standard Telemetry endpoint (incoming.telemetry.mozilla.org).
+
+To avoid double counting, the full installer does not send a ping when it is launched from the stub installer, so pings where ``installer_type = "full"`` correspond to installs that did not use the stub.
+
+--------------------------
+Querying the install pings
+--------------------------
+
+The pings are recorded in the ``firefox_installer.install`` table, accessible in `Redash <https://sql.telemetry.mozilla.org>`_ [#redashlogin]_ using the default "Telemetry (BigQuery)" data source.
+
+Some of the columns are marked [DEPRECATED] because they involve features that were removed, mostly when the stub installer was `streamlined <https://bugzilla.mozilla.org/show_bug.cgi?id=1328445>`_ in Firefox 55. These columns were not removed to keep compatibility and so we could continue to use the old data, but they should no longer be used.
+
+The columns are annotated with "(stub)", "(full)", or "(both)" to indicate which types of installer provide meaningful values.
+
+See also the `JSON schema <https://github.com/mozilla-services/mozilla-pipeline-schemas/blob/master/templates/firefox-installer/install/install.1.schema.json>`_.
+
+submission_timestamp (both)
+ Time the ping was received
+
+installer_type (both)
+ Which type of installer generated this ping (full or stub)
+
+installer_version (full)
+ Version of the installer itself [#stubversion]_
+
+build_channel (both)
+ Channel the installer was built with the branding for ("release", "beta", "nightly", or "default")
+
+update_channel (both)
+ Value of MOZ_UPDATE_CHANNEL for the installer build; should generally be the same as build_channel
+
+version, build_id (both)
+ Version number and Build ID of the installed product, from ``application.ini``. This is **not** the version of the installer itself.
+
+ stub: 0 if the installation failed
+
+ full: ``""`` if not found [#versionfailure]_
+
+locale (both)
+ Locale of the installer and of the installed product, in AB_CD format
+
+from_msi (full)
+ True if the install was launched from an MSI wrapper.
+
+_64bit_build (both)
+ True if a 64-bit build was selected for installation.
+
+ stub: This means the OS is 64-bit, the RAM requirement was met, and no third-party software that blocks 64-bit installations was found
+
+ full: Hardcoded based on the architecture to be installed
+
+_64bit_os (both)
+ True if the version of Windows on the machine was 64-bit.
+
+os_version (both)
+ Version number of Windows in ``major.minor.build`` format [#win10build]_
+
+service_pack (stub)
+ Latest Windows service pack installed on the machine.
+
+server_os (both)
+ True if the installed OS is a server version of Windows.
+
+admin_user (both)
+ True if the installer was run by a user with administrator privileges (and the UAC prompt was accepted). Specifically, this reports whether :abbr:`HKLM (HKEY_LOCAL_MACHINE)` was writeable.
+
+default_path (both)
+ True if the default installation path was not changed.
+
+ stub: [DEPRECATED] [#stubdefaultpath]_
+
+set_default (both)
+ True if the option to set the new installation as the default browser was left selected.
+
+ stub: [DEPRECATED] [#stubsetdefault]_
+
+new_default (both)
+ True if the new installation is now the default browser (registered to handle the http protocol).
+
+ full: Checks the association using ``AppAssocReg::QueryCurrentDefault`` and :abbr:`HKCU (HKEY_CURRENT_USER)`.
+
+ stub: [DEPRECATED] [#stubnewdefault]_
+
+old_default (both)
+ True if firefox.exe in a different directory is now the default browser, mutually exclusive with new_default. The details are the same as new_default.
+
+had_old_install (both)
+ True if at least one existing installation of Firefox was found on the system prior to this installation.
+
+ full: Checks for the installation directory given in the ``Software\Mozilla\${BrandFullName}`` registry keys, either :abbr:`HKLM` or :abbr:`HKCU`
+
+ stub: Checks for the top level profile directory ``%LOCALAPPDATA%\Mozilla\Firefox``
+
+old_version, old_build_id (stub)
+ Version number and Build ID (from ``application.ini``) of a previous installation of Firefox in the install directory, 0 if not found
+
+bytes_downloaded (stub)
+ Size of the full installer data that was transferred before the download ended (whether it failed, was cancelled, or completed normally)
+
+download_size (stub)
+ Expected size of the full installer download according to the HTTP response headers
+
+download_retries (stub)
+ Number of times the full installer download was retried or resumed. 10 retries is the maximum.
+
+download_time (stub)
+ Number of seconds spent downloading the full installer [#downloadphase]_
+
+download_latency (stub)
+ Seconds between sending the full installer download request and receiving the first response data
+
+download_ip (stub)
+ IP address of the server the full installer was download from (can be either IPv4 or IPv6)
+
+manual_download (stub)
+ True if the user clicked on the button that opens the manual download page. The prompt to do that is shown after the installation fails or is cancelled.
+
+intro_time (both)
+ Seconds the user spent on the intro screen.
+
+ stub: [DEPRECATED] The streamlined stub no longer has this screen, so this should always be 0.
+
+options_time (both)
+ Seconds the user spent on the options screen.
+
+ stub: [DEPRECATED] The streamlined stub no longer has this screen, so this should always be 0.
+
+preinstall_time (stub)
+ Seconds spent verifying the downloaded full installer and preparing to run it
+
+install_time (both)
+ full: Seconds taken by the installation phase.
+
+ stub: Seconds taken by the full installer.
+
+finish_time (both)
+ full: Seconds the user spent on the finish page.
+
+ stub: Seconds spent waiting for the installed application to launch.
+
+succeeded (both)
+ True if a new installation was successfully created. False if that didn't happen for any reason, including when the user closed the installer window.
+
+disk_space_error (stub)
+ [DEPRECATED] True if the installation failed because the drive we're trying to install to does not have enough space. The streamlined stub no longer sends a ping in this case, because the installation drive can no longer be selected.
+
+no_write_access (stub)
+ [DEPRECATED] True if the installation failed because the user doesn't have permission to write to the path we're trying to install to. The streamlined stub no longer sends a ping in this case, because the installation directory can no longer be selected.
+
+user_cancelled (both)
+ True if the installation failed because the user cancelled it or closed the window.
+
+out_of_retries (stub)
+ True if the installation failed because the download had to be retried too many times (currently 10)
+
+file_error (stub)
+ True if the installation failed because the downloaded file couldn't be read from
+
+sig_not_trusted (stub)
+ True if the installation failed because the signature on the downloaded file wasn't valid or wasn't signed by a trusted authority
+
+sig_unexpected (stub)
+ True if the installation failed because the signature on the downloaded file didn't have the expected subject and issuer names
+
+install_timeout (stub)
+ True if the installation failed because running the full installer timed out. Currently that means it ran for more than 150 seconds for a new installation, or 165 seconds for a paveover installation.
+
+new_launched (both)
+ True if the installation succeeded and tried to launch the newly installed application.
+
+old_running (stub)
+ [DEPRECATED] True if the installation succeeded and we weren't able to launch the newly installed application because a copy of Firefox was already running. This should always be false since the check for a running copy was `removed <https://bugzilla.mozilla.org/show_bug.cgi?id=1601806>`_ in Firefox 74.
+
+attribution (both)
+ Any attribution data that was included with the installer
+
+profile_cleanup_prompt (stub)
+ 0: neither profile cleanup prompt was shown
+
+ 1: the "reinstall" version of the profile cleanup prompt was shown (no existing installation was found, but the user did have an old Firefox profile)
+
+ 2: the "paveover" version of the profile cleanup prompt was shown (an installation of Firefox was already present, but it's an older version)
+
+profile_cleanup_requested (stub)
+ True if either profile cleanup prompt was shown and the user accepted the prompt
+
+funnelcake (stub)
+ `Funnelcake <https://wiki.mozilla.org/Funnelcake>`_ ID
+
+ping_version (stub)
+ Version of the stub ping, currently 8
+
+silent (full)
+ True if the install was silent (see :ref:`Full Installer Configuration`)
+
+---------
+Footnotes
+---------
+
+.. [#earlyexit] No ping is sent if the installer exits early because initial system requirements checks fail.
+
+.. [#redashlogin] A Mozilla LDAP login is required to access Redash.
+
+.. [#stubversion] The version of the installer would be useful for the stub, but it is not currently sent as part of the stub ping.
+
+.. [#versionfailure] If the installation failed or was cancelled, the full installer will still report the version number of whatever was in the installation directory, or ``""`` on if it couldn't be read.
+
+.. [#win10build] Previous versions of Windows have used a very small set of build numbers through their entire lifecycle. However, Windows 10 gets a new build number with every major update (about every 6 months), and many more builds have been released on its insider channels. So, to prevent a huge amount of noise, queries using this field should generally filter out the build number and only use the major and minor version numbers to differentiate Windows versions, unless the build number is specifically needed.
+
+.. [#stubdefaultpath] ``default_path`` should always be true in the stub, since we no longer support changing the path, but see `bug 1351697 <https://bugzilla.mozilla.org/show_bug.cgi?id=1351697>`_.
+
+.. [#stubsetdefault] We no longer attempt to change the default browser setting in the streamlined stub, so set_default should always be false.
+
+.. [#stubnewdefault] We no longer attempt to change the default browser setting in the streamlined stub, so new_default should usually be false, but the stub still checks the association at ``Software\Classes\http\shell\open\command`` in :abbr:`HKLM` or :abbr:`HKCU`.
+
+.. [#downloadphase] ``download_time`` was previously called ``download_phase_time``, this includes retries during the download phase. There was a different ``download_time`` field that specifically measured only the time of the last download, this is still submitted but it is ignored during ingestion.
diff --git a/toolkit/components/telemetry/docs/data/launcher-process-failure-ping.rst b/toolkit/components/telemetry/docs/data/launcher-process-failure-ping.rst
new file mode 100644
index 0000000000..f09e0422af
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/launcher-process-failure-ping.rst
@@ -0,0 +1,96 @@
+
+Launcher Process Failure ping
+=============================
+
+This ping is generated by the Firefox launcher process when it fails to successfully start the browser, or generated by the browser process when it fails to start a sandboxed process.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ type: "launcher-process-failure",
+ "version": 1,
+ "id": <UUID>,
+ "creationDate": <Date string in ISO format>,
+ "update_channel": <string>,
+ "build_id": <string>,
+ "build_version": <string>,
+ // Windows version number in major.minor.build.UBR format (UBR is optional, only available on Win10)
+ "os_version": <string>,
+ // True if this build was running atop a Windows Server OS
+ "server_os": <bool>,
+ // The current user's OS locale setting
+ "os_locale": <string>,
+ // CPU Architecture. One of the values from the Windows SYSTEM_INFO::wProcessorArchitecture field
+ "cpu_arch": <int>,
+ "num_logical_cpus": <int>,
+ // True if the process was launched with Administrator privileges
+ // but without User Account Control (= UAC)
+ "is_admin_without_uac": <bool>,
+ // The type of the process which failed to start as a sandboxed process.
+ // If the launcher process fails to launch the browser process, this property is not set.
+ "process_type": <string>,
+ "memory": {
+ // Free space available in the page file, in bytes
+ "total_phys": <int>,
+ // Available physical memory on the machine, in bytes
+ "avail_phys": <int>,
+ // Free space available in the page file, in bytes
+ "avail_page_file": <int>,
+ // Available virtual memory on the machine, in bytes
+ "avail_virt": <int>
+ },
+ "xpcom_abi": <string>,
+ "launcher_error": {
+ // The leaf name of the source file where the error was raised
+ "source_file": <string>,
+ // The line number of the source file where the error was raised
+ "source_line": <int>,
+ // The HRESULT error code of the error that was raised
+ "hresult": <int>,
+ // First sixteen bytes of a function that we failed to hook (Nightly-only).
+ // This field is added only on detour failures.
+ "detour_orig_bytes": <string>
+ },
+ "security": {
+ // A list of names of installed antivirus products
+ "av": [
+ <string>,
+ ...
+ ],
+ // A list of names of installed antispyware products
+ "antispyware": [
+ <string>,
+ ...
+ ],
+ // A list of names of installed firewall products
+ "firewall": [
+ <string>,
+ ...
+ ]
+ },
+ // A mapping of all modules present in the failing process, including
+ // their version numbers and an optional index into the signatures array
+ "modules": {
+ <moduleName>: [
+ <string>,
+ <int>
+ ],
+ ...
+ },
+ // A list of all signatures that were used to sign the binaries that are
+ // listed in modules.
+ "signatures": [
+ <string>,
+ ...
+ ]
+ }
+
+Version History
+~~~~~~~~~~~~~~~
+
+- Firefox 82: Added ``detour_orig_bytes`` (`bug 1588245 <https://bugzilla.mozilla.org/show_bug.cgi?id=1588245>`_).
+- Firefox 82: Added ``process_type`` (`bug 1630444 <https://bugzilla.mozilla.org/show_bug.cgi?id=1630444>`_).
+- Firefox 71: Added ``is_admin_without_uac`` (`bug 1567605 <https://bugzilla.mozilla.org/show_bug.cgi?id=1567605>`_).
+- Firefox 67: Initial release (`bug 1460433 <https://bugzilla.mozilla.org/show_bug.cgi?id=1460433>`_).
diff --git a/toolkit/components/telemetry/docs/data/main-ping.rst b/toolkit/components/telemetry/docs/data/main-ping.rst
new file mode 100644
index 0000000000..23f7d8c600
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/main-ping.rst
@@ -0,0 +1,504 @@
+
+"main" ping
+===========
+
+.. toctree::
+ :maxdepth: 2
+
+This is the "main" Telemetry ping type, whose payload contains most of the measurements that are used to track the performance and health of Firefox in the wild.
+It includes histograms and other performance and diagnostic data.
+
+This ping may be triggered for one of many reasons documented by the ``reason`` field:
+
+* ``aborted-session`` - this ping is regularly saved to disk (every 5 minutes), overwriting itself, and deleted at shutdown. If a previous aborted session ping is found at startup, it gets sent to the server. The first aborted-session ping is generated as soon as Telemetry starts
+* ``environment-change`` - the :doc:`environment` changed, so the session measurements got reset and a new subsession starts
+* ``shutdown`` - triggered when the browser session ends. For the first browsing session, this ping is saved to disk and sent on the next browser restart. From the second browsing session on, this ping is sent immediately on shutdown using the :doc:`../internals/pingsender`, unless the OS is shutting down
+* ``daily`` - a session split triggered in 24h hour intervals at local midnight. If an ``environment-change`` ping is generated by the time it should be sent, the daily ping is rescheduled for the next midnight
+* ``saved-session`` - the *"classic"* Telemetry payload with measurements covering the whole browser session (only submitted on Android)
+
+.. _sessionsplit:
+
+Most reasons lead to a session split, initiating a new *subsession*. We reset important measurements for those subsessions.
+
+After a new subsession split, the ``internal-telemetry-after-subsession-split`` topic is notified to all the observers. *This is an internal topic and is only meant for internal Telemetry usage.*
+
+.. note::
+
+ ``saved-session`` is sent with a different ping type (``saved-session``, not ``main``), but otherwise has the same format as discussed here. As of Firefox 61 this is sent on Android only.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ version: 4,
+
+ info: {
+ reason: <string>, // what triggered this ping: "saved-session", "environment-change", "shutdown", ...
+ revision: <string>, // the Histograms.json revision
+ timezoneOffset: <integer>, // time-zone offset from UTC, in minutes, for the current locale
+ previousBuildId: <string>, // null if this is the first run, or the previous build ID is unknown
+
+ sessionId: <uuid>, // random session id, shared by subsessions
+ subsessionId: <uuid>, // random subsession id
+ previousSessionId: <uuid>, // session id of the previous session, null on first run.
+ previousSubsessionId: <uuid>, // subsession id of the previous subsession (even if it was in a different session),
+ // null on first run.
+
+ subsessionCounter: <unsigned integer>, // the running no. of this subsession since the start of the browser session
+ profileSubsessionCounter: <unsigned integer>, // the running no. of all subsessions for the whole profile life time
+
+ sessionStartDate: <ISO date>, // hourly precision, ISO date in local time
+ subsessionStartDate: <ISO date>, // hourly precision, ISO date in local time
+ sessionLength: <integer>, // the session length until now in seconds, monotonic
+ subsessionLength: <integer>, // the subsession length in seconds, monotonic
+
+ addons: <string>, // obsolete, use ``environment.addons``
+ },
+
+ processes: {...},
+ simpleMeasurements: {...},
+
+ // The following properties may all be null if we fail to collect them.
+ histograms: {...},
+ keyedHistograms: {...},
+ chromeHangs: {...}, // removed in firefox 62
+ threadHangStats: [...], // obsolete in firefox 57, use the 'bhr' ping
+ log: [...], // obsolete in firefox 61, use Event Telemetry or Scalars
+ gc: {...},
+ fileIOReports: {...},
+ lateWrites: {...},
+ addonDetails: {...},
+ UIMeasurements: [...], // Android only
+ slowSQL: {...},
+ slowSQLstartup: {...},
+ }
+
+info
+----
+
+sessionLength
+~~~~~~~~~~~~~
+The length of the current session so far in seconds.
+This uses a monotonic clock, so this may mismatch with other measurements that
+are not monotonic like calculations based on ``Date.now()``.
+
+Note that this currently does not behave consistently over our supported platforms:
+
+* On Windows this uses ``GetTickCount64()``, which does increase over sleep periods
+* On macOS this uses ``mach_absolute_time()``, which does not increase over sleep periods
+* On POSIX/Linux this uses ``clock_gettime(CLOCK_MONOTONIC, &ts)``, which should not increase over sleep time
+
+See `bug 1204823 <https://bugzilla.mozilla.org/show_bug.cgi?id=1204823>`_ for details.
+
+subsessionLength
+~~~~~~~~~~~~~~~~
+The length of this subsession in seconds.
+This uses a monotonic clock, so this may mismatch with other measurements that are not monotonic (e.g. based on ``Date.now()``).
+
+Also see the remarks for ``sessionLength`` on platform consistency.
+
+processes
+---------
+This section contains per-process data.
+
+Structure:
+
+.. code-block:: js
+
+ "processes" : {
+ // ... other processes ...
+ "parent": {
+ scalars: {...},
+ keyedScalars: {...},
+ // parent process histograms and keyedHistograms are in main payload
+ },
+ "content": {
+ scalars: {...},
+ keyedScalars: {...},
+ histograms: {...},
+ keyedHistograms: {...},
+ },
+ "gpu": {
+ // ...
+ }
+ }
+
+histograms and keyedHistograms
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+This section contains histograms and keyed histograms accumulated on content processes. Histograms recorded on a content child process have different character than parent histograms. For instance, ``GC_MS`` will be much different in ``processes.content`` as it has to contend with web content, whereas the instance in ``payload.histograms`` has only to contend with browser JS. Also, some histograms may be absent if never recorded on a content child process (``EVENTLOOP_UI_ACTIVITY`` is parent-process-only).
+
+This format was adopted in Firefox 51 via bug 1218576.
+
+scalars and keyedScalars
+~~~~~~~~~~~~~~~~~~~~~~~~
+This section contains the :doc:`../collection/scalars` that are valid for the current platform. Scalars are only submitted if data was added to them, and are only reported with subsession pings. The recorded scalars are described in the `Scalars.yaml <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/Scalars.yaml>`_ file. The ``info.revision`` field indicates the revision of the file that describes the reported scalars.
+
+simpleMeasurements
+------------------
+This section contains a list of simple measurements, or counters. In addition to the ones highlighted below, Telemetry timestamps (see `here <https://searchfox.org/mozilla-central/search?q=TelemetryTimestamps.add&redirect=false&case=true>`__ and `here <https://searchfox.org/mozilla-central/search?q=recordTimestamp&redirect=false&case=true>`__) can be reported.
+
+totalTime
+~~~~~~~~~
+A non-monotonic integer representing the number of seconds the session has been alive.
+
+addonManager
+~~~~~~~~~~~~
+Only available in the extended set of measures, it contains a set of counters related to Addons. See `here <https://searchfox.org/mozilla-central/search?q=AddonManagerPrivate.recordSimpleMeasure&redirect=false&case=true>`__ for a list of recorded measures.
+
+UITelemetry
+~~~~~~~~~~~
+As of Firefox 61 this section is no longer present.
+
+Only available in the extended set of measures. For more see :ref:`uitelemetry`.
+
+startupInterrupted
+~~~~~~~~~~~~~~~~~~
+A boolean set to true if startup was interrupted by an interactive prompt.
+
+js
+~~
+This section contains a series of counters from the JavaScript engine.
+
+Structure:
+
+.. code-block:: js
+
+ "js" : {
+ // ...
+ }
+
+As of Firefox 59 this section no longer contains any entries, as of Firefox 61 this section is removed.
+
+maximalNumberOfConcurrentThreads
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+An integer representing the highest number of threads encountered so far during the session.
+
+startupSessionRestoreReadBytes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Windows-only integer representing the number of bytes read by the main process up until the session store has finished restoring the windows.
+
+startupSessionRestoreWriteBytes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Windows-only integer representing the number of bytes written by the main process up until the session store has finished restoring the windows.
+
+startupWindowVisibleReadBytes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Windows-only integer representing the number of bytes read by the main process up until after a XUL window is made visible.
+
+startupWindowVisibleWriteBytes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Windows-only integer representing the number of bytes written by the main process up until after a XUL window is made visible.
+
+debuggerAttached
+~~~~~~~~~~~~~~~~
+A boolean set to true if a debugger is attached to the main process.
+
+shutdownDuration
+~~~~~~~~~~~~~~~~
+The time, in milliseconds, it took to complete the last shutdown.
+
+failedProfileLockCount
+~~~~~~~~~~~~~~~~~~~~~~
+The number of times the system failed to lock the user profile.
+
+activeTicks
+~~~~~~~~~~~
+Integer count of the number of five-second intervals ('ticks') the user was considered 'active' (sending UI events to the window). An extra event is fired immediately when the user becomes active after being inactive. This is for some mouse and gamepad events, and all touch, keyboard, wheel, and pointer events (see `EventStateManager.cpp <https://searchfox.org/mozilla-central/source/dom/events/EventStateManager.cpp#504>`__).
+This measure might be useful to give a trend of how much a user actually interacts with the browser when compared to overall session duration. It does not take into account whether or not the window has focus or is in the foreground. Just if it is receiving these interaction events.
+Note that in ``main`` pings, this measure is reset on subsession splits, while in ``saved-session`` pings it covers the whole browser session.
+
+histograms
+----------
+This section contains the histograms that are valid for the current platform. ``Flag`` histograms are always created and submitted with a default value of ``false`` if a value of ``true`` is not recorded during the time period. Other histogram types (see :ref:`choosing-histogram-type`) are not created nor submitted if no data was added to them. The type and format of the reported histograms is described by the ``Histograms.json`` file. Its most recent version is available `here <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/Histograms.json>`__. The ``info.revision`` field indicates the revision of the file that describes the reported histograms.
+
+keyedHistograms
+---------------
+This section contains the keyed histograms available for the current platform.
+
+As of Firefox 48, this section does not contain empty keyed histograms anymore.
+
+threadHangStats
+---------------
+As of Firefox 57 this section is no longer present, and has been replaced with the :doc:`bhr ping <backgroundhangmonitor-ping>`.
+
+Contains the statistics about the hangs in main and background threads. Note that hangs in this section capture the `label stack <https://developer.mozilla.org/en-US/docs/Mozilla/Performance/Profiling_with_the_Built-in_Profiler#Native_stack_vs._label_stack>`_ and an incomplete JS stack, which is not 100% precise. For particularly egregious hangs, and on nightly, an unsymbolicated native stack is also captured. The amount of time that is considered "egregious" is different from thread to thread, and is set when the BackgroundHangMonitor is constructed for that thread. In general though, hangs from 5 - 10 seconds are generally considered egregious. Shorter hangs (1 - 2s) are considered egregious for other threads (the compositor thread, and the hang monitor that is only enabled during tab switch).
+
+To avoid submitting overly large payloads, some limits are applied:
+
+* Identical, adjacent "(chrome script)" or "(content script)" stack entries are collapsed together. If a stack is reduced, the "(reduced stack)" frame marker is added as the oldest frame.
+* The depth of the reported label stacks is limited to 11 entries. This value represents the 99.9th percentile of the thread hangs stack depths reported by Telemetry.
+* The native stacks are limited to a depth of 25 stack frames.
+
+Structure:
+
+.. code-block:: js
+
+ "threadHangStats" : [
+ {
+ "name" : "Gecko",
+ "activity" : {...}, // a time histogram of all task run times
+ "nativeStacks": { // captured for all hangs on nightly, or egregious hangs on beta
+ "memoryMap": [
+ ["wgdi32.pdb", "08A541B5942242BDB4AEABD8C87E4CFF2"],
+ ["igd10iumd32.pdb", "D36DEBF2E78149B5BE1856B772F1C3991"],
+ // ... other entries in the format ["module name", "breakpad identifier"] ...
+ ],
+ "stacks": [
+ [
+ [
+ 0, // the module index or -1 for invalid module indices
+ 190649 // the offset of this program counter in its module or an absolute pc
+ ],
+ [1, 2540075],
+ // ... other frames ...
+ ],
+ // ... other stacks ...
+ ]
+ },
+ "hangs" : [
+ {
+ "stack" : [
+ "Startup::XRE_Main",
+ "Timer::Fire",
+ "(content script)",
+ "IPDL::PPluginScriptableObject::SendGetChildProperty",
+ ... up to 11 frames ...
+ ],
+ "nativeStack": 0, // index into nativeStacks.stacks array
+ "histogram" : {...}, // the time histogram of the hang times
+ "annotations" : [
+ {
+ "pluginName" : "Shockwave Flash",
+ "pluginVersion" : "18.0.0.209"
+ },
+ ... other annotations ...
+ ]
+ },
+ ],
+ },
+ ... other threads ...
+ ]
+
+.. _chromeHangs:
+
+chromeHangs
+-----------
+As of Firefox 62, chromeHangs has been removed. Please look to the bhr ping for
+similar functionality.
+
+Contains the statistics about the hangs happening exclusively on the main thread of the parent process. Precise C++ stacks are reported. This is only available on Nightly Release on Windows, when building using "--enable-profiling" switch.
+
+Some limits are applied:
+
+* Reported chrome hang stacks are limited in depth to 50 entries.
+* The maximum number of reported stacks is 50.
+
+The module names can contain unicode characters.
+
+Structure:
+
+.. code-block:: js
+
+ "chromeHangs" : {
+ "memoryMap" : [
+ ["wgdi32.pdb", "08A541B5942242BDB4AEABD8C87E4CFF2"],
+ ["igd10iumd32.pdb", "D36DEBF2E78149B5BE1856B772F1C3991"],
+ ... other entries in the format ["module name", "breakpad identifier"] ...
+ ],
+ "stacks" : [
+ [
+ [
+ 0, // the module index or -1 for invalid module indices
+ 190649 // the offset of this program counter in its module or an absolute pc
+ ],
+ [1, 2540075],
+ ... other frames, up to 50 ...
+ ],
+ ... other stacks, up to 50 ...
+ ],
+ "durations" : [8, ...], // the hang durations (in seconds)
+ "systemUptime" : [692, ...], // the system uptime (in minutes) at the time of the hang
+ "firefoxUptime" : [672, ...], // the Firefox uptime (in minutes) at the time of the hang
+ "annotations" : [
+ [
+ [0, ...], // the indices of the related hangs
+ {
+ "pluginName" : "Shockwave Flash",
+ "pluginVersion" : "18.0.0.209",
+ ... other annotations as key:value pairs ...
+ }
+ ],
+ ...
+ ]
+ },
+
+log
+---
+As of Firefox 61 this section is no longer present, use :ref:`eventtelemetry` or :doc:`../collection/scalars`.
+
+This section contains a log of important or unusual events reported through Telemetry.
+
+Structure:
+
+.. code-block:: js
+
+ "log": [
+ [
+ "Event_ID",
+ 3785, // the timestamp (in milliseconds) for the log entry
+ ... other data ...
+ ],
+ ...
+ ]
+
+At present there is one known users of this section: Telemetry Experiments.
+
+Telemetry Experiments uses it to note when experiments are activated and terminated.
+
+fileIOReports
+-------------
+Contains the statistics of main-thread I/O recorded during the execution. Only the I/O stats for the XRE and the profile directories are currently reported, neither of them disclosing the full local path.
+
+Structure:
+
+.. code-block:: js
+
+ "fileIOReports": {
+ "{xre}": [
+ totalTime, // Accumulated duration of all operations
+ creates, // Number of create/open operations
+ reads, // Number of read operations
+ writes, // Number of write operations
+ fsyncs, // Number of fsync operations
+ stats, // Number of stat operations
+ ],
+ "{profile}": [ ... ],
+ ...
+ }
+
+lateWrites
+----------
+This sections reports writes to the file system that happen during shutdown. The reported data contains the stack and the file names of the loaded libraries at the time the writes happened.
+
+The file names of the loaded libraries can contain unicode characters.
+
+Structure:
+
+.. code-block:: js
+
+ "lateWrites" : {
+ "memoryMap" : [
+ ["wgdi32.pdb", "08A541B5942242BDB4AEABD8C87E4CFF2"],
+ ... other entries in the format ["module name", "breakpad identifier"] ...
+ ],
+ "stacks" : [
+ [
+ [
+ 0, // the module index or -1 for invalid module indices
+ 190649 // the offset of this program counter in its module or an absolute pc
+ ],
+ [1, 2540075],
+ ... other frames ...
+ ],
+ ... other stacks ...
+ ],
+ },
+
+addonDetails
+------------
+This section contains per add-on telemetry details, as reported by each add-on provider. The XPI provider is the only one reporting at the time of writing (`see Searchfox <https://searchfox.org/mozilla-central/search?q=setTelemetryDetails&case=true>`_). Telemetry does not manipulate or enforce a specific format for the supplied provider's data.
+
+Structure:
+
+.. code-block:: js
+
+ "addonDetails": {
+ "XPI": {
+ "adbhelper@mozilla.org": {
+ "location": "app-profile",
+ "name": "ADB Helper",
+ "creator": "Mozilla & Android Open Source Project",
+ },
+ ...
+ },
+ ...
+ }
+
+slowSQL
+-------
+This section contains the information about the slow SQL queries for both the main and other threads. The execution of an SQL statement is considered slow if it takes 50ms or more on the main thread or 100ms or more on other threads. Slow SQL statements will be automatically trimmed to 1000 characters. This limit doesn't include the ellipsis and database name, that are appended at the end of the stored statement.
+
+Structure:
+
+.. code-block:: js
+
+ "slowSQL": {
+ "mainThread": {
+ "Sanitized SQL Statement": [
+ 1, // the number of times this statement was hit
+ 200 // the total time (in milliseconds) that was spent on this statement
+ ],
+ ...
+ },
+ "otherThreads": {
+ "VACUUM /* places.sqlite */": [
+ 1,
+ 330
+ ],
+ ...
+ }
+ },
+
+slowSQLStartup
+--------------
+This section contains the slow SQL statements gathered at startup (until the "sessionstore-windows-restored" event is fired). The structure of this section resembles the one for `slowSQL`_.
+
+UIMeasurements
+--------------
+This section is Android-only and contains UI specific Telemetry measurements and events (`see here <https://searchfox.org/mozilla-central/search?q=UITelemetry.%28addEvent|startSession|stopSession%29&redirect=false&case=false&regexp=true>`_).
+
+Structure:
+
+.. code-block:: js
+
+ "UIMeasurements": [
+ {
+ "type": "event", // either "session" or "event"
+ "action": "action.1",
+ "method": "menu",
+ "sessions": [],
+ "timestamp": 12345,
+ "extras": "settings"
+ },
+ {
+ "type": "session",
+ "name": "awesomescreen.1",
+ "reason": "commit",
+ "start": 123,
+ "end": 456
+ }
+ ...
+ ],
+
+Version History
+---------------
+
+- Firefox 88:
+
+ - Stopped reporting ``flashVersion`` since Flash is no longer supported. (`bug 1682030 <https://bugzilla.mozilla.org/show_bug.cgi?id=1682030>`_)
+
+- Firefox 61:
+
+ - Stopped reporting ``childPayloads`` (`bug 1443599 <https://bugzilla.mozilla.org/show_bug.cgi?id=1443599>`_).
+ - Stopped reporting ``saved-session`` pings on Firefox Desktop (`bug 1443603 <https://bugzilla.mozilla.org/show_bug.cgi?id=1443603>`_).
+ - Stopped reporting ``simpleMeasurements.js`` (`bug 1278920 <https://bugzilla.mozilla.org/show_bug.cgi?id=1278920>`_).
+ - Stopped reporting ``UITelemetry`` (`bug 1443605 <https://bugzilla.mozilla.org/show_bug.cgi?id=1443605>`_)
+
+- Firefox 62:
+
+ - ``events`` are now reported via the :doc:`../data/event-ping` (`bug 1460595 <https://bugzilla.mozilla.org/show_bug.cgi?id=1460595>`_).
+
+- Firefox 80:
+
+ - Stopped reporting ``GCTelemetry`` (`bug 1482089 <https://bugzilla.mozilla.org/show_bug.cgi?id=1482089>`_).
diff --git a/toolkit/components/telemetry/docs/data/modules-ping.rst b/toolkit/components/telemetry/docs/data/modules-ping.rst
new file mode 100644
index 0000000000..c3b193f8dc
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/modules-ping.rst
@@ -0,0 +1,46 @@
+
+"modules" ping
+==============
+
+This ping is sent once a week and includes the modules loaded in the Firefox process.
+
+The client ID and environment are submitted with this ping.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ type: "modules",
+ ... common ping data
+ clientId: <UUID>,
+ environment: { ... },
+ payload: {
+ version: 1,
+ modules: [
+ {
+ name: <string>, // Name of the module file (e.g. xul.dll)
+ version: <string>, // Version of the module
+ debugID: <string>, // ID of the debug information file
+ debugName: <string>, // Name of the debug information file
+ certSubject: <string>, // Name of the organization that signed the binary (Optional, only defined when present)
+ },
+ ...
+ ],
+ }
+ }
+
+Notes
+~~~~~
+
+The version information is only available on Windows, it is null on other platforms.
+
+The debug name is the name of the PDB on Windows (which isn't always the same as the module name modulo the extension, e.g. the PDB for C:\Windows\SysWOW64\ntdll.dll is wntdll.pdb) and is the same as the module name on other platforms.
+
+The debug ID is platform-dependent. It is compatible with the Breakpad ID used on Socorro.
+
+Sometimes the debug name and debug ID are missing for Windows modules (often with malware). In this case, they will be "null".
+
+The length of the modules array is limited to 512 entries.
+
+The name and debug name are length limited, with a maximum of 64 characters.
diff --git a/toolkit/components/telemetry/docs/data/new-profile-ping.rst b/toolkit/components/telemetry/docs/data/new-profile-ping.rst
new file mode 100644
index 0000000000..67a95b45b4
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/new-profile-ping.rst
@@ -0,0 +1,83 @@
+
+"new-profile" ping
+==================
+
+This opt-out ping is sent from Firefox Desktop 30 minutes after the browser is started, on the first session
+of a newly created profile. If the first session of a newly-created profile was shorter than 30 minutes, it
+gets sent using the :doc:`../internals/pingsender` at shutdown.
+
+.. note::
+
+ We don't sent the ping immediately after Telemetry completes initialization to give the user enough
+ time to tweak their data collection preferences.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ type: "new-profile",
+ ... common ping data
+ clientId: <UUID>,
+ environment: { ... },
+ payload: {
+ reason: "startup", // or "shutdown"
+ processes: { ... }
+ }
+ }
+
+payload.reason
+--------------
+If this field contains ``startup``, then the ping was generated at the scheduled time after
+startup. If it contains ``shutdown``, then the browser was closed before the time the
+ping was scheduled. In the latter case, the ping is generated during shutdown and sent
+using the :doc:`../internals/pingsender`.
+
+processes
+---------
+This section contains per-process data.
+
+Structure:
+
+.. code-block:: js
+
+ "processes" : {
+ "parent": {
+ "scalars": {...}
+ }
+ }
+
+scalars
+~~~~~~~
+This section contains the :doc:`../collection/scalars` that are valid for the ``new-profile`` ping,
+that is the ``record_into_store`` list contains ``new-profile``.
+Scalars are only submitted if data was added to them.
+The recorded scalars are described in the `Scalars.yaml <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/Scalars.yaml>`_ file.
+
+Duplicate pings
+---------------
+We expect a low fraction of duplicates of this ping, mostly due to crashes happening
+right after sending the ping and before the telemetry state gets flushed to the disk. This should
+be fairly low in practice and manageable during the analysis phase.
+
+Expected behaviours
+-------------------
+The following is a list of conditions and expected behaviours for the ``new-profile`` ping:
+
+- **The ping is generated at the browser shutdown on a new profile, after the privacy policy is displayed:**
+
+ - *for an user initiated browser shutdown*, ``new-profile`` is sent immediately using the :doc:`../internals/pingsender`;
+ - *for a browser shutdown triggered by OS shutdown*, ``new-profile`` is saved to disk and sent next time the browser restarts.
+- **The ping is generated before the privacy policy is displayed**: ``new-profile`` is saved to disk and sent
+ next time the browser restarts.
+- **The ping is set to be generated and Telemetry is disabled**: ``new-profile`` is never sent, even if Telemetry is
+ turned back on later.
+- **Firefox crashes before the ping can be generated**: ``new-profile`` will be scheduled to be generated and
+ sent again on the next restart.
+- **User performs a profile refresh**:
+
+ - *the ping was already sent*: ``new-profile`` will not be sent again.
+ - *the ping was not sent*: ``new-profile`` will be generated and sent.
+ - *the refresh happens immediately after the profile creation, before the policy is shown*: ``new-profile`` will not be sent again.
+- **Firefox is run with an old profile that already sent Telemetry data**: ``new-profile`` will not be generated
+ nor sent.
diff --git a/toolkit/components/telemetry/docs/data/pioneer-study.rst b/toolkit/components/telemetry/docs/data/pioneer-study.rst
new file mode 100644
index 0000000000..d592c692ab
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/pioneer-study.rst
@@ -0,0 +1,58 @@
+=============
+Pioneer Study
+=============
+
+The `pioneer-study` ping is the main transport used by the Pioneer components.
+
+-------
+Payload
+-------
+
+It is made up of a clear text payload and an encrypted data payload, following the structure described below.
+
+Structure:
+
+.. code-block:: js
+
+ "payload": {
+ "encryptedData": "<encrypted token>",
+ "schemaVersion": 1,
+ "schemaName": "debug",
+ "schemaNamespace": "<namespace>",
+ "encryptionKeyId": "<key id>",
+ "pioneerId": "<UUID>",
+ "studyName": "pioneer-v2-example"
+ }
+
+See also the `JSON schemas <https://github.com/mozilla-services/mozilla-pipeline-schemas/tree/master/schemas/pioneer-debug>`_.
+
+encryptedData
+ The encrypted data sent using the Pioneer platform.
+
+schemaVersion
+ The payload format version.
+
+schemaName
+ The name of the schema of the encrypted data.
+
+schemaNamespace
+ The namespace used to segregate data on the pipeline.
+
+encryptionKeyId
+ The id of the key used to encrypt the data. If `discarded` is used, then the `encryptedData` will be ignored and not decoded (only possible for `deletion-request` and `pioneer-enrollment` schemas).
+
+pioneerId
+ The id of the pioneer client.
+
+studyName (optional)
+ The id of the study for which the data is being collected.
+
+------------------------
+Special Pioneer Payloads
+------------------------
+
+This ping has two special Pioneer payload configurations, indicated by the different `schemaName`: `deletion-request` and `pioneer-enrollemnt`.
+
+The `deletion-request` is sent when a user opts out from a Pioneer study: it contains the `pioneerId` and the `studyName`.
+
+The `pioneer-enrollment` is sent when a user opts into the Pioneer program: in this case it reports `schemaNamespace: "pioneer-meta"` and will have no `studyName`. It is also sent when enrolling into a study, in which case it reports the same namespace as the `deletion-request` (i.e. the id the study making the request) and the `pioneer-enrollment` schema name.
diff --git a/toolkit/components/telemetry/docs/data/sync-ping.rst b/toolkit/components/telemetry/docs/data/sync-ping.rst
new file mode 100644
index 0000000000..4668b4e695
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/sync-ping.rst
@@ -0,0 +1,357 @@
+
+"sync" ping
+===========
+
+This is an aggregated format that contains information about each sync that occurred during a timeframe. It is submitted every 12 hours, and on browser shutdown, but only if the ``syncs`` property would not be empty. The ping does not contain the environment block, nor the clientId.
+
+Each item in the ``syncs`` property is generated after a sync is completed, for both successful and failed syncs, and contains measurements pertaining to sync performance and error information.
+
+A JSON-schema document describing the exact format of the ping's payload property can be found at `services/sync/tests/unit/sync\_ping\_schema.json <https://searchfox.org/mozilla-central/source/services/sync/tests/unit/sync_ping_schema.json>`_.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ version: 4,
+ type: "sync",
+ ... common ping data
+ payload: {
+ version: 1,
+ os : { ... }, // os data from the current telemetry environment. OS specific, but typically includes name, version and locale.
+ discarded: <integer count> // Number of syncs discarded -- left out if zero.
+ why: <string>, // Why did we submit the ping? Either "shutdown", "schedule", or "idchanged".
+ uid: <string>, // Hashed FxA unique ID, or string of 32 zeros. If this changes between syncs, the payload is submitted.
+ deviceID: <string>, // Hashed FxA Device ID, hex string of 64 characters, not included if the user is not logged in. If this changes between syncs, the payload is submitted.
+ sessionStartDate: <ISO date>, // Hourly precision, ISO date in local time
+ // Array of recorded syncs. The ping is not submitted if this would be empty
+ syncs: [{
+ when: <integer milliseconds since epoch>,
+ took: <integer duration in milliseconds>,
+ didLogin: <bool>, // Optional, is this the first sync after login? Excluded if we don't know.
+ why: <string>, // Optional, why the sync occurred, excluded if we don't know.
+
+ // Optional, excluded if there was no error.
+ failureReason: {
+ name: <string>, // "httperror", "networkerror", "shutdownerror", etc.
+ code: <integer>, // Only present for "httperror" and "networkerror".
+ error: <string>, // Only present for "othererror" and "unexpectederror".
+ from: <string>, // Optional, and only present for "autherror".
+ },
+
+ // Optional, excluded if we couldn't get a valid uid or local device id
+ devices: [{
+ os: <string>, // OS string as reported by Services.appinfo.OS, if known
+ version: <string>, // Firefox version, as reported by Services.appinfo.version if known
+ id: <string>, // Hashed FxA device id for device
+ type: <string>, // broad device "type", as reported by fxa ("mobile", "tv", etc).
+ syncID: <string>, // Hashed Sync device id for device, if the user is a sync user.
+ }],
+
+ // Internal sync status information. Omitted if it would be empty.
+ status: {
+ sync: <string>, // The value of the Status.sync property, unless it indicates success.
+ service: <string>, // The value of the Status.service property, unless it indicates success.
+ },
+ // Information about each engine's sync.
+ engines: [
+ {
+ name: <string>, // "bookmarks", "tabs", etc.
+ took: <integer duration in milliseconds>, // Optional, values of 0 are omitted.
+
+ status: <string>, // The value of Status.engines, if it holds a non-success value.
+
+ // Optional, excluded if all items would be 0. A missing item indicates a value of 0.
+ incoming: {
+ applied: <integer>, // Number of records applied
+ succeeded: <integer>, // Number of records that applied without error
+ failed: <integer>, // Number of records that failed to apply
+ failedReasons: [
+ name: <string> // Error message trying to apply the record
+ count: <integer> // count of how many times this error occurred
+ ],
+ },
+
+ // Optional, excluded if it would be empty. Records that would be
+ // empty (e.g. 0 sent and 0 failed) are omitted.
+ outgoing: [
+ {
+ sent: <integer>, // Number of outgoing records sent. Zero values are omitted.
+ failed: <integer>, // Number that failed to send. Zero values are omitted.
+ failedReasons: [
+ name: <string> // Error message trying to apply the record
+ count: <integer> // count of how many times this error occurred
+ ],
+ }
+ ],
+ // Optional, excluded if there were no errors
+ failureReason: { ... }, // Same as above.
+
+ // Timings and counts for detailed steps that the engine reported
+ // as part of its sync. Optional; omitted if the engine didn't
+ // report any extra steps.
+ steps: {
+ name: <string>, // The step name.
+ took: <integer duration in milliseconds>, // Omitted if 0.
+ // Optional, extra named counts (e.g., number of items handled
+ // in this step). Omitted if the engine didn't report extra
+ // counts.
+ counts: [
+ {
+ name: <string>, // The counter name.
+ count: <integer>, // The counter value.
+ },
+ ],
+ },
+
+ // Optional, excluded if it would be empty or if the engine cannot
+ // or did not run validation on itself.
+ validation: {
+ // Optional validator version, default of 0.
+ version: <integer>,
+ checked: <integer>,
+ took: <non-monotonic integer duration in milliseconds>,
+ // Entries with a count of 0 are excluded, the array is excluded if no problems are found.
+ problems: [
+ {
+ name: <string>, // The problem identified.
+ count: <integer>, // Number of times it occurred.
+ }
+ ],
+ // Format is same as above, this is only included if we tried and failed
+ // to run validation, and if it's present, all other fields in this object are optional.
+ failureReason: { ... },
+ }
+ }
+ ],
+ // Information about any storage migrations that have occurred. Omitted if it would be empty.
+ migrations: [
+ // See the section on the `migrations` array for detailed documentation on what may appear here.
+ {
+ type: <string identifier>,
+ // per-type data
+ }
+ ]
+ }],
+ // The "node type" as reported by the token server. This will not change
+ // from sync to sync, so is reported once per ping. Optional because it
+ // will not appear if the token server omits this information, but in
+ // general, we will expect all "new" pings to have it.
+ syncNodeType: <string>,
+ events: [
+ event_array // See events below.
+ ],
+ histograms: { ... } // See histograms below
+ }
+ }
+
+info
+----
+
+discarded
+~~~~~~~~~
+
+The ping may only contain a certain number of entries in the ``"syncs"`` array, currently 500 (it is determined by the ``"services.sync.telemetry.maxPayloadCount"`` preference). Entries beyond this are discarded, and recorded in the discarded count.
+
+syncs.took
+~~~~~~~~~~
+
+These values should be monotonic. If we can't get a monotonic timestamp, -1 will be reported on the payload, and the values will be omitted from the engines. Additionally, the value will be omitted from an engine if it would be 0 (either due to timer inaccuracy or finishing instantaneously).
+
+uid
+~~~~~~~~~
+
+This property containing a hash of the FxA account identifier, which is a 32 character hexadecimal string. In the case that we are unable to authenticate with FxA and have never authenticated in the past, it will be a placeholder string consisting of 32 repeated ``0`` characters.
+
+syncs.why
+~~~~~~~~~
+
+One of the following values:
+
+- ``startup``: This is the first sync triggered after browser startup.
+- ``schedule``: This is a sync triggered because it has been too long since the last sync.
+- ``score``: This sync is triggered by a high score value one of sync's trackers, indicating that many changes have occurred since the last sync.
+- ``user``: The user manually triggered the sync.
+- ``tabs``: The user opened the synced tabs sidebar, which triggers a sync.
+
+syncs.status
+~~~~~~~~~~~~
+
+The ``engine.status``, ``payload.status.sync``, and ``payload.status.service`` properties are sync error codes, which are listed in `services/sync/modules/constants.js <https://searchfox.org/mozilla-central/source/services/sync/modules/constants.js>`_, and success values are not reported.
+
+syncs.failureReason
+~~~~~~~~~~~~~~~~~~~
+
+Stores error information, if any is present. Always contains the "name" property, which identifies the type of error it is. The types can be.
+
+- ``httperror``: Indicates that we received an HTTP error response code, but are unable to be more specific about the error. Contains the following properties:
+
+ - ``code``: Integer HTTP status code.
+
+- ``nserror``: Indicates that an exception with the provided error code caused sync to fail.
+
+ - ``code``: The nsresult error code (integer).
+
+- ``shutdownerror``: Indicates that the sync failed because we shut down before completion.
+
+- ``autherror``: Indicates an unrecoverable authentication error.
+
+ - ``from``: Where the authentication error occurred, one of the following values: ``tokenserver``, ``fxaccounts``, or ``hawkclient``.
+
+- ``othererror``: Indicates that it is a sync error code that we are unable to give more specific information on. As with the ``syncStatus`` property, it is a sync error code, which are listed in `services/sync/modules/constants.js <https://searchfox.org/mozilla-central/source/services/sync/modules/constants.js>`_.
+
+ - ``error``: String identifying which error was present.
+
+- ``unexpectederror``: Indicates that some other error caused sync to fail, typically an uncaught exception.
+
+ - ``error``: The message provided by the error.
+
+- ``sqlerror``: Indicates that we received a ``mozIStorageError`` from a database query.
+
+ - ``code``: Value of the ``error.result`` property, one of the constants listed `here <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/MozIStorageError#Constants>`_.
+
+syncs.engine.name
+~~~~~~~~~~~~~~~~~
+
+Third-party engines are not reported, so only the following values are allowed: ``addons``, ``bookmarks``, ``clients``, ``forms``, ``history``, ``passwords``, ``prefs``, and ``tabs``.
+
+syncs.engine.validation.problems
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For engines that can run validation on themselves, an array of objects describing validation errors that have occurred. Items that would have a count of 0 are excluded. Each engine will have its own set of items that it might put in the ``name`` field, but there are a finite number. See ``BookmarkProblemData.getSummary`` in `services/sync/modules/bookmark\_validator.js <https://searchfox.org/mozilla-central/source/services/sync/modules/bookmark_validator.js>`_ for an example.
+
+syncs.devices
+~~~~~~~~~~~~~
+
+The list of remote devices associated with this account, as reported by the clients collection. The ID of each device is hashed using the same algorithm as the local id.
+
+Events in the "sync" ping
+-------------------------
+
+The sync ping includes events in the same format as they are included in the
+main ping, see :ref:`eventtelemetry`.
+
+All events submitted as part of the sync ping which already include the "extra"
+object (the 6th parameter of the event array described in the event telemetry
+documentation) may also include a "serverTime" parameter, which the most recent
+unix timestamp sent from the sync server (as a string). This arrives in the
+``X-Weave-Timestamp`` HTTP header, and may be omitted in cases where the client
+has not yet made a request to the server, or doesn't have it for any other
+reason. It is included to improve flow analysis across multiple clients.
+
+Every event recorded in this ping will have a category of ``sync``. The following
+events are defined, categorized by the event method.
+
+Histograms in the "sync" ping
+-----------------------------
+
+The sync ping includes histograms relating to measurements of password manager usage.
+These histograms are duplicated in the main ping. Histograms are only included in a ping if they have been set by the pwmgr code.
+Currently, the histograms that can be included are:
+
+PWMGR_BLOCKLIST_NUM_SITES
+PWMGR_FORM_AUTOFILL_RESULT
+PWMGR_LOGIN_LAST_USED_DAYS
+PWMGR_LOGIN_PAGE_SAFETY
+PWMGR_NUM_PASSWORDS_PER_HOSTNAME
+PWMGR_NUM_SAVED_PASSWORDS
+PWMGR_PROMPT_REMEMBER_ACTION
+PWMGR_PROMPT_UPDATE_ACTION
+PWMGR_SAVING_ENABLED
+
+Histograms are objects with the following 6 properties:
+- min - minimum bucket size
+- max - maximum bucket size
+- histogram_type
+- counts - array representing contents of the buckets in the histogram
+- ranges - array with calculated bucket sizes
+
+sendcommand
+~~~~~~~~~~~
+
+Records that Sync wrote a remote "command" to another client. These commands
+cause that other client to take some action, such as resetting Sync on that
+client, or opening a new URL.
+
+- object: The specific command being written.
+- value: Not used (ie, ``null``)
+- extra: An object with the following attributes:
+
+ - deviceID: A GUID which identifies the device the command is being sent to.
+ - flowID: A GUID which uniquely identifies this command invocation. This GUID
+ is the same for every device the tab is sent to.
+ - streamID: A GUID which uniquely identifies this command invocation's
+ specific target. This GUID is unique for every device the tab is
+ sent to (new in Firefox 79).
+ - serverTime: (optional) Most recent server timestamp, as described above.
+
+processcommand
+~~~~~~~~~~~~~~
+
+Records that Sync processed a remote "command" previously sent by another
+client. This is logically the "other end" of ``sendcommand``.
+
+- object: The specific command being processed.
+- value: Not used (ie, ``null``)
+- extra: An object with the following attributes:
+
+ - flowID: A GUID which uniquely identifies this command invocation. The value
+ for this GUID will be the same as the flowID sent to the client via
+ ``sendcommand``.
+ - streamID: A GUID which uniquely identifies this command invocation's
+ specific target. The value for this GUID will be the same as the
+ streamID sent to the client via ``sendcommand`` (new in Firefox 79).
+ - reason: A string value of either ``"poll"``, ``"push"``, or ``"push-missed"``
+ representing an explanation for why the command is being processed.
+ - serverTime: (optional) Most recent server timestamp, as described above.
+
+The ``migrations`` Array
+------------------------
+
+The application-services developers are in the process of oxidizing parts of firefox sync and the related data storage code, which typically requires migrating the old storage into a new database and/or format.
+
+When a migration like this occurs, a record is reported in this list the next time the sync ping is submitted.
+
+Because the format of each data store may be drastically different, we are not attempting to come up with a generic representation here, and currently planning on allowing each migration record to vary independently (at least for now). These records will be distinctly identified by their ``"type"`` field.
+
+They should only appear once per migration (that is, we'd rather fail to report a record than report them multiple times).
+
+migrations.type: ``"webext-storage"``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This indicates a migration was performed from the legacy kinto-based extension-storage database into the new webext-storage rust implementation.
+
+It contains the following fields:
+
+- ``type``: Always the string ``"webext-storage"``.
+
+- ``entries``: The number of entries/preferences in the source (legacy) database, including ones we failed to read. See below for information on the distinction between ``entries`` and ``extensions`` in this record.
+
+- ``entriesSuccessful``: The number of entries/preferences (see below) which we have successfully migrated into the destination database..
+
+- ``extensions``: The number of distinct extensions which have at least one preference in the source (legacy) database.
+
+- ``extensionsSuccessful``: The number of distinct extensions which have at least one preference in the destination (migrated) database.
+
+- ``openFailure``: A boolean flag that is true if we hit a read error prior to . This likely indicates complete corruption, or a bug in an underlying library like rusqlite.
+
+
+Note: "entries" vs "extensions"
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``webext-storage`` migration record detailed above contains counts for both:
+
+- The number of "entries" detected vs successfully migrated.
+- The number of "extensions" detected vs successfully migrated.
+
+This may seem redundant, but these refer to different (but related) things. The distinction here has to do with the way the two databases store extension-storage data:
+
+* The legacy database stores one row for each (``extension_id``, ``preference_name``, ``preference_value``) triple. These are referred to as ``entries``.
+
+* Conversely, the new database stores one row per extension, which is a pair containing both the ``extension_id``, as well as a dictionary holding all preference data, and so are equivalent to extensions.
+
+(The description above is a somewhat simplified view of things, as it ignores a number values each database stores which is irrelevant for migration)
+
+That is, ``entries`` represent each individual preference setting, and ``extensions`` represent the collected set of preferences for a given extension.
+
+Counts for are *both* of these are present as it's likely that the disparity would point to different kinds of issues with the migration code.
diff --git a/toolkit/components/telemetry/docs/data/third-party-modules-ping.rst b/toolkit/components/telemetry/docs/data/third-party-modules-ping.rst
new file mode 100644
index 0000000000..3871b2e4b3
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/third-party-modules-ping.rst
@@ -0,0 +1,135 @@
+.. _third-party-modules-ping:
+
+"third-party-modules" ping
+==========================
+
+This ping contains information about events whereby third-party modules
+were loaded into Firefox processes.
+
+.. code-block:: js
+
+ {
+ "type": "third-party-modules",
+ ... common ping data
+ "clientId": <UUID>,
+ "environment": { ... },
+ "payload": {
+ "structVersion": 1,
+ // List of DLL filenames that are on the dynamic blocklist
+ "blockedModules": [<string>],
+ "modules": [
+ {
+ // The sanitized name of the module as resolved by the Windows loader.
+ "resolvedDllName": <string>,
+ // Version of the DLL as contained in its resources's fixed version information.
+ "fileVersion": <string>,
+ // The value of the CompanyName field as extracted from the DLL's version information. This property is only present when such version info is present, and when the 'signedBy' property is absent.
+ "companyName": <string>,
+ // The organization whose certificate was used to sign the DLL. Only present for signed modules.
+ "signedBy": <string>,
+ // Flags that indicate this module's level of trustworthiness. This corresponds to one or more mozilla::ModuleTrustFlags OR'd together.
+ "trustFlags": <unsigned int>
+ },
+ ... Additional modules (maximum 100)
+ ],
+ "processes": {
+ <string containing processType and pid, formatted as `${processType}.0x${pid}">`: {
+ // Except for Default (which is remapped to "browser"), one of the process string names specified in xpcom/build/GeckoProcessTypes.h.
+ "processType": <string>,
+ // Elapsed time since process creation that this object was generated, in seconds.
+ "elapsed": <number>,
+ // Time spent loading xul.dll in milliseconds.
+ "xulLoadDurationMS": <number>,
+ // Number of dropped events due to failures sanitizing file paths.
+ "sanitizationFailures": <int>,
+ // Number of dropped events due to failures computing trust levels.
+ "trustTestFailures": <int>,
+ // Array of module load events for this process. The entries of this array are ordered to be in sync with the combinedStacks.stacks array (see below)
+ "events": [
+ {
+ // Elapsed time since process creation that this event was generated, in milliseconds.
+ "processUptimeMS": <int>,
+ // Time spent loading this module, in milliseconds.
+ "loadDurationMS": <number>,
+ // Thread ID for the thread that loaded the module.
+ "threadID": <int>,
+ // Name of the thread that loaded the module, when applicable.
+ "threadName": <string>,
+ // The sanitized name of the module that was requested by the invoking code. Only exists when it is different from resolvedDllName.
+ "requestedDllName": <string>,
+ // The base address to which the loader mapped the module.
+ "baseAddress": <string formatted as "0x%x">,
+ // Index of the element in the modules array that contains details about the module that was loaded during this event.
+ "moduleIndex": <int>,
+ // True if the module is included in the executable's Import Directory Table.
+ "isDependent": <bool>,
+ // The status of DLL load. This corresponds to enum ModuleLoadInfo::Status.
+ "loadStatus": <int>
+ },
+ ... Additional events (maximum 50)
+ ],
+ "combinedStacks": [
+ "memoryMap": [
+ [
+ // Name of the module symbol file, e.g. ``xul.pdb``
+ <string>,
+ // Breakpad identifier of the module, e.g. ``08A541B5942242BDB4AEABD8C87E4CFF2``
+ <string>
+ ],
+ ... Additional modules
+ ],
+ // Array of stacks for this process. These entries are ordered to be in sync with the events array
+ "stacks": [
+ [
+ [
+ // The module index or -1 for invalid module indices
+ <integer>,
+ // The program counter relative to its module base, or an absolute pc if the module index is -1
+ <unsigned integer>
+ ],
+ ... Additional stack frames (maximum 512)
+ ],
+ ... Additional stack traces (maximum 50)
+ ]
+ ]
+ },
+ ... Additional processes (maximum 100)
+ }
+ }
+ }
+
+payload.processes[...].events[...].resolvedDllName
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The effective path to the module file, sanitized to remove any potentially
+sensitive information. In most cases, the directory path is removed leaving only
+the leaf name, e.g. ``foo.dll``. There are three exceptions:
+
+* Paths under ``%ProgramFiles%`` are preserved, e.g. ``%ProgramFiles%\FooApplication\foo.dll``
+* Paths under ``%SystemRoot%`` are preserved, e.g. ``%SystemRoot%\System32\DriverStore\FileRepository\nvlt.inf_amd64_97992900c592012e\nvinitx.dll``
+* Paths under the temporary path are preserved, e.g. ``%TEMP%\bin\foo.dll``
+
+payload.processes[...].events[...].requestedDllName
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The name of the module as it was requested from the OS. This string is also
+sanitized in a similar fashion to to ``resolvedDllName``. This string is
+omitted from the ping when it is identical to ``resolvedDllName``.
+
+Notes
+~~~~~
+* The client id is submitted with this ping.
+* The :doc:`Telemetry Environment <../data/environment>` is submitted in this ping.
+* String fields within ``payload`` are limited in length to 260 characters.
+* This ping is sent once daily.
+* If there are no events to report, this ping is not sent.
+
+Version History
+~~~~~~~~~~~~~~~
+- Firefox 110: Added ``blockedModules`` (`bug 1808158 <https://bugzilla.mozilla.org/show_bug.cgi?id=1808158>`_).
+- Firefox 77: Added ``isDependent`` (`bug 1620118 <https://bugzilla.mozilla.org/show_bug.cgi?id=1620118>`_).
+- Firefox 71: Renamed from untrustedModules to third-party-modules with a revised schema (`bug 1542830 <https://bugzilla.mozilla.org/show_bug.cgi?id=1542830>`_).
+- Firefox 70: Added ``%SystemRoot%`` as an exemption to path sanitization (`bug 1573275 <https://bugzilla.mozilla.org/show_bug.cgi?id=1573275>`_).
+- Firefox 66:
+ - Added Windows Side-by-side directory trust flag (`bug 1514694 <https://bugzilla.mozilla.org/show_bug.cgi?id=1514694>`_).
+ - Added module load times (``xulLoadDurationMS``, ``loadDurationMS``) and xul.dll trust flag (`bug 1518490 <https://bugzilla.mozilla.org/show_bug.cgi?id=1518490>`_).
+ - Added SysWOW64 trust flag (`bug 1518798 <https://bugzilla.mozilla.org/show_bug.cgi?id=1518798>`_).
+- Firefox 65: Initial support (`bug 1435827 <https://bugzilla.mozilla.org/show_bug.cgi?id=1435827>`_).
diff --git a/toolkit/components/telemetry/docs/data/uitour-ping.rst b/toolkit/components/telemetry/docs/data/uitour-ping.rst
new file mode 100644
index 0000000000..06e4a9f49b
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/uitour-ping.rst
@@ -0,0 +1,25 @@
+
+"uitour-tag" ping
+=================
+
+This ping is submitted via the UITour ``setTreatmentTag`` API. It may be used by
+the tour to record what settings were made by a user or to track the result of
+A/B experiments.
+
+The client ID is submitted with this ping.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ version: 1,
+ type: "uitour-tag",
+ clientId: <string>,
+ payload: {
+ tagName: <string>,
+ tagValue: <string>
+ }
+ }
+
+See also: :doc:`common ping fields <common-ping>`
diff --git a/toolkit/components/telemetry/docs/data/uninstall-ping.rst b/toolkit/components/telemetry/docs/data/uninstall-ping.rst
new file mode 100644
index 0000000000..281cc3fcec
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/uninstall-ping.rst
@@ -0,0 +1,36 @@
+
+"uninstall" ping
+================
+
+This opt-out ping is sent from the Windows uninstaller when the uninstall finishes. Notably it includes ``clientId`` and the :doc:`Telemetry Environment <environment>`. It follows the :doc:`common ping format <common-ping>`.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ type: "uninstall",
+ ... common ping data
+ clientId: <UUID>,
+ environment: { ... },
+ payload: {
+ otherInstalls: <integer>, // Optional, number of other installs on the system, max 11.
+ }
+ }
+
+See also the `JSON schema <https://github.com/mozilla-services/mozilla-pipeline-schemas/blob/master/templates/telemetry/uninstall/uninstall.4.schema.json>`_. These pings are recorded in the ``telemetry.uninstall`` table in Redash, using the default "Telemetry (BigQuery)" data source.
+
+payload.otherInstalls
+---------------------
+This is a count of how many other installs of Firefox were present on the system at the time the ping was written. It is the number of values in the ``Software\Mozilla\Firefox\TaskBarIDs`` registry key, for both 32-bit and 64-bit architectures, for both HKCU and HKLM, excluding duplicates, and excluding a value for this install (if present). For example, if this is the only install on the system, the value will be 0. It may be missing in case of an error.
+
+This count is capped at 11. This avoids introducing a high-resolution identifier in case of a system with a large, unique number of installs.
+
+Uninstall Ping storage and lifetime
+-----------------------------------
+
+On delayed Telemetry init (about 1 minute into each run of Firefox), if opt-out telemetry is enabled, this ping is written to disk. There is a single ping for each install, any uninstall pings from the same install are removed before the new ping is written.
+
+The ping is removed if Firefox notices that opt-out telemetry has been disabled, either when the ``datareporting.healthreport.uploadEnabled`` pref goes false or when it is false on delayed init. Conversely, when opt-out telemetry is re-enabled, the ping is written as Telemetry is setting itself up again.
+
+The ping is sent by the uninstaller some arbitrary time after it is written to disk by Firefox, so it could be significantly out of date when it is submitted. There should be little impact from stale data, since analysis is likely to focus on clients that uninstalled soon after running Firefox, and this ping mostly changes when Firefox itself is updated.
diff --git a/toolkit/components/telemetry/docs/data/update-ping.rst b/toolkit/components/telemetry/docs/data/update-ping.rst
new file mode 100644
index 0000000000..037d521019
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/update-ping.rst
@@ -0,0 +1,79 @@
+
+"update" ping
+==================
+
+This opt-out ping is sent from Firefox Desktop when a browser update is ready to be applied and after it was correctly applied.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ type: "update",
+ ... common ping data
+ clientId: <UUID>,
+ environment: { ... },
+ payload: {
+ reason: <string>, // "ready", "success"
+ targetChannel: <string>, // "nightly" (only present for reason = "ready")
+ targetVersion: <string>, // "56.0a1" (only present for reason = "ready")
+ targetBuildId: <string>, // "20080811053724" (only present for reason = "ready")
+ targetDisplayVersion: <string>, // "56.0a1" (only present for reason = "ready")
+ previousChannel: <string>, // "nightly" or null (only present for reason = "success")
+ previousVersion: <string>, // "55.0a1" (only present for reason = "success")
+ previousBuildId: <string>, // "20080810053724" (only present for reason = "success")
+ }
+ }
+
+payload.reason
+--------------
+This field supports the following values:
+
+- ``ready`` meaning that the ping was generated after an update was downloaded and marked as ready to be processed. For *non-staged* updates this happens as soon as the download finishes and is verified while for *staged* updates this happens before the staging step is started.
+- ``success`` the ping was generated after the browser was restarted and the update correctly applied.
+
+payload.targetChannel
+-----------------------
+The Firefox channel the update was fetched from (only valid for pings with reason "ready").
+
+payload.targetVersion
+-----------------------
+The Firefox version the browser is updating to. Follows the same format as application.version (only valid for pings with reason "ready").
+
+payload.targetBuildId
+-----------------------
+The Firefox build id the browser is updating to. Follows the same format as application.buildId (only valid for pings with reason "ready").
+
+payload.targetDisplayVersion
+----------------------------
+The Firefox display version the browser is updating to. This may contain a different value than ``targetVersion``, e.g. for the ``Beta`` channel this field will report the beta suffix while ``targetVersion`` will only report the version number.
+
+payload.previousChannel
+-----------------------
+The Firefox channel the profile was on before the update was applied (only valid for pings with reason "success").
+This can be ``null``.
+
+payload.previousVersion
+-----------------------
+The Firefox version the browser is updating from. Follows the same format as application.version (only valid for pings with reason "success").
+
+payload.previousBuildId
+-----------------------
+The Firefox build id the browser is updating from. Follows the same format as application.buildId (only valid for pings with reason "success").
+
+Expected behaviours
+-------------------
+The following is a list of conditions and expected behaviours for the ``update`` ping:
+
+- **The ping is generated once every time an update is downloaded, after it was verified:**
+
+ - *for users who saw the privacy policy*, the ``update`` ping is sent immediately;
+ - *for users who did not see the privacy policy*, the ``update`` ping is saved to disk and sent after the policy is displayed.
+- **If the download of the update retries or other fallback occurs**: the ``update`` ping will not be generated
+ multiple times, but only one time once the download is complete and verified.
+- **If automatic updates are disabled**: when the user forces a manual update, no ``update`` ping will be generated.
+- **If updates fail to apply**: in some cases the client will download the same update blob and generate a new ``update`` ping for the same target version and build id, with a different document id.
+- **If the build update channel contains the CCK keyword**, the update ping will not report it but rather report a vanilla channel name (e.g. ``mozilla-cck-test-beta`` gets reported as ``beta``).
+- **If a profile refresh occurs before the update is applied**, the update ping with ``reason = success`` will not be generated.
+- **If the update is applied on a new profile, different then the one it was downloaded in**, the update ping with ``reason = success`` will not be generated.
+- **If a newer browser version is installed over an older**, the update ping with ``reason = success`` will not be generated.
diff --git a/toolkit/components/telemetry/docs/data/xfocsp-error-report-ping.rst b/toolkit/components/telemetry/docs/data/xfocsp-error-report-ping.rst
new file mode 100644
index 0000000000..f1b6f928a3
--- /dev/null
+++ b/toolkit/components/telemetry/docs/data/xfocsp-error-report-ping.rst
@@ -0,0 +1,69 @@
+
+"xfocsp-error-report" ping
+==========================
+
+This opt-in ping is sent when an X-Frame-Options error or a CSP: frame-ancestors
+happens to report the error. Users can opt-in this by checking the reporting
+checkbox. After users opt-in, this ping will be sent every time the error
+happens. Users can opt-out this by un-checking the reporting checkbox on the
+error page. The client_id and environment are not sent with this ping.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ "type": "xfocsp-error-report",
+ ... common ping data
+ "payload": {
+ "error_type": <string>,
+ "xfo_header": <string>,
+ "csp_header": <string>,
+ "frame_hostname": <string>,
+ "top_hostname": <string>,
+ "frame_uri": <string>,
+ "top_uri": <string>,
+ }
+ }
+
+info
+----
+
+error_type
+~~~~~~~~~~
+
+The type of what error triggers this ping. This could be either "xfo" or "csp".
+
+xfo_header
+~~~~~~~~~~
+
+The X-Frame-Options value in the response HTTP header.
+
+csp_header
+~~~~~~~~~~
+
+The CSP: frame-ancestors value in the response HTTP header.
+
+frame_hostname
+~~~~~~~~~~~~~~
+
+The hostname of the frame which triggers the error.
+
+top_hostname
+~~~~~~~~~~~~
+
+The hostname of the top-level page which loads the frame.
+
+frame_uri
+~~~~~~~~~
+
+The uri of the frame which triggers the error. This excludes the query strings.
+
+top_uri
+~~~~~~~
+
+The uri of the top-level page which loads the frame. This excludes the query
+strings.
+
+
+See also: :doc:`common ping fields <common-ping>`
diff --git a/toolkit/components/telemetry/docs/index.rst b/toolkit/components/telemetry/docs/index.rst
new file mode 100644
index 0000000000..71120ccde5
--- /dev/null
+++ b/toolkit/components/telemetry/docs/index.rst
@@ -0,0 +1,36 @@
+=========
+Telemetry
+=========
+
+Telemetry is a feature that allows data collection.
+This is being used to collect performance metrics and other information about how Firefox performs in the wild, e.g. update events or session lengths.
+
+There are two main ways of gathering data, Desktop Telemetry - documented here - which is used in Firefox Desktop
+and `Glean <https://docs.telemetry.mozilla.org/concepts/glean/glean.html>`__ which is
+Mozilla’s newer telemetry framework and used for example in Firefox on Android.
+Information which is gathered is called a probe in Desktop Telemetry or a metric in Glean.
+The data is being sent in so-called pings. When pings cannot be sent immediately, caching is implemented as well.
+
+This means, client-side the main building blocks are:
+
+* :doc:`data collection <collection/index>`, e.g. in histograms and scalars
+* assembling :doc:`concepts/pings` with the general information and the data payload
+* sending them to the server and local ping retention
+
+There are also some notable special cases:
+
+1. `Firefox on Glean (FOG) <../glean/index.html>`__ a wrapper around Glean for Firefox Desktop.
+2. `GeckoView Streaming Telemetry <../internals/geckoview-streaming.html>`__ - gecko uses Desktop Telemetry for recording data, but on Android (Fenix) Glean is used for sending the data. GeckoView provides the necessary adapter to get the data from Desktop Telemetry to Glean.
+
+*Note:* Mozilla's `data collection policy <https://wiki.mozilla.org/Firefox/Data_Collection>`_ documents the process and requirements that are applied here.
+
+.. toctree::
+ :maxdepth: 5
+ :titlesonly:
+
+ start/index
+ concepts/index
+ collection/index
+ data/index
+ internals/index
+ obsolete/index
diff --git a/toolkit/components/telemetry/docs/internals/index.rst b/toolkit/components/telemetry/docs/internals/index.rst
new file mode 100644
index 0000000000..78679bda0d
--- /dev/null
+++ b/toolkit/components/telemetry/docs/internals/index.rst
@@ -0,0 +1,25 @@
+=========
+Internals
+=========
+
+Here is a quick overview of the most important code parts. They can be found in the telemetry folder.
+
+* TelemetryController: Main telemetry logic, e.g. assembling pings, local storage (when archiving is enabled), preference changes, testing
+* Telemetry.cpp contains most of the public interface, implements the IDL
+* The different data types for telemetry are handled in TelemetryHistogram, TelemetryScalar, TelemetryEvent.
+* TelemetryEnvironment: A helper for gathering environment data, like build version or graphics data
+* TelemetryScheduler: Starts regular jobs for collecting and sending data
+* TelemetrySend: Sending and caching of pings
+* TelemetryStorage: Handles writing pings to disk for TelemetrySend
+* TelemetrySession: Collects data for a browsing session, includes many of the most important probes (aka metrics)
+* Policy: A layer of indirection added to provide testability. A common pattern in many files
+* pings/: Contains definitions and handling for most ping types, like EventPing
+
+More details on different topics can be found in these chapters:
+
+.. toctree::
+ :maxdepth: 2
+ :titlesonly:
+ :glob:
+
+ **
diff --git a/toolkit/components/telemetry/docs/internals/integration_tests/index.rst b/toolkit/components/telemetry/docs/internals/integration_tests/index.rst
new file mode 100644
index 0000000000..389fa8b80e
--- /dev/null
+++ b/toolkit/components/telemetry/docs/internals/integration_tests/index.rst
@@ -0,0 +1,143 @@
+=================
+Integration Tests
+=================
+
+The aim of the telemetry-tests-client suite is to verify Firefox collects telemetry probes, aggregates that data, and submits telemetry
+pings containing the data to a HTTP server. The integration tests try to make no assumptions about the internal workings of Firefox and
+use automation to mimic user behavior.
+
+The integration test suite for Firefox Client Telemetry runs on CI `tier 1 <https://wiki.mozilla.org/Sheriffing/Job_Visibility_Policy>`_
+with treeherder symbol `tt(c)`
+and is checked in to version control at mozilla-central under
+`toolkit/components/telemetry/tests/marionette/tests/client <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/tests/marionette/tests/client/>`_.
+
+Test Main Tab Scalars
+---------------------
+
+- PATH: ``telemetry/tests/marionette/tests/client/test_main_tab_scalars.py``
+- This test opens and closes a number of browser tabs,
+ restarts the browser in a new session
+ and then verifies the correctness of scalar data in the resulting `main` ping.
+
+Test Search Counts
+------------------
+
+- PATH: ``toolkit/telemetry/tests/marionette/tests/client/test_search_counts_across_subsessions.py``
+- This test performs a search in a new tab,
+ restarts Firefox in a new session and verifies the correctness of client, session and subsession IDs,
+ as well as scalar and keyed histogram data in the `shutdown` ping,
+ installs an addon, verifies the `environment-change` ping, and performs three additional search actions
+ before restarting and verifying the new `main` ping.
+
+
+Test Deletion Request Ping
+--------------------------
+
+- PATH: ``toolkit/telemetry/tests/marionette/tests/client/test_deletion_request_ping.py``
+- This test installs an addon and verifies a ping is received. The test takes note of the client ID.
+ It then disables telemetry and checks for a `deletion-request` ping.
+ After it receives the correct ping it makes sure that no other pings are sent.
+ Telemetry is then re-enabled and the `main` ping is checked to see if the client ID has changed.
+ The test asserts that the user has opted back in to telemetry.
+
+Test Event Ping
+---------------
+
+- PATH: ``toolkit/telemetry/tests/marionette/tests/client/test_event_ping.py``
+- This test checks for a basic `event` ping. It opens firefox, performs a search and checks the `event`
+ ping for the correct number of searches performed (1) and the correct search engine.
+
+Test Fog Custom Ping
+--------------------
+
+- PATH: ``toolkit/telemetry/tests/marionette/tests/client/test_fog_custom_ping.py``
+- This test creates a custom ping using the Glean API and asserts this ping is sent correctly.
+
+Test Fog Deletion Request Ping
+------------------------------
+
+- PATH: ``toolkit/telemetry/tests/marionette/tests/client/test_fog_deletion_request_ping.py``
+- This test opens the browser, performs a search and disables telemetry after the search.
+ It asserts that the telemetry is disabled and no pings exist.
+ The browser is restarted and telemetry is then re-enabled.
+ Then we set a `debug tag <https://mozilla.github.io/glean/book/user/debugging/debug-ping-view.html>`_
+ which is attached to the ping.
+ Telemetry is then disabled again to trigger a `deletion-request` ping.
+ We verify that 1) The debug tag is present; and 2) that the client ID
+ in the second `deletion-request` ping is different from the first client ID.
+
+Test Fog User Activity
+----------------------
+
+- PATH: ``toolkit/telemetry/tests/marionette/tests/client/test_fog_user_activity.py``
+- This test checks that a `baseline` ping is sent when the user starts or stops using Firefox.
+
+Test Background Update Ping
+---------------------------
+
+- PATH: ``toolkit/telemetry/tests/marionette/tests/client/test_fog_user_activity.py``
+- In this test we launch Firefox to prepare a profile and to disable the background update setting.
+ We exit Firefox,
+ leaving the (unlocked) profile to be used as the default profile for the background update task (and not having multiple instances running).
+ The task will not try to update, but it will send a ping.
+ Then we restart Firefox to unwind the background update setting and allow shutdown to proceed cleanly.
+
+Running the tests locally
+-------------------------
+
+You can run the tests on your local machine using
+`mach <https://firefox-source-docs.mozilla.org/mach/index.html>`__:
+
+``./mach telemetry-tests-client``
+
+Running the tests on try
+------------------------
+
+You can run the tests across all platforms on the try server using
+`mach <https://firefox-source-docs.mozilla.org/mach/index.html>`__:
+
+``./mach try fuzzy -q "'telemetry-tests-client"``
+
+Disabling an individual failing test
+------------------------------------
+
+The telemetry-tests-client suite is implemented in Python and uses Marionette for browser automation and wptserve for the HTTP ping server.
+The integration tests are based on Python's unittest testing library and can be disabled by calling
+`self.skipTest("reason") <https://docs.python.org/3/library/unittest.html#skipping-tests-and-expected-failures>`_ in a test method.
+
+The example below demonstrates how to disable test_main_ping2:
+
+.. code-block:: python
+
+ import unittest
+
+ from telemetry_harness.testcase import TelemetryTestCase
+
+ class TestMainPingExample(TelemetryTestCase):
+ """Example tests for the telemetry main ping."""
+
+ def test_main_ping1(self):
+ """Example test that we want to run."""
+
+ self.search_in_new_tab("mozilla firefox")
+
+ def test_main_ping2(self):
+ """Example test that we want to skip."""
+
+ self.skipTest("demonstrating skipping")
+
+ self.search_in_new_tab("firefox telemetry")
+
+
+Who to contact for help
+-----------------------
+
+- The test cases are owned by Chris Hutten-Czapski (chutten on matrix) from the Firefox Telemetry team
+ (`#telemetry <https://chat.mozilla.org/#/room/#telemetry:mozilla.org>`__ on matrix)
+- The test harness is owned by Raphael Pierzina (raphael on matrix) from the Ecosystem Test Engineering team
+ (`#telemetry <https://chat.mozilla.org/#/room/#telemetry:mozilla.org>`__ on matrix)
+
+Bugzilla
+--------
+
+Bugs can be filed under the Toolkit product for the Telemetry component.
diff --git a/toolkit/components/telemetry/docs/internals/mentored-bugs.rst b/toolkit/components/telemetry/docs/internals/mentored-bugs.rst
new file mode 100644
index 0000000000..bdc2de96b2
--- /dev/null
+++ b/toolkit/components/telemetry/docs/internals/mentored-bugs.rst
@@ -0,0 +1,49 @@
+==========================
+Template for Mentored Bugs
+==========================
+
+We like to encourage external contributions to the Firefox code base and the Telemetry module specifically.
+In order to set up a mentored bug, you can use the following template.
+Post it as a comment and add relevant steps in part 3.
+
+.. code-block:: md
+
+ To help Mozilla out with this bug, here's the steps:
+
+ 1. Comment here on the bug that you want to volunteer to help.
+ This will tell others that you're working on the next steps.
+ 2. [Download and build the Firefox source code](https://firefox-source-docs.mozilla.org/setup/index.html)
+ * If you have any problems, please ask on
+ [Element/Matrix](https://chat.mozilla.org/#/room/#introduction:mozilla.org)
+ in the `#introduction` channel. They're there to help you get started.
+ * You can also read the
+ [Firefox Contributors' Quick Reference](https://firefox-source-docs.mozilla.org/contributing/contribution_quickref.html),
+ which has answers to most development questions.
+ 3. Start working on this bug. <SPECIFIC STEPS RELEVANT TO THIS BUG>
+ * If you have any problems with this bug,
+ please comment on this bug and set the needinfo flag for me.
+ Also, you can find me and my teammates on the `#telemetry` channel on
+ [Element/Matrix](https://chat.mozilla.org/#/room/#telemetry:mozilla.org)
+ most hours of most days.
+ 4. Build your change with `mach build` and test your change with
+ `mach test toolkit/components/telemetry/tests/`.
+ Also check your changes for adherence to our style guidelines by using `mach lint`
+ 5. Submit the patch (including an automated test, if applicable) for review.
+ Mark me as a reviewer so I'll get an email to come look at your code.
+ * [Getting your code reviewed](https://firefox-source-docs.mozilla.org/setup/contributing_code.html#getting-your-code-reviewed)
+ * This is when the bug will be assigned to you.
+ 6. After a series of reviews and changes to your patch,
+ I'll mark it for checkin or push it to autoland.
+ Your code will soon be shipping to Firefox users worldwide!
+ 7. ...now you get to think about what kind of bug you'd like to work on next.
+ Let me know what you're interested in and I can help you find your next contribution.
+
+
+Don't forget to add yourself as a :code:`Mentor` on the bug,
+and add these tags to the :code:`Whiteboard`:
+
+* Add :code:`[lang=<language>]` to show what languages solving this bug will involve.
+* Add one of :code:`[good first bug]`, :code:`[good second bug]`, :code:`[good next bug]`
+ to indicate for whom this bug might be a good point for contribution.
+
+If this is a Good First Bug, be sure to also add the :code:`good-first-bug` :code:`Keyword`.
diff --git a/toolkit/components/telemetry/docs/internals/pingsender.rst b/toolkit/components/telemetry/docs/internals/pingsender.rst
new file mode 100644
index 0000000000..be60f699ff
--- /dev/null
+++ b/toolkit/components/telemetry/docs/internals/pingsender.rst
@@ -0,0 +1,36 @@
+Ping Sender
+===========
+
+The ping sender is a minimalistic program whose sole purpose is to deliver a
+telemetry ping. It accepts the following parameters:
+
+- the URL the ping will be sent to (as an HTTP POST command);
+- the path to an uncompressed file holding the ping contents.
+
+Once the ping has been read from disk the ping sender will try to post it once, exiting
+with a non-zero value if it fails. If sending the ping succeeds then the ping file is removed.
+
+The content of the HTTP request is *gzip* encoded. The request comes with a few
+additional headers:
+
+- ``User-Agent: pingsender/1.0``
+- ``X-PingSender-Version: 1.0``. Even if this data is already included by the user agent, this
+ header is needed as the pipeline is not currently storing use agent strings and doing that
+ could require storing a fair chunk of redundant extra data. We need to discern between pings
+ sent using the ping sender and the ones sent using the normal flow, at the end of the
+ ingestion pipeline, for validation purposes.
+
+.. note::
+
+ The ping sender relies on libcurl for Linux and Mac build and on WinInet for
+ Windows ones for its HTTP functionality. It currently ignores Firefox or the
+ system proxy configuration.
+
+In non-debug mode the ping sender doesn't print anything, not even on error,
+this is done deliberately to prevent startling the user on architectures such
+as Windows that would open a separate console window just to display the
+program output. If you need runtime information to be printed out compile the
+ping sender with debugging enabled.
+
+The pingsender is not supported on Firefox for Android
+(see `bug 1335917 <https://bugzilla.mozilla.org/show_bug.cgi?id=1335917>`_)
diff --git a/toolkit/components/telemetry/docs/internals/preferences.rst b/toolkit/components/telemetry/docs/internals/preferences.rst
new file mode 100644
index 0000000000..0c63ae031d
--- /dev/null
+++ b/toolkit/components/telemetry/docs/internals/preferences.rst
@@ -0,0 +1,280 @@
+Preferences and Defines
+=======================
+
+Telemetry behaviour is controlled through the mozconfig defines and preferences listed here.
+
+mozconfig Defines
+-----------------
+
+``MOZ_TELEMETRY_REPORTING``
+
+ When Defined (which it is for official builds):
+
+ * If ``RELEASE_OR_BETA`` is not defined, defines ``MOZ_TELEMETRY_ON_BY_DEFAULT``
+
+ When Not Defined:
+
+ * If ``datareporting.healthreport.uploadEnabled`` is locked, we print a message in the Privacy settings that you cannot turn on data submission and disabled the checkbox so you don't try.
+ * Android: hides the data submission UI to prevent users from thinking they can turn it on
+ * Disables Telemetry from being sent (due to ``Telemetry::IsOfficialTelemetry``)
+
+``MOZ_TELEMETRY_ON_BY_DEFAULT``
+
+ When Defined:
+
+ * Android: enables ``toolkit.telemetry.enabled``
+
+``MOZ_SERVICES_HEALTHREPORT``
+
+ When Defined (which it is on most platforms):
+
+ * Sets ``datareporting.healthreport.{infoURL|uploadEnabled}`` in ``modules/libpref/init/all.js``.
+
+``MOZ_DATA_REPORTING``
+
+ When Defined (which it is when ``MOZ_TELEMETRY_REPORTING``, ``MOZ_SERVICES_HEALTHREPORT``, or ``MOZ_CRASHREPORTER`` is defined (so, on most platforms, but not typically on developer builds)):
+
+ * Enables ``app.shield.optoutstudies.enabled``
+
+ When Not Defined:
+
+ * Disables ``app.shield.optoutstudies.enabled``
+ * Removes parts of the Data Collection Preferences UI in ``privacy.xhtml``
+
+``MOZILLA_OFFICIAL``
+
+ When Not Defined (defined on our own external builds and builds from several Linux distros, but not typically on defeloper builds):
+
+ * Disables Telemetry from being sent (due to ``Telemetry::IsOfficialTelemetry``)
+
+``MOZ_UPDATE_CHANNEL``
+
+ When not ``release`` or ``beta``:
+
+ * If ``MOZ_TELEMETRY_REPORTING`` is also defined, defines ``MOZ_TELEMETRY_ON_BY_DEFAULT``
+
+ When ``beta``:
+
+ * If ``toolkit.telemetry.enabled`` is otherwise unset at startup, ``toolkit.telemetry.enabled`` is defaulted to ``true`` (this is irrespective of ``MOZ_TELEMETRY_REPORTING``)
+
+ When ``nightly`` or ``aurora`` or ``beta`` or ``default``:
+
+ * Desktop: Locks ``toolkit.telemetry.enabled`` to ``true``. All other values for ``MOZ_UPDATE_CHANNEL`` on Desktop locks ``toolkit.telemetry.enabled`` to ``false``.
+ * Desktop: Defaults ``Telemetry::CanRecordExtended`` (and, thus ``Telemetry::CanRecordReleaseData``) to ``true``. All other values of ``MOZ_UPDATE_CHANNEL`` on Desktop defaults these to ``false``.
+
+``DEBUG``
+
+ When Defined:
+
+ * Disables Telemetry from being sent (due to ``Telemetry::IsOfficialTelemetry``)
+
+**In Short:**
+
+ For builds downloaded from mozilla.com ``MOZ_TELEMETRY_REPORTING`` is defined, ``MOZ_TELEMETRY_ON_BY_DEFAULT`` is on if you downloaded Nightly or Developer Edition, ``MOZ_SERVICES_HEALTHREPORT`` is defined, ``MOZ_DATA_REPORTING`` is defined, ``MOZILLA_OFFICIAL`` is defined, ``MOZ_UPDATE_CHANNEL`` is set to the channel you downloaded, and ``DEBUG`` is false. This means Telemetry is, by default, collecting some amount of information and is sending it to Mozilla.
+
+ For builds you make yourself with a blank mozconfig, ``MOZ_UPDATE_CHANNEL`` is set to ``default`` and everything else is undefined. This means Telemetry is, by default, collecting an extended amount of information but isn't sending it anywhere.
+
+Preferences
+-----------
+
+``toolkit.telemetry.unified``
+
+ This controls whether unified behavior is enabled. If true:
+
+ * Telemetry is always enabled and recording *base* data.
+ * Telemetry will send additional ``main`` pings.
+
+ It defaults to ``true``, but is ``false`` on Android (Fennec) builds.
+
+``toolkit.telemetry.enabled``
+
+ If ``unified`` is off, this controls whether the Telemetry module is enabled. It can be set or unset via the `Preferences` dialog in Firefox for Android (Fennec).
+ If ``unified`` is on, this is locked to ``true`` if ``MOZ_UPDATE_CHANNEL`` is ``nightly`` or ``aurora`` or ``beta`` or ``default`` (which is the default value of ``MOZ_UPDATE_CHANNEL`` for developer builds). Otherwise it is locked to ``false``. This controls a diminishing number of things and is intended to be deprecated, and then removed.
+
+``datareporting.healthreport.uploadEnabled``
+
+ If ``unified`` is true, this controls whether we send Telemetry data.
+ If ``unified`` is false, we don't use this value.
+
+``toolkit.telemetry.archive.enabled``
+
+ Allow pings to be archived locally. This can only be enabled if ``unified`` is on.
+
+``toolkit.telemetry.server``
+
+ The server Telemetry pings are sent to. Change requires restart.
+
+``toolkit.telemetry.log.level``
+
+ This sets the Telemetry logging verbosity per ``Log.sys.mjs``. The available levels, in descending order of verbosity, are ``Trace``, ``Debug``, ``Config``, ``Info``, ``Warn``, ``Error`` and ``Fatal`` with the default being ``Warn``.
+
+ By default logging goes only the console service.
+
+``toolkit.telemetry.log.dump``
+
+ Sets whether to dump Telemetry log messages to ``stdout`` too.
+
+``toolkit.telemetry.shutdownPingSender.enabled``
+
+ Allow the ``shutdown`` ping to be sent when the browser shuts down, from the second browsing session on, instead of the next restart, using the :doc:`ping sender <pingsender>`.
+
+``toolkit.telemetry.shutdownPingSender.enabledFirstSession``
+
+ Allow the ``shutdown`` ping to be sent using the :doc:`ping sender <pingsender>` from the first browsing session.
+
+``toolkit.telemetry.firstShutdownPing.enabled``
+
+ Allow a duplicate of the ``main`` shutdown ping from the first browsing session to be sent as a separate ``first-shutdown`` ping.
+
+``toolkit.telemetry.newProfilePing.enabled``
+
+ Enable the :doc:`../data/new-profile-ping` on new profiles.
+
+``toolkit.telemetry.newProfilePing.delay``
+
+ Controls the delay after which the :doc:`../data/new-profile-ping` is sent on new profiles.
+
+``toolkit.telemetry.updatePing.enabled``
+
+ Enable the :doc:`../data/update-ping` on browser updates.
+
+``toolkit.telemetry.eventping.minimumFrequency``
+
+ The minimum frequency at which an :doc:`../data/event-ping` will be sent.
+ Default is 60 (minutes).
+
+``toolkit.telemetry.eventping.maximumFrequency``
+
+ The maximum frequency at which an :doc:`../data/event-ping` will be sent.
+ Default is 10 (minutes).
+
+``toolkit.telemetry.overrideUpdateChannel``
+
+ Override the ``channel`` value that is reported via Telemetry.
+ This is useful for distinguishing different types of builds that otherwise still report as the same update channel.
+
+``toolkit.telemetry.ipcBatchTimeout``
+
+ How long, in milliseconds, we batch accumulations from child processes before
+ sending them to the parent process.
+ Default is 2000 (milliseconds).
+
+``toolkit.telemetry.pioneerId``
+
+ If a user has opted into the Pioneer program, this will contain their Pioneer ID.
+
+Data-choices notification
+-------------------------
+
+``toolkit.telemetry.reportingpolicy.firstRun``
+
+ This preference is not present until the first run. After, its value is set to false. This is used to show the infobar with a more aggressive timeout if it wasn't shown yet.
+
+``datareporting.policy.firstRunURL``
+
+ If set, a browser tab will be opened on first run instead of the infobar.
+
+``datareporting.policy.dataSubmissionEnabled``
+
+ This is the data submission master kill switch. If disabled, no policy is shown or upload takes place, ever.
+
+``datareporting.policy.dataSubmissionPolicyNotifiedTime``
+
+ Records the date user was shown the policy. This preference is also used on Android.
+
+``datareporting.policy.dataSubmissionPolicyAcceptedVersion``
+
+ Records the version of the policy notified to the user. This preference is also used on Android.
+
+``datareporting.policy.dataSubmissionPolicyBypassNotification``
+
+ Used in tests, it allows to skip the notification check.
+
+``datareporting.policy.currentPolicyVersion``
+
+ Stores the current policy version, overrides the default value defined in TelemetryReportingPolicy.sys.mjs.
+
+``datareporting.policy.minimumPolicyVersion``
+
+ The minimum policy version that is accepted for the current policy. This can be set per channel.
+
+``datareporting.policy.minimumPolicyVersion.channel-NAME``
+
+ This is the only channel-specific version that we currently use for the minimum policy version.
+
+GeckoView
+---------
+
+``toolkit.telemetry.geckoview.streaming``
+
+ Whether the GeckoView mode we're running in is the variety that uses the :doc:`GeckoView Streaming Telemetry API <../internals/geckoview-streaming>` or not.
+ Defaults to false.
+
+``toolkit.telemetry.geckoview.batchDurationMS``
+
+ The duration in milliseconds over which :doc:`GeckoView Streaming Telemetry <../internals/geckoview-streaming>` will batch accumulations before passing it on to its delegate.
+ Defaults to 5000.
+
+``toolkit.telemetry.geckoview.maxBatchStalenessMS``
+
+ The maximum time (in milliseconds) between flushes of the
+ :doc:`GeckoView Streaming Telemetry <../internals/geckoview-streaming>`
+ batch to its delegate.
+ Defaults to 60000.
+
+Testing
+-------
+
+The following prefs are for testing purpose only.
+
+``toolkit.telemetry.initDelay``
+
+ Delay before initializing telemetry (seconds).
+
+``toolkit.telemetry.minSubsessionLength``
+
+ Minimum length of a telemetry subsession and throttling time for common environment changes (seconds).
+
+``toolkit.telemetry.collectInterval``
+
+ Minimum interval between data collection (seconds).
+
+``toolkit.telemetry.scheduler.tickInterval``
+
+ Interval between scheduler ticks (seconds).
+
+``toolkit.telemetry.scheduler.idleTickInterval``
+
+ Interval between scheduler ticks when the user is idle (seconds).
+
+``toolkit.telemetry.idleTimeout``
+
+ Timeout until we decide whether a user is idle or not (seconds).
+
+``toolkit.telemetry.modulesPing.interval``
+
+ Interval between "modules" ping transmissions.
+
+``toolkit.telemetry.send.overrideOfficialCheck``
+
+ If true, allows sending pings on unofficial builds. Requires a restart.
+
+``toolkit.telemetry.testing.overridePreRelease``
+
+ If true, allows recording opt-in Telemetry on the Release channel. Requires a restart.
+
+``toolkit.telemetry.untrustedModulesPing.frequency``
+
+ Interval, in seconds, between "untrustedModules" ping transmissions.
+
+``toolkit.telemetry.healthping.enabled``
+
+ If false, sending health pings is disabled. Defaults to true.
+
+``toolkit.telemetry.testing.disableFuzzingDelay``
+
+ If true, ping sending is not delayed when sending between 0am and 1am local time.
+
+``toolkit.telemetry.testing.overrideProductsCheck``
+
+ If true, allow all probes to be recorded no matter what the current product is.
diff --git a/toolkit/components/telemetry/docs/internals/review.rst b/toolkit/components/telemetry/docs/internals/review.rst
new file mode 100644
index 0000000000..80a3bd57de
--- /dev/null
+++ b/toolkit/components/telemetry/docs/internals/review.rst
@@ -0,0 +1,144 @@
+===========================
+Telemetry review guidelines
+===========================
+
+General guidelines for reviewing changes
+========================================
+
+These are the general principles we follow when reviewing changes.
+
+- *Be constructive.* Both reviewers and patch authors should be allies that aim to get the change landed together.
+- *Consider the impact.* We deliver critical data that is processed and used by many systems and people. Any disruption should be planned and intentional.
+- *Be diligent.* All changes should be tested under typical conditions.
+- *Know your limits.* Defer to other peers or experts where sensible.
+
+Main considerations for any change
+========================================
+
+For any change, these are the fundamental questions that we always need satisfactory answers for.
+
+- Does this have a plan?
+
+ - Is there a specific need to do this?
+ - Does this change need `a proposal <https://github.com/mozilla/Fx-Data-Planning/blob/master/process/ProposalProcess.md>`_ first?
+ - Do we need to announce this before we do this? (e.g. for `deprecations <https://github.com/mozilla/Fx-Data-Planning/blob/master/process/Deprecation.md>`_)
+
+- Does this involve the right people?
+
+ - Does this change need input from... A data engineer? A data scientist?
+ - Does this change need data review?
+
+- Is this change complete?
+
+ - Does this change have sufficient test coverage?
+ - Does this change have sufficient documentation?
+
+- Do we need follow-ups?
+
+ - Do we need to file validation bugs? Or other follow-up bugs?
+ - Do we need to communicate this to our users? Or other groups?
+
+Additional considerations
+=========================
+
+Besides the basic considerations above, these are additional detailed considerations that help with reviewing changes.
+
+Considerations for all changes
+------------------------------
+
+- Follow our standards and best practices.
+
+ - Firefox Desktop:
+
+ - :ref:`The Mozilla coding style <Coding style>`
+ - `The toolkit code review guidelines <https://wiki.mozilla.org/Toolkit/Code_Review>`_
+
+ - Mobile:
+
+ - `Android/Kotlin code style <https://kotlinlang.org/docs/reference/coding-conventions.html>`_
+ - `iOS/Swift code style <https://github.com/mozilla-mobile/firefox-ios/wiki/Swift-Style-Guides>`_
+
+- Does this impact performance significantly?:
+
+ - Don't delay application initialisation (unless absolutely necessary).
+ - Don't ever block on network requests.
+ - Make longer tasks async whenever feasible.
+
+- Does this affect products more broadly than expected?
+
+ - Consider all our platforms: Windows, Mac, Linux, Android.
+ - Consider all our products: Firefox, Fennec, GeckoView, Glean.
+
+- Does this fall afoul of common architectural failures?
+
+ - Prefer APIs that take non-String types unless writing a parser.
+
+- Sanity checking:
+
+ - How does this behave in a release build? Have you tested this?
+ - Does this change contain test coverage? We require test coverage for every new code, changes and bug fixes.
+
+- Does this need documentation updates?
+
+ - To the :ref:`in-tree docs <Telemetry>`?
+ - To the `firefox-data-docs <https://docs.telemetry.mozilla.org/>`_ (`repository <https://github.com/mozilla/firefox-data-docs>`_)?
+ - To the `glean documentation <https://github.com/mozilla-mobile/android-components/tree/master/components/service/glean>`_?
+
+- Following up:
+
+ - Do we have a validation bug filed yet?
+ - Do all TODOs have follow-up bugs filed?
+ - Do we need to communicate this to our users?
+
+ - `fx-data-dev <https://mail.mozilla.org/listinfo/fx-data-dev>`_ (Main Firefox data list)
+ - `firefox-dev <https://mail.mozilla.org/listinfo/firefox-dev>`_ (Firefox application developers)
+ - `dev-platform <https://lists.mozilla.org/listinfo/dev-platform>`_ (Gecko / platform developers)
+ - `mobile-firefox-dev <https://mail.mozilla.org/listinfo/mobile-firefox-dev>`_ (Mobile developers)
+ - fx-team (Firefox staff)
+
+ - Do we need to communicate this to other groups?
+
+ - Data engineering, data science, data stewards, ...?
+
+Consider the impact on others
+-----------------------------
+
+- Could this change break upstream pipeline jobs?
+
+ - Does this change the format of outgoing data in an unhandled way?
+
+ - E.g. by adding, removing, or changing the type of a non-metric payload field.
+
+ - Does this require ping schema updates?
+ - Does this break jobs that parse the registry files for metrics? (Scalars.yaml, metrics.yaml, etc.)
+
+- Do we need to involve others?
+
+ - Changes to data formats, ping contents, ping semantics etc. require involving a data engineer.
+ - Changes to any outgoing data that is in active use require involving the stakeholders (e.g. data scientists).
+
+Considerations for Firefox Desktop
+----------------------------------
+
+- For profiles:
+
+ - How does using different profiles affect this?
+ - How does switching between profiles affect this?
+ - What happens when users switch between different channels?
+
+- Footguns:
+
+ - Does this have side-effects on Fennec? (Unified Telemetry is off there, so behavior is pretty different.)
+ - Is your code gated on prefs, build info, channels? Tests should cover that.
+ - If test is gated on isUnified, code should be too (and vice-versa)
+
+ - Test for the other case
+
+ - Any code using `new Date()` should get additional scrutiny
+ - Code using `new Date()` should be using Policy so it can be mocked
+ - Tests using `new Date()` should use specific dates, not the current one
+
+ - How does this impact Build Faster support/Artifact builds/Dynamic builtin scalars or events? Will this be testable by others on artifact builds?
+ - We work in the open: Does the change include words that might scare end users?
+ - How does this handle client id resets?
+ - How does this handle users opting out of data collection?
diff --git a/toolkit/components/telemetry/docs/internals/tests.rst b/toolkit/components/telemetry/docs/internals/tests.rst
new file mode 100644
index 0000000000..58adbb94af
--- /dev/null
+++ b/toolkit/components/telemetry/docs/internals/tests.rst
@@ -0,0 +1,99 @@
+Tests
+=====
+
+A high-level test strategy for Firefox Telemetry is defined in the
+`Test Strategy document <https://docs.google.com/document/d/1Mi6va3gE4HSv5LjXNREvMa2V4q-LKIFDTwA2o4yeo_c/edit>`_.
+
+Firefox Telemetry is a complicated and old component.
+So too are the organization and expanse of its tests.
+Let’s break them down by harness.
+
+Unless otherwise mentioned the tests live in subdirectories of
+``toolkit/components/telemetry/tests``.
+
+Mochitest
+---------
+:Location: ``t/c/t/t/browser/``
+:Language: Javascript
+ (`mochitest <https://firefox-source-docs.mozilla.org/testing/mochitest-plain>`__)
+
+This test harness runs nearly the entire Firefox and gives access to multiple tabs and browser chrome APIs.
+It requires window focus to complete correctly,
+so it isn’t recommended to add new tests here.
+The tests that are here maybe would be more at home as telemetry-tests-client tests as they tend to be integration tests.
+
+Google Test
+-----------
+:Location: ``t/c/t/t/gtest/``
+:Language: C++
+ (`googletest <https://github.com/google/googletest>`_)
+
+This test harness runs a specially-built gtest shell around libxul which allows you to write unit tests against public C++ APIs.
+It should be used to test the C++ API and core of Firefox Telemetry.
+This is for tests like
+“Do we correctly accumulate to bucket 0 if I pass -1 to ``Telemetry::Accumulate``?”
+
+Integration Tests (telemetry-tests-client and telemetry-integration-tests)
+--------------------------------------------------------------------------
+:Location: ``t/c/t/t/marionette/tests/client`` and ``t/c/t/t/integration/``
+:Language: Python
+ (`unittest <https://docs.python.org/3/library/unittest.html>`__,
+ `pytest <https://docs.pytest.org/en/latest/>`_)
+
+The most modern of the test harnesses,
+telemetry-integration-tests uses marionette to puppet the entire browser allowing us to write integration tests that include ping servers and multiple browser runs.
+You should use this if you’re testing Big Picture things like
+“Does Firefox resend its “deletion-request” ping if the network is down when Telemetry is first disabled?”.
+
+At time of writing there are two “editions” of integration tests.
+Prefer writing new tests in telemetry-tests-client
+(the unittest-based one in ``t/c/t/t/marionette/tests/client``)
+while we evaluate CI support for telemetry-integration-tests.
+
+More info: :doc:`./integration_tests/index`
+
+Definitions Files Tests
+-----------------------
+:Location: ``t/c/t/t/python``
+:Language: Python
+ (`unittest <https://docs.python.org/3/library/unittest.html>`__)
+
+This harness pulls in the parsers and scripts used to turn JSON and YAML probe definitions into code.
+It should be used to test the build scripts and formats of the definitions files
+Histograms.json, Scalars.yaml, and Events.yaml.
+This is for tests like
+“Does the build fail if someone forgot to put in a bug number for a new Histogram?”.
+
+xpcshell
+--------
+:Location: ``t/c/t/t/unit``
+:Language: Javascript
+ (`xpcshell <https://firefox-source-docs.mozilla.org/testing/xpcshell>`__)
+
+This test harness uses a stripped-down shell of the Firefox browser to run privileged Javascript.
+It should be used to write unit tests for the Javascript API and app-level logic of Firefox Telemetry.
+This is for tests like
+“Do we correctly accumulate to bucket 0 if I pass -1 to ``Telemetry.getHistogramById(...).add``?”
+and
+“Do we reschedule pings that want to be sent near local midnight?”.
+
+Since these tests are easy to write and quick to run we have in the past bent this harness in a few interesting shapes
+(see PingServer)
+to have it support integration tests as well.
+New integration tests should use telemetry-tests-client instead.
+
+Instrumentation Tests
+---------------------
+:Location: Various
+:Language: Usually Javascript
+ (`xpcshell <https://firefox-source-docs.mozilla.org/testing/xpcshell>`__ or
+ `mochitest <https://firefox-source-docs.mozilla.org/testing/mochitest-plain>`__)
+
+In addition to the tests of Firefox Telemetry,
+other code owners have written tests that ensure that their code records appropriate values to Telemetry.
+They should use the
+``toolkit/components/telemetry/tests/unit/TelemetryTestUtils.sys.mjs``
+module to make their lives easier.
+This can be used for tests like
+“If five bookmarks are read from the database,
+does the bookmark count Histogram have a value of 5 in it?”.
diff --git a/toolkit/components/telemetry/docs/obsolete/activation-ping.rst b/toolkit/components/telemetry/docs/obsolete/activation-ping.rst
new file mode 100644
index 0000000000..a2c241aec4
--- /dev/null
+++ b/toolkit/components/telemetry/docs/obsolete/activation-ping.rst
@@ -0,0 +1,69 @@
+
+"activation" ping (obsolete)
+============================
+
+This mobile-specific ping is intendend to track activations of distributions of mobile products
+with a small error rate.
+
+This will be sent at Startup. Minimally, we want to get this ping at least once from every client.
+
+Submission will be per the Edge server specification::
+
+ /submit/mobile/activation/v/docId
+
+This is a modern “structure ingestion” ping (the namespace is not telemetry). For structured
+ingestion, we capture the schema version as one of the URI parameters, so we don’t need to
+include it in the body of the message.
+
+* ``v`` is the ping format version
+* ``docId`` is a UUID for deduping
+
+Structure:
+
+.. code-block:: js
+
+ {
+ "identifier": <string>, // Googled Ad ID hashed using bcrypt
+ "clientId": <string>, // client id, e.g. "c641eacf-c30c-4171-b403-f077724e848a"
+ //included only if identifier was unabled to be retrieved
+ "manufacturer": <string>, // Build.MANUFACTURER
+ "model": <string>, // Build.MODEL
+ "locale": <string>, // application locale, e.g. "en-US"
+ "os": <string>, // OS name.
+ "osversion": <string>, // OS version.
+ "created": <string>, // date the ping was created
+ // in local time, "yyyy-mm-dd"
+ "tz": <integer>, // timezone offset (in minutes) of the
+ // device when the ping was created
+ "app_name": <string>, // "Fennec"
+ "channel": <string>, // Android package name e.g. "org.mozilla.firefox"
+ "distributionId": <string> // Distribution identifier (optional)
+ }
+
+
+Field details
+-------------
+
+identifier
+~~~~~~~~~~
+The ``identifier`` field is the Google Ad ID hashed using bcrypt. Ideally we want to send this instead of the
+client_id but not all distributions have Google Play Services enabled.
+
+client_id
+~~~~~~~~~~
+The ``client_id`` field represents the telemetry client id and it is only included if the identifier is empty.
+
+channel
+~~~~~~~
+The ``channel`` field represents the Android package name.
+
+Version history
+---------------
+* v1: initial version - shipped in `Fennec 68 <https://bugzilla.mozilla.org/show_bug.cgi?id=1534451>`_.
+
+Android implementation notes
+----------------------------
+On Android, the uploader has a high probability of delivering the complete data
+for a given client but not a 100% probability. This was a conscious decision to
+keep the code simple. Even if we drop a ping, it will be resent on future startups
+until we have confirmation that it has been uploaded.
diff --git a/toolkit/components/telemetry/docs/obsolete/core-ping.rst b/toolkit/components/telemetry/docs/obsolete/core-ping.rst
new file mode 100644
index 0000000000..6fee237805
--- /dev/null
+++ b/toolkit/components/telemetry/docs/obsolete/core-ping.rst
@@ -0,0 +1,510 @@
+
+"core" ping (obsolete)
+======================
+
+This mobile-specific ping is intended to provide the most critical
+data in a concise format, allowing for frequent uploads.
+
+Since this ping is used to measure retention, it should be sent
+each time the browser is opened.
+
+Submission will be per the Edge server specification::
+
+ /submit/telemetry/docId/docType/appName/appVersion/appUpdateChannel/appBuildID
+
+* ``docId`` is a UUID for deduping
+* ``docType`` is “core”
+* ``appName`` is “Fennec”
+* ``appVersion`` is the version of the application (e.g. "46.0a1")
+* ``appUpdateChannel`` is “release”, “beta”, etc.
+* ``appBuildID`` is the build number
+
+Note: Counts below (e.g. search & usage times) are “since the last
+ping”, not total for the whole application lifetime.
+
+Structure:
+
+.. code-block::
+
+ {
+ "v": 10, // ping format version
+ "clientId": <string>, // client id, e.g.
+ // "c641eacf-c30c-4171-b403-f077724e848a"
+ "seq": <positive integer>, // running ping counter, e.g. 3
+ "locale": <string>, // application locale, e.g. "en-US"
+ "os": <string>, // OS name.
+ "osversion": <string>, // OS version.
+ "device": <string>, // Build.MANUFACTURER + " - " + Build.MODEL
+ // where manufacturer is truncated to 12 characters
+ // & model is truncated to 19 characters
+ "arch": <string>, // e.g. "arm", "x86"
+ "profileDate": <pos integer>, // Profile creation date in days since
+ // UNIX epoch.
+ "defaultSearch": <string>, // Identifier of the default search engine,
+ // e.g. "yahoo".
+ "displayVersion": <string>, // Version displayed to user, e.g. 57.0b3 (optional)
+ "distributionId": <string>, // Distribution identifier (optional)
+ "campaignId": <string>, // Adjust's campaign identifier (optional)
+ "created": <string>, // date the ping was created
+ // in local time, "yyyy-mm-dd"
+ "tz": <integer>, // timezone offset (in minutes) of the
+ // device when the ping was created
+ "sessions": <integer>, // number of sessions since last upload
+ "durations": <integer>, // combined duration, in seconds, of all
+ // sessions since last upload
+ "searches": <object>, // Optional, object of search use counts in the
+ // format: { "engine.source": <pos integer> }
+ // e.g.: { "yahoo.suggestion": 3, "other.listitem": 1 }
+ "experiments": [<string>, /* … */], // Optional, array of identifiers
+ // for the active experiments
+ "accessibilityServices": [<string>, /* … */], // Optional, array of identifiers for
+ // enabled accessibility services that
+ // interact with our android products.
+ "flashUsage": <integer>, // number of times flash plugin is played since last upload
+ "defaultBrowser": <boolean> // true if the user has set Firefox as default browser
+ "bug_1501329_affected": <boolean> // true if Firefox previously used canary clientId
+ // when submitting telemetry
+ "fennec": <object> // Fennec only.
+ // Block of a variety of fields of different types.
+ // Used to understand the usage of Fennec features in the release population
+ // to understand when Fenix is ready to support Fennec users.
+ {
+ "new_tab": {
+ "top_sites_clicked": <int>, // Number of times a Top Site was opened from the Awesome Screen.
+ // Resets after each sent core ping.
+ "pocket_stories_clicked": <int>, // Number of time a Pocket Recommended website was opened
+ // from the Awesome Screen.
+ // Resets after each sent core ping.
+ }
+ "settings_advanced": {
+ "restore_tabs": <boolean>, // State of the "Settings/Advanced/Restore Tabs" setting
+ "show_images": <string>, // State of the "Settings/Advanced/Show images" setting
+ // Value will be be "user-specified" for any non-default values
+ "show_web_fonts": <boolean>, // State of the "Settings/Advanced/Show web fonts" setting
+ },
+ "settings_general": {
+ "full_screen_browsing": <boolean>, // Current state of the
+ // "Settings/General/Full-screen browsing" setting.
+ "tab_queue": <boolean>, // State of the "Settings/General/Tab queue" setting.
+ "tab_queue_usage_count": <int>, // Number of tabs opened through Tab Queue.
+ // Resets after each sent core ping.
+ "compact_tabs": <boolean>, // State of the "Settings/General/Compact tabs" setting.
+ "homepage": {
+ "custom_homepage": <boolean>, // "true" if not "about:home".
+ "custom_homepage_use_for_newtab": <boolean>, // If the "Settings/General/Home/Also use for new tabs"
+ // setting is enabled.
+ "topsites_enabled": <boolean>, // If the "Settings/General/Home/Top Sites"
+ // setting is set to "Show".
+ "pocket_enabled": <boolean>, // If the "Settings/General/Home/Top Sites/Recommended by Pocket"
+ // setting is enabled.
+ "recent_bookmarks_enabled": <boolean>, // If the "Settings/General/Home/Top Sites/
+ // Additional Content/Recent Bookmarks"
+ // setting is enabled.
+ "visited_enabled": <boolean>, // If the "Settings/General/Home/Top Sites/Additional Content/Visited"
+ // setting is enabled.
+ bookmarks_enabled": <boolean>, // If the "Settings/General/Home/Bookmarks" setting is set to "Show".
+ "history_enabled": <boolean>, // If the "Settings/General/Home/History" setting is set to "Show".
+ }
+ },
+ "settings_privacy": {
+ "do_not_track": <boolean>, // If the "Settings/Privacy/Do not track" is enabled.
+ "master_password": <boolean>, // If the "Settings/Privacy/Use master password" is enabled.
+ "master_password_usage_count": <int>, // Number of times the user has entered their master password.
+ // Resets after each sent core ping.
+ },
+ "settings_notifications": {
+ "product_feature_tips": <boolean>, // If the "Settings/Notifications/Product and feature tips"
+ // setting is enabled.
+ },
+ "addons": {
+ "active": [addon_id_1, addon_id_2, …, ], // From all installed addons, which ones are active.
+ "disabled": [addon_id_1, addon_id_2, …], // From all installed addons, which ones are disabled.
+ },
+ "page_options": {
+ "save_as_pdf": <int>, // Number of times the user has used "Page/Save to PDF".
+ // Resets after each sent core ping.
+ "print": <int>, // Number of times the user has used the "Page/Print".
+ // Resets after each sent core ping.
+ "total_added_search_engines": <int>, // The absolute number of user added search engines,
+ // not just those added during this session.
+ "total_sites_pinned_to_topsites": <int>, // The absolute number of times the user has used
+ // the "Pin Site" functionality.
+ // Not just those added during this session.
+ "view_source": <int>, // Number of times the user has used the "Page/View Page Source".
+ // Resets after each sent core ping.
+ "bookmark_with_star": <int>, // The number of times the user has used the "Menu / <Star>".
+ // Resets after each sent core ping.
+ "current_pwas_count": <int>, // On Android >=25 - a positive number of PWAs currently on
+ // homescreen, installed from this app.
+ // On Android <25 - a default of "-1".
+ },
+ "sync": {
+ "only_over_wifi": <boolean>, // "true" if the "Settings/Sync/Sync only over Wi-Fi"
+ // setting is enabled.
+ // null if the user is not signed into Sync.
+ }
+ }
+ }
+
+Field details
+-------------
+
+device
+~~~~~~
+The ``device`` field is filled in with information specified by the hardware
+manufacturer. As such, it could be excessively long and use excessive amounts
+of limited user data. To avoid this, we limit the length of the field. We're
+more likely have collisions for models within a manufacturer (e.g. "Galaxy S5"
+vs. "Galaxy Note") than we are for shortened manufacturer names so we provide
+more characters for the model than the manufacturer.
+
+distributionId
+~~~~~~~~~~~~~~
+The ``distributionId`` contains the distribution ID as specified by
+preferences.json for a given distribution. More information on distributions
+can be found `here <https://wiki.mozilla.org/Mobile/Distribution_Files>`_.
+
+It is optional.
+
+campaignId
+~~~~~~~~~~~~~~
+The ``campaignId`` contains the campaign identifier like '3ly8t0'.
+It's generated by `Adjust <https://docs.adjust.com/en/tracker-generation/#segmenting-users-dynamically-with-campaign-structure-parameters>`_,
+It can only used to identify a campaign, but can't target to a specific user.
+
+It is optional because not everyone has a campaign to begin with.
+
+defaultSearch
+~~~~~~~~~~~~~
+On Android, this field may be ``null``. To get the engine, we rely on
+``SearchEngineManager#getDefaultEngine``, which searches in several places in
+order to find the search engine identifier:
+
+* Shared Preferences
+* The distribution (if it exists)
+* The localized default engine
+
+If the identifier could not be retrieved, this field is ``null``. If the
+identifier is retrieved, we attempt to create an instance of the search
+engine from the search plugins (in order):
+
+* In the distribution
+* From the localized plugins shipped with the browser
+* The third-party plugins that are installed in the profile directory
+
+If the plugins fail to create a search engine instance, this field is also
+``null``.
+
+This field can also be ``null`` when a custom search engine is set as the
+default.
+
+sessions & durations
+~~~~~~~~~~~~~~~~~~~~
+On Android, a session is the time when Firefox is focused in the foreground.
+`sessions` tracks the number of sessions since the last upload and
+`durations` is the accumulated duration in seconds of all of these
+sessions. Note that showing a dialog (including a Firefox dialog) will
+take Firefox out of focus & end the current session.
+
+An implementation that records a session when Firefox is completely hidden is
+preferable (e.g. to avoid the dialog issue above), however, it's more complex
+to implement and so we chose not to, at least for the initial implementation.
+
+profileDate
+~~~~~~~~~~~
+On Android, this value is created at profile creation time and retrieved or,
+for legacy profiles, taken from the package install time (note: this is not the
+same exact metric as profile creation time but we compromised in favor of ease
+of implementation).
+
+Additionally on Android, this field may be ``null`` in the unlikely event that
+all of the following events occur:
+
+#. The times.json file does not exist
+#. The package install date could not be persisted to disk
+
+The reason we don't just return the package install time even if the date could
+not be persisted to disk is to ensure the value doesn't change once we start
+sending it: we only want to send consistent values.
+
+searches
+~~~~~~~~
+This describes the search engine usage(count). The format is { "<engine identifier>.<source>"" : count }
+This is optional because the users may have never used the search feature.
+There's no difference if extended telemetry is enabled (prerelease builds) or not.
+
+Possible value :
+
+.. code-block:: js
+
+ {
+ "yahoo.listitem":2,
+ "duckduckgo.listitem":1,
+ "google.suggestion":1
+ }
+
+**<engine identifier>**: the identifier of the the search engine. The identifier is collected the way same as desktop.
+we only record the search engine name when:
+
+* builtin or suggested search engines with an ID (includes partner search engines in various distribution scenarios).
+ If it's not a built-in engine, we show "null" or "other".
+* If the user has "Health Report" and core ping enabled.
+
+**<sources>**: it's from one of the 'method's in UI telemetry. Possible values:
+
+* actionbar: the user types in the url bar and hits enter to use the default
+ search engine
+* listitem: the user selects a search engine from the list of secondary search
+ engines at the bottom of the screen
+* suggestion: the user clicks on a search suggestion or, in the case that
+ suggestions are disabled, the row corresponding with the main engine
+
+accessibilityServices
+~~~~~~~~~~~~~~~~~~~~~
+This describes which accessibility services are currently enabled on user's device and could be interacting with our
+products. This is optional because users often do not have any accessibility services enabled. If present, the value is
+a list of accessibility service ids.
+
+fennec.new_tab.top_sites_clicked
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `top_sites_clicked` field contains the number of times a top site was
+opened from the new tab page since the last time the core ping was sent.
+This counter is reset when the core ping has been sent.
+
+
+Fennec.new_tab.pocket_stories_clicked
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `pocket_stories_clicked` contains the number of times a pocket story was
+opened from the new tab page since the last time the core ping was sent.
+This counter is reset when the core ping has been sent.
+
+Fennec.settings_advanced.restore_tabs
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `restore_tabs` field contains state of the "Settings/Advanced/Restore Tabs"
+setting. It is true for "Always Restore" and false for "Don’t restore after
+quitting Firefox".
+The value is determined at the time of sending the core ping.
+
+Fennec.settings_advanced.show_images
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `show_images` field contains the state of the
+"Settings/Advanced/Show images" settings.
+It is a string value set to "default" if the setting is "Always", or
+"user~specified" for any of the other options.
+The value is determined at the time of sending the core ping.
+
+Fennec.settings_advanced.show_web_fonts
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `show_web_fonts` field is a boolean that contains the current state of the
+"Settings/Advanced/Show web fonts" setting.
+The value is determined at the time of sending the core ping.
+
+Fennec.settings_general.full_screen_browsing
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `full_screen_browsing` field is a boolean that contains the current state
+of the "Settings/General/Full~screen browsing" setting.
+The value is determined at the time of sending the core ping.
+
+Fennec.settings_general.tab_queue
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `tab_queue` field is a boolean that contains the current state of the
+"Settings/General/Tab queue" setting.
+The value is determined at the time of sending the core ping.
+
+Fennec.settings_general.tab_queue_usage_count
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `tab_queue_usage_count` is a counter that increments with the number of
+tabs opened through the tab queue.
+It contains the total number of queued tabs opened since the last time the
+Core Ping was sent.
+This counter is reset when the core ping has been sent.
+
+Fennec.settings_general.compact_tabs
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `compact_tabs` field is a boolean that contains the current state of the
+"Settings/General/Compact tabs" setting.
+The value is determined at the time of sending the core ping.
+
+Fennec.settings_general.homepage.custom_homepage
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `custom_homepage` field is set to true if the homepage is not set to the
+the default `about:home`.
+The value is determined at the time of sending the core ping.
+
+Fennec.settings_general.homepage.custom_homepage_use_for_newtab
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `custom_homepage_use_for_newtab` field is set to true if the
+"Settings/General/Home/Also use for new tabs" setting is enabled.
+The value is determined at the time of sending the core ping.
+
+Fennec.settings_general.homepage.topsites_enabled
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `topsites_enabled` setting is true if the "Settings/General/Home/Top Sites"
+setting is set to "Show".
+The value is determined at the time of sending the core ping.
+
+Fennec.settings_general.homepage.pocket_enabled
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `pocket_enabled` setting is true if the
+"Settings/General/Home/Top Sites/Recommended by Pocket" setting is enabled.
+The value is determined at the time of sending the core ping.
+
+Fennec.settings_general.homepage.recent_bookmarks_enabled
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `recent_bookmarks_enabled` setting is true if the
+"Settings/General/Home/Top Sites/Additional Content/Recent Bookmarks" setting
+is enabled.
+The value is determined at the time of sending the core ping.
+
+Fennec.settings_general.homepage.visited_enabled
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `visited_enabled` setting is true if the
+"Settings/General/Home/Top Sites/Additional Content/Visited" setting is
+enabled.
+The value is determined at the time of sending the core ping.
+
+Fennec.settings_general.homepage.bookmarks_enabled
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `bookmarks_enabled` setting is true if the
+"Settings/General/Home/Bookmarks" setting is set to "Show".
+The value is determined at the time of sending the core ping.
+
+Fennec.settings_general.homepage.history_enabled
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `history_enabled` setting is true if the "Settings/General/Home/History"
+setting is set to "Show".
+The value is determined at the time of sending the core ping.
+
+Fennec.settings_privacy.do_not_track
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `do_not_track` setting is true if the "Settings/Privacy/Do not track" is
+enabled.
+The value is determined at the time of sending the core ping.
+
+Fennec.settings_privacy.master_password
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `master_password` setting is true if the
+"Settings/Privacy/Use master password" is enabled.
+The value is determined at the time of sending the core ping.
+
+Fennec.settings_privacy.master_password_usage_count
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `master_password_usage_count` field contains the number of times the user
+has entered their master password since the last time the core ping was sent.
+This counter is reset when the core ping has been sent.
+
+Fennec.settings_notifications.product_feature_tips
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `product_feature_tips` setting is true if the
+"Settings/Notifications/Product and feature tips" setting is enabled.
+The value is determined at the time of sending the core ping.
+
+fennec.page_options.save_as_pdf
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `save_as_pdf` field contains the number of times the user has used the
+"Page/Save to PDF" feature since the last time the core ping was sent.
+This counter is reset when the core ping has been sent.
+
+fennec.page_options.print
+~~~~~~~~~~~~~~~~~~~~~~~~~
+The `print` field contains the number of times the user has used the
+"Page/Print" feature since the last time the core ping was sent.
+This counter is reset when the core ping has been sent.
+
+fennec.page_options.total_added_search_engines
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `total_added_search_engines` is an absolute value that contains the number
+of search engines the user has added manually.
+The value is determined at the time of sending the core ping and never reset
+to zero.
+
+fennec.page_options.total_sites_pinned_to_topsites
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `total_sites_pinned_to_topsites` is an absolute value that contains the
+number of sites the user has pinned to top sites.
+The value is determined at the time of sending the core ping and never reset
+to zero.
+
+fennec.page_options.view_source
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `view_source` field contains the number of times the user has used the
+"Page/View Page Source" feature since the last time the core ping was sent.
+This counter is reset when the core ping has been sent.
+
+Fennec.page_options.bookmark_with_star
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `bookmark_with_star` field contains the number of times the user has used
+the "Menu / <Star>"" feature since the last time the core ping was sent.
+This counter is reset when the core ping has been sent.
+
+Fennec.page_options.current_pwas_count
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `current_pwas_count` field contains the number of currently installed PWAs
+from this application.
+As Android APIs for querying this are only available on Android >=25 for lower
+versions of Android the value of this key will be "-1".
+The value is determined at the time of sending the core ping.
+
+Fennec.sync.only_over_wifi
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+The `only_over_wifi` setting is true if the
+"Settings/Sync/Sync only over Wi~Fi" setting is enabled.
+The value is determined at the time of sending the core ping.
+If the user is not signed into sync, then this value is set to `null`.
+The value is determined at the time of sending the core ping.
+
+Other parameters
+----------------
+
+HTTP "Date" header
+~~~~~~~~~~~~~~~~~~
+This header is used to track the submission date of the core ping in the format
+specified by
+`rfc 2616 sec 14.18 <https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.18>`_,
+et al (e.g. "Tue, 01 Feb 2011 14:00:00 GMT").
+
+
+Version history
+---------------
+* v10: added ``bug_1501329_affected``
+* v9:
+
+ - Apr 2017: changed ``arch`` to contain device arch rather than the one we
+ built against & ``accessibilityServices``
+ - Dec 2017: added ``defaultBrowser`` to know if the user has set Firefox as
+ default browser (Dec 2017)
+ - May 2018: added (optional) ``displayVersion`` to distinguish Firefox beta versions easily
+
+* v8: added ``flashUsage``
+* v7: added ``sessionCount`` & ``sessionDuration`` & ``campaignId``
+* v6: added ``searches``
+* v5: added ``created`` & ``tz``
+* v4: ``profileDate`` will return package install time when times.json is not available
+* v3: added ``defaultSearch``
+* v2: added ``distributionId``
+* v1: initial version - shipped in `Fennec 45 <https://bugzilla.mozilla.org/show_bug.cgi?id=1205835>`_.
+
+Notes
+~~~~~
+
+* ``distributionId`` (v2) actually landed after ``profileDate`` (v4) but was
+ uplifted to 46, whereas ``profileDate`` landed on 47. The version numbers in
+ code were updated to be increasing (bug 1264492) and the version history docs
+ rearranged accordingly.
+
+Android implementation notes
+----------------------------
+On Android, the uploader has a high probability of delivering the complete data
+for a given client but not a 100% probability. This was a conscious decision to
+keep the code simple. The cases where we can lose data:
+
+* Resetting the field measurements (including incrementing the sequence number)
+ and storing a ping for upload are not atomic. Android can kill our process
+ for memory pressure in between these distinct operations so we can just lose
+ a ping's worth of data. That sequence number will be missing on the server.
+* If we exceed some number of pings on disk that have not yet been uploaded,
+ we remove old pings to save storage space. For those pings, we will lose
+ their data and their sequence numbers will be missing on the server.
+
+Note: we never expect to drop data without also dropping a sequence number so
+we are able to determine when data loss occurs.
diff --git a/toolkit/components/telemetry/docs/obsolete/deletion-ping.rst b/toolkit/components/telemetry/docs/obsolete/deletion-ping.rst
new file mode 100644
index 0000000000..dfa7fefa00
--- /dev/null
+++ b/toolkit/components/telemetry/docs/obsolete/deletion-ping.rst
@@ -0,0 +1,26 @@
+
+"deletion" ping (obsolete)
+==========================
+
+This ping is generated when a user turns off FHR upload from the Preferences panel, changing the related ``datareporting.healthreport.uploadEnabled`` preference. This requests that all associated data from that user be deleted.
+
+This ping contains the client id and no environment data.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ version: 4,
+ type: "deletion",
+ ... common ping data
+ clientId: <UUID>,
+ payload: { }
+ }
+
+Version History
+---------------
+
+- Firefox 63:
+
+ - Replaced by "optout" ping (`bug 1445921 <https://bugzilla.mozilla.org/show_bug.cgi?id=1445921>`_).
diff --git a/toolkit/components/telemetry/docs/obsolete/ecosystem-telemetry.rst b/toolkit/components/telemetry/docs/obsolete/ecosystem-telemetry.rst
new file mode 100644
index 0000000000..e9902ff89c
--- /dev/null
+++ b/toolkit/components/telemetry/docs/obsolete/ecosystem-telemetry.rst
@@ -0,0 +1,109 @@
+Ecosystem Telemetry (obsolete)
+==============================
+
+This module transmits Ecosystem Telemetry from Firefox Desktop.
+It is only sent for Firefox Account users, using a single ping type
+"account-ecosystem"
+
+.. note::
+
+ You might like to read the `background information on Ecosystem
+ Telemetry <https://mozilla.github.io/ecosystem-platform/docs/features/firefox-accounts/ecosystem-telemetry/>`_
+
+The existing telemetry client id is **not** submitted with the ping, but an
+"ecosystem client id" is - this has the same semantics as the existing
+client id, although is a different value, and is not sent in any other ping.
+
+An anonymized user ID is submitted with each ping - `read more about these
+IDs and how they're designed to safeguard user privacy <https://mozilla.github.io/ecosystem-platform/docs/features/firefox-accounts/ecosystem-telemetry/>`_
+
+A reduced Telemetry environment is submitted in the ping, as described below.
+
+Environment
+-----------
+
+In an effort to reduce the possibility of fingerprinting, we only provide the
+following environment subset:
+
+.. code-block:: js
+
+ {
+ settings: {
+ locale: <string>, // e.g. "it", null on failure
+ },
+ system: {
+ memoryMB: <number>,
+ os: {
+ name: <string>, // e.g. "Windows_NT", null on failure
+ version: <string>, // e.g. "6.1", null on failure
+ locale: <string>, // "en" or null on failure
+ },
+ cpu: {
+ speedMHz: <number>, // cpu clock speed in MHz
+ }
+ },
+ profile: {
+ creationDate: <integer>, // integer days since UNIX epoch, e.g. 16446
+ firstUseDate: <integer>, // integer days since UNIX epoch, e.g. 16446 - optional
+ }
+ }
+
+account-ecosystem ping
+----------------------
+
+.. code-block:: js
+
+ {
+ "type": "account-ecosystem",
+ ... common ping data
+ "environment": { ... }, // as above
+ "payload": {
+ "reason": <string>, // Why the ping was submitted
+ "ecosystemAnonId": <string>, // The anonymized ID, as described above.
+ "ecosystemClientId": <guid>, // The ecosystem client ID as described above.
+ "duration": <number>, // duration since ping was last sent or since the beginning of the Firefox session in seconds
+ "histograms": {...},
+ "keyedHistograms": {...},
+ "scalars": {...},
+ "keyedScalars": {...},
+ }
+ }
+
+reason
+~~~~~~
+The ``reason`` field contains the information about why the "account-ecosystem" ping was submitted:
+
+* ``periodic`` - Sent roughly every 24 hours
+* ``shutdown`` - Sent on shutdown
+* ``logout`` - Sent when the user logs out
+
+histograms and keyedHistograms
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+This section contains the :doc:`../collection/histograms` that are valid for the account-ecosystem ping, per process.
+The recorded histograms are described in `Histograms.json <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/Histograms.json>`_, marked with the `account-ecosystem` store.
+
+scalars and keyedScalars
+~~~~~~~~~~~~~~~~~~~~~~~~
+This section contains the :doc:`../collection/scalars` that are valid for the account-ecosystem ping, per process.
+Scalars are only submitted if data was added to them.
+The recorded scalars are described in `Scalars.yaml <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/Scalars.yaml>`_, marked with the `account-ecosystem` store.
+
+Send behavior
+-------------
+
+Without an account
+~~~~~~~~~~~~~~~~~~
+
+Never.
+
+When a user logs into Firefox Accounts, this ping is submitted as described in
+"With an account" below. No ping is immediately sent.
+
+With an account
+~~~~~~~~~~~~~~~
+
+The ping is submitted; roughly every 24 hours with reason *periodic*. On
+shutdown this ping is submitted with reason *shutdown*.
+
+If the user logs out and disconnects the account, this ping is submitted with
+reason *logout*. While logged out, no pings will be submitted.
diff --git a/toolkit/components/telemetry/docs/obsolete/fhr/architecture.rst b/toolkit/components/telemetry/docs/obsolete/fhr/architecture.rst
new file mode 100644
index 0000000000..2e9c37f3d3
--- /dev/null
+++ b/toolkit/components/telemetry/docs/obsolete/fhr/architecture.rst
@@ -0,0 +1,226 @@
+.. _healthreport_architecture:
+
+============
+Architecture
+============
+
+``healthreporter.jsm`` contains the main interface for FHR, the
+``HealthReporter`` type. An instance of this is created by the
+``data_reporting_service``.
+
+``providers.jsm`` contains numerous ``Metrics.Provider`` and
+``Metrics.Measurement`` used for collecting application metrics. If you
+are looking for the FHR probes, this is where they are.
+
+Storage
+=======
+
+Firefox Health Report stores data in 3 locations:
+
+* Metrics measurements and provider state is stored in a SQLite database
+ (via ``Metrics.Storage``).
+* Service state (such as the IDs of documents uploaded) is stored in a
+ JSON file on disk (via OS.File).
+* Lesser state and run-time options are stored in preferences.
+
+Preferences
+===========
+
+Preferences controlling behavior of Firefox Health Report live in the
+``datareporting.healthreport.*`` branch.
+
+Service and Data Control
+------------------------
+
+The follow preferences control behavior of the service and data upload.
+
+service.enabled
+ Controls whether the entire health report service runs. The overall
+ service performs data collection, storing, and submission.
+
+ This is the primary kill switch for Firefox Health Report
+ outside of the build system variable. i.e. if you are using an
+ official Firefox build and wish to disable FHR, this is what you
+ should set to false to prevent FHR from not only submitting but
+ also collecting data.
+
+uploadEnabled
+ Whether uploading of data is enabled. This is the preference the
+ checkbox in the preferences UI reflects. If this is
+ disabled, FHR still collects data - it just doesn't upload it.
+
+service.loadDelayMsec
+ How long (in milliseconds) after initial application start should FHR
+ wait before initializing.
+
+ FHR may initialize sooner than this if the FHR service is requested.
+ This will happen if e.g. the user goes to ``about:healthreport``.
+
+service.loadDelayFirstRunMsec
+ How long (in milliseconds) FHR should wait to initialize on first
+ application run.
+
+ FHR waits longer than normal to initialize on first application run
+ because first-time initialization can use a lot of I/O to initialize
+ the SQLite database and this I/O should not interfere with the
+ first-run user experience.
+
+documentServerURI
+ The URI of a Bagheera server that FHR should interface with for
+ submitting documents.
+
+ You typically do not need to change this.
+
+documentServerNamespace
+ The namespace on the document server FHR should upload documents to.
+
+ You typically do not need to change this.
+
+infoURL
+ The URL of a page containing more info about FHR, it's privacy
+ policy, etc.
+
+about.reportUrl
+ The URL to load in ``about:healthreport``.
+
+about.reportUrlUnified
+ The URL to load in ``about:healthreport``. This is used instead of ``reportUrl`` for UnifiedTelemetry when it is not opt-in.
+
+service.providerCategories
+ A comma-delimited list of category manager categories that contain
+ registered ``Metrics.Provider`` records. Read below for how provider
+ registration works.
+
+If the entire service is disabled, you lose data collection. This means
+that **local** data analysis won't be available because there is no data
+to analyze! Keep in mind that Firefox Health Report can be useful even
+if it's not submitting data to remote servers!
+
+Logging
+-------
+
+The following preferences allow you to control the logging behavior of
+Firefox Health Report.
+
+logging.consoleEnabled
+ Whether to write log messages to the web console. This is true by
+ default.
+
+logging.consoleLevel
+ The minimum log level FHR messages must have to be written to the
+ web console. By default, only FHR warnings or errors will be written
+ to the web console. During normal/expected operation, no messages of
+ this type should be produced.
+
+logging.dumpEnabled
+ Whether to write log messages via ``dump()``. If true, FHR will write
+ messages to stdout/stderr.
+
+ This is typically only enabled when developing FHR.
+
+logging.dumpLevel
+ The minimum log level messages must have to be written via
+ ``dump()``.
+
+State
+-----
+
+currentDaySubmissionFailureCount
+ How many submission failures the client has encountered while
+ attempting to upload the most recent document.
+
+lastDataSubmissionFailureTime
+ The time of the last failed document upload.
+
+lastDataSubmissionRequestedTime
+ The time of the last document upload attempt.
+
+lastDataSubmissionSuccessfulTime
+ The time of the last successful document upload.
+
+nextDataSubmissionTime
+ The time the next data submission is scheduled for. FHR will not
+ attempt to upload a new document before this time.
+
+pendingDeleteRemoteData
+ Whether the client currently has a pending request to delete remote
+ data. If true, the client will attempt to delete all remote data
+ before an upload is performed.
+
+FHR stores various state in preferences.
+
+Registering Providers
+=====================
+
+Firefox Health Report providers are registered via the category manager.
+See ``HealthReportComponents.manifest`` for providers defined in this
+directory.
+
+Essentially, the category manager receives the name of a JS type and the
+URI of a JSM to import that exports this symbol. At run-time, the
+providers registered in the category manager are instantiated.
+
+Providers are registered via the category manager to make registration
+simple and less prone to errors. Any XPCOM component can create a
+category manager entry. Therefore, new data providers can be added
+without having to touch core Firefox Health Report code. Additionally,
+category manager registration means providers are more likely to be
+registered on FHR's terms, when it wants. If providers were registered
+in code at application run-time, there would be the risk of other
+components prematurely instantiating FHR (causing a performance hit if
+performed at an inopportune time) or semi-complicated code around
+observers or listeners. Category manager entries are only 1 line per
+provider and leave FHR in control: they are simple and safe.
+
+Document Generation and Lifecycle
+=================================
+
+FHR will attempt to submit a JSON document containing data every 24 wall
+clock hours.
+
+At upload time, FHR will query the database for **all** information from
+the last 180 days and assemble this data into a JSON document. We
+attempt to upload this JSON document with a client-generated UUID to the
+configured server.
+
+Before we attempt upload, the generated UUID is stored in the JSON state
+file on local disk. At this point, the client assumes the document with
+that UUID has been successfully stored on the server.
+
+If the client is aware of other document UUIDs that presumably exist on
+the server, those UUIDs are sent with the upload request so the client
+can request those UUIDs be deleted. This helps ensure that each client
+only has 1 document/UUID on the server at any one time.
+
+Importance of Persisting UUIDs
+------------------------------
+
+The choices of how, where, and when document UUIDs are stored and updated
+are very important. One should not attempt to change things unless she
+has a very detailed understanding of why things are the way they are.
+
+The client is purposefully very conservative about forgetting about
+generated UUIDs. In other words, once a UUID is generated, the client
+deliberately holds on to that UUID until it's very confident that UUID
+is no longer stored on the server. The reason we do this is because
+*orphaned* documents/UUIDs on the server can lead to faulty analysis,
+such as over-reporting the number of Firefox installs that stop being
+used.
+
+When uploading a new UUID, we update the state and save the state file
+to disk *before* an upload attempt because if the upload succeeds but
+the response never makes it back to the client, we want the client to
+know about the uploaded UUID so it can delete it later to prevent an
+orphan.
+
+We maintain a list of UUIDs locally (not simply the last UUID) because
+multiple upload attempts could fail the same way as the previous
+paragraph describes and we have no way of knowing which (if any)
+actually succeeded. The safest approach is to assume every document
+produced managed to get uploaded some how.
+
+We store the UUIDs on a file on disk and not anywhere else because we
+want storage to be robust. We originally stored UUIDs in preferences,
+which only flush to disk periodically. Writes to preferences were
+apparently getting lost. We switched to writing directly to files to
+eliminate this window.
diff --git a/toolkit/components/telemetry/docs/obsolete/fhr/dataformat.rst b/toolkit/components/telemetry/docs/obsolete/fhr/dataformat.rst
new file mode 100644
index 0000000000..730d7514b8
--- /dev/null
+++ b/toolkit/components/telemetry/docs/obsolete/fhr/dataformat.rst
@@ -0,0 +1,1998 @@
+.. _healthreport_dataformat:
+
+==============
+Payload Format
+==============
+
+Currently, the Firefox Health Report is submitted as a compressed JSON
+document. The root JSON element is an object. A *version* field defines
+the version of the payload which in turn defines the expected contents
+the object.
+
+As of 2013-07-03, desktop submits Version 2, and Firefox for Android submits
+Version 3 payloads.
+
+Version 3
+=========
+
+Version 3 is a complete rebuild of the document format. Events are tracked in
+an "environment". Environments are computed from a large swath of local data
+(e.g., add-ons, CPU count, versions), and a new environment comes into being
+when one of its attributes changes.
+
+Client documents, then, will include descriptions of many environments, and
+measurements will be attributed to one particular environment.
+
+A map of environments is present at the top level of the document, with the
+current named "current" in the map. Each environment has a hash identifier and
+a set of attributes. The current environment is completely described, and has
+its hash present in a "hash" attribute. All other environments are represented
+as a tree diff from the current environment, with their hash as the key in the
+"environments" object.
+
+A removed add-on has the value 'null'.
+
+There is no "last" data at present.
+
+Daily data is hierarchical: by day, then by environment, and then by
+measurement, and is present in "data", just as in v2.
+
+Leading by example::
+
+ {
+ "lastPingDate": "2013-06-29",
+ "thisPingDate": "2013-07-03",
+ "version": 3,
+ "environments": {
+ "current": {
+ "org.mozilla.sysinfo.sysinfo": {
+ "memoryMB": 1567,
+ "cpuCount": 4,
+ "architecture": "armeabi-v7a",
+ "_v": 1,
+ "version": "4.1.2",
+ "name": "Android"
+ },
+ "org.mozilla.profile.age": {
+ "_v": 1,
+ "profileCreation": 15827
+ },
+ "org.mozilla.addons.active": {
+ "QuitNow@TWiGSoftware.com": {
+ "appDisabled": false,
+ "userDisabled": false,
+ "scope": 1,
+ "updateDay": 15885,
+ "foreignInstall": false,
+ "hasBinaryComponents": false,
+ "blocklistState": 0,
+ "type": "extension",
+ "installDay": 15885,
+ "version": "1.18.02"
+ },
+ "{dbbf9331-b713-6eda-1006-205efead09dc}": {
+ "appDisabled": false,
+ "userDisabled": "askToActivate",
+ "scope": 8,
+ "updateDay": 15779,
+ "foreignInstall": true,
+ "blocklistState": 0,
+ "type": "plugin",
+ "installDay": 15779,
+ "version": "11.1 r115"
+ },
+ "desktopbydefault@bnicholson.mozilla.org": {
+ "appDisabled": false,
+ "userDisabled": true,
+ "scope": 1,
+ "updateDay": 15870,
+ "foreignInstall": false,
+ "hasBinaryComponents": false,
+ "blocklistState": 0,
+ "type": "extension",
+ "installDay": 15870,
+ "version": "1.1"
+ },
+ "{6e092a7f-ba58-4abb-88c1-1a4e50b217e4}": {
+ "appDisabled": false,
+ "userDisabled": false,
+ "scope": 1,
+ "updateDay": 15828,
+ "foreignInstall": false,
+ "hasBinaryComponents": false,
+ "blocklistState": 0,
+ "type": "extension",
+ "installDay": 15828,
+ "version": "1.1.0"
+ },
+ "{46551EC9-40F0-4e47-8E18-8E5CF550CFB8}": {
+ "appDisabled": false,
+ "userDisabled": true,
+ "scope": 1,
+ "updateDay": 15879,
+ "foreignInstall": false,
+ "hasBinaryComponents": false,
+ "blocklistState": 0,
+ "type": "extension",
+ "installDay": 15879,
+ "version": "1.3.2"
+ },
+ "_v": 1
+ },
+ "org.mozilla.appInfo.appinfo": {
+ "_v": 3,
+ "appLocale": "en_us",
+ "osLocale": "en_us",
+ "distribution": "",
+ "acceptLangIsUserSet": 0,
+ "isTelemetryEnabled": 1,
+ "isBlocklistEnabled": 1
+ },
+ "geckoAppInfo": {
+ "updateChannel": "nightly",
+ "id": "{aa3c5121-dab2-40e2-81ca-7ea25febc110}",
+ "os": "Android",
+ "platformBuildID": "20130703031323",
+ "platformVersion": "25.0a1",
+ "vendor": "Mozilla",
+ "name": "fennec",
+ "xpcomabi": "arm-eabi-gcc3",
+ "appBuildID": "20130703031323",
+ "_v": 1,
+ "version": "25.0a1"
+ },
+ "hash": "tB4Pnnep9yTxnMDymc3dAB2RRB0=",
+ "org.mozilla.addons.counts": {
+ "extension": 4,
+ "plugin": 1,
+ "_v": 1,
+ "theme": 0
+ }
+ },
+ "k2O3hlreMeS7L1qtxeMsYWxgWWQ=": {
+ "geckoAppInfo": {
+ "platformBuildID": "20130630031138",
+ "appBuildID": "20130630031138",
+ "_v": 1
+ },
+ "org.mozilla.appInfo.appinfo": {
+ "_v": 2,
+ }
+ },
+ "1+KN9TutMpzdl4TJEl+aCxK+xcw=": {
+ "geckoAppInfo": {
+ "platformBuildID": "20130626031100",
+ "appBuildID": "20130626031100",
+ "_v": 1
+ },
+ "org.mozilla.addons.active": {
+ "QuitNow@TWiGSoftware.com": null,
+ "{dbbf9331-b713-6eda-1006-205efead09dc}": null,
+ "desktopbydefault@bnicholson.mozilla.org": null,
+ "{6e092a7f-ba58-4abb-88c1-1a4e50b217e4}": null,
+ "{46551EC9-40F0-4e47-8E18-8E5CF550CFB8}": null,
+ "_v": 1
+ },
+ "org.mozilla.addons.counts": {
+ "extension": 0,
+ "plugin": 0,
+ "_v": 1
+ }
+ }
+ },
+ "data": {
+ "last": {},
+ "days": {
+ "2013-07-03": {
+ "tB4Pnnep9yTxnMDymc3dAB2RRB0=": {
+ "org.mozilla.appSessions": {
+ "normal": [
+ {
+ "r": "P",
+ "d": 2,
+ "sj": 653
+ },
+ {
+ "r": "P",
+ "d": 22
+ },
+ {
+ "r": "P",
+ "d": 5
+ },
+ {
+ "r": "P",
+ "d": 0
+ },
+ {
+ "r": "P",
+ "sg": 3560,
+ "d": 171,
+ "sj": 518
+ },
+ {
+ "r": "P",
+ "d": 16
+ },
+ {
+ "r": "P",
+ "d": 1079
+ }
+ ],
+ "_v": "4"
+ }
+ },
+ "k2O3hlreMeS7L1qtxeMsYWxgWWQ=": {
+ "org.mozilla.appSessions": {
+ "normal": [
+ {
+ "r": "P",
+ "d": 27
+ },
+ {
+ "r": "P",
+ "d": 19
+ },
+ {
+ "r": "P",
+ "d": 55
+ }
+ ],
+ "_v": "4"
+ },
+ "org.mozilla.searches.counts": {
+ "bartext": {
+ "google": 1
+ },
+ "_v": "4"
+ },
+ "org.mozilla.experiment": {
+ "lastActive": "some.experiment.id"
+ "_v": "1"
+ }
+ }
+ }
+ }
+ }
+ }
+
+App sessions in Version 3
+-------------------------
+
+Sessions are divided into "normal" and "abnormal". Session objects are stored as discrete JSON::
+
+ "org.mozilla.appSessions": {
+ _v: 4,
+ "normal": [
+ {"r":"P", "d": 123},
+ ],
+ "abnormal": [
+ {"r":"A", "oom": true, "stopped": false}
+ ]
+ }
+
+Keys are:
+
+"r"
+ reason. Values are "P" (activity paused), "A" (abnormal termination).
+"d"
+ duration. Value in seconds.
+"sg"
+ Gecko startup time (msec). Present if this is a clean launch. This
+ corresponds to the telemetry timer *FENNEC_STARTUP_TIME_GECKOREADY*.
+"sj"
+ Java activity init time (msec). Present if this is a clean launch. This
+ corresponds to the telemetry timer *FENNEC_STARTUP_TIME_JAVAUI*,
+ and includes initialization tasks beyond initial
+ *onWindowFocusChanged*.
+
+Abnormal terminations will be missing a duration and will feature these keys:
+
+"oom"
+ was the session killed by an OOM exception?
+"stopped"
+ was the session stopped gently?
+
+Version 3.2
+-----------
+
+As of Firefox 35, the search counts measurement is now bumped to v6, including the *activity* location for the search activity.
+
+Version 3.1
+-----------
+
+As of Firefox 27, *appinfo* is now bumped to v3, including *osLocale*,
+*appLocale* (currently always the same as *osLocale*), *distribution* (a string
+containing the distribution ID and version, separated by a colon), and
+*acceptLangIsUserSet*, an integer-boolean that describes whether the user set
+an *intl.accept_languages* preference.
+
+The search counts measurement is now at version 5, which indicates that
+non-partner searches are recorded. You'll see identifiers like "other-Foo Bar"
+rather than "other".
+
+
+Version 3.2
+-----------
+
+In Firefox 32, Firefox for Android includes a device configuration section
+in the environment description::
+
+ "org.mozilla.device.config": {
+ "hasHardwareKeyboard": false,
+ "screenXInMM": 58,
+ "screenLayout": 2,
+ "uiType": "default",
+ "screenYInMM": 103,
+ "_v": 1,
+ "uiMode": 1
+ }
+
+Of these, the only keys that need explanation are:
+
+uiType
+ One of "default", "smalltablet", "largetablet".
+uiMode
+ A mask of the Android *Configuration.uiMode* value, e.g.,
+ *UI_MODE_TYPE_CAR*.
+screenLayout
+ A mask of the Android *Configuration.screenLayout* value. One of the
+ *SCREENLAYOUT_SIZE_* constants.
+
+Note that screen dimensions can be incorrect due to device inaccuracies and platform limitations.
+
+Other notable differences from Version 2
+----------------------------------------
+
+* There is no default browser indicator on Android.
+* Add-ons include a *blocklistState* attribute, as returned by AddonManager.
+* Searches are now version 4, and are hierarchical: how the search was started
+ (bartext, barkeyword, barsuggest), and then counts per provider.
+
+Version 2
+=========
+
+Version 2 is the same as version 1 with the exception that it has an additional
+top-level field, *geckoAppInfo*, which contains basic application info.
+
+geckoAppInfo
+------------
+
+This field is an object that is a simple map of string keys and values
+describing basic application metadata. It is very similar to the *appinfo*
+measurement in the *last* section. The difference is this field is almost
+certainly guaranteed to exist whereas the one in the data part of the
+payload may be omitted in certain scenarios (such as catastrophic client
+error).
+
+Its keys are as follows:
+
+appBuildID
+ The build ID/date of the application. e.g. "20130314113542".
+
+version
+ The value of nsXREAppData.version. This is the application's version. e.g.
+ "21.0.0".
+
+vendor
+ The value of nsXREAppData.vendor. Can be empty an empty string. For
+ official Mozilla builds, this will be "Mozilla".
+
+name
+ The value of nsXREAppData.name. For official Firefox builds, this
+ will be "Firefox".
+
+id
+ The value of nsXREAppData.ID.
+
+platformVersion
+ The version of the Gecko platform (as opposed to the app version). For
+ Firefox, this is almost certainly equivalent to the *version* field.
+
+platformBuildID
+ The build ID/date of the Gecko platfor (as opposed to the app version).
+ This is commonly equivalent to *appBuildID*.
+
+os
+ The name of the operating system the application is running on.
+
+xpcomabi
+ The binary architecture of the build.
+
+updateChannel
+ The name of the channel used for application updates. Official Mozilla
+ builds have one of the values {release, beta, aurora, nightly}. Local and
+ test builds have *default* as the channel.
+
+Version 1
+=========
+
+Top-level Properties
+--------------------
+
+The main JSON object contains the following properties:
+
+lastPingDate
+ UTC date of the last upload. If this is the first upload from this client,
+ this will not be present.
+
+thisPingDate
+ UTC date when this payload was constructed.
+
+version
+ Integer version of this payload format. Currently only 1 is defined.
+
+clientID
+ An identifier that identifies the client that is submitting data.
+
+ This property may not be present in older clients.
+
+ See :ref:`healthreport_identifiers` for more info on identifiers.
+
+clientIDVersion
+ Integer version associated with the generation semantics for the
+ ``clientID``.
+
+ If the value is ``1``, ``clientID`` is a randomly-generated UUID.
+
+ This property may not be present in older clients.
+
+data
+ Object holding data constituting health report.
+
+Data Properties
+---------------
+
+The bulk of the health report is contained within the *data* object. This
+object has the following keys:
+
+days
+ Object mapping UTC days to measurements from that day. Keys are in the
+ *YYYY-MM-DD* format. e.g. "2013-03-14"
+
+last
+ Object mapping measurement names to their values.
+
+
+The value of *days* and *last* are objects mapping measurement names to that
+measurement's values. The values are always objects. Each object contains
+a *_v* property. This property defines the version of this measurement.
+Additional non-underscore-prefixed properties are defined by the measurement
+itself (see sections below).
+
+Example
+-------
+
+Here is an example JSON document for version 1::
+
+ {
+ "version": 1,
+ "thisPingDate": "2013-03-11",
+ "lastPingDate": "2013-03-10",
+ "data": {
+ "last": {
+ "org.mozilla.addons.active": {
+ "masspasswordreset@johnathan.nightingale": {
+ "userDisabled": false,
+ "appDisabled": false,
+ "version": "1.05",
+ "type": "extension",
+ "scope": 1,
+ "foreignInstall": false,
+ "hasBinaryComponents": false,
+ "installDay": 14973,
+ "updateDay": 15317
+ },
+ "places-maintenance@bonardo.net": {
+ "userDisabled": false,
+ "appDisabled": false,
+ "version": "1.3",
+ "type": "extension",
+ "scope": 1,
+ "foreignInstall": false,
+ "hasBinaryComponents": false,
+ "installDay": 15268,
+ "updateDay": 15379
+ },
+ "_v": 1
+ },
+ "org.mozilla.appInfo.appinfo": {
+ "_v": 1,
+ "appBuildID": "20130309030841",
+ "distributionID": "",
+ "distributionVersion": "",
+ "hotfixVersion": "",
+ "id": "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}",
+ "locale": "en-US",
+ "name": "Firefox",
+ "os": "Darwin",
+ "platformBuildID": "20130309030841",
+ "platformVersion": "22.0a1",
+ "updateChannel": "nightly",
+ "vendor": "Mozilla",
+ "version": "22.0a1",
+ "xpcomabi": "x86_64-gcc3"
+ },
+ "org.mozilla.profile.age": {
+ "_v": 1,
+ "profileCreation": 12444
+ },
+ "org.mozilla.appSessions.current": {
+ "_v": 3,
+ "startDay": 15773,
+ "activeTicks": 522,
+ "totalTime": 70858,
+ "main": 1245,
+ "firstPaint": 2695,
+ "sessionRestored": 3436
+ },
+ "org.mozilla.sysinfo.sysinfo": {
+ "_v": 1,
+ "cpuCount": 8,
+ "memoryMB": 16384,
+ "architecture": "x86-64",
+ "name": "Darwin",
+ "version": "12.2.1"
+ }
+ },
+ "days": {
+ "2013-03-11": {
+ "org.mozilla.addons.counts": {
+ "_v": 1,
+ "extension": 15,
+ "plugin": 12,
+ "theme": 1
+ },
+ "org.mozilla.places.places": {
+ "_v": 1,
+ "bookmarks": 757,
+ "pages": 104858
+ },
+ "org.mozilla.appInfo.appinfo": {
+ "_v": 1,
+ "isDefaultBrowser": 1
+ }
+ },
+ "2013-03-10": {
+ "org.mozilla.addons.counts": {
+ "_v": 1,
+ "extension": 15,
+ "plugin": 12,
+ "theme": 1
+ },
+ "org.mozilla.places.places": {
+ "_v": 1,
+ "bookmarks": 757,
+ "pages": 104857
+ },
+ "org.mozilla.searches.counts": {
+ "_v": 1,
+ "google.urlbar": 4
+ },
+ "org.mozilla.appInfo.appinfo": {
+ "_v": 1,
+ "isDefaultBrowser": 1
+ }
+ }
+ }
+ }
+ }
+
+Measurements
+============
+
+The bulk of payloads consists of measurement data. An individual measurement
+is merely a collection of related values e.g. *statistics about the Places
+database* or *system information*.
+
+Each measurement has an integer version number attached. When the fields in
+a measurement or the semantics of data within that measurement change, the
+version number is incremented.
+
+All measurements are defined alphabetically in the sections below.
+
+org.mozilla.addons.addons
+-------------------------
+
+This measurement contains information about the currently-installed add-ons.
+
+Version 2
+^^^^^^^^^
+
+This version adds the human-readable fields *name* and *description*, both
+coming directly from the Addon instance as most properties in version 1.
+Also, all plugin details are now in org.mozilla.addons.plugins.
+
+Version 1
+^^^^^^^^^
+
+The measurement object is a mapping of add-on IDs to objects containing
+add-on metadata.
+
+Each add-on contains the following properties:
+
+* userDisabled
+* appDisabled
+* version
+* type
+* scope
+* foreignInstall
+* hasBinaryComponents
+* installDay
+* updateDay
+
+With the exception of *installDay* and *updateDay*, all these properties
+come direct from the Addon instance. See https://developer.mozilla.org/en-US/docs/Addons/Add-on_Manager/Addon.
+*installDay* and *updateDay* are the number of days since UNIX epoch of
+the add-ons *installDate* and *updateDate* properties, respectively.
+
+Notes
+^^^^^
+
+Add-ons that have opted out of AMO updates via the
+*extensions._id_.getAddons.cache.enabled* preference are, since Bug 868306
+(Firefox 24), included in the list of submitted add-ons.
+
+Example
+^^^^^^^
+::
+
+ "org.mozilla.addons.addons": {
+ "_v": 2,
+ "{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}": {
+ "userDisabled": false,
+ "appDisabled": false,
+ "name": "Adblock Plus",
+ "version": "2.4.1",
+ "type": "extension",
+ "scope": 1,
+ "description": "Ads were yesterday!",
+ "foreignInstall": false,
+ "hasBinaryComponents": false,
+ "installDay": 16093,
+ "updateDay": 16093
+ },
+ "{e4a8a97b-f2ed-450b-b12d-ee082ba24781}": {
+ "userDisabled": true,
+ "appDisabled": false,
+ "name": "Greasemonkey",
+ "version": "1.14",
+ "type": "extension",
+ "scope": 1,
+ "description": "A User Script Manager for Firefox",
+ "foreignInstall": false,
+ "hasBinaryComponents": false,
+ "installDay": 16093,
+ "updateDay": 16093
+ }
+ }
+
+org.mozilla.addons.plugins
+--------------------------
+
+This measurement contains information about the currently-installed plugins.
+
+Version 1
+^^^^^^^^^
+
+The measurement object is a mapping of plugin IDs to objects containing
+plugin metadata.
+
+The plugin ID is constructed of the plugins filename, name, version and
+description. Every plugin has at least a filename and a name.
+
+Each plugin contains the following properties:
+
+* name
+* version
+* description
+* blocklisted
+* disabled
+* clicktoplay
+* mimeTypes
+* updateDay
+
+With the exception of *updateDay* and *mimeTypes*, all these properties come
+directly from ``nsIPluginTag`` via ``nsIPluginHost``.
+*updateDay* is the number of days since UNIX epoch of the plugins last modified
+time.
+*mimeTypes* is the list of mimetypes the plugin supports, see
+``nsIPluginTag.getMimeTypes()``.
+
+Example
+^^^^^^^
+
+::
+
+ "org.mozilla.addons.plugins": {
+ "_v": 1,
+ "Flash Player.plugin:Shockwave Flash:12.0.0.38:Shockwave Flash 12.0 r0": {
+ "mimeTypes": [
+ "application/x-shockwave-flash",
+ "application/futuresplash"
+ ],
+ "name": "Shockwave Flash",
+ "version": "12.0.0.38",
+ "description": "Shockwave Flash 12.0 r0",
+ "blocklisted": false,
+ "disabled": false,
+ "clicktoplay": false
+ },
+ "Default Browser.plugin:Default Browser Helper:537:Provides information about the default web browser": {
+ "mimeTypes": [
+ "application/apple-default-browser"
+ ],
+ "name": "Default Browser Helper",
+ "version": "537",
+ "description": "Provides information about the default web browser",
+ "blocklisted": false,
+ "disabled": true,
+ "clicktoplay": false
+ }
+ }
+
+org.mozilla.addons.counts
+-------------------------
+
+This measurement contains information about historical add-on counts.
+
+Version 1
+^^^^^^^^^
+
+The measurement object consists of counts of different add-on types. The
+properties are:
+
+extension
+ Integer count of installed extensions.
+plugin
+ Integer count of installed plugins.
+theme
+ Integer count of installed themes.
+lwtheme
+ Integer count of installed lightweight themes.
+
+Notes
+^^^^^
+
+Add-ons opted out of AMO updates are included in the counts. This differs from
+the behavior of the active add-ons measurement.
+
+If no add-ons of a particular type are installed, the property for that type
+will not be present (as opposed to an explicit property with value of 0).
+
+Example
+^^^^^^^
+
+::
+
+ "2013-03-14": {
+ "org.mozilla.addons.counts": {
+ "_v": 1,
+ "extension": 21,
+ "plugin": 4,
+ "theme": 1
+ }
+ }
+
+
+
+org.mozilla.appInfo.appinfo
+---------------------------
+
+This measurement contains basic XUL application and Gecko platform
+information. It is reported in the *last* section.
+
+Version 2
+^^^^^^^^^
+
+In addition to fields present in version 1, this version has the following
+fields appearing in the *days* section:
+
+isBlocklistEnabled
+ Whether the blocklist ping is enabled. This is an integer, 0 or 1.
+ This does not indicate whether the blocklist ping was sent but merely
+ whether the application will try to send the blocklist ping.
+
+isTelemetryEnabled
+ Whether Telemetry is enabled. This is an integer, 0 or 1.
+
+Version 1
+^^^^^^^^^
+
+The measurement object contains mostly string values describing the
+current application and build. The properties are:
+
+* vendor
+* name
+* id
+* version
+* appBuildID
+* platformVersion
+* platformBuildID
+* os
+* xpcomabi
+* updateChannel
+* distributionID
+* distributionVersion
+* hotfixVersion
+* locale
+* isDefaultBrowser
+
+Notes
+^^^^^
+
+All of the properties appear in the *last* section except for
+*isDefaultBrowser*, which appears under *days*.
+
+Example
+^^^^^^^
+
+This example comes from an official macOS Nightly build::
+
+ "org.mozilla.appInfo.appinfo": {
+ "_v": 1,
+ "appBuildID": "20130311030946",
+ "distributionID": "",
+ "distributionVersion": "",
+ "hotfixVersion": "",
+ "id": "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}",
+ "locale": "en-US",
+ "name": "Firefox",
+ "os": "Darwin",
+ "platformBuildID": "20130311030946",
+ "platformVersion": "22.0a1",
+ "updateChannel": "nightly",
+ "vendor": "Mozilla",
+ "version": "22.0a1",
+ "xpcomabi": "x86_64-gcc3"
+ },
+
+org.mozilla.appInfo.update
+--------------------------
+
+This measurement contains information about the application update mechanism
+in the application.
+
+Version 1
+^^^^^^^^^
+
+The following daily values are reported:
+
+enabled
+ Whether automatic application update checking is enabled. 1 for yes,
+ 0 for no.
+autoDownload
+ Whether automatic download of available updates is enabled.
+
+Notes
+^^^^^
+
+This measurement was merged to mozilla-central for JS FHR on 2013-07-15.
+
+Example
+^^^^^^^
+
+::
+
+ "2013-07-15": {
+ "org.mozilla.appInfo.update": {
+ "_v": 1,
+ "enabled": 1,
+ "autoDownload": 1,
+ }
+ }
+
+org.mozilla.appInfo.versions
+----------------------------
+
+This measurement contains a history of application version numbers.
+
+Version 2
+^^^^^^^^^
+
+Version 2 reports more fields than version 1 and is not backwards compatible.
+The following fields are present in version 2:
+
+appVersion
+ An array of application version strings.
+appBuildID
+ An array of application build ID strings.
+platformVersion
+ An array of platform version strings.
+platformBuildID
+ An array of platform build ID strings.
+
+When the application is upgraded, the new version and/or build IDs are
+appended to their appropriate fields.
+
+Version 1
+^^^^^^^^^
+
+When the application version (*version* from *org.mozilla.appinfo.appinfo*)
+changes, we record the new version on the day the change was seen. The new
+versions for a day are recorded in an array under the *version* property.
+
+Notes
+^^^^^
+
+If the application isn't upgraded, this measurement will not be present.
+This means this measurement will not be present for most days if a user is
+on the release channel (since updates are typically released every 6 weeks).
+However, users on the Nightly and Aurora channels will likely have a lot
+of these entries since those builds are updated every day.
+
+Values for this measurement are collected when performing the daily
+collection (typically occurs at upload time). As a result, it's possible
+the actual upgrade day may not be attributed to the proper day - the
+reported day may lag behind.
+
+The app and platform versions and build IDs should be identical for most
+clients. If they are different, we are possibly looking at a *Frankenfox*.
+
+Example
+^^^^^^^
+
+::
+
+ "2013-03-27": {
+ "org.mozilla.appInfo.versions": {
+ "_v": 2,
+ "appVersion": [
+ "22.0.0"
+ ],
+ "appBuildID": [
+ "20130325031100"
+ ],
+ "platformVersion": [
+ "22.0.0"
+ ],
+ "platformBuildID": [
+ "20130325031100"
+ ]
+ }
+ }
+
+org.mozilla.appSessions.current
+-------------------------------
+
+This measurement contains information about the currently running XUL
+application's session.
+
+Version 3
+^^^^^^^^^
+
+This measurement has the following properties:
+
+startDay
+ Integer days since UNIX epoch when this session began.
+activeTicks
+ Integer count of *ticks* the session was active for. Gecko periodically
+ sends out a signal when the session is active. Session activity
+ involves keyboard or mouse interaction with the application. Each tick
+ represents a window of 5 seconds where there was interaction.
+totalTime
+ Integer seconds the session has been alive.
+main
+ Integer milliseconds it took for the Gecko process to start up.
+firstPaint
+ Integer milliseconds from process start to first paint.
+sessionRestored
+ Integer milliseconds from process start to session restore.
+
+Example
+^^^^^^^
+
+::
+
+ "org.mozilla.appSessions.current": {
+ "_v": 3,
+ "startDay": 15775,
+ "activeTicks": 4282,
+ "totalTime": 249422,
+ "main": 851,
+ "firstPaint": 3271,
+ "sessionRestored": 5998
+ }
+
+org.mozilla.appSessions.previous
+--------------------------------
+
+This measurement contains information about previous XUL application sessions.
+
+Version 3
+^^^^^^^^^
+
+This measurement contains per-day lists of all the sessions started on that
+day. The following properties may be present:
+
+cleanActiveTicks
+ Active ticks of sessions that were properly shut down.
+cleanTotalTime
+ Total number of seconds for sessions that were properly shut down.
+abortedActiveTicks
+ Active ticks of sessions that were not properly shut down.
+abortedTotalTime
+ Total number of seconds for sessions that were not properly shut down.
+main
+ Time in milliseconds from process start to main process initialization.
+firstPaint
+ Time in milliseconds from process start to first paint.
+sessionRestored
+ Time in milliseconds from process start to session restore.
+
+Notes
+^^^^^
+
+Sessions are recorded on the date on which they began.
+
+If a session was aborted/crashed, the total time may be less than the actual
+total time. This is because we don't always update total time during periods
+of inactivity and the abort/crash could occur after a long period of idle,
+before we've updated the total time.
+
+The lengths of the arrays for {cleanActiveTicks, cleanTotalTime},
+{abortedActiveTicks, abortedTotalTime}, and {main, firstPaint, sessionRestored}
+should all be identical.
+
+The length of the clean sessions plus the length of the aborted sessions should
+be equal to the length of the {main, firstPaint, sessionRestored} properties.
+
+It is not possible to distinguish the main, firstPaint, and sessionRestored
+values from a clean vs aborted session: they are all lumped together.
+
+For sessions spanning multiple UTC days, it's not possible to know which
+days the session was active for. It's possible a week long session only
+had activity for 2 days and there's no way for us to tell which days.
+
+Example
+^^^^^^^
+
+::
+
+ "org.mozilla.appSessions.previous": {
+ "_v": 3,
+ "cleanActiveTicks": [
+ 78,
+ 1785
+ ],
+ "cleanTotalTime": [
+ 4472,
+ 88908
+ ],
+ "main": [
+ 32,
+ 952
+ ],
+ "firstPaint": [
+ 2755,
+ 3497
+ ],
+ "sessionRestored": [
+ 5149,
+ 5520
+ ]
+ }
+
+org.mozilla.crashes.crashes
+---------------------------
+
+This measurement contains a historical record of application crashes.
+
+Version 6
+^^^^^^^^^
+
+This version adds tracking for out-of-memory (OOM) crashes in the main process.
+An OOM crash will be counted as both main-crash and main-crash-oom.
+
+This measurement will be reported on each day there was a crash or crash
+submission. Records may contain the following fields, whose values indicate
+the number of crashes, hangs, or submissions that occurred on the given day:
+
+* content-crash
+* content-crash-submission-succeeded
+* content-crash-submission-failed
+* content-hang
+* content-hang-submission-succeeded
+* content-hang-submission-failed
+* gmplugin-crash
+* gmplugin-crash-submission-succeeded
+* gmplugin-crash-submission-failed
+* main-crash
+* main-crash-oom
+* main-crash-submission-succeeded
+* main-crash-submission-failed
+* main-hang
+* main-hang-submission-succeeded
+* main-hang-submission-failed
+* plugin-crash
+* plugin-crash-submission-succeeded
+* plugin-crash-submission-failed
+* plugin-hang
+* plugin-hang-submission-succeeded
+* plugin-hang-submission-failed
+
+Version 5
+^^^^^^^^^
+
+This version adds support for Gecko media plugin (GMP) crashes.
+
+This measurement will be reported on each day there was a crash or crash
+submission. Records may contain the following fields, whose values indicate
+the number of crashes, hangs, or submissions that occurred on the given day:
+
+* content-crash
+* content-crash-submission-succeeded
+* content-crash-submission-failed
+* content-hang
+* content-hang-submission-succeeded
+* content-hang-submission-failed
+* gmplugin-crash
+* gmplugin-crash-submission-succeeded
+* gmplugin-crash-submission-failed
+* main-crash
+* main-crash-submission-succeeded
+* main-crash-submission-failed
+* main-hang
+* main-hang-submission-succeeded
+* main-hang-submission-failed
+* plugin-crash
+* plugin-crash-submission-succeeded
+* plugin-crash-submission-failed
+* plugin-hang
+* plugin-hang-submission-succeeded
+* plugin-hang-submission-failed
+
+Version 4
+^^^^^^^^^
+
+This version follows up from version 3, adding submissions which are now
+tracked by the :ref:`crashes_crashmanager`.
+
+This measurement will be reported on each day there was a crash or crash
+submission. Records may contain the following fields, whose values indicate
+the number of crashes, hangs, or submissions that occurred on the given day:
+
+* main-crash
+* main-crash-submission-succeeded
+* main-crash-submission-failed
+* main-hang
+* main-hang-submission-succeeded
+* main-hang-submission-failed
+* content-crash
+* content-crash-submission-succeeded
+* content-crash-submission-failed
+* content-hang
+* content-hang-submission-succeeded
+* content-hang-submission-failed
+* plugin-crash
+* plugin-crash-submission-succeeded
+* plugin-crash-submission-failed
+* plugin-hang
+* plugin-hang-submission-succeeded
+* plugin-hang-submission-failed
+
+Version 3
+^^^^^^^^^
+
+This version follows up from version 2, building on improvements to
+the :ref:`crashes_crashmanager`.
+
+This measurement will be reported on each day there was a
+crash. Records may contain the following fields, whose values indicate
+the number of crashes or hangs that occurred on the given day:
+
+* main-crash
+* main-hang
+* content-crash
+* content-hang
+* plugin-crash
+* plugin-hang
+
+Version 2
+^^^^^^^^^
+
+The switch to version 2 coincides with the introduction of the
+:ref:`crashes_crashmanager`, which provides a more robust source of
+crash data.
+
+This measurement will be reported on each day there was a crash. The
+following fields may be present in each record:
+
+mainCrash
+ The number of main process crashes that occurred on the given day.
+
+Yes, version 2 does not track submissions like version 1. It is very
+likely submissions will be re-added later.
+
+Also absent from version 2 are plugin crashes and hangs. These will be
+re-added, likely in version 3.
+
+Version 1
+^^^^^^^^^
+
+This measurement will be reported on each day there was a crash. The
+following properties are reported:
+
+pending
+ The number of crash reports that haven't been submitted.
+submitted
+ The number of crash reports that were submitted.
+
+Notes
+^^^^^
+
+Main process crashes are typically submitted immediately after they
+occur (by checking a box in the crash reporter, which should appear
+automatically after a crash). If the crash reporter submits the crash
+successfully, we get a submitted crash. Else, we leave it as pending.
+
+A pending crash does not mean it will eventually be submitted.
+
+Pending crash reports can be submitted post-crash by going to
+about:crashes.
+
+If a pending crash is submitted via about:crashes, the submitted count
+increments but the pending count does not decrement. This is because FHR
+does not know which pending crash was just submitted and therefore it does
+not know which day's pending crash to decrement.
+
+Example
+^^^^^^^
+
+::
+
+ "org.mozilla.crashes.crashes": {
+ "_v": 1,
+ "pending": 1,
+ "submitted": 2
+ },
+ "org.mozilla.crashes.crashes": {
+ "_v": 2,
+ "mainCrash": 2
+ }
+ "org.mozilla.crashes.crashes": {
+ "_v": 4,
+ "main-crash": 2,
+ "main-crash-submission-succeeded": 1,
+ "main-crash-submission-failed": 1,
+ "main-hang": 1,
+ "plugin-crash": 2
+ }
+
+org.mozilla.healthreport.submissions
+------------------------------------
+
+This measurement contains a history of FHR's own data submission activity.
+It was added in Firefox 23 in early May 2013.
+
+Version 2
+^^^^^^^^^
+
+This is the same as version 1 except an additional field has been added.
+
+uploadAlreadyInProgress
+ A request for upload was initiated while another upload was in progress.
+ This should not occur in well-behaving clients. It (along with a lock
+ preventing simultaneous upload) was added to ensure this never occurs.
+
+Version 1
+^^^^^^^^^
+
+Daily counts of upload events are recorded.
+
+firstDocumentUploadAttempt
+ An attempt was made to upload the client's first document to the server.
+ These are uploads where the client is not aware of a previous document ID
+ on the server. Unless the client had disabled upload, there should be at
+ most one of these in the history of the client.
+
+continuationUploadAttempt
+ An attempt was made to upload a document that replaces an existing document
+ on the server. Most upload attempts should be attributed to this as opposed
+ to *firstDocumentUploadAttempt*.
+
+uploadSuccess
+ The upload attempt recorded by *firstDocumentUploadAttempt* or
+ *continuationUploadAttempt* was successful.
+
+uploadTransportFailure
+ An upload attempt failed due to transport failure (network unavailable,
+ etc).
+
+uploadServerFailure
+ An upload attempt failed due to a server-reported failure. Ideally these
+ are failures reported by the FHR server itself. However, intermediate
+ proxies, firewalls, etc may trigger this depending on how things are
+ configured.
+
+uploadClientFailure
+ An upload attempt failued due to an error/exception in the client.
+ This almost certainly points to a bug in the client.
+
+The result for an upload attempt is always attributed to the same day as
+the attempt, even if the result occurred on a different day from the attempt.
+Therefore, the sum of the result counts should equal the result of the attempt
+counts.
+
+org.mozilla.hotfix.update
+-------------------------
+
+This measurement contains results from the Firefox update hotfix.
+
+The Firefox update hotfix bypasses the built-in application update mechanism
+and installs a modern Firefox.
+
+Version 1
+^^^^^^^^^
+
+The fields in this measurement are dynamically created based on which
+versions of the update hotfix state file are found on disk.
+
+The general format of the fields is ``<version>.<thing>`` where ``version``
+is a hotfix version like ``v20140527`` and ``thing`` is a key from the
+hotfix state file, e.g. ``upgradedFrom``. Here are some of the ``things``
+that can be defined.
+
+upgradedFrom
+ String identifying the Firefox version that the hotfix upgraded from.
+ e.g. ``16.0`` or ``17.0.1``.
+
+uninstallReason
+ String with enumerated values identifying why the hotfix was uninstalled.
+ Value will be ``STILL_INSTALLED`` if the hotfix is still installed.
+
+downloadAttempts
+ Integer number of times the hotfix started downloading an installer.
+ Download resumes are part of this count.
+
+downloadFailures
+ Integer count of times a download supposedly completed but couldn't
+ be validated. This likely represents something wrong with the network
+ connection. The ratio of this to ``downloadAttempts`` should be low.
+
+installAttempts
+ Integer count of times the hotfix attempted to run the installer.
+ This should ideally be 1. It should only be greater than 1 if UAC
+ elevation was canceled or not allowed.
+
+installFailures
+ Integer count of total installation failures this client experienced.
+ Can be 0. ``installAttempts - installFailures`` implies install successes.
+
+notificationsShown
+ Integer count of times a notification was displayed to the user that
+ they are running an older Firefox.
+
+org.mozilla.places.places
+-------------------------
+
+This measurement contains information about the Places database (where Firefox
+stores its history and bookmarks).
+
+Version 1
+^^^^^^^^^
+
+Daily counts of items in the database are reported in the following properties:
+
+bookmarks
+ Integer count of bookmarks present.
+pages
+ Integer count of pages in the history database.
+
+Example
+^^^^^^^
+
+::
+
+ "org.mozilla.places.places": {
+ "_v": 1,
+ "bookmarks": 388,
+ "pages": 94870
+ }
+
+org.mozilla.profile.age
+-----------------------
+
+This measurement contains information about the current profile's age (and
+in version 2, the profile's most recent reset date)
+
+Version 2
+^^^^^^^^^
+
+*profileCreation* and *profileReset* properties are present. Both define
+the integer days since UNIX epoch that the current profile was created or
+reset accordingly.
+
+Version 1
+^^^^^^^^^
+
+A single *profileCreation* property is present. It defines the integer
+days since UNIX epoch that the current profile was created.
+
+Notes
+^^^^^
+
+It is somewhat difficult to obtain a reliable *profile born date* due to a
+number of factors, but since Version 2, improvements have been made - on a
+"profile reset" we copy the profileCreation date from the old profile and
+record the time of the reset in profileReset.
+
+Example
+^^^^^^^
+
+::
+
+ "org.mozilla.profile.age": {
+ "_v": 2,
+ "profileCreation": 15176
+ "profileReset": 15576
+ }
+
+org.mozilla.searches.counts
+---------------------------
+
+This measurement contains information about searches performed in the
+application.
+
+Version 6 (mobile)
+^^^^^^^^^^^^^^^^^^
+
+This adds two new search locations: *widget* and *activity*, corresponding to the search widget and search activity respectively.
+
+Version 2
+^^^^^^^^^
+
+This behaves like version 1 except we added all search engines that
+Mozilla has a partner agreement with. Like version 1, we concatenate
+a search engine ID with a search origin.
+
+Another difference with version 2 is we should no longer misattribute
+a search to the *other* bucket if the search engine name is localized.
+
+The set of search engine providers is:
+
+* amazon-co-uk
+* amazon-de
+* amazon-en-GB
+* amazon-france
+* amazon-it
+* amazon-jp
+* amazondotcn
+* amazondotcom
+* amazondotcom-de
+* aol-en-GB
+* aol-web-search
+* bing
+* eBay
+* eBay-de
+* eBay-en-GB
+* eBay-es
+* eBay-fi
+* eBay-france
+* eBay-hu
+* eBay-in
+* eBay-it
+* google
+* google-jp
+* google-ku
+* google-maps-zh-TW
+* mailru
+* mercadolibre-ar
+* mercadolibre-cl
+* mercadolibre-mx
+* seznam-cz
+* twitter
+* twitter-de
+* twitter-ja
+* yahoo
+* yahoo-NO
+* yahoo-answer-zh-TW
+* yahoo-ar
+* yahoo-bid-zh-TW
+* yahoo-br
+* yahoo-ch
+* yahoo-cl
+* yahoo-de
+* yahoo-en-GB
+* yahoo-es
+* yahoo-fi
+* yahoo-france
+* yahoo-fy-NL
+* yahoo-id
+* yahoo-in
+* yahoo-it
+* yahoo-jp
+* yahoo-jp-auctions
+* yahoo-mx
+* yahoo-sv-SE
+* yahoo-zh-TW
+* yandex
+* yandex-ru
+* yandex-slovari
+* yandex-tr
+* yandex.by
+* yandex.ru-be
+
+And of course, *other*.
+
+The sources for searches remain:
+
+* abouthome
+* contextmenu
+* searchbar
+* urlbar
+
+The measurement will only be populated with providers and sources that
+occurred that day.
+
+If a user switches locales, searches from default providers on the older
+locale will still be supported. However, if that same search engine is
+added by the user to the new build and is *not* a default search engine
+provider, its searches will be attributed to the *other* bucket.
+
+Version 1
+^^^^^^^^^
+
+We record counts of performed searches grouped by search engine and search
+origin. Only search engines with which Mozilla has a business relationship
+are explicitly counted. All other search engines are grouped into an
+*other* bucket.
+
+The following search engines are explicitly counted:
+
+* Amazon.com
+* Bing
+* Google
+* Yahoo
+* Other
+
+The following search origins are distinguished:
+
+about:home
+ Searches initiated from the search text box on about:home.
+context menu
+ Searches initiated from the context menu (highlight text, right click,
+ and select "search for...")
+search bar
+ Searches initiated from the search bar (the text field next to the
+ Awesomebar)
+url bar
+ Searches initiated from the awesomebar/url bar.
+
+Due to the localization of search engine names, non en-US locales may wrongly
+attribute searches to the *other* bucket. This is fixed in version 2.
+
+Example
+^^^^^^^
+
+::
+
+ "org.mozilla.searches.counts": {
+ "_v": 1,
+ "google.searchbar": 3,
+ "google.urlbar": 7
+ },
+
+org.mozilla.searches.engines
+----------------------------
+
+This measurement contains information about search engines.
+
+Version 1
+^^^^^^^^^
+
+This version debuted with Firefox 31 on desktop. It contains the
+following properties:
+
+default
+ Daily string identifier or name of the default search engine provider.
+
+ This field will only be collected if Telemetry is enabled. If
+ Telemetry is enabled and then later disabled, this field may
+ disappear from future days in the payload.
+
+ The special value ``NONE`` could occur if there is no default search
+ engine.
+
+ The special value ``UNDEFINED`` could occur if a default search
+ engine exists but its identifier could not be determined.
+
+ This field's contents are
+ ``Services.search.defaultEngine.identifier`` (if defined) or
+ ``"other-"`` + ``Services.search.defaultEngine.name`` if not.
+ In other words, search engines without an ``.identifier``
+ are prefixed with ``other-``.
+
+Version 2
+^^^^^^^^^
+
+Starting with Firefox 40, there is an additional optional value:
+
+cohort
+ Daily cohort string identifier, recorded if the user is part of
+ search defaults A/B testing.
+
+org.mozilla.sync.sync
+---------------------
+
+This daily measurement contains information about the Sync service.
+
+Values should be recorded for every day FHR measurements occurred.
+
+Version 1
+^^^^^^^^^
+
+This version debuted with Firefox 30 on desktop. It contains the following
+properties:
+
+enabled
+ Daily numeric indicating whether Sync is configured and enabled. 1 if so,
+ 0 otherwise.
+
+preferredProtocol
+ String version of the maximum Sync protocol version the client supports.
+ This will be ``1.1`` for for legacy Sync and ``1.5`` for clients that
+ speak the Firefox Accounts protocol.
+
+actualProtocol
+ The actual Sync protocol version the client is configured to use.
+
+ This will be ``1.1`` if the client is configured with the legacy Sync
+ service or if the client only supports ``1.1``.
+
+ It will be ``1.5`` if the client supports ``1.5`` and either a) the
+ client is not configured b) the client is using Firefox Accounts Sync.
+
+syncStart
+ Count of sync operations performed.
+
+syncSuccess
+ Count of sync operations that completed successfully.
+
+syncError
+ Count of sync operations that did not complete successfully.
+
+ This is a measure of overall sync success. This does *not* reflect
+ recoverable errors (such as record conflict) that can occur during
+ sync. This is thus a rough proxy of whether the sync service is
+ operating without error.
+
+org.mozilla.sync.devices
+------------------------
+
+This daily measurement contains information about the device type composition
+for the configured Sync account.
+
+Version 1
+^^^^^^^^^
+
+Version 1 was introduced with Firefox 30.
+
+Field names are dynamic according to the client-reported device types from
+Sync records. All fields are daily last seen integer values corresponding to
+the number of devices of that type.
+
+Common values include:
+
+desktop
+ Corresponds to a Firefox desktop client.
+
+mobile
+ Corresponds to a Fennec client.
+
+org.mozilla.sync.migration
+--------------------------
+
+This daily measurement contains information about sync migration (that is, the
+semi-automated process of migrating a legacy sync account to an FxA account.)
+
+Measurements will start being recorded after a migration is offered by the
+sync server and stop after migration is complete or the user elects to "unlink"
+their sync account. In other words, it is expected that users with Sync setup
+for FxA or with sync unconfigured will not collect data, and that for users
+where data is collected, the collection will only be for a relatively short
+period.
+
+Version 1
+^^^^^^^^^
+
+Version 1 was introduced with Firefox 37 and includes the following properties:
+
+state
+ Corresponds to either a STATE_USER_* string or a STATE_INTERNAL_* string in
+ FxaMigration.jsm. This reflects a state where we are waiting for the user,
+ or waiting for some internal process to complete on the way to completing
+ the migration.
+
+declined
+ Corresponds to the number of times the user closed the migration infobar.
+
+unlinked
+ Set if the user declined to migrate and instead "unlinked" Sync from the
+ browser.
+
+accepted
+ Corresponds to the number of times the user explicitly elected to start or
+ continue the migration - it counts how often the user clicked on any UI
+ created specifically for migration. The "ideal" UX for migration would see
+ this at exactly 1, some known edge-cases (eg, browser restart required to
+ finish) could expect this to be 2, and anything more means we are doing
+ something wrong.
+
+org.mozilla.sysinfo.sysinfo
+---------------------------
+
+This measurement contains basic information about the system the application
+is running on.
+
+Version 2
+^^^^^^^^^
+
+This version debuted with Firefox 29 on desktop.
+
+A single property was introduced.
+
+isWow64
+ If present, this property indicates whether the machine supports WoW64.
+ This property can be used to identify whether the host machine is 64-bit.
+
+ This property is only present on Windows machines. It is the preferred way
+ to identify 32- vs 64-bit support in that environment.
+
+Version 1
+^^^^^^^^^
+
+The following properties may be available:
+
+cpuCount
+ Integer number of CPUs/cores in the machine.
+memoryMB
+ Integer megabytes of memory in the machine.
+manufacturer
+ The manufacturer of the device.
+device
+ The name of the device (like model number).
+hardware
+ Unknown.
+name
+ OS name.
+version
+ OS version.
+architecture
+ OS architecture that the application is built for. This is not the
+ actual system architecture.
+
+Example
+^^^^^^^
+
+::
+
+ "org.mozilla.sysinfo.sysinfo": {
+ "_v": 1,
+ "cpuCount": 8,
+ "memoryMB": 8192,
+ "architecture": "x86-64",
+ "name": "Darwin",
+ "version": "12.2.0"
+ }
+
+
+org.mozilla.translation.translation
+-----------------------------------
+
+This daily measurement contains information about the usage of the translation
+feature. It is a special telemetry measurement which will only be recorded in
+FHR if telemetry is enabled.
+
+Version 1
+^^^^^^^^^
+
+Daily counts are reported in the following properties:
+
+translationOpportunityCount
+ Integer count of the number of opportunities there were to translate a page.
+missedTranslationOpportunityCount
+ Integer count of the number of missed opportunities there were to translate a page.
+ A missed opportunity is when the page language is not supported by the translation
+ provider.
+pageTranslatedCount
+ Integer count of the number of pages translated.
+charactersTranslatedCount
+ Integer count of the number of characters translated.
+detectedLanguageChangedBefore
+ Integer count of the number of times the user manually adjusted the detected
+ language before translating.
+detectedLanguageChangedAfter
+ Integer count of the number of times the user manually adjusted the detected
+ language after having first translated the page.
+targetLanguageChanged
+ Integer count of the number of times the user manually adjusted the target
+ language.
+deniedTranslationOffer
+ Integer count of the number of times the user opted-out offered
+ page translation, either by the Not Now button or by the notification's
+ close button in the "offer" state.
+autoRejectedTranlationOffer
+ Integer count of the number of times the user is not offered page
+ translation because they had previously clicked "Never translate this
+ language" or "Never translate this site".
+showOriginalContent
+ Integer count of the number of times the user activated the Show Original
+ command.
+
+Additional daily counts broken down by language are reported in the following
+properties:
+
+translationOpportunityCountsByLanguage
+ A mapping from language to count of opportunities to translate that
+ language.
+missedTranslationOpportunityCountsByLanguage
+ A mapping from language to count of missed opportunities to translate that
+ language.
+pageTranslatedCountsByLanguage
+ A mapping from language to the counts of pages translated from that
+ language. Each language entry will be an object containing a "total" member
+ along with individual counts for each language translated to.
+
+Other properties:
+
+detectLanguageEnabled
+ Whether automatic language detection is enabled. This is an integer, 0 or 1.
+showTranslationUI
+ Whether the translation feature UI will be shown. This is an integer, 0 or 1.
+
+Example
+^^^^^^^
+
+::
+
+ "org.mozilla.translation.translation": {
+ "_v": 1,
+ "detectLanguageEnabled": 1,
+ "showTranslationUI": 1,
+ "translationOpportunityCount": 134,
+ "missedTranslationOpportunityCount": 32,
+ "pageTranslatedCount": 6,
+ "charactersTranslatedCount": "1126",
+ "detectedLanguageChangedBefore": 1,
+ "detectedLanguageChangedAfter": 2,
+ "targetLanguageChanged": 0,
+ "deniedTranslationOffer": 3,
+ "autoRejectedTranlationOffer": 1,
+ "showOriginalContent": 2,
+ "translationOpportunityCountsByLanguage": {
+ "fr": 100,
+ "es": 34
+ },
+ "missedTranslationOpportunityCountsByLanguage": {
+ "it": 20,
+ "nl": 10,
+ "fi": 2
+ },
+ "pageTranslatedCountsByLanguage": {
+ "fr": {
+ "total": 6,
+ "es": 5,
+ "en": 1
+ }
+ }
+ }
+
+
+org.mozilla.experiments.info
+----------------------------------
+
+Daily measurement reporting information about the Telemetry Experiments service.
+
+Version 1
+^^^^^^^^^
+
+Property:
+
+lastActive
+ ID of the final Telemetry Experiment that is active on a given day, if any.
+
+
+Version 2
+^^^^^^^^^
+
+Adds an additional optional property:
+
+lastActiveBranch
+ If the experiment uses branches, the branch identifier string.
+
+Example
+^^^^^^^
+
+::
+
+ "org.mozilla.experiments.info": {
+ "_v": 2,
+ "lastActive": "some.experiment.id",
+ "lastActiveBranch": "control"
+ }
+
+org.mozilla.uitour.treatment
+----------------------------
+
+Daily measurement reporting information about treatment tagging done
+by the UITour module.
+
+Version 1
+^^^^^^^^^
+
+Daily text values in the following properties:
+
+<tag>:
+ Array of discrete strings corresponding to calls for setTreatmentTag(tag, value).
+
+Example
+^^^^^^^
+
+::
+
+ "org.mozilla.uitour.treatment": {
+ "_v": 1,
+ "treatment": [
+ "optin",
+ "optin-DNT"
+ ],
+ "another-tag": [
+ "foobar-value"
+ ]
+ }
+
+org.mozilla.passwordmgr.passwordmgr
+-----------------------------------
+
+Daily measurement reporting information about the Password Manager
+
+Version 1
+^^^^^^^^^
+
+Property:
+
+numSavedPasswords
+ number of passwords saved in the Password Manager
+
+enabled
+ Whether or not the user has disabled the Password Manager in preferences
+
+Example
+^^^^^^^
+
+::
+
+ "org.mozilla.passwordmgr.passwordmgr": {
+ "_v": 1,
+ "numSavedPasswords": 5,
+ "enabled": 0,
+ }
+
+Version 2
+^^^^^^^^^
+
+More detailed measurements of login forms & their behavior
+
+numNewSavedPasswordsInSession
+ Number of passwords saved to the password manager this session.
+
+numSuccessfulFills
+ Number of times the password manager filled in password fields for user this session.
+
+numTotalLoginsEncountered
+ Number of times a login form was encountered by the user in the session.
+
+Example
+^^^^^^^
+
+::
+
+ "org.mozilla.passwordmgr.passwordmgr": {
+ "_v": 2,
+ "numSavedPasswords": 32,
+ "enabled": 1,
+ "numNewSavedPasswords": 5,
+ "numSuccessfulFills": 11,
+ "numTotalLoginsEncountered": 23,
+ }
diff --git a/toolkit/components/telemetry/docs/obsolete/fhr/identifiers.rst b/toolkit/components/telemetry/docs/obsolete/fhr/identifiers.rst
new file mode 100644
index 0000000000..82ad0e49e6
--- /dev/null
+++ b/toolkit/components/telemetry/docs/obsolete/fhr/identifiers.rst
@@ -0,0 +1,83 @@
+.. _healthreport_identifiers:
+
+===========
+Identifiers
+===========
+
+Firefox Health Report records some identifiers to keep track of clients
+and uploaded documents.
+
+Identifier Types
+================
+
+Document/Upload IDs
+-------------------
+
+A random UUID called the *Document ID* or *Upload ID* is generated when the FHR
+client creates or uploads a new document.
+
+When clients generate a new *Document ID*, they persist this ID to disk
+**before** the upload attempt.
+
+As part of the upload, the client sends all old *Document IDs* to the server
+and asks the server to delete them. In well-behaving clients, the server
+has a single record for each client with a randomly-changing *Document ID*.
+
+Client IDs
+----------
+
+A *Client ID* is an identifier that **attempts** to uniquely identify an
+individual FHR client. Please note the emphasis on *attempts* in that last
+sentence: *Client IDs* do not guarantee uniqueness.
+
+The *Client ID* is generated when the client first runs or as needed.
+
+The *Client ID* is transferred to the server as part of every upload. The
+server is thus able to affiliate multiple document uploads with a single
+*Client ID*.
+
+Client ID Versions
+^^^^^^^^^^^^^^^^^^
+
+The semantics for how a *Client ID* is generated are versioned.
+
+Version 1
+ The *Client ID* is a randomly-generated UUID.
+
+History of Identifiers
+======================
+
+In the beginning, there were just *Document IDs*. The thinking was clients
+would clean up after themselves and leave at most 1 active document on the
+server.
+
+Unfortunately, this did not work out. Using brute force analysis to
+deduplicate records on the server, a number of interesting patterns emerged.
+
+Orphaning
+ Clients would upload a new payload while not deleting the old payload.
+
+Divergent records
+ Records would share data up to a certain date and then the data would
+ almost completely diverge. This appears to be indicative of profile
+ copying.
+
+Rollback
+ Records would share data up to a certain date. Each record in this set
+ would contain data for a day or two but no extra data. This could be
+ explained by filesystem rollback on the client.
+
+A significant percentage of the records on the server belonged to
+misbehaving clients. Identifying these records was extremely resource
+intensive and error-prone. These records were undermining the ability
+to use Firefox Health Report data.
+
+Thus, the *Client ID* was born. The intent of the *Client ID* was to
+uniquely identify clients so the extreme effort required and the
+questionable reliability of deduplicating server data would become
+problems of the past.
+
+The *Client ID* was originally a randomly-generated UUID (version 1). This
+allowed detection of orphaning and rollback. However, these version 1
+*Client IDs* were still susceptible to use on multiple profiles and
+machines if the profile was copied.
diff --git a/toolkit/components/telemetry/docs/obsolete/fhr/index.rst b/toolkit/components/telemetry/docs/obsolete/fhr/index.rst
new file mode 100644
index 0000000000..d114a02814
--- /dev/null
+++ b/toolkit/components/telemetry/docs/obsolete/fhr/index.rst
@@ -0,0 +1,34 @@
+================================
+Firefox Health Report (Obsolete)
+================================
+
+**Firefox Health Report (FHR) is obsolete and no longer ships with Firefox.
+This documentation will live here for a few more cycles.**
+
+Firefox Health Report is a background service that collects application
+metrics and periodically submits them to a central server. The core
+parts of the service are implemented in this directory. However, the
+actual XPCOM service is implemented in the
+``data_reporting_service``.
+
+The core types can actually be instantiated multiple times and used to
+power multiple data submission services within a single Gecko
+application. In other words, everything in this directory is effectively
+a reusable library. However, the terminology and some of the features
+are very specific to what the Firefox Health Report feature requires.
+
+.. toctree::
+ :maxdepth: 1
+
+ architecture
+ dataformat
+ identifiers
+
+Legal and Privacy Concerns
+==========================
+
+Because Firefox Health Report collects and submits data to remote
+servers and is an opt-out feature, there are legal and privacy
+concerns over what data may be collected and submitted. **Additions or
+changes to submitted data should be signed off by responsible
+parties.**
diff --git a/toolkit/components/telemetry/docs/obsolete/geckoview-streaming.rst b/toolkit/components/telemetry/docs/obsolete/geckoview-streaming.rst
new file mode 100644
index 0000000000..10dfcdf860
--- /dev/null
+++ b/toolkit/components/telemetry/docs/obsolete/geckoview-streaming.rst
@@ -0,0 +1,26 @@
+GeckoView Streaming API
+=======================
+
+As an alternative to the normal mode where Firefox Desktop records and sends data,
+Telemetry can instead route Histogram samples and Scalar values out of Gecko to a Telemetry Delegate.
+
+To do this, ``toolkit.telemetry.geckoview.streaming`` must be set to true,
+and Gecko must have been built with ``MOZ_WIDGET_ANDROID`` defined.
+
+See :doc:`this guide <../start/report-gecko-telemetry-in-glean>`
+for how to collect data in this mode.
+
+Details
+=======
+
+Samples accumulated on Histograms and values set
+(``ScalarAdd`` and ``ScalarSetMaximum`` operations are not supported)
+on Scalars that have ``products`` lists that include ``geckoview_streaming``
+will be redirected to a small batching service in
+``toolkit/components/telemetry/geckoview/streaming``.
+The batching service
+(essentially just tables of histogram/scalar names to lists of samples/values)
+will hold on to these lists of samples/values paired to the histogram/scalar names for a length of time
+(``toolkit.telemetry.geckoview.batchDurationMS`` (default 5000))
+after which the next accumulation or ``ScalarSet`` will trigger the whole batch
+(all lists) to be passed over to the ``StreamingTelemetryDelegate``.
diff --git a/toolkit/components/telemetry/docs/obsolete/hybrid-content.rst b/toolkit/components/telemetry/docs/obsolete/hybrid-content.rst
new file mode 100644
index 0000000000..9eb0b00341
--- /dev/null
+++ b/toolkit/components/telemetry/docs/obsolete/hybrid-content.rst
@@ -0,0 +1,374 @@
+===================================
+Hybrid Content Telemetry (obsolete)
+===================================
+
+Hybrid content is web content that is loaded as part of Firefox, appears as part of
+Firefox to the user and is primarily intended to be used in Firefox. This can be
+either a page that ships with Firefox or that can be loaded dynamically from our hosted
+services. Hybrid content telemetry allows Mozilla pages to check whether data
+collection is enabled and to submit Telemetry data.
+
+.. important::
+
+ Every new or changed data collection in Firefox (including hybrid content) needs a `data collection review <https://wiki.mozilla.org/Firefox/Data_Collection>`__ from a Data Steward.
+
+The recorded data will be sent to Mozilla servers by Firefox, if the collection is enabled, with the :doc:`main-ping <../data/main-ping>`.
+
+Adding content data collection
+==============================
+Telemetry can be sent from web content by:
+
+1. granting the web content's host privileges in the Firefox codebase;
+2. including the ``HybridContentTelemetry-lib.js`` file in the page;
+3. registering the probes after the library is loaded;
+4. using the API to send Telemetry.
+
+Granting the privileges
+-----------------------
+For security/privacy reasons `Mozilla.ContentTelemetry` will only work on a list of allowed secure origins.
+The list of allowed origins can be found in
+`browser/app/permissions <https://searchfox.org/mozilla-central/source/browser/app/permissions>`_ .
+A host needs to be given the ``hc_telemetry`` permission in order to be allowed to use the API.
+
+Example:
+
+::
+
+ origin hc_telemetry 1 https://discovery.addons.mozilla.org
+
+Adding an entry to the ``permissions`` file requires riding the trains. If "go-faster" content requires
+granting permissions to a Mozilla page, it can do so by using the `permission manager <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIPermissionManager>`_
+
+.. code-block:: js
+
+ function addonInit() {
+ // The following code must be called before attempting to load a page that uses
+ // hybrid content telemetry on https://example.mozilla.org.
+ let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin("https://example.mozilla.org");
+ Services.perms.addFromPrincipal(principal, "hc_telemetry", Services.perms.ALLOW_ACTION);
+ }
+
+ function addonCleanup() {
+ // The permission must be removed if no longer needed (e.g. the add-on is shut down).
+ let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin("https://example.mozilla.org");
+ Services.perms.removeFromPrincipal(principal, "hc_telemetry");
+ }
+
+.. important::
+
+ Granted permissions do not disappear when a "go-faster" add-on is uninstalled but are cleared when the browser is closed. If permissions need to be cleaned without closing the browser, it must be done manually. Moreover, permissions are keyed by origin: ``http://mozilla.com`` and ``https://mozilla.com`` are different things.
+
+Including the library
+---------------------
+To use hybrid content telemetry the related content JS library needs to be included in the page. We have different integration options:
+
+* Add ``mozilla-hybrid-content-telemetry`` as a dependency to the project and require it in the code.
+* Load it directly from the `external unpkg CDN <https://unpkg.com/mozilla-hybrid-content-telemetry/HybridContentTelemetry-lib.js>`_.
+* Manually fetch the latest version from the `main repository <https://hg.mozilla.org/mozilla-central/file/tip/toolkit/components/telemetry/hybrid-content/HybridContentTelemetry-lib.js>`_ and add it to the page repository. Then this file can be deployed along with the page.
+
+Example (manual inclusion):
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: html
+
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <!-- Other head stuff -->
+ <script type="application/javascript" src="HybridContentTelemetry-lib.js"></script>
+ </head>
+ <body> <!-- Other body stuff --> </body>
+ </html>
+
+Example (NPM dependency):
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Add the dependency to your project:
+
+.. code-block:: shell
+
+ npm install --save mozilla-hybrid-content-telemetry@1.0.0
+
+In your app load the module and use the :ref:`API <the-api>`:
+
+.. code-block:: js
+
+ const ContentTelemetry = require("mozilla-hybrid-content-telemetry");
+
+ ContentTelemetry.registerEvents("page.interaction", {
+ "click": {
+ methods: ["click"],
+ objects: ["red_button", "blue_button"],
+ }
+ });
+
+ // Now events can be recorded.
+ ContentTelemetry.recordEvent("page.interaction", "click", "red_button");
+
+.. note::
+
+ The following examples assume the manual inclusion of the JS library.
+
+Registering the probes
+----------------------
+Probe registration can happen at any time after the library is loaded in the page, but registering early enough ensures that the definition is available once a recording attempt is made.
+
+Example:
+
+.. code-block:: html
+
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <!-- Other head stuff -->
+ <script type="application/javascript">
+ window.onload = function() {
+ if (!Mozilla || !Mozilla.ContentTelemetry) {
+ // .. uh-oh, was library loaded? Report the error.
+ return;
+ }
+ // Register the probe.
+ Mozilla.ContentTelemetry.registerEvents("page.interaction", {
+ "click": {
+ methods: ["click"],
+ objects: ["red_button", "blue_button"],
+ }
+ });
+ };
+ </script>
+ </head>
+ <body> <!-- Other body stuff --> </body>
+ </html>
+
+Recording the data
+------------------
+Data recording can happen at any time after a probe has been registered. The data will be recorded and sent by Firefox if permitted by the Telemetry :doc:`preferences <../internals/preferences>`.
+
+Example:
+
+.. code-block:: html
+
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <!-- Other head stuff -->
+ <script type="application/javascript">
+ function triggerEvent() {
+ if (!Mozilla || !Mozilla.ContentTelemetry) {
+ // .. uh-oh, was library loaded? Report the error.
+ return;
+ }
+ Mozilla.ContentTelemetry.recordEvent("page.interaction", "click", "red_button");
+ };
+ </script>
+ </head>
+ <body>
+ <!-- Other body stuff -->
+ <div id="content">
+ <button id='event-recording' onclick="triggerEvent();">
+ Trigger Recording
+ </button>
+ </div>
+ </body>
+ </html>
+
+Checking if upload is enabled
+-----------------------------
+Mozilla pages can check if data upload is enabled, as reported by Telemetry :doc:`preferences <../internals/preferences>`. This is useful for pages which are not using Telemetry to collect data, but
+need to comply to our data policy for the collection.
+
+Example:
+
+.. code-block:: html
+
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <!-- Other head stuff -->
+ <script type="application/javascript">
+ function recordData() {
+ if (!Mozilla || !Mozilla.ContentTelemetry) {
+ // .. uh-oh, was library loaded? Report the error.
+ return;
+ }
+
+ if (!Mozilla.ContentTelemetry.canUpload()) {
+ // User has opted-out of Telemetry. No collection must take place.
+ return;
+ }
+
+ // ... perform the collection without Telemetry below this point.
+ };
+ </script>
+ </head>
+ <body>
+ <!-- Other body stuff -->
+ <div id="content">
+ <button id='event-recording' onclick="recordData();">
+ Trigger Recording
+ </button>
+ </div>
+ </body>
+ </html>
+
+
+.. _the-api:
+
+The API
+=======
+The hybrid content API is available to the web content through the inclusion of the `HybridContentTelemetry-lib.js <https://searchfox.org/mozilla-central/source/toolkit/components/telemetry/hybrid-content/HybridContentTelemetry-lib.js>`_ library.
+
+The initial implementation of the API allows the registration and the recording of events.
+
+JS API
+------
+Authorized content can use the following functions:
+
+.. code-block:: js
+
+ Mozilla.ContentTelemetry.canUpload();
+ Mozilla.ContentTelemetry.initPromise();
+ Mozilla.ContentTelemetry.registerEvents(category, eventData);
+ Mozilla.ContentTelemetry.recordEvent(category, method, object, value, extra);
+
+These functions will not throw. If an unsupported operation is performed (e.g. recording an unknown event) an error will be logged to the browser console.
+
+.. note::
+
+ Data collected using this API will always respect the user Telemetry preferences: if a user has chosen to not send Telemetry data to Mozilla servers, Telemetry from hybrid content pages will not be sent either.
+ Like other Telemetry data, it will still be recorded locally and available through ``about:telemetry``.
+
+``Mozilla.ContentTelemetry.canUpload()``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ Mozilla.ContentTelemetry.canUpload();
+
+This function returns true if the browser is allowed to send collected data to Mozilla servers (i.e. ``datareporting.healthreport.uploadEnabled`` is ``true``), false otherwise. See :doc:`preferences <../internals/preferences>`.
+
+.. note::
+
+ The page should use this function to check if it is allowed to collect data. This is only needed in case the Telemetry system is not be being used for collection. If Telemetry is used, then this is taken care of internally by the Telemetry API. The page should not cache the returned value: users can opt in or out from the Data Collection at any time and so the returned value may change.
+
+Example:
+
+.. code-block:: js
+
+ if (Mozilla.ContentTelemetry.canUpload()) {
+ // ... perform the data collection here using another measurement system.
+ }
+
+``Mozilla.ContentTelemetry.initPromise()``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ Mozilla.ContentTelemetry.initPromise();
+
+This function returns a Promise that gets resolved as soon as Hybrid Content Telemetry is correctly initialized and the value from ``canUpload`` can be reliably read. The promise will reject if Hybrid Content Telemetry is disabled or the host doesn't have enough privileges to use the API.
+
+``Mozilla.ContentTelemetry.registerEvents()``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ Mozilla.ContentTelemetry.registerEvents(category, eventData);
+
+Register new dynamic events from the content. This accepts the same parameters and is subject to the same limitation as ``Services.telemetry.registerEvents()``. See the `events` documentation for the definitive reference.
+
+.. note::
+
+ Make sure to call this before recording events, as soon as the library is loaded (e.g. `window load event <https://developer.mozilla.org/en-US/docs/Web/Events/load>`_). This will make sure that the definition will be ready when recording.
+
+The data recorded into events registered with this function will end up in the ``dynamic`` process section of the main ping.
+
+Example:
+
+.. code-block:: js
+
+ Mozilla.ContentTelemetry.registerEvents("page.interaction", {
+ "click": {
+ methods: ["click"],
+ objects: ["red_button", "blue_button"],
+ }
+ });
+ // Now events can be recorded.
+ Mozilla.ContentTelemetry.recordEvent("page.interaction", "click", "red_button");
+
+``Mozilla.ContentTelemetry.recordEvent()``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: js
+
+ Mozilla.ContentTelemetry.recordEvent(category, method, object, value, extra);
+
+Record a registered event. This accepts the same parameters and is subject to the same limitation as ``Services.telemetry.recordEvent()``. See the `events` documentation for the definitive reference.
+
+Example:
+
+.. code-block:: js
+
+ Mozilla.ContentTelemetry.recordEvent("ui", "click", "reload-btn");
+ // event: [543345, "ui", "click", "reload-btn"]
+ Mozilla.ContentTelemetry.recordEvent("ui", "search", "search-bar", "google");
+ // event: [89438, "ui", "search", "search-bar", "google"]
+ Mozilla.ContentTelemetry.recordEvent("ui", "completion", "search-bar", "yahoo",
+ {"querylen": "7", "results": "23"});
+ // event: [982134, "ui", "completion", "search-bar", "yahoo",
+ // {"qerylen": "7", "results": "23"}]
+
+Data Review
+===========
+
+Adding the ``hc_telemetry`` permission for a new domain in `browser/app/permissions <https://searchfox.org/mozilla-central/source/browser/app/permissions>`_
+requires `Data Collection Review <https://wiki.mozilla.org/Firefox/Data_Collection>`_ as we are enabling a new method of data collection.
+
+Giving a domain permission to use Hybrid Content Telemetry also gives any Extensions running on this domain permission to use Hybrid Content Telemetry.
+If the domain is already on the `list of restricted domains <https://hg.mozilla.org/integration/mozilla-inbound/file/39e131181d44/modules/libpref/init/all.js#l5120>`_
+(configured by the ``extensions.webextensions.restrictedDomains`` preference), Extensions don't run on this domain and therefore cannot access the Hybrid Content Telemetry API.
+No additional approval is necessary.
+
+If the domain is not on that list, you need additional privacy review. In that case request help from the Telemetry team.
+
+Testing
+=======
+
+In order to test Hybrid Content Telemetry integrations, the permission API can be used to enable certain hosts.
+The ``Services.perms.addFromPrincipal`` API is available in the Browser Console as well as in ``xpcshell`` and ``mochi`` tests with access to the ``Services.*`` APIs.
+
+The respective ``hc_telemetry`` permission needs to be set before any pages on that host load the ``HybridContentTelemetry-lib.js`` file.
+
+Manual testing
+--------------
+
+After starting the browser, open the Browser Console (Tools -> Web Developer -> Browser Console).
+To enable Hybrid Content Telemetry on ``https://example.mozilla.org``, execute this code snippet in the console:
+
+.. code-block:: js
+
+ let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin("https://example.mozilla.org");
+ Services.perms.addFromPrincipal(principal, "hc_telemetry", Services.perms.ALLOW_ACTION);
+
+Afterwards load the page on ``https://example.mozilla.org`` and it will be able to record Telemetry data.
+
+.. note::
+
+ Manual testing requires a host that handles HTTPS connections, as this kind of collection is only allowed on secure hosts. To allow for local testing, a local proxy capable of handling HTTPS connection is required.
+
+Automated testing
+-----------------
+
+In test frameworks with privileged access the permission can be set in the ``head.js`` or during test setup.
+Add the code snippet in your ``head.js`` to enable Hybrid Content ContentTelemetry on ``https://example.mozilla.org``:
+
+.. code-block:: js
+
+ let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin("https://example.mozilla.org");
+ Services.perms.addFromPrincipal(principal, "hc_telemetry", Services.perms.ALLOW_ACTION);
+
+Version History
+===============
+
+- Firefox 59: Initial hybrid content telemetry support (`bug 1417473 <https://bugzilla.mozilla.org/show_bug.cgi?id=1417473>`_).
+- Firefox 71: Hybrid Content Telemetry removed (`bug 1520491 <https://bugzilla.mozilla.org/show_bug.cgi?id=1520491>`_).
diff --git a/toolkit/components/telemetry/docs/obsolete/index.rst b/toolkit/components/telemetry/docs/obsolete/index.rst
new file mode 100644
index 0000000000..fc2acf7615
--- /dev/null
+++ b/toolkit/components/telemetry/docs/obsolete/index.rst
@@ -0,0 +1,15 @@
+.. _telemetry_obsolete:
+
+======================
+Obsolete Documentation
+======================
+
+.. toctree::
+ :glob:
+ :maxdepth: 5
+ :titlesonly:
+
+ uitelemetry/index
+ fhr/index
+ hybrid-content
+ *
diff --git a/toolkit/components/telemetry/docs/obsolete/optout-ping.rst b/toolkit/components/telemetry/docs/obsolete/optout-ping.rst
new file mode 100644
index 0000000000..910bb41220
--- /dev/null
+++ b/toolkit/components/telemetry/docs/obsolete/optout-ping.rst
@@ -0,0 +1,33 @@
+
+"optout" ping (obsolete)
+========================
+
+This ping is generated when a user turns off FHR upload from the Preferences panel, changing the related ``datareporting.healthreport.uploadEnabled`` :doc:`preference <../internals/preferences>`.
+
+This ping contains no client id and no environment data.
+
+Structure:
+
+.. code-block:: js
+
+ {
+ version: 4,
+ type: "optout",
+ ... common ping data
+ payload: { }
+ }
+
+Expected behaviours
+-------------------
+The following is a list of expected behaviours for the ``optout`` ping:
+
+- Sending the "optout" ping is best-effort. Telemetry tries to send the ping once and discards it immediately if sending fails.
+- The ping might be delayed if ping sending is throttled (e.g. around midnight).
+- The ping can be lost if the browser is shutdown before the ping is sent out the "optout" ping is discarded.
+
+Version History
+---------------
+
+- Firefox 63:
+
+ - "optout" ping replaced the "deletion" ping (`bug 1445921 <https://bugzilla.mozilla.org/show_bug.cgi?id=1445921>`_).
diff --git a/toolkit/components/telemetry/docs/obsolete/uitelemetry/index.rst b/toolkit/components/telemetry/docs/obsolete/uitelemetry/index.rst
new file mode 100644
index 0000000000..89447cc9eb
--- /dev/null
+++ b/toolkit/components/telemetry/docs/obsolete/uitelemetry/index.rst
@@ -0,0 +1,146 @@
+.. _uitelemetry:
+
+==================================
+UITelemetry data format (obsolete)
+==================================
+
+.. note::
+
+ ``UITelemetry`` is deprecated. As of Firefox 61, ``UITelemetry`` is no longer reported.
+
+UI Telemetry sends its data as a JSON blob. This document describes the different parts
+of the JSON blob.
+
+``toolbars``
+============
+
+This tracks the state of the user's UI customizations. It has the following properties:
+
+- ``sizemode`` - string indicating whether the window is in maximized, normal (restored) or
+ fullscreen mode;
+- ``bookmarksBarEnabled`` - boolean indicating whether the bookmarks bar is visible;
+- ``menuBarEnabled`` - boolean indicating whether the menu bar is visible (always false on OS X);
+- ``titleBarEnabled`` - boolean indicating whether the (real) titlebar is visible (rather than
+ having tabs in the titlebar);
+- ``defaultKept`` - list of strings identifying toolbar buttons and items that are still in their
+ default position. Only the IDs of builtin widgets are sent (ie not add-on widgets);
+- ``defaultMoved`` - list of strings identifying toolbar buttons and items that are no longer in
+ their default position, but have not been removed to the palette. Only the IDs of builtin widgets
+ are sent (ie not add-on widgets);
+- ``nondefaultAdded`` - list of strings identifying toolbar buttons and items that have been added
+ from the palette. Only the IDs of builtin widgets are sent (ie not add-on widgets);
+- ``defaultRemoved`` - list of strings identifying toolbar buttons and items that are in the
+ palette that are elsewhere by default. Only the IDs of builtin widgets are sent
+ (ie not add-on widgets);
+- ``addonToolbars`` - the number of non-default toolbars that are customizable. 1 by default
+ because it counts the add-on bar shim;
+- ``visibleTabs`` - array of the number of visible tabs per window;
+- ``hiddenTabs`` - array of the number of hidden tabs per window (ie tabs in panorama groups which
+ are not the current group);
+- ``countableEvents`` - please refer to the next section.
+- ``durations`` - an object mapping descriptions to duration records, which records the amount of
+ time a user spent doing something. Currently only has one property:
+
+ - ``customization`` - how long a user spent customizing the browser. This is an array of
+ objects, where each object has a ``duration`` property indicating the time in milliseconds,
+ and a ``bucket`` property indicating a bucket in which the duration info falls.
+
+
+.. _UITelemetry_countableEvents:
+
+``countableEvents``
+===================
+
+Countable events are stored under the ``toolbars`` section. They count the number of times certain
+events happen. No timing or other correlating information is stored - purely the number of times
+things happen.
+
+``countableEvents`` contains a list of buckets as its properties. A bucket represents the state the browser was in when these events occurred, such as currently running an interactive tour. There are 3 types of buckets:
+
+- ``__DEFAULT__`` - No bucket, for times when the browser is not in any special state.
+- ``bucket_<NAME>`` - Normal buckets, for when the browser is in a special state. The ``<NAME>`` in the bucket ID is the name associated with the bucket and may be further broken down into parts by the ``|`` character.
+- ``bucket_<NAME>|<INTERVAL>`` - Expiring buckets, which are similar to a countdown timer. The ``<INTERVAL>`` in the bucket ID describes the time interval the recorded event happened in. The intervals are ``1m`` (one minute), ``3m`` (three minutes), ``10m`` (ten minutes), and ``1h`` (one hour). After one hour, the ``__DEFAULT__`` bucket is automatically used again.
+
+Each bucket is an object with the following properties:
+
+- ``click-builtin-item`` is an object tracking clicks on builtin customizable toolbar items, keyed
+ off the item IDs, with an object for each item with keys ``left``, ``middle`` and ``right`` each
+ storing a number indicating how often the respective type of click has happened.
+- ``click-menu-button`` is the same, except the item ID is always 'button'.
+- ``click-bookmarks-bar`` is the same, with the item IDs being replaced by either ``container`` for
+ clicks on bookmark or livemark folders, and ``item`` for individual bookmarks.
+- ``click-menubar`` is similar, with the item IDs being replaced by one of ``menu``, ``menuitem``
+ or ``other``, depending on the kind of item clicked. Note that this is not tracked on OS X, where
+ we can't listen for these events because of the global menubar.
+- ``click-bookmarks-menu-button`` is also similar, with the item IDs being replaced by:
+
+ - ``menu`` for clicks on the 'menu' part of the item;
+ - ``add`` for clicks that add a bookmark;
+ - ``edit`` for clicks that open the panel to edit an existing bookmark;
+ - ``in-panel`` for clicks when the button is in the menu panel, and clicking it does none of the
+ above;
+- ``customize`` tracks different types of customization events without the ``left``, ``middle`` and
+ ``right`` distinctions. The different events are the following, with each storing a count of the
+ number of times they occurred:
+
+ - ``start`` counts the number of times the user starts customizing;
+ - ``add`` counts the number of times an item is added somewhere from the palette;
+ - ``move`` counts the number of times an item is moved somewhere else (but not to the palette);
+ - ``remove`` counts the number of times an item is removed to the palette;
+ - ``reset`` counts the number of times the 'restore defaults' button is used;
+- ``search`` is an object tracking searches of various types, keyed off the search
+ location, storing a number indicating how often the respective type of search
+ has happened.
+
+ - There are also two special keys that mean slightly different things.
+
+ - ``urlbar-keyword`` records searches that would have been an invalid-protocol
+ error, but are now keyword searches. They are also counted in the ``urlbar``
+ keyword (along with all the other urlbar searches).
+ - ``selection`` searches records selections of search suggestions. They include
+ the source, the index of the selection, and the kind of selection (mouse or
+ enter key). Selection searches are also counted in their sources.
+
+
+
+``UITour``
+==========
+
+The UITour API provides ways for pages on trusted domains to safely interact with the browser UI and request it to perform actions such as opening menus and showing highlights over the browser chrome - for the purposes of interactive tours. We track some usage of this API via the ``UITour`` object in the UI Telemetry output.
+
+Each page is able to register itself with an identifier, a ``Page ID``. A list of Page IDs that have been seen over the last 8 weeks is available via ``seenPageIDs``.
+
+Page IDs are also used to identify buckets for :ref:`UITelemetry_countableEvents`, in the following circumstances:
+
+- The current tab is a tour page. This will be a normal bucket with the name ``UITour|<PAGEID>``, where ``<PAGEID>`` is the page's registered ID. This will result in bucket IDs such as ``bucket_UITour|australis-tour``.
+- A tour tab is open but another tab is active. This will be an expiring bucket with the name ``UITour|<PAGEID>|inactive``. This will result in bucket IDs such as ``bucket_UITour|australis-tour|inactive|1m``.
+- A tour tab has recently been open but has been closed. This will be an expiring bucket with the name ``UITour|<PAGEID>|closed``. This will result in bucket IDs such as ``bucket_UITour|australis-tour|closed|10m``.
+
+
+
+``contextmenu``
+===============
+
+We track context menu interactions to figure out which ones are most often used and/or how
+effective they are. In the ``contextmenu`` object, we first store things per-bucket. Next, we
+divide the following different context menu situations:
+
+- ``selection`` if there is content on the page that's selected on which the user clicks;
+- ``link`` if the user opened the context menu for a link
+- ``image-link`` if the user opened the context menu on an image or canvas that's a link;
+- ``image`` if the user opened the context menu on an image (that isn't a link);
+- ``canvas`` if the user opened the context menu on a canvas (that isn't a link);
+- ``media`` if the user opened the context menu on an HTML video or audio element;
+- ``input`` if the user opened the context menu on a text input element;
+- ``other`` for all other openings of the content menu;
+
+Each of these objects (if they exist) then gets a "withcustom" and/or a "withoutcustom" property
+for context menus opened with custom page-created items and without them, and each of those
+properties holds an object with IDs corresponding to a count of how often an item with that ID was
+activated in the context menu. Only builtin context menu items are tracked, and besides those items
+there are four special items which get counts:
+
+- ``close-without-interaction`` is incremented when the user closes the context menu without interacting with it;
+- ``custom-page-item`` is incremented when the user clicks an item that was created by the page;
+- ``unknown`` is incremented when an item without an ID was clicked;
+- ``other-item`` is incremented when an add-on-provided menuitem is clicked.
diff --git a/toolkit/components/telemetry/docs/start/adding-a-new-probe.rst b/toolkit/components/telemetry/docs/start/adding-a-new-probe.rst
new file mode 100644
index 0000000000..f1baeadf82
--- /dev/null
+++ b/toolkit/components/telemetry/docs/start/adding-a-new-probe.rst
@@ -0,0 +1,153 @@
+============================
+Adding a new Telemetry probe
+============================
+
+In Firefox, the Telemetry system collects various measures of Firefox performance, hardware, usage and customizations and submit it to Mozilla. This article provides an overview of what is needed to add any new Telemetry data collection.
+
+.. important::
+
+ Every new data collection in Firefox needs a `data collection review <https://wiki.mozilla.org/Firefox/Data_Collection#Requesting_Approval>`__ from a data collection peer. Just set the feedback? flag for one of the data peers. They try to reply within a business day.
+
+What is your goal?
+==================
+
+We have various :doc:`data collection tools <../collection/index>` available, each serving different needs. Before diving right into technical details, it is best to take a step back and consider what you need to achieve.
+
+Your goal could be to answer product questions like “how many people use feature X?” or “what is the error rate of service Y?”.
+You could also be focused more on answering engineering questions, say “which web features are most used?” or “how is the performance of engine Z?”.
+
+From there, questions you should ask are:
+
+- What is the minimum data that can answer your questions?
+- How many people do you need this data from?
+- Is data from the pre-release channels sufficient?
+
+This also informs the `data collection review <https://wiki.mozilla.org/Firefox/Data_Collection>`__, which requires a plan for how to use the data. Data collection review is required for all new data collection.
+
+Data collection levels
+======================
+
+Most of our data collection falls into one of two levels, *release* and *pre-release*.
+
+**Release data** is recorded by default on all channels, users need to explicitly opt out to disable it. This has `stricter constraints <https://wiki.mozilla.org/Firefox/Data_Collection#Requirements>`_ for what data we can collect. "Most" users submit this data.
+
+**Pre-release data** is not recorded on release, but is collected by default on our pre-release channels (Beta and Nightly), so it can be biased.
+
+These levels cover what is described in the `Firefox privacy notice <https://www.mozilla.org/en-US/privacy/firefox/>`_. For other needs, there might be custom mechanisms that clearly require user opt-in and show what data is collected.
+
+Rich data & aggregate data
+==========================
+
+For the recording and transmission of data, we have various data types available. We can divide these data types into two large groups.
+
+**Aggregate data** is aggregated on the client-side and cheap to send, process and analyze. This could e.g. be a simple count of tab opens or a histogram showing how long it takes to switch between tabs. This should be your default choice and is well supported in our analysis tools.
+
+**Rich data** is used when questions can not be answered from aggregate data. When we send more detailed data we can e.g. see when a specific UI interaction happened and in which context.
+
+As a general rule, you can inform the choice of data types from your goals like this:
+
++------------------------+-----------------+-----------------------+
+| Goals | Collection type | Implementation |
++========================+=================+=======================+
+| On-going monitoring | Aggregate data | Histograms |
+| | | |
+| Health tracking | | Scalars |
+| | | |
+| KPI impact | | Environment data |
++------------------------+-----------------+-----------------------+
+| Detailed user behavior | Rich data | Event Telemetry |
+| | | |
+| Funnel analysis | | Detailed custom pings |
+| | | |
+| Diagnostics | | Logs |
+| | | |
+| | | Crash data |
++------------------------+-----------------+-----------------------+
+
+Aggregate data
+--------------
+
+Most of our data collection happens through :doc:`scalars <../collection/scalars>` and :doc:`histograms <../collection/histograms>`:
+
+- Scalars allow collection of simple values, like counts, booleans and strings.
+- Histograms allow collection of multiple different values, but aggregate them into a number of buckets. Each bucket has a value range and a count of how many values we recorded.
+
+Both scalars & histograms allow recording by keys. This allows for more flexible, two-level data collection.
+
+Other collections can build on top of scalars & histograms. An example is :doc:`use counters <../collection/use-counters>`, which submit web feature usage through histograms.
+
+We also collect :doc:`environment data <../data/environment>`. This consists of mostly scalar values that capture the “working environment” a Firefox session lives in, and includes e.g. data on hardware, OS, add-ons and some settings. Any data that is part of the "working environment", or needs to split :doc:`subsessions <../concepts/sessions>`, should go into it.
+
+Rich data
+---------
+
+Aggregate data can tell you that something happened, but is usually lacking details about what exactly. When more details are needed, we can collect them using other tools that submit less efficient data. This usually means that we can't enable the data collection for all users, for cost and performance concerns.
+
+There are multiple mechanisms to collect rich data:
+
+**Stack collection** helps with e.g. diagnosing hangs. Stack data is recorded into chrome hangs and threadhang stats. To diagnose where rarely used code is called from, you can use stack capturing.
+
+:doc:`Event Telemetry <../collection/events>` provides a way to record both when and what happened. This enables e.g. funnel analysis for usage.
+
+:doc:`Custom pings <../collection/custom-pings>` are used when other existing data collection does not cover your need. Submitting a custom ping enables you to submit your own JSON package that will be delivered to the Telemetry servers. However, this loses you access to existing tooling and makes it harder to join your data with other sources.
+
+Setup & building
+================
+
+Every build of Firefox has Telemetry enabled. Local developer builds with no custom build flags will record all Telemetry data, but not send it out.
+
+When adding any new scalar, histogram or event Firefox needs to be built. Artifact builds are currently not supported, even if code changes are limited to JavaScript.
+
+Usually you don't need to send out data to add new Telemetry. In the rare event you do, you need the following in your *.mozconfig*::
+
+ MOZ_TELEMETRY_REPORTING=1
+ MOZILLA_OFFICIAL=1
+
+Testing
+=======
+
+Local confirmation
+------------------
+
+Your first step should always be to confirm your new data collection locally.
+
+The *about:telemetry* page allows to view any data you submitted to Telemetry in the last 60 days, whether it is in existing pings or in new custom pings. You can choose which pings to display on the top-left.
+
+If you need to confirm when - or if - pings are getting sent, you can run an instance of the `gzipServer <https://github.com/mozilla/gzipServer>`_ locally. It emulates roughly how the official Telemetry servers respond, and saves all received pings to disk for inspection.
+
+Test coverage
+-------------
+
+Any data collection that you need to base decisions on needs to have test coverage. Using JS, you can access the recorded values for your data collection. You can use the following functions:
+
+- for scalars, `getSnapshotForScalars() <https://searchfox.org/mozilla-central/rev/f997bd6bbfc4773e774fdb6cd010142370d186f9/toolkit/components/telemetry/core/nsITelemetry.idl#90-102>`_
+ or `getSnapshotForKeyedScalars() <https://searchfox.org/mozilla-central/rev/f997bd6bbfc4773e774fdb6cd010142370d186f9/toolkit/components/telemetry/core/nsITelemetry.idl#104-116>`_
+- for histograms, `getSnapshotForHistograms() <https://searchfox.org/mozilla-central/rev/f997bd6bbfc4773e774fdb6cd010142370d186f9/toolkit/components/telemetry/core/nsITelemetry.idl#54-74>`_
+ or `getSnapshotForKeyedHistograms() <https://searchfox.org/mozilla-central/rev/f997bd6bbfc4773e774fdb6cd010142370d186f9/toolkit/components/telemetry/core/nsITelemetry.idl#76-88>`_
+
+ * Optionally, histogram objects have a `snapshot() <https://searchfox.org/mozilla-central/rev/f997bd6bbfc4773e774fdb6cd010142370d186f9/toolkit/components/telemetry/core/nsITelemetry.idl#285-287,313-315>`_ method.
+
+- for events, `snapshotEvents() <https://searchfox.org/mozilla-central/rev/f997bd6bbfc4773e774fdb6cd010142370d186f9/toolkit/components/telemetry/core/nsITelemetry.idl#542-558>`_
+
+If you need to test that pings were correctly passed to Telemetry, you can use `TelemetryArchiveTesting <https://searchfox.org/mozilla-central/search?q=TelemetryArchiveTesting&redirect=false>`_.
+
+Validation
+----------
+
+While it's important to confirm that the data collection works on your machine, the Firefox user population is very diverse. Before basing decisions on any new data, it should be validated. This could take various forms.
+
+For *new data collection* using existing Telemetry data types, the transport mechanism is already tested. It is sufficient to validate the incoming values. This could happen through `Redash <https://docs.telemetry.mozilla.org/tools/stmo.html>`_ or through `custom analysis <https://docs.telemetry.mozilla.org/tools/spark.html>`_.
+
+For *new custom pings*, you'll want to check schema validation results, as well as that the contents look valid.
+
+Getting help
+============
+
+You can find all important Telemetry resources listed on `telemetry.mozilla.org <https://telemetry.mozilla.org/>`_.
+
+The Telemetry team is there to help with any problems. You can reach us via:
+
+- Matrix in `#telemetry:mozilla.org <https://chat.mozilla.org/#/room/#telemetry:mozilla.org>`_
+- Slack in `#data-help <https://mozilla.slack.com/messages/data-help/>`_
+- the `fx-data-dev mailing list <https://mail.mozilla.org/listinfo/fx-data-dev>`_
+- flags for `one of the peers <https://wiki.mozilla.org/Modules/Toolkit#Telemetry>`_ on Bugzilla or send us an e-mail
diff --git a/toolkit/components/telemetry/docs/start/index.rst b/toolkit/components/telemetry/docs/start/index.rst
new file mode 100644
index 0000000000..9cc544c9a3
--- /dev/null
+++ b/toolkit/components/telemetry/docs/start/index.rst
@@ -0,0 +1,28 @@
+===============
+Getting started
+===============
+
+If you are interested in extending data collection by adding new probes have a look at
+
+.. toctree::
+ :maxdepth: 2
+ :titlesonly:
+ :glob:
+
+ adding-a-new-probe
+ report-gecko-telemetry-in-glean
+
+If you want to work with the telemetry code itself, for example to fix a bug, it is often helpful to start with these steps:
+
+1. Have a look at about:telemetry to see which data is being collected and sent.
+2. Increase the log level in about:config by setting toolkit.telemetry.log.level to Debug or Trace. This will show telemetry information in the browser console. To enable the browser console follow `these instructions <../../../../devtools-user/browser_console/index.html>`__.
+3. Run a local telemetry receiver, e.g. `this one <https://github.com/mozilla/gzipServer>`__ and set ``toolkit.telemetry.server`` to “localhost” (Like the next preference this needs a restart.)
+4. Set ``toolkit.telemetry.send.overrideOfficialCheck = true``, otherwise local debug builds will not send telemetry data. (Requires restart.)
+
+More information about the internals can be found `here <../internals/index.html>`__.
+
+Further Reading
+###############
+
+* `Telemetry Portal <https://telemetry.mozilla.org/>`_ - Discover all important resources for working with data
+* `Telemetry Data Documentation <https://docs.telemetry.mozilla.org/>`_ - Find what data is available & how to use it
diff --git a/toolkit/components/telemetry/docs/start/report-gecko-telemetry-in-glean.rst b/toolkit/components/telemetry/docs/start/report-gecko-telemetry-in-glean.rst
new file mode 100644
index 0000000000..1e7cb4aca5
--- /dev/null
+++ b/toolkit/components/telemetry/docs/start/report-gecko-telemetry-in-glean.rst
@@ -0,0 +1,36 @@
+=======================================================
+How to report Gecko Telemetry in engine-gecko via Glean
+=======================================================
+
+In Gecko, the `Telemetry <../index.html>`__ system collects various measures of Gecko performance, hardware, usage and customizations.
+When the Gecko engine is embedded in Android products that use
+`the Glean SDK <https://docs.telemetry.mozilla.org/concepts/glean/glean.html>`__ for data collection, then Gecko metrics can be reported in `Glean pings <https://mozilla.github.io/glean/book/user/pings/index.html>`__.
+This article provides an overview of what is needed to report any existing or new Telemetry data collection in Glean.
+
+.. important::
+
+ Every new or changed data collection in Firefox needs a `data collection review <https://wiki.mozilla.org/Data_Collection>`__ from a Data Steward.
+
+Using Glean
+===========
+In short, the way to collect data in all Mozilla products using Gecko is to use Glean.
+The Glean SDK is present in Gecko and all of Firefox Desktop via
+`Firefox on Glean (FOG) <../../glean/index.html>`__.
+If you instrument your Gecko data collection using Glean metrics,
+they will be reported by all products that use both Gecko and Glean so long as it is defined in a
+``metrics.yaml`` file in the ``gecko_metrics`` list of ``toolkit/components/glean/metrics_index.py``.
+
+See `these docs <../../glean/user/new_definitions_file.html>`__ for details.
+Additional relevant concepts are covered in
+`this guide for migrating Firefox Telemetry collections to Glean <../../glean/user/migration.html>`__.
+
+To make sure your data is also reported in Telemetry when your code is executed in Firefox Desktop,
+you must be sure to mirror the collection in Telemetry.
+If possible, you should use the
+`Glean Interface For Firefox Telemetry (GIFFT) <../../glean/user/gifft.html>`__
+and let FOG mirror the call for you.
+If that doesn't look like it'll work out for you,
+you can instead add your Glean API calls just next to your Telemetry API calls.
+
+As always, if you have any questions, you can find helpful people in
+`the #telemetry channel on Mozilla's Matrix <https://chat.mozilla.org/#/room/#telemetry:mozilla.org>`__.