Android OSは、それを保持しているアプリまたはサービスが殺された場合、Wakelockをリリースしますか?

StackOverflow https://stackoverflow.com/questions/4697873

質問

Wakelockについて質問があります。以下に示す場合、Android OSはWakelockをリリースします(PARTIAL_WAKE_LOCK Wakelockを防止するために、指定する必要がある場合)は、電源を切るまで(睡眠ではなく)電源を獲得し、バッテリーを浪費しました。

ケース1-A:
アプリは、スレッドの1つでWakelock(タイムアウトオプションを使用)を取得しました(この場合は合理的だと思います)。重要なタスクが終了したときにWakelockをリリースするように設計されています。アプリはTaskManagerまたは悪名高いTaskKillerによって殺される可能性があり、アプリはスレッドをWakelockをリリースする機会がありません。そのワークロックはどうなりますか?

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

ケース2-A:
(ブロードキャストレシーバーを介して)AlarmManagerによって開始されたサービスがあり、サービスがWakelock(タイムアウトオプション付き)を取得したサービスがあると想像してください。このサービスは、Wakelock-Acquired-Timeの最小にするように設計されています。しかし、残念ながら、Android OSはこのサービスを選択して、メモリクランチのために殺しました。 (Wakelockが買収されたときにOSがサービスを殺しないかどうかはわかりませんが、OSは気にしないと思います。しかし、OSが後でWakelockをリリースすることを願っています。)そのWakelockはどうなりますか?

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

役に立ちましたか?

解決

Wakelockの実装の概要

使用するとき pm.newWakeLock 新しいWakelockを作成するには、 PowerManager 新しいWakelockオブジェクトを作成して返すだけです。 Wakelockオブジェクトはバインダーオブジェクトではないため、複数のプロセスで使用することはできません。ただし、そのWakelockオブジェクトには、Mtokenという名前のバインダーオブジェクトが含まれています。

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

したがって、このwakelockオブジェクトでcaveを獲得またはリリースすると、実際にそのトークンをに渡します 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 私たちが前に述べたまさに触覚です。このメソッドは受信者を登録します( wakeLock)このバインダーが消えた場合の通知の場合。このバインダーオブジェクトが予期せずに消える場合(通常、そのホスティングプロセスが殺されたため)、 binderDied メソッドは受信者に呼び出されます。

ワークロックが入っていることに注意してください PowerManagerService ワークロックとは異なります 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(コードが登場する場所)では、それは真実です。さらに、wakelockクラスにファイナライズ方法があります PowerManager, 、しかし、これはあなたの質問の鍵ではありません。

他のヒント

Androidシステムは、殺されたプロセスのためにWakelocksを維持していないと思います(私は確かにこれを知りません)と思います。おそらく、Sigkillでプロセスを殺すと、そのプロセスが保持しているWakelockも削除します。

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top