Battery drain when using CoreLocation Significant Location Monitoring & CoreBluetooth
Asked Answered
O

3

38

We've released an application which runs in the background and uses CoreBluetooth & CoreLocation to automatically save your parking location.

At a high level our app just looks for a CoreBluetooth disconnect event and turns on GPS until we get an location fix (accuracy <=10m) or 3 minutes max time (this could occur when you park in an underground parking lot with no GPS coverage). We then use Significant Location Monitoring to automatically re-launch our application in event of the system terminating our app.

During our development we never saw a battery drain issue ourselves, however 75% of our users say that they see a significant battery drain. 10% of our backers responded to the poll so it's a difficult to determine how representative the breakdown is, but it's a large percentage of our users. http://www.findmycarsmarter.com/forum/viewtopic.php?f=4&t=30

We then released an update that allowed users to disable Significant Location Monitoring and 60% say that by disabling Significant Location Monitoring the drain goes away. http://www.findmycarsmarter.com/forum/viewtopic.php?f=4&t=42

Initially we could not duplicate the drain issue ourselves, but we found that when we installed a simple app that just turned on Significant Location Monitoring in conjunction with Find My Car Smarter, we intermittently saw the drain reproduce. In the drain state the phone does not enter hibernate. This is indicated by the usage time in (Settings->Usage->Time since last full charge) continuing to increment even though the phone had been put to sleep and the display is off. Something prevents the system from entering hibernate. The battery drains about 15% per hour in this stage. This drain shows up intermittently and seems to clear itself out after an hour or two and come again randomly. We have not found a way to reliability reproduce the drain.

We believe the issue is caused by multiple clients calling into CoreLocation. We asked a few users who experienced the issue to wipe their phone and only install our Find My Car Smarter app. Alone with just this app installed, the drain did not exhibit. We have had other reports that when our app is used with Google Latitude or Facebook, etc is when they see the drain occur. Or if they go and kill other applications the drain goes away. We've seen the drain persist through a power cycle, with no apps launched. This implies that it has to be a system level service that prevents the OS from sleeping.

Even though we think the issue is caused by some race condition of multiple clients calling into CoreLocation, we never saw the issue reproduce with apps that only used CoreLocation. We even created 4 or 5 different apps that would simultaneously access CoreLocation and we didn't see the drain occur. We did however see the issue when we had an app with CoreLocation and a second app with CoreLocation + CoreBluetooth. There are probably very few apps that use the CoreLocation + CoreBluetooth combination, so potentially that's why more developers haven't hit this issue. Although we're at a loss to explain how CoreLocation & CoreBluetooth interact to cause this drain and how the second app with CoreLocation comes into the equation. Since the drain was intermittent it's possible that it's just a fluke that the issue only happened when we were testing with CoreLocation + CoreBluetooth.

On a wiped 5.0.1 iPhone 4S with only these two apps CTM1 & FMC installed we were able to intermittently get into the drain state. Interestingly, the drain issue seemed to occur much less frequently on a wiped device then our normal device. Unfortunately we only saw the drain state a few times and without being able to reliably reproduce the drain we don't have a good control state to work from.

We've filed a bug report with Apple and opened up a Technical Support Incident, but maybe the Stackover community can also provide some insight. We've seen this issue both in 5.0.1 & in 5.1 Beta 3.

CTM1 http://www.findmycarsmarter.com/files/CTM1.zip

On Going into the Background
    [locationManager stopUpdatingLocation];
    [locationManager stopUpdatingHeading];
    [locationManager startMonitoringSignificantLocationChanges];

On Re-entering Foreground
    [locationManager stopMonitoringSignificantLocationChanges];
    [locationManager startUpdatingLocation];
    [locationManager startUpdatingHeading];
On didUpdateToLocation
    //do nothing
On didUpdateHeading
    //do nothing

FMC http://www.findmycarsmarter.com/files/FMC.zip

On Going into the Background
    [btleManager stopScan];
    [locationManager stopUpdatingLocation];
    [locationManager stopUpdatingHeading];
    [locationManager startMonitoringSignificantLocationChanges];

On Re-entering Foreground
    [locationManager stopMonitoringSignificantLocationChanges];
    [locationManager startUpdatingLocation];
    [locationManager startUpdatingHeading];        
    [btleManager scanForPeripheralsWithServices:nil options:nil];
On didUpdateToLocation
    //do nothing
On didUpdateHeading
    //do nothing
On centralManagerDidUpdateState
    [btleManager scanForPeripheralsWithServices:nil options:nil];
On didDiscoverPeripheral
    [btleManager connectPeripheral:device options:nil];
On didConnectPeripheral
    //update log
On didDisconnectPeripheral
    //initiate reconnect
    [btleManager connectPeripheral:device options:nil];

If you see any coding mistakes that might account for the drain please let us know.

One other question we did have, if we're using both GPS & Significant Location Monitoring, is there a reason to call stopMonitoringSignificantLocationChanges? Looking at the Regions sample code they call stopMonitoringSignificantLocationChanges & startLocationUpdate on entering foreground and stopLocationUpdate & startMonitoringSignificantLocationChanges on entering background, but I'm wondering if this is necessary/recommended/required?

Update:

We've confirmed with Apple Developer Technical Support that for applications using both GPS & Significant Location Monitoring that our sequence of turning off Significant Location Monitoring before enabling GPS update is correct.

We've also confirmed that the drain issue can still be seen in the GM 5.1 & with a re-compiled Find My Car Smarter application against the 5.1 Frameworks.

Update:

