Таймерът не изтича точно по време на състояние на заспиване в Android

Опитваме се да внедрим таймер за собствен код в android. Таймерът трябва да работи точно по време на режим на събуждане и заспиване. Когато таймерът изтече, нашият собствен код ще изпрати DPD (Dead peer detection) съобщения до мрежата. Опитахме следните подходи.

  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. Използване на wake lock *Опитваме се да избегнем използването на wake lock, тъй като може да причини значителни проблеми с производителността

P.S - Реализацията на 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 Class, използвайте кода по-долу, за да придобиете частично заключване за активиране

  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