如果持有它的应用程序或服务被杀死,Android 操作系统是不是会释放唤醒锁?

Posted

技术标签:

【中文标题】如果持有它的应用程序或服务被杀死,Android 操作系统是不是会释放唤醒锁?【英文标题】: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 秒。这个超时选项是否保持有效?

【问题讨论】:

【参考方案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

以上是关于如果持有它的应用程序或服务被杀死,Android 操作系统是不是会释放唤醒锁?的主要内容,如果未能解决你的问题,请参考以下文章

Android:如果任务管理器杀死,则重新调用应用程序

Android,前台服务让app保持活力吗?

Firebase 云消息服务 - 即使应用程序被杀死也能接收通知

android (Service & PhoneStateListener) - 当应用程序被任务管理器、杀手或内存不足杀死时,服务确实重新启动但不工作

应用程序被杀死时Android后台服务正在重新启动

Android:在应用程序被杀死后从小部件中查找服务是不是正在运行