iOS Google Mobile Ads SDK seemingly startsUpdateLocation in background on a 1 minute timer

96 views
Skip to first unread message

Jared Egan

unread,
Apr 23, 2018, 6:50:34 PM4/23/18
to Google Mobile Ads SDK Developers
Greetings, I'm tracking down a severe battery issue that we're experiencing with our app, which occurs while the app is in the background. Focusing on location activity, my methodology is as follows:

- Swizzle several `CLLocationManager` methods.
- Each time this gets called, log a detailed remote log. This log examines the stack trace and places blame on which party was responsible for which call. The full stack trace is also sent.
- Create a helper class that tracks how much a particular `CLLocationManager` instance goes between calling `startUpdatingLocation` & `stopUpdatingLocation`.

In my test over last week, I noticed that the GoogleMobileAdsSDK had an alarming amount of `CLLocationManager` activity in the background, asking for "best accuracy" (-1). It seems that once it got going, every minute it would call start & stop several times. Details below:

SDK version was: 7.28.0

This occurs when the user gives "Always Allow" location permission. This is not the only SDK that uses location in our app, in the background. Though I don't understand why the GoogleMobileAdSDK is using location in the background at all.

Across a 24 hour period:
`startUpdatingLocation` was called: 8238 times (with the string "GAD" present in the stack trace)
`startUpdatingLocation` was called: 13874 times (with the string "GAD" present in the stack trace)
For a calculated cumulative time of 26 mins, 2 secs

This is the stack trace for this call:
0   MyApp                              0x0000000102ecb5f8 _T08MyApp15GBLoggingHelperC23logLocationManagerEventySS_So010CLLocationG0C7managerSo8CLRegionCSg6regionSo8NSNumberCSg0L18MonitoringAccuracys10DictionaryVySSypGSg9extraDatatFZ + 2560
1   MyApp                              0x0000000102ecbf38 _T08MyApp15GBLoggingHelperC23logLocationManagerEventySS_So010CLLocationG0C7managerSo8CLRegionCSg6regionSo8NSNumberCSg0L18MonitoringAccuracys10DictionaryVySSypGSg9extraDatatFZTo + 324
2   MyApp                              0x000000010253b06c -[CLLocationManager(Swizzler) LocationManagerAnalyzer_startUpdatingLocation] + 196
3   MyApp                              0x0000000103705588 GADDispatchAsyncSafeMainQueue + 60
4   MyApp                              0x0000000103709d9c GADIsContentRenderedInView + 5612
5   MyApp                              0x000000010371d528 GADCategories_GADSlot_State + 5832
6   MyApp                              0x000000010371ce68 GADCategories_GADSlot_State + 4104
7   MyApp                              0x0000000103705588 GADDispatchAsyncSafeMainQueue + 60
8   MyApp                              0x000000010371cdc8 GADCategories_GADSlot_State + 3944
9   MyApp                              0x000000010371d028 GADCategories_GADSlot_State + 4552
10  Foundation                          0x0000000186777d24 __NSFireTimer + 88
11  CoreFoundation                      0x0000000185d2e92c <redacted> + 28
12  CoreFoundation                      0x0000000185d2e650 <redacted> + 864
13  CoreFoundation                      0x0000000185d2de50 <redacted> + 248
14  CoreFoundation                      0x0000000185d2ba38 <redacted> + 1928
15  CoreFoundation                      0x0000000185c4bfb8 CFRunLoopRunSpecific + 436
16  GraphicsServices                    0x0000000187ae3f84 GSEventRunModal + 100
17  UIKit                               0x000000018f2202e8 UIApplicationMain + 208
18  MyApp                              0x000000010253dbfc main + 76
19  libdyld.dylib                       0x000000018576e56c <redacted> + 4",

Details of this location manger settings:
"allowsBackgroundLocationUpdates": false,
"desiredAccuracy": -1,
"party": "google",
"distanceFilter": -1,
"activityType": "other",
"pausesLocationUpdatesAutomatically": true,
"showsBackgroundLocationIndicator": false


My app has the following "background activity modes":

<array>
 
<string>fetch</string>
 
<string>location</string>
 
<string>remote-notification</string>
</array>


For full detail on how time was calculated:

Code from Swizzled Objective C
```
- (void)LocationManagerAnalyzer_startUpdatingLocation {
    self.CLLocationManagerSwizzler_isUpdatingLocation = @(YES);


    [GBLoggingHelper logLocationManagerEvent:@"startUpdatingLocation"
                                     manager:self
                                      region:nil
                    regionMonitoringAccuracy:nil
                                   extraData:nil];


    [self LocationManagerAnalyzer_startUpdatingLocation];
}
```



