diff options
Diffstat (limited to 'mobile/android/docs/geckoview/contributor/native-debugging.rst')
-rw-r--r-- | mobile/android/docs/geckoview/contributor/native-debugging.rst | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/mobile/android/docs/geckoview/contributor/native-debugging.rst b/mobile/android/docs/geckoview/contributor/native-debugging.rst new file mode 100644 index 0000000000..e04872c141 --- /dev/null +++ b/mobile/android/docs/geckoview/contributor/native-debugging.rst @@ -0,0 +1,242 @@ +.. -*- Mode: rst; fill-column: 80; -*- + +===================== +Debugging Native Code +===================== + +Table of contents +================= + +.. contents:: :local: + +Debugging Native Code in Android Studio. +======================================== + +If you want to work on the C++ code that powers GeckoView, you will need +to be able to perform native debugging inside Android Studio. This +article will guide you through how to do that. + +If you need to get set up with GeckoView for the first time, follow the +`Quick Start Guide <geckoview-quick-start.html>`_. + +Perform a debug build of Gecko. +------------------------------- + +1. Edit your ``mozconfig`` file and add the following lines. These will + ensure that the build includes debug checks and symbols. + +.. code:: + + ac_add_options --enable-debug + ac_add_options --with-android-ndk="<path>/.mozbuild/android-ndk-r17b" + +2. Ensure that the following lines are commented out in your + ``mozconfig`` if present. ``./mach configure`` will not allow + artifact builds to be enabled when generating a debug build. + +.. code:: + + # ac_add_options --enable-artifact-builds + +3. To be absolutely sure that Android Studio will pick up your debug + symbols, the first time you perform a debug build it is best to + clobber your ``MOZ_OBJDIR``. Subsequent builds should not need this + step. + +.. code:: bash + + ./mach clobber + +4. Build as usual. Because this is a debug build, and because you have + clobbered your ``MOZ_OBJDIR``, this will take a long time. Subsequent + builds will be incremental and take less time, so go make yourself a + cup of your favourite beverage. + +.. code:: bash + + ./mach build + +Set up lldb to find your symbols +-------------------------------- + +Edit your ``~/.lldbinit`` file (or create one if one does not already +exist) and add the following lines. + +The first line tells LLDB to enable inline breakpoints - Android Studio +will need this if you want to use visual breakpoints. + +The remaining lines tell LLDB where to go to find the symbols for +debugging. + +.. code:: bash + + settings set target.inline-breakpoint-strategy always + settings append target.exec-search-paths <PATH>/objdir-android-opt/toolkit/library/build + settings append target.exec-search-paths <PATH>/objdir-android-opt/mozglue/build + +Set up Android Studio to perform native debugging. +================================================== + +1. Edit the configuration that you want to debug by clicking + ``Run -> Edit Configurations...`` and selecting the correct + configuration from the options on the left hand side of the resulting + window. +2. Select the ``Debugger`` tab. +3. Select ``Dual`` from the ``Debug type`` select box. Dual will allow + debugging of both native and Java code in the same session. It is + possible to use ``Native``, but it will only allow for debugging + native code, and it’s frequently necessary to break in the Java code + that configures Gecko and child processes in order to attach + debuggers at the correct times. +4. Under ``Symbol Directories``, add a new path pointing to + ``<PATH>/objdir-android-opt/toolkit/library/build``, the same path + that you entered into your ``.lldbinit`` file. +5. Select ``Apply`` and ``OK`` to close the window. + +Debug Native code in Android Studio +=================================== + +1. The first time you are running a debug session for your app, it’s + best to start from a completely clean build. Click + ``Build -> Rebuild Project`` to clean and rebuild. You can also + choose to remove any existing builds from your emulator to be + completely sure, but this may not be necessary. +2. If using Android Studio visual breakpoints, set your breakpoints in + your native code. +3. Run the app in debug mode as usual. +4. When debugging Fennec or geckoview_example, you will almost + immediately hit a breakpoint in ``ElfLoader.cpp``. This is expected. + If you are not using Android Studio visual breakpoints, you can set + your breakpoints here using the lldb console that is available now + this breakpoint has been hit. To set a breakpoint, select the app tab + (if running Dual, there will also be an ``<app> java`` tab) from the + debug window, and then select the ``lldb`` console tab. Type the + following into the console: + +.. code:: + + b <file>.cpp:<line number> + +5. Once your breakpoints have been set, click the continue execution + button to move beyond the ``ElfLoader`` breakpoint and your newly set + native breakpoints should be hit. Debug as usual. + +Attaching debuggers to content and other child processes +-------------------------------------------------------- + +Internally, GeckoView has a multi-process architecture. The main Gecko +process lives in the main Android process, but content rendering and +some other functions live in child processes. This balances load, +ensures certain critical security properties, and allows GeckoView to +recover if content processes become unresponsive or crash. However, it’s +generally delicate to debug child processes because they come and go. + +The general approach is to make the Java code in the child process that +you want to debug wait for a Java debugger at startup, and then to +connect such a Java debugger manually from the Android Studio UI. + +`Bug 1522318 <https://bugzilla.mozilla.org/show_bug.cgi?id=1522318>`__ +added environment variables that makes GeckoView wait for Java debuggers +to attach, making this debug process more developer-friendly. See +`Configuring GeckoView for Automation <../consumer/automation.html>`__ +for instructions on how to set environment variables that configure +GeckoView’s runtime environment. + +Making processes wait for a Java debugger +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following environment variable makes the main (Gecko) process wait +for a Java debugger to connect: + +.. code:: shell + + MOZ_DEBUG_WAIT_FOR_JAVA_DEBUGGER=1 + +This is a superset of Android Studio’s built-in debugging support so +it’s not particularly useful (unless you want to attach a different jdwp +debugger). + +The following environment variable makes every child process wait for a +Java debugger to connect: + +.. code:: shell + + MOZ_DEBUG_CHILD_WAIT_FOR_JAVA_DEBUGGER= + +Set ``MOZ_DEBUG_CHILD_WAIT_FOR_JAVA_DEBUGGER=suffix`` in the environment +to make child processes with an Android process name ending with +``suffix`` wait for a Java debugger to connect. For example, the +following environment variable makes every child content process wait +for a Java debugger to connect: + +.. code:: shell + + MOZ_DEBUG_CHILD_WAIT_FOR_JAVA_DEBUGGER=:tab + +An easy way to set this is with ``./mach run``: + +.. code:: shell + + ./mach run --setenv MOZ_DEBUG_CHILD_WAIT_FOR_JAVA_DEBUGGER=:tab + +Attaching a Java debugger to a waiting child process +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is standard: follow the `Android Studio instructions <https://developer.android.com/studio/debug/index.html#attach-debugger>`_. +You must attach a Java debugger, so you almost certainly want to attach +a ``Dual`` debugger and you definitely can’t attach only a ``Native`` +debugger. + +Determining the correct process to attach to is a little tricky because +the mapping from process ID (pid) to process name is not always clear. +Gecko content child processes are suffixed ``:tab`` at this time. + +If you attach ``Dual`` debuggers to both the main process and a content +child process, you will have four (4!) debug tabs to manage in Android +Studio, which is awkward. Android Studio doesn’t appear to configure +attached debuggers in the same way that it configures debuggers +connecting to launched Run Configurations, so you may need to manually +configure search paths – i.e., you may need to invoke the contents of +your ``lldbinit`` file in the appropriate ``lldb`` console by hand, +using an invocation like +``command source /absolute/path/to/topobjdir/lldbinit``. + +Android Studio also doesn’t appear to support targeting breakpoints from +the UI (say, from clicking in a gutter) to specific debug tabs, so you +may also need to set breakpoints in the appropriate ``lldb`` console by +hand. + +Managing more debug tabs may require different approaches. + +Using Android Studio on Windows +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can now use :ref:`artifact builds <Understanding Artifact Builds>` +mode on `MozillaBuild environment <https://wiki.mozilla.org/MozillaBuild>`_ even if you are +not using WSL. If you want to debug GeckoView using Android Studio on +Windows, you have to set an additional environment variable via the +Control Panel to run the gradle script. The ``mach`` command sets these +variables automatically, but Android Studio cannot. + +If you install MozillaBuild tools to ``C:\mozilla-build`` (default +installation path), you have to set the ``MOZILLABUILD`` environment +variable to recognize MozillaBuild installation path. + +To set environment variable on Windows 10, open the ``Control Panel`` +from ``Windows System``, then select ``System and Security`` - +``System`` - ``Advanced system settings`` - +``Environment Variables ...``. + +To set the ``MOZILLABUILD`` variable, click ``New...`` in +``User variables for``, then ``Variable name:`` is ``MOZILLABUILD`` and +``Variable value:`` is ``C:\mozilla-build``. + +You also have to append some tool paths to the ``Path`` environment +variable. + +To append the variables to PATH, double click ``Path`` in +``User Variables for``, then click ``New``. And append the following +variables to ``Path``. + +- ``%MOZILLABUILD%\msys\bin`` +- ``%MOZILLABUILD%\bin`` |