Bug 1776313 - Add design docs part 1.
authorAgi Sferro <agi@sferro.dev>
Mon, 27 Jun 2022 23:53:55 +0000
changeset 622234 b3e2563524cea94dbcd7490112693d9f742f2306
parent 622233 ad472cdbdd980049db0a37f8553d4bdbd490e304
child 622235 0abf4079a1d516bae23e15ec5e5507211e11a53b
push id39910
push userbszekely@mozilla.com
push dateTue, 28 Jun 2022 09:16:40 +0000
treeherdermozilla-central@3a227a2156b9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1776313
milestone104.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1776313 - Add design docs part 1. Differential Revision: https://phabricator.services.mozilla.com/D150297
mobile/android/docs/geckoview/design/breaking-changes.rst
mobile/android/docs/geckoview/design/index.rst
mobile/android/docs/geckoview/design/login-storage-api.rst
mobile/android/docs/geckoview/design/managing-extensions.rst
mobile/android/docs/geckoview/design/priority-hint.rst
mobile/android/docs/geckoview/design/save-to-pdf.rst
mobile/android/docs/geckoview/design/sharing-rust-libraries.rst
mobile/android/docs/geckoview/index.rst
new file mode 100644
--- /dev/null
+++ b/mobile/android/docs/geckoview/design/breaking-changes.rst
@@ -0,0 +1,232 @@
+Breaking changes in GeckoView
+=============================
+
+Agi sferro <agi@sferro.dev>
+
+Abstract
+--------
+
+This document describes the reasoning behind the GeckoView deprecation policy,
+where we are today and where we want to be in the future.
+
+Background
+----------
+
+The following sections illustrate how breaking changes are expensive and
+frustrating as a consumer of GeckoView, as a Gecko engineer and as an external
+consumer, how they take away time from the Fenix team and reduce the average
+testing time on Nightly up to 30%. And finally, how breaking changes negate the
+very advantages that brought us to the current modularized architecture.
+
+Introduction
+------------
+
+GeckoView is a library that provides consumers access to Gecko and is the main
+way through which Gecko is consumed on Mozilla’s Android products.
+
+GeckoView provides Nightly, Beta and Release channels which update with the
+same cadence as Firefox Desktop does.
+
+Firefox for Android (code name Fenix) is developed on a standalone repository
+on GitHub and uses GeckoView through Android Components (AC for short), an
+Android library also developed on its own standalone repository.
+
+Fenix also provides Nightly, Beta and Release updates that mirror GeckoView and
+Firefox Desktop’s.
+
+Testing days
+------------
+
+All Firefox Gecko-based products release a new major version every 4 weeks.
+Which means that, on average, a commit that lands on a random day during the
+release cycle gets 2 weeks of testing time on the Nightly user base.
+
+We try to increase the average testing time on Nightly by having a few “soft”
+code-freeze days before each Merge day where engineers are not supposed to push
+risky changes, but there’s no enforcement and it’s left to each engineer to
+decide whether their change is risky or not.
+
+Each day where the Nightly build is delayed, every change contained in the
+current Nightly cycle gets 7% (1 out of 14 days) on average less testing that
+it normally would during a build. That is assuming that a problem gets
+immediately reported and the report is immediately referred to the right
+Engineering team.
+
+Assuming a 4 days report delay, each day where the Nightly build is delayed,
+due to reasons such as breaking changes, reduces the average testing time by
+10%.
+
+Nightly update
+--------------
+
+Fenix Nightly consumes GeckoView indirectly through Android Components. Each
+day, an automated script makes a change in Fenix’s codebase to update AC’s
+version. This change is then submitted to Fenix’s CI and, if all tests pass, is
+merged to the codebase automatically.
+
+A new Fenix Nightly build is then generated and automatically published to
+Google’s Play Store, from where it gets distributed to all Nightly users on
+Android.
+
+Android Components has a similar automated process which publishes new versions
+every day, picking up the new GeckoView nightly build.
+
+The update process fails from time to time. The cause of the failure largely
+falls in one of the following three buckets.
+
+- An intermittent test failure
+- A bug introduced in the latest AC or GeckoView update which causes a test to
+  fail
+- A backward incompatible change has been made in AC or GeckoView that breaks
+  the build.
+
+The current mitigation for 1 is to disable or fix tests that fail
+intermittently, similarly to what happens in mozilla-central.
+
+2 and 3 are problems unique to Fenix and AC (as compared to Firefox Desktop)
+and are a direct consequence of the multi-package infrastructure of Fenix.
+
+Build breakages
+---------------
+
+When the automated Nightly update fails, an engineer on the Fenix team needs to
+manually intervene to unblock the build.
+
+The need for a manual intervention automatically adds a day of Nightly build
+delay when the failure occurs outside of business hours, and 2 or 3 days of
+delay when the failure happens on a Friday night.
+
+Therefore, even assuming that a build breakage takes no time to fix, the
+average testing time is reduced by 7-30% for each build breakage that occurs.
+
+In the case where the breakage takes a few days or more to fix, the average
+testing time can be reduced to as much as half of what it would be on a
+breakage-free Nightly cycle.
+
+Build breakages put undue burden on the Fenix team, who has to jump on the
+breakage and has to drop their current work to avoid losing additional testing
+days.
+
+Reducing breakages
+------------------
+
+Breakages caused by upstream teams like GeckoView can be divided into 2 groups:
+
+- Behavior changes that cause test failures downstream
+- Breaking changes in the API that cause the build to fail.
+
+To reduce breakages from group 1, the GeckoView team maintains an extensive set
+of integration tests that operate solely on the GeckoView API, and therefore
+rarely break because of refactoring.
+
+For group 2, the GeckoView team instituted a deprecation policy which requires
+each backward-incompatible change to keep the old code for 3 releases, allowing
+downstream consumers, like Fenix, time to migrate asynchronously to the new
+code without breaking the build.
+
+Functional testing and prototyping
+----------------------------------
+
+GeckoView offers a test browser app called GeckoViewExample (or GVE) that is
+developed in-tree and thus always available to test local changes.
+
+GVE is the main testing vehicle for Gecko and GeckoView engineers that want to
+develop new code, however, there frequently are issues or new features that
+cannot be tested on GVE and need to be tested directly on Fenix.
+
+To test new code in Fenix, the build system offers an easy way to swap
+locally-build GeckoView in Fenix.
+
+The process of testing new Gecko code in Fenix needs to be straightforward, as
+it’s often used by platform engineers that are unfamiliar with Android and
+Fenix itself, and are not likely to retain knowledge from running code on
+Android and would likely need help to do so from the GeckoView or Fenix team.
+
+Side-effects of build breakages
+-------------------------------
+
+When a breakage lands in mozilla-central and until the breakage is fixed in the
+Fenix codebase, a locally built GeckoView is not compatible with the
+most-recent tip of Fenix.
+
+This can be confusing to an engineer that is unfamiliar to Fenix, and can cause
+frustration and time lost trying to figure out why upstream code, without
+modifications, fails to compile.
+
+Beyond confusion, an incompatibility on the GeckoView/Fenix combined history
+negates the primary advantage of building Fenix in a separate package:
+decoupling Gecko from the Android front-end.
+
+Building older versions from source is also harder, as the set of version
+couples (GeckoView, Fenix) that are compatible with each other is not
+explicitly documented anywhere.
+
+External consumers
+------------------
+
+For apps interested in building a browser for Android, GeckoView provides the
+unique combination of being a modern Web engine with a relatively stable API.
+
+For comparison, alternatives to GeckoView include:
+
+- WebView, Android’s way of embedding web pages on Android apps. WebView has
+  has several drawbacks for browser developers, including:
+
+  - having a limited API for building browsers, as it does not expose modern
+    Web features or browser-specific APIs like bookmarks, passwords, etc;
+  - not allowing developers to control the underlying Chromium version. WebView
+    users will get whatever version of WebView is installed on the device.
+  - On the other hand, using WebView has the advantage of providing a smaller
+    download package, as the bulk of the engine is already installed on the
+    device.
+
+- Fork Chromium, which has the drawback of either having to rewrite the entire
+  browser front-end or locally patching the Chrome front-end, which involves
+  frequent changes and updates to be on top of. Using Chromium has the advantage
+  of providing the most stable, performant and compatible Web Engine on the
+  market.
+
+If the cost of updating GeckoView becomes high enough because of frequent API
+changes, the advantage of using GeckoView is negated.
+
+Prior Art
+---------
+
+Many public libraries offer a deprecation policy similar or better than
+GeckoView. For example, Android APIs need to be deprecated for a few releases
+before being considered for removal, and completely removed only in exceptional
+cases. Google products’ deprecated APIs are supported for a year before being
+removed. Ebay requires deprecating an API before removal.
+
+Status quo
+----------
+
+Making backward-incompatible changes to the GeckoView API is currently heavily
+discouraged and requires approval by the GeckoView team.
+
+We do, however, have breaking changes from time to time. The last breaking
+change was in June 2021, a refactor of the permission API which we didn’t think
+was worth executing in a backward compatible way. Before that, the last
+breaking change was in September 2020.
+
+Tracking breaking changes
+-------------------------
+
+Internally, GeckoView tracks the API using apilint. Each change that touches
+the API requires an additional GeckoView peer to review the patch and a
+description of the change in the changelog.
+
+Apilint also tracks deprecated APIs and enforces their removal, so that old,
+deprecated APIs don’t linger in the codebase for longer than necessary.
+
+The future
+----------
+
+The ideal end state for GeckoView would be to not have any more backward
+incompatible changes. Our experience is that supporting the old APIs for a
+limited time is a small overhead in our development and that the benefits from
+having a backward compatible API greatly outweigh the cost.
+
+We cannot, however, predict all future needs of GeckoView and Firefox as a
+whole, so we cannot exclude the possibility of having new breaking changes
+going forward.
new file mode 100644
--- /dev/null
+++ b/mobile/android/docs/geckoview/design/index.rst
@@ -0,0 +1,19 @@
+.. -*- Mode: rst; fill-column: 80; -*-
+
+===========
+Design docs
+===========
+
+.. toctree::
+   :maxdepth: 1
+   :glob:
+   :hidden:
+
+   *
+
+- `Breaking changes <breaking-changes.html>`_
+- `Login Storage <login-storage-api.html>`_
+- `Extension Managing <managing-extensions.html>`_
+- `Priority Hint  <priority-hint.html>`_
+- `Save to PDF <save-to-pdf.html>`_
+- `Sharing rust libraries across the Firefox stack <sharing-rust-libraries.html>`_
new file mode 100644
--- /dev/null
+++ b/mobile/android/docs/geckoview/design/login-storage-api.rst
@@ -0,0 +1,207 @@
+GeckoView Login Storage API
+===========================
+
+Eugen Sawin <esawin@mozilla.com>
+
+December 20th, 2019
+
+Motivation
+----------
+
+The current GV Autofill API provides all the essential callbacks and meta
+information for the implementation of autofill/login app support. It also
+manages the fallback to the Android ``AutofillManager``, which delegates
+requests to the system-wide autofill service set by the user.
+
+However, the current GV Autofill API does not leverage the complete range of
+Gecko heuristics that handle many autofill/login scenarios.
+
+The GV Login Storage API is meant to bridge that gap and provide an
+intermediate solution for Fenix to enable feature-rich autofill/login support
+without duplicating Gecko mechanics. As a storage-level API, it would also
+enable easy integration with the existing Firefox Sync AC.
+
+API Proposal A (deprecated)
+---------------------------
+
+Unified Login Storage API: session delegate
+
+.. code:: java
+
+  class LoginStorage {
+      class Login {
+          String guid;
+          // @Fenix: currently called `hostname` in AsyncLoginsStorage.
+          String origin;
+          // @Fenix: currently called `formSubmitURL` in AsyncLoginsStorage
+          String formActionOrigin;
+          String httpRealm;
+          String username;
+          String password;
+      }
+
+      class Hint {
+          // @Fenix: Automatically save the login and indicate this to the
+          // user.
+          int GENERATED;
+          // @Fenix: Don’t prompt to save but allow the user to open UI to
+          // save if they really want.
+          int PRIVATE_MODE;
+          // The data looks like it may be some other data (e.g. CC) entered
+          // in a password field.
+          // @Fenix: Don’t prompt to save but allow the user to open UI to
+          // save if they want (e.g. in case the CC number is actually the
+          // username for a credit card account)
+          int LOW_CONFIDENCE;
+          // TBD
+      }
+
+      interface Delegate {
+          // Notify that the given login has been used for login.
+          // @Fenix: call AsyncLoginsStorage.touch(login.guid).
+          void onLoginUsed(Login login);
+
+          // Request logins for the given domain.
+          // @Fenix: return AsyncLoginsStorage.getByHostname(domain).
+          GeckoResult<Login[]> onLoginRequest(String domain);
+
+          // Request to save or update the given login.
+          // The hint should help determining the appropriate user prompting
+          // behavior.
+          // @Fenix: Use the API from application-services/issues/1983 to
+          // determine whether to show a Save or Update button on the
+          // doorhanger, taking into account un/pw edits in the doorhanger.
+          // When the user confirms the save/update,
+          void onLoginSave(Login login, int hint);
+
+          // TBD (next API iteration): handle autocomplete selection.
+          // GeckoResult<Login> onLoginSelect(Login[] logins);
+      }
+  }
+
+Extension of ``GeckoSession``
+
+.. code:: java
+
+  // Extending existing session class.
+  class GeckoSession {
+      // Set the login storage delegate for this session.
+      void setLoginStorageDelegate(LoginStorage.Delegate delegate);
+
+      LoginStorage.Delegate getLoginStorageDelegate();
+  }
+
+API Proposal B
+--------------
+
+Split Login Storage API: runtime storage delegate / session prompts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Split storing and prompting. Fetching and saving of logins is handled by the
+runtime delegate, prompting for saving and (in future) autocompletion is
+handled by the prompt delegate.
+
+.. code:: java
+
+  class LoginStorage {
+      class Login {
+          String guid;
+          // @Fenix: currently called `hostname` in AsyncLoginsStorage.
+          String origin;
+          // @Fenix: currently called `formSubmitURL` in AsyncLoginsStorage
+          String formActionOrigin;
+          String httpRealm;
+          String username;
+          String password;
+      }
+
+      interface Delegate {
+          // v2
+          // Notify that the given login has been used for login.
+          // @Fenix: call AsyncLoginsStorage.touch(login.guid).
+          void onLoginUsed(Login login);
+
+          // Request logins for the given domain.
+          // @Fenix: return AsyncLoginsStorage.getByHostname(domain).
+          GeckoResult<Login[]> onLoginFetch(String domain);
+
+          // Request to save or update the given login.
+          void onLoginSave(Login login);
+      }
+  }
+
+Extension of ``GeckoRuntime``
+
+.. code:: java
+
+  // Extending existing runtime class.
+  class GeckoRuntime {
+      // Set the login storage delegate for this runtime.
+      void setLoginStorageDelegate(LoginStorage.Delegate delegate);
+  }
+
+Extension of ``GeckoSession.PromptDelegate``
+
+.. code:: java
+
+  // Extending existing prompt delegate.
+  class GeckoSession {
+      interface PromptDelegate {
+          class LoginStoragePrompt extends BasePrompt {
+              class Type {
+                  int SAVE;
+                  // TBD: autocomplete selection.
+                  // int SELECT;
+              }
+
+              class Hint {
+                  // v2
+                  // @Fenix: Automatically save the login and indicate this
+                  // to the user.
+                  int GENERATED;
+                  // @Fenix: Don’t prompt to save but allow the user to open
+                  // UI to save if they really want.
+                  int PRIVATE_MODE;
+                  // The data looks like it may be some other data (e.g. CC)
+                  // entered in a password field
+                  // @Fenix: Don’t prompt to save but allow the user to open
+                  // UI to save if they want (e.g. in case the CC number is
+                  // actually the username for a credit card account)
+                  int LOW_CONFIDENCE;
+                  // TBD
+              }
+
+              // Type
+              int type;
+
+              // Hint
+              // The hint should help determining the appropriate user
+              // prompting behavior.
+              // @Fenix: Use the API from application-services/issues/1983 to
+              // determine whether to show a Save or Update button on the
+              // doorhanger, taking into account un/pw edits in the
+              // doorhanger. When the user confirms the save/update.
+              int hint;
+
+              // For SAVE, it will hold the login to be stored or updated.
+              // For SELECT, it will hold the logins for the autocomplete
+              // selection.
+              Login[] logins;
+
+              // Confirm SAVE prompt: the login would include a user’s edits
+              // to what will be saved.
+              // v2
+              // Confirm SELECT (autocomplete) prompt by providing the
+              // selected login.
+              PromptResponse confirm(Login login);
+
+              // Dismiss request.
+              PromptResponse dismiss();
+          }
+
+          GeckoResult<PromptResponse> onLoginStoragePrompt(
+              GeckoSession session,
+              LoginStoragePrompt prompt
+          );
+      }
+  }
new file mode 100644
--- /dev/null
+++ b/mobile/android/docs/geckoview/design/managing-extensions.rst
@@ -0,0 +1,229 @@
+GeckoView Extension Managing API
+================================
+
+Agi Sferro <agi@sferro.dev>
+
+November 19th, 2019
+
+Introduction
+------------
+
+This document describes the API for installing, uninstalling and updating
+Extensions with GeckoView.
+
+Installing an extension provides the extension the ability to run at startup
+time, especially useful for e.g. extensions that intercept network requests,
+like an ad-blocker or a proxy extension. It also provides additional security
+from third-party extensions like signature checking and prompting the user for
+permissions.
+
+For this version of the API we will assume that the extension store is backed
+by ``addons.mozilla.org``, and so are the signatures. Running a third-party
+extension store is something we might consider in the future but explicitly not
+in scope for this document.
+
+API
+---
+
+The embedder will be able to install, uninstall, enable, disable and update
+extensions using the similarly-named APIs.
+
+Installing
+^^^^^^^^^^
+
+Gecko will download the extension pointed by the URI provided in install, parse
+the manifest and signature and provide an ``onInstallPrompt`` callback with the
+list of permissions requested by the extension and some information about the
+extension.
+
+The embedder will be able to install bundled first-party extensions using
+``installBuiltIn``. This method will only accept URIs that start with
+``resource://`` and will give additional privileges like being able to use app
+messaging and not needing a signature.
+
+Each permission will have a machine readable name that the embedder will use to
+produce user-facing internationalized strings. E.g. “bookmarks” gives access to
+bookmarks, “sessions” gives access to recently closed sessions. The full list
+of permissions that are currently shown to the UI in Firefox Desktop is
+available at: ``chrome/browser/browser.properties``
+
+Updating
+^^^^^^^^
+
+To update an extension, the embedder will be able to call update which will
+check if any update is available (using the update_url provided by the
+extension, or addons.mozilla.org if no update_url has been provided). The
+embedder will receive a GeckoResult that will provide the updated extension
+object. This result can also be used to know when the update process is
+complete, e.g. the embedder could use it to display a persistent notification
+to the user to avoid having the app be killed while updates are in process.
+
+If the updated extension needs additional permissions, ``GeckoView`` will call
+``onUpdatePrompt``.
+
+Until this callback is resolved (i.e. the embedder’s returned ``GeckoResult``
+is completed), the old addon will be running, only when the prompt is resolved
+and the update is applied the new version of the addon starts running and the
+``GeckoResult`` returned from update is resolved.
+
+This callback will provide both the current ``WebExtension`` object and the
+updated WebExtension object so that the embedder can show appropriate
+information to the user, e.g. the app might decide to remember whether the user
+denied the request for a certain version and only prompt the user once the
+version string changes.
+
+As a side effect of updating, Gecko will check its internal blocklist and might
+disable extensions that are incompatible with the current version of Gecko or
+deemed unsafe. The resulting ``WebExtension`` object will reflect that by
+having isEnabled set to false. The embedder will be able to inspect the reason
+why the extension was disabled using ``metaData.blockedReason``.
+
+Gecko will not update any extension or blocklist state without the embedder’s
+input.
+
+Enabling and Disabling
+^^^^^^^^^^^^^^^^^^^^^^
+
+Embedders will be able to enable and disabling extension using the homonymous
+APIs. Calling enable on an extension might not actually enable it if the
+extension has been added to the Gecko blocklist. Embedders can check the value
+of ``metaData.blockedReason`` to display to the user whether the extension can
+actually be enabled or not. The returned WebExtension object will reflect the
+updated enablement state in isEnabled.
+
+Listing
+^^^^^^^
+
+The embedder is expected to keep a collection of all available extensions using
+the result of install and update. To retrieve the extensions that are already
+installed the embedder will be able to use ``listInstalled`` which will
+asynchronously retrieve the full list of extensions. We recommend calling
+``listInstalled`` every time the user is presented with the extension manager
+UI to ensure all information is up to date.
+
+Outline
+^^^^^^^
+
+.. code:: java
+
+  public class WebExtensionController {
+    // Start the process of installing an extension,
+    // the embedder will either get the installed extension
+    // or an error
+    GeckoResult<WebExtension> install(String uri);
+
+    // Install a built-in WebExtension with privileged
+    // permissions, uri must be resource://
+    // Privileged WebExtensions have access to experiments
+    // (i.e. they can run chrome code), don’t need signatures
+    // and have access to native messaging to the app
+    GeckoResult<WebExtension> installBuiltIn(String uri)
+
+    GeckoResult<Void> uninstall(WebExtension extension);
+
+    GeckoResult<WebExtension> enable(WebExtension extension);
+
+    GeckoResult<WebExtension> disable(WebExtension extension);
+
+    GeckoResult<List<WebExtension>> listInstalled();
+
+    // Checks for updates. This method returns a GeckoResult that is
+    // resolved either with the updated WebExtension object or null
+    // if the extension does not have pending updates.
+    GeckoResult<WebExtension> update(WebExtension extension);
+
+    public interface PromptDelegate {
+        GeckoResult<AllowOrDeny> onInstallPrompt(WebExtension extension);
+
+        GeckoResult<AllowOrDeny> onUpdatePrompt(
+            WebExtension currentlyInstalled,
+            WebExtension updatedExtension,
+            List<String> newPermissions);
+
+        // Called when the extension calls browser.permission.request
+        GeckoResult<AllowOrDeny> onOptionalPrompt(
+            WebExtension extension,
+            List<String> optionalPermissions);
+    }
+
+    void setPromptDelegate(PromptDelegate promptDelegate);
+  }
+
+As part of this document, we will add a ``MetaData`` field to WebExtension
+which will contain all the information known about the extension. Note: we will
+rename ``ActionIcon`` to Icon to represent its generic use as the
+``WebExtension`` icon class.
+
+.. code:: java
+
+  public class WebExtension {
+    // Renamed from ActionIcon
+    static class Icon {}
+
+    final MetaData metadata;
+    final boolean isBuiltIn;
+
+    final boolean isEnabled;
+
+    public static class SignedStateFlags {
+      final static int UNKNOWN;
+      final static int PRELIMINARY;
+      final static int SIGNED;
+      final static int SYSTEM;
+      final static int PRIVILEGED;
+    }
+
+    // See nsIBlocklistService.idl
+    public static class BlockedReason {
+      final static int NOT_BLOCKED;
+      final static int SOFTBLOCKED;
+      final static int BLOCKED;
+      final static int OUTDATED;
+      final static int VULNERABLE_UPDATE_AVAILABLE;
+      final static int VULNERABLE_NO_UPDATE;
+    }
+
+    public class MetaData {
+      final Icon icon;
+      final String[] permissions;
+      final String[] origins;
+      final String name;
+      final String description;
+      final String version;
+      final String creatorName;
+      final String creatorUrl;
+      final String homepageUrl;
+      final String optionsPageUrl;
+      final boolean openOptionsPageInTab;
+      final boolean isRecommended;
+      final @BlockedReason int blockedReason;
+      final @SignedState int signedState;
+      // more if needed
+    }
+  }
+
+Implementation Details
+^^^^^^^^^^^^^^^^^^^^^^
+
+We will use ``AddonManager`` as a backend for ``WebExtensionController`` and
+delegate the prompt to the app using ``PromptDelegate``. We will also merge
+``WebExtensionController`` and ``WebExtensionEventDispatcher`` for ease of
+implementation.
+
+Existing APIs
+^^^^^^^^^^^^^
+
+Some APIs today return a ``WebExtension`` object that might have not been
+fetched yet by ``listInstalled``. In these cases, GeckoView will return a stub
+``WebExtension`` object in which the metadata field will be null to avoid
+waiting for a addon list call. To ensure that the metadata field is populated,
+the embedder will need to call ``listInstalled`` at least once during the app
+startup.
+
+Deprecation Path
+^^^^^^^^^^^^^^^^
+
+The existing ``registerWebExtension`` and ``unregisterWebExtension`` APIs will
+be deprecated by ``installBuiltIn`` and ``uninstall``. We will remove the above
+APIs 6 releases after the implementation of ``installBuiltIn`` lands and mark
+it as deprecated in the API.
new file mode 100644
--- /dev/null
+++ b/mobile/android/docs/geckoview/design/priority-hint.rst
@@ -0,0 +1,68 @@
+GeckoView Priority Hint API
+===========================
+
+Cathy Lu <calu@mozilla.com>, `Bug 1764998 <https://bugzilla.mozilla.org/show_bug.cgi?id=1764998>`_
+
+May 2nd, 2022
+
+Summary
+-------
+
+This document describes the API for setting a process to high priority by
+applying a high priority hint. Instead of deducing the priority based on the
+extension’s active priority, this will add an API to set it explicitly. 
+
+Motivation
+----------
+
+This API will allow Glean metrics to be measured in order to compare
+performance and stability metrics for process prioritization on vs off.
+Previously, prioritization depended on whether or not a ``GeckoSession`` had a
+surface associated with it, which lowered the priority of background tabs and
+needed to be reloaded more often.
+
+Goals
+-----
+
+Apps can set ``priorityHint`` on a ``GeckoSession``.
+
+Existing Work
+-------------
+
+In `bug 1753700 <https://bugzilla.mozilla.org/show_bug.cgi?id=1753700>`_, we
+added an API in dom/ipc to allow ``GeckoViewWebExtension`` to set a specific
+``remoteTab``’s boolean ``priorityHint``. This allows tabs that do not have a
+surface but are active according to web extension to have high priority.
+
+Implementation
+--------------
+
+In ``GeckoSession``, add an API ``setPriorityHint`` that takes an integer as a
+parameter. The priority int can be ``PRIORITY_DEFAULT`` or ``PRIORITY_HIGH``.
+Specified and active tabs would be ``PRIORITY_HIGH``. The default would be
+``PRIORITY_DEFAULT``. The API will dispatch an event
+``GeckoView:SetPriorityHint``.
+
+.. code:: java
+
+  public void setPriorityHint(final @Priority int priorityHint)
+
+Listeners in ``GeckoViewContent.jsm`` will set
+``this.browser.frameLoader.remoteTab.priorityHint`` to the boolean passed in. 
+
+.. code:: java
+
+  case "GeckoView:setPriorityHint":
+    if (this.browser.isRemoteBrowser) {
+      let remoteTab = this.browser.frameLoader?.remoteTab;
+      if (remoteTab) {
+        remoteTab.renderLayers.priorityHint = val;
+      }
+    }
+  break;
+
+Additional Complexities
+-----------------------
+
+Apps that use this API will need to manually use the API to set the
+priorityHint when the tab goes to foreground or background.
new file mode 100644
--- /dev/null
+++ b/mobile/android/docs/geckoview/design/save-to-pdf.rst
@@ -0,0 +1,202 @@
+GeckoView Save to PDF
+=====================
+
+Olivia Hall <ohall@mozilla.com>, Jonathan Almeida <jon@mozilla.com>
+
+Why
+---
+
+- The Save to PDF feature was originally available in Fennec and users would
+  like to see the return of this feature. There are a lot of user requests for
+  Save to PDF in Fenix.
+- We would have more parity with Desktop, and be able to share the same
+  underlying implementation with them.
+- Product is currently evaluating the addition of pdf.js as well; having Save
+  to PDF would be an added bonus.
+
+Goals
+-----
+
+- Save the current page to a text-based PDF document.
+- Embedders should also be able to call into GeckoView to provide a PDF copy of
+  the selected GeckoSession.
+- Enable the ability to iterate on PDF customizations.
+
+Non-Goals
+---------
+
+- We do not want to implement a PDF “preview” of the document prior to the
+  download. This has open questions: does Product want this, should this be
+  implemented by the embedder, etc.
+- The generated PDF should not match the theme (e.g., light or dark mode) of
+  the currently displayed page - the PDF will always appear as themeless or as
+  a plain document.
+- No customizable settings. The current API design will not include
+  customization settings that the embedder can control. This can be worked on
+  in a follow-up feature request. Our current API design however, would enable
+  for these particular iterations.
+
+What
+----
+
+This work will add a method to ``GeckoSession`` called ``savePdf`` for
+embedders to use, which will communicate with a new ``GeckoViewPdf.jsm`` to
+create the PDF file. When the document is available, the
+``GeckoViewPdfController`` will notify the
+``ContentDelegate.onExternalResponse`` with the downloadable document.
+
+- ``GeckoViewPdf.jsm`` - JavaScript implementation that converts the content to
+  a PDF and saves the file, also responds to messaging from
+  ``GeckoViewPdfController``.
+- ``GeckoViewPdfController.java`` - The Controller coordinates between the Java
+  and JS through response messaging and notifies the content delegate when the
+  PDF is available for use.
+
+API
+---
+
+GeckoSession.java
+^^^^^^^^^^^^^^^^^
+
+.. code:: java
+
+  public class GeckoSession {
+    public GeckoSession(final @Nullable GeckoSessionSettings settings) {
+      mPdfController = new PdfController(this);
+    }
+
+    @UiThread
+    public void saveAsPdf(PdfSettings settings) {
+      mPdfController.savePdf(null);
+    }
+  }
+
+
+GeckoViewPdf.jsm
+^^^^^^^^^^^^^^^^
+.. code:: java
+
+  this.registerListener([
+      "GeckoView:SavePdf",
+    ]);
+
+  async onEvent(aEvent, aData, aCallback) {
+    debug`onEvent: event=${aEvent}, data=${aData}`;
+
+    switch (aEvent) {
+      case "GeckoView:SavePdf":
+        this.saveToPDF();
+        Break;
+      }
+    }
+  }
+
+  async saveToPDF() {
+   // Reference: https://searchfox.org/mozilla-central/source/remote/cdp/domains/parent/Page.jsm#519
+  }
+
+
+GeckoViewPdfController.java
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.. code:: java
+
+  class PdfController {
+    private static final String LOGTAG = "PdfController";
+    private final GeckoSession mSession;
+
+    PdfController(final GeckoSession session) {
+      mSession = session;
+    }
+
+    private PdfDelegate mDelegate;
+    private BundleEventListener mEventListener;
+
+    /* package */
+    PdfController() {
+      mEventListener = new EventListener();
+      EventDispatcher.getInstance()
+        .registerUiThreadListener(mEventListener,"GeckoView:PdfSaved");
+    }
+
+    @UiThread
+    public void setDelegate(final @Nullable PdfDelegate delegate) {
+      ThreadUtils.assertOnUiThread();
+      mDelegate = delegate;
+    }
+
+    @UiThread
+    @Nullable
+    public PdfDelegate getDelegate() {
+      ThreadUtils.assertOnUiThread();
+      return mDelegate;
+    }
+
+    @UiThread
+    public void savePdf() {
+      ThreadUtils.assertOnUiThread();
+      mEventDispatcher.dispatch("GeckoView:SavePdf", null);
+    }
+
+
+    private class EventListener implements BundleEventListener {
+
+      @Override
+      public void handleMessage(
+        final String event,
+        final GeckoBundle message,
+        final EventCallback callback
+      ) {
+        if (mDelegate == null) {
+          callback.sendError("Not allowed");
+          return;
+        }
+
+        switch (event) {
+          case "GeckoView:PdfSaved": {
+            final ContentDelegate delegate = mSession.getContentDelegate();
+
+            if (message.containsKey("pdfPath")) {
+            InputStream inputStream; /* construct InputStream from local file path */
+            WebResponse response = WebResponse.Builder()
+              .body(inputStream)
+              // Add other attributes as well.
+              .build();
+
+              if (delegate != null) {
+                delegate.onExternalResponse(mSession, response);
+              } else {
+                throw Exception("Needs ContentDelegate for this to work.")
+              }
+            }
+
+            break;
+          }
+        }
+      }
+    }
+  }
+
+geckoview.js
+^^^^^^^^^^^^
+.. code:: java
+
+  {
+    name: "GeckoViewPdf",
+    onInit: {
+       resource: "resource://gre/modules/GeckoViewPdf.jsm",
+    }
+  }
+
+
+Testing
+-------
+
+- Tests for the jsm and java code will be covered by mochitests and junit.
+- Make assertions to check that the text and images are in the finished PDF;
+  the PDF is a non-zero file size.
+
+Risks
+-----
+
+The API and the code that this work would be using are pretty new, currently
+prefered off in Nightly and could contain implementation bugs.
new file mode 100644
--- /dev/null
+++ b/mobile/android/docs/geckoview/design/sharing-rust-libraries.rst
@@ -0,0 +1,276 @@
+Sharing rust libraries across the Firefox (for Android) stack
+=============================================================
+
+`Agi Sferro <agi@sferro.dev>`
+
+March 20th, 2021
+
+The problem
+-----------
+
+We don’t have a good story for integrating a rust library so that it’s
+available to use in Gecko, GeckoView, AC and Fenix and also in a way that rust
+can call rust directly avoiding a C FFI layer.
+
+Goals
+-----
+
+- Being able to integrate a rust library that can be called from Gecko,
+  GeckoView, AC, Fenix, including having singleton-like instances that are
+  shared across the stack, per-process.
+- The rust library should be able to call and be called by other rust libraries
+  or rust code in Gecko directly (i.e. without a C FFI layer)
+- A built-time assurance that all components in the stack compile against the
+  same version of the rust library
+- Painless, quick and automated updates. Should be able to produce chemspill
+  updates for the rust library in under 24h with little manual intervention
+  (besides security checks / code review / QA).
+- Support for non-Gecko consumers of the rust library is essential. I.e.
+  providing a version of Gecko that does not include any of the libraries
+- (optional?) Provide an easy way to create bundles of rust libraries depending
+  on consumers needs.
+
+Proposal
+--------
+
+1. Rename libmegazord.so to librustcomponents.so to clarify what the purpose of
+   this artifact is.
+2. Every rust library that wants to be called or wants to call rust code
+   directly will be included in libxul.so (which contains most of Gecko native
+   code), and vendored in mozilla-central. This includes, among others, Glean and
+   Nimbus.
+3. libxul.so will expose the necessary FFI symbols for the Kotlin wrappers
+   needed by the libraries vendored in mozilla-central in step (2).
+4. At every nightly / beta / release build of Gecko, we will generate an (or
+   possibly many) additional librustcomponents.so artifacts that will be published
+   as an AAR in maven.mozilla.org. This will also publish all the vendored
+   libraries in mozilla-central to maven, which will have a dependency on the
+   librustcomponents.so produced as part of this step. Doing this will ensure that
+   both libxul.so and librustcomponents.so contain the exact same code and can be
+   swapped freely in the dependency graph.
+5. Provide a new GeckoView build with artifactId geckoview-omni which will
+   depend on all the rust libraries. The existing geckoview will not have such
+   dependency and will be kept for third-party users of GeckoView.
+6. GeckoView will depend on the Kotlin wrappers of all the libraries that
+   depend on librustcomponents.so built in step (4) in the .pom file. For example
+
+  .. code:: xml
+
+    <dependency>
+      <groupId>org.mozilla.telemetry</groupId>
+      <artifactId>glean</artifactId>
+      <version>33.1.2</version>
+      <scope>compile</scope>
+    </dependency>
+  It will also exclude the org.mozilla.telemetry.glean dependency to
+  librustcomponents.so, as the native code is now included in libxul.so as part
+  of step (2). Presumably Glean will discover where its native code lives by
+  either trying librustcomponents.so or libxul.so (or some other better methods,
+  suggestions welcome).
+7. Android Components and Fenix will remove their explicit dependency on Glean,
+   Nimbus and all other libraries provided by GeckoView, and instead consume the
+   one provided by GeckoView (this step is optional, note that any version
+   conflict would cause a build error).
+
+The good
+--------
+
+- We get automated integration with AC for free. When an update for a library
+  is pushed to mozilla-central, a new nightly build for GeckoView will be
+  produced which is already consumed by AC automatically (and indirectly into
+  Fenix).
+- Publishing infrastructure to maven is already figured out, and we can reuse
+  the existing process for GeckoView to publish all the dependencies.
+- If a consumer (say AC) uses a mismatched version for a dependency, a
+  compile-time error will be thrown.
+- All consumers of the rust libraries packaged this way are on the same version
+  (provided they stay up to date with releases)
+- Non-Mozilla consumers get first-class visibility into what is packaged into
+  GeckoView, and can independently discover Glean, Nimbus, etc, since we define
+  our dependencies in the pom file.
+- Gecko Desktop and Gecko Mobile consumer Glean and other libraries in the same
+  way, removing unnecessary deviation.
+
+Worth Noting
+------------
+
+- Uplifts to beta / release versions of Fenix will involve more checks as they
+  impact Gecko too.
+
+The Bad
+-------
+
+- Libraries need to be vendored in mozilla-central. Dependencies will follow
+  the Gecko train which might not be right for them, as some dependencies don’t
+  really have a nightly vs stable version. - This could change in the future, as
+  the integration gets deeper and updates to the library become more frequent /
+  at every commit.
+- Locally testing a change in a rust library involves rebuilding all of Gecko.
+  This is a side effect of statically linking rust libraries to Gecko.
+- All rust libraries that are both used by Android and Gecko will need to be
+  updated together, and we cannot have separate versions on Desktop/Mobile.
+  Although this can be mitigated by providing flexible dependency on the library
+  side (e.g. nimbus doesn’t need to depend on a specific version of - Glean and
+  can accept whatever is in Gecko)
+- Code that doesn’t natively live in mozilla-central has double the work to get
+  into a product - first a release process is needed from the native repo, then
+  a phabricator process for the vendoring.
+
+Alternatives Considered
+-----------------------
+
+Telemetry delegate
+^^^^^^^^^^^^^^^^^^
+
+GeckoView provides a Java Telemetry delegate interface that Glean can implement
+on the AC layer to provide Glean functionality to consumers. Glean would offer
+a rust wrapper to the Java delegate API to transparently call either the
+delegate (when built for mobile) or the Glean instance directly (when built for
+Desktop).
+
+Drawbacks
+"""""""""
+
+- This involves a lot of work on the Glean side to build and maintain the
+  delegate
+- A large section of the Glean API is embedded in the GeckoView API without a
+  direct dependency
+- We don’t expect the telemetry delegate to have other implementations other
+  than Glean itself, despite the apparent generic nature of the telemetry
+  delegate
+- Glean and GeckoView engineers need to coordinate for every API update, as an
+  update to the Glean API likely triggers an update to the GV API.
+- Gecko Desktop and Gecko Mobile use Glean a meaningfully different way
+- Doesn’t solve the dependency problem: even though in theory this would allow
+  Gecko to work with multiple Glean versions, in practice the GV Telemetry
+  delegate is going to track Glean so closely that it will inevitably require
+  pretty specific Glean versions to work.
+
+Advantages
+""""""""""
+
+- Explicit code dependency, an uninformed observer can understand how telemetry
+  is extracted from GeckoView by just looking at the API
+- No hard Glean version requirement, AC can be (in theory) built with a
+  different Glean version than Gecko and things would still work
+
+Why we decided against
+""""""""""""""""""""""
+
+The amount of ongoing maintenance work involved on the Glean side far outweighs
+the small advantages, namely to not tie AC to a specific Glean version.
+Significantly complicates the stack.
+
+Dynamic Discovery
+^^^^^^^^^^^^^^^^^
+
+Gecko discovers when it’s being loaded as part of Fenix (or some other
+Gecko-powered browser) by calling dlsym on the Glean library. When the
+discovery is successful, and the Glean version matches, Gecko will directly use
+the Glean provided by Fenix.
+
+Drawbacks
+"""""""""
+
+- Non standard, non-Mozilla apps will not expect this to work the way it does
+- “Magic”: there’s no way to know that the dyscovery is happening (or what
+  version of Glean is provided with Gecko) unless you know it’s there.
+- The standard failure mode is at runtime, as there’s no built-in way to check
+  that the version provided by Gecko is the same as the one provided by Fenix
+  at build time.
+- Doesn’t solve the synchronization problem: Gecko and Fenix will have to be on
+  the same Glean version for this to work.
+- Gecko Mobile deviates meaningfully from Desktop in the way it uses Glean for
+  no intrinsic reason
+
+Advantages
+""""""""""
+
+- This system is transparent to Consuming apps, e.g. Nimbus can use Glean as
+  is, with no significant modifications needed.
+
+Why we decided against
+""""""""""""""""""""""
+
+- This alternative does not provide substantial benefits over the proposal
+  outlined in this doc and has significant drawbacks like the runtime failure
+  case and the non-standard linking process.
+
+Hybrid Dynamic Discovery
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+This is a variation of the Dynamic Discovery where Gecko and GeckoView include
+Glean directly and consumers get Glean from Gecko dynamically (i.e. they dlsym
+libxul.so).
+
+Drawbacks
+"""""""""
+
+- Glean still needs to build a wrapper for libraries not included in Gecko
+  (like Nimbus) that want to call Glean directly.
+
+Advantages
+""""""""""
+
+- The dependency to Glean is explicit and clear from an uninformed observer
+  point of view.
+- Smaller scope, only Glean would need to be moved to mozilla-central
+
+Why we decided against
+""""""""""""""""""""""
+
+Not enough advantages over the proposal, significant ongoing maintenance work
+required from the Glean side.
+
+Open Questions
+--------------
+
+- How does iOS consume megazord today? Do they have a maven-like dependency
+  system we can use to publish the iOS megazord?
+- How do we deal with licenses in about:license? Application-services has a
+  build step that extracts rust dependencies and puts them in the pom file
+- What would be the process for coordinating a-c breaking changes?
+- Would the desire to vendor apply even if this were not Rust code?
+
+Common Questions
+----------------
+
+- **How do we make sure GV/AC/Gecko consume the same version of the native
+  libraries?** The pom dependency in GeckoView ensures that any GeckoView
+  consumers depend on the same version of a given library, this includes AC and
+  Fenix.
+- **What happens to non-Gecko consumers of megazord?** This plan is transparent
+  to a non-Gecko consumer of megazord, as they will still consume the native
+  libraries through the megazord dependency in Glean/Nimbus/etc. With the added
+  benefit that, if the consumer stays up to date with the megazord dependency,
+  they will use the same version that Gecko uses.
+- **What’s the process to publish an update to the megazord?** When a team
+  wants to publish an update to the megazord it will need to commit the update
+  to mozilla-central. A new build will be generated in the next nightly cycle,
+  producing an updated version of the megazord. My understanding is that current
+  megazord releases are stable (and don’t have beta/nightly cycles) so for
+  external consumers, consuming the nightly build could be adequate, and provide
+  the fastest turnaround on updates. For Gecko consumers the turnaround will be
+  the same to Firefox Desktop (i.e. roughly 6-8 weeks from commit to release
+  build).
+- **How do we handle security uplifts?** If you have a security release one
+  rust library you would need to request uplift to beta/release branches
+  (depending on impact) like all other Gecko changes. The process in itself can
+  be expedited and have a fast turnaround when needed (below 24h). We have been
+  using this process for all Gecko changes so I would not expect particular
+  problems with it.
+- **What about OOP cases? E.g. GeckoView as a service?** We briefly discussed
+  this in the email chain, there are ways we could make that work (e.g.
+  providing a IPC shim). The details are fuzzy but since we don’t have any
+  immediate need for such support knowing that it’s doable with a reasonable
+  amount of work is enough for now.
+- **Vendoring in mozilla-central seems excessive.** I agree. This is an
+  unfortunate requirement stemming from a few assumptions (which could be
+  challenged! We are choosing not to):
+
+   - Gecko wants to vendor whatever it consumes for rust
+   - We want rust to call rust directly (without a C FFI layer)
+   - We want adding new libraries to be a painless experience
+
+  Because of the above, vendoring in mozilla-central seems to be the best if not
+  the only way to achieve our goals.
--- a/mobile/android/docs/geckoview/index.rst
+++ b/mobile/android/docs/geckoview/index.rst
@@ -16,16 +16,17 @@ That is where GeckoView comes in. GeckoV
 Documentation
 =============
 
 .. toctree::
    :titlesonly:
 
    consumer/index
    contributor/index
+   design/index
    Changelog <https://mozilla.github.io/geckoview/javadoc/mozilla-central/org/mozilla/geckoview/doc-files/CHANGELOG>
    API Javadoc <https://mozilla.github.io/geckoview/javadoc/mozilla-central/index.html>
 
 =================
 More information
 =================
 
 * Talk to us on `Matrix <https://chat.mozilla.org/#/room/#geckoview:mozilla.org>`_