Dozeについて気づいたこと
バッテリーステータスについて調査をしていた時についでにDozeについても確認してみたところ、Android14では自分が知っている挙動とは異なることに気づきました
Doze | |
---|---|
Android13 | ![]() |
Android14 | ![]() |
2台のデバイスを横に並べて同様に動かしたので、操作によってこのような違いが出てるとは考えられません。少なくとも結果からAndroid 14でDozeの挙動が大きく変わっていることは間違いなさそうです
リファレンスも読んでみたのですが、言及されておらず原因不明
なんだこりゃ
調べてみる
わかったこととしては、以下の通り
Deep-Doze
- DeepDozeとLightDozeは並列で実行されている
- DeepDozeは以下の流れでステートが遷移されている
- STATE_ACTIVE :アクティブ状態
- STATE_INACTIVE :非アクティブ (画面OFF、物理的に動いていない)
- STATE_IDLE_PENDING :次のスリープまで待機
- STATE_SENSING :センサー検知中
- STATE_LOCATING :現在地を特定中
- STATE_IDLE :スリープ状態
- STATE_IDLE_MAINTENANCE :一時的にスリープ状態を抜ける
- DeepDozeはSTATE_INACTIVEから下の状態を指しているよう
Light-Doze
- LightDozeは以下の流れでステートが遷移されている
- LIGHT_STATE_ACTIVE :デバイスは現在アクティブです
- LIGHT_STATE_INACTIVE :非アクティブ (画面OFF)
- LIGHT_STATE_PRE_IDLE :現在の作業が終わるまで一時的なスリープ状態
- LIGHT_STATE_IDLE:スリープ状態
- LIGHT_STATE_WAITING_FOR_NETWORK :ネット接続を待機
- LIGHT_STATE_IDLE_MAINTENANCE:一時的にスリープから抜ける
- LightDozeはLIGHT_STATE_INACTIVEから下の状態を指しているよう
AOSP読んでみる
調べてみたものの、やはり言及されている記事は見当たらなかったので上記の知識を踏まえてコードを確認してみる
DeepDoze編
はじめにDeep-Dozeについて確認していく
デバイスが使われている状態(STATE_ACTIVE)から非アクティブ状態(STATE_INACTIVE)へ遷移する該当コードは以下の通り
ここは 13と 14で多少差はあるが、今回の主題に関係がない改修だった
@GuardedBy("this")
void becomeInactiveIfAppropriateLocked() {
verifyAlarmStateLocked();
~~ 中略 ~~
if (mDeepEnabled) {
if (mQuickDozeActivated) {
~~ 中略 ~~
} else if (mState == STATE_ACTIVE) {
moveToStateLocked(STATE_INACTIVE, "no activity");
resetIdleManagementLocked();
long delay = mInactiveTimeout;
if (shouldUseIdleTimeoutFactorLocked()) {
delay = (long) (mPreIdleFactor * delay);
}
if (isUpcomingAlarmClock()) {
// If there's an upcoming AlarmClock alarm, we won't go into idle, so
// setting a wakeup alarm before the upcoming alarm is futile. Set the idle
// alarm to after the upcoming AlarmClock alarm.
scheduleAlarmLocked(
mAlarmManager.getNextWakeFromIdleTime() - mInjector.getElapsedRealtime()
+ delay);
} else {
scheduleAlarmLocked(delay);
}
}
}
if (mLightState == LIGHT_STATE_ACTIVE && mLightEnabled) {
moveToLightStateLocked(LIGHT_STATE_INACTIVE, "no activity");
resetLightIdleManagementLocked();
scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,
mConstants.FLEX_TIME_SHORT, true);
}
}
アクティブ状態(STATE_ACTIVE)であった場合、非アクティブ状態へと遷移させ、scheduleAlarmLocked(delay)
でアラームをかけてDeepDoze状態へ入るようにしている
scheduleAlarmLocked
のコードも念のため載せておく
@GuardedBy("this")
@VisibleForTesting
void scheduleAlarmLocked(long delay) {
if (DEBUG) Slog.d(TAG, "scheduleAlarmLocked(" + delay + ", " + stateToString(mState) + ")");
if (mUseMotionSensor && mMotionSensor == null
&& mState != STATE_QUICK_DOZE_DELAY
&& mState != STATE_IDLE
&& mState != STATE_IDLE_MAINTENANCE) {
// If there is no motion sensor on this device, but we need one, then we won't schedule
// alarms, because we can't determine if the device is not moving. This effectively
// turns off normal execution of device idling, although it is still possible to
// manually poke it by pretending like the alarm is going off.
// STATE_QUICK_DOZE_DELAY skips the motion sensing so if the state is past the motion
// sensing stage (ie, is QUICK_DOZE_DELAY, IDLE, or IDLE_MAINTENANCE), then idling
// can continue until the user interacts with the device.
return;
}
mNextAlarmTime = SystemClock.elapsedRealtime() + delay;
if (mState == STATE_IDLE) {
mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
} else if (mState == STATE_LOCATING) {
// Use setExact so we don't keep the GPS active for too long.
mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
} else {
if (mConstants.USE_WINDOW_ALARMS) {
mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mNextAlarmTime, mConstants.FLEX_TIME_SHORT,
"DeviceIdleController.deep", mDeepAlarmListener, mHandler);
} else {
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
}
}
}
注目していただきたい点としては、この時のアラームの間隔は long delay = mInactiveTimeout;
であるということだ
この時delayで用いられているmInactiveTimeout
について遡っていくと13 と14 で大きな違いがある
mInactiveTimeout
Android13
Android13では以下の通りである
mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
/**
* This is the time, after becoming inactive, at which we start looking at the
* motion sensor to determine if the device is being left alone. We don't do this
* immediately after going inactive just because we don't want to be continually running
* the motion sensor whenever the screen is off.
* @see #KEY_INACTIVE_TIMEOUT
*/
public long INACTIVE_TIMEOUT = DEFAULT_INACTIVE_TIMEOUT;
private static final long DEFAULT_INACTIVE_TIMEOUT =(30 * 60 * 1000L) / (!COMPRESS_TIME ? 1 : 10);
以上から短くて3分。最長で30分であることがわかる
Android14
Android14では以下のようである
mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
/**
* This is the time, after becoming inactive, at which we start looking at the
* motion sensor to determine if the device is being left alone. We don't do this
* immediately after going inactive just because we don't want to be continually running
* the motion sensor whenever the screen is off.
* @see #KEY_INACTIVE_TIMEOUT
*/
public long INACTIVE_TIMEOUT = DEFAULT_INACTIVE_TIMEOUT;
private static final long DEFAULT_INACTIVE_TIMEOUT =(30 * 60 * 1000L) / (!COMPRESS_TIME ? 1 : 10);
private void initDefault() {
~~中略~~
mDefaultInactiveTimeout = getTimeout(
res.getInteger(com.android.internal.R.integer.device_idle_inactive_to_ms),
mDefaultInactiveTimeout);
private long getTimeout(long defTimeout, long compTimeout) {
return (!COMPRESS_TIME || defTimeout < compTimeout) ? defTimeout : compTimeout;
}
<!-- Default for DeviceIdleController.Constants.INACTIVE_TIMEOUT -->
<integer name="device_idle_inactive_to_ms">60000</integer>
getTimeoutのコードから
- COMPRESS_TIME が false または defTimeout < compTimeout の場合
- defTimeout を返す
- COMPRESS_TIME が true かつ defTimeout >= compTimeout の場合
- compTimeout を返す
defTimeoutは常に1分であり、compTimeoutの値は最小でも3分であることから、常にdefTimeout(1分)を返す
したがって、常に1分である
DeepDoze編 結論
Android13 | Android14 | |
---|---|---|
long | 30min | 1min |
short | 3min | 1min |
Android13では状況によって3~30分の時間でDeepDozeに入る仕様であったが、Android14では常に1分でDeepDozeへ入るように変更が加えられていた
開発者が望んだ挙動かどうかは定かではないが、1分後に速攻でDeepDozeかかるのは不便という他ない
LightDoze編
LightDozeについても同様にみていく
先ほどのbecomeInactiveIfAppropriateLockedの
scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,mConstants.FLEX_TIME_SHORT, true);
が該当箇所
=編集中…=