48

我对唤醒锁有疑问。在下面显示的情况下,android 操作系统是否释放唤醒锁(PARTIAL_WAKE_LOCK如果您需要指定)以防止唤醒锁被获取并浪费电池直到关闭电源(不是睡眠)。

案例 1-a:
应用程序在其中一个线程中获得了唤醒锁(无超时选项)(请认为在这种情况下是合理的),并且它旨在在关键任务完成时释放唤醒锁。App 可以被 taskmanager 或臭名昭著的 taskkiller 杀死,并且 app 没有机会让其线程释放唤醒锁。那个唤醒锁会发生什么?

案例 1-b:(
如果案例 1-a 的回答是“是的,不用担心”,那么请忽略此案例。)与案例 1-a 相同,但应用程序为唤醒锁定提供了超时选项,例如 3 秒。此超时选项是否保持有效?

案例 2-a:
请想象有一个由 AlarmManager(通过广播接收器)启动的服务,并且该服务已获得唤醒锁(无超时选项)。该服务旨在使唤醒锁获取时间最短。但不幸的是,由于内存紧张,Android OS 选择了这个服务来杀死。(我不知道操作系统在获取唤醒锁时是否不会终止服务,但我猜操作系统不在乎。但我希望操作系统稍后会释放唤醒锁。)那个唤醒锁会发生什么?

案例 2-b:(
如果案例 2-a 的回答是“是的,不用担心”,那么请忽略此案例。)与案例 2-a 相同,但服务为唤醒锁定提供了超时选项,例如 3 秒。此超时选项是否保持有效?

4

2 回答 2

49

WakeLock 实现概述

当我们使用pm.newWakeLock创建一个新的唤醒锁时,PowerManager只需创建一个新的 WakeLock 对象并返回。WakeLock 对象不是 binder 对象,因此不能通过多个进程使用。但是,在该 WakeLock 对象中,它包含一个名为 mToken 的 Binder 对象。

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

因此,当您在此 WakeLock 对象上调用 acquire 或 release 时,它​​实际上将该令牌传递给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如果此活页夹消失,此方法会为通知的接收者 (the) 注册。如果这个 binder 对象意外消失(通常是因为它的宿主进程已被杀死),那么该binderDied方法将在接收者上调用。

请注意,WakeLock in 与 WakeLock inPowerManagerService不同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,但这不是您问题的关键。

于 2013-04-28T01:28:29.880 回答
6

我会假设(我不确定)Android系统不会为被杀死的进程保留唤醒锁。最有可能的是,当它使用 sigkill 杀死一个进程时,它也会删除该进程持有的任何唤醒锁。

否则,正如您所说,崩溃会导致手机始终处于唤醒状态,我没有观察到。

于 2011-04-05T07:54:26.817 回答