Таймер не истекает точно во время сна в Android

Мы пытаемся реализовать таймер для собственного кода в Android. Таймер должен работать точно во время пробуждения и спящего режима. Когда таймер истекает, наш собственный код будет отправлять в сеть сообщения DPD (обнаружение мертвых узлов). Мы пробовали следующие подходы.

  1. Использование API-интерфейса Android Framework для диспетчера аварийных сигналов в коде пользовательского пространства и ниже приведены результаты:

    • This doesn't give the accurate results even during wake state for small timers like 2s,3s,5s.
    • Не работает именно для спящего режима тоже.
  2. Мы попытались использовать таймер ядра в коде пространства ядра, и ниже приведены результаты:

    • Works perfectly for wake state.
    • Но для таймеров состояния сна срок действия вообще не истекает. Когда мы пробуждаем устройство вручную, таймеры истекают. Итак, в заключение, таймеры ядра не работают в состоянии сна.

3. Использование блокировки пробуждения * Мы стараемся избегать использования блокировки пробуждения, так как это может привести к серьезным проблемам с производительностью.

PS - Реализация Ipsec с открытым исходным кодом strongswan отправляет сообщения DPD точное время даже в спящем режиме. Но похоже, что strongswan не использует блокировку пробуждения, поэтому мы все еще пытаемся выяснить, как это работает в спящем режиме. Любой, кто ищет ответ на этот вопрос вопрос, возможно, захочет изучить этот код.

Может ли кто-нибудь предложить что-то, чтобы решить эту проблему.


person somil    schedule 24.11.2017    source источник
comment
похоже, вам придется держать устройство частично бодрствующим, используя wakelock. Другого пути я думаю нет.   -  person Vladyslav Matviienko    schedule 24.11.2017
comment
Что вы имеете в виду под состоянием сна в Android?   -  person demo_Ashif    schedule 24.11.2017
comment
@ Влад Матвиенко Да, это последний вариант, но мы не знаем о его влиянии на энергопотребление. Вы знаете об этом?   -  person somil    schedule 30.11.2017


Ответы (3)


Когда Android переходит в спящий режим, у него будет несколько состояний, последнее — замораживание всех процессов и отключение процессора. В этом случае ваше время не будет стрелять. Вы должны создать событие, которое разбудит ядро ​​и установит блокировку пробуждения, чтобы процессор больше не выключался. Это можно сделать с помощью будильников Android.

person skoperst    schedule 21.12.2017

Единственный способ заставить таймер точно работать в спящем режиме — поддерживать устройство в частично бодрствующем состоянии с помощью Wakelock. Но убедитесь, что вашему приложению действительно нужен таймер, чтобы он работал все время, потому что в документе говорится:

Использование этого API значительно повлияет на срок службы батареи устройства. Не приобретайте PowerManager.WakeLocks, если они вам действительно не нужны, используйте минимально возможные уровни и обязательно выпускайте их как можно скорее.

Пройдите через класс PowerManager, используйте приведенный ниже код для получения частичной блокировки пробуждения.

  PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
  PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
  wl.acquire();
  ..cpu will stay on during this section..
  wl.release();
person Shree    schedule 23.12.2017

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

private int timeToStart;
private TimerState timerState;

 private static final int MAX_TIME = 60;  //Time length is 60 seconds

private enum TimerState {
    STOPPED,
    RUNNING

}


private void initTimer() {
    Log.e(TAG,"initTimer called");

    long startTime = mPrefs.getStartedTime(); //here mprefs is your shared preference manager
    if (startTime > 0) {
        timeToStart = (int) (MAX_TIME - (getNow() - startTime));
        if (timeToStart <= 0) {
            // TIMER EXPIRED
            onTimerFinish();
        } else {
            startTimer();
            timerState = TimerState.RUNNING;
        }
    } else {
        timeToStart = MAX_TIME;
        timerState = TimerState.STOPPED;
    }
}

    private long getNow() {
    Calendar rightNow = Calendar.getInstance();
    return rightNow.getTimeInMillis() / 1000;
}

    private void onTimerFinish() {
    Log.e(TAG,"onTimerFinish() called");

    timerState = TimerState.STOPPED;
    mPrefs.setStartedTime(0);
    timeToStart = MAX_TIME;

}

private void startTimer() {
    Log.e(TAG,"startTimer() called");

    countDownTimer = new CountDownTimer(timeToStart * 1000, 1000) {

        @Override
        public void onTick(long millisUntilFinished) {
            timeToStart -= 1;
        }

        @Override
        public void onFinish() {
            onTimerFinish();
        }
    }.start();
}

    public void setAlarmManager() {
    int wakeUpTime = (mPrefs.getStartedTime() + MAX_TIME) * 1000;
    AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(this, TimeReceiver.class);
    PendingIntent sender = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        am.setAlarmClock(new AlarmManager.AlarmClockInfo(wakeUpTime, sender), sender);
    } else {
        am.set(AlarmManager.RTC_WAKEUP, wakeUpTime, sender);
    }
}

    public void removeAlarmManager() {
    Intent intent = new Intent(this, TimeReceiver.class);
    PendingIntent sender = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
    AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    am.cancel(sender);
}

    @Override
    protected void onResume() {
    super.onResume();
        initTimer();
        removeAlarmManager();

}
person demo_Ashif    schedule 24.11.2017