1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
# Invalidations Component
## Introduction
Let's start with an example. On Chrome OS there exists a concept called
"policy" - one can think of them as dynamic flags that change Chrome's
behaviour. They are changed on the Admin Panel from where they get propagated
to Chrome OS devices. There is a scheduled "poll job" that fetches those
policies every N hours, but preferably we would like to have the latest policy
in matter of minutes/seconds. We could shorten the polling interval to 1
minute, but that would put a very high unnecessary load on the servers. To
solve this problem we introduce a concept called "invalidation" where the server
notifies the devices when their policy changes and then they fetch the new
policy - note that this way the devices only fetch the policy when needed.
Invalidation Service - the word comes from cache invalidation. Imagine you have
a database which has some objects in it. Cache is just a quick access copy of
those objects. When an object changes in the database so should the copy of that
object in cache.
If we consider the client device as a cache then whenever some object changes in
the server, so should the copy of this object in the client device. All the
invalidation related interaction between client device and server is done
through Invalidation Service.
An **Invalidation** (a message to invalidate some object) is sent and received
using a publish/subscribe service. In practice, this is Firebase Cloud Messaging
(FCM, see
[firebase.google.com/docs/cloud-messaging](https://firebase.google.com/docs/cloud-messaging)
or [go/fcm](http://go/fcm)) and Fandango (see
[go/fandango](http://go/fandango)).
In general the whole thing looks as follows:

***
## Terminology
* **InstanceID**: An identifier for "a specific app installed on a specific
device". The term comes from GMSCore on Android. Here, an "app" is a client of
invalidations, such as Sync, Drive, or Policy. It's just a mostly random
string of 8 bytes, created by Chrome.
* **Registration**: As in "registering with FCM"; means making an InstanceID
known to the FCM server. The result of registering is an **InstanceID token**
(note that this is different from an InstanceID).
* **Topic**: A "namespace" or "channel" of messages that clients can subscribe
to. For Sync, they correspond to data types. A topic can be either private
(i.e. GAIA-keyed) or public. For private topics, a unique ID derived from the
user's GAIA ID is appended to the topic name to make it unique (though this
is an implementation detail which is hidden from clients).
* **Subscription**: As in "subscribing to a topic", i.e. telling the server that
this client (identified by InstanceID token) is interested in a given topic.
* **ProjectID** (aka **SenderID**): An ID from the Google Cloud Platform console
that identifies a client of invalidations (such as Sync, Drive, or Policy).
E.g. for Sync its value is kInvalidationGCMSenderId. Note that (as opposed to
InstanceID) this is constant across all users and Chrome instances.
***
## Classes
### InvalidationHandler
An **InvalidationHandler** is a client (receiver) of Invalidations. Every
feature that wants to receive Invalidations needs to implement an
InvalidationHandler and register it with InvalidationService (see below).
InvalidationHandler has the following methods (the list is not exhaustive):
* **OnIncomingInvalidation** is called from InvalidationService to notify
about incoming Invalidation messages.
* **GetOwnerName** must return a unique name for this InvalidationHandler.
***
### InvalidationService
**InvalidationService** is the main entry point for clients of the Invalidations
system. This is where an InvalidationHandler registers/unregisters itself, and
where it registers the Topics it is interested in. When a message arrives,
InvalidationService calls OnIncomingInvalidation for the receiving
InvalidationHandler.
InvalidationService provides the following methods (the list is not exhaustive):
* **AddObserver** allows an InvalidationHandler to register
itself as a observer for Invalidations. InvalidationService will only
dispatch messages to registered handlers.
* **UpdateInterestedTopics** allows InvalidationHandler to change the set of
Topics it is interested in.
* **RemoveObserver** lets an InvalidationHandler unregister
itself again, after which it stops receiving Invalidations.
An InvalidationService instance is usually tied to a profile (via
**ProfileInvalidationProviderFactory**), but on ChromeOS there is also a
device-scoped instance, managed by **AffiliatedInvalidationServiceProvider**
(used for device policies, which must apply even before any user is signed in).
***
### FCMInvalidationService
**FCMInvalidationService** is the only real (non-test) implementation of
InvalidationService, using [FCM](http://go/fcm)+[Fandango](http://go/fandango)
as its publish/subscribe service. It delegates most of the work to
InvalidatorRegistrarWithMemory and FCMInvalidationListener.
***
### InvalidatorRegistrarWithMemory
**InvalidatorRegistrarWithMemory** maintains the mapping between Topics and
InvalidationHandlers. When a message arrives via FCMInvalidationListener,
InvalidatorRegistrarWithMemory dispatches that message (invalidation) to the
appropriate InvalidationHandler.
InvalidatorRegistrarWithMemory also persists the set of Topics per handler, to
avoid redundant re-subscriptions after every Chrome restart.
***
### FCMInvalidationListener
**FCMInvalidationListener** gets the list of interesting Topics from
FCMInvalidationService. It passes the Topics to PerUserTopicSubscriptionManager
(see below) for subscription/unsubscription, receives Invalidation messages from
FCMNetworkHandler, and passes Invalidations for the interesting Topics back to
FCMInvalidationService.
***
### PerUserTopicSubscriptionManager
**PerUserTopicSubscriptionManager** manages subscriptions to Topics, sending
subscription or unsubscriptions requests to the server as necessary. It persists
the set of subscribed Topics in prefs to avoid redundant re-subscriptions after
Chrome restarts.
***
### FCMNetworkHandler
**FCMNetworkHandler** is responsible for communication via GCM channel. It
provides the following functionality:
* Retrieves the InstanceID token required for the subscription. When this token
is received, it is passed to PerUserTopicSubscriptionManager which subscribes
to Topics with the given token.
* Receives messages from GCM driver and passes them up to
FCMInvalidationListener, where they are converted to Invalidations.
|