Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keep wifi active in foreground service after phone goes to sleep

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.

like image 986
FCin Avatar asked Aug 04 '18 10:08

FCin


1 Answers

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.

like image 82
Barr J Avatar answered Oct 22 '22 13:10

Barr J