I can see a number of events in our error logging service where we track expired BGAppRefreshTask. We use BGAppRefreshTask to update metadata.
By looking into those events I can see most of reported expired tasks expired around 2-5 seconds after the app was launched. The documentations says: The system decides the best time to launch your background task, and provides your app up to 30 seconds of background runtime.
I expected "up to 30 seconds" to be 10-30 seconds range, not that extremely short.
Is there any heuristic that affects how much time the app gets?
Is there a way to tell if the app was launched due to the background refresh task? If we have this information we can optimize what the app does during those 5 seconds.
Thank you!.
So, let me start here:
How can I test the following:
The basic idea I was outlining there was using a local notification as the hint/trigger that background app refresh has occurred, so you can then unlock the device "immediately" if/when you see that alert. However, that technique is also useful for situations like this:
We are not able to reproduce those expiration on our devices (or the QA devices) so there's no way to get sysdiagnose because our error tracking is fully anonymized and our app don't have accounts, we don't know which exact users are affected.
If you have formal beta testers and/or the app is being used by your development team or other "known" users, then you can use the same local notification "trick" to notify one those "special" users that they should collect a sysdiagnose from that device. Typically you'd do something like enabling the flag in TestFlight (where the users are "known" and willing to collect this kind of data for you) and disable it in "production"/App Store (where you don't want to bother/confuse customers).
One small cautionary not here:
The app uses Bugsnag to track handled and unhandled errors and it shows the time of the event since when the Bugsnag was loaded (applicationDidFinishLaunching).
This is how I can see that a very large number of expired tasks are under 5 seconds after the Bugsnag was loaded.
One thing to be careful about here is making sure you're data means EXACTLY what you think it means. In the case here, what you're actually comparing is the time Bugsnag logs a particular message against the time expiration logged. It's possible that's entirely fine- Bugsnag initialization time is short and "constant" so, practically speaking, it's the same as if you'd logged directly out of "applicationDidFinishLaunching". However, it could also be the case that Bugsnag under some unknown set of circumstances, Bugsnag takes longer to load/initialize, making the expiration time look much shorter than it actually is.
There are also other, more complicated variations on that "theme". Most of our APIs like this have some degree of protection against "cheating" built in, so that an app can't get extra runtime by tweaking it's own internal processing to delay when it receives information from the system. SO, for example, in a sequence like this:
-
Spends 20s doing "stuff" prior to applicationDidFinishLaunching
-
Sets up BGTaskScheduler in applicationDidFinishLaunching
-
System calls launchHandler to start task.
...Then I'd expect that task to expire closer to 10s vs. 30s.
Lastly, returning to this point:
our error tracking is fully anonymized
Does the system let you track issues by device, even though the device itself is anonymous? Putting that another way, can you see "all" the data produced by a given device, even though you don't know who/which physical device that actually is. If you're able to correlate data, then that might given you insight it to what actually triggers the issue.
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware