Closed Bug 1345651 Opened 7 years ago Closed 3 years ago

Add ability to determine if a registered push subscription is no longer valid

Categories

(Firefox for Android Graveyard :: Firefox Accounts, enhancement, P5)

enhancement

Tracking

(Not tracked)

RESOLVED INCOMPLETE

People

(Reporter: Grisha, Unassigned)

References

Details

The autopush service will drop router and message table entries for clients which have not connected in 30-60 days. Clients then are expected to re-register.

Applications using webpush are expected to deal with by re-registering and notifying their application servers via an out-of-band channel when they're notified of an expired subscription via subscriptionchanged event.

In the Android implementation, this event is currently fired if there's a mismatch between subscriptions that gecko is aware of and what Fennec's DumpSubscriptions method returns [0][1].

However, after registering them Fennec never will only drop PushSubscriptions if asked by Gecko, and otherwise a registered PushSubscription will live on as long as PushRegistration lives on. As such, there's currently no way of figuring out if a given subscription is no longer valid, and removing it from a list of subscriptions returned to Gecko. And so, applications which requested a possibly-no-longer-valid subscription will not be notified via subscriptionchanged event.

Maintaining usage information for subscriptions on the client and trying to estimate if they could be invalid is rather problematic, as we do not want to depend on how frequently autopush purges records internally, or on any other of its internal behaviour.

It seems that in order to determine which subscriptions are no longer valid, we need an additional autopush interface for bridged (mobile) clients. Simplest approach to this might be:
- clients GET a list of all currently valid subscriptions for a given UAID.
- they then remove no-longer-valid local subscriptions (and perhaps inform Gecko in case of Android).

Clients may assume that subscriptions could be invalidated once a month, and so this GET call could be performed once a month as well (or _at least_ once a month, if a client is not active for a period of time, e.g. device is turned off).

Semi-related side note:
Assuming a desired life-cycle of a "webpush" subscription registered by a WebPush application doesn't make sense, as this is application's responsibility. However, in case of an FxA service, Fennec _is_ the application, and it desires its subscription to be always valid. Bug 1329793 addresses this problem in a simplistic way - once a month unsubscribe, subscribe again, and update FxA server device record with a new subscription endpoint. However, if the above is implemented, this will allow us to only re-register a subscription if it's expired, thus minimizing unnecessary and costly network activity.

Perhaps an additional avenue to explore is having an ability to _ask_ autopush to keep a subscription valid. However, that seems quite specific to needs of FxA, and the more generic solution proposed above should allow Fennec to achieve the same end result.

[0] https://dxr.mozilla.org/mozilla-central/source/dom/push/PushServiceAndroidGCM.jsm#182
[1] https://dxr.mozilla.org/mozilla-central/source/mobile/android/base/java/org/mozilla/gecko/push/PushService.java#305
JR, does my understanding of the problem seem correct, and if so, what do you think of adding such endpoint to autopush?
Flags: needinfo?(jrconlin)
https://68.media.tumblr.com/0bdca5027dfe52dbc9ee892eb1ef10a6/tumblr_njydmzHlZK1txe8e9o1_500.gif

Thank you for the really clear explanation, Grisha! I'd love to see this captured in the Android Push docs, once we have an answer. I think you've accurately identified a missing link in the API: bridged clients don't know when their channels expire, so they can't tell service workers (or FxA) to re-register.
I can add a call that returns a list of known channelIDs for a given URL.

I'll presume that it should be something like:

GET /v1/{type}/{app_id}/registration/{uaid}/subscription
Authorization: Bearer {secret}

and that it would return something like
{"channelIDs": [...]}

If I get a confirmation, I'll file an issue in autopush.

One other note:

The client could also just register it's own channel and every few weeks often fire off a message to itself. All the server needs is for the UAID to get some message for a given UAID to keep it from expiring that UAID. You could keep a single time value when you last checked / got any message and if the value is < now - (86400 * 28) fire off another. (If time < now - (86400 * 45) probably safe to just re-register.) Cost of an int storage.
Flags: needinfo?(jrconlin)
(In reply to JR Conlin [:jrconlin,:jconlin] from comment #3)
> I can add a call that returns a list of known channelIDs for a given URL.
> 
> I'll presume that it should be something like:
> 
> GET /v1/{type}/{app_id}/registration/{uaid}/subscription
> Authorization: Bearer {secret}
> 
> and that it would return something like
> {"channelIDs": [...]}
> 
> If I get a confirmation, I'll file an issue in autopush.
> 
> One other note:
> 
> The client could also just register it's own channel and every few weeks
> often fire off a message to itself. All the server needs is for the UAID to
> get some message for a given UAID to keep it from expiring that UAID. You
> could keep a single time value when you last checked / got any message and
> if the value is < now - (86400 * 28) fire off another. (If time < now -
> (86400 * 45) probably safe to just re-register.) Cost of an int storage.

The client already takes steps to ensure its uaid is not expired whilst it's still active.  This is talking about chids expiring.  In general, bridged Android clients will never witness a chid expiring; this ticket tracks changing that, so we can give feedback to the ServiceWorker that the push-subscription-changed.  The motivating issue is to achieve this for FxA device registration, which doesn't run via a ServiceWorker, but instead by code in the browser.
(In reply to JR Conlin [:jrconlin,:jconlin] from comment #3)
> I can add a call that returns a list of known channelIDs for a given URL.
> 
> I'll presume that it should be something like:
> 
> GET /v1/{type}/{app_id}/registration/{uaid}/subscription
> Authorization: Bearer {secret}
> 
> and that it would return something like
> {"channelIDs": [...]}
> 
> If I get a confirmation, I'll file an issue in autopush.

This is exactly what I had in mind. File away! I'll add android support for this, and we'll likely need to add iOS support for this endpoint as well to better support FxA device registration.
I think I saw a PR fly by somewhere in GH for this. JR, could you please post a link here and a short status update? Thanks!
Flags: needinfo?(jrconlin)
That's great! We should be able to do the client work now.
Re-triaging per https://bugzilla.mozilla.org/show_bug.cgi?id=1473195

Needinfo :susheel if you think this bug should be re-triaged.
Priority: -- → P5
We have completed our launch of our new Firefox on Android. The development of the new versions use GitHub for issue tracking. If the bug report still reproduces in a current version of [Firefox on Android nightly](https://play.google.com/store/apps/details?id=org.mozilla.fenix) an issue can be reported at the [Fenix GitHub project](https://github.com/mozilla-mobile/fenix/). If you want to discuss your report please use [Mozilla's chat](https://wiki.mozilla.org/Matrix#Connect_to_Matrix) server https://chat.mozilla.org and join the [#fenix](https://chat.mozilla.org/#/room/#fenix:mozilla.org) channel.
Status: NEW → RESOLVED
Closed: 3 years ago
Resolution: --- → INCOMPLETE
Product: Firefox for Android → Firefox for Android Graveyard
You need to log in before you can comment on or make changes to this bug.