Forum Xamarin.Android

Background location service on Android 7 - fighting with Doze and Alarmmanager

Hi everyone

A small intro
Really hope that some of you are willing to help me get this issue out of the way before I loose the rest of my hair.
I know that there are hundreds of posts out there regarding this issue but the more I read the more confused I get and no post concludes a final solution that works on all Android versions.
The only thing I can be sure of is that I tried almost every possible solution that I can think of and that I'm still not happy with the result.

What I'm trying to accomplish
I need a background service of some kind running on Android platform (old as well as new (7+)) that can get the device position by GPS and post it to my server. I need to have it run at a specific interval and I do not give a s... about battery optimization and Doze.

My setup:
Visual Studio 2015 with all the Xamarin addins etc. (On Windows 10)
HTC One M9 running Android 7.0

What I have tried so far
I started of by this example: https://developer.xamarin.com/samples/mobile/BackgroundLocationDemo/.
Download, Build, Deploy with USB cable on my phone. Worked fine.
Then i wrapped it in a BroadcastReceiver and using AlarmManager to schedule the Location updates so it would continue to run even if the app was closed. That also worked fine.
The main project setup is a MainActivity with some start/stop buttons, a BroadcastReceiver and a Location Service (ILocationListener).

Until I updated my phone (from Android 6.0 to 7.0) the AlarmManager worked fine by just initiating on intervals like so
alarmManager.SetRepeating(AlarmType.ElapsedRealtimeWakeup, ElapsedRealtime, interval, pendingIntent);
with interval setup to every about 4 minutes.
But after upgrading the phone to 7.0 it only fired up a few times (typically for about an hour) and then nothing - no data received on my webserver/webservice.

I then started reading up on Android Doze etc. and modified the code so that I now use the AlarmManager.setExactAndAllowWhileIdle - both on my main activity and when resetting the alarm everytime the BroadcastReceiver's OnReceive is hit
Here is the codecode:
override public void OnReceive(Context context, Intent intent)
{
// Start by set a new alarmtrigger
Intent alarmIntent = new Intent(context, Java.Lang.Class.FromType(typeof(AlarmReceiver)));
var pendingIntent = PendingIntent.GetBroadcast(context, 0, alarmIntent, 0);
AlarmManager alarmManager = (AlarmManager)context.GetSystemService(Context.AlarmService);
long triggerAtTime = SystemClock.ElapsedRealtime() + (4 * 60 * 1000);
alarmManager.SetExactAndAllowWhileIdle(AlarmType.ElapsedRealtimeWakeup, triggerAtTime, pendingIntent);

My problem is that as soon as I remove my phone from charging cable it doesn't wake from Doze and fires the alarm. It actually even stops working at some point even when it is plugged in. I added some logging info to the part of the code that sets the triggerAtTime and can see that everytime the BroadCastReceiver is triggered the new Alarm is scheduled as the first thing. But after the AlarmManager has been running a few times it is suddently just ignored and nothing happens.
So my experience is like this.
1. Starting the location updates by clicking "Start" on the main activity
2. First alarm is set to start within 5 seconds.
3. The BroadcastReceiver is hit and the new alarm is set (in 10 minutes, also working with 4 minutes and 20 minutes etc.)
4. The broadcastReceiver starts the locationservice and as soon as the device has GPS signal it sends of the location into to my webservice and shuts down.
5. After 10 minutes (exactly) the broadcastreceiver is hit again and the step 3,4,5 is repeating for about an hour. Then after that it stops. BroadcastReceiver isn't hit anymore. No change even if device is powered and keept alive.

I have read multiple times that SetExactAndAllowWhileIdle and SetAndAllowWhileIdle should be used for when the device is idle (in some Doze stage) but maybe I'm missing some permission settings or missed some key build target understanding etc.

Yesterday I tried using the WakefulBroadcastReceiver and StartWakefulService instead but the same issue applied - after about an hour of running smoothly the alarm i just ignored at some point. There are a lot of confusion regarding the 15 / 9 minute interval while using the SetExactAndAllowWhileIdle and I have tried every 20 minutes with the same result.

Main documentation on "SetExactAndAllowWhileIdle" here: https://developer.android.com/reference/android/app/AlarmManager.html#setExactAndAllowWhileIdle(int, long, android.app.PendingIntent)

My compile/target info is:
Compile using Android version: Android 7.0 (Nougat)
Minimum Android to target: Android 7.0 (API level 24 - Nougat)
Target Android version: Android 7.0 (API level 24 - Nougat)

I have tried to have the app running in both Debug and Release.
I have also tried putting the app in whitelist (Settings > Power > Poweroptimization).

At some point I know that it must be possible to have a background service running that cuts through Doze.
I tried downloading the EverTrack / CorvusGPS app which does exactly what I want and regardless of the device being powered or on battery this app keeps posting location updates every 10 minutes (exactly) no matter what (even on Android 7) so I know that it can be done.

If what I try to accomplish can be done in a different way please let me know but it needs to work in a reliable way so all answers that can get me in the right direction would be helpful. And please feel free to ask anything.

Thanks for reading all that and I look forward hearing from you.

Maybe the folks in Xamarin can post an example of a background location service that runs at an exact interval regardless of the device powersaving mode? I know a lot of developers out there would be happy.

Best regards Søren

Posts

  • If you leave the device for several hours, does the service come back at least once at some point? If not, maybe Doze's not the problem, since for what I'm reading it should have activity windows to get notifications and such every once in a while even during full Doze (or maybe this only applies for incoming notifications?).

    If the problem is indeed Doze .. Have you tried sending something from your server to the device? For what I've read, only high-priority notifications can get the device off of Doze, but for testing purposes you could send something from the server to see if it get's picked up by your service on the time window that's allowed for batch notifications.

  • SrenBjerreSrenBjerre USMember

    Hi Sebastian.

    I have tried keeping it running for days and it never comes back to life. It really seems like it just gets killed at some point and that the Alarmmanager alarm either isn't set at all or it's just ignored when the alarm goes off.
    As far as I can see in the logs the alarm is set (10 minutes after it goes off) every time but after about an hour it just stops. OnRecieve isn't called.

    The funny thing is that the service stops at some point even when it is connected to the charger and is kept alive (= screen on)

    I haven't tried sending notifications from the server to the device.

    After writing the original post I changed my focus to a foreground service which works fine and keeps running until I stop it, but I would still very much wan't this version to run as well so if any of you out there knows about a trick to keep a background service running please feel free to come forward with your knowledge.

  • EricBrunnerEricBrunner USMember ✭✭
    Hi

    I posted a similar issue here https://forums.xamarin.com/discussion/comment/278292#Comment_278292
    I could solve my case with running the service as a foreground service, aquire / release battery wakelocks and whitelist my app.

    Best
    Eric
Sign In or Register to comment.