Выпускает ли ОС Android wakelock, если приложение или служба, удерживающая его, убиты?

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

Случай 1-a:
Приложение приобрело wakelock (без опции тайм-аута) в одном из своих потоков (пожалуйста, подумайте, что это разумно в этом случае), и он был разработан, чтобы освободить wakelock, когда критическая задача была завершена. Приложение может быть убито taskmanager или пресловутый taskkiller, и приложение не имеет никаких шансов, чтобы его поток освободить wakelock. Что происходит с этой блокировкой?

Случай 1-b:
(Если ответ на случай 1-a "Да, не волнуйтесь", то, пожалуйста, проигнорируйте этот случай.) То же, что и в случае 1-A, но приложение дало опцию тайм-аута wakelock, скажем, 3 секунды. Этот параметр тайм-аута действителен?

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

случай 2-b:
(Если ответ на случай 2-a "Да, не волнуйтесь", то, пожалуйста, проигнорируйте это случай.) То же, что и в случае 2-a, но служба дала опцию тайм-аута wakelock, скажем, 3 секунды. Этот параметр тайм-аута действителен?

2 ответов


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

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

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

поэтому, когда вы вызываете acquire или 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 работает при приобретении или выпуске wakelock поможет вам ответить на ваш вопрос.

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) для уведомления, если эта папка исчезнет. Если этот объект binder неожиданно исчезает (как правило, потому, что его процесс размещения был убит), то binderDied способ будет сделать звонил получателю.

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

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

на handleWakeLockDeath выпустит этот 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();
    }
}

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


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

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