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 or go/fcm) and Fandango (see go/fandango).
In general the whole thing looks as follows:
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):
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):
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 is the only real (non-test) implementation of InvalidationService, using FCM+Fandango as its publish/subscribe service. It delegates most of the work to InvalidatorRegistrarWithMemory and FCMInvalidationListener.
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 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 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 is responsible for communication via GCM channel. It provides the following functionality: