48 votes

Le système d'exploitation Android libère-t-il un wakelock si l'application ou le service qui le détient est tué ?

J'ai une question sur le wakelock. Dans les cas montrés ci-dessous, est-ce que le système d'exploitation Android libère le wakelock ( PARTIAL_WAKE_LOCK si vous devez le spécifier) pour éviter que le wakelock soit laissé acquis et gaspille la batterie jusqu'à la mise hors tension (pas en veille).

Cas 1-a :
L'application a acquis un wakelock (sans option de timeout) dans l'un de ses threads (veuillez penser que c'est raisonnable dans ce cas) et elle a été conçue pour libérer le wakelock lorsque la tâche critique est terminée. L'application peut être tuée par le taskmanager ou un taskkiller notoire, et l'application n'a aucune chance de laisser son thread libérer le wakelock. Qu'arrive-t-il à ce wakelock ?

Cas 1-b :
(Si la réponse au cas 1-a est "Oui, ne vous inquiétez pas", alors veuillez ignorer ce cas). Identique au cas 1-a mais l'application a donné une option de délai d'attente pour le wakelock, disons 3 secondes. Cette option de délai d'attente reste-t-elle valide ?

Cas 2-a :
Imaginez qu'un service a été lancé par AlarmManager (via un récepteur de diffusion) et que ce service a acquis un wakelock (sans option de temporisation). Ce service est conçu pour que le temps d'acquisition du wakelock soit minimal. Mais malheureusement, Android OS a choisi de tuer ce service à cause d'un manque de mémoire. (Je ne sais pas si le système d'exploitation ne tue pas le service lorsque le wakelock est acquis, mais je suppose qu'il s'en moque. Mais j'espère qu'OS libérera wakelock plus tard). Qu'arrive-t-il à ce wakelock ?

Cas 2-b :
(Si la réponse au cas 2-a est "Oui, ne vous inquiétez pas", alors veuillez ignorer ce cas). Identique au cas 2-a mais le service a donné une option de délai d'attente pour le wakelock, disons 3 secondes. Cette option de délai d'attente reste-t-elle valide ?

48voto

StarPinkER Points 6096

Aperçu de l'implémentation de WakeLock

Lorsque nous utilisons pm.newWakeLock pour créer un nouveau wakelock, l'option PowerManager crée simplement un nouvel objet WakeLock et retourne. L'objet WakeLock n'est pas un objet Binder, il ne peut donc pas être utilisé par plusieurs processus. Cependant, dans cet objet WakeLock, il contient un objet Binder nommé mToken.

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

Donc quand vous appelez acquire ou release sur cet objet WakeLock, il passe 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 PowerManagerService fonctionne lors de l'acquisition ou de 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'énoncé clé est le lock.linkToDeath(wakeLock, 0); . Ce lock est exactement le mToken que nous avons mentionné précédemment. Cette méthode permet d'enregistrer le destinataire (le wakeLock ) pour recevoir une notification si ce classeur disparaît. Si cet objet binder disparaît de manière inattendue (généralement parce que le processus qui l'héberge a été tué), l'objet binderDied sera appelée sur le destinataire.

Remarquez que le WakeLock dans PowerManagerService est différent du WakeLock dans PowerManager il s'agit d'une mise en œuvre de IBinder.DeathRecipient . Consultez donc son binderDied méthode.

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

El handleWakeLockDeath va libérer ce 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 de votre question, la réponse est de ne pas s'inquiéter. Au moins dans Android 4.2 (d'où provient le code), c'est vrai. De plus, il y a une méthode finalize sur la classe WakeLock en PowerManager mais ce n'est pas la clé de votre question.

6voto

Joseph Earl Points 11953

Je suppose (je n'en suis pas certain) que le système Android ne conserve pas les wakelocks pour les processus tués. Il est fort probable que lorsqu'il tue un processus avec sigkill, il supprime également tous les wakelocks détenus par ce processus.

Sinon, comme vous le dites, les accidents conduiraient à ce que le téléphone soit toujours éveillé, ce que je n'ai pas observé.

0voto

AndroidKid Points 3330

WakeLock est un moyen inefficace de garder l'écran allumé. Utilisez plutôt le WindowManager pour faire la magie. La ligne suivante suffira pour le WakeLock. La permission WakeLock est également nécessaire pour que cela fonctionne. Ce code est également plus efficace que le WakeLock.

getWindow().addFlags(LayoutParams.FLAG_KEEP_SCREEN_ON);

Vous n'avez pas besoin de libérer le WakeLock manuellement. Ce code permettra au système Android de gérer le verrouillage automatiquement. Lorsque votre application est au premier plan, le WakeLock est maintenu et le système Android libère le verrou automatiquement.

Il existe également d'autres types de verrous, vous pouvez en combiner quelques-uns avec celui-ci, pour améliorer la fonctionnalité. Dans vos 3 cas, le système Android va gérer la fonction wakeLock automatiquement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X