Swift code that tracks location manager active time
```
// Tracking start and stops
static var activeLocationManagers = [CLLocationManager: Date]()


@objc static func logLocationManagerEvent(_ name: String,
                                              manager: CLLocationManager,
                                              region: CLRegion?,
                                              regionMonitoringAccuracy: NSNumber?,
                                              extraData: [String: Any]?) {
        var data = [String: Any]()
       
        if name.contains("startUpdatingLocation") {
            if activeLocationManagers[manager] == nil {
                activeLocationManagers[manager] = Date()
            }
        } else if name.contains("stopUpdatingLocation") {
            if let time = activeLocationManagers[manager] {
                let timeActive = Date().timeIntervalSince(time)
                data["timeActive"] = timeActive
                activeLocationManagers[manager] = nil
            }
        }
        // ...


        // data gets logged remotely
}
```

This is a snippet of the log for startUpdatingLocation & stopUpdatingLocation:

4/13 11:40:33: [google] start updating, accuracy: -1
4/13 11:40:33: [google] start updating, accuracy: -1
4/13 11:40:33: [google] start updating, accuracy: -1
4/13 11:40:33:   [google] stop updating. Time active: 0.13 seconds
4/13 11:40:33: [google] start updating, accuracy: -1
4/13 11:40:33:   [google] stop updating. Time active: 0.02 seconds
4/13 11:40:33: [google] start updating, accuracy: -1
4/13 11:40:33:   [google] stop updating. Time active: 0.04 seconds
4/13 11:41:33: [google] start updating, accuracy: -1
4/13 11:41:33: [google] start updating, accuracy: -1
4/13 11:41:33: [google] start updating, accuracy: -1
4/13 11:41:33:   [google] stop updating. Time active: 0.32 seconds
4/13 11:41:33: [google] start updating, accuracy: -1
4/13 11:41:33: [google] start updating, accuracy: -1
4/13 11:41:33:   [google] stop updating. Time active: 0.08 seconds
4/13 11:42:33: [google] start updating, accuracy: -1
4/13 11:42:33: [google] start updating, accuracy: -1
4/13 11:42:33:   [google] stop updating. Time active: 0.09 seconds
4/13 11:42:33: [google] start updating, accuracy: -1
4/13 11:42:33:   [google] stop updating. Time active: 0.03 seconds
4/13 11:42:33: [google] start updating, accuracy: -1
4/13 11:42:33: [google] start updating, accuracy: -1
4/13 11:42:33:   [google] stop updating. Time active: 0.06 seconds
4/13 11:43:33: [google] start updating, accuracy: -1
4/13 11:43:33: [google] start updating, accuracy: -1
4/13 11:43:33:   [google] stop updating. Time active: 0.13 seconds
4/13 11:43:33: [google] start updating, accuracy: -1
4/13 11:43:33: [google] start updating, accuracy: -1
4/13 11:43:33: [google] start updating, accuracy: -1
4/13 11:43:33:   [google] stop updating. Time active: 0.12 seconds
4/13 11:44:33: [google] start updating, accuracy: -1
4/13 11:44:33: [google] start updating, accuracy: -1
4/13 11:44:33:   [google] stop updating. Time active: 0.11 seconds
4/13 11:44:33: [google] start updating, accuracy: -1
4/13 11:44:33: [google] start updating, accuracy: -1
4/13 11:44:33: [google] start updating, accuracy: -1
4/13 11:44:33:   [google] stop updating. Time active: 0.11 seconds
4/13 11:45:33: [google] start updating, accuracy: -1
4/13 11:45:33: [google] start updating, accuracy: -1
4/13 11:45:33:   [google] stop updating. Time active: 1.07 seconds
4/13 11:45:33:   [google] stop updating. Time active: ??
4/13 11:45:33: [google] start updating, accuracy: -1
4/13 11:45:33: [google] start updating, accuracy: -1
4/13 11:45:33: [google] start updating, accuracy: -1
4/13 11:45:33:   [google] stop updating. Time active: 1.49 seconds
4/13 11:45:33:   [google] stop updating. Time active: ??
4/13 11:45:33:   [google] stop updating. Time active: ??
4/13 11:46:36: [google] start updating, accuracy: -1
4/13 11:46:36:   [google] stop updating. Time active: 0.17 seconds
4/13 11:46:36: [google] start updating, accuracy: -1
4/13 11:46:36:   [google] stop updating. Time active: 0.05 seconds
4/13 11:46:36: [google] start updating, accuracy: -1
4/13 11:46:36:   [google] stop updating. Time active: 0.05 seconds
4/13 11:46:36: [google] start updating, accuracy: -1
4/13 11:46:36:   [google] stop updating. Time active: 0.05 seconds
4/13 11:46:36: [google] start updating, accuracy: -1
4/13 11:46:36:   [google] stop updating. Time active: 0.03 seconds
4/13 11:47:33: [google] start updating, accuracy: -1
4/13 11:47:33:   [google] stop updating. Time active: 0.16 seconds
4/13 11:47:33: [google] start updating, accuracy: -1
4/13 11:47:33:   [google] stop updating. Time active: 0.15 seconds
4/13 11:47:33: [google] start updating, accuracy: -1
4/13 11:47:33:   [google] stop updating. Time active: 0.15 seconds
4/13 11:47:33: [google] start updating, accuracy: -1
4/13 11:47:33:   [google] stop updating. Time active: 0.30 seconds
4/13 11:47:33: [google] start updating, accuracy: -1
4/13 11:47:33:   [google] stop updating. Time active: 0.16 seconds
4/13 11:48:33: [google] start updating, accuracy: -1
4/13 11:48:33:   [google] stop updating. Time active: 0.15 seconds
4/13 11:48:33: [google] start updating, accuracy: -1
4/13 11:48:33:   [google] stop updating. Time active: 0.15 seconds
4/13 11:48:33: [google] start updating, accuracy: -1
4/13 11:48:33:   [google] stop updating. Time active: 0.17 seconds
4/13 11:48:33:   [google] stop updating. Time active: ??
4/13 11:48:33: [google] start updating, accuracy: -1
4/13 11:48:33:   [google] stop updating. Time active: 0.16 seconds
4/13 11:48:33: [google] start updating, accuracy: -1
4/13 11:48:43:   [google] stop updating. Time active: 0.15 seconds

