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