42

J'ai une question à propos de wakelock. Dans les cas indiqués ci-dessous, le système d'exploitation Android libère wakelock (PARTIAL_WAKE_LOCK si vous avez besoin de spécifier) ​​pour empêcher le wakelock a été laissé acquis et gaspillage de la batterie jusqu'à la mise hors tension (pas de veille).Le système d'exploitation Android libère-t-il un wakelock si l'application ou le service qui le détient est tué?

Cas 1-a:
App a acquis wakelock (w/o option de délai d'attente) dans l'un de ses fils (s'il vous plaît pense qu'il est raisonnable dans ce cas) et il a été conçu pour libérer wakelock lorsque la tâche critique était fini. App peut être tué par taskmanager ou taskkiller notoire, et l'application n'a aucune chance de laisser son thread libérer wakelock. Qu'arrive-t-il à ce wakelock?

Cas 1-b:
(. Si la réponse à 1 cas-un est "Oui, ne vous inquiétez pas", alors s'il vous plaît ignorer ce cas) Identique au cas 1-a, mais l'application a donné l'option délai d'attente wakelock, disons 3 secondes. Cette option de temporisation est-elle maintenue valide?

Cas n ° 2-a:
S'il vous plaît imaginer il y a un service qui a été lancé par AlarmManager (via le récepteur de radiodiffusion) et le service a acquis une wakelock (w/o option de délai d'attente). Ce service est conçu pour rendre le minimum acquis par wakelock. Mais malheureusement, Android OS a choisi ce service pour tuer en raison de la crise de la mémoire. (Je ne sais pas si OS ne va pas tuer le service quand wakelock est acquis, mais je suppose que le système d'exploitation ne s'en soucie pas, mais j'espère que le système d'exploitation sortira wakelock plus tard.) Qu'advient-il de ce wakelock?

Cas n ° 2-b:
(. Si la réponse au cas 2-a: "Oui, ne vous inquiétez pas", alors s'il vous plaît ignorer ce cas) Identique au cas 2-un, mais le service a donné l'option délai d'attente wakelock, disons 3 secondes. Cette option de temporisation est-elle maintenue valide?

Répondre

43

WakeLock Présentation de l'implémentation

Lorsque nous utilisons pm.newWakeLock pour créer une nouvelle wakelock, le PowerManager crée simplement un nouvel objet WakeLock et retourne. L'objet WakeLock n'est pas un objet liant, il ne peut donc pas être utilisé via plusieurs processus. Toutefois, dans cet objet WakeLock, il contient un objet Binder nommé mToken.

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

Ainsi, lorsque vous appelez acquérir ou libérer sur cet objet WakeLock, il passe en réalité ce jeton à PowerManagerService.

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

Regardez comment fonctionne PowerManagerService lors de l'acquisition ou la libération d'un wakelock vous aidera à répondre à votre question.

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

L'instruction clé est lock.linkToDeath(wakeLock, 0);. Ce lock est exactement le mToken que nous avons mentionné auparavant. Cette méthode enregistre le destinataire (le wakeLock) pour une notification si ce classeur disparaît.Si cet objet de classeur disparaît de façon inattendue (généralement parce que son processus d'hébergement a été supprimé), la méthode binderDied est appelée sur le destinataire.

Notez que le WakeLock dans PowerManagerService est différent du WakeLock dans PowerManager, il est une implémentation de IBinder.DeathRecipient. Donc, consultez sa méthode binderDied.

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

Le handleWakeLockDeath dégagera que 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(); 
    } 
} 

Donc, je pense que dans les deux cas dans votre question, la réponse est ne vous inquiétez pas. Au moins dans Android 4.2 (d'où vient le code), c'est vrai. En outre, il existe une méthode finalize sur la classe WakeLock dans PowerManager, mais ce n'est pas la clé de votre question.

+4

Merci pour votre réponse détaillée et claire à cette question de 2 ans. Votre réponse aide définitivement de nombreux développeurs, y compris moi. – Tomcat

+1

Avec plaisir, je ne sais pas pourquoi cette vieille question a sauté à la toute première place de la liste des questions triées par intéressant. @Matou – StarPinkER

6

Je suppose (je ne sais pas avec certitude) que le système Android ne conserve pas les wakelocks pour les processus tués. Très probablement quand il tue un processus avec sigkill, il supprime également les wakelocks détenus par ce processus. Sinon, comme vous le dites, les pannes conduiraient le téléphone à être toujours éveillé, ce que je n'ai pas observé.

+0

Cela me semble raisonnable. Je suppose que tu as raison. J'espère que SDK décrit clairement ce comportement. – Tomcat

+0

J'ai également trouvé timeout pour wakelock a bug [link] http://code.google.com/p/android/issues/detail?id=14184 donc nous ne pouvons pas l'utiliser de manière efficace. (J'ai essayé avec OS2.2 et échoué, puis Google conduit à ce lien.) – Tomcat

+1

Un test simple serait de faire une application qui définit un écran de garde sur wakelock, puis avoir un bouton dans l'application qui provoque intentionnellement un FC. Ensuite, attendez et voyez si l'écran s'éteint ou non. –

Questions connexes