tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

processes.rst (65206B)


      1 Gecko Processes
      2 ===============
      3 
      4 Before Creating a New Process
      5 -----------------------------
      6 
      7 Firefox started out as a one process application.  Then, one became two as
      8 NPAPI plugins like Flash were pushed into their own process (plugin processes)
      9 for security and stability reasons.  Then, it split again so that the browser
     10 could also disentangle itself from web content (content processes).  Then,
     11 implementations on some platforms developed processes for graphics ("GPU"
     12 processes).  And for media codecs.  And VR.  And file URLs.  And sockets.  And
     13 even more content processes.  And so on...
     14 
     15 Here is an incomplete list of *good* reasons we've created new processes:
     16 
     17 * Separating HTML and JS from the browser makes it possible to secure the
     18  browser and the rest of the system from them, even when those APIs are
     19  compromised.
     20 * Browser stability was also improved by separating HTML and JS from the
     21  browser, since catastrophic failures related to a tab could be limited to the
     22  tab instead of crashing the browser.
     23 * Site isolation requires additional processes to separate HTML and JS for
     24  different sites.  The separation of memory spaces undermines many types of
     25  exploits.
     26 * Sandboxing processes offers great security guarantees but requires making
     27  tradeoffs between power and protection.  More processes means more options.
     28  For example, we heavily sandbox content processes to protect from external
     29  code, while the File process, which is a content process that can access
     30  ``file://`` URLs, has a sandbox that is similar but allows access to local
     31  files.
     32 * One of the benefits of the GPU process was that it improved browser
     33  stability by separating a system component that had frequent stability
     34  issues -- GPU drivers.  The same logic inspired the NPAPI (Flash) plugin
     35  process.
     36 
     37 Informed by this history, there is some of non-obvious preparation that you
     38 should do before starting down this path.  This falls under the category of
     39 "First, do no harm":
     40 
     41 * **Consult the Platform and IPC teams** (#ipc) to develop the plan for the
     42  way your process will integrate with the systems in which it will exist, as
     43  well as how it will be handled on any platforms where it will *not* exist.
     44  For example, an application's process hierarchy forms a tree where one process
     45  spawns another.  Currently, all processes in Firefox are spawned by the main
     46  process (excepting the `launcher process`_).  There is good reason for this,
     47  mostly based on our sandboxing restrictions that forbid non-main processes
     48  from launching new processes themselves.  But it means that the main process
     49  will need to know to create your process.  If you make the decision to do
     50  this from, say, a content process, you will need a safe, performant and
     51  stable way to request this of the main process.  You will also need a way to
     52  efficiently communicate directly with your new process.  And you will need to
     53  consider limitations of some platforms (think Android) where you may not want
     54  to or not be able to spawn the new process.
     55 * **Consult the sandboxing team** (#hardening) to discuss what the sandbox for
     56  your new process will look like.  Anything that compromises security is a
     57  non-starter.  You may, for instance, want to create a new process to escape
     58  the confines of the sandbox in a content process.  This can be legitimate,
     59  for example you may need access to some device API that is unavailable to a
     60  content process, but the security for your new process will then have to come
     61  from a different source.  "I won't run Javascript" is not sufficient.  Keep
     62  in mind that your process will have to have some mechanism for communication
     63  with other processes to be useful, so it is always a potential target.
     64 
     65 .. note::
     66    Firefox has, to date, undergone exactly one occurrence of the *removal* of
     67    a process type.  In 2020, the NPAPI plugin process was removed when the
     68    last supported plugin, Adobe's FlashPlayer, reached its end-of-life.
     69 
     70 .. _launcher process: https://wiki.mozilla.org/Platform/Integration/InjectEject/Launcher_Process/
     71 
     72 Firefox Process Hierarchy
     73 -------------------------
     74 
     75 This diagram shows the primary process types in Firefox.
     76 
     77 .. mermaid::
     78 
     79    graph TD
     80        RDD -->|PRemoteMediaManager| Content
     81        RDD(Data Decoder) ==>|PRDD| Main
     82 
     83        Launcher --> Main
     84 
     85        Main ==>|PContent| Content
     86        Main ==>|PSocketProcess| Socket(Network Socket)
     87        Main ==>|PGMP| GMP(Gecko Media Plugins)
     88        VR ==>|PVR| Main
     89        GPU ==>|PGPU| Main
     90 
     91        Socket -->|PSocketProcessBridge| Content
     92 
     93        GPU -->|PCompositorManager| Main
     94        GPU -->|PCompositorManager| Content
     95 
     96        Content -->|PGMPContent| GMP
     97 
     98        VR -->|PVRGPU| GPU
     99 
    100 .. warning::
    101    The main process is sometimes called the UI process, the chrome process,
    102    the browser process or the parent process.  This is true for documentation,
    103    conversation and, most significantly, **code**.  Due to the syntactic
    104    overlap with IPDL actors, that last name can get pretty confusing.  Less
    105    commonly, the content process is called the renderer process, which is it's
    106    name in Chromium code.  Since the content process sandbox won't allow it,
    107    Firefox never does (hardware) rendering in the content/rendering process!
    108 
    109 The arrows point from the parent side to the child.  Bolded arrows indicate the
    110 first top-level actors for the various process types.  The other arrows show
    111 important actors that are usually the first connections established between the
    112 two processes.  These relationships difficult to discern from code.  Processes
    113 should clearly document their top-level connections in their IPDL files.
    114 
    115 Some process types only exist on some platforms and some processes may only be
    116 created on demand.  For example, Mac builds do not use a GPU process but
    117 instead fold the same actor connections into its main process (except ``PGPU``,
    118 which it does not use).  These exceptions are also very hard to learn from code
    119 and should be clearly documented.
    120 
    121 ``about:processes`` shows statistics for the processes in a currently running
    122 browser.  It is also useful to see the distribution of web pages across content
    123 processes.
    124 
    125 .. _Adding a New Type of Process:
    126 
    127 Adding a New Type of Process
    128 ----------------------------
    129 
    130 Adding a new process type doesn't require any especially difficult steps but it
    131 does require a lot of steps that are not obvious.  This section will focus on
    132 the steps as it builds an example.  It will be light on the details of the
    133 classes and protocols involved.  Some implementations may need to seek out a
    134 deeper understanding of the components set up here but most should instead
    135 strive for simplicity.
    136 
    137 In the spirit of creating a *responsible* process, the sample will connect
    138 several components that any deployed Gecko process is likely to need.  These
    139 include configuring a sandbox, :ref:`registration with the CrashReporter service <Crash Reporter>`
    140 and ("minimal") XPCOM initialization.  Consult documentation for these
    141 components for more information on their integration.
    142 
    143 This example will be loosely based on the old (now defunct) IPDL **Extending a
    144 Protocol** example for adding a new actor.  We will add a command to the
    145 browser's ``navigator`` JS object, ``navigator.getAssistance()``.  When the
    146 user enters the new command in, say, the browser's console window, it will
    147 create a new process of our new **Demo** process type and ask that process for
    148 "assistance" in the form of a string that it will then print to the console.
    149 Once that is done, the new process will be cleanly destroyed.
    150 
    151 Code for the complete demo can be found `here
    152 <https://phabricator.services.mozilla.com/D119038>`_.
    153 
    154 Common Architecture
    155 ~~~~~~~~~~~~~~~~~~~
    156 
    157 Every type of process (besides the launcher and main processes) needs two
    158 classes and an actor pair to launch.  This sample will be adding a process type
    159 we call **Demo**.
    160 
    161 * An actor pair where the parent actor is a top-level actor in the main process
    162  and the child is the (first) top-level actor in the new process.  It is common
    163  for this actor to simply take the name of the process type.  The sample uses
    164  ``PDemo``, so it creates ``DemoParent`` and ``DemoChild`` actor subclasses
    165  as usual (see :ref:`IPDL: Inter-Thread and Inter-Process Message Passing`).
    166 * A subclass of `GeckoChildProcessHost
    167  <https://searchfox.org/mozilla-central/source/ipc/glue/GeckoChildProcessHost.h>`_
    168  that exists in the main process (where new processes are created) and handles
    169  most of the machinery needed for new process creation.  It is common for these
    170  names to be the process type plus ``ProcessParent`` or ``ProcessHost``.  The
    171  sample uses ``DemoParent::Host``, a private class, which keeps
    172  ``GeckoChildProcessHost`` out of the **Demo** process' *public interface*
    173  since it is large, complicated and mostly unimportant externally.  This
    174  complexity is also why it is a bad idea to add extra responsibilities to the
    175  ``Host`` object that inherits it.
    176 * A subclass of `ProcessChild
    177  <https://searchfox.org/mozilla-central/source/ipc/glue/ProcessChild.h>`_ that
    178  exists in the new process.  These names are usually generated by affixing
    179  ``ProcessChild`` or ``ProcessImpl`` to the type.  The sample will use
    180  ``DemoChild::Process``, another private class, for the same reasons it did
    181  with the ``Host``.
    182 
    183 A fifth class is optional but integration with common services requires
    184 something like it:
    185 
    186 * A singleton class that "manages" the collective of processes (usually the
    187  Host objects) of the new type in the main process.  In many instances, there
    188  is at most one instance of a process type, so this becomes a singleton that
    189  manages a singleton... that manages a singleton.  Object ownership is often
    190  hard to establish between manager objects and the hosts they manage.  It is
    191  wise to limit the power of these classes.  This class will often get its name
    192  by appending ``ProcessManager`` to the process type.  The sample provides a
    193  very simple manager in ``DemoParent::Manager``.
    194 
    195 Finally, it is highly probable and usually desirable for the new process to
    196 include another new top-level actor that represents the top-level operations
    197 and communications of the new process.  This actor will use the new process as
    198 a child but may have any other process as the parent, unlike ``PDemo`` whose
    199 parent is always the main process.  This new actor will be created by the main
    200 process, which creates a pair of ``Endpoint`` objects specifically for the
    201 desired process pairing, and then sends those ``Endpoint`` objects to their
    202 respective processes.  The **Demo** example is interesting because the user can
    203 issue the command from a content process or the main one, by opening the
    204 console in a normal or a privileged page (e.g. ``about:sessionrestore``),
    205 respectively.  Supporting both of these cases will involve very little
    206 additional effort.  The sample will show this as part of implementing the
    207 second top-level actor pair ``PDemoHelpline`` in `Connecting With Other
    208 Processes`_, where the parent can be in either the main or a content process.
    209 
    210 The rest of the sections will explain how to compose these classes and
    211 integrate them with Gecko.
    212 
    213 Process Bookkeeping
    214 ~~~~~~~~~~~~~~~~~~~
    215 .. _process-bookkeeping:
    216 
    217 To begin with, look at the `geckoprocesstypes generator
    218 <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/xpcom/geckoprocesstypes_generator/geckoprocesstypes/__init__.py>`_
    219 which adds the bones for a new process (by defining enum values and so on).
    220 Some further manual intervention is still required, and you need to follow the
    221 following checklists depending on your needs.
    222 
    223 Basic requirements
    224 ^^^^^^^^^^^^^^^^^^
    225 
    226 * Add a new entry to the `enum WebIDLProcType
    227  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/dom/chrome-webidl/ChromeUtils.webidl#610-638>`_
    228 * Update the `static_assert
    229  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/toolkit/xre/nsAppRunner.cpp#988-990>`_
    230  call checking for boundary against ``GeckoProcessType_End``
    231 * Add your process to the correct ``MessageLoop::TYPE_x`` in the first
    232  ``switch(XRE_GetProcessType())`` in `XRE_InitChildProcess
    233  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/toolkit/xre/nsEmbedFunctions.cpp#572-590>`_.
    234  You can get more information about that topic in `this comment
    235  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/ipc/chromium/src/base/message_loop.h#159-187>`_
    236 * Instantiate your child within the second ``switch (XRE_GetProcessType())`` in
    237  `XRE_InitChildProcess
    238  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/toolkit/xre/nsEmbedFunctions.cpp#615-671>`_
    239 * Add a new entry ``PROCESS_TYPE_x`` in `nsIXULRuntime interface
    240  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/xpcom/system/nsIXULRuntime.idl#183-196>`_
    241 
    242 Graphics
    243 ########
    244 
    245 If you need graphics-related interaction, hack into `gfxPlatform
    246 <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/gfx/thebes/gfxPlatform.cpp>`_
    247 
    248 - Add a call to your process manager init in ``gfxPlatform::Init()`` in
    249  `gfxPlatform
    250  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/gfx/thebes/gfxPlatform.cpp#808-810>`_
    251 - Add a call to your process manager shutdown in ``gfxPlatform::Shutdown()`` in
    252  `gfxPlatform
    253  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/gfx/thebes/gfxPlatform.cpp#1255-1259>`_
    254 
    255 Android
    256 #######
    257 
    258 You might want to talk with `#geckoview` maintainers to ensure if this is
    259 required or applicable to your new process type.
    260 
    261 - Add a new ``<service>`` entry against
    262  ``org.mozilla.gecko.process.GeckoChildProcessServices$XXX`` in the
    263  `AndroidManifest
    264  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/mobile/android/geckoview/src/main/AndroidManifest.xml#45-81>`_
    265 - Add matching class inheritance from `GeckoChildProcessServices
    266  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoChildProcessServices.jinja#10-13>`_
    267 - Add new entry in `public enum GeckoProcessType
    268  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessType.java#11-23>`_
    269 
    270 Crash reporting
    271 ###############
    272 
    273 - Add ``InitCrashReporter`` message to the parent-side `InitCrashReporter
    274  <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/PUtilityProcess.ipdl#30>`_
    275 - Ensure your parent class inherits `public ipc::CrashReporterHelper<GeckoProcessType_Xxx>
    276  <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/UtilityProcessParent.h#23>`_
    277 - Add new ``Xxx*Status`` `annotations
    278  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/toolkit/crashreporter/CrashAnnotations.yaml#968-971>`_
    279  entry for your new process type description. The link here points to
    280  `UtilityProcessStatus` so you can see the similar description you have to
    281  write, but you might want to respect ordering in that file and put your new
    282  code at the appropriate place.
    283 - Add entry in `PROCESS_CRASH_SUBMIT_ATTEMPT
    284  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/toolkit/components/telemetry/Histograms.json#13403-13422>`_ and
    285  `submit_attempt` in `toolkit/components/crashes/metrics.yaml`.
    286 
    287 Memory reporting
    288 ################
    289 
    290 Throughout the linked code, please consider those methods more as boilerplate code that will require some trivial modification to fit your exact usecase.
    291 
    292 - Add definition of memory reporter to your new :ref:`top-level actor <Top Level Actors>`
    293 
    294  + Type inclusion `MemoryReportTypes <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/PUtilityProcess.ipdl#6>`_
    295  + To parent-side `AddMemoryReport <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/PUtilityProcess.ipdl#32>`_
    296  + To child-side `RequestMemoryReport <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/PUtilityProcess.ipdl#44-48>`_
    297 
    298 - Add handling for your new process within `nsMemoryReporterManager::GetReportsExtended <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/xpcom/base/nsMemoryReporterManager.cpp#1813-1819>`_
    299 - Provide a process manager level abstraction
    300 
    301  + Implement a new class deriving ``MemoryReportingProcess`` such as `UtilityMemoryReporter <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/UtilityProcessManager.cpp#253-292>`_
    302  + Write a `GetProcessMemoryReport <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/UtilityProcessManager.cpp#294-300>`_
    303 
    304 - On the child side, provide an implementation for `RequestMemoryReport <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/UtilityProcessChild.cpp#153-166>`_
    305 - On the parent side
    306 
    307  + Provide an implementation for `RequestMemoryReport <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/UtilityProcessParent.cpp#41-69>`_
    308  + Provide an implementation for `AddMemoryReport <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/UtilityProcessParent.cpp#71-77>`_
    309 
    310 If you want to add a test that ensures proper behavior, you can have a look at the `utility process memory report test <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/test/browser/browser_utility_memoryReport.js>`_
    311 
    312 Process reporting
    313 #################
    314 
    315 Those elements will be used for exposing processes to users in some `about:`
    316 pages. You might want to ping `#fluent-reviewers` to ensure if you need your
    317 process there.
    318 
    319 - Add a `user-facing localizable name
    320  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/toolkit/locales/en-US/toolkit/global/processTypes.ftl#39-57>`_
    321  for your process, if needed
    322 - Hashmap from process type to user-facing string above in `const ProcessType
    323  <https://searchfox.org/mozilla-central/rev/c5c002f81f08a73e04868e0c2bf0eb113f200b03/toolkit/modules/ProcessType.sys.mjs#10-16>`_
    324 - For `about:processes` you will probably want to follow the following steps:
    325 
    326  + Add handling for your new process type producing a unique `fluentName <https://searchfox.org/mozilla-central/rev/be4604e4be8c71b3c1dbff2398a5b05f15411673/toolkit/components/aboutprocesses/content/aboutProcesses.js#472-539>`_, i.e., constructing a dynamic name is highly discouraged
    327  + Add matching localization strings within `about:processes localization file <https://searchfox.org/mozilla-central/rev/be4604e4be8c71b3c1dbff2398a5b05f15411673/toolkit/locales/en-US/toolkit/about/aboutProcesses.ftl#35-55>`_
    328  + Add matching localization strings within `about:support localization file <https://searchfox.org/mozilla-central/source/toolkit/locales/en-US/toolkit/global/processTypes.ftl#54-60>`_
    329 
    330 Profiler
    331 ########
    332 
    333 - Add definition of ``PProfiler`` to your new IPDL
    334 
    335  + Type inclusion `protocol PProfiler <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/PUtilityProcess.ipdl#9>`_
    336  + Child-side `InitProfiler <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/PUtilityProcess.ipdl#42>`_
    337 
    338 - Make sure your initialization path contains a `SendInitProfiler <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/UtilityProcessHost.cpp#222-223>`_. You will want to perform the call once a ``OnChannelConnected`` is issued, thus ensuring your new process is connected to IPC.
    339 - Provide an implementation for `InitProfiler <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/UtilityProcessChild.cpp#147-151>`_
    340 
    341 - You will probably want to make sure your child process code register within the profiler a proper name, otherwise it will default to ``GeckoMain`` ; this can be done by issuing ``profiler_set_process_name(nsCString("XxX"))`` on the child init side.
    342 
    343 Static Components
    344 #################
    345 
    346 The amount of changes required here are significant, `Bug 1740485: Improve
    347 StaticComponents code generation
    348 <https://bugzilla.mozilla.org/show_bug.cgi?id=1740485>`_ tracks improving that.
    349 
    350 - Update allowance in those configuration files to match new process selector
    351  that includes your new process. When exploring those components definitions,
    352  keep in mind that you are looking at updating `processes` field in the
    353  `Classes` object. The `ProcessSelector` value will come from what the reader
    354  writes based on the instructions below. Some of these also contains several
    355  services, so you might have to ensure you have all your bases covered. Some of
    356  the components might not need to be updated as well.
    357 
    358  + `libpref <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/modules/libpref/components.conf>`_
    359  + `telemetry <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/toolkit/components/telemetry/core/components.conf>`_
    360  + `android <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/widget/android/components.conf>`_
    361  + `gtk <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/widget/gtk/components.conf>`_
    362  + `windows <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/widget/windows/components.conf>`_
    363  + `base <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/xpcom/base/components.conf>`_
    364  + `components <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/xpcom/components/components.conf>`_
    365  + `ds <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/xpcom/ds/components.conf>`_
    366  + `threads <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/xpcom/threads/components.conf>`_
    367  + `cocoa kWidgetModule <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/widget/cocoa/nsWidgetFactory.mm#194-202>`_
    368  + `build <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/xpcom/build/components.conf>`_
    369  + `XPCOMinit kXPCOMModule <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/xpcom/build/XPCOMInit.cpp#172-180>`_
    370 
    371 - Within `static components generator
    372  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/xpcom/components/gen_static_components.py>`_
    373 
    374  + Add new definition in ``ProcessSelector`` for your new process
    375    ``ALLOW_IN_x_PROCESS = 0x..``
    376  + Add new process selector masks including your new process definition
    377  + Also add those into the ``PROCESSES`` structure
    378 
    379 - Within `module definition <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/xpcom/components/Module.h>`_
    380 
    381  + Add new definition in ``enum ProcessSelector``
    382  + Add new process selector mask including the new definition
    383  + Update ``kMaxProcessSelector``
    384 
    385 - Within `nsComponentManager <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/xpcom/components/nsComponentManager.cpp>`_
    386 
    387  + Add new selector match in ``ProcessSelectorMatches`` for your new process
    388    (needed?)
    389  + Add new process selector for ``gProcessMatchTable`` in
    390    ``nsComponentManagerImpl::Init()``
    391 
    392 Glean telemetry
    393 ###############
    394 
    395 - Ensure your new IPDL includes on the child side
    396 
    397  + `FlushFOGData
    398    <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/PUtilityProcess.ipdl#55>`_
    399  + `TestTriggerMetrics
    400    <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/PUtilityProcess.ipdl#60>`_
    401 
    402 - Provide a parent-side implementation for `FOGData
    403  <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/UtilityProcessParent.cpp#79-82>`_
    404 - Provide a child-side implementation for `FlushFOGData
    405  <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/UtilityProcessChild.cpp#179-183>`_
    406 - Child-side should flush its FOG data at IPC `ActorDestroy
    407  <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/UtilityProcessChild.cpp#199-201>`_
    408 - Child-side `test metrics
    409  <https://searchfox.org/mozilla-central/rev/fc4d4a8d01b0e50d20c238acbb1739ccab317ebc/ipc/glue/UtilityProcessChild.cpp#185-191>`_
    410 - Within `FOGIPC
    411  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/toolkit/components/glean/ipc/FOGIPC.cpp>`_
    412 
    413  + Add handling of your new process type within ``FlushAllChildData()`` `here
    414    <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/toolkit/components/glean/ipc/FOGIPC.cpp#106-121>`_
    415    and ``SendFOGData()`` `here
    416    <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/toolkit/components/glean/ipc/FOGIPC.cpp#165-182>`_
    417  + Add support for sending test metrics in ``TestTriggerMetrics()`` `here
    418    <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/toolkit/components/glean/ipc/FOGIPC.cpp#208-232>`_
    419 
    420 - Handle process shutdown in ``register_process_shutdown()`` of `glean
    421  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/toolkit/components/glean/api/src/ipc.rs>`_
    422 
    423 Third-Party Modules
    424 ###################
    425 
    426 - Ensure your new IPDL includes on the child side
    427 
    428  + `GetUntrustedModulesData
    429    <https://searchfox.org/mozilla-central/rev/2ce39261ea6a69e49d87f76a119494b2a7a7e42a/ipc/glue/PUtilityProcess.ipdl#106>`_
    430  + `UnblockUntrustedModulesThread
    431    <https://searchfox.org/mozilla-central/rev/2ce39261ea6a69e49d87f76a119494b2a7a7e42a/ipc/glue/PUtilityProcess.ipdl#113>`_
    432 
    433 - Provide a parent side implementation for both
    434 
    435 - Add handling of your new process type in ``MultiGetUntrustedModulesData::GetUntrustedModuleLoadEvents()`` `here <https://searchfox.org/mozilla-central/rev/2ce39261ea6a69e49d87f76a119494b2a7a7e42a/toolkit/components/telemetry/other/UntrustedModules.cpp#145-151>`_
    436 
    437 - `Update your IPDL <https://searchfox.org/mozilla-central/rev/2ce39261ea6a69e49d87f76a119494b2a7a7e42a/ipc/glue/PUtilityProcess.ipdl#75>`_ and make sure your ``Init()`` can receive a boolean for
    438  ``isReadyForBackgroundProcessing`` `like here <https://searchfox.org/mozilla-central/rev/2ce39261ea6a69e49d87f76a119494b2a7a7e42a/ipc/glue/UtilityProcessChild.cpp#157-160>`_, then within the child's ``RecvInit()``
    439  make sure a call to ``DllServices``'s ``StartUntrustedModulesProcessor()`` `is
    440  performed <https://searchfox.org/mozilla-central/rev/2ce39261ea6a69e49d87f76a119494b2a7a7e42a/ipc/glue/UtilityProcessChild.cpp#185-186>`_.
    441 
    442 - Ensure your new IPDL includes for the parent side
    443 
    444  + `GetModulesTrust <https://searchfox.org/mozilla-central/rev/2ce39261ea6a69e49d87f76a119494b2a7a7e42a/ipc/glue/PUtilityProcess.ipdl#60-61>`_
    445 
    446 - Provide an implementation on the `parent side <https://searchfox.org/mozilla-central/rev/2ce39261ea6a69e49d87f76a119494b2a7a7e42a/ipc/glue/UtilityProcessParent.cpp#69-81>`_
    447 
    448 - Expose your new process type as supported in ``UntrustedModulesProcessor::IsSupportedProcessType()`` `like others <https://searchfox.org/mozilla-central/rev/2ce39261ea6a69e49d87f76a119494b2a7a7e42a/toolkit/xre/dllservices/UntrustedModulesProcessor.cpp#76-91>`_
    449 
    450 - Update ``UntrustedModulesProcessor::SendGetModulesTrust()`` to call `your new child process <https://searchfox.org/mozilla-central/rev/2ce39261ea6a69e49d87f76a119494b2a7a7e42a/toolkit/xre/dllservices/UntrustedModulesProcessor.cpp#757-761>`_
    451 
    452 Sandboxing
    453 ##########
    454 
    455 Sandboxing changes related to a new process can be non-trivial, so it is
    456 strongly advised that you reach to the Sandboxing team in ``#hardening`` to
    457 discuss your needs prior to making changes.
    458 
    459 Linux Sandbox
    460 _____________
    461 
    462 Linux sandboxing mostly works by allowing / blocking system calls for child
    463 process and redirecting (brokering) some from the child to the parent. Rules
    464 are written in a specific DSL: `BPF
    465 <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl.h#21-72>`_.
    466 
    467 - Add new ``SetXXXSandbox()`` function within `linux sandbox
    468  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/linux/Sandbox.cpp#719-748>`_
    469 - Within `sandbox filter
    470  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/linux/SandboxFilter.cpp>`_
    471 
    472  + Add new helper ``GetXXXSandboxPolicy()`` `like this one
    473    <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/linux/SandboxFilter.cpp#2036-2040>`_
    474    called by ``SetXXXSandbox()``
    475  + Derive new class `similar to this
    476    <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/linux/SandboxFilter.cpp#2000-2034>`_
    477    inheriting ``SandboxPolicyCommon`` or ``SandboxPolicyBase`` and defining
    478    the sandboxing policy
    479 
    480 - Add new ``SandboxBrokerPolicyFactory::GetXXXProcessPolicy()`` in `sandbox
    481  broker
    482  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/linux/broker/SandboxBrokerPolicyFactory.cpp#881-932>`_
    483 - Add new case handling in ``GetEffectiveSandboxLevel()`` in `sandbox launch
    484  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/linux/launch/SandboxLaunch.cpp#243-271>`_
    485 - Add new entry in ``enum class ProcType`` of `sandbox reporter header
    486  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/linux/reporter/SandboxReporterCommon.h#32-39>`_
    487 - Add new case handling in ``SubmitToTelemetry()`` in `sandbox reporter
    488  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/linux/reporter/SandboxReporter.cpp#131-152>`_
    489 - Add new case handling in ``SandboxReportWrapper::GetProcType()`` of `sandbox
    490  reporter wrapper
    491  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/linux/reporter/SandboxReporterWrappers.cpp#69-91>`_
    492 
    493 MacOS Sandbox
    494 _____________
    495 
    496 - Add new case handling in ``GeckoChildProcessHost::StartMacSandbox()`` of
    497  `GeckoChildProcessHost <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/ipc/glue/GeckoChildProcessHost.cpp#1720-1743>`_
    498 - Add new entry in ``enum MacSandboxType`` defined in `macOS sandbox header
    499  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/mac/Sandbox.h#12-20>`_
    500 - Within `macOS sandbox core
    501  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/mac/Sandbox.mm>`_
    502  handle the new ``MacSandboxType`` in
    503 
    504   + ``MacSandboxInfo::AppendAsParams()`` in the `switch statement
    505     <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/mac/Sandbox.mm#164-188>`_
    506   + ``StartMacSandbox()`` in the `series of if/else statements
    507     <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/mac/Sandbox.mm#286-436>`_.
    508     This code sets template values for the sandbox string rendering, and is
    509     running on the side of the main process.
    510   + ``StartMacSandboxIfEnabled()`` in this `switch statement
    511     <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/mac/Sandbox.mm#753-782>`_.
    512     You might also need a ``GetXXXSandboxParamsFromArgs()`` that performs CLI
    513     parsing on behalf of ``StartMacSandbox()``.
    514 
    515 - Create the new sandbox definition file
    516  ``security/sandbox/mac/SandboxPolicy<XXX>.h`` for your new process ``<XXX>``,
    517  and make it exposed in the ``EXPORTS.mozilla`` section of `moz.build
    518  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/mac/moz.build#7-13>`_.
    519  Those rules follows a specific Scheme-like language. You can learn more about
    520  it in `Apple Sandbox Guide
    521  <https://reverse.put.as/wp-content/uploads/2011/09/Apple-Sandbox-Guide-v1.0.pdf>`_
    522  as well as on your system within ``/System/Library/Sandbox/Profiles/``.
    523 
    524 Windows Sandbox
    525 _______________
    526 
    527 - Introduce a new ``SandboxBroker::SetSecurityLevelForXXXProcess()`` that
    528  defines the new sandbox in the sandbox broker basing yourself on this
    529  `example <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp#1241-1344>`_
    530 
    531 - Add new case handling in ``WindowsProcessLauncher::DoSetup()`` calling
    532  ``SandboxBroker::SetSecurityLevelForXXXProcess()`` in `GeckoChildProcessHost
    533  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/ipc/glue/GeckoChildProcessHost.cpp#1391-1470>`_.
    534  This will apply actual sandboxing rules to your process.
    535 
    536 Sandbox tests
    537 _____________
    538 
    539 - New process' first top level actor needs to `include PSandboxTesting
    540  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/common/test/PSandboxTesting.ipdl>`_
    541  and implement ``RecvInitSandboxTesting`` `like there
    542  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/ipc/glue/UtilityProcessChild.cpp#165-174>`_.
    543 - Add your new process ``string_name`` in the ``processTypes`` list of `sandbox
    544  tests <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/test/browser_sandbox_test.js#17>`_
    545 - Add a new case in ``SandboxTest::StartTests()`` in `test core
    546  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/common/test/SandboxTest.cpp#100-232>`_
    547  to handle your new process
    548 - Add a new if branch for your new process in ``SandboxTestingChild::Bind()``
    549  in `testing child
    550  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/common/test/SandboxTestingChild.cpp#68-96>`_
    551 - Add a new ``RunTestsXXX`` function for your new process (called by ``Bind()``
    552  above) `similar to that implementation
    553  <https://searchfox.org/mozilla-central/rev/d4b9c457db637fde655592d9e2048939b7ab2854/security/sandbox/common/test/SandboxTestingChildTests.h#333-363>`_
    554 
    555 Creating the New Process
    556 ~~~~~~~~~~~~~~~~~~~~~~~~
    557 
    558 The sample does this in ``DemoParent::LaunchDemoProcess``.  The core
    559 behavior is fairly clear:
    560 
    561 .. code-block:: cpp
    562 
    563    /* static */
    564    bool DemoParent::LaunchDemoProcess(
    565            base::ProcessId aParentPid, LaunchDemoProcessResolver&& aResolver) {
    566        UniqueHost host(new Host(aParentPid, std::move(aResolver)));
    567 
    568        // Prepare "command line" startup args for new process
    569        std::vector<std::string> extraArgs;
    570        if (!host->BuildProcessArgs(&extraArgs)) {
    571          return false;
    572        }
    573 
    574        // Async launch creates a promise that we use below.
    575        if (!host->AsyncLaunch(extraArgs)) {
    576          return false;
    577        }
    578 
    579        host->WhenProcessHandleReady()->Then(
    580          GetCurrentSerialEventTarget(), __func__,
    581          [host = std::move(host)](
    582              const ipc::ProcessHandlePromise::ResolveOrRejectValue&
    583                  aResult) mutable {
    584            if (aResult.IsReject()) {
    585              host->ResolveAsFailure();
    586              return;
    587            }
    588 
    589            auto actor = MakeRefPtr<DemoParent>(std::move(host));
    590            actor->Init();
    591          });
    592    }
    593 
    594 First, it creates an object of our ``GeckoChildProcessHost`` subclass (storing
    595 some stuff for later).  ``GeckoChildProcessHost`` is a base class that
    596 abstracts the system-level operations involved in launching the new process.
    597 It is the most substantive part of the launch procedure.  After its
    598 construction, the code prepares a bunch of strings to pass on the "command
    599 line", which is the only way to pass data to the new process before IPDL is
    600 established.  All new processes will at least include ``-parentBuildId`` for
    601 validating that dynamic libraries are properly versioned, and shared memory for
    602 passing user preferences, which can affect early process behavior.  Finally, it
    603 tells ``GeckoChildProcessHost`` to asynchronously launch the process and run
    604 the given lambda when it has a result.  The lambda creates ``DemoParent`` with
    605 the new host, if successful.
    606 
    607 In this sample, the ``DemoParent`` is owned (in the reference-counting sense)
    608 by IPDL, which is why it doesn't get assigned to anything.  This simplifies the
    609 design dramatically.  IPDL takes ownership when the actor calls ``Bind`` from
    610 the ``Init`` method:
    611 
    612 .. code-block:: cpp
    613 
    614    DemoParent::DemoParent(UniqueHost&& aHost)
    615        : mHost(std::move(aHost)) {}
    616 
    617    DemoParent::Init() {
    618      mHost->TakeInitialEndpoint().Bind(this);
    619      // ...
    620      mHost->MakeBridgeAndResolve();
    621    }
    622 
    623 After the ``Bind`` call, the actor is live and communication with the new
    624 process can begin.  The constructor concludes by initiating the process of
    625 connecting the ``PDemoHelpline`` actors; ``Host::MakeBridgeAndResolve`` will be
    626 covered in `Creating a New Top Level Actor`_.  However, before we get into
    627 that, we should finish defining the lifecycle of the process.  In the next
    628 section we look at launching the new process from the new process' perspective.
    629 
    630 .. warning::
    631    The code could have chosen to create a ``DemoChild`` instead of a
    632    ``DemoParent`` and the choice may seem cosmetic but it has substantial
    633    implications that could affect browser stability.  The most
    634    significant is that the prohibitibition on synchronous IPDL messages going
    635    from parent to child can no longer guarantee freedom from multiprocess
    636    deadlock.
    637 
    638 Initializing the New Process
    639 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    640 
    641 The new process first adopts the **Demo** process type in
    642 ``XRE_InitChildProcess``, where it responds to the **Demo** values we added to
    643 some enums above.  Specifically, we need to choose the type of MessageLoop our
    644 main thread will run (this is discussed later) and we need to create our
    645 ``ProcessChild`` subclass.  This is not an insignificant choice so pay close
    646 attention to the `MessageLoop` options:
    647 
    648 .. code-block:: cpp
    649 
    650    MessageLoop::Type uiLoopType;
    651    switch (XRE_GetProcessType()) {
    652      case GeckoProcessType_Demo:
    653        uiLoopType = MessageLoop::TYPE_MOZILLA_CHILD;  break;
    654      // ...
    655    }
    656 
    657    // ...
    658 
    659    UniquePtr<ProcessChild> process;
    660    switch (XRE_GetProcessType()) {
    661        // ...
    662        case GeckoProcessType_Demo:
    663          process = MakeUnique<DemoChild::Process>(parentPID);
    664          break;
    665    }
    666 
    667 We then need to create our singleton ``DemoChild`` object, which can occur in
    668 the constructor or the ``Process::Init()`` call, which is common.  We store a
    669 strong reference to the actor (as does IPDL) so that we are guaranteed that it
    670 exists as long as the ``ProcessChild`` does -- although the message channel may
    671 be closed.  We will release the reference either when the process is properly
    672 shutting down or when an IPC error closes the channel.
    673 
    674 ``Init`` is given the command line arguments constructed above so it will need
    675 to be overridden to parse them.  It does this, binds our actor by
    676 calling ``Bind`` as was done with the parent, then initializes a bunch of
    677 components that the process expects to use:
    678 
    679 .. code-block:: cpp
    680 
    681    bool DemoChild::Init(int aArgc, char* aArgv[]) {
    682    #if defined(MOZ_SANDBOX) && defined(XP_WIN)
    683      mozilla::SandboxTarget::Instance()->StartSandbox();
    684    #elif defined(__OpenBSD__) && defined(MOZ_SANDBOX)
    685      StartOpenBSDSandbox(GeckoProcessType_Demo);
    686    #endif
    687 
    688      if (!mozilla::ipc::ProcessChild::InitPrefs(aArgc, aArgv)) {
    689        return false;
    690      }
    691 
    692      if (NS_WARN_IF(NS_FAILED(nsThreadManager::get().Init()))) {
    693        return false;
    694      }
    695 
    696      if (NS_WARN_IF(!TakeInitialEndpoint().Bind(this))) {
    697        return false;
    698      }
    699 
    700      // ... initializing components ...
    701 
    702      if (NS_FAILED(NS_InitMinimalXPCOM())) {
    703        return false;
    704      }
    705 
    706      return true;
    707    }
    708 
    709 This is a slimmed down version of the real ``Init`` method.  We see that it
    710 establishes a sandbox (more on this later) and then reads the command line and
    711 preferences that we sent from the main process.  It then initializes the thread
    712 manager, which is required by for the subsequent ``Bind`` call.
    713 
    714 Among the list of components we initialize in the sample code, XPCOM is
    715 special.  XPCOM includes a suite of components, including the component
    716 manager, and is usually required for serious Gecko development.  It is also
    717 heavyweight and should be avoided if possible.  We will leave the details of
    718 XPCOM development to that module but we mention XPCOM configuration that is
    719 special to new processes, namely ``ProcessSelector``.    ``ProcessSelector``
    720 is used to determine what process types have access to what XPCOM components.
    721 By default, a process has access to none.  The code adds enums for selecting
    722 a subset of process types, like
    723 ``ALLOW_IN_GPU_RDD_VR_SOCKET_UTILITY_AND_DEMO_PROCESS``, to the
    724 ``ProcessSelector`` enum in `gen_static_components.py
    725 <https://searchfox.org/mozilla-central/source/xpcom/components/gen_static_components.py>`_
    726 and `Module.h
    727 <https://searchfox.org/mozilla-central/source/xpcom/components/Module.h>`_.
    728 It then updates the selectors in various ``components.conf`` files and
    729 hardcoded spots like ``nsComponentManager.cpp`` to add the **Demo** processes
    730 to the list that can use them.  Some modules are required to bootstrap XPCOM
    731 and will cause it to fail to initialize if they are not permitted.
    732 
    733 At this point, the new process is idle, waiting for messages from the main
    734 process that will start the ``PDemoHelpline`` actor.  We discuss that in
    735 `Creating a New Top Level Actor`_ below but, first, let's look at how the main
    736 and **Demo** processes will handle clean destruction.
    737 
    738 Destroying the New Process
    739 ~~~~~~~~~~~~~~~~~~~~~~~~~~
    740 
    741 Gecko processes have a clean way for clients to request that they shutdown.
    742 Simply calling ``Close()`` on the top level actor at either endpoint will begin
    743 the shutdown procedure (so, ``PDemoParent::Close`` or ``PDemoChild::Close``).
    744 The only other way for a child process to terminate is to crash.  Each of these
    745 three options requires some special handling.
    746 
    747 .. note::
    748    There is no need to consider the case where the parent (main) process
    749    crashed, because the **Demo** process would be quickly terminated by Gecko.
    750 
    751 In cases where ``Close()`` is called, the shutdown procedure is fairly
    752 straightforward.  Once the call completes, the actor is no longer connected to
    753 a channel -- messages will not be sent or received, as is the case with any
    754 normal top-level actor (or any managed actor after calling
    755 ``Send__delete__()``).  In the sample code, we ``Close`` the ``DemoChild``
    756 when some (as yet unwritten) **Demo** process code calls
    757 ``DemoChild::Shutdown``.
    758 
    759 .. code-block:: cpp
    760 
    761    /* static */
    762    void DemoChild::Shutdown() {
    763      if (gDemoChild) {
    764        // Wait for the other end to get everything we sent before shutting down.
    765        // We never want to Close during a message (response) handler, so
    766        // we dispatch a new runnable.
    767        auto dc = gDemoChild;
    768        RefPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
    769            "DemoChild::FinishShutdown",
    770            [dc2 = std::move(gDemoChild)]() { dc2->Close(); });
    771        dc->SendEmptyMessageQueue(
    772            [runnable](bool) { NS_DispatchToMainThread(runnable); },
    773            [runnable](mozilla::ipc::ResponseRejectReason) {
    774              NS_DispatchToMainThread(runnable);
    775            });
    776      }
    777    }
    778 
    779 The comment in the code makes two important points:
    780 
    781 * ``Close`` should never be called from a message handler (e.g. in a
    782  ``RecvFoo`` method).  We schedule it to run later.
    783 * If the ``DemoParent`` hasn't finished handling messages the ``DemoChild``
    784  sent, or vice-versa, those messages will be lost.  For that reason, we have a
    785  trivial sentinel message ``EmptyMessageQueue`` that we simply send and wait
    786  to respond before we ``Close``.  This guarantees that the main process will
    787  have handled all of the messages we sent before it.  Because we know the
    788  details of the ``PDemo`` protocol, we know that this means we won't lose any
    789  important messages this way.  Note that we say "important" messages because
    790  we could still lose messages sent *from* the main process.  For example, a
    791  ``RequestMemoryReport`` message sent by the MemoryReporter could be lost.
    792  The actor would need a more complex shutdown protocol to catch all of these
    793  messages but in our case there would be no point.  A process that is
    794  terminating is probably not going to produce useful memory consumption data.
    795  Those messages can safely be lost.
    796 
    797 `Debugging Process Startup`_ looks at what happens if we omit the
    798 ``EmptyMessageQueue`` message.
    799 
    800 We can also see that, once the ``EmptyMessageQueue`` response is run, we are
    801 releasing ``gDemoChild``, which will result in the termination of the process.
    802 
    803 .. code-block:: cpp
    804 
    805    DemoChild::~DemoChild() {
    806      // ...
    807      XRE_ShutdownChildProcess();
    808    }
    809 
    810 At this point, the ``DemoParent`` in the main process is alerted to the
    811 channel closure because IPDL will call its :ref:`ActorDestroy <Actor Lifetimes
    812 in C++>` method.
    813 
    814 .. code-block:: cpp
    815 
    816    void DemoParent::ActorDestroy(ActorDestroyReason aWhy) {
    817      if (aWhy == AbnormalShutdown) {
    818        GenerateCrashReport(OtherPid());
    819      }
    820      // ...
    821    }
    822 
    823 IPDL then releases its (sole) reference to ``DemoParent`` and the destruction
    824 of the process apparatus is complete.
    825 
    826 The ``ActorDestroy`` code shows how we handle the one remaining shutdown case:
    827 a crash in the **Demo** process.  In this case, IPDL will *detect* the dead
    828 process and free the ``DemoParent`` actor as above, only with an
    829 ``AbnormalShutdown`` reason.  We generate a crash report, which requires crash
    830 reporter integration, but no additional "special" steps need to be taken.
    831 
    832 Creating a New Top Level Actor
    833 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    834 
    835 We now have a framework that creates the new process and connects it to the
    836 main process.  We now want to make another top-level actor but this one will be
    837 responsible for our intended behavior, not just bootstrapping the new process.
    838 Above, we saw that this is started by ``Host::MakeBridgeAndResolve`` after the
    839 ``DemoParent`` connection is established.
    840 
    841 .. code-block:: cpp
    842 
    843    bool DemoParent::Host::MakeBridgeAndResolve() {
    844      ipc::Endpoint<PDemoHelplineParent> parent;
    845      ipc::Endpoint<PDemoHelplineChild> child;
    846 
    847      auto resolveFail = MakeScopeExit([&] { mResolver(Nothing()); });
    848 
    849      // Parent side is first argument (main/content), child is second (demo).
    850      nsresult rv = PDempHelpline::CreateEndpoints(&parent, &child);
    851 
    852      // ...
    853 
    854      if (!mActor->SendCreateDemoHelplineChild(std::move(child))) {
    855        NS_WARNING("Failed to SendCreateDemoHelplineChild");
    856        return false;
    857      }
    858 
    859      resolveFail.release();
    860      mResolver(Some(std::move(parent)));
    861      return true;
    862    }
    863 
    864 Because the operation of launching a process is asynchronous, we have
    865 configured this so that it creates the two endpoints for the new top-level
    866 actors, then we send the child one to the new process and resolve a promise
    867 with the other.  The **Demo** process creates its ``PDemoHelplineChild``
    868 easily:
    869 
    870 .. code-block:: cpp
    871 
    872    mozilla::ipc::IPCResult DemoChild::RecvCreateDemoHelplineChild(
    873        Endpoint<PDemoHelplineChild>&& aEndpoint) {
    874      mDemoHelplineChild = new DemoHelplineChild();
    875      if (!aEndpoint.Bind(mDemoHelplineChild)) {
    876        return IPC_FAIL(this, "Unable to bind DemoHelplineChild");
    877      }
    878      return IPC_OK();
    879    }
    880 
    881 ``MakeProcessAndGetAssistance`` binds the same way:
    882 
    883 .. code-block:: cpp
    884 
    885    RefPtr<DemoHelplineParent> demoHelplineParent = new DemoHelplineParent();
    886    if (!endpoint.Bind(demoHelplineParent)) {
    887      NS_WARNING("Unable to bind DemoHelplineParent");
    888      return false;
    889    }
    890    MOZ_ASSERT(ok);
    891 
    892 However, the parent may be in the main process or in content.  We handle both
    893 cases in the next section.
    894 
    895 .. _Connecting With Other Processes:
    896 
    897 Connecting With Other Processes
    898 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    899 
    900 ``DemoHelplineParent::MakeProcessAndGetAssistance`` is the method that we run
    901 from either the main or the content process and that should kick off the
    902 procedure that will result in sending a string (that we get from a new **Demo**
    903 process) to a DOM promise.  It starts by constructing a different promise --
    904 one like the ``mResolver`` in ``Host::MakeBridgeAndResolve`` in the last
    905 section that produced a ``Maybe<Endpoint<PDemoHelplineParent>>``.  In the main
    906 process, we just make the promise ourselves and call
    907 ``DemoParent::LaunchDemoProcess`` to start the procedure that will result in
    908 it being resolved as already described.  If we are calling from the content
    909 process, we simply write an async ``PContent`` message that calls
    910 ``DemoParent::LaunchDemoProcess`` and use the message handler's promise as
    911 our promise:
    912 
    913 .. code-block:: cpp
    914 
    915    /* static */
    916    bool DemoHelplineParent::MakeProcessAndGetAssistance(
    917        RefPtr<mozilla::dom::Promise> aPromise) {
    918      RefPtr<LaunchDemoProcessPromise> resolver;
    919 
    920      if (XRE_IsContentProcess()) {
    921        auto* contentChild = mozilla::dom::ContentChild::GetSingleton();
    922        MOZ_ASSERT(contentChild);
    923 
    924        resolver = contentChild->SendLaunchDemoProcess();
    925      } else {
    926        MOZ_ASSERT(XRE_IsParentProcess());
    927        auto promise = MakeRefPtr<LaunchDemoProcessPromise::Private>(__func__);
    928        resolver = promise;
    929 
    930        if (!DemoParent::LaunchDemoProcess(
    931                base::GetCurrentProcId(),
    932                [promise = std::move(promise)](
    933                    Maybe<Endpoint<PDemoHelplineParent>>&& aMaybeEndpoint) mutable {
    934                  promise->Resolve(std::move(aMaybeEndpoint), __func__);
    935                })) {
    936          NS_WARNING("Failed to launch Demo process");
    937          resolver->Reject(NS_ERROR_FAILURE);
    938          return false;
    939        }
    940      }
    941 
    942      resolver->Then(
    943          GetMainThreadSerialEventTarget(), __func__,
    944          [aPromise](Maybe<Endpoint<PDemoHelplineParent>>&& maybeEndpoint) mutable {
    945            if (!maybeEndpoint) {
    946              aPromise->MaybeReject(NS_ERROR_FAILURE);
    947              return;
    948            }
    949 
    950            RefPtr<DemoHelplineParent> demoHelplineParent = new DemoHelplineParent();
    951            Endpoint<PDemoHelplineParent> endpoint = maybeEndpoint.extract();
    952            if (!endpoint.Bind(demoHelplineParent)) {
    953              NS_WARNING("Unable to bind DemoHelplineParent");
    954              return false;
    955            }
    956            MOZ_ASSERT(ok);
    957 
    958            // ... communicate with PDemoHelpline and write message to console ...
    959          },
    960          [aPromise](mozilla::ipc::ResponseRejectReason&& aReason) {
    961            aPromise->MaybeReject(NS_ERROR_FAILURE);
    962          });
    963 
    964      return true;
    965    }
    966 
    967    mozilla::ipc::IPCResult ContentParent::RecvLaunchDemoProcess(
    968        LaunchDemoProcessResolver&& aResolver) {
    969      if (!DemoParent::LaunchDemoProcess(OtherPid(),
    970                                          std::move(aResolver))) {
    971        NS_WARNING("Failed to launch Demo process");
    972      }
    973      return IPC_OK();
    974    }
    975 
    976 To summarize, connecting processes always requires endpoints to be constructed
    977 by the main process, even when neither process being connected is the main
    978 process.  It is the only process that creates ``Endpoint`` objects.  From that
    979 point, connecting is just a matter of sending the endpoints to the right
    980 processes, constructing an actor for them, and then calling ``Endpoint::Bind``.
    981 
    982 Completing the Sample
    983 ~~~~~~~~~~~~~~~~~~~~~
    984 
    985 We have covered the main parts needed for the sample.  Now we just need to wire
    986 it all up.  First, we add the new JS command to ``Navigator.webidl`` and
    987 ``Navigator.h``/``Navigator.cpp``:
    988 
    989 .. code-block:: cpp
    990 
    991    partial interface Navigator {
    992      [Throws]
    993      Promise<DOMString> getAssistance();
    994    };
    995 
    996    already_AddRefed<Promise> Navigator::GetAssistance(ErrorResult& aRv) {
    997      if (!mWindow || !mWindow->GetDocShell()) {
    998        aRv.Throw(NS_ERROR_UNEXPECTED);
    999        return nullptr;
   1000      }
   1001 
   1002      RefPtr<Promise> echoPromise = Promise::Create(mWindow->AsGlobal(), aRv);
   1003      if (NS_WARN_IF(aRv.Failed())) {
   1004        return nullptr;
   1005      }
   1006 
   1007      if (!DemoHelplineParent::MakeProcessAndGetAssistance(echoPromise)) {
   1008        aRv.Throw(NS_ERROR_FAILURE);
   1009        return nullptr;
   1010      }
   1011 
   1012      return echoPromise.forget();
   1013    }
   1014 
   1015 Then, we need to add the part that gets the string we use to resolve the
   1016 promise in ``MakeProcessAndGetAssistance`` (or reject it if it hasn't been
   1017 resolved by the time ``ActorDestroy`` is called):
   1018 
   1019 .. code-block:: cpp
   1020 
   1021    using DemoPromise = MozPromise<nsString, nsresult, true>;
   1022 
   1023    /* static */
   1024    bool DemoHelplineParent::MakeProcessAndGetAssistance(
   1025        RefPtr<mozilla::dom::Promise> aPromise) {
   1026 
   1027        // ... construct and connect demoHelplineParent ...
   1028 
   1029        RefPtr<DemoPromise> promise = demoHelplineParent->mPromise.Ensure(__func__);
   1030        promise->Then(
   1031            GetMainThreadSerialEventTarget(), __func__,
   1032            [demoHelplineParent, aPromise](nsString aMessage) mutable {
   1033              aPromise->MaybeResolve(aMessage);
   1034            },
   1035            [demoHelplineParent, aPromise](nsresult aErr) mutable {
   1036              aPromise->MaybeReject(aErr);
   1037            });
   1038 
   1039        if (!demoHelplineParent->SendRequestAssistance()) {
   1040          NS_WARNING("DemoHelplineParent::SendRequestAssistance failed");
   1041        }
   1042    }
   1043 
   1044    mozilla::ipc::IPCResult DemoHelplineParent::RecvAssistance(
   1045        nsString&& aMessage, const AssistanceResolver& aResolver) {
   1046      mPromise.Resolve(aMessage, __func__);
   1047      aResolver(true);
   1048      return IPC_OK();
   1049    }
   1050 
   1051    void DemoHelplineParent::ActorDestroy(ActorDestroyReason aWhy) {
   1052      mPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
   1053    }
   1054 
   1055 The ``DemoHelplineChild`` has to respond to the ``RequestAssistance`` method,
   1056 which it does by returning a string and then calling ``Close`` on itself when
   1057 the string has been received (but we do not call ``Close`` in the ``Recv``
   1058 method!).  We use an async response to the ``GiveAssistance`` message to detect
   1059 that the string was received.  During closing, the actor's ``ActorDestroy``
   1060 method then calls the ``DemoChild::Shutdown`` method we defined in `Destroying
   1061 the New Process`_:
   1062 
   1063 .. code-block:: cpp
   1064 
   1065    mozilla::ipc::IPCResult DemoHelplineChild::RecvRequestAssistance() {
   1066      RefPtr<DemoHelplineChild> me = this;
   1067      RefPtr<nsIRunnable> runnable =
   1068          NS_NewRunnableFunction("DemoHelplineChild::Close", [me]() { me->Close(); });
   1069 
   1070      SendAssistance(
   1071          nsString(HelpMessage()),
   1072          [runnable](bool) { NS_DispatchToMainThread(runnable); },
   1073          [runnable](mozilla::ipc::ResponseRejectReason) {
   1074            NS_DispatchToMainThread(runnable);
   1075          });
   1076 
   1077      return IPC_OK();
   1078    }
   1079 
   1080    void DemoHelplineChild::ActorDestroy(ActorDestroyReason aWhy) {
   1081      DemoChild::Shutdown();
   1082    }
   1083 
   1084 During the **Demo** process lifetime, there are two references to the
   1085 ``DemoHelplineChild``, one from IPDL and one from the ``DemoChild``.  The call
   1086 to ``Close`` releases the one held by IPDL and the other isn't released until
   1087 the ``DemoChild`` is destroyed.
   1088 
   1089 Running the Sample
   1090 ~~~~~~~~~~~~~~~~~~
   1091 
   1092 To run the sample, build and run and open the console.  The new command is
   1093 ``navigator.getAssistance().then(console.log)``.  The message sent by
   1094 ``SendAssistance`` is then logged to the console.  The sample code also
   1095 includes the name of the type of process that was used for the
   1096 ``DemoHelplineParent`` so you can confirm that it works from main and from
   1097 content.
   1098 
   1099 Debugging Process Startup
   1100 -------------------------
   1101 
   1102 Debugging a child process at the start of its life is tricky.  With most
   1103 platforms/toolchains, it is surprisingly difficult to connect a debugger before
   1104 the main routine begins execution.  You may also find that console logging is
   1105 not yet established by the operating system, especially when working with
   1106 sandboxed child processes.  Gecko has some facilities that make this less
   1107 painful.
   1108 
   1109 .. _Debugging with IPDL Logging:
   1110 
   1111 Debugging with IPDL Logging
   1112 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
   1113 
   1114 This is also best seen with an example.  To start, we can create a bug in the
   1115 sample by removing the ``EmptyMessageQueue`` message sent to ``DemoParent``.
   1116 This message was intended to guarantee that the ``DemoParent`` had handled all
   1117 messages sent before it, so we could ``Close`` with the knowledge that we
   1118 didn't miss anything.  This sort of bug can be very difficult to track down
   1119 because it is likely to be intermittent and may manifest more easily on some
   1120 platforms/architectures than others.  To create this bug, replace the
   1121 ``SendEmptyMessageQueue`` call in ``DemoChild::Shutdown``:
   1122 
   1123 .. code-block:: cpp
   1124 
   1125    auto dc = gDemoChild;
   1126    RefPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
   1127        "DemoChild::FinishShutdown",
   1128        [dc2 = std::move(gDemoChild)]() { dc2->Close(); });
   1129    dc->SendEmptyMessageQueue(
   1130        [runnable](bool) { NS_DispatchToMainThread(runnable); },
   1131        [runnable](mozilla::ipc::ResponseRejectReason) {
   1132          NS_DispatchToMainThread(runnable);
   1133        });
   1134 
   1135 with just an (asynchronous) call to ``Close``:
   1136 
   1137 .. code-block:: cpp
   1138 
   1139    NS_DispatchToMainThread(NS_NewRunnableFunction(
   1140        "DemoChild::FinishShutdown",
   1141        [dc = std::move(gDemoChild)]() { dc->Close(); }));
   1142 
   1143 When we run the sample now, everything seems to behave ok but we see messages
   1144 like these in the console: ::
   1145 
   1146    ###!!! [Parent][RunMessage] Error: (msgtype=0x410001,name=PDemo::Msg_InitCrashReporter) Channel closing: too late to send/recv, messages will be lost
   1147 
   1148    [Parent 16672, IPC I/O Parent] WARNING: file c:/mozilla-src/mozilla-unified/ipc/chromium/src/base/process_util_win.cc:167
   1149    [Parent 16672, Main Thread] WARNING: Not resolving response because actor is dead.: file c:/mozilla-src/mozilla-unified/ipc/glue/ProtocolUtils.cpp:931
   1150    [Parent 16672, Main Thread] WARNING: IPDL resolver dropped without being called!: file c:/mozilla-src/mozilla-unified/ipc/glue/ProtocolUtils.cpp:959
   1151 
   1152 We could probably figure out what is happening here from the messages but,
   1153 with more complex protocols, understanding what led to this may not be so easy.
   1154 To begin diagnosing, we can turn on IPC Logging, which was defined in the IPDL
   1155 section on :ref:`Message Logging`.  We just need to set an environment variable
   1156 before starting the browser.  Let's turn it on for all ``PDemo`` and
   1157 ``PDemoHelpline`` actors: ::
   1158 
   1159    MOZ_IPC_MESSAGE_LOG="PDemo,PDemoHelpline"
   1160 
   1161 To underscore what we said above, when logging is active, the change in timing
   1162 makes the error message go away and everything closes properly on a tested
   1163 Windows desktop.  However, the issue remains on a Macbook Pro and the log
   1164 shows the issue rather clearly: ::
   1165 
   1166    [time: 1627075553937959][63096->63085] [PDemoChild] Sending  PDemo::Msg_InitCrashReporter
   1167    [time: 1627075553949441][63085->63096] [PDemoParent] Sending  PDemo::Msg_CreateDemoHelplineChild
   1168    [time: 1627075553950293][63092->63096] [PDemoHelplineParent] Sending  PDemoHelpline::Msg_RequestAssistance
   1169    [time: 1627075553979151][63096<-63085] [PDemoChild] Received  PDemo::Msg_CreateDemoHelplineChild
   1170    [time: 1627075553979433][63096<-63092] [PDemoHelplineChild] Received  PDemoHelpline::Msg_RequestAssistance
   1171    [time: 1627075553979498][63096->63092] [PDemoHelplineChild] Sending  PDemoHelpline::Msg_GiveAssistance
   1172    [time: 1627075553980105][63092<-63096] [PDemoHelplineParent] Received  PDemoHelpline::Msg_GiveAssistance
   1173    [time: 1627075553980181][63092->63096] [PDemoHelplineParent] Sending reply  PDemoHelpline::Reply_GiveAssistance
   1174    [time: 1627075553980449][63096<-63092] [PDemoHelplineChild] Received  PDemoHelpline::Reply_GiveAssistance
   1175    [tab 63092] NOTE: parent actor received `Goodbye' message.  Closing channel.
   1176    [default 63085] NOTE: parent actor received `Goodbye' message.  Closing channel.
   1177    [...]
   1178    ###!!! [Parent][RunMessage] Error: (msgtype=0x420001,name=PDemo::Msg_InitCrashReporter) Channel closing: too late to send/recv, messages will be lost
   1179    [...]
   1180    [default 63085] NOTE: parent actor received `Goodbye' message.  Closing channel.
   1181 
   1182 The imbalance with ``Msg_InitCrashReporter`` is clear.  The message was not
   1183 *Received* before the channel was closed.  Note that the first ``Goodbye`` for
   1184 the main (default) process is for the ``PDemoHelpline`` actor -- in this case,
   1185 its child actor was in a content (tab) process.  The second default process
   1186 ``Goodbye`` is from the **Demo** process, sent when doing ``Close``.  It might
   1187 seem that it should handle the ``Msg_InitCrashReporter`` if it can handle the
   1188 later ``Goodbye`` but this does not happen for safety reasons.
   1189 
   1190 Early Debugging For A New Process
   1191 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   1192 
   1193 Let's assume now that we still don't understand the problem -- maybe we don't
   1194 know that the ``InitCrashReporter`` message is sent internally by the
   1195 ``CrashReporterClient`` we initialized.  Or maybe we're only looking at Windows
   1196 builds.  We decide we'd like to be able to hook a debugger to the new process
   1197 so that we can break on the ``SendInitCrashReporter`` call.  Attaching the
   1198 debugger has to happen fast -- process startup probably completes in under a
   1199 second.  Debugging this is not always easy.
   1200 
   1201 Windows users have options that work with both the Visual Studio and WinDbg
   1202 debuggers.  For Visual Studio users, there is an easy-to-use VS addon called
   1203 the `Child Process Debugging Tool`_ that allows you to connect to *all*
   1204 processes that are launched by a process you are debugging.  So, if the VS
   1205 debugger is connected to the main process, it will automatically connect to the
   1206 new **Demo** process (and every other launched process) at the point that they
   1207 are spawned.  This way, the new process never does anything outside of the
   1208 debugger.  Breakpoints, etc work as expected.  The addon mostly works like a
   1209 toggle and will remain on until it is disabled from the VS menu.
   1210 
   1211 WinDbg users can achieve essentially the same behavior with the `.childdbg`_
   1212 command.  See the docs for details but essentially all there is to know is that
   1213 ``.childdbg 1`` enables it and ``.childdbg 0`` disables it.  You might add it
   1214 to a startup config file (see the WinDbg ``-c`` command line option)
   1215 
   1216 Linux and mac users should reference gdb's ``detach-on-fork``.  The command to
   1217 debug child processes is ``set detach-on-fork off``.  Again, the behavior is
   1218 largely what you would expect -- that all spawned processes are added to the
   1219 current debug session.  The command can be added to ``.gdbinit`` for ease.  At
   1220 the time of this writing, lldb does not support automatically connecting to
   1221 newly spawned processes.
   1222 
   1223 Finally, Linux users can use ``rr`` for time-travel debugging.  See :ref:`Debugging
   1224 Firefox with rr <Debugging Firefox with rr>` for details.
   1225 
   1226 These solutions are not always desirable.  For example, the fact that they hook
   1227 *all* spawned processes can mean that targeting breakpoints to one process
   1228 requires us to manually disconnect many other processes.  In these cases, an
   1229 easier solution may be to use Gecko environment variables that will cause the
   1230 process to sleep for some number of seconds.  During that time, you can find
   1231 the process ID (PID) for the process you want to debug and connect your
   1232 debugger to it.  OS tools like ``ProcessMonitor`` can give you the PID but it
   1233 will also be clearly logged to the console just before the process waits.
   1234 
   1235 Set ``MOZ_DEBUG_CHILD_PROCESS=1`` to turn on process startup pausing.  You can
   1236 also set ``MOZ_DEBUG_CHILD_PAUSE=N`` where N is the number of seconds to sleep.
   1237 The default is 10 seconds on Windows and 30 on other platforms.
   1238 
   1239 Pausing for the debugger is not a panacea.  Since the environmental variables
   1240 are not specific to process type, you will be forced to wait for all of the
   1241 processes Gecko creates before you wait for it to get to yours.  The pauses can
   1242 also end up exposing unknown concurrency bugs in the browser before it even
   1243 gets to your issue, which is good to discover but doesn't fix your bug.  That
   1244 said, any of these strategies would be enough to facilitate easily breaking on
   1245 ``SendInitCrashReporter`` and finding our sender.
   1246 
   1247 .. _Child Process Debugging Tool: https://marketplace.visualstudio.com/items?itemName=vsdbgplat.MicrosoftChildProcessDebuggingPowerTool
   1248 .. _.childdbg: https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/-childdbg--debug-child-processes-