21

I want to receive packets from wifi when my phone is locked. The problem is that when I lock my screen, my foreground service stops receiving packets. I'm using Foreground Service like this:

public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
    var notification = new Notification.Builder(this)
        .SetContentTitle(Resources.GetString(Resource.String.app_name))
        .SetContentText(Resources.GetString(Resource.String.notification_text))
        .SetSmallIcon(Resource.Drawable.ic_stat_name)
        .SetContentIntent(BuildIntentToShowMainActivity())
        .SetOngoing(true)
        .AddAction(BuildRestartTimerAction())
        .AddAction(BuildStopServiceAction())
        .Build();


    // Enlist this instance of the service as a foreground service
    StartForeground(Constants.SERVICE_RUNNING_NOTIFICATION_ID, notification);

    /*DO THIS EVEN WHEN SCREEN IS LOCKED*/

    var powerManager = (PowerManager)GetSystemService(PowerService);
    _wakeLock = powerManager.NewWakeLock(WakeLockFlags.Partial, "WakeLockTag");
    _wakeLock.Acquire();

    var wifiManager = (WifiManager)GetSystemService(WifiService);
    _wifiLock = wifiManager.CreateWifiLock(WifiMode.FullHighPerf, "xamarin_wifi_lock");
    _wifiLock.Acquire();

    if (!powerManager.IsIgnoringBatteryOptimizations("com.xamarin.xample.foregroundservicedemo") ||
        !_wakeLock.IsHeld || !_wifiLock.IsHeld)
        throw new InvalidOperationException("OPTIMIZATIONS NOT ACTIVE");

    string msg = timestamper.GetFormattedTimestamp();
    Log.Debug(TAG, msg);
    Intent intent = new Intent(Constants.NOTIFICATION_BROADCAST_ACTION);
    intent.SetAction(Android.Provider.Settings.ActionIgnoreBatteryOptimizationSettings);
    intent.PutExtra(Constants.BROADCAST_MESSAGE_KEY, msg);
    LocalBroadcastManager.GetInstance(this).SendBroadcast(intent);
    Task.Run(() =>
    {
        using (var client = new UdpClient(12345))
        {
            while (true)
            {
                var result = client.ReceiveAsync().Result;
                Console.WriteLine($"RECEIVED: {result.Buffer.Length}");
            }
        }
    });

    return StartCommandResult.Sticky;
}

I'm doing the following things to make sure it is not killed:

  1. Starting Foreground Service
  2. Using StartCommandResult.Sticky
  3. Using Wake Lock
  4. Using Wifi Lock
  5. Setting WifiSleepPolicy to Never (I have it setup in my phone settings)
  6. Setting ActionIgnoreBatteryOptimizationSettings in intent
  7. Whitelisting my app through adb command prompt while debugging

What else am I missing? I am using Samsung A5 with Android 6.0 - API 23.

I looked into logs from adb command prompt and I checked that my service is in fact running as Foreground Service and all locks are held.

Zaren Wienclaw
  • 181
  • 4
  • 15
