c# – Keep wifi active in foreground service after phone goes to sleep-ThrowExceptions

Exception or error:

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.

How to solve:

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.

Leave a Reply

Your email address will not be published. Required fields are marked *