зеркало из https://github.com/mozilla/gecko-dev.git
145 строки
6.6 KiB
ReStructuredText
145 строки
6.6 KiB
ReStructuredText
.. -*- Mode: rst; fill-column: 80; -*-
|
|
|
|
=======================================================
|
|
The architecture of the Fennec Webpush implementation
|
|
=======================================================
|
|
|
|
Overview of the Push API
|
|
========================
|
|
|
|
The *Push API* is a Web API that allows web applications to "wake up" the User
|
|
Agent (the browser, Fennec), even when the application is not visible (or even
|
|
loaded in a tab). The Push API can only be used by secure sites that register a
|
|
Service Worker.
|
|
|
|
There are four major components in Push:
|
|
|
|
1. A *web application*;
|
|
2. The User Agent (Fennec);
|
|
3. An *app server* associated to the web application;
|
|
4. A *push service backend*.
|
|
|
|
These are listed roughly in the order that they appear in a successful push
|
|
message. First, the web application registers a Service Worker and requests a
|
|
*push subscription*. Fennec arranges a push channel and returns a subscription,
|
|
including a User-Agent-specific *push endpoint* URL to the web application. The
|
|
web application then provides that push endpoint URL to its app server. When
|
|
the app server wishes to push a message to the web application, it posts the
|
|
message and some additional meta-data to the provided push endpoint URL. The
|
|
message is received by the *push service backend* and delivered by some
|
|
unspecified out-of-band mechanism to the User Agent.
|
|
|
|
Two notes on terminology
|
|
------------------------
|
|
|
|
"Push notifications" mean many things to many people. In this system, "push
|
|
notifications" may or may not notify the user. Therefore, we use the term "push
|
|
messages" exclusively. This avoids confusing the push system with the "Web
|
|
Notification" API, which provides the familiar pop-up and system notification
|
|
based user interface.
|
|
|
|
Throughout, we use Fennec to refer to the Java-and-Android application shell,
|
|
and Gecko to refer to the embedded Gecko platform.
|
|
|
|
Overview of the Fennec Push implementation
|
|
==========================================
|
|
|
|
Fennec uses the Google Cloud Messaging (GCM) service to deliver messages to the
|
|
User Agent. Fennec registers for Google Cloud Messaging directly, like any
|
|
other Android App; however, consumers do not interact with GCM directly. To
|
|
provide a uniform interface to all consumers across all implementations, Fennec
|
|
intermediates through the Mozilla-specific *autopush* service. Autopush
|
|
maintains User Agent identification and authentication, provides per-web
|
|
application messaging channels, and bridges unauthenticated push messages to the
|
|
GCM delivery queue.
|
|
|
|
The Fennec Push implementation is designed to address the following technical
|
|
challenge: **GCM events, including incoming push messages, can occur when Gecko
|
|
is not running**. In case of an incoming push message, if Gecko is not running
|
|
Fennec will request startup of necessary Gecko services and queue incoming
|
|
push messages in the meantime. Once services are running, messages are sent over.
|
|
|
|
It's worth noting that Fennec uses push to implement internal functionality like
|
|
Sync and Firefox Accounts, and that these background services are *not* tied to
|
|
Gecko being available.
|
|
|
|
Therefore, the principal constraints and requirements are:
|
|
|
|
1) Fennec must be able to service GCM events, including incoming push messages,
|
|
independently of Gecko.
|
|
|
|
2) Gecko must be able to maintain push subscriptions across its entire
|
|
life-cycle.
|
|
|
|
3) Fennec must be able to use push messages for non-Gecko purposes independently
|
|
of Gecko.
|
|
|
|
Significant previous experience building Fennec background services has shown
|
|
that configuring such services across the Gecko-Fennec interface is both
|
|
valuable and difficult. Therefore, we add the following requirement:
|
|
|
|
4) Gecko must own the push configuration details where appropriate and possible.
|
|
|
|
We explicitly do not care to support push messages across multiple processes. This
|
|
will matter more in a post-e10s-on-Android world.
|
|
|
|
Push component architecture
|
|
===========================
|
|
|
|
Fennec components
|
|
-----------------
|
|
|
|
The two major components are the `PushManager` and the associated
|
|
`PushManagerStorage`. The `PushManager` interacts with the GCM system on the
|
|
device and the autopush service, updating the `PushManagerStorage` as the system
|
|
state changes.
|
|
|
|
There is a unique `PushManagerStorage` instance per-App that may only be
|
|
accessed by the main process. The `PushManagerStorage` maintains two mappings.
|
|
The first is a one-to-one mapping from a Gecko profile to a `PushRegistration`:
|
|
a datum of User Agent state. The `PushManager` maintains each profile's
|
|
registration across Android life-cycle events, Gecko events, and GCM events.
|
|
Each `PushRegistration` includes:
|
|
|
|
* autopush server configuration details;
|
|
* debug settings;
|
|
* profile details;
|
|
* access tokens and invalidation timestamps.
|
|
|
|
The second mapping is a one-to-many mapping from push registrations to
|
|
`PushSubscription` instances. A push subscription corresponds to a unique push
|
|
message channel from the autopush server to Fennec. Each `PushSubscription`
|
|
includes:
|
|
|
|
* a Fennec service identifier, one of "webpush" or "fxa";
|
|
* an associated Gecko profile;
|
|
* a unique channel identifier.
|
|
|
|
The `PushManager` uses the `PushSubscription` service and profile maintained in
|
|
the `PushManagerStorage` to determine how to deliver incoming GCM push messages.
|
|
|
|
Each `PushRegistration` corresponds to a unique *uaid* (User-Agent ID) on the
|
|
autopush server. Each *uaid* is long-lived; a healthy client will maintain the
|
|
same *uaid* until the client's configuration changes or the service expires the
|
|
registration due to inactivity or an unexpected server event. Each
|
|
`PushSubscription` is associated to a given *uaid* and corresponds to a unique
|
|
(per-*uaid*) *chid* (Channel ID) on the autopush server. An individual *chid*
|
|
is potentially long-lived, but clients must expect the service to expire *chid*s
|
|
as part of regular maintenance. The `PushManager` uses an `AutopushClient`
|
|
instance to interact with the autopush server.
|
|
|
|
Between the `PushManager`, the `PushManagerStorage`, and assorted GCM event
|
|
broadcast receivers, push messages that do not target Gecko can be implemented.
|
|
|
|
Gecko components
|
|
----------------
|
|
|
|
The Gecko side of the architecture is implemented in JavaScript by the
|
|
`PushServiceAndroidGCM.jsm` module. This registers a PushService, like the Web
|
|
Socket and HTTP2 backed services, which simply delegates to the Fennec
|
|
`PushManager` using `Messaging.jsm` and friends.
|
|
|
|
There are some complications: first, Gecko must maintain the autopush
|
|
configuration; and second, it is possible for the push system to change while
|
|
Gecko is not running. Therefore, the communication is bi-directional
|
|
throughout, so that Gecko can react to Fennec events after-the-fact. |