commit 1ba924db4f5170942397430e5f76e2303623dd0b
parent c7dd1efaff8180014af79b6db9aaebc30ab2a7ec
Author: Andrea Marchesini <amarchesini@mozilla.com>
Date: Mon, 10 Nov 2025 14:06:23 +0000
Bug 1998795 - IPProtection: implement the ACTIVATING state - part 5 - documentation r=ip-protection-reviewers,sstreich
Differential Revision: https://phabricator.services.mozilla.com/D271908
Diffstat:
3 files changed, 52 insertions(+), 13 deletions(-)
diff --git a/browser/components/ipprotection/IPProtectionService.sys.mjs b/browser/components/ipprotection/IPProtectionService.sys.mjs
@@ -136,12 +136,11 @@ class IPProtectionServiceSingleton extends EventTarget {
}
/**
- * Request to update the current state.
- *
- * Updates will be queued if another update is in progress.
+ * Recomputes the current state synchronously using the latest helper data.
+ * Callers should update their own inputs before invoking this.
*/
#updateState() {
- this.#setState(this.#checkState());
+ this.#setState(this.#computeState());
}
/**
@@ -149,7 +148,7 @@ class IPProtectionServiceSingleton extends EventTarget {
*
* @returns {Promise<IPProtectionStates>}
*/
- #checkState() {
+ #computeState() {
// The IPP feature is disabled.
if (!this.featureEnabled) {
return IPProtectionStates.UNINITIALIZED;
diff --git a/browser/components/ipprotection/docs/Components.rst b/browser/components/ipprotection/docs/Components.rst
@@ -157,5 +157,6 @@ Recommended steps:
Be mindful of ordering if your helper depends on others. For example,
``IPPNimbusHelper`` is registered last to avoid premature state updates
triggered by Nimbus’ immediate callback.
-4. If your component needs to trigger a recomputation, call
- ``IPProtectionService.updateState``.
+4. If your component needs to recompute the service state, call
+ ``IPProtectionService.updateState()`` after updating the helper data it
+ relies on; the recomputation is synchronous.
diff --git a/browser/components/ipprotection/docs/StateMachine.rst b/browser/components/ipprotection/docs/StateMachine.rst
@@ -1,11 +1,14 @@
State Machine
=============
+Service state machine
+---------------------
+
The finite state machine is implemented in the ``IPProtectionService`` class
and the states are defined in the ``IPProtectionStates`` object.
-States
-------
+Service states
+~~~~~~~~~~~~~~
The service transitions across the following states:
@@ -15,20 +18,56 @@ The service transitions across the following states:
- ``READY``: Ready to activate the proxy.
High‑level transitions
-----------------------
+~~~~~~~~~~~~~~~~~~~~~~
- Feature disabled → ``UNINITIALIZED``.
- During startup, if initialization isn’t complete, use cached state from ``IPPStartupCache``.
- Not signed in → ``UNAVAILABLE`` if not eligible, otherwise ``UNAUTHENTICATED``.
- If an entitlement is cached/valid → ``READY``.
-- Otherwise, check enrollment with Guardian (via ``IPPErollHelper``):
+- Otherwise, check enrollment with Guardian (via ``IPPEnrollAndEntitleManager``):
- Not enrolled → ``UNAVAILABLE`` (not eligible).
- Enrolled → fetch entitlement; if successful → ``READY``, else ``UNAVAILABLE`` when not eligible.
Events and integration points
------------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ``IPProtectionService:StateChanged`` is dispatched on state changes with
``detail.state`` and ``detail.prevState``.
-- Helpers can call ``IPProtectionService.updateState()`` to request a recomputation.
+- Helpers can call ``IPProtectionService.updateState()`` to recompute the state immediately; update any helper-owned data first because the call is synchronous.
- Public actions: ``start(userAction)``, ``stop(userAction)``, and ``startLoginFlow(browser)``.
+
+Proxy manager state machine
+---------------------------
+
+The ``IPPProxyManager`` layers a proxy‑specific finite state machine on top of
+``IPProtectionService``. It mirrors eligibility changes from the service and
+drives the lifecycle of the proxy connection.
+
+Proxy states
+~~~~~~~~~~~~
+
+- ``NOT_READY``: Service is not ``READY``. Channel filters are torn down and UI should not offer activation.
+- ``READY``: Service is ``READY`` and the proxy can be activated.
+- ``ACTIVATING``: ``start()`` is creating a channel filter, fetching a proxy pass, and selecting an endpoint.
+- ``ACTIVE``: Proxy connected. Usage and network observers are reporting metrics.
+- ``ERROR``: A recoverable error occurred while activating or rotating credentials. Errors are kept in a bounded history.
+
+Proxy transitions
+~~~~~~~~~~~~~~~~~
+
+- ``IPProtectionService:StateChanged`` → ``IPPProxyManager.updateState()``:
+ - Service ``READY`` → proxy ``READY`` (resets connection/error history).
+ - Any other service state → proxy ``NOT_READY`` (stops active connections).
+- ``start(userAction)`` from ``READY`` moves to ``ACTIVATING``.
+ - Successful activation → ``ACTIVE`` and telemetry ``ipprotection.toggled``.
+ - Failures (missing entitlement, server list, proxy pass…) → ``ERROR`` via ``#setErrorState``.
+- ``stop(userAction)`` from ``ACTIVE`` → ``READY`` after closing the channel filter and observers.
+- ``reset()`` or helper‑driven recomputations call ``updateState()`` which demotes the proxy back to ``READY``/``NOT_READY`` and clears the credential cache.
+- Network errors (``proxy-http-error`` with 401) trigger Proxy Pass rotation while staying ``ACTIVE``; repeated failures bubble up through ``#setErrorState``.
+
+Proxy events and hooks
+~~~~~~~~~~~~~~~~~~~~~~
+
+- ``IPPProxyManager:StateChanged`` is dispatched with ``detail.state`` whenever the proxy state machine moves.
+- ``IPPProxyManager`` listens to ``IPProtectionService:StateChanged`` and to ``proxy-http-error`` from ``IPPNetworkErrorObserver``.
+- Consumers can observe ``IPPProxyManager.state`` (or listen for events) to synchronize UI/telemetry with the proxy lifecycle.