FCin
  • 3,804
  • 4
  • 20
  • 49
  • Full-time services on Android are coming to an end, but you can use a *foregrounded* service for now. – SushiHangover Aug 04 '18 at 10:06
  • @SushiHangover I used Foreground service and it stops after ~1 second when screen goes off. – FCin Aug 04 '18 at 10:06
  • @SushiHangover I need something that works until user closes the app, but it must work when screen is off. – FCin Aug 04 '18 at 10:10
  • Then you need to apply for a wake lock on the device (of course that does not mean that certain OEM's version will not doze your app, the user might have to manually whitelist it in Settings), otherwise using something like WorkManager is the future as it will use AlarmManager, JobScheduler, Firebase JobDispatcher, etc... depending upon the API level, but of course that is time/task-based, not a continuously running service. – SushiHangover Aug 04 '18 at 10:30
  • @SushiHangover I tried adding WakeLock to my foreground service, but with no luck. Can you take a look? I updated my question. – FCin Aug 04 '18 at 11:28
  • [This answer](https://stackoverflow.com/a/32150246) is I believe what you’re looking for. There is an option in settings where users can choose not to optimize specific apps and will disable doze for those particular apps, I believe that’s what the answer does. But please be careful that someone mentioned in the comments that it got their app suspended from google play without notice. Let me know if this helps. – Mr.O Aug 09 '18 at 10:30
  • @Mr.O Thanks, I already have battery optimizations turned off in my phone. That's why I have this check: `powerManager.IsIgnoringBatteryOptimizations`. – FCin Aug 09 '18 at 10:33

1 Answers1

5

What you're doing is just great, all is good. However!!

Let us take a look at devleport.android.com's post:

Google Play policies prohibit apps from requesting direct exemption from Power Management features in Android 6.0+ (Doze and App Standby) unless the core function of the app is adversely affected.

You stated:

I am using Samsung A5 with Android 6.0 - API 23.

Meaning, you won't be able to keep your foreground service when the phone goes to sleep because the core function of the app is not adversely affected.

This the reason why you notice you stopped receiving packets when the phone is asleep.

please explore the entire link I attached and also us the Power Manager guide.

edit: I now noticed that furthermore:

If a user leaves a device unplugged and stationary for a period of time, with the screen off, the device enters Doze mode. In Doze mode, the system attempts to conserve battery by restricting apps' access to network and CPU-intensive services. It also prevents apps from accessing the network and defers their jobs, syncs, and standard alarms.

Doze restrictions:

  • Network access is suspended.
  • The system ignores wake locks.
  • Standard AlarmManager alarms (including setExact() and setWindow()) are deferred to the next maintenance window.
  • If you need to set alarms that fire while in Doze, use setAndAllowWhileIdle() or setExactAndAllowWhileIdle().
  • Alarms set with setAlarmClock() continue to fire normally — the system exits Doze shortly before those alarms fire.
  • The system does not perform Wi-Fi scans.
  • The system does not allow sync adapters to run.
  • The system does not allow JobScheduler to run.

This will conclude my answer to all of your queries.

EDIT 2:

I investigated a little further, there is an entire post regarding this issue in Xamarin.Android.

there is also a solution to wake the phone every 10 minutes to bypass it here.

Barr J
  • 10,636
  • 1
  • 28
  • 46
  • There must be a workaround for this, because I have applications installed on the same phone that are able to perform wifi activities when screen is locked. – FCin Aug 06 '18 at 11:54
  • you will have to dig deeper in developer.android.com because for now, the only possibility for you is to try and deactivate the power saving feature of Doze, in fact, investigate those apps and check if power saving is enabled while you use them. – Barr J Aug 06 '18 at 11:57
  • I will try to check what features these applications deactivate, but I don't really know what to look for. I disabled battery optimizations. I whitelisted the application. What other power saving features are there that can cause "dozing"? Also the core of my application is affected by this issue. My app is 100% focused on streaming through wifi. – FCin Aug 06 '18 at 12:03
  • 1
    I will play with this once I get back home, but my worry is that it will run every 10 minutes and doze in 10 seconds and I need continuous stream without breaks longer than ~500ms. – FCin Aug 06 '18 at 12:17
  • So I tried it, but this solution works only for phones that doze after >10 mins. Mine dozes after a couple of seconds, so this is not very useful to me unfortunately. Although I checked `isDeviceIdleMode ` and it always returns `false` for me, so maybe my phone has some different mode instead of doze? – FCin Aug 06 '18 at 16:02
  • Doze shoudln't kick in if you are using a Foreground service and you are showing a sticky notification for it. – Cheesebaron Aug 08 '18 at 06:19
  • @Cheesebaron I can see that my Foreground Service is running and if I just write code to print "Hello World" in it, then it works when I turn the screen off. The problem is that when I write code to e.g. receive packages from wifi, then it stops the second I turn the screen off. So it looks like the phone blocks wifi, but doesn't stop Foreground Service. – FCin Aug 08 '18 at 06:32
  • @BarrJ Did you ever try using the solution mentioned in edit 2? If yes did it work out for you? – FreakyAli Apr 02 '19 at 11:08
  • Solution 2 works but considered as a lot of.. let's call it, Chasing after your tail. You have to deal wilth many events in the process: `OnTimeEvent`, `OnStartCommand`, `OnCreate`. My point is, that it works but it hold behind great development and testing work. – Barr J Apr 03 '19 at 05:03