Выпускает ли ОС Android функцию wakelock, если приложение или служба, в которой он находится, уничтожена? - PullRequest
46 голосов
/ 15 января 2011

У меня вопрос по поводу wakelock. В случаях, показанных ниже, освобождает ли ОС Android функцию wakelock (PARTIAL_WAKE_LOCK, если необходимо указать), чтобы предотвратить оставление wakelock, приобретенного и разряжающего аккумулятор до отключения питания (не сна).

Дело 1-а:
Приложение приобрело функцию wakelock (без тайм-аута) в одном из своих потоков (пожалуйста, подумайте, что в этом случае это целесообразно), и оно было разработано для освобождения wakelock после завершения критической задачи. Приложение может быть убито TaskManager или пресловутым TaskKiller, и приложение не может позволить своему потоку освободить wakelock. Что происходит с этим wakelock?

Дело 1-b:
(Если ответом на вопрос 1-а является «Да, не волнуйтесь», пожалуйста, проигнорируйте этот случай.) То же, что и в случае 1-а, но приложение дало возможность тайм-аута, например, на 3 секунды. Этот параметр времени ожидания остается действительным?

Дело 2-а:
Пожалуйста, представьте, что есть служба, которая была запущена AlarmManager (через широковещательный приемник), и служба приобрела функцию wakelock (без тайм-аута). Этот сервис предназначен для того, чтобы сделать минимальное время, необходимое для бодрствования. Но, к сожалению, ОС Android выбрала этот сервис, чтобы убить из-за нехватки памяти. (Я не знаю, будет ли ОС уничтожать службу при получении wakelock, но я думаю, что OS не заботится. Но я надеюсь, что ОС выпустит wakelock позже.) Что происходит с этим wakelock?

Дело 2-б:
(Если ответ на вопрос 2-а - «Да, не волнуйтесь», пожалуйста, проигнорируйте этот случай.) То же, что и в случае 2-а, но служба дала возможность тайм-аута, например, на 3 секунды. Этот параметр времени ожидания остается действительным?

Ответы [ 2 ]

47 голосов
/ 28 апреля 2013

Обзор реализации WakeLock

Когда мы используем pm.newWakeLock для создания нового wakelock, PowerManager просто создает новый объект WakeLock и возвращает. Объект WakeLock не является объектом связывания, поэтому его нельзя использовать в нескольких процессах. Однако в этом объекте WakeLock он содержит объект Binder с именем mToken.

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

Поэтому, когда вы вызываете acqu или release для этого объекта WakeLock, он фактически передает этот токен PowerManagerService.

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

Посмотрите, как работает PowerManagerService, когда приобретение или освобождение от вейк-блокировки поможет вам ответить на ваш вопрос.

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

Ключевым утверждением является lock.linkToDeath(wakeLock, 0);. Это lock как раз тот mToken, о котором мы упоминали ранее. Этот метод регистрирует получателя (wakeLock) для уведомления, если этот переплет исчезает. Если этот объект связывания неожиданно исчезнет (обычно из-за того, что его хост-процесс был уничтожен), то для получателя будет вызван метод binderDied.

Обратите внимание, что WakeLock в PowerManagerService отличается от WakeLock в PowerManager, это реализация IBinder.DeathRecipient. Так что проверь его binderDied метод.

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

handleWakeLockDeath освободит этот будильник.

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

Так что я думаю, что в обоих случаях в вашем вопросе ответ не волнуйтесь. По крайней мере, в Android 4.2 (откуда взялся код) это правда. Более того, в классе WakeLock есть метод finalize в PowerManager, но это не ключ к вашему вопросу.

6 голосов
/ 05 апреля 2011

Я бы предположил (я не знаю это наверняка), что система Android не хранит блокировку для убитых процессов.Скорее всего, когда он убивает процесс с помощью sigkill, он также удаляет любые wakelocks, удерживаемые этим процессом.

В противном случае, как вы говорите, сбой приведет к тому, что телефон всегда будет активен, чего я не наблюдал.

...