Events and notifications
Session Restore reports what it is doing in two ways: DOM events dispatched on a browser window or on a tab, and observer service notifications.
All of the DOM events bubble and none of them is cancelable. SSTabRestored is
a CustomEvent; the rest carry no data.
In the diagrams below, blue pill-shaped boxes are DOM events and rectangular amber boxes are observer notifications.
Restoring a session at startup
A previous session is restored automatically after a restart due to an update or
crash, or with automatic session restore enabled via the “Open previous windows
and tabs” setting (browser.startup.page = 3).
---
config:
flowchart:
wrappingWidth: 400
---
flowchart TD
classDef event fill:#dbeafe,stroke:#1e40af,color:#1a1a1a;
classDef topic fill:#fef3c7,stroke:#92400e,color:#1a1a1a;
init["sessionstore-init-started"]
read["sessionstore-state-read"]
final["sessionstore-state-finalized"]
restoring["sessionstore-restoring-on-startup"]
wRestoring(["SSWindowRestoring"])
wBusy(["SSWindowStateBusy"])
wReady(["SSWindowStateReady"])
wRestored(["SSWindowRestored"])
single["sessionstore-single-window-restored"]
tRestoring(["SSTabRestoring"])
tRestored(["SSTabRestored"])
all["sessionstore-windows-restored"]
perf["sessionstore-finished-restoring-initial-tabs"]
init -->|"session file read"| read
read -->|"session state parsed"| final
final -->|"first window's delayed startup finished"| restoring
restoring -->|"for each window in the session"| wRestoring
wRestoring -->|"immediately after"| wBusy
wBusy -->|"window sized and its tabs created"| wReady
wReady -->|"immediately after"| wRestored
wRestored -->|"immediately after"| single
wBusy -->|"for each tab, concurrently"| tRestoring
tRestoring -->|"tab content restored"| tRestored
single -->|"after the last window"| all
all -->|"ten seconds idle"| perf
class init,read,final,restoring,single,all,perf topic;
class wRestoring,wBusy,wReady,wRestored,tRestoring,tRestored event;
A session being restored at startup, from reading the session file to the last tab getting restored.
SessionStartup reads the session file and decides what kind of session it
holds; SessionStore then restores the windows in it, and each window restores
its tabs.
SSWindowRestoring and SSWindowStateBusy fire back to back here, but they
mark different things. SSWindowRestoring and SSWindowRestored belong to a
window being restored. SSWindowStateBusy and SSWindowStateReady bracket any
restore into the window, including a single tab reopened later in the session,
which fires that pair without either of the other two. They are driven by a
counter, so nested restores fire them once: SSWindowStateBusy when the count
leaves zero and SSWindowStateReady when it returns to zero.
A window’s tabs restore on their own schedule, so the diagram’s two branches
run concurrently: the window’s busy counter does not track tab content, and a
tab can fire SSTabRestoring and SSTabRestored before or after its window
fires SSWindowStateReady and SSWindowRestored.
sessionstore-single-window-restored means the window exists with its tabs in
it, not that their content has been restored.
Most tabs are not restored when their window is. With
browser.sessionstore.restore_on_demand and
browser.sessionstore.restore_tabs_lazily both on, which is the default,
Session Restore creates a tab without a browser element and restores it when
the user selects it – possibly minutes later, or never. Such a tab fires
neither SSTabRestoring nor SSTabRestored in the meantime, though it does get
its label and icon from the session state, so a consumer waiting on
SSTabRestoring to read either one waits too long. Pinned tabs are the
exception and restore with their window, unless
browser.sessionstore.restore_pinned_tabs_on_demand is set.
sessionstore-windows-restored is the tree’s startup milestone as much as it is
a Session Restore signal, and
Browser Startup covers that role and the races around it. What
Session Restore means by it is narrow: every window of the startup session has
been opened and populated. It fires exactly once per browser session, including
when there was nothing to restore, so it is safe to use as “the browser is up”.
A whole-session restore that happens later notifies
sessionstore-browser-state-restored instead, precisely so the startup
observers do not run a second time.
Restoring a browser window later
undoCloseWindow(), setWindowState() and restoreLastSession() reuse the
per-window part of the sequence above: SSWindowRestoring, SSWindowStateBusy,
then SSWindowStateReady, SSWindowRestored and
sessionstore-single-window-restored for each window they restore. The
startup-only topics do not fire again.
Restoring a single closed tab with undoCloseTab() fires the busy/ready pair on
its window and the restoring/restored pair on the tab, and nothing else.
Closing a browser window or a tab
---
config:
flowchart:
wrappingWidth: 400
---
flowchart TD
classDef event fill:#dbeafe,stroke:#1e40af,color:#1a1a1a;
classDef topic fill:#fef3c7,stroke:#92400e,color:#1a1a1a;
classDef step fill:#e5e7eb,stroke:#4b5563,color:#1a1a1a;
dwc["domwindowclosed"]
closing(["SSWindowClosing"])
collect["window state collected;<br/>tabs moved to the<br/>closed-windows list"]
changed["sessionstore-closed-objects-changed"]
flush["sessionstore-browser-shutdown-flush"]
dwc -->|"tracked by Session Restore"| closing
closing -->|"consumers have written their state"| collect
collect -->|"a tick later"| changed
changed -.->|"then, per browser, once its<br/>last update arrives"| flush
class dwc,changed,flush topic;
class closing event;
class collect step;
A browser window being closed, and the closed-objects notification that follows.
SSWindowClosing is the last point at which a consumer can still write window
data with setCustomWindowValue(); after it, Session Restore stops tracking the
window.
Closing a tab is the same story without the window part: the TabClose handler
moves the tab into its window’s closed-tabs list and asks for
sessionstore-closed-objects-changed.
sessionstore-browser-shutdown-flush fires per browser element (MozBrowser),
once its last state update has arrived from the content process – not at application
shutdown, despite the name. It matters because that update can still change the
closed-tab list after sessionstore-closed-objects-changed already fired, which
is why Firefox View refreshes its list on both topics.
Reading closed state after a change
sessionstore-closed-objects-changed and sessionstore-saved-tab-groups-changed
are dispatched from a zero-delay timer, and the first one is coalesced behind a
dirty flag. So a consumer that closes a tab and then reads getClosedTabCount()
synchronously gets the count from before the close, and several changes in one
turn of the event loop produce one notification. Read the lists from the
observer, not from the code that made the change.
Rewriting the session before it is used
sessionstore-state-read is an extension point rather than a signal. Its
subject is an nsISupportsString holding the session file’s JSON, and
SessionStartup reparses the string after notifying: an observer that assigns
to subject.data changes the session that gets restored. Rewriting it to
something that does not parse leaves the browser with no session at all.
DOM events
Event |
Target |
Fires when |
|---|---|---|
|
browser window |
The window is closing, before Session Restore stops tracking it. |
|
browser window |
The window started restoring itself or one of its tabs. |
|
browser window |
The window finished the restores that made it busy. |
|
browser window |
Session Restore is about to restore state into the window. |
|
browser window |
The window’s own state is restored and its tabs exist. |
|
|
The tab’s chrome is restored: label, icon and session history. |
|
|
The tab’s content finished restoring. |
Observer notifications
Startup and restore:
Topic |
Subject |
Fires when |
|---|---|---|
|
|
|
|
|
The session file has been read, before its JSON is parsed. |
|
|
|
|
|
There is a session to restore at startup. Does not fire when there is nothing to restore. |
|
|
The user asked for the previous session, through |
|
the browser window |
One browser window has been restored, at startup or later. |
|
|
The startup session’s last browser window has been restored. Fires once per browser session. |
|
|
A whole session has been restored after startup, by |
|
|
|
Closed tabs, windows and tab groups:
Topic |
Subject |
Fires when |
|---|---|---|
|
|
The list of closed tabs, windows or tab groups changed. Coalesced, and dispatched a tick late. |
|
|
The list of saved tab groups changed. Dispatched a tick late. |
|
|
A browser element’s final state update has been processed. |
|
|
The previous session has been discarded, so it can no longer be restored. |
|
|
The previous session became restorable again, which happens when the last regular browser window closes while a taskbar tab window stays open. |
Persisting to disk:
Topic |
Subject |
Fires when |
|---|---|---|
|
|
|
|
|
The last write of the session finished. |
Internal and test-only, listed so they are recognizable rather than to be consumed:
Topic |
Subject |
Fires when |
|---|---|---|
|
|
A tab’s content finished restoring, or there was nothing to restore.
|
|
|
A tab’s content finished restoring. Requires
|
|
|
Session Restore has handled |
Topics Session Restore observes
Most of what Session Restore listens for is browser lifecycle it has no say over. Three topics are different, in that notifying them asks it to do something:
browser:purge-session-historyWipe the session file and drop everything Session Restore is holding: closed tabs and windows, saved tab groups, the previous session, and the session history of open tabs. This is what sanitization uses.
browser:purge-session-history-for-domainThe same, restricted to the domain passed as the notification’s data.
clear-origin-attributes-dataForget closed tabs belonging to the
userContextIdin the notification’s JSON data. Used when a container is deleted.