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秒)を与えました。このタイムアウトオプションは有効に保たれていますか?
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メソッドがありますが、これはそうではありません。あなたの質問の鍵。
Androidシステムは強制終了されたプロセスのウェイクロックを保持しないと思います(これは確かにわかりません)。おそらく、sigkillを使用してプロセスを強制終了すると、それによって保持されているウェイクロックも削除されます。処理する。
そうでなければ、あなたが言うように、クラッシュは電話が常に起きていることにつながるでしょう、それは私が観察していませんでした。