summaryrefslogtreecommitdiffstats
path: root/mobile/android/docs/geckoview/design
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
commit0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch)
treea31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /mobile/android/docs/geckoview/design
parentInitial commit. (diff)
downloadfirefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz
firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--mobile/android/docs/geckoview/design/breaking-changes.rst232
-rw-r--r--mobile/android/docs/geckoview/design/index.rst19
-rw-r--r--mobile/android/docs/geckoview/design/login-storage-api.rst207
-rw-r--r--mobile/android/docs/geckoview/design/managing-extensions.rst229
-rw-r--r--mobile/android/docs/geckoview/design/priority-hint.rst68
-rw-r--r--mobile/android/docs/geckoview/design/save-to-pdf.rst202
-rw-r--r--mobile/android/docs/geckoview/design/sharing-rust-libraries.rst279
7 files changed, 1236 insertions, 0 deletions
diff --git a/mobile/android/docs/geckoview/design/breaking-changes.rst b/mobile/android/docs/geckoview/design/breaking-changes.rst
new file mode 100644
index 0000000000..8838a225fa
--- /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.
diff --git a/mobile/android/docs/geckoview/design/index.rst b/mobile/android/docs/geckoview/design/index.rst
new file mode 100644
index 0000000000..f0e2a2dc84
--- /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>`_
diff --git a/mobile/android/docs/geckoview/design/login-storage-api.rst b/mobile/android/docs/geckoview/design/login-storage-api.rst
new file mode 100644
index 0000000000..3dc4ceac62
--- /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
+ );
+ }
+ }
diff --git a/mobile/android/docs/geckoview/design/managing-extensions.rst b/mobile/android/docs/geckoview/design/managing-extensions.rst
new file mode 100644
index 0000000000..8592854ecd
--- /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.
diff --git a/mobile/android/docs/geckoview/design/priority-hint.rst b/mobile/android/docs/geckoview/design/priority-hint.rst
new file mode 100644
index 0000000000..4a915bb7ed
--- /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.
diff --git a/mobile/android/docs/geckoview/design/save-to-pdf.rst b/mobile/android/docs/geckoview/design/save-to-pdf.rst
new file mode 100644
index 0000000000..fc4edc6310
--- /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
+pref'd off in Nightly and could contain implementation bugs.
diff --git a/mobile/android/docs/geckoview/design/sharing-rust-libraries.rst b/mobile/android/docs/geckoview/design/sharing-rust-libraries.rst
new file mode 100644
index 0000000000..1aa6657b1f
--- /dev/null
+++ b/mobile/android/docs/geckoview/design/sharing-rust-libraries.rst
@@ -0,0 +1,279 @@
+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 build-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.