Browser Startup
Invoking your code on browser startup
The first rule of running code during startup is: don’t.
We take performance very seriously and ideally your component/feature should initialize only when needed.
If you have established that you really must run code during startup, available entrypoints are:
registering a
browser-idle-startup
category entry for your JS module (or even a “best effort” user idle task, seeBrowserGlue.sys.mjs
)registering a
browser-window-delayed-startup
category entry for your JS module. Note that this is invoked for each browser window.registering a
browser-before-ui-startup
category entry if you really really need to. This will run code before the first browser window appears on the screen and make Firefox seem slow, so please don’t do it unless absolutely necessary.
See the category manager indirection docs for more details on this.
Other useful points in startup are:
BrowserGlue
’s_onFirstWindowLoaded
(which should be converted to use a category manager call instead), which fires after the first browser window’sbrowser-window-delayed-startup
call (see above).BrowserGlue
’s_scheduleBestEffortUserIdleTasks
as mentioned above. Note that in this case, your code may not run at all if the browser is shut down quickly.BrowserGlue
’s_onWindowsRestored
, and/or the observer service’ssessionstore-windows-restored
topic, and/or a category manager call that should replace theBrowserGlue
list of direct calls. This fires after session restore has completed restoring all windows (but before all pages that may have been restored have necessarily loaded). Note that this is guaranteed to fire even if automatic session restore is not enabled.
How do first run/first startup experiments work?
Why does synchronously reading Nimbus feature values work for
customizing display features like about:welcome
onboarding and the
default browser prompt? The key invariant is that the display
decisions wait for sessionstore-windows-restored
to show
customizable UI, and therefore we just need Nimbus available to read
at that point. This is arranged either via the --first-startup
flag; or, for subsequent startups, the relevant Nimbus features being
marked isEarlyStartup: true
. When isEarlyStartup: true
, Nimbus
caches all its feature variables as Gecko preferences, ready to be
read during early startup. (See the early startup
docs.)
Customizable display features like about:welcome
or the default
browser prompt are used in
_maybeShowDefaultBrowserPrompt()
,
which is invoked as part of a startup idle task. Startup idle tasks
are scheduled in response to
sessionstore-windows-restored
.
Now, why is sessionstore-windows-restored
late enough for a
first startup experiment? The answer is subtle.
During Firefox launch, final-ui-startup
is
notified,
and in response SessionStore
is initialized. Additionally,
Nimbus/Normandy initialization is started but not
awaited.
Then the command line is
handled.
When --first-startup
is passed, we spin the event loop to allow
Nimbus/Normandy time to complete its initialization and first
fetch
before continuing to process the command line. See the
FirstStartup
module.
(Important caveat: --first-startup
is only used on Windows; see Bug
1872934, for
example.)
This races with SessionStore
, which itself waits for the first
browser window to be shown – in particular, the
sessionstore-windows-restored
notification waits for the first
browser window’s browser-delayed-startup-finished
notification.
This first browser-delayed-startup-finished
notification is not
guaranteed to be after --first-startup
has spun the event loop!
But, when launched with only --first-startup
and flags considered
very early in nsAppRunner.cpp
– as the stub installer
does
– then the first window is guaranteed to be after the event loop
has been spun, and therefore sessionstore-windows-restored
is after
as well. (As a counter-example: try firefox.exe --browser --first-startup
and witness the --browser
flag
creating a window before spinning the event loop, inadvertently racing
against sessionstore-windows-restored
.) Making this deterministic
is tracked by Bug
1944431.
Together, this means that first-startup experiments will be loaded in
time to impact display features such as about:welcome
and the
default browser prompt, and we should not have a “split brain”
scenario in which the Nimbus feature is intermittently unavailable to
the relevant display features.