Shutting down Firefox for Android¶
Background¶
Normally, apps on Android don’t need to provide any support for explicit quitting, instead they are just sent into the background where they eventually get killed by the OS’s low-memory killer.
Nevertheless, Firefox on Android allows explicit quitting to support the use case of users wanting to clear part or all of their private data after finishing a browsing session. When this option to “Clear private data on exit” is activated from the settings, a “Quit” button is provided in the menu.
Because Firefox on Android uses a native UI (written in Java), which also holds some of the user’s browsing data, this creates some additional complications when compared to quitting on desktop.
Technical details¶
When the “Quit” button is used, the UI sends a Browser:Quit
notification to Gecko’s BrowserApp
,
which initiates the normal Gecko shutdown procedure. At the same time however, the native UI needs to
shutdown as well, so as to
- provide an immediate visual feedback to the user that Firefox is indeed quitting
- avoid a state where the UI is still running “normally” while the rendering engine is already shutting down, which could lead to loosing incoming external tabs if they were to arrive within that period.
Therefore, shutdown of the native UI was originally started simultaneously with notifying Gecko.
Because the clearing of private data during shutdown is handled by Gecko’s Sanitizer
, while some
private data, e.g. the browsing history, is held in a database by the native UI, this means that
Gecko needs to message the native UI during shutdown if the user wants the browsing history to be
cleared on quitting.
Shutting down the UI simultaneously with Gecko therefore introduced a race condition where the data
clearing could fail because the native UI thread responsible for receiving Gecko’s sanitization
messages had already exited by the time Gecko’s Sanitizer
was attempting to e.g. clear the
user’s browsing history (for further reading, compare bug 1266594).
To fix this issue, the native UI (in GeckoApp
) now waits for the Sanitizer
to run and
message all necessary sanitization handlers and only starts its shutdown after receiving a
Sanitize:Finished
message with a shutdown: true
parameter set. While this introduces a
certain delay in closing the UI, it is still faster than having to wait for Gecko to exit completely
before starting to close the UI.
Currently, quitting Firefox therefore proceeds roughly as follows:
- The user presses the “Quit” button in the main menu, which sends a
Browser:Quit
notification toBrowserApp
. This notification also contains additional parameters indicating which types of private user data - if any - to clear during shutdown. BrowserApp.quit
runs, which initiates Gecko shutdown by sending out aquit-application-requested
notification.- If nobody cancelled shutdown in response to the
quit-application-requested
notification, quitting proceeds and theSessionStore
enters shutdown mode (STATE_QUITTING
), which basically means that no new (asynchronous) writes are started to prevent any interference with the final flushing of data. BrowserApp
calls theSanitizer
to clear up any private user data that might need cleaning. After theSanitizer
has invoked all required sanitization handlers (including any on the native Java UI side, e.g. for the browsing history) and finished running, it sends aSanitize:Finished
message back to the native UI.- On receiving the
Sanitize:Finished
message,GeckoApp
starts the shutdown of the native UI as well by callingdoShutdown()
. - After sending the
Sanitize:Finished
message, Gecko’sSanitizer
runs the callback provided byBrowserApp.quit
, which isappStartup.quit(Ci.nsIAppStartup.eForceQuit)
, thereby starting the actual and final shutting down of Gecko. - On receiving the final
quit-application
notification, theSessionStore
synchronously writes its current state to disk.