diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /mobile/android/docs/geckoview/contributor/geckoview-architecture.rst | |
parent | Initial commit. (diff) | |
download | firefox-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 'mobile/android/docs/geckoview/contributor/geckoview-architecture.rst')
-rw-r--r-- | mobile/android/docs/geckoview/contributor/geckoview-architecture.rst | 826 |
1 files changed, 826 insertions, 0 deletions
diff --git a/mobile/android/docs/geckoview/contributor/geckoview-architecture.rst b/mobile/android/docs/geckoview/contributor/geckoview-architecture.rst new file mode 100644 index 0000000000..e4235dd4dd --- /dev/null +++ b/mobile/android/docs/geckoview/contributor/geckoview-architecture.rst @@ -0,0 +1,826 @@ +.. -*- Mode: rst; fill-column: 80; -*- + +===================== +Architecture overview +===================== + +.. contents:: Table of Contents + :depth: 2 + :local: + +Introduction +============ + +*Gecko* is a Web engine developed by Mozilla and used to power Firefox on +various platforms. A Web engine is roughly comprised of a JavaScript engine, a +Rendering engine, HTML parser, a Network stack, various media encoders, a +Graphics engine, a Layout engine and more. + +Code that is part of a browser itself is usually referred to as "chrome" code +(from which the popular Chrome browser takes its name) as opposed to code part +of a Web site, which is usually referred to "content" code or content Web page. + +*GeckoView* is an Android library that can be used to embed Gecko into Android +apps. Android apps that embed Gecko this way are usually referred to by +"embedders" or simply "apps". + +GeckoView powers all currently active Mozilla browsers on Android, like Firefox +for Android and Firefox Focus. + +API +=== + +The following sections describe parts of the GeckoView API that are public and +exposed to embedders. + + |api-diagram| + +Overall tenets +-------------- + +GeckoView is an opinionated library that contains a minimal UI and makes no +assumption about the type of app that is being used by. Its main consumers +inside Mozilla are browsers, so a lot of features of GeckoView are geared +towards browsers, but there is no assumption that the embedder is actually a +browser (e.g. there is no concept of "tab" in GeckoView). + +The GeckoView API tries to retain as little data as possible, delegating most +data storage to apps. Notable exceptions to this rule are: permissions, +extensions and cookies. + +View, Runtime and Session +------------------------- + + |view-runtime-session| + +There are three main classes in the GeckoView API: + +- ``GeckoRuntime`` represents an instance of Gecko running in an app. Normally, + apps have only one instance of the runtime which lives for as long as the app + is alive. Any object in the API that is not specific to a *session* + (more to this later) is usually reachable from the runtime. +- ``GeckoSession`` represents a web site *instance*. You can think of it as a + *tab* in a browser or a Web view in an app. Any object related to the + specific session will be reachable from this object. Normally, embedders + would have many instances of ``GeckoSession`` representing each tab that is + currently open. Internally, a session is represented as a "window" with one + single tab in it. +- ``GeckoView`` is an Android ``View`` that embedders can use to paint a + ``GeckoSession`` in the app. Normally, only ``GeckoSession`` s associated to + a ``GeckoView`` are actually *alive*, i.e. can receive events, fire timers, + etc. + +Delegates +--------- + +Because GeckoView has no UI elements and doesn't store a lot of data, it needs +a way to *delegate* behavior when Web sites need functionality that requires +these features. + +To do that, GeckoView exposes Java interfaces to the embedders, called +Delegates. Delegates are normally associated to either the runtime, when they +don't refer to a specific session, or a session, when they are +session-specific. + +The most important delegates are: + +- ``Autocomplete.StorageDelegate`` Which is used by embedders to implement + autocomplete functionality for logins, addresses and credit cards. +- ``ContentDelegate`` Which receives events from the content Web page like + "open a new window", "on fullscreen request", "this tab crashed" etc. +- ``HistoryDelegate`` Which receives events about new or modified history + entries. GeckoView itself does not store history so the app is required to + listen to history events and store them permanently. +- ``NavigationDelegate`` Informs the embedder about navigation events and + requests. +- ``PermissionDelegate`` Used to prompt the user for permissions like + geolocation, notifications, etc. +- ``PromptDelegate`` Implements content-side prompts like alert(), confirm(), + basic HTTP auth, etc. +- ``MediaSession.Delegate`` Informs the embedder about media elements currently + active on the page and allows the embedder to pause, resume, receive playback + state etc. +- ``WebExtension.MessageDelegate`` Used by the embedder to exchange messages + with built-in extensions. See also `Interacting with Web Content <../consumer/web-extensions.html>`_. + + +.. _GeckoDisplay: + +GeckoDisplay +------------ + +GeckoView can paint to either a ``SurfaceView`` or a ``TextureView``. + +- ``SufaceView`` is what most apps will use and it's the default, it provides a + barebone wrapper around a GL surface where GeckoView can paint on. + SurfaceView is not part of normal Android compositing, which means that + Android is not able to paint (partially) on top of a SurfaceView or apply + transformations and animations to it. +- ``TextureView`` offers a surface which can be transformed and animated but + it's slower and requires more memory because it's `triple-buffered + <https://en.wikipedia.org/wiki/Multiple_buffering#Triple_buffering>`_ + (which is necessary to offer animations). + +Most apps will use the ``GeckoView`` class to paint the web page. The +``GeckoView`` class is an Android ``View`` which takes part in the Android view +hierarchy. + +Android recycles the ``GeckoView`` whenever the app is not visible, releasing +the associated ``SurfaceView`` or ``TextureView``. This triggers a few actions +on the Gecko side: + +- The GL Surface is released, and Gecko is notified in + `SyncPauseCompositor <https://searchfox.org/mozilla-central/rev/ead7da2d9c5400bc7034ff3f06a030531bd7e5b9/widget/android/nsWindow.cpp#1114>`_. +- The ``<browser>`` associated to the ``GeckoSession`` is `set to inactive <https://searchfox.org/mozilla-central/rev/ead7da2d9c5400bc7034ff3f06a030531bd7e5b9/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoView.java#553>`_, + which essentially freezes the JavaScript engine. + +Apps that do not use ``GeckoView``, because e.g. they cannot use +``SurfaceView``, need to manage the active state manually and call +``GeckoSession.setActive`` whenever the session is not being painted on the +screen. + +Thread safety +------------- + +Apps will inevitably have to deal with the Android UI in a significant way. +Most of the Android UI toolkit operates on the UI thread, and requires +consumers to execute method calls on it. The Android UI thread runs an event +loop that can be used to schedule tasks on it from other threads. + +Gecko, on the other hand, has its own main thread where a lot of the front-end +interactions happen, and many methods inside Gecko expect to be called on the +main thread. + +To not overburden the App with unnecessary multi-threaded code, GeckoView will +always bridge the two "main threads" and redirect method calls as appropriate. +Most GeckoView delegate calls will thus happen on the Android UI thread and +most APIs are expected to be called on the UI thread as well. + +This can sometimes create unexpected performance considerations, as illustrated +in later sections. + +GeckoResult +----------- + +An ubiquitous tool in the GeckoView API is ``GeckoResult``. GeckoResult is a +promise-like class that can be used by apps and by Gecko to return values +asynchronously in a thread-safe way. Internally, ``GeckoResult`` will keep +track of what thread it was created on, and will execute callbacks on the same +thread using the thread's ``Handler``. + +When used in Gecko, ``GeckoResult`` can be converted to ``MozPromise`` using +``MozPromise::FromGeckoResult``. + +Page load +--------- + + |pageload-diagram| + +GeckoView offers several entry points that can be used to react to the various +stages of a page load. The interactions can be tricky and surprising so we will +go over them in details in this section. + +For each page load, the following delegate calls will be issued: +``onLoadRequest``, ``onPageStart``, ``onLocationChange``, +``onProgressChange``, ``onSecurityChange``, ``onSessionStateChange``, +``onCanGoBack``, ``onCanGoForward``, ``onLoadError``, ``onPageStop``. + +Most of the method calls are self-explanatory and offer the App a chance to +update the UI in response to a change in the page load state. The more +interesting delegate calls will be described below. + +onPageStart and onPageStop +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``onPageStart`` and ``onPageStop`` are guaranteed to appear in pairs and in +order, and denote the beginning and the end of a page load. In between a start +and stop event, multiple ``onLoadRequest`` and ``onLocationChange`` call can be +executed, denoting redirects. + +onLoadRequest +~~~~~~~~~~~~~ + +``onLoadRequest``, which is perhaps the most important, can be used by the App +to intercept page loads. The App can either *deny* the load, which will stop +the page from loading, and handle it internally, or *allow* the +load, which will load the page in Gecko. ``onLoadRequest`` is called for all +page loads, regardless of whether they were initiated by the app itself, by Web +content, or as a result of a redirect. + +When the page load originates in Web content, Gecko has to synchronously +wait for the Android UI thread to schedule the call to ``onLoadRequest`` and +for the App to respond. This normally takes a negligible amount of time, but +when the Android UI thread is busy, e.g. because the App is being painted for +the first time, the delay can be substantial. This is an area of GeckoView that +we are actively trying to improve. + +onLoadError +~~~~~~~~~~~ + +``onLoadError`` is called whenever the page does not load correctly, e.g. +because of a network error or a misconfigured HTTPS server. The App can return +a URL to a local HTML file that will be used as error page internally by Gecko. + +onLocationChange +~~~~~~~~~~~~~~~~ + +``onLocationChange`` is called whenever Gecko commits to a navigation and the +URL can safely displayed in the URL bar. + +onSessionStateChange +~~~~~~~~~~~~~~~~~~~~ + +``onSessionStateChange`` is called whenever any piece of the session state +changes, e.g. form content, scrolling position, zoom value, etc. Changes are +batched to avoid calling this API too frequently. + +Apps can use ``onSessionStateChange`` to store the serialized state to +disk to support restoring the session at a later time. + +Third-party root certificates +----------------------------- + +Gecko maintains its own Certificate Authority store and does not use the +platform's CA store. GeckoView follows the same policy and will not, by +default, read Android's CA store to determine root certificates. + +However, GeckoView provides a way to import all third-party CA roots added to +the Android CA store by setting the `enterpriseRootsEnabled +<https://mozilla.github.io/geckoview/javadoc/mozilla-central/org/mozilla/geckoview/GeckoRuntimeSettings.Builder.html#enterpriseRootsEnabled(boolean)>`_ +runtime setting to ``true``, this feature is implemented in `EnterpriseRoots +<https://searchfox.org/mozilla-central/rev/26a6a38fb515dbab0bb459c40ec4b877477eefef/mobile/android/geckoview/src/main/java/org/mozilla/gecko/EnterpriseRoots.java>`_ + +There is not currently any API for an app to manually specify additional CA +roots, although this might change with `Bug 1522162 +<https://bugzilla.mozilla.org/show_bug.cgi?id=1522162>`_. + +Lite and Omni builds +--------------------- + +A variation of the default GeckoView build, dubbed `Omni` in the codebase, +provides additional libraries that can be helpful when building a browser app. +Currently, the `Glean +<https://docs.telemetry.mozilla.org/concepts/glean/glean.html>`_ library is +included in the ``geckoview-omni`` package. The default build ``geckoview``, +which does not contain such libraries, is similarly dubbed `Lite` in the +codebase. + +The additional libraries in the Omni package are directly built into Gecko's +main ``.so`` file, ``libxul.so``. These libraries are then declared in the +``.module`` package inside the ``maven`` repository, e.g. see the ``.module`` +file for `geckoview-omni +<https://maven.mozilla.org/maven2/org/mozilla/geckoview/geckoview-omni/102.0.20220623063721/geckoview-omni-102.0.20220623063721.module>`_: + +.. code-block:: json + + "capabilities": [ + { + "group": "org.mozilla.geckoview", + "name": "geckoview-omni", + "version": "102.0.20220623063721" + }, + { + "group": "org.mozilla.telemetry", + "name": "glean-native", + "version": "44.1.1" + } + ] + +Notice the ``org.mozilla.telemetry:glean-native`` capability is declared +alongside ``org.mozilla.geckoview``. + +The main Glean library then depends on ``glean-native`` which is either +provided in a standalone package (for apps that do not include GeckoView) or by +the GeckoView capability above. + +In Treeherder, the Lite build is denoted with ``Lite``, while the Omni builds +don't have extra denominations as they are the default build, so e.g. for +``x86_64`` the platorm names would be: + +- ``Android 7.0 x86-64`` for the Omni build +- ``Android 7.0 x86-64 Lite`` for the Lite build + +Extensions +---------- + +Extensions can be installed using ``WebExtensionController::install`` and +``WebExtensionController::installBuiltIn``, which asynchronously returns a +``WebExtension`` object that can be used to set delegates for +extension-specific behavior. + +The ``WebExtension`` object is immutable, and will be replaced every time a +property changes. For instance, to disable an extension, apps can use the +``disable`` method, which will return an updated version of the +``WebExtension`` object. + +Internally, all ``WebExtension`` objects representing one extension share the +same delegates, which are stored in ``WebExtensionController``. + +Given the extensive sprawling amount of data associated to extensions, +extension installation persists across restarts. Existing extensions can be +listed using ``WebExtensionController::list``. + +In addition to ordinary WebExtension APIs, GeckoView allows ``builtIn`` +extensions to communicate to the app via native messaging. Apps can register +themselves as native apps and extensions will be able to communicate to the app +using ``connectNative`` and ``sendNativeMessage``. Further information can be +found `here <../consumer/web-extensions.html>`__. + +Internals +========= + +The following sections describe how Gecko and GeckoView are implemented. These +parts of GeckoView are not normally exposed to embedders. + +Process Model +------------- + +Internally, Gecko uses a multi-process architecture, most of the chrome code +runs in the *main* process, while content code runs in *child* processes also +called *content* processes. There are additional types of specialized processes +like the *socket* process, which runs parts of the networking code, the *gpu* +process which executes GPU commands, the *extension* process which runs most +extension content code, etc. + +We intentionally do not expose our process model to embedders. + +To learn more about the multi-process architecture see `Fission for GeckoView +engineers <https://gist.github.com/agi/c900f3e473ff681158c0c907e34780e4>`_. + +The majority of the GeckoView Java code runs on the main process, with a thin +glue layer on the child processes, mostly contained in ``GeckoThread``. + +Process priority on Android +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +On Android, each process is assigned a given priority. When the device is +running low on memory, or when the system wants to conserve resources, e.g. +when the screen has been off for a long period of time, or the battery is low, +Android will sort all processes in reverse priority order and kill, using a +``SIGKILL`` event, enough processes until the given free memory and resource +threshold is reached. + +Processes that are necessary to the function of the device get the highest +priority, followed by apps that are currently visible and focused on the +screen, then apps that are visible (but not on focus), background processes and +so on. + +Processes that do not have a UI associated to it, e.g. background services, +will normally have the lowest priority, and thus will be killed most +frequently. + +To increase the priority of a service, an app can ``bind`` to it. There are +three possible ``bind`` priority values + +- ``BIND_IMPORTANT``: The process will be *as important* as the process binding + to it +- default priority: The process will have lower priority than the process + binding to it, but still higher priority than a background service +- ``BIND_WAIVE_PRIORITY``: The bind will be ignored for priority + considerations. + +It's important to note that the priority of each service is only relative to +the priority of the app binding to it. If the app is not visible, the app +itself and all services attached to it, regardless of binding, will get +background priority (i.e. the lowest possible priority). + +Process management +~~~~~~~~~~~~~~~~~~ + +Each Gecko process corresponds to an Android ``service`` instance, which has to +be declared in GeckoView's ``AndroidManifest.xml``. + +For example, this is the definition of the ``media`` process: + +.. code-block:: + + <service + android:name="org.mozilla.gecko.media.MediaManager" + android:enabled="true" + android:exported="false" + android:isolatedProcess="false" + android:process=":media"> + +Process creation is controlled by Gecko which interfaces to Android using +``GeckoProcessManager``, which translates Gecko's priority to Android's +``bind`` values. + +Because all priorities are waived when the app is in the background, it's not +infrequent that Android kills some of GeckoView's services, while still leaving +the main process alive. + +It is therefore very important that Gecko is able to recover from process +disappearing at any moment at runtime. + +Priority Hint +~~~~~~~~~~~~~ + +Internally, GeckoView ties the lifetime of the ``Surface`` associated to a +``GeckoSession`` and the process priority of the process where the session +lives. + +The underlying assumption is that a session that is not visible doesn't have a +surface associated to it and it's not being used by the user so it shouldn't +receive high priority status. + +The way this is implemented is `by setting +<https://searchfox.org/mozilla-central/rev/5b2d2863bd315f232a3f769f76e0eb16cdca7cb0/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoView.java#114,123>`_ +the ``active`` property on the ``browser`` object to ``false``, which causes +Gecko to de-prioritize the process, assuming that no other windows in the same +process have ``active=true``. See also `GeckoDisplay`_. + +However, there are use cases where just looking at the surface is not enough. +For instance, when the user opens the settings menu, the currently selected tab +becomes invisible, but the user will still expect the browser to retain that +tab state with a higher priority than all the other tabs. Similarly, when the +browser is put in the background, the surface associated to the current tab +gets destroyed, but the current tab is still more important than the other +tabs, but because it doesn't have a surface associated to it, we have no way to +differentiate it from all the other tabs. + +To solve the above problem, we expose an API for consumers to *boost* a session +priority, `setPriorityHint +<https://mozilla.github.io/geckoview/javadoc/mozilla-central/org/mozilla/geckoview/GeckoSession.html#setPriorityHint(int)>`_. +The priority hint is taken into consideration when calculating the +priority of a process. Any process that contains either an active session or a +session with the priority hint `is boosted +<https://searchfox.org/mozilla-central/rev/5b2d2863bd315f232a3f769f76e0eb16cdca7cb0/dom/ipc/BrowserParent.cpp#3593>`_ +to the highest priority. + +Shutdown +-------- + +Android does not provide apps with a notification whenever the app is shutting +down. As explained in the section above, apps will simply be killed whenever +the system needs to reclaim resources. This means that Gecko on Android will +never shutdown cleanly, and that shutdown actions will never execute. + +.. _principals: + +Principals +---------- + +In Gecko, a *website* loaded in a session is represented by an abstraction +called `principal +<https://searchfox.org/mozilla-central/rev/5b2d2863bd315f232a3f769f76e0eb16cdca7cb0/caps/nsIPrincipal.idl>`_. +Principals contain information that is used to determine what permissions have +been granted to the website instance, what APIs are available to it, which +container the page is loaded in, is the page in private browsing or not, etc. + +Principals are used throughout the Gecko codebase, GeckoView, however, does not +expose the concept to the API. This is intentional, as exposing it would +potentially expose the app to various security sensitive concepts, which would +violate the "secure" requirement for the GeckoView API. + +The absence of principals from the API is, e.g., why GeckoView does not offer a +way to set permissions given a URL string, as permissions are internally stored +by principal. See also `Setting Permissions`_. + +To learn more about principals see `this talk by Bobby Holley +<https://www.youtube.com/watch?v=28FPetl5Fl4>`_. + +Window model +------------ + +Internally, Gecko has the concept of *window* and *tab*. Given that GeckoView +doesn't have the concept of tab (since it might be used to build something that +is *not* a browser) we hide Gecko tabs from the GeckoView API. + +Each ``GeckoSession`` corresponds to a Gecko ``window`` object with exactly one +``tab`` in it. Because of this you might see ``window`` and ``session`` used +interchangeably in the code. + +Internally, Gecko uses ``window`` s for other things other than +``GeckoSession``, so we have to sometime be careful about knowing which windows +belong to GeckoView and which don't. For example, the background extension page +is implemented as a ``window`` object that doesn't paint to a surface. + +EventDispatcher +--------------- + +The GeckoView codebase is written in C++, JavaScript and Java, it runs across +processes and often deals with asynchronous and garbage-collected code with +complex lifetime dependencies. To make all of this work together, GeckoView +uses a cross-language event-driven architecture. + +The main orchestrator of this event-driven architecture is ``EventDispatcher``. +Each language has an implementation of ``EventDispatcher`` that can be used to +fire events that are reachable from any language. + +Each window (i.e. each session) has its own ``EventDispatcher`` instance, which +is also present on the content process. There is also a global +``EventDispatcher`` that is used to send and receive events that are not +related to a specific session. + +Events can have data associated to it, which is represented as a +``GeckoBundle`` (essentially a ``String``-keyed variant map) on the Java and +C++ side, and a plain object on the JavaScript side. Data is automatically +converted back and forth by ``EventDispatcher``. + +In Java, events are fired in the same thread where the listener was registered, +which allows us to ensure that events are received in a consistent order and +data is kept consistent, so that we by and large don't have to worry about +multi-threaded issues. + +JNI +--- + +GeckoView code uses the Java Native Interface or JNI to communicate between +Java and C++ directly. Our JNI exports are generated from the Java source code +whenever the ``@WrapForJNI`` annotation is present. For non-GeckoView code, the +list of classes for which we generate imports is defined at +``widget/android/bindings``. + +The lifetime of JNI objects depends on their native implementation: + +- If the class implements ``mozilla::SupportsWeakPtr``, the Java object will + store a ``WeakPtr`` to the native object and will not own the lifetime of the + object. +- If the class implements ``AddRef`` and ``Release`` from ``nsISupports``, the + Java object will store a ``RefPtr`` to the native object and will hold a + strong reference until the Java object releases the object using + ``DisposeNative``. +- If neither cases apply, the Java object will store a C++ pointer to the + native object. + +Calling Runtime delegates from native code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Runtime delegates can be reached directly using the ``GeckoRuntime`` singleton. +A common pattern is to expose a ``@WrapForJNI`` method on ``GeckoRuntime`` that +will call the delegate, that than can be used on the native side. E.g. + +.. code:: java + + @WrapForJNI + private void featureCall() { + ThreadUtils.runOnUiThread(() -> { + if (mFeatureDelegate != null) { + mFeatureDelegate.feature(); + } + }); + } + +And then, on the native side: + +.. code:: cpp + + java::GeckoRuntime::LocalRef runtime = java::GeckoRuntime::GetInstance(); + if (runtime != nullptr) { + runtime->FeatureCall(); + } + +Session delegates +~~~~~~~~~~~~~~~~~ + +``GeckoSession`` delegates require a little more care, as there's a copy of a +delegate for each ``window``. Normally, a method on ``android::nsWindow`` is +added which allows Gecko code to call it. A reference to ``nsWindow`` can be +obtained from a ``nsIWidget`` using ``nsWindow::From``: + +.. code:: cpp + + RefPtr<nsWindow> window = nsWindow::From(widget); + window->SessionDelegateFeature(); + +The ``nsWindow`` implementation can then forward the call to +``GeckoViewSupport``, which is the JNI native side of ``GeckoSession.Window``. + +.. code:: cpp + + void nsWindow::SessionDelegateFeature() { + auto acc(mGeckoViewSupport.Access()); + if (!acc) { + return; + } + acc->SessionDelegateFeature(aResponse); + } + +Which can in turn forward the call to the Java side using the JNI stubs. + +.. code:: cpp + + auto GeckoViewSupport::SessionDelegateFeature() { + GeckoSession::Window::LocalRef window(mGeckoViewWindow); + if (!window) { + return; + } + window->SessionDelegateFeature(); + } + +And finally, the Java implementation calls the session delegate. + +.. code:: java + + @WrapForJNI + private void sessionDelegateFeature() { + final GeckoSession session = mOwner.get(); + if (session == null) { + return; + } + ThreadUtils.postToUiThread(() -> { + final FeatureDelegate delegate = session.getFeatureDelegate(); + if (delegate == null) { + return; + } + delegate.feature(); + }); + } + +.. _permissions: + +Permissions +----------- + +There are two separate but related permission concepts in GeckoView: `Content` +permissions and `Android` permissions. See also the related `consumer doc +<../consumer/permissions.html>`_ on permissions. + +Content permissions +~~~~~~~~~~~~~~~~~~~ + +Content permissions are granted to individual web sites (more precisely, +`principals`_) and are managed internally using ``nsIPermissionManager``. +Content permissions are used by Gecko to keep track which website is allowed to +access a group of Web APIs or functionality. The Web has the concept of +permissions, but not all Gecko permissions map to Web-exposed permissions. + +For instance, the ``Notification`` permission, which allows websites to fire +notifications to the user, is exposed to the Web through +`Notification.requestPermission +<https://developer.mozilla.org/en-US/docs/Web/API/Notification/requestPermission>`_, +while the `autoplay` permission, which allows websites to play video and audio +without user interaction, is not exposed to the Web and websites have no way to +set or request this permission. + +GeckoView retains content permission data, which is an explicit violation of +the design principle of not storing data. This is done because storing +permissions is very complex, making a mistake when dealing with permissions +often ends up being a security vulnerability, and because permissions depend on +concepts that are not exposed to the GeckoView API like `principals`_. + +Android permissions +~~~~~~~~~~~~~~~~~~~ + +Consumers of GeckoView are Android apps and therefore they have to receive +permission to use certain features on behalf of websites. + +For instance, when a website requests Geolocation permission for the first +time, the app needs to request the corresponding Geolocation Android permission +in order to receive position data. + +You can read more about Android permissions on `this doc +<https://developer.android.com/guide/topics/permissions/overview>`_. + + +Implementation +~~~~~~~~~~~~~~ + +The main entry point from Gecko is ``nsIContentPermissionPrompt.prompt``, which +is handled in the `Permission module +<https://searchfox.org/mozilla-central/rev/256f84391cf5d4e3a4d66afbbcd744a5bec48956/mobile/android/components/geckoview/GeckoViewPermission.jsm#21>`_ +in the same process where the request is originated. + +The permission module calls the child actor `GeckoViewPermission +<https://searchfox.org/mozilla-central/rev/9dc5ffe42635b602d4ddfc9a4b8ea0befc94975a/mobile/android/actors/GeckoViewPermissionChild.jsm#47>`_ +which issues a `GeckoView:ContentPermission +<https://searchfox.org/mozilla-central/rev/9dc5ffe42635b602d4ddfc9a4b8ea0befc94975a/mobile/android/actors/GeckoViewPermissionChild.jsm#75>`_ +request to the Java front-end as needed. + +Media permissions are requested using a global observer, and therefore are +handled in a `Process actor +<https://searchfox.org/mozilla-central/rev/9dc5ffe42635b602d4ddfc9a4b8ea0befc94975a/mobile/android/actors/GeckoViewPermissionProcessChild.jsm#41>`_, +media permissions requests have enough information to redirect the request to +the corresponding window child actor, with the exception of requests that are +not associated with a window, which are redirected to the `current active +window +<https://searchfox.org/mozilla-central/rev/9dc5ffe42635b602d4ddfc9a4b8ea0befc94975a/mobile/android/actors/GeckoViewPermissionProcessParent.jsm#28-35>`_. + +Setting permissions +~~~~~~~~~~~~~~~~~~~ + +Permissions are stored in a map between a `principal <#principals>`_ and a list +of permission (key, value) pairs. To prevent security vulnerabilities, GeckoView +does not provide a way to set permissions given an arbitrary URL and requires +consumers to get hold of the `ContentPermission +<https://mozilla.github.io/geckoview/javadoc/mozilla-central/org/mozilla/geckoview/GeckoSession.PermissionDelegate.ContentPermission.html>`_ +object. The ContentPermission object is returned in `onLocationChange +<https://mozilla.github.io/geckoview/javadoc/mozilla-central/org/mozilla/geckoview/GeckoSession.NavigationDelegate.html#onLocationChange(org.mozilla.geckoview.GeckoSession,java.lang.String,java.util.List)>`_ +upon navigation, making it unlikely to have confusion bugs whereby the +permission is given to the wrong website. + +Internally, some permissions are only present when a certain override is set, +e.g. Tracking Protection override permissions are only present when the page +has been given a TP override. Because the only way to set the value of a +permission is to get hold of the ``ContentPermission`` object, `we manually insert +<https://searchfox.org/mozilla-central/rev/5b2d2863bd315f232a3f769f76e0eb16cdca7cb0/mobile/android/modules/geckoview/GeckoViewNavigation.jsm#605-625>`_ +a `trackingprotection` permission on every page load. + +Autofill Support +---------------- + +GeckoView supports third-party autofill providers through Android's `autofill framework <https://developer.android.com/guide/topics/text/autofill>`_. Internally, this support is referred to as `autofill`. + +Document tree +~~~~~~~~~~~~~ + +The autofill Java front-end is located in the `Autofill class +<https://searchfox.org/mozilla-central/rev/9dc5ffe42635b602d4ddfc9a4b8ea0befc94975a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/Autofill.java#37>`_. +GeckoView maintains a virtual tree structure of the current document for each +``GeckoSession``. + +The virtual tree structure is composed of `Node +<https://searchfox.org/mozilla-central/rev/9dc5ffe42635b602d4ddfc9a4b8ea0befc94975a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/Autofill.java#593>`_ +objects which are immutable. Data associated to a node, including mutable data +like the current value, is stored in a separate `NodeData +<https://searchfox.org/mozilla-central/rev/9dc5ffe42635b602d4ddfc9a4b8ea0befc94975a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/Autofill.java#171>`_ +class. Only HTML nodes that are relevant to autofilling are referenced in the +virtual structure and each node is associated to a root node, e.g. the root +``<form>`` element. All root nodes are children of the autofill `mRoot +<https://searchfox.org/mozilla-central/rev/9dc5ffe42635b602d4ddfc9a4b8ea0befc94975a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/Autofill.java#210>`_ +node, hence making the overall structure a tree rather than a collection of +trees. Note that the root node is the only node in the virtual structure that +does not correspond to an actual element on the page. + +Internally, nodes are assigned a unique ``UUID`` string, which is used to match +nodes between the Java front-end and the data stored in GeckoView's chrome +Javascript. The autofill framework itself requires integer IDs for nodes, so we +store a mapping between UUIDs and integer IDs in the associated ``NodeData`` +object. The integer IDs are used only externally, while internally only the +UUIDs are used. The reason why we use a separate ID structure from the autofill +framework is that this allows us to `generate UUIDs +<https://searchfox.org/mozilla-central/rev/7e34cb7a0094a2f325a0c9db720cec0a2f2aca4f/mobile/android/actors/GeckoViewAutoFillChild.jsm#217-220>`_ +directly in the isolated content processes avoiding an IPC roundtrip to the +main process. + +Each ``Node`` object is associated to an ``EventCallback`` object which is +invoked whenever the node is autofilled by the autofill framework. + +Detecting autofillable nodes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +GeckoView scans every web page for password ``<input>`` elements whenever the +``pageshow`` event `fires +<https://searchfox.org/mozilla-central/rev/9dc5ffe42635b602d4ddfc9a4b8ea0befc94975a/mobile/android/actors/GeckoViewAutoFillChild.jsm#74-78>`_. + +It also uses ``DOMFormHasPassword`` and ``DOMInputPasswordAdded`` to detect +whenever a password element is added to the DOM after the ``pageshow`` event. + +Prefs +----- + +`Preferences </modules/libpref/index.html>`_ (or prefs) are used throughout +Gecko to configure the browser, enable custom features, etc. + +GeckoView does not directly expose prefs to Apps. A limited set configuration +options is exposed through ``GeckoRuntimeSettings``. + +``GeckoRuntimeSettings`` can be easily mapped to a Gecko ``pref`` using +``Pref``, e.g. + +.. code:: java + + /* package */ final Pref<Boolean> mPrefExample = + new Pref<Boolean>("example.pref", false); + +The value of the pref can then be read internally using ``mPrefExample.get`` +and written to using ``mPrefExample.commit``. + +Front-end and back-end +---------------------- + + |code-layers| + +Gecko and GeckoView code can be divided in five layers: + +- **Java API** the outermost code layer that is publicly accessible to + GeckoView embedders. +- **Java Front-End** All the Java code that supports the API and talks directly + to the Android APIs and to the JavaScript and C++ front-ends. +- **JavaScript Front-End** The main interface to the Gecko back-end (or Gecko + proper) in GeckoView is JavaScript, we use this layer to call into Gecko and + other utilities provided by Gecko, code lives in ``mobile/android`` +- **C++ Front-End** A smaller part of GeckoView is written in C++ and interacts + with Gecko directly, most of this code is lives in ``widget/android``. +- **C++/Rust Back-End** This is often referred to as "platform", includes all + core parts of Gecko and is usually accessed to in GeckoView from the C++ + front-end or the JavaScript front-end. + +Modules and Actors +------------------ + +GeckoView's JavaScript Front-End is largely divided into units called modules +and actors. For each feature, each window will have an instance of a Module, a +parent-side Actor and (potentially many) content-side Actor instances. For a +detailed description of this see `here <https://gist.github.com/agi/c900f3e473ff681158c0c907e34780e4#actors>`__. + +Testing infrastructure +---------------------- + +For a detailed description of our testing infrastructure see `GeckoView junit +Test Framework <junit.html>`_. + +.. |api-diagram| image:: ../assets/api-diagram.png +.. |view-runtime-session| image:: ../assets/view-runtime-session.png +.. |pageload-diagram| image:: ../assets/pageload-diagram.png +.. |code-layers| image:: ../assets/code-layers.png |