Подтвердить что ты не робот

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

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