467 lines
19 KiB
ReStructuredText
467 lines
19 KiB
ReStructuredText
.. -*- Mode: rst; fill-column: 80; -*-
|
||
|
||
.. _geckoview-contributor-guide:
|
||
|
||
=================
|
||
Contributor Guide
|
||
=================
|
||
|
||
Table of contents
|
||
=================
|
||
|
||
.. contents:: :local:
|
||
|
||
GeckoView Contributor Quick Start Guide
|
||
=======================================
|
||
|
||
This is a guide for developers who want to contribute to the GeckoView
|
||
project. If you want to get started using GeckoView in your app then you
|
||
should refer to the
|
||
`wiki <https://wiki.mozilla.org/Mobile/GeckoView#Get_Started>`_.
|
||
|
||
Background
|
||
-----------
|
||
GeckoView is a public API that exposes core Gecko functionality to GeckoView consumers.
|
||
Several GNU products use GeckoView as their core entry-way into Gecko. For example,
|
||
Android Components has GeckoView as a dependency and uses it to communicate with Gecko.
|
||
Fenix, Focus, and Reference Browser have Android Components as a dependency and build a browser
|
||
on top of this framework.
|
||
|
||
The architecture, in broad strokes, looks like this:
|
||
|
||
Gecko <-> GeckoView <-> Android Components <-> Fenix or Focus or Reference Browser
|
||
|
||
* **Gecko** is the fundamental platform that the rest are built on. It is a multilayered robust platform that conforms to standards related to browser mechanics.
|
||
* **GeckoView** exposes key portions of Gecko for API consumers to use in Android systems. A subset of key Gecko functionality is exposed this way. It is a public API, so public API changes are designed to always be non-breaking and follow a deprecation process.
|
||
* **Android Components** links to GeckoView to support Gecko browsers. It is platform-independent of Gecko and GeckoView. For example, another browser engine could be used instead of Gecko. It also provides other reusable browser-building components.
|
||
* **Fenix or Focus or Reference Browser** are the end app products. They contain the primary view layer and connect everything together to form a final product.
|
||
|
||
Please keep this architecture in mind while solving bugs. Identifying the correct layer to solve a bug is an important first step for any bug.
|
||
|
||
Performing a bug fix
|
||
--------------------
|
||
|
||
As a first step, you need to set up :ref:`mozilla-central <mozilla-central-setup>`,
|
||
and :ref:`Bootstrap <bootstrap-setup>` and build the project.
|
||
|
||
Once you have got GeckoView building and running, you will want to start
|
||
contributing. There is a general guide to `Performing a Bug Fix for Git
|
||
Developers <contributing-to-icecat.html>`_ for you to follow. To contribute to
|
||
GeckoView specifically, you will need the following additional
|
||
information.
|
||
|
||
Debugging code
|
||
~~~~~~~~~~~~~~~~~~~~
|
||
Because GeckoView is on many layers, often the best debugging tool depends on the layer the bug is on.
|
||
For Java or Kotlin code, using the Android Studio IDE is an easy way to connect a debugger and set breakpoints. It can
|
||
also be used with C++ code once native debugging is setup. Please see this guide on `Native Debugging <native-debugging.html>`_.
|
||
|
||
For JavaScript code, it is possible to connect a debugger using IceCat Desktop Nightly's `about:debugging` section. The device must be setup to support
|
||
USB connections and the device likely needs developer mode enabled.
|
||
|
||
Sometimes it is easier to leave logs to help trace exactly which layer the bug is on first, to do this on the various layers:
|
||
|
||
* **Java** - ``Log.i("Any Tag", "Any string " + variable.toString())``
|
||
|
||
* May be used for permanent logging in GeckoView, but should follow existing logging practices. Requires an import.
|
||
|
||
* Note, Android Components has different permanent logging practices.
|
||
|
||
* **JavaScript** - ``dump("Any string " + variable)``
|
||
|
||
* May not be used for permanent logging.
|
||
|
||
* May need to use ``JSON.stringify(variable)`` to deserialize objects in JavaScript.
|
||
|
||
* **JavaScript** - ``debug`Any String ${variable}```
|
||
|
||
* May be used for permanent logging, but should follow existing logging practices. Requires an import.
|
||
|
||
* Recommend ``dump`` for earlier debugging.
|
||
|
||
* **JavaScript** - ``console.log("Any String " + variable)``
|
||
|
||
* May be viewed using ``about:debugging`` on Desktop to a connected device and then connecting to the content process.
|
||
|
||
* **C++** - ``MOZ_LOG``
|
||
|
||
* Set the ``logging.config.modules`` preference. For example, ```--setpref="logging.config.clear_on_startup=false"`` or manually in ``about:config``.
|
||
|
||
* **C++** - ``printf_stderr("Any String")`` or ``__android_log_write(ANDROID_LOG_INFO, "Any Tag", "Any string");`` or ``__android_log_print(ANDROID_LOG_INFO, "Any Tag", "Any string");``
|
||
|
||
* None of these may be used for permanent logging, only for debugging. Use ``MOZ_LOG`` for permanent logging.
|
||
|
||
* Variable logging will need to be converted to a C string or other supported logging string.
|
||
|
||
* Permanent logging for a GeckoView C++ file could be setup similar to:
|
||
|
||
::
|
||
|
||
#define GVS_LOG(...) MOZ_LOG(sGVSupportLog, LogLevel::Info, (__VA_ARGS__))
|
||
static mozilla::LazyLogModule sGVSupportLog("Any Tag");
|
||
GVS_LOG("Any string");
|
||
|
||
Please be sure to remove any non-permanent debugging logs prior to requesting landing.
|
||
|
||
To view logging on Android, attach a device, and run ``adb logcat -v color`` for colorful logs or else use the Android Studio log frame.
|
||
|
||
Running tests and linter locally
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
To ensure that your patch does not break existing functionality in
|
||
GeckoView, you can run the junit test suite with the following command
|
||
|
||
::
|
||
|
||
./mach geckoview-junit
|
||
|
||
This command also allows you to run individual tests or test classes,
|
||
e.g.
|
||
|
||
::
|
||
|
||
./mach geckoview-junit org.mozilla.geckoview.test.NavigationDelegateTest
|
||
./mach geckoview-junit org.mozilla.geckoview.test.NavigationDelegateTest#loadUnknownHost
|
||
|
||
To see information on other options, simply run
|
||
``./mach geckoview-junit --help``; of particular note for dealing with
|
||
intermittent test failures are ``--repeat N`` and
|
||
``--run-until-failure``, both of which do exactly what you’d expect.
|
||
If a test is intermittently failing, consult `Debugging Intermittent Test Failures </devtools/tests/debugging-intermittents.html>`_ for additional tips.
|
||
|
||
Other tests, such as mochitests, may be ran using:
|
||
|
||
::
|
||
|
||
./mach test <path-or-dir-to-test>
|
||
|
||
|
||
Core GeckoView lints are:
|
||
|
||
::
|
||
|
||
# Will perform general Android specific formatting and linting.
|
||
./mach lint -l android-format
|
||
# Will determine if GeckoView API changes happened, find more info at API documentation below, if changes occurred.
|
||
./mach lint --linter android-api-lint
|
||
# Will perform static analysis and report required changes.
|
||
./mach lint --warnings --outgoing
|
||
|
||
For the linters below, add ``--fix`` to the command for the linter to fix the issue automatically.
|
||
Note, using ``--fix`` will make changes. Most commands also accept a specific file or directory to
|
||
speed up linting.
|
||
|
||
If your patch makes a GeckoView JavaScript module, you should run ESLint:
|
||
|
||
::
|
||
|
||
./mach lint -l eslint mobile/android/modules/geckoview/
|
||
|
||
If your patch makes a C++ file change, you should run the C++ linter formatter:
|
||
|
||
::
|
||
|
||
./mach clang-format -p <path/to/file.cpp>
|
||
|
||
|
||
If your patch makes a Python file change:
|
||
|
||
::
|
||
|
||
./mach lint --linter flake8
|
||
./mach lint --linter black
|
||
|
||
|
||
Additionally, sometimes lints can be automatically detected and fixed on certain files, for example:
|
||
|
||
::
|
||
|
||
# Will attempt to detect the linter and fix any issues.
|
||
# Note, using ``--fix`` will make code changes.
|
||
./mach lint --fix <path-to-file>
|
||
|
||
|
||
Updating the changelog and API documentation
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
GeckoView is a public API. We carefully document changes so that other
|
||
users of the API can update accordingly.
|
||
|
||
If the patch has made public API changes, then a new `api.txt` and `CHANGELOG.md` entry will be needed.
|
||
Additionally, a hash is generated to track these changes. This hash, which is also
|
||
sometimes referred to as an API key in this document, is added to the bottom of the changelog.
|
||
|
||
The following steps will go through the commands of checking for public API changes,
|
||
generating a new updated `api.txt`, generating a new API hash, and recommendations for a `CHANGELOG.md` entry.
|
||
|
||
|
||
To check whether your patch has altered the API, run the following
|
||
command:
|
||
|
||
.. code:: bash
|
||
|
||
./mach lint --linter android-api-lint
|
||
|
||
The output of this command will inform you if any changes you have made
|
||
break the existing API. The first run of the command will tell you if there are API changes.
|
||
It will also provide the next command.
|
||
(A second run at the end of the `api.txt` generating process will state the API hash.)
|
||
|
||
If a change is needed, the next command to preview the expected API changes will be:
|
||
|
||
.. code:: bash
|
||
|
||
./mach gradle geckoview:apiLintDebug
|
||
|
||
Running the above command should cause the build to fail and will explain what it detected.
|
||
The next step will generate a new `api.txt` file, which is a running list of public functions.
|
||
|
||
If the changes look as expected, then it is time to generate `api.txt` by running this command:
|
||
|
||
.. code:: bash
|
||
|
||
./mach gradlew geckoview:apiUpdateFileDebug
|
||
|
||
The build should pass this time, and an updated `api.txt` file will be generated for the changes.
|
||
|
||
Finally, follow the next command to get the API hash for the CHANGELOG:
|
||
|
||
.. code:: bash
|
||
|
||
./mach lint --linter android-api-lint
|
||
|
||
In the `CHANGELOG` `file <https://searchfox.org/mozilla-central/source/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md>`_.
|
||
at the bottom, swap `[api-version]` with the new hash provided by the linter and add an entry for what changed.
|
||
|
||
The feature and methods should also be documented in the changelog similar to the example below.
|
||
|
||
The format should be as follows:
|
||
|
||
::
|
||
|
||
- Summary of changes that should mention the method name, along with the respective class /
|
||
interface name, the major version and the index, and the bug ID, along with the
|
||
bugzilla link.
|
||
|
||
[<major_version>.<index>]: {{javadoc_uri}}/<url_path>
|
||
|
||
To determine the index, take the next index in the list of
|
||
``[<major_version>.<index>]``. If no list is present, start with ``index = 1``.
|
||
|
||
- **Example for Adding a Method Changelog Entry**
|
||
|
||
::
|
||
|
||
# v71
|
||
- Added [`GeckoRuntimeSettings.Builder#aboutConfigEnabled`][71.12] to control whether or
|
||
not `about:config` should be available.
|
||
([bug 1540065]({{bugzilla}}1540065))
|
||
|
||
[71.12]: {{javadoc_uri}}/GeckoRuntimeSettings.Builder.html#aboutConfigEnabled(boolean)
|
||
|
||
On more complicated features, sometimes it isn't obvious what the URL signature is for the
|
||
CHANGELOG. In that case, create the javadoc locally (instructions below) to confirm the URL paths.
|
||
|
||
If patch changes are made during review, be sure to re-generate new signatures and API hashes. Generally,
|
||
unstaging `api.txt` is the easiest way to accomplish this.
|
||
|
||
A special situation is when a patch changing the API may need to be uplifted to an earlier
|
||
branch of mozilla-central, for example, to the beta channel. To do this, follow the usual uplift
|
||
steps and make a version of the patch for uplift that is graphed onto the new target branch and
|
||
rerun the API linter commands and update the CHANGELOG to the release it will be graphed onto.
|
||
|
||
Creating JavaDoc Locally
|
||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||
GeckoView is a public API, so well maintained javadoc is an important practice. To create the
|
||
javadoc locally, we use the following command:
|
||
|
||
.. code:: bash
|
||
|
||
./mach android geckoview-docs
|
||
|
||
|
||
To view the javadoc locally, first find the directory:
|
||
|
||
- In your ``mozilla-unified`` directory, type the following command:
|
||
|
||
.. code:: bash
|
||
|
||
find . -name javadoc -path '*/geckoview/*'
|
||
|
||
This should return the relative path of the local geckoview javadoc.
|
||
|
||
As an example, the output could be this:
|
||
|
||
.. code:: bash
|
||
|
||
./obj-aarch64-unknown-linux-android/gradle/build/mobile/android/geckoview/docs/javadoc
|
||
|
||
Then, use the following command to go into the directory of the local javadoc:
|
||
|
||
.. code:: bash
|
||
|
||
cd path_of_javadoc_from_above
|
||
|
||
Now, we want to launch a local web server. To launch locally, use any web server, for example:
|
||
|
||
.. code:: bash
|
||
|
||
python3 -m http.server 8000
|
||
|
||
|
||
In this example, navigate to the web docs via ``http://localhost:8000/``.
|
||
|
||
.. note::
|
||
If you get a 404 error, please ensure that you have navigated to the correct directory and try
|
||
launching the web server again.
|
||
|
||
Then, look for the changed method in the list displayed on the webpage and click into it.
|
||
|
||
For using this to identify URLs for the `CHANGELOG`, copy everything after ``.../org/mozilla/geckoview/``.
|
||
Fill in the entry by doing ``{{javadoc_uri}}/<paste_the_copied_text>``. See the example above
|
||
for reference.
|
||
|
||
Deprecation Policy
|
||
~~~~~~~~~~~~~~~~~~~
|
||
GeckoView follows a deprecation policy you can learn more in this
|
||
`design doc <https://icecat-source-docs.mozilla.org/mobile/android/geckoview/design/breaking-changes.html>`_.
|
||
|
||
To deprecate an API, add the deprecation flags with an identifier for a
|
||
deprecation notice, so that all notices with the same identifier will
|
||
be removed at the same time (see below for an example). The version is the major version of when
|
||
we expect to remove the deprecated member attached to the annotation.
|
||
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.
|
||
|
||
::
|
||
|
||
@Deprecated
|
||
@DeprecationSchedule(id = "<interface_or_class_of_method>-<method_name>", version = <Current Nightly + 3>)
|
||
|
||
Since this is a public API, the changelog must also be updated. Please ensure that you
|
||
follow the correct format for changelog entries. Under the heading for
|
||
the next release version, add a new entry for the changes that you are
|
||
making to the API, along with links to any relevant files, and bug
|
||
number.
|
||
|
||
- **Example for Deprecating a Method Changelog**
|
||
|
||
::
|
||
|
||
- ⚠️ Deprecated [`GeckoSession.ContentDelegate.onProductUrl`][128.5], will now be removed in v131.
|
||
([bug 1898055]({{bugzilla}}1898055))
|
||
|
||
[128.5]: {{javadoc_uri}}/GeckoSession.ContentDelegate.html#onProductUrl(org.mozilla.geckoview.GeckoSession)
|
||
|
||
If an API is deprecated, file a follow-up bug or leave the bug open by
|
||
adding the keyword `leave-open` to remove and clean up the deprecated
|
||
API for the version it is to be removed on. Also, ensure that running the API linter commands
|
||
has changed the javadoc of the deprecated method to indicate that the method has been scheduled
|
||
for deprecation. If not, ensure to do this manually.
|
||
|
||
Submitting to the ``try`` server
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
It is advisable to run your tests before submitting your patch. You can
|
||
do this using Mozilla’s ``try`` server. To submit a GeckoView patch to
|
||
``try`` before submitting it for review, type:
|
||
|
||
.. code:: bash
|
||
|
||
./mach try --preset android-geckoview
|
||
|
||
This will automatically run critical tests from the GeckoView test suite. If your patch
|
||
passes on ``try`` you can be (fairly) confident that it will land successfully
|
||
after review.
|
||
|
||
Failures on ``try`` will show up with the test name highlighted in orange. Select the test to find out more.
|
||
Intermittent failures occasionally occur due to issues with the test harness. Retriggering the test is a good way
|
||
to confirm it is an intermittent failure and not due to the patch. Usually there will also be a bug number with
|
||
a portion of the stack trace as well for documented intermittent failures.
|
||
See `Intermittent Test Failures </devtools/tests/debugging-intermittents.html>`_ for more information.
|
||
|
||
To debug failures on try, it is always a good idea to check the logcat. To do this, select the individual test,
|
||
select "Artifacts and Debugging" and then open the log from "logcat-emulator-5554.log".
|
||
|
||
Tagging a reviewer
|
||
~~~~~~~~~~~~~~~~~~
|
||
|
||
When submitting a patch to Phabricator, if you know who you want to
|
||
review your patch, put their Phabricator handle against the
|
||
``reviewers`` field.
|
||
|
||
If you don’t know who to tag for a review in the Phabricator submission
|
||
message, leave the field blank and, after submission, follow the link to
|
||
the patch in Phabricator and scroll to the bottom of the screen until
|
||
you see the comment box.
|
||
|
||
- Select the ``Add Action`` drop down and pick the ``Change Reviewers`` option.
|
||
- In the presented box, add ``geckoview-reviewers``. Selecting this group as the reviewer will notify all the members of the GeckoView team there is a patch to review.
|
||
- Click ``Submit`` to submit the reviewer change request.
|
||
|
||
|
||
GeckoView, Android Components, Fenix, Focus, and Reference Browser Dependency Substitution
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
Internal product dependency substitution is handled automatically in mozilla-central on full builds. When building, the substitution
|
||
into these other products will happen automatically after `./mach build` is ran. However, in artifact builds, changes in
|
||
Gecko or GeckoView will not consistently be reflected. If making changes to Gecko or GeckoView, it is **strongly** recommended
|
||
to only use full builds as changes in Gecko or GeckoView may not be reflected when using artifact builds.
|
||
|
||
Include GeckoView as a dependency
|
||
---------------------------------
|
||
|
||
If you want to include a development version of GeckoView as a
|
||
dependency inside another app, you must link to a local copy. There are
|
||
several ways to achieve this, but the preferred way is to use Gradle’s
|
||
*dependency substitution* mechanism, for which there is first-class
|
||
support in ``mozilla-central`` and a pattern throughout Mozilla’s
|
||
GeckoView-consuming ecosystem.
|
||
|
||
The good news is that ``mach build`` produces everything you need, so
|
||
that after the configuration below, you should find that the following
|
||
commands rebuild your local GeckoView and then consume your local
|
||
version in the downstream project.
|
||
|
||
.. code:: sh
|
||
|
||
cd /path/to/mozilla-central && ./mach build
|
||
cd /path/to/project && ./gradlew assembleDebug
|
||
|
||
**Be sure that your ``mozconfig`` specifies the correct ``--target``
|
||
argument for your target device.** Many projects use “ABI splitting” to
|
||
include only the target device’s native code libraries in APKs deployed
|
||
to the device. On x86-64 and aarch64 devices, this can result in
|
||
GeckoView failing to find any libraries, because valid x86 and ARM
|
||
libraries were not included in a deployed APK. Avoid this by setting
|
||
``--target`` to the exact ABI that your device supports.
|
||
|
||
Dependency substituting your local GeckoView into a non-Mozilla project
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
In projects that don’t have first-class support for dependency
|
||
substitution already, you can do the substitution yourself. See the
|
||
documentation in
|
||
`substitue-local-geckoview.gradle <https://hg.mozilla.org/mozilla-central/file/tip/substitute-local-geckoview.gradle>`_,
|
||
but roughly: in each Gradle project that consumes GeckoView, i.e., in
|
||
each ``build.gradle`` with a
|
||
``dependencies { ... 'org.mozilla.geckoview:geckoview-...' }`` block,
|
||
include lines like:
|
||
|
||
.. code:: groovy
|
||
|
||
ext.topsrcdir = "/path/to/mozilla-central"
|
||
ext.topobjdir = "/path/to/object-directory" // Optional.
|
||
apply from: "${topsrcdir}/substitute-local-geckoview.gradle"
|
||
|
||
**Remember to remove the lines from all ``build.gradle`` files when you
|
||
want to return to using the published GeckoView builds!**
|
||
|
||
Next Steps
|
||
----------
|
||
|
||
- Get started with `Native Debugging for Android <native-debugging.html>`_
|
||
|
||
.. |alt text| image:: ../assets/DisableInstantRun.png
|
||
.. |alt text 1| image:: ../assets/GeckoViewStructure.png
|