Почему система Android (6.0) блокирует сетевое соединение после ~1 часа в глубоком сне

У меня проблемы с режимом глубокого сна андроида после одного часа глубокого сна. Проблема возникает только на Android 6+. На Android <5 проблема не возникает. Не проверено с Android 5, потому что ни одно устройство не доступно.

Конфигурация устройства:
У меня есть два устройства Android 6, Google Nexus 5 и HTC One M9. Оба устройства настроены только как Wi-Fi (без SIM-карты), а политика Wi-Fi настроена как всегда (даже в спящем режиме).

Ситуация:
У меня есть бодрствующий широковещательный приемник, который зарегистрирован на AlarmManager.ELAPSED_REALTIME_WAKEUP, чтобы срабатывать каждые 2 минуты, когда приложение переходит в фоновый режим. Также блокировка Wi-Fi взимается, когда приложение приостановлено и выпущено, если приложение выходит на передний план.

Поскольку Android KitKat AlarmManager.setRepeating (...) не исчерпан, на Android 6 я использую AlarmManager.setWindow (...) с окном всего 1 секунды.
Каждый раз, когда получатель срабатывает, получатель (PendingIntent) снова перерегистрируется.

Получатель имеет простую работу. Он должен только вызвать вебурл (получить запрос). Разблокировка активируется после успешного выполнения запроса, истечения времени ожидания или возникновения исключения.

В манифесте также существует разрешение WAKE_LOCK.

Эта проблема:
Когда я помещаю приложение в фоновом режиме (приемник становится включенным) и затем выключаю экран, приемник вызывается правильно каждые 2 минуты, но через ~1 час сетевой запрос не выполняется.

Журнал показывает, что получатель вызывается также через 1 час, только сетевой запрос не выполняется.

Пример исходного кода:

public class TestTools {
    private static final String LOG_TAG = TestTools.class.getSimpleName();

    public static String excuteGet(String targetURL) {
        try {
            URL obj = new URL(targetURL);
            HttpURLConnection con = (HttpURLConnection) obj.openConnection();
            con.setRequestMethod("GET");
            con.setConnectTimeout(10*1000);
            con.setReadTimeout(5*1000);

            int responseCode = con.getResponseCode();
            Log.d(LOG_TAG, "GET Response Code :: " + responseCode);

            if (responseCode == HttpURLConnection.HTTP_OK) { // success
                BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
                String inputLine;
                StringBuilder response = new StringBuilder();

                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }
                in.close();

                // print result
                Log.d(LOG_TAG, response.toString());

                return response.toString();
            } else {
                Log.d(LOG_TAG, String.format("GET request not worked (response code :: %s)", responseCode));
            }
        }
        catch (ProtocolException e) {
            Log.d(LOG_TAG, "ProtocolException: " + e.getMessage());
        }
        catch (MalformedURLException e) {
            Log.d(LOG_TAG, "MalformedURLException: " + e.getMessage());
        }
        catch (IOException e) {
            Log.d(LOG_TAG, "IOException: " + e.getMessage());
        }

        return null;
    }

}

public class Receiver extends WakefulBroadcastReceiver {
    @Override
    public void onReceive(final Context context, final Intent intent) {
        Log.d(LOG_TAG, "onReceive");

        final Thread test = new Thread(new Runnable() {
            @Override
            public void run() {
                TestTools.excuteGet("http://www.google.de/");
            }
        });
        test.start();

        try {
            test.join();
        } catch (InterruptedException e) {
            Log.d(LOG_TAG, e.getMessage());
        }

        // here the receiver is reregistered

        WakefulBroadcastReceiver.completeWakefulIntent(intent);
    }
}

У вас есть идея, что идет не так и как это исправить?


Обновление: чтобы приложение работало в режиме ожидания Android, вам необходимо установить этот https://developer.android.com/training/monitoring-device-state/doze-standby.html

1 ответ

Решение

но через ~1 час сетевой запрос не выполняется

Предположительно, устройство перешло в режим Doze.

У вас есть идея, что идет не так?

С точки зрения пользователя и с точки зрения Android ничего не происходит неправильно. Все работает как положено.

Пожалуйста, поймите, что режим Doze был добавлен специально, чтобы запретить разработчикам делать то, что вы пытаетесь сделать. Выполнение сетевых операций ввода-вывода каждые две минуты очень плохо для батареи. Слишком много разработчиков не заботятся о пользователях и батареях этих пользователей, и поэтому Android забирает контроль у этих разработчиков, чтобы помочь пользователям.

как это исправить?

Во многом нечего исправить. Опять же, все работает в соответствии со спецификациями. Возможно, вам придется скорректировать свои ожидания.

Теперь, если пользователь считает, что пользователь хочет, чтобы ваше приложение потребляло больше батареи, он может добавить ваше приложение в белый список оптимизации батареи. Это в меню "Настройки"> "Приложения"> (значок шестеренки на панели действий) > "Игнорировать оптимизацию батареи". Любое приложение, для которого установлено "игнорировать оптимизацию батареи", будет вести себя как старые устройства.

Пользователь также может держать свое устройство на зарядном устройстве; во время зарядки устройство не перейдет в режим ожидания.

Другие вопросы по тегам