【问题标题】:Does the Android OS release a wakelock if the app or service holding it is killed?如果持有它的应用程序或服务被杀死,Android 操作系统是否会释放唤醒锁?
【发布时间】:2011-06-09 12:46:00
【问题描述】:

我对唤醒锁有疑问。在下面显示的情况下,android OS 是否会释放唤醒锁(PARTIAL_WAKE_LOCK,如果您需要指定)以防止获取唤醒锁并在关闭电源(非睡眠)之前浪费电池。

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

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

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

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

【问题讨论】:

    标签: android android-source wakelock kill-process android-wake-lock


    【解决方案1】:

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

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

    【讨论】:

    • 对我来说这听起来很合理。我猜你是对的。我希望 SDK 清楚地描述这种行为。
    • 我还发现唤醒锁超时有错误 [link]code.google.com/p/android/issues/detail?id=14184 所以我们不能有效地使用它。 (我用 OS2.2 尝试过,但失败了,然后谷歌找到了那个链接。)
    • 一个简单的测试是制作一个在唤醒锁上设置保持屏幕的应用程序,然后在应用程序中有一个按钮,它会故意导致 FC。然后就等着看屏幕是否关闭。
    【解决方案2】:

    WakeLock 实施概述

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

        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 在获取或释放唤醒锁时的工作方式将帮助您回答您的问题。

    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 方法。

    注意PowerManagerService 中的WakeLock 与PowerManager 中的WakeLock 不同,它是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(代码来自哪里)中,这是真的。此外,PowerManager 中的 WakeLock 类有一个 finalize 方法,但这不是您问题的关键。

    【讨论】:

    • 感谢您对这个已有 2 年历史的问题的详细、清晰的回答。您的回答肯定对包括我在内的许多开发者有所帮助。
    • 高兴地,我不知道为什么这个老问题会跳到按有趣排序的问题列表的第一位。 @Tomcat
    猜你喜欢
    • 2015-05-14
    • 2011-09-13
    • 1970-01-01
    • 2015-05-12
    • 1970-01-01
    • 1970-01-01
    • 2016-01-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多