I'm running another test with the latest version 7.30.0. I couldn't find any mention of this bug in the release notes.

Please advise, this is the highest priority item for our app, and as you can imagine is causing all sorts of frustrated users.

mobileadssdk-a...@google.com

unread,
Apr 24, 2018, 4:54:46 AM4/24/18
to Jared Egan, Google Mobile Ads SDK Developers
Hi Jared,

Thank you for bringing this to our attention and giving us a lot of helpful details.

Please note that as per guide, if a user has granted your app location permissions, location data is automatically passed to the SDK, however, you can opt to enable or disable location data for ads. That said, I implemented the CLLocationManagerDelegate events in our sample app and didn't receive any location updates via didUpdateLocations. Only when I called the startUpdatingLocation() method did I start receiving location update notifications continuously. However, you don't necessarily need to explicitly call the startUpdatingLocation() method in order to load ads via the Mobile Ads SDK. 

On the other hand, you mentioned that the Mobile Ads SDK is not the only SDK that is using the Location Manager in your app so it might be the other SDK that is triggering the behavior you described. That said, could you check if you can replicate the behavior you described in our sample apps?

Regards,
Ivan Bautista
Mobile Ads SDK Team

Jared Egan

unread,
Apr 24, 2018, 2:30:37 PM4/24/18
to Google Mobile Ads SDK Developers
Hey Ivan, thanks for the reply.

There are other SDKs in the app, yes. Given the stack trace, I don't see how another SDK could trigger this behavior in the Google SDK. It seems to me that the Google Mobile Ads SDK has an NSTimer on a 1 minute loop (or it resets it after it fires). For what it's worth, this was not a RELEASE configured build. Someone suggested a DEBUG build may screw up the stack trace, but I don't have much confidence that the config would really lead to this stack trace.

This log was created using the 7.28.0 version of the SDK. The release notes for 7.30.0 just say "Bug fixes and improvements". If someone could tell me there was a NSTimer & CLLocationManager bug that got fixed between 7.28 & 7.30, then I could sleep better at night.

I ran another test with my app and version 7.30 and did not see the issue. I may run another test with 7.28 to try and see it again. Thanks for the links, will look into those as well.

- Jared

Ram Parameswaran (Mobile SDK Team)

unread,
May 2, 2018, 3:31:00 PM5/2/18
to Google Mobile Ads SDK Developers
Hey Jared,

The GMA iOS SDK determines user location each time a ad request is sent out, including ad refreshes (which might explain the 1 minute behavior you're seeing). However, there was no change in location information collection between 7.28 and 7.30.

- Ram

Jared Egan

unread,
May 3, 2018, 1:54:46 PM5/3/18
to Google Mobile Ads SDK Developers
The CLLocationManager starts I mentioned in the log above happened in the background. The SDK shouldn't do that. Furthermore, we only use the SDK to make DFP requests, for which we specify the location explicitly in the request. We never call `configureWithApplicationID`. So I'm not sure why the SDK is collecting location at all. I just saw evidence of this same behavior in the latest version (7.30.0). I'm chasing down several leads on things that may be draining our user's battery in the background, these logs are definitely suspicious.

Is there a way to just disable this SDK from using location at all? I can't seem to find one in any of the headers.

- Jared

Jared Egan

unread,
May 8, 2018, 3:56:31 PM5/8/18
to Google Mobile Ads SDK Developers
Let me state my problem more succinctly:

While my app is in the background, the GoogleMobileAdsSDK is starting a CLLocationManager thousands of times, requesting the "best" accuracy. I believe this is one of the leading causes of bad battery blame that's being attributed to my app and leading bad app reviews and uninstalls. I believe this is a bug in the GoogleMobileAdsSDK.

I have provided a high amount of detail with this problem. I've spent a long time making sure my data is accurate. Is there a better place for me to report a bug? If I reproduce this from the sample app, will that result in some action being taken?

Besides all the detail in my original post, here is the full explanation of my methodology:

I've attached a txt file of the background activity the stack trace shows as belonging to the GoogleMobileAdsSDK.

Any response is appreciated.

- Jared
background_activity_google.txt
Reply all
Reply to author
Forward
0 new messages