web-dev-qa-db-ja.com

Android OSは、それを保持しているアプリまたはサービスが強制終了された場合、ウェイクロックを解放しますか?

Wakelockについて質問があります。以下に示す場合、Android OSリリースwakelock(PARTIAL_WAKE_LOCK指定する必要がある場合)ウェイクロックを取得したままにして、電源をオフにするまで(スリープではなく)バッテリーを浪費するのを防ぎます。

ケース1-a:
アプリはスレッドの1つでwakelock(タイムアウトオプションなし)を取得し(この場合は妥当だと考えてください)、重要なタスクが終了したときにwakelockを解放するように設計されています。アプリはタスクマネージャーまたは悪名高いタスクキラーによって強制終了される可能性があり、アプリはスレッドにウェイクロックを解放させる機会がありません。そのウェイクロックはどうなりますか?

ケース1-b:
(ケース1-aの答えが「はい、心配しないでください」の場合は、このケースを無視してください。)ケース1-aと同じですが、アプリはwakelockにタイムアウトオプション(たとえば3秒)を与えました。このタイムアウトオプションは有効に保たれていますか?

ケース2-a:
AlarmManagerによって(ブロードキャストレシーバーを介して)開始されたサービスがあり、そのサービスがwakelock(タイムアウトオプションなし)を取得したと想像してください。このサービスは、wakelockの取得時間を最小限に抑えるように設計されています。しかし、残念ながら、Android OSは、メモリ不足のためにこのサービスを強制終了しました(wakelockが取得されたときにOSがサービスを強制終了しないかどうかはわかりませんが、OSは気にしないと思います) 。しかし、OSが後でwakelockをリリースすることを願っています。)そのwakelockはどうなりますか?

ケース2-b:
(ケース2-aの答えが「はい、心配しないでください」の場合は、このケースを無視してください。)ケース2-aと同じですが、サービスはwakelockにタイムアウトオプション(たとえば3秒)を与えました。このタイムアウトオプションは有効に保たれていますか?

48
Tomcat

WakeLock実装の概要

_pm.newWakeLock_を使用して新しいwakelockを作成すると、PowerManagerは単に新しいWakeLockオブジェクトを作成して戻ります。 WakeLockオブジェクトはバインダーオブジェクトではないため、複数のプロセスで使用することはできません。ただし、その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)を登録します。このバインダーオブジェクトが予期せず消えた場合(通常、そのホスティングプロセスが強制終了されたため)、受信者で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メソッドがありますが、これはそうではありません。あなたの質問の鍵。

47
StarPinkER

Androidシステムは強制終了されたプロセスのウェイクロックを保持しないと思います(これは確かにわかりません)。おそらく、sigkillを使用してプロセスを強制終了すると、それによって保持されているウェイクロックも削除されます。処理する。

そうでなければ、あなたが言うように、クラッシュは電話が常に起きていることにつながるでしょう、それは私が観察していませんでした。

6
Joseph Earl