Closed Bug 1364822 Opened 7 years ago Closed 3 years ago

[Background Sync] Support BackgroundSync "sync" events when Gecko is not running and the device goes online

Categories

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

enhancement

Tracking

(Not tracked)

RESOLVED INCOMPLETE

People

(Reporter: asuth, Unassigned)

References

Details

The BackgroundSync single-shot sync spec calls for firing "sync" events at ServiceWorkers when a (usable) network becomes available.  We need to be able to start Gecko when not running so the BackgroundSyncService can do this.  Bug 1252650 covered the somewhat similar case for DOM Push notifications.

The initial BackgroundSync implementation (on bug 1217544, hopefully landing soon) gets its network status information via the NS_IOSERVICE_OFFLINE_STATUS_TOPIC "network:offline-status-changed" observer topic.  This obviously does not work if Gecko is not running.

Based on a quick survey of things, it seems like this is the current situation:
- Per https://developer.android.com/topic/performance/background-optimization.html
 - Android apps targeting SDK versions prior to 24 can register to receive CONNECTIVITY_CHANGE intents via the manifest which can start the app.  When targeting 24 or later (Android 7.0), CONNECTIVITY_CHANGE can still be used, but it's only effective when the app is running if it registers via Context.registerReceiver.
 - Android apps targeting API 21 and higher can use the JobInfo.Builder and the JOB_SCHEDULER_SERVICE/JobScheduler to specify a job with NETWORK_TYPE_ANY that can be used to start the app/its JobService.
- GeckoNetworkManager[1] already does Context.registerReceiver on ConnectivityManager.CONNECTIVITY_ACTION when instructed to via the HAL EnableNetworkNotifications() call.  Unfortunately, it seems like it explicitly only exists when Gecko is active[2], perhaps because it mainly is just a HAL implementation for Gecko exposed via JNI.

Given that GeckoNetworkManager doesn't seem to be suitable and using a CONNECTIVITY_ACTION manifest option is both already deprecated and user-battery-unfriendly, it seems like JobScheduler is the way to go.  How to hook that up might want to be informed by whatever strategy we think would make sense for implementing the background-fetch spec (https://github.com/WICG/background-fetch).

1: https://searchfox.org/mozilla-central/source/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoNetworkManager.java
2: https://searchfox.org/mozilla-central/source/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java#144
What will this do to our power footprint? How can we assess that going forward?

ISTM the worst-case is that an app like Twitter declares that it wants to sync in the background, and on a tube ride to work or a backcountry drive it'll cause Gecko to be launched every few minutes, with Firefox being killed soon after each time to reclaim resources.

Can we make sure to rate limit (either in JobScheduler itself, or in the Java intent handler, but not solely in Gecko for obvious reasons!), and perhaps also specify NETWORK_TYPE_UNMETERED to mitigate bandwidth concerns? Does Android take care of doing any of these things for us?
(In reply to Richard Newman [:rnewman] from comment #1)
> What will this do to our power footprint? How can we assess that going
> forward?

Lets be clear, this needs to be designed.  This bug is a placeholder for this work.  An explicit goal would be to build it in a way that can be power efficient.

Consider that sites can already trigger this undesirable behavior by using push notifications to start background loads.  The purpose of this API is provide a better mechanism that the OS can more intelligently schedule to be batter efficient.

Perhaps as a conservative place to start we could only trigger "background sync while FF is closed" when the device connects to wifi.
(In reply to Richard Newman [:rnewman] from comment #1)
> Can we make sure to rate limit (either in JobScheduler itself, or in the
> Java intent handler, but not solely in Gecko for obvious reasons!), and
> perhaps also specify NETWORK_TYPE_UNMETERED to mitigate bandwidth concerns?
> Does Android take care of doing any of these things for us?

Yes, there are a few relevant pieces of JobScheduler functionality we can leverage:

-  JobInfo.Builder.setTriggerContentUpdateDelay[1] says "Set the delay (in milliseconds) from when a content change is detected until the job is scheduled. If there are more changes during that time, the delay will be reset to start at the time of the most recent change."  Which I think means we can use this as an attempt to help ensure that the network has stabilized in cases of spotty coverage like the Tube or a back-country drive.  Pathological situations are of course still possible, but it's a useful tool that doesn't need to be implemented by Gecko.

- setBackoffCriteria[2] supports linear and exponential back-offs if we report a failure that means the job wasn't completed.

- setRequiresDeviceIdle[3] supports waiting for the device to be idle.

Having said that, an explicit use-case for background sync is "I just wrote an email/chat message/etc. and I'm offline, but I want it delivered at the first opportunity."  That's a scenario where timeliness does matter and it could be appropriate to try and leverage the brief window of coverage at a tube stop for at least our first try, at least for apps that aren't constantly blowing their budget (https://wicg.github.io/budget-api/) when we have such tracking.

Of course, since in the "I just wrote..." case, we'd expect Firefox to still be around unless evicted by the user bringing up a resource heavy game/etc.  So it could definitely make sense to initially err on the side of conservative, battery-friendly constants.  If the user is wondering whether their message got sent, they'd likely bring Firefox up again to check, at which point the "sync" event would have a chance to fire based on Gecko's use of the GeckoNetworkManager.

Also, keep in mind that right now single-shot background sync just provides: "I want to do something that requires being online.  If we're not online now, notify me when we are, if we are online, let's do it now.  In the event my SW gets killed or loses network during the process of the sync event, I want to get more tries in the future when we're online".

Periodic sync will happen in the future, but right now backgroundsync can't be used for ill-conceived "update my app every 5 minutes" by sites.  That foot-gun falls to the push API :).  I think implementing periodic sync will require adoption of budget tracking and other infrastructure before we could turn that on.  Probably also the ability to expose PWA's as their own app on the system so that we can also attribute the battery usage to the PWA rather than Firefox?  It sounded like the mechanism Chrome was introducing (and that we'll also be allowed to use) to let PWAs pretend to be real apps might allow something like this.  (Noting that there's a lot of if's about that and whether/when our architecture would let us truly apportion the power usage.  This is just blind speculation/hope on my part.)

1: https://developer.android.com/reference/android/app/job/JobInfo.Builder.html#setTriggerContentMaxDelay(long)
2: https://developer.android.com/reference/android/app/job/JobInfo.Builder.html#setBackoffCriteria(long,%20int)
3: https://developer.android.com/reference/android/app/job/JobInfo.Builder.html#setRequiresDeviceIdle(boolean)
I left out:

- setRequiredNetworkType[1] that does let us specify JobInfo.NETWORK_TYPE_UNMETERED or other values.

- setRequiresCharging[2] which we could use if we started up and failed to sync and also saw battery was so low that any further wake-ups without charging would be a gratuitous waste.  (Although maybe Android's job scheduler would make that decision for us anyways?)

1: https://developer.android.com/reference/android/app/job/JobInfo.Builder.html#setRequiredNetworkType(int)
2: https://developer.android.com/reference/android/app/job/JobInfo.Builder.html#setRequiresCharging(boolean)
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.