Android OSは、それを保持しているアプリまたはサービスが殺された場合、Wakelockをリリースしますか?
-
11-10-2019 - |
質問
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も削除します。
そうでなければ、あなたが言うように、クラッシュは電話が常に目を覚ましていることにつながりますが、私はそれを観察していません。