It looks like the issue is triggered when our app is launched from the background in response to a Significant Location Monitoring event. We actually don't handle this scenario properly in our sample code but we do in our actual app.

In the sample code, on a background re-launch we'll turn on location update and since there is not a applicationDidEnterBackground call, the GPS will be left on.

In our app we check to see if we were launched from the background by looking for the UIApplicationLaunchOptionsLocationKey flag, if so we start Significant Location Monitoring, otherwise we were launched in the foreground and we start Updating Location.

Apple got back to us and stated that usage of Significant Location Monitoring does not require the location set in UIBackgroundModes array in the Info.plist. We removed this entry and it appears that the battery drain state is no longer hit. We still have bluetooth-central in the UIBackgroundModes list. At the moment we're unclear as to why this helps. We're going to be running some more experiments to help us understand this better. If anyone has any suggestions please let us know.

Olney answered 1/3, 2012 at 8:57 Comment(3)
There's a suitable profiler for battery drain in Instruments.Emitter
"We then use Significant Location Monitoring to automatically re-launch our application in event of the system terminating our app." Can you please explain what you mean by this? I'm trying to find a solution to ensure BTLE persists in the background. As of now, after 5 minutes in the background, my iOS app loses its BTLE receiving capabilities.Schmidt
@Schmidt disclaimer: I don't know what I'm talking about. But the OP even stated this himself. Set the bluetooth in UIBackgroundModes to keep your bluetooth alive.Byer
O
17

At the end of the day, Apple's suggestion of removing location from UIBackgroundModes fixed our battery drain issue.

In order to still get locations in the background we had to wrap the [locationManager startLocationUpdates] & [locationManager stopLocationUpdates] calls with:

[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler];
[[UIApplication sharedApplication] endBackgroundTask:];
Olney answered 16/4, 2012 at 5:31 Comment(7)
can you paste an example of how to do this? From what I know, beginBackgroundTaskWithExpirationHandler will only give you 10 mins on the background. If you don't set the app as UIBackgroundModes it wont "wake up" due to location changes...Swanee
Even if location is not set in UIBackgroundModes, if your app has called startMonitoringSignificantLocationChanges it will still get relaunched on a significant location change event. You just won't be given more then a few seconds to execute, which is where the beginBackgroundTaskWithExpirationHandler comes into play to give you up to 10 minutes to execution time. This was news to us too and is not clearly documented. Here's a beginBackgroundTaskWithExpirationHandler example #7346778Olney
So i should add the beginBackgroundTaskWithExpirationHandler in the "locationManager:didUpdateToLocation:FromLocation" to get 10 more mins after a location update, right?Swanee
In our application, when we get the didDisconnectPeripheral callback we call beginBackgroundTaskWithExpirationHandler this give us up to 10 minutes to get a GPS fix, we then call startUpdatingLocation, wait until we get an accurate GPS fix and call stopUpdatingLocation & endBackgroundTask. This may not be applicable to your application. I don't think you want to call beginBackgroundTaskWithExpirationHandler in locationManager:didUpdateToLocation:FromLocation as you might end up never letting the phone sleep, which would cause battery drain.Olney
Was this bug ever fixed in iOS 6, 7 or 8?Lewse
@DanReese Seems not to be much of a "bug" to begin with, given the Apple Documentation quoted here: If your iOS app must keep monitoring location even while it’s in the background, use the standard location service and specify the location value of the UIBackgroundModes key to continue running in the background and receiving location updates. (<snip something about pausesLocationUpdatesAutomatically/>) Examples of apps that might need this type of location updating are fitness or turn-by-turn navigation apps. This clause may not have been around in 2012 but it speaks for itself.Byer
That is, indeed the find-my-car functionality needs to perform background location fetching, but not appropriately shutting itself off (clearly in this case being hindered by the use of location for UIBackgroundModes) thereafter is a problem. Defensive programming might have for example employed more drastic measures to terminate the "runaway" background process, as no additional location data is needed for its business logic.Byer
U
2

You could debug status of the app using any repetitive signal sound. Just make sure you didn't put 'plays audio' in the background modes requirements for this test. If your app running - you will hear this sounds even application is in the background. If app is suspended - you will hear nothing. This is probably simplest method to detect that the app is not properly suspended.

Using Profiler for debug of this issue is problematic because many things works different in debug mode when device connected to computer. Especially power saving things.

Also, please make sure you do everything right in response to significant location changes. If you start location updates - make sure you've set some timer (for 3 minutes, for example) that shuts down location updates. Anyway, the iOS will kill you app even it started location updates from response to significant location changes. Does not matter what you did started in response - the app will be killed in 10 minutes if still running - pay attention to crash logs - such event will be logged there.

Also, check all your 3rd party code and libs - perhaps some of them turns GPS and use it for somethings. Mostly paranoid, but may happen for analytic and advertising targeting purposes.

Unionize answered 9/4, 2012 at 15:47 Comment(1)
Good suggestion! We tried it out unfortunately if we don't declare audio in UIBackgroundModes no audio gets played even if our application is running. If we do put audio in UIBackgroundModes than the audio playback causes our app to not suspend.Olney
F
0

CoreLocation enabled applications generally made for background mode , so it can run in background, definitely it usage more battery , for my suggestion is always try to stop the location service when it is no need .

[locationManager stopUpdatingLocation];

then after according to your requirement then start accordingly,

Thanks

Floria answered 13/4, 2012 at 13:4 Comment(1)
We're definitely not leaving startUpdatingLocation or startUpdatingHeading on, we put debug messages for whenever this callback gets and can tell that this is not causing the issue.Olney

© 2022 - 2024 — McMap. All rights reserved.