42

Ho una domanda su wakelock. Nei casi illustrati di seguito, il sistema operativo Android rilascia wakelock (PARTIAL_WAKE_LOCK se è necessario specificare) per impedire che wakelock sia stato acquisito e sprecare batteria fino allo spegnimento (non in modalità di sospensione).Il sistema operativo Android rilascia un wakelock se l'app o il servizio che lo contiene viene ucciso?

Caso 1-a:
App ha acquisito Wakelock (w/opzione di timeout o) in uno dei thread (si prega di pensare che è ragionevole in questo caso) ed è stato progettato per rilasciare Wakelock quando compito critico era finito. L'app può essere uccisa dal task manager o dal famigerato taskkiller e l'app non ha alcuna possibilità di rilasciare il suo thread wakelock. Cosa succede a quel wakelock?

Caso 1-b:
opzione di timeout (Se la risposta al caso 1-a è "Sì, non ti preoccupare", quindi si prega di ignorare questo caso.) Stesso caso 1-a, ma ha dato app per wakelock, diciamo 3 secondi. L'opzione di timeout è valida?

Caso 2-a:
Si prega di immaginare c'è un servizio che è stato avviato da AlarmManager (tramite ricevitore broadcast) e il servizio ha acquisito una Wakelock (w/opzione di timeout o). Questo servizio è progettato per rendere minimo il tempo acquisito da wakelock. Sfortunatamente, il sistema operativo Android ha scelto questo servizio per uccidere a causa di problemi di memoria. (Non so se il sistema operativo non ucciderà il servizio quando wakelock verrà acquisito, ma suppongo che il sistema operativo non gli importi, ma spero che il SO rilascerà wakelock più tardi.) Cosa succede a quel wakelock?

Caso 2-b:
opzione di timeout (Se la risposta al caso 2-a è "Sì, non ti preoccupare", quindi si prega di ignorare questo caso.) Stesso caso 2-a, ma il servizio ha dato per wakelock, diciamo 3 secondi. L'opzione di timeout è valida?

risposta

43

Wakelock Attuazione Panoramica

Quando usiamo pm.newWakeLock per creare un nuovo Wakelock, il PowerManager crea semplicemente un nuovo oggetto Wakelock e ritorna. L'oggetto WakeLock non è un oggetto binder, quindi non può essere utilizzato attraverso più processi. Tuttavia, in quell'oggetto WakeLock, contiene un oggetto Binder chiamato mToken.

WakeLock(int flags, String tag) { 
     mFlags = flags; 
     mTag = tag; 
     mToken = new Binder(); 
    } 

Così, quando si chiama acquisire o rilasciare su questo oggetto Wakelock, in realtà passa che token per PowerManagerService.

private void acquireLocked() { 
     if (!mRefCounted || mCount++ == 0) { 
      mHandler.removeCallbacks(mReleaser); 
      try { 
       mService.acquireWakeLock(mToken, mFlags, mTag, mWorkSource); 
      } catch (RemoteException e) { 
      } 
      mHeld = true; 
     } 
    } 

Guardate come PowerManagerService opere durante l'acquisizione o il rilascio di una Wakelock vi aiuterà a rispondere alla tua domanda.

void acquireWakeLockInternal(IBinder lock, int flags, String tag, WorkSource ws, 
     int uid, int pid) { 
    synchronized (mLock) { 
     ... 
     WakeLock wakeLock; 
     int index = findWakeLockIndexLocked(lock); 
     if (index >= 0) { 
      ... 
      // Update existing wake lock. This shouldn't happen but is harmless. 
      ... 
     } else { 
      wakeLock = new WakeLock(lock, flags, tag, ws, uid, pid); 
      try { 
       lock.linkToDeath(wakeLock, 0); 
      } catch (RemoteException ex) { 
       throw new IllegalArgumentException("Wake lock is already dead."); 
      } 
      notifyWakeLockAcquiredLocked(wakeLock); 
      mWakeLocks.add(wakeLock); 
     } 
     ... 
    } 
    ... 
} 

La frase chiave è lock.linkToDeath(wakeLock, 0);. Quello lock è esattamente il moken che abbiamo menzionato prima. Questo metodo registra il destinatario (wakeLock) per una notifica se questo raccoglitore scompare.Se questo oggetto legatore scompare inaspettatamente (in genere perché il processo di hosting è stato interrotto), il metodo binderDied verrà richiamato sul destinatario.

Si noti che il WakeLock in PowerManagerService è diverso da WakeLock in PowerManager, è un'implementazione di IBinder.DeathRecipient. Quindi controlla il suo metodo binderDied.

@Override 
    public void binderDied() { 
     PowerManagerService.this.handleWakeLockDeath(this); 
    } 

Il handleWakeLockDeath rilascerà che Wakelock.

private void handleWakeLockDeath(WakeLock wakeLock) { 
    synchronized (mLock) { 
     ... 
     int index = mWakeLocks.indexOf(wakeLock); 
     if (index < 0) { 
      return; 
     } 

     mWakeLocks.remove(index); 
     notifyWakeLockReleasedLocked(wakeLock); 

     applyWakeLockFlagsOnReleaseLocked(wakeLock); 
     mDirty |= DIRTY_WAKE_LOCKS; 
     updatePowerStateLocked(); 
    } 
} 

Quindi penso in entrambi i casi nella tua domanda, la risposta è non preoccuparti. Almeno in Android 4.2 (da dove viene il codice), è vero. Inoltre, esiste un metodo finalize sulla classe WakeLock in PowerManager, ma questa non è la chiave della tua domanda.

+4

Grazie per la tua risposta dettagliata e chiara a questa domanda di 2 anni. La tua risposta sicuramente aiuta molti sviluppatori, incluso me. – Tomcat

+1

Con piacere, non so perché questa vecchia domanda è saltata al primo posto della lista delle domande ordinata per interesse. @Tomcat – StarPinkER

6

Suppongo (non lo so per certo) che il sistema Android non mantenga i wakelock per i processi uccisi. Molto probabilmente quando uccide un processo con sigkill, rimuove anche i wakelock trattenuti da quel processo.

In caso contrario, come dici tu, gli arresti anomali porterebbero il telefono a essere sempre sveglio, cosa che non ho osservato.

+0

Mi sembra ragionevole. Credo che tu abbia ragione. Spero che SDK descriva chiaramente questo comportamento. – Tomcat

+0

Ho anche trovato il timeout per wakelock ha un bug [link] http://code.google.com/p/android/issues/detail?id=14184 quindi non possiamo usarlo in modo efficiente. (L'ho provato con OS2.2 e non è riuscito, quindi Google ha indirizzato a quel collegamento.) – Tomcat

+1

Un semplice test è la creazione di un'applicazione che imposta una schermata di mantenimento su wakelock, quindi un pulsante nell'app che causa intenzionalmente un FC. Quindi aspetta e vedi se lo schermo si spegne o no. –

Problemi correlati