Why is Network access in my geofence broadcast receiver unreliable?
Asked Answered
R

0

3

Use case:

When geofence triggers we need to contact server ASAP. We have solved this with an implicit BroadcastReceiver calling a Service for several years, but problematic in new versions due to Doze and Oreo background restrictions.

Attempted fixes:

  1. We moved geofence registering from implicit -> explicit broadcast receiver to get around the "background mode" restriction.

  2. We tried to do it as in Googles examples, i.e. the broadcast receiver calling enqueueWork() on a JobIntentService. The problem with this is that we often noticed a long "lag" between when the job was scheduled and when it actually ran. Our record is over one hour!

So, we instead tried to move all functionality into the BroadcastReceiver and use goAsync() to do the network call. (if you try to do the network operation synchronously you get a "no network from main thread" exception).

It works insofar that we can start a thread and it executes the code, but the network operation gives us trouble.


Problem:

So, our current solution, because of the above issues, is an explicit BroadcastReceiver, using goAsync() to do the server call.

However, the network call works very intermittently. We quite often get "java.net.SocketException: Socket is closed" errors. It is not a server issue, and it always works when called from our "regular" application code.

I am not sure why this happens, but I suspect Doze mode? Although, I am not sure how I can get that when the Receiver is actually called by the geofence trigger.

Questions:

  1. Does anyone know why the network operation would fail from our goAsync()? Again, the threading works, its just that we get socket errors on the actual network operation.

  2. Is there, in newer versions of Android, any way from a geofence trigger to make a network call directly, as we're trying to do, besides the things we've already tried?

Pointers and thoughts much appreciated!

Refulgent answered 10/9, 2018 at 11:58 Comment(11)
Lag is definitely Doze. Are you using a BroadcastReceiver at all? As of Android O, that's not required or desirable. Have the JobScheduler directly schedule to a JobIntentService. Since onHandleWork occurs on a thread, you can do networking there.Bide
If you look at the Google geofence example on GitHub, they use a BroadcastReceiver that calls a jobintentservice. I mention above why I try to avoid the jobintentservice, it takes too long time between the schedule and the execution. github.com/googlesamples/android-play-location/tree/master/…Refulgent
There's no reason to use the receiver at all. By removing it, you won't have a problem like that.Bide
@Refulgent I haven't tried this, but I wonder if using a SyncAdapter would work instead of goAsync in this case. I don't believe SyncAdapters are currently subject to Android O and P's background restrictions.Polariscope
@Michael, ok but I'd still have to invoke it from the broadcastreceiver, which means I'd still have to job-schedule it? Or do you mean I could invoke it as per the "old way"? Worth a shot I guessRefulgent
Have you tried checking PowerManager.isDeviceIdleMode() to see if Doze is active? Don't have an answer for you but I'm curious to know as well.Jemma
@Refulgent One thing I can think of that might exacerbate this issue is that when the geofence transition happens, this could be accompanied by a network transition from Wifi->LTE, or LTE->Wifi. So, it's possible that you won't be able to report the transition right away in which case you'll have to schedule a retry when the network is available again. Lots of corner cases to deal with when it comes to geofencing on Android, I'm afraid.Polariscope
@Refulgent Just passing on something I learned about trying to report a fence transition when the app is running on Android P and is in the RARE bucket. The RARE bucket throttles network activity to a window once every 24 hours. In order to bump out of the RARE bucket in order to report the transition over the network, you'll need to start a foreground service. In my case, I made an IntentService and start it normally if I'm on Android <= N and start in the foreground on Android >= O.Polariscope
@Michael. Thanks for feedback, that's what we ended up doing too. Only way to get it to excute within at least reasonable time-frame was via foreground service + notification...Refulgent
@Refulgent For me the foreground service + notification method seems to work. Not ideal, because a notification is shown for less than a second, but at least it works. Did you ever find a better solution or is this still the way to go?Carbonic
@Thomas, yeah we do the foreground shuffle... I don't know of anything better unfortunately.Refulgent

© 2022 - 2024 — McMap. All rights reserved.