Храните Wi-Fi в режиме ожидания перед тем, как телефон перейдет спать

Я хочу получать пакеты с Wi-Fi, когда мой телефон заблокирован. Проблема в том, что когда я блокирую свой экран, мой основной сервис перестает принимать пакеты. Я использую Foreground Service следующим образом:

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;
}

Я делаю следующее, чтобы убедиться, что он не убит:

  1. Запуск службы на переднем плане
  2. Использование StartCommandResult.Sticky
  3. Использование Wake Lock
  4. Использование Wifi Lock
  5. Установка WifiSleepPolicy на Never (у меня есть настройка в настройках моего телефона)
  6. Настройка ActionIgnoreBatteryOptimizationSettings в намерениях
  7. Переключение моего приложения с помощью командной строки adb во время отладки

Что еще мне не хватает? Я использую Samsung A5 с Android 6.0 - API 23.

Я просмотрел журналы из командной строки adb, и я проверил, что моя служба фактически работает как Foreground Service, и все блокировки хранятся.

Ответ 1

То, что вы делаете, просто здорово, все хорошо. Тем не мение!!

Давайте посмотрим на сообщение devleport.android.com:

Политики Google Play запрещают приложениям запрашивать прямое освобождение от функций управления питанием в Android 6. 0+ (Doze и App Standby), если не будет затронута основная функция приложения.

Вы заявили:

Я использую Samsung A5 с Android 6.0 - API 23.

Значит, вы не сможете сохранить свою функцию переднего плана, когда телефон перейдет в спящий режим, потому что основная функция приложения не пострадает.

Это причина, по которой вы заметили, что перестали получать пакеты, когда телефон спит.

пожалуйста, изучите всю ссылку, которую я приложил, а также руководство по управлению Power Manager.

Теперь я заметил, что кроме того:

Если пользователь покидает устройство, отключенное и неподвижное в течение определенного периода времени, при выключенном экране устройство переходит в режим Doze. В режиме "Дозирование" система пытается сохранить батарею , ограничив доступ приложений к сети и интенсивным нагрузкам. Он также запрещает приложениям получать доступ к сети и откладывает их работу, синхронизацию и стандартные аварийные сигналы.

Ограничения на дозу:

  • Доступ к сети приостановлен.
  • Система игнорирует блокировки слежения.
  • Стандартные тревоги AlarmManager (включая setExact() и setWindow()) откладываются до следующего окна обслуживания.
  • Если вам нужно установить аварийные сигналы, которые срабатывают во время Doze, используйте setAndAllowWhileIdle() или setExactAndAllowWhileIdle().
  • Аварийные сигналы, установленные с помощью setAlarmClock(), продолжают нормально срабатывать - система выходит из Doze незадолго до того, как эти аварийные сигналы срабатывают.
  • Система не выполняет сканирование Wi-Fi.
  • Система не позволяет запускать адаптеры синхронизации.
  • Система не позволяет запустить JobScheduler.

Это завершит мой ответ на все ваши запросы.

EDIT 2:

Я исследовал немного дальше, есть целый пост по этой проблеме в Xamarin.Android.

есть также решение разбудить телефон каждые 10 минут, чтобы обойти его здесь.