diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /browser/components/urlbar/docs | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | browser/components/urlbar/docs/contact.rst | 9 | ||||
-rw-r--r-- | browser/components/urlbar/docs/debugging.rst | 4 | ||||
-rw-r--r-- | browser/components/urlbar/docs/experiments.rst | 727 | ||||
-rw-r--r-- | browser/components/urlbar/docs/index.rst | 26 | ||||
-rw-r--r-- | browser/components/urlbar/docs/overview.rst | 413 | ||||
-rw-r--r-- | browser/components/urlbar/docs/telemetry.rst | 445 | ||||
-rw-r--r-- | browser/components/urlbar/docs/utilities.rst | 26 |
7 files changed, 1650 insertions, 0 deletions
diff --git a/browser/components/urlbar/docs/contact.rst b/browser/components/urlbar/docs/contact.rst new file mode 100644 index 0000000000..abd9947528 --- /dev/null +++ b/browser/components/urlbar/docs/contact.rst @@ -0,0 +1,9 @@ +Getting in Touch +================ + +For any questions regarding the Address Bar, the team is available through +the #search channel on Slack and the fx-search@mozilla.com mailing +list. + +Issues can be `filed in Bugzilla <https://bugzilla.mozilla.org/enter_bug.cgi?product=Firefox&component=Address%20Bar>`_ +under the Firefox / Address Bar component. diff --git a/browser/components/urlbar/docs/debugging.rst b/browser/components/urlbar/docs/debugging.rst new file mode 100644 index 0000000000..689657c068 --- /dev/null +++ b/browser/components/urlbar/docs/debugging.rst @@ -0,0 +1,4 @@ +Debugging & Logging +=================== + +*Content to be written* diff --git a/browser/components/urlbar/docs/experiments.rst b/browser/components/urlbar/docs/experiments.rst new file mode 100644 index 0000000000..f1217df391 --- /dev/null +++ b/browser/components/urlbar/docs/experiments.rst @@ -0,0 +1,727 @@ +Extensions & Experiments +======================== + +This document describes address bar extensions and experiments: what they are, +how to run them, how to write them, and the processes involved in each. + +The primary purpose right now for writing address bar extensions is to run +address bar experiments. But extensions are useful outside of experiments, and +not all experiments use extensions. + +Like all Firefox extensions, address bar extensions use the WebExtensions_ +framework. + +.. _WebExtensions: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions + +.. toctree:: + :caption: Table of Contents + + experiments + +WebExtensions +------------- + +**WebExtensions** is the name of Firefox's extension architecture. The "web" +part of the name hints at the fact that Firefox extensions are built using Web +technologies: JavaScript, HTML, CSS, and to a certain extent the DOM. + +Individual extensions themselves often are referred to as *WebExtensions*. For +clarity and conciseness, this document will refer to WebExtensions as +*extensions*. + +Why are we interested in extensions? Mainly because they're a powerful way to +run experiments in Firefox. See Experiments_ for more on that. In addition, we'd +also like to build up a robust set of APIs useful to extension authors, although +right now the API can only be used by Mozilla extensions. + +WebExtensions are introduced and discussed in detail on `MDN +<WebExtensions_>`__. You'll need a lot of that knowledge in order to build +address bar extensions. + +Developing Address Bar Extensions +--------------------------------- + +Overview +~~~~~~~~ + +The address bar WebExtensions API currently lives in two API namespaces, +``browser.urlbar`` and ``browser.experiments.urlbar``. The reason for this is +historical and is discussed in the `Developing Address Bar Extension APIs`_ +section. As a consumer of the API, there are only two important things you need +to know: + +* There's no meaningful difference between the APIs of the two namespaces. + Their kinds of functions, events, and properties are similar. You should + think of the address bar API as one single API that happens to be split into + two namespaces. + +* However, there is a big difference between the two when it comes to setting up + your extension to use them. This is discussed next. + +The ``browser.urlbar`` API namespace is built into Firefox. It's a +**privileged API**, which means that only Mozilla-signed and temporarily +installed extensions can use it. The only thing your Mozilla extension needs to +do in order to use it is to request the ``urlbar`` permission in its +manifest.json, as illustrated `here <urlbarPermissionExample_>`__. + +In contrast, the ``browser.experiments.urlbar`` API namespace is bundled inside +your extension. APIs that are bundled inside extensions are called +**experimental APIs**, and the extensions in which they're bundled are called +**WebExtension experiments**. As with privileged APIs, experimental APIs are +available only to Mozilla-signed and temporarily installed extensions. +("WebExtension experiments" is a term of art and shouldn't be confused with the +general notion of experiments that happen to use extensions.) For more on +experimental APIs and WebExtension experiments, see the `WebExtensions API +implementation documentation <webextAPIImplBasicsDoc_>`__. + +Since ``browser.experiments.urlbar`` is bundled inside your extension, you'll +need to include it in your extension's repo by doing the following: + +1. The implementation consists of two files, api.js_ and schema.json_. In your + extension repo, create a *experiments/urlbar* subdirectory and copy the + files there. See `this repo`__ for an example. + +2. Add the following ``experiment_apis`` key to your manifest.json (see here__ + for an example in context):: + + "experiment_apis": { + "experiments_urlbar": { + "schema": "experiments/urlbar/schema.json", + "parent": { + "scopes": ["addon_parent"], + "paths": [["experiments", "urlbar"]], + "script": "experiments/urlbar/api.js" + } + } + } + +As mentioned, only Mozilla-signed and temporarily installed extensions can use +these two API namespaces. For information on running the extensions you develop +that use these namespaces, see `Running Address Bar Extensions`_. + +.. _urlbarPermissionExample: https://github.com/0c0w3/urlbar-top-sites-experiment/blob/ac1517118bb7ee165fb9989834514b1082575c10/src/manifest.json#L24 +.. _webextAPIImplBasicsDoc: https://firefox-source-docs.mozilla.org/toolkit/components/extensions/webextensions/basics.html +.. _api.js: https://searchfox.org/mozilla-central/source/browser/components/urlbar/tests/ext/api.js +.. _schema.json: https://searchfox.org/mozilla-central/source/browser/components/urlbar/tests/ext/schema.json +__ https://github.com/0c0w3/dynamic-result-type-extension/tree/master/src/experiments/urlbar +__ https://github.com/0c0w3/dynamic-result-type-extension/blob/0987da4b259b9fcb139b31d771883a2f822712b5/src/manifest.json#L28 + +browser.urlbar +~~~~~~~~~~~~~~ + +Currently the only documentation for ``browser.urlbar`` is its `schema +<urlbar.json_>`__. Fortunately WebExtension schemas are JSON and aren't too hard +to read. If you need help understanding it, see the `WebExtensions API +implementation documentation <webextAPIImplDoc_>`__. + +For examples on using the API, see the Cookbook_ section. + +.. _urlbar.json: https://searchfox.org/mozilla-central/source/browser/components/extensions/schemas/urlbar.json + +browser.experiments.urlbar +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As with ``browser.urlbar``, currently the only documentation for +``browser.experiments.urlbar`` is its schema__. For examples on using the API, +see the Cookbook_ section. + +__ https://searchfox.org/mozilla-central/source/browser/components/urlbar/tests/ext/schema.json + +Workflow +~~~~~~~~ + +The web-ext_ command-line tool makes the extension-development workflow very +simple. Simply start it with the *run* command, passing it the location of the +Firefox binary you want to use. web-ext will launch your Firefox and remain +running until you stop it, watching for changes you make to your extension's +files. When it sees a change, it automatically reloads your extension — in +Firefox, in the background — without your having to do anything. It's really +nice. + +The `web-ext documentation <web-ext commands_>`__ lists all its options, but +here are some worth calling out for the *run* command: + +``--browser-console`` + Automatically open the browser console when Firefox starts. Very useful for + watching your extension's console logging. (Make sure "Show Content Messages" + is checked in the console.) + +``-p`` + This option lets you specify a path to a profile directory. + +``--keep-profile-changes`` + Normally web-ext doesn't save any changes you make to the profile. Use this + option along with ``-p`` to reuse the same profile again and again. + +``--verbose`` + web-ext suppresses Firefox messages in the terminal unless you pass this + option. If you've added some ``dump`` calls in Firefox because you're working + on a new ``browser.urlbar`` API, for example, you won't see them without this. + +web-ext also has a *build* command that packages your extension's files into a +zip file. The following *build* options are useful: + +``--overwrite-dest`` + Without this option, web-ext won't overwrite a zip file it previously created. + +web-ext can load its configuration from your extension's package.json. That's +the recommended way to configure it. Here's an example__. + +Finally, web-ext can also sign extensions, but if you're developing your +extension for an experiment, you'll use a different process for signing. See +`The Experiment Development Process`_. + +.. _web-ext: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Getting_started_with_web-ext +.. _web-ext commands: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/web-ext_command_reference +__ https://github.com/0c0w3/urlbar-top-sites-experiment/blob/6681a7126986bc2565d036b888cb5b8807397ce5/package.json#L7 + +Automated Tests +~~~~~~~~~~~~~~~ + +It's possible to write `browser chrome mochitests`_ for your extension the same +way we write tests for Firefox. One of the example extensions linked throughout +this document includes a test_, for instance. + +See the readme in the example-addon-experiment_ repo for a workflow. + +.. _browser chrome mochitests: https://developer.mozilla.org/en-US/docs/Mozilla/Browser_chrome_tests +.. _test: https://github.com/0c0w3/urlbar-top-sites-experiment/blob/master/tests/tests/browser/browser_urlbarTopSitesExtension.js + +Cookbook +~~~~~~~~ + +*To be written.* For now, you can find example uses of ``browser.experiments.urlbar`` and ``browser.urlbar`` in the following repos: + +* https://github.com/mozilla-extensions/firefox-quick-suggest-weather +* https://github.com/0c0w3/urlbar-tips-experiment +* https://github.com/0c0w3/urlbar-top-sites-experiment +* https://github.com/0c0w3/urlbar-search-interventions-experiment + +Further Reading +~~~~~~~~~~~~~~~ + +`WebExtensions on MDN <WebExtensions_>`__ + The place to learn about developing WebExtensions in general. + +`Getting started with web-ext <web-ext_>`__ + MDN's tutorial on using web-ext. + +`web-ext command reference <web-ext commands_>`__ + MDN's documentation on web-ext's commands and their options. + +Developing Address Bar Extension APIs +------------------------------------- + +Built-In APIs vs. Experimental APIs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Originally we developed the address bar extension API in the ``browser.urlbar`` +namespace, which is built into Firefox as discussed above. By "built into +Firefox," we mean that the API is developed in `mozilla-central +<urlbar.json_>`__ and shipped inside Firefox just like any other Firefox +feature. At the time, that seemed like the right thing to do because we wanted +to build an API that ultimately could be used by all extension authors, not only +Mozilla. + +However, there were a number of disadvantages to this development model. The +biggest was that it tightly coupled our experiments to specific versions of +Firefox. For example, if we were working on an experiment that targeted Firefox +72, then any APIs used by that experiment needed to land and ship in 72. If we +weren't able to finish an API by the time 72 shipped, then the experiment would +have to be postponed until 73. Our experiment development timeframes were always +very short because we always wanted to ship our experiments ASAP. Often we +targeted the Firefox version that was then in Nightly; sometimes we even +targeted the version in Beta. Either way, it meant that we were always uplifting +patch after patch to Beta. This tight coupling between Firefox versions and +experiments erased what should have been a big advantage of implementing +experiments as extensions in the first place: the ability to ship experiments +outside the usual cyclical release process. + +Another notable disadvantage of this model was just the cognitive weight of the +idea that we were developing APIs not only for ourselves and our experiments but +potentially for all extensions. This meant that not only did we have to design +APIs to meet our immediate needs, we also had to imagine use cases that could +potentially arise and then design for them as well. + +For these reasons, we stopped developing ``browser.urlbar`` and created the +``browser.experiments.urlbar`` experimental API. As discussed earlier, +experimental APIs are APIs that are bundled inside extensions. Experimental APIs +can do anything that built-in APIs can do with the added flexibility of not +being tied to specific versions of Firefox. + +Adding New APIs +~~~~~~~~~~~~~~~ + +All new address bar APIs should be added to ``browser.experiments.urlbar``. +Although this API does not ship in Firefox, it's currently developed in +mozilla-central, in `browser/components/urlbar/tests/ext/ <extDirectory_>`__ -- +note the "tests" subdirectory. Developing it in mozilla-central lets us take +advantage of our usual build and testing infrastructure. This way we have API +tests running against each mozilla-central checkin, against all versions of +Firefox that are tested on Mozilla's infrastructure, and we're alerted to any +breaking changes we accidentally make. When we start a new extension repo, we +copy schema.json and api.js to it as described earlier (or clone an example repo +with up-to-date copies of these files). + +Generally changes to the API should be reviewed by someone on the address bar +team and someone on the WebExtensions team. Shane (mixedpuppy) is a good +contact. + +.. _extDirectory: https://searchfox.org/mozilla-central/source/browser/components/urlbar/tests/ext/ + +Anatomy of an API +~~~~~~~~~~~~~~~~~ + +Roughly speaking, a WebExtensions API implementation comprises three different +pieces: + +Schema + The schema declares the functions, properties, events, and types that the API + makes available to extensions. Schemas are written in JSON. + + The ``browser.experiments.urlbar`` schema is schema.json_, and the + ``browser.urlbar`` schema is urlbar.json_. + + For reference, the schemas of built-in APIs are in + `browser/components/extensions/schemas`_ and + `toolkit/components/extensions/schemas`_. + + .. _browser/components/extensions/schemas: https://searchfox.org/mozilla-central/source/browser/components/extensions/schemas/ + .. _toolkit/components/extensions/schemas: https://searchfox.org/mozilla-central/source/toolkit/components/extensions/schemas/ + +Internals + Every API hooks into some internal part of Firefox. For the address bar API, + that's the Urlbar implementation in `browser/components/urlbar`_. + + .. _browser/components/urlbar: https://searchfox.org/mozilla-central/source/browser/components/urlbar/ + +Glue + Finally, there's some glue code that implements everything declared in the + schema. Essentially, this code mediates between the previous two pieces. It + translates the function calls, property accesses, and event listener + registrations made by extensions using the public-facing API into terms that + the Firefox internals understand, and vice versa. + + For ``browser.experiments.urlbar``, this is api.js_, and for + ``browser.urlbar``, it's ext-urlbar.js_. + + For reference, the implementations of built-in APIs are in + `browser/components/extensions`_ and `toolkit/components/extensions`_, in the + *parent* and *child* subdirecties. As you might guess, code in *parent* runs + in the main process, and code in *child* runs in the extensions process. + Address bar APIs deal with browser chrome and their implementations therefore + run in the parent process. + + .. _ext-urlbar.js: https://searchfox.org/mozilla-central/source/browser/components/extensions/parent/ext-urlbar.js + .. _browser/components/extensions: https://searchfox.org/mozilla-central/source/browser/components/extensions/ + .. _toolkit/components/extensions: https://searchfox.org/mozilla-central/source/toolkit/components/extensions/ + +Keep in mind that extensions run in a different process from the main process. +That has implications for your APIs. They'll generally need to be async, for +example. + +Further Reading +~~~~~~~~~~~~~~~ + +`WebExtensions API implementation documentation <webextAPIImplDoc_>`__ + Detailed info on implementing a WebExtensions API. + +.. _webextAPIImplDoc: https://firefox-source-docs.mozilla.org/toolkit/components/extensions/webextensions/ + +Running Address Bar Extensions +------------------------------ + +As discussed above, ``browser.experiments.urlbar`` and ``browser.urlbar`` are +privileged APIs. There are two different points to consider when it comes to +running an extension that uses privileged APIs: loading the extension in the +first place, and granting it access to privileged APIs. There's a certain bar +for loading any extension regardless of its API usage that depends on its signed +state and the Firefox build you want to run it in. There's yet a higher bar for +granting it access to privileged APIs. This section discusses how to load +extensions so that they can access privileged APIs. + +Since we're interested in extensions primarily for running experiments, there +are three particular signed states relevant to us: + +Unsigned + There are two ways to run unsigned extensions that use privileged APIs. + + They can be loaded temporarily using a Firefox Nightly build or + Developer Edition but not Beta or Release [source__], and the + ``extensions.experiments.enabled`` preference must be set to true [source__]. + You can load extensions temporarily by visiting + about:debugging#/runtime/this-firefox and clicking "Load Temporary Add-on." + `web-ext <Workflow_>`__ also loads extensions temporarily. + + __ https://searchfox.org/mozilla-central/rev/053826b10f838f77c27507e5efecc96e34718541/toolkit/components/extensions/Extension.jsm#1884 + __ https://searchfox.org/mozilla-central/rev/014fe72eaba26dcf6082fb9bbaf208f97a38594e/toolkit/mozapps/extensions/internal/AddonSettings.jsm#93 + + They can be also be loaded normally (not temporarily) in a custom build where + the build-time setting ``AppConstants.MOZ_REQUIRE_SIGNING`` [source__, source__] + and ``xpinstall.signatures.required`` pref are both false. As in the previous + paragraph, such builds include Nightly and Developer Edition but not Beta or + Release [source__]. In addition, your custom build must modify the + ``Extension.isPrivileged`` getter__ to return true. This getter determines + whether an extension can access privileged APIs. + + __ https://searchfox.org/mozilla-central/rev/053826b10f838f77c27507e5efecc96e34718541/toolkit/mozapps/extensions/internal/XPIProvider.jsm#2382 + __ https://searchfox.org/mozilla-central/rev/053826b10f838f77c27507e5efecc96e34718541/toolkit/mozapps/extensions/internal/AddonSettings.jsm#36 + __ https://searchfox.org/mozilla-central/search?q=MOZ_REQUIRE_SIGNING&case=false®exp=false&path= + __ https://searchfox.org/mozilla-central/rev/053826b10f838f77c27507e5efecc96e34718541/toolkit/components/extensions/Extension.jsm#1874 + + Extensions remain unsigned as you develop them. See the Workflow_ section for + more. + +Signed for testing (Signed for QA) + Signed-for-testing extensions that use privileged APIs can be run using the + same techniques for running unsigned extensions. + + They can also be loaded normally (not temporarily) if you use a Firefox build + where the build-time setting ``AppConstants.MOZ_REQUIRE_SIGNING`` is false and + you set the ``xpinstall.signatures.dev-root`` pref to true + [source__]. ``xpinstall.signatures.dev-root`` does not exist by default and + must be created. + + __ https://searchfox.org/mozilla-central/rev/053826b10f838f77c27507e5efecc96e34718541/toolkit/mozapps/extensions/internal/XPIInstall.jsm#262 + + You encounter extensions that are signed for testing when you are writing + extensions for experiments. See the Experiments_ section for details. + + "Signed for QA" is another way of referring to this signed state. + +Signed for release + Signed-for-release extensions that use privileged APIs can be run in any + Firefox build with no special requirements. + + You encounter extensions that are signed for release when you are writing + extensions for experiments. See the Experiments_ section for details. + +.. important:: + To see console logs from extensions in the browser console, select the "Show + Content Messages" option in the console's settings. This is necessary because + extensions run outside the main process. + +Experiments +----------- + +**Experiments** let us try out ideas in Firefox outside the usual release cycle +and on particular populations of users. + +For example, say we have a hunch that the top sites shown on the new-tab page +aren't very discoverable, so we want to make them more visible. We have one idea +that might work — show them every time the user begins an interaction with the +address bar — but we aren't sure how good an idea it is. So we test it. We write +an extension that does just that, make sure it collects telemetry that will help +us answer our question, ship it outside the usual release cycle to a small +percentage of Beta users, collect and analyze the telemetry, and determine +whether the experiment was successful. If it was, then we might want to ship the +feature to all Firefox users. + +Experiments sometimes are also called **studies** (not to be confused with *user +studies*, which are face-to-face interviews with users conducted by user +researchers). + +There are two types of experiments: + +Pref-flip experiments + Pref-flip experiments are simple. If we have a fully baked feature in the + browser that's preffed off, a pref-flip experiment just flips the pref on, + enabling the feature for users running the experiment. No code is required. + We tell the experiments team the name of the pref we want to flip, and they + handle it. + + One important caveat to pref-flip studies is that they're currently capable of + flipping only a single pref. There's an extension called Multipreffer_ that + can flip multiple prefs, though. + + .. _Multipreffer: https://github.com/mozilla/multipreffer + +Add-on experiments + Add-on experiments are much more complex but much more powerful. (Here + *add-on* is a synonym for extension.) They're the type of experiments that + this document has been discussing all along. + + An add-on experiment is shipped as an extension that we write and that + implements the experimental feature we want to test. To reiterate, the + extension is a WebExtension and uses WebExtensions APIs. If the current + WebExtensions APIs do not meet the needs of your experiment, then you must + create either experimental or built-in APIs so that your extension can use + them. If necessary, you can make any new built-in APIs privileged so that they + are available only to Mozilla extensions. + + An add-on experiment can collect additional telemetry that's not collected in + the product by using the privileged ``browser.telemetry`` WebExtensions API, + and of course the product will continue to collect all the telemetry it + usually does. The telemetry pings from users running the experiment will be + correlated with the experiment with no extra work on our part. + +A single experiment can deliver different UXes to different groups of users +running the experiment. Each group or UX within an experiment is called a +**branch**. Experiments often have two branches, control and treatment. The +**control branch** actually makes no UX changes. It may capture additional +telemetry, though. Think of it as the control in a science experiment. It's +there so we can compare it to data from the **treatment branch**, which does +make UX changes. Some experiments may require multiple treatment branches, in +which case the different branches will have different names. Add-on experiments +can implement all branches in the same extension or each branch in its own +extension. + +Experiments are delivered to users by a system called **Normandy**. Normandy +comprises a client side that lives in Firefox and a server side. In Normandy, +experiments are defined server-side in files called **recipes**. Recipes include +information about the experiment like the Firefox release channel and version +that the experiment targets, the number of users to be included in the +experiment, the branches in the experiment, the percentage of users on each +branch, and so on. + +Experiments are tracked by Mozilla project management using a system called +Experimenter_. + +Finally, there was an older version of the experiments program called +**Shield**. Experiments under this system were called **Shield studies** and +could be be shipped as extensions too. + +.. _Experimenter: https://experimenter.services.mozilla.com/ + +Further Reading +~~~~~~~~~~~~~~~ + +`Pref-Flip and Add-On Experiments <https://mana.mozilla.org/wiki/pages/viewpage.action?spaceKey=FIREFOX&title=Pref-Flip+and+Add-On+Experiments>`__ + A comprehensive document on experiments from the Experimenter team. See the + child pages in the sidebar, too. + +`Client Implementation Guidelines for Experiments <https://docs.telemetry.mozilla.org/cookbooks/client_guidelines.html>`_ + Relevant documentation from the telemetry team. + +#ask-experimenter Slack channel + A friendly place to get answers to your experiment questions. + +The Experiment Development Process +---------------------------------- + +This section describes an experiment's life cycle. + +1. Experiments usually originate with product management and UX. They're + responsible for identifying a problem, deciding how an experiment should + approach it, the questions we want to answer, the data we need to answer + those questions, the user population that should be enrolled in the + experiment, the definition of success, and so on. + +2. UX makes a spec that describes what the extension looks like and how it + behaves. + +3. There's a kickoff meeting among the team to introduce the experiment and UX + spec. It's an opportunity for engineering to ask questions of management, UX, + and data science. It's really important for engineering to get a precise and + accurate understanding of how the extension is supposed to behave — right + down to the UI changes — so that no one makes erroneous assumptions during + development. + +4. At some point around this time, the team (usually management) creates a few + artifacts to track the work and facilitate communication with outside teams + involved in shipping experiments. They include: + + * A page on `Experimenter <Experiments_>`__ + * A QA PI (product integrity) request so that QA resources are allocated + * A bug in `Data Science :: Experiment Collaboration`__ so that data science + can track the work and discuss telemetry (engineering might file this one) + + __ https://bugzilla.mozilla.org/enter_bug.cgi?assigned_to=nobody%40mozilla.org&bug_ignored=0&bug_severity=normal&bug_status=NEW&bug_type=task&cf_firefox_messaging_system=---&cf_fx_iteration=---&cf_fx_points=---&comment=%23%23%20Brief%20Description%20of%20the%20request%20%28required%29%3A%0D%0A%0D%0A%23%23%20Business%20purpose%20for%20this%20request%20%28required%29%3A%0D%0A%0D%0A%23%23%20Requested%20timelines%20for%20the%20request%20or%20how%20this%20fits%20into%20roadmaps%20or%20critical%20decisions%20%28required%29%3A%0D%0A%0D%0A%23%23%20Links%20to%20any%20assets%20%28e.g%20Start%20of%20a%20PHD%2C%20BRD%3B%20any%20document%20that%20helps%20describe%20the%20project%29%3A%0D%0A%0D%0A%23%23%20Name%20of%20Data%20Scientist%20%28If%20Applicable%29%3A%0D%0A%0D%0A%2APlease%20note%20if%20it%20is%20found%20that%20not%20enough%20information%20has%20been%20given%20this%20will%20delay%20the%20triage%20of%20this%20request.%2A&component=Experiment%20Collaboration&contenttypemethod=list&contenttypeselection=text%2Fplain&filed_via=standard_form&flag_type-4=X&flag_type-607=X&flag_type-800=X&flag_type-803=X&flag_type-936=X&form_name=enter_bug&maketemplate=Remember%20values%20as%20bookmarkable%20template&op_sys=Unspecified&priority=--&product=Data%20Science&rep_platform=Unspecified&target_milestone=---&version=unspecified + +5. Engineering breaks down the work and files bugs. There's another engineering + meeting to discuss the breakdown, or it's discussed asynchronously. + +6. Engineering sets up a GitHub repo for the extension. See `Implementing + Experiments`_ for an example repo you can clone to get started. Disable + GitHub Issues on the repo so that QA will file bugs in Bugzilla instead of + GitHub. There's nothing wrong with GitHub Issues, but our team's project + management tracks all work through Bugzilla. If it's not there, it's not + captured. + +7. Engineering or management fills out the Add-on section of the Experimenter + page as much as possible at this point. "Active Experiment Name" isn't + necessary, and "Signed Release URL" won't be available until the end of the + process. + +8. Engineering implements the extension and any new WebExtensions APIs it + requires. + +9. When the extension is done, engineering or management clicks the "Ready for + Sign-Off" button on the Experimenter page. That changes the page's status + from "Draft" to "Ready for Sign-Off," which allows QA and other teams to sign + off on their portions of the experiment. + +10. Engineering requests the extension be signed "for testing" (or "for + QA"). Michael (mythmon) from the Experiments team and Rehan (rdalal) from + Services Engineering are good contacts. Build the extension zip file using + web-ext as discussed in Workflow_. Attach it to a bug (a metabug for + implementing the extension, for example), needinfo Michael or Rehan, and ask + him to sign it. He'll attach the signed version to the bug. If neither + Michael nor Rehan is available, try asking in the #ask-experimenter Slack + channel. + +11. Engineering sends QA the link to the signed extension and works with them to + resolve bugs they find. + +12. When QA signs off, engineering asks Michael to sign the extension "for + release" using the same needinfo process described earlier. + +13. Paste the URL of the signed extension in the "Signed Release URL" textbox of + the Add-on section of the Experimenter page. + +14. Other teams sign off as they're ready. + +15. The experiment ships! 🎉 + + +Implementing Experiments +------------------------ + +This section discusses how to implement add-on experiments. Pref-flip +experiments are much simpler and don't need a lot of explanation. You should be +familiar with the concepts discussed in the `Developing Address Bar Extensions`_ +and `Running Address Bar Extensions`_ sections before reading this one. + +The most salient thing about add-on experiments is that they're implemented +simply as privileged extensions. Other than being privileged and possibly +containing bundled experimental APIs, they're similar to all other extensions. + +The `top-sites experiment extension <topSites_>`__ is an example of a real, +shipped experiment. + +.. _topSites: https://github.com/0c0w3/urlbar-top-sites-experiment + +Setup +~~~~~ + +example-addon-experiment_ is a repo you can clone to get started. It's geared +toward urlbar extensions and includes the stub of a browser chrome mochitest. + +.. _example-addon-experiment: https://github.com/0c0w3/example-addon-experiment + +browser.normandyAddonStudy +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As discussed in Experiments_, an experiment typically has more than one branch +so that it can test different UXes. The experiment's extension(s) needs to know +the branch the user is enrolled in so that it can behave appropriately for the +branch: show the user the proper UX, collect the proper telemetry, and so on. + +This is the purpose of the ``browser.normandyAddonStudy`` WebExtensions API. +Like ``browser.urlbar``, it's a privileged API available only to Mozilla +extensions. + +Its schema is normandyAddonStudy.json_. + +It's a very simple API. The primary function is ``getStudy``, which returns the +study the user is currently enrolled in or null if there isn't one. (Recall that +*study* is a synonym for *experiment*.) One of the first things an experiment +extension typically does is to call this function. + +The Normandy client in Firefox will keep an experiment extension installed only +while the experiment is active. Therefore, ``getStudy`` should always return a +non-null study object. Nevertheless, the study object has an ``active`` boolean +property that's trivial to sanity check. (The example extension does.) + +The more important property is ``branch``, the name of the branch that the user +is enrolled in. Your extension should use it to determine the appropriate UX. + +Finally, there's an ``onUnenroll`` event that's fired when the user is +unenrolled in the study. It's not quite clear in what cases an extension would +need to listen for this event given that Normandy automatically uninstalls +extensions on unenrollment. Maybe if they create some persistent state that's +not automatically undone on uninstall by the WebExtensions framework? + +If your extension itself needs to unenroll the user for some reason, call +``endStudy``. + +.. _normandyAddonStudy.json: https://searchfox.org/mozilla-central/source/browser/components/extensions/schemas/normandyAddonStudy.json + +Telemetry +~~~~~~~~~ + +Experiments can capture telemetry in two places: in the product itself and +through the privileged ``browser.telemetry`` WebExtensions API. The API schema +is telemetry.json_. + +The telemetry pings from users running experiments are automatically correlated +with those experiments, no extra work required. That's true regardless of +whether the telemetry is captured in the product or though +``browser.telemetry``. + +The address bar has some in-product, preffed off telemetry that we want to +enable for all our experiments — at least that's the thinking as of August 2019. +It's called `engagement event telemetry`_, and it records user *engagements* +with and *abandonments* of the address bar [source__]. We added a +BrowserSetting_ on ``browser.urlbar`` just to let us flip the pref and enable +this telemetry in our experiment extensions. Call it like this:: + + await browser.urlbar.engagementTelemetry.set({ value: true }); + +.. _telemetry.json: https://searchfox.org/mozilla-central/source/toolkit/components/extensions/schemas/telemetry.json +.. _engagement event telemetry: https://bugzilla.mozilla.org/show_bug.cgi?id=1559136 +__ https://searchfox.org/mozilla-central/rev/7088fc958db5935eba24b413b1f16d6ab7bd13ea/browser/components/urlbar/UrlbarController.jsm#598 +.. _BrowserSetting: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/types/BrowserSetting + +Engineering Best Practices +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Clear up questions with your UX person early and often. There's often a gap +between what they have in their mind and what you have in yours. Nothing wrong +with that, it's just the nature of development. But misunderstandings can cause +big problems when they're discovered late. This is especially true of UX +behaviors, as opposed to visuals or styling. It's no fun to realize at the end +of a release cycle that you've designed the wrong WebExtensions API because some +UX detail was overlooked. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Related to the previous point, make builds of your extension for your UX person +so they can test it. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Taking the previous point even further, if your experiment will require a +substantial new API(s), you might think about prototyping the experiment +entirely in a custom Firefox build before designing the API at all. Give it to +your UX person. Let them disect it and tell you all the problems with it. Fill +in all the gaps in your understanding, and then design the API. We've never +actually done this, though. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It's a good idea to work on the extension as you're designing and developing the +APIs it'll use. You might even go as far as writing the first draft of the +extension before even starting to implement the APIs. That lets you spot +problems that may not be obvious were you to design the API in isolation. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Your extension's ID should end in ``@shield.mozilla.org``. QA will flag it if it +doesn't. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Set ``"hidden": true`` in your extension's manifest.json. That hides it on +about:addons. (It can still be seen on about:studies.) QA will spot this if you +don't. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are drawbacks of hiding features behind prefs and enabling them in +experiment extensions. Consider not doing that if feasible, or at least weigh +these drawbacks against your expected benefits. + +* Prefs stay flipped on in private windows, but experiments often have special + requirements around private-browsing mode (PBM). Usually, they shouldn't be + active in PBM at all, unless of course the point of the experiment is to test + PBM. Extensions also must request PBM access ("incognito" in WebExtensions + terms), and the user can disable access at any time. The result is that part + of your experiment could remain enabled — the part behind the pref — while + other parts are disabled. + +* Prefs stay flipped on in safe mode, even though your extension (like all + extensions) will be disabled. This might be a bug__ in the WebExtensions + framework, though. + + __ https://bugzilla.mozilla.org/show_bug.cgi?id=1576997 diff --git a/browser/components/urlbar/docs/index.rst b/browser/components/urlbar/docs/index.rst new file mode 100644 index 0000000000..633bca91b6 --- /dev/null +++ b/browser/components/urlbar/docs/index.rst @@ -0,0 +1,26 @@ +Address Bar +=========== + +This document describes the implementation of Firefox's address bar, also known +as the quantumbar or urlbar. The address bar was also called the awesomebar +until Firefox 68, when it was substantially rewritten. + +The address bar is a specialized search access point that aggregates data from +several different sources, including: + + * Places (Firefox's history and bookmarks system) + * Search engines (including search suggestions) + * WebExtensions + * Open tabs + +Most of the address bar code lives in `browser/components/urlbar <https://searchfox.org/mozilla-central/source/browser/components/urlbar/>`_. +A separate and important back-end piece currently is `toolkit/components/places/UnifiedComplete.jsm <https://searchfox.org/mozilla-central/source/toolkit/components/places/UnifiedComplete.jsm>`_, which was carried over from awesomebar and has not yet been rewritten for quantumbar. + +.. toctree:: + + overview + utilities + telemetry + debugging + experiments + contact diff --git a/browser/components/urlbar/docs/overview.rst b/browser/components/urlbar/docs/overview.rst new file mode 100644 index 0000000000..e7306bceea --- /dev/null +++ b/browser/components/urlbar/docs/overview.rst @@ -0,0 +1,413 @@ +Architecture Overview +===================== + +The address bar is implemented as a *model-view-controller* (MVC) system. One of +the scopes of this architecture is to allow easy replacement of its components, +for easier experimentation. + +Each search is represented by a unique object, the *UrlbarQueryContext*. This +object, created by the *View*, describes the search and is passed through all of +the components, along the way it gets augmented with additional information. +The *UrlbarQueryContext* is passed to the *Controller*, and finally to the +*Model*. The model appends results to a property of *UrlbarQueryContext* in +chunks, it sorts them through a *Muxer* and then notifies the *Controller*. + +See the specific components below, for additional details about each one's tasks +and responsibilities. + + +The UrlbarQueryContext +---------------------- + +The *UrlbarQueryContext* object describes a single instance of a search. +It is augmented as it progresses through the system, with various information: + +.. highlight:: JavaScript +.. code:: + + UrlbarQueryContext { + allowAutofill; // {boolean} If true, providers are allowed to return + // autofill results. Even if true, it's up to providers + // whether to include autofill results, but when false, no + // provider should include them. + isPrivate; // {boolean} Whether the search started in a private context. + maxResults; // {integer} The maximum number of results requested. It is + // possible to request more results than the shown ones, and + // do additional filtering at the View level. + searchString; // {string} The user typed string. + userContextId; // {integer} The user context ID (containers feature). + + // Optional properties. + muxer; // {string} Name of a registered muxer. Muxers can be registered + // through the UrlbarProvidersManager. + providers; // {array} List of registered provider names. Providers can be + // registered through the UrlbarProvidersManager. + sources: {array} list of accepted UrlbarUtils.RESULT_SOURCE for the context. + // This allows to switch between different search modes. If not + // provided, a default will be generated by the Model, depending on + // the search string. + engineName: // {string} if sources is restricting to just SEARCH, this + // property can be used to pick a specific search engine, by + // setting it to the name under which the engine is registered + // with the search service. + currentPage: // {string} url of the page that was loaded when the search + // began. + allowSearchSuggestions: // {boolean} Whether to allow search suggestions. + // This is a veto, meaning that when false, + // suggestions will not be fetched, but when true, + // some other condition may still prohibit + // suggestions, like private browsing mode. Defaults + // to true. + + // Properties added by the Model. + results; // {array} list of UrlbarResult objects. + tokens; // {array} tokens extracted from the searchString, each token is an + // object in the form {type, value, lowerCaseValue}. + } + + +The Model +--------- + +The *Model* is the component responsible for retrieving search results based on +the user's input, and sorting them accordingly to their importance. +At the core is the `UrlbarProvidersManager <https://searchfox.org/mozilla-central/source/browser/components/urlbar/UrlbarProvidersManager.jsm>`_, +a component tracking all the available search providers, and managing searches +across them. + +The *UrlbarProvidersManager* is a singleton, it registers internal providers on +startup and can register/unregister providers on the fly. +It can manage multiple concurrent queries, and tracks them internally as +separate *Query* objects. + +The *Controller* starts and stops queries through the *UrlbarProvidersManager*. +It's possible to wait for the promise returned by *startQuery* to know when no +more results will be returned, it is not mandatory though. +Queries can be canceled. + +.. note:: + + Canceling a query will issue an interrupt() on the database connection, + terminating any running and future SQL query, unless a query is running inside + a *runInCriticalSection* task. + +The *searchString* gets tokenized by the `UrlbarTokenizer <https://searchfox.org/mozilla-central/source/browser/components/urlbar/UrlbarTokenizer.jsm>`_ +component into tokens, some of these tokens have a special meaning and can be +used by the user to restrict the search to specific result type (See the +*UrlbarTokenizer::TYPE* enum). + +.. caution:: + + The tokenizer uses heuristics to determine each token's type, as such the + consumer may want to check the value before applying filters. + +.. highlight:: JavaScript +.. code:: + + UrlbarProvidersManager { + registerProvider(providerObj); + unregisterProvider(providerObj); + registerMuxer(muxerObj); + unregisterMuxer(muxerObjOrName); + async startQuery(queryContext); + cancelQuery(queryContext); + // Can be used by providers to run uninterruptible queries. + runInCriticalSection(taskFn); + } + +UrlbarProvider +~~~~~~~~~~~~~~ + +A provider is specialized into searching and returning results from different +information sources. Internal providers are usually implemented in separate +*jsm* modules with a *UrlbarProvider* name prefix. External providers can be +registered as *Objects* through the *UrlbarProvidersManager*. +Each provider is independent and must satisfy a base API, while internal +implementation details may vary deeply among different providers. + +.. important:: + + Providers are singleton, and must track concurrent searches internally, for + example mapping them by UrlbarQueryContext. + +.. note:: + + Internal providers can access the Places database through the + *PlacesUtils.promiseLargeCacheDBConnection* utility. + +.. highlight:: JavaScript +.. code:: + + class UrlbarProvider { + /** + * Unique name for the provider, used by the context to filter on providers. + * Not using a unique name will cause the newest registration to win. + * @abstract + */ + get name() { + return "UrlbarProviderBase"; + } + /** + * The type of the provider, must be one of UrlbarUtils.PROVIDER_TYPE. + * @abstract + */ + get type() { + throw new Error("Trying to access the base class, must be overridden"); + } + /** + * Whether this provider should be invoked for the given context. + * If this method returns false, the providers manager won't start a query + * with this provider, to save on resources. + * @param {UrlbarQueryContext} queryContext The query context object + * @returns {boolean} Whether this provider should be invoked for the search. + * @abstract + */ + isActive(queryContext) { + throw new Error("Trying to access the base class, must be overridden"); + } + /** + * Gets the provider's priority. Priorities are numeric values starting at + * zero and increasing in value. Smaller values are lower priorities, and + * larger values are higher priorities. For a given query, `startQuery` is + * called on only the active and highest-priority providers. + * @param {UrlbarQueryContext} queryContext The query context object + * @returns {number} The provider's priority for the given query. + * @abstract + */ + getPriority(queryContext) { + // By default, all providers share the lowest priority. + return 0; + } + /** + * Starts querying. + * @param {UrlbarQueryContext} queryContext The query context object + * @param {function} addCallback Callback invoked by the provider to add a new + * result. A UrlbarResult should be passed to it. + * @note Extended classes should return a Promise resolved when the provider + * is done searching AND returning results. + * @abstract + */ + startQuery(queryContext, addCallback) { + throw new Error("Trying to access the base class, must be overridden"); + } + /** + * Cancels a running query, + * @param {UrlbarQueryContext} queryContext The query context object to cancel + * query for. + * @abstract + */ + cancelQuery(queryContext) { + throw new Error("Trying to access the base class, must be overridden"); + } + } + +UrlbarMuxer +~~~~~~~~~~~ + +The *Muxer* is responsible for sorting results based on their importance and +additional rules that depend on the UrlbarQueryContext. The muxer to use is +indicated by the UrlbarQueryContext.muxer property. + +.. caution:: + + The Muxer is a replaceable component, as such what is described here is a + reference for the default View, but may not be valid for other implementations. + +.. highlight:: JavaScript +.. code:: + + class UrlbarMuxer { + /** + * Unique name for the muxer, used by the context to sort results. + * Not using a unique name will cause the newest registration to win. + * @abstract + */ + get name() { + return "UrlbarMuxerBase"; + } + /** + * Sorts UrlbarQueryContext results in-place. + * @param {UrlbarQueryContext} queryContext the context to sort results for. + * @abstract + */ + sort(queryContext) { + throw new Error("Trying to access the base class, must be overridden"); + } + } + + +The Controller +-------------- + +`UrlbarController <https://searchfox.org/mozilla-central/source/browser/components/urlbar/UrlbarController.jsm>`_ +is the component responsible for reacting to user's input, by communicating +proper course of action to the Model (e.g. starting/stopping a query) and the +View (e.g. showing/hiding a panel). It is also responsible for reporting Telemetry. + +.. note:: + + Each *View* has a different *Controller* instance. + +.. highlight:: JavaScript +.. code:: + + UrlbarController { + async startQuery(queryContext); + cancelQuery(queryContext); + // Invoked by the ProvidersManager when results are available. + receiveResults(queryContext); + // Used by the View to listen for results. + addQueryListener(listener); + removeQueryListener(listener); + } + + +The View +-------- + +The View is the component responsible for presenting search results to the +user and handling their input. + +.. caution + + The View is a replaceable component, as such what is described here is a + reference for the default View, but may not be valid for other implementations. + +`UrlbarInput.jsm <https://searchfox.org/mozilla-central/source/browser/components/urlbar/UrlbarInput.jsm>`_ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Implements an input box *View*, owns an *UrlbarView*. + +.. highlight:: JavaScript +.. code:: + + UrlbarInput { + constructor(options = { textbox, panel }); + // Uses UrlbarValueFormatter to highlight the base host, search aliases + // and to keep the host visible on overflow. + formatValue(val); + openResults(); + // Converts an internal URI (e.g. a URI with a username or password) into + // one which we can expose to the user. + makeURIReadable(uri); + // Handles an event which would cause a url or text to be opened. + handleCommand(); + // Called by the view when a result is selected. + resultsSelected(); + // The underlying textbox + textbox; + // The results panel. + panel; + // The containing window. + window; + // The containing document. + document; + // An UrlbarController instance. + controller; + // An UrlbarView instance. + view; + // Whether the current value was typed by the user. + valueIsTyped; + // Whether the context is in Private Browsing mode. + isPrivate; + // Whether the input box is focused. + focused; + // The go button element. + goButton; + // The current value, can also be set. + value; + } + +`UrlbarView.jsm <https://searchfox.org/mozilla-central/source/browser/components/urlbar/UrlbarView.jsm>`_ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Represents the base *View* implementation, communicates with the *Controller*. + +.. highlight:: JavaScript +.. code:: + + UrlbarView { + // Manage View visibility. + open(); + close(); + // Invoked when the query starts. + onQueryStarted(queryContext); + // Invoked when new results are available. + onQueryResults(queryContext); + // Invoked when the query has been canceled. + onQueryCancelled(queryContext); + // Invoked when the query is done. This is invoked in any case, even if the + // query was canceled earlier. + onQueryFinished(queryContext); + // Invoked when the view opens. + onViewOpen(); + // Invoked when the view closes. + onViewClose(); + } + + +UrlbarResult +------------ + +An `UrlbarResult <https://searchfox.org/mozilla-central/source/browser/components/urlbar/UrlbarResult.jsm>`_ +instance represents a single search result with a result type, that +identifies specific kind of results. +Each kind has its own properties, that the *View* may support, and a few common +properties, supported by all of the results. + +.. note:: + + Result types are also enumerated by *UrlbarUtils.RESULT_TYPE*. + +.. highlight:: JavaScript +.. code:: + + UrlbarResult { + constructor(resultType, payload); + + type: {integer} One of UrlbarUtils.RESULT_TYPE. + source: {integer} One of UrlbarUtils.RESULT_SOURCE. + title: {string} A title that may be used as a label for this result. + icon: {string} Url of an icon for this result. + payload: {object} Object containing properties for the specific RESULT_TYPE. + autofill: {object} An object describing the text that should be + autofilled in the input when the result is selected, if any. + autofill.value: {string} The autofill value. + autofill.selectionStart: {integer} The first index in the autofill + selection. + autofill.selectionEnd: {integer} The last index in the autofill selection. + suggestedIndex: {integer} Suggest a preferred position for this result + within the result set. + } + +The following RESULT_TYPEs are supported: + +.. highlight:: JavaScript +.. code:: + + // An open tab. + // Payload: { icon, url, userContextId } + TAB_SWITCH: 1, + // A search suggestion or engine. + // Payload: { icon, suggestion, keyword, query, providesSearchMode, inPrivateWindow, isPrivateEngine } + SEARCH: 2, + // A common url/title tuple, may be a bookmark with tags. + // Payload: { icon, url, title, tags } + URL: 3, + // A bookmark keyword. + // Payload: { icon, url, keyword, postData } + KEYWORD: 4, + // A WebExtension Omnibox result. + // Payload: { icon, keyword, title, content } + OMNIBOX: 5, + // A tab from another synced device. + // Payload: { icon, url, device, title } + REMOTE_TAB: 6, + // An actionable message to help the user with their query. + // textData and buttonTextData are objects containing an l10n id and args. + // If a tip is untranslated it's possible to provide text and buttonText. + // Payload: { icon, textData, buttonTextData, [buttonUrl], [helpUrl] } + TIP: 7, + // A type of result created at runtime, for example by an extension. + // Payload: { dynamicType } + DYNAMIC: 8, diff --git a/browser/components/urlbar/docs/telemetry.rst b/browser/components/urlbar/docs/telemetry.rst new file mode 100644 index 0000000000..6ebb5f0d07 --- /dev/null +++ b/browser/components/urlbar/docs/telemetry.rst @@ -0,0 +1,445 @@ +Telemetry +========= + +This section describes existing telemetry probes measuring interaction with the +Address Bar. + +.. toctree:: + :caption: Table of Contents + + telemetry + +Histograms +---------- + +PLACES_AUTOCOMPLETE_1ST_RESULT_TIME_MS + This probe tracks the amount of time it takes to get the first result. + It is an exponential histogram with values between 5 and 100. + +PLACES_AUTOCOMPLETE_6_FIRST_RESULTS_TIME_MS + This probe tracks the amount of time it takes to get the first six results. + It is an exponential histogram with values between 50 and 1000. + +FX_URLBAR_SELECTED_RESULT_METHOD + This probe tracks how a result was picked by the user from the list. + It is a categorical histogram with these values: + + - ``enter`` + The user pressed Enter without selecting a result first. + This most likely happens when the user confirms the default preselected + result (aka *heuristic result*), or when they select with the keyboard a + one-off search button and confirm with Enter. + - ``enterSelection`` + The user selected a result, but not using Tab or the arrow keys, and then + pressed Enter. This is a rare and generally unexpected event, there may be + exotic ways to select a result we didn't consider, that are tracked here. + Look at arrowEnterSelection and tabEnterSelection for more common actions. + - ``click`` + The user clicked on a result. + - ``arrowEnterSelection`` + The user selected a result using the arrow keys, and then pressed Enter. + - ``tabEnterSelection`` + The first key the user pressed to select a result was the Tab key, and then + they pressed Enter. Note that this means the user could have used the arrow + keys after first pressing the Tab key. + - ``rightClickEnter`` + Before QuantumBar, it was possible to right-click a result to highlight but + not pick it. Then the user could press Enter. This is no more possible. + +Scalars +------- + +urlbar.tips + This is a keyed scalar whose values are uints and are incremented each time a + tip result is shown, a tip is picked, and a tip's help button is picked. The + keys are: + + - ``intervention_clear-help`` + Incremented when the user picks the help button in the clear-history search + intervention. + - ``intervention_clear-picked`` + Incremented when the user picks the clear-history search intervention. + - ``intervention_clear-shown`` + Incremented when the clear-history search intervention is shown. + - ``intervention_refresh-help`` + Incremented when the user picks the help button in the refresh-Firefox + search intervention. + - ``intervention_refresh-picked`` + Incremented when the user picks the refresh-Firefox search intervention. + - ``intervention_refresh-shown`` + Incremented when the refresh-Firefox search intervention is shown. + - ``intervention_update_ask-help`` + Incremented when the user picks the help button in the update_ask search + intervention, which is shown when there's a Firefox update available but the + user's preference says we should ask them to download and apply it. + - ``intervention_update_ask-picked`` + Incremented when the user picks the update_ask search intervention. + - ``intervention_update_ask-shown`` + Incremented when the update_ask search intervention is shown. + - ``intervention_update_refresh-help`` + Incremented when the user picks the help button in the update_refresh search + intervention, which is shown when the user's browser is up to date but they + triggered the update intervention. We show this special refresh intervention + instead. + - ``intervention_update_refresh-picked`` + Incremented when the user picks the update_refresh search intervention. + - ``intervention_update_refresh-shown`` + Incremented when the update_refresh search intervention is shown. + - ``intervention_update_restart-help`` + Incremented when the user picks the help button in the update_restart search + intervention, which is shown when there's an update and it's been downloaded + and applied. The user needs to restart to finish. + - ``intervention_update_restart-picked`` + Incremented when the user picks the update_restart search intervention. + - ``intervention_update_restart-shown`` + Incremented when the update_restart search intervention is shown. + - ``intervention_update_web-help`` + Incremented when the user picks the help button in the update_web search + intervention, which is shown when we can't update the browser or possibly + even check for updates for some reason, so the user should download the + latest version from the web. + - ``intervention_update_web-picked`` + Incremented when the user picks the update_web search intervention. + - ``intervention_update_web-shown`` + Incremented when the update_web search intervention is shown. + - ``tabtosearch_onboard-shown`` + Incremented when a tab-to-search onboarding result is shown, once per engine + per engagement. Please note that the number of times tab-to-search + onboarding results are picked is the sum of all keys in + ``urlbar.searchmode.tabtosearch_onboard``. + - ``searchTip_onboard-picked`` + Incremented when the user picks the onboarding search tip. + - ``searchTip_onboard-shown`` + Incremented when the onboarding search tip is shown. + - ``searchTip_redirect-picked`` + Incremented when the user picks the redirect search tip. + - ``searchTip_redirect-shown`` + Incremented when the redirect search tip is shown. + +urlbar.searchmode.* + This is a set of keyed scalars whose values are uints incremented each + time search mode is entered in the Urlbar. The suffix on the scalar name + describes how search mode was entered. Possibilities include: + + - ``bookmarkmenu`` + Used when the user selects the Search Bookmarks menu item in the Library + menu. + - ``handoff`` + Used when the user uses the search box on the new tab page and is handed off + to the address bar. + - ``keywordoffer`` + Used when the user selects a keyword offer result. + - ``oneoff`` + Used when the user selects a one-off engine in the Urlbar. + - ``shortcut`` + Used when the user enters search mode with a keyboard shortcut or menu bar + item (e.g. ``Accel+K``). + - ``tabmenu`` + Used when the user selects the Search Tabs menu item in the tab overflow + menu. + - ``tabtosearch`` + Used when the user selects a tab-to-search result. These results suggest a + search engine when the search engine's domain is autofilled. + - ``tabtosearch_onboard`` + Used when the user selects a tab-to-search onboarding result. These are + shown the first few times the user encounters a tab-to-search result. + - ``topsites_newtab`` + Used when the user selects a search shortcut Top Site from the New Tab Page. + - ``topsites_urlbar`` + Used when the user selects a search shortcut Top Site from the Urlbar. + - ``touchbar`` + Used when the user taps a search shortct on the Touch Bar, available on some + Macs. + - ``typed`` + Used when the user types an engine alias in the Urlbar. + - ``other`` + Used as a catchall for other behaviour. We don't expect this scalar to hold + any values. If it does, we need to correct an issue with search mode entry + points. + + The keys for the scalars above are engine and source names. If the user enters + a remote search mode with a built-in engine, we record the engine name. If the + user enters a remote search mode with an engine they installed (e.g. via + OpenSearch or a WebExtension), we record ``other`` (not to be confused with + the ``urlbar.searchmode.other`` scalar above). If they enter a local search + mode, we record the English name of the result source (e.g. "bookmarks", + "history", "tabs"). Note that we slightly modify the engine name for some + built-in engines: we flatten all localized Amazon sites (Amazon.com, + Amazon.ca, Amazon.de, etc.) to "Amazon" and we flatten all localized + Wikipedia sites (Wikipedia (en), Wikipedia (fr), etc.) to "Wikipedia". This + is done to reduce the number of keys used by these scalars. + +urlbar.picked.* + This is a set of keyed scalars whose values are uints incremented each + time a result is picked from the Urlbar. The suffix on the scalar name + is the result type. The keys for the scalars above are the 0-based index of + the result in the urlbar panel when it was picked. + + .. note:: + Available from Firefox 84 on. Use the *FX_URLBAR_SELECTED_** histograms in + earlier versions. See the `Obsolete probes`_ section below. + + Valid result types are: + + - ``autofill`` + An origin or a URL completed the user typed text inline. + - ``bookmark`` + A bookmarked URL. + - ``dynamic`` + A specially crafted result, often used in experiments when basic types are + not flexible enough for a rich layout. + - ``extension`` + Added by an add-on through the omnibox WebExtension API. + - ``formhistory`` + A search suggestion from previous search history. + - ``history`` + A URL from history. + - ``keyword`` + A bookmark keyword. + - ``remotetab`` + A tab synced from another device. + - ``searchengine`` + A search result, but not a suggestion. May be the default search action + or a search alias. + - ``searchsuggestion`` + A remote search suggestion. + - ``switchtab`` + An open tab. + - ``tabtosearch`` + A tab to search result. + - ``tip`` + A tip result. + - ``topsite`` + An entry from top sites. + - ``unknown`` + An unknown result type, a bug should be filed to figure out what it is. + - ``visiturl`` + The user typed string can be directly visited. + +urlbar.picked.searchmode.* + This is a set of keyed scalars whose values are uints incremented each time a + result is picked from the Urlbar while the Urlbar is in search mode. The + suffix on the scalar name is the search mode entry point. The keys for the + scalars are the 0-based index of the result in the urlbar panel when it was + picked. + + .. note:: + These scalars share elements of both ``urlbar.picked.*`` and + ``urlbar.searchmode.*``. Scalar name suffixes are search mode entry points, + like ``urlbar.searchmode.*``. The keys for these scalars are result indices, + like ``urlbar.picked.*``. + + .. note:: + These data are a subset of the data recorded by ``urlbar.picked.*``. For + example, if the user enters search mode by clicking a one-off then selects + a Google search suggestion at index 2, we would record in **both** + ``urlbar.picked.searchsuggestion`` and ``urlbar.picked.searchmode.oneoff``. + + +Event Telemetry +--------------- + +The event telemetry is grouped under the ``urlbar`` category. + +Event Method + There are two methods to describe the interaction with the urlbar: + + - ``engagement`` + It is defined as a completed action in urlbar, where a user inserts text + and executes one of the actions described in the Event Object. + - ``abandonment`` + It is defined as an action where the user inserts text but does not + complete an engagement action, usually unfocusing the urlbar. This also + happens when the user switches to another window, regardless of urlbar + focus. + +Event Value + This is how the user interaction started + + - ``typed``: The text was typed into the urlbar. + - ``dropped``: The text was drag and dropped into the urlbar. + - ``pasted``: The text was pasted into the urlbar. + - ``topsites``: The user opened the urlbar view without typing, dropping, + or pasting. + In these cases, if the urlbar input is showing the URL of the loaded page + and the user has not modified the input’s content, the urlbar views shows + the user’s top sites. Otherwise, if the user had modified the input’s + content, the urlbar view shows results based on what the user has typed. + To tell whether top sites were shown, it's enough to check whether value is + ``topsites``. To know whether the user actually picked a top site, check + check that ``numChars`` == 0. If ``numChars`` > 0, the user initially opened + top sites, but then they started typing and confirmed a different result. + - ``returned``: The user abandoned a search, for example by switching to + another tab/window, or focusing something else, then came back to it + and continued. We consider a search continued if the user kept at least the + first char of the original search string. + - ``restarted``: The user abandoned a search, for example by switching to + another tab/window, or focusing something else, then came back to it, + cleared it and then typed a new string. + +Event Object + These describe actions in the urlbar: + + - ``click`` + The user clicked on a result. + - ``enter`` + The user confirmed a result with Enter. + - ``drop_go`` + The user dropped text on the input field. + - ``paste_go`` + The user used Paste & Go feature. It is not the same as paste and Enter. + - ``blur`` + The user unfocused the urlbar. This is only valid for ``abandonment``. + +Event Extra + This object contains additional information about the interaction. + Extra is a key-value store, where all the keys and values are strings. + + - ``elapsed`` + Time in milliseconds from the initial interaction to an action. + - ``numChars`` + Number of input characters the user typed or pasted at the time of + submission. + - ``numWords`` + Number of words in the input. The measurement is taken from a trimmed input + split up by its spaces. This is not a perfect measurement, since it will + return an incorrect value for languages that do not use spaces or URLs + containing spaces in its query parameters, for example. + - ``selType`` + The type of the selected result at the time of submission. + This is only present for ``engagement`` events. + It can be one of: ``none``, ``autofill``, ``visiturl``, ``bookmark``, + ``history``, ``keyword``, ``searchengine``, ``searchsuggestion``, + ``switchtab``, ``remotetab``, ``extension``, ``oneoff``, ``keywordoffer``, + ``canonized``, ``tip``, ``tiphelp``, ``formhistory``, ``tabtosearch``, + ``unknown`` + In practice, ``tabtosearch`` should not appear in real event telemetry. + Opening a tab-to-search result enters search mode and entering search mode + does not currently mark the end of an engagement. It is noted here for + completeness. + - ``selIndex`` + Index of the selected result in the urlbar panel, or -1 for no selection. + There won't be a selection when a one-off button is the only selection, and + for the ``paste_go`` or ``drop_go`` objects. There may also not be a + selection if the system was busy and results arrived too late, then we + directly decide whether to search or visit the given string without having + a fully built result. + This is only present for ``engagement`` events. + - ``provider`` + The name of the result provider for the selected result. Existing values + are: ``HeuristicFallback``, ``Autofill``, ``UnifiedComplete``, + ``TokenAliasEngines``, ``SearchSuggestions``, ``UrlbarProviderTopSites``. + Values can also be defined by `URLBar provider experiments`_. + + .. _URLBar provider experiments: experiments.html#developing-address-bar-extensions + +Search probes relevant to the Address Bar +----------------------------------------- + +SEARCH_COUNTS + This histogram tracks search engines and Search Access Points. It is augmented + by multiple SAPs, including the urlbar. + It's a keyed histogram, the keys are strings made up of search engine names + and SAP names, for example ``google.urlbar``. + For each key, this records the count of searches made using that engine and SAP. + SAP names can be: + + - ``alias`` This is when using an alias (like ``@google``) in the urlbar. + Note there is often confusion between the terms alias and keyword, and + they may be used inappropriately: aliases refer to search engines, while + keywords refer to bookmarks. We expect no results for this SAP in Firefox + 83+, since urlbar-searchmode replaces it. + - ``abouthome`` + - ``contextmenu`` + - ``newtab`` + - ``searchbar`` + - ``system`` + - ``urlbar`` Except aliases and search mode. + - ``urlbar-searchmode`` Used when the Urlbar is in search mode. + - ``webextension`` + - ``oneoff-urlbar`` + - ``oneoff-searchbar`` + - ``unknown`` This is actually the searchbar, when using the current engine + one-off button. + +browser.engagement.navigation.* + These keyed scalars track search through different SAPs, for example the + urlbar is tracked by ``browser.engagement.navigation.urlbar``. + It counts loads triggered in a subsession from the specified SAP, broken down + by the originating action. + Possible SAPs are: + + - ``urlbar`` Except search mode. + - ``urlbar_searchmode`` Used when the Urlbar is in search mode. + - ``searchbar`` + - ``about_home`` + - ``about_newtab`` + - ``contextmenu`` + - ``webextension`` + - ``system`` Indicates a search from the command line. + + Recorded actions may be: + + - ``search`` + Used for any search from ``contextmenu``, ``system`` and ``webextension``. + - ``search_alias`` + For ``urlbar``, indicates the user confirmed a search through an alias. + - ``search_enter`` + For ``about_home`` and ``about:newtab`` this counts any search. + For the other SAPs it tracks typing and then pressing Enter. + - ``search_formhistory`` + For ``urlbar``, indicates the user picked a form history result. + - ``search_oneoff`` + For ``urlbar`` or ``searchbar``, indicates the user confirmed a search + using a one-off button. + - ``search_suggestion`` + For ``urlbar`` or ``searchbar``, indicates the user confirmed a search + suggestion. + +Obsolete probes +--------------- + +Obsolete histograms +~~~~~~~~~~~~~~~~~~~ + +FX_URLBAR_SELECTED_RESULT_INDEX (OBSOLETE) + This probe tracked the indexes of picked results in the results list. + It was an enumerated histogram with 17 buckets. + +FX_URLBAR_SELECTED_RESULT_TYPE and FX_URLBAR_SELECTED_RESULT_TYPE_2 (from Firefox 78 on) (OBSOLETE) + This probe tracked the types of picked results. + It was an enumerated histogram with 17 buckets: + + 0. autofill + 1. bookmark + 2. history + 3. keyword + 4. searchengine + 5. searchsuggestion + 6. switchtab + 7. tag + 8. visiturl + 9. remotetab + 10. extension + 11. preloaded-top-site + 12. tip + 13. topsite + 14. formhistory + 15. dynamic + 16. tabtosearch + +FX_URLBAR_SELECTED_RESULT_INDEX_BY_TYPE and FX_URLBAR_SELECTED_RESULT_INDEX_BY_TYPE_2 (from Firefox 78 on) (OBSOLETE) + This probe tracked picked result type, for each one it tracked the index where + it appeared. + It was a keyed histogram where the keys were result types (see + FX_URLBAR_SELECTED_RESULT_TYPE above). For each key, this recorded the indexes + of picked results for that result type. + +Obsolete search probes +---------------------- + +navigation.search (OBSOLETE) + This is a legacy and disabled event telemetry that is currently under + discussion for removal or modernization. It can't be enabled through a pref. + it's more or less equivalent to browser.engagement.navigation, but can also + report the picked search engine. diff --git a/browser/components/urlbar/docs/utilities.rst b/browser/components/urlbar/docs/utilities.rst new file mode 100644 index 0000000000..8fa3b8509e --- /dev/null +++ b/browser/components/urlbar/docs/utilities.rst @@ -0,0 +1,26 @@ +Utilities +========= + +Various modules provide shared utilities to the other components: + +`UrlbarPrefs.jsm <https://searchfox.org/mozilla-central/source/browser/components/urlbar/UrlbarPrefs.jsm>`_ +------------------------------------------------------------------------------------------------------------- + +Implements a Map-like storage or urlbar related preferences. The values are kept +up-to-date. + +.. highlight:: JavaScript +.. code:: + + // Always use browser.urlbar. relative branch, except for the preferences in + // PREF_OTHER_DEFAULTS. + UrlbarPrefs.get("delay"); // Gets value of browser.urlbar.delay. + +.. note:: + + Newly added preferences should always be properly documented in UrlbarPrefs. + +`UrlbarUtils.jsm <https://searchfox.org/mozilla-central/source/browser/components/urlbar/UrlbarUtils.jsm>`_ +------------------------------------------------------------------------------------------------------------- + +Includes shared utils and constants shared across all the components. |