Android 8.1 Doze模式分析(三)——Deep Doze模式

article/2025/9/15 10:39:24

概述

Deep Doze,也就是Android的Doze模式了,表示深度Doze,比起LightDoze,它将进行更多的限制:无法进行网络访问和 GPS/WLAN 扫描、唤醒被忽略、闹钟和作业/同步被延迟。当然,它的触发条件也将更加苛刻:灭屏、未充电、静止。

因此,如果要支持DeepDoze,则相应设备还必须具有大幅度动作检测器 (SMD),否则,无法探测到到底是静止还是移动。

原理

DIC中也定义了七个用来表示Deep Doze模式的值:

//表示doze模式
private int mState;
//mState值,表示设备处于活动状态
private static final int STATE_ACTIVE = 0;
//mState值,表示设备处于不交互状态,灭屏、静止
private static final int STATE_INACTIVE = 1;
//mState值,表示设备刚结束不交互状态,等待进入IDLE状态
private static final int STATE_IDLE_PENDING = 2;
//mState值,表示设备正在感应动作
private static final int STATE_SENSING = 3;
//mState值,表示设备正在定位
private static final int STATE_LOCATING = 4;
//mState值,表示设备处于空闲状态,也即Doze模式
private static final int STATE_IDLE = 5;
//mState值,表示设备正处于Doze模式,紧接着退出Doze进入维护状态
private static final int STATE_IDLE_MAINTENANCE = 6;

和Light Doze一样,DeepDoze模式也从becomeInactiveIfAppropriateLocked()方法开始,这点已经在分析LightDoze时分析了,这里再来看一遍,该方法中涉及到Doze模式的代码如下:

void becomeInactiveIfAppropriateLocked() {if ((!mScreenOn && !mCharging) || mForceIdle) {if (mState == STATE_ACTIVE && mDeepEnabled) {//Doze模式状态由ACTIVE变为INACTIVEmState = STATE_INACTIVE;//重置Doze模式相关标记值、定时器resetIdleManagementLocked();//设置一个30mins的定时scheduleAlarmLocked(mInactiveTimeout, false);//30mins}.......................
}

当DeepDoze处于活动状态,并且Doze模式可用时,会通过Alarm一步步进入IDLE状态。首先会由交互状态变为不交互状态时,会重置所有数据后发送一个定时Alarm操作,重置操作如下:

void resetIdleManagementLocked() {mNextIdlePendingDelay = 0;mNextIdleDelay = 0;//下次LightDoze的定时时间mNextLightIdleDelay = 0;//取消DeepDoze发送的定时AlarmcancelAlarmLocked();//取消用于STATE_SENSING状态时长的AlarmcancelSensingTimeoutAlarmLocked();//取消GPS定位和Generic定位的更新cancelLocatingLocked();//取消、解绑接收传感器的触发事件stopMonitoringMotionLocked();//停止检测器检测mAnyMotionDetector.stop();
}

重置后会重新设置一个定时Alarm,时长为15分钟,代码如下:

void scheduleAlarmLocked(long delay, boolean idleUntil) {if (mMotionSensor == null) {//如果没有运动传感器,则返回,因为无法判断设备是否保持静止if (mMotionSensor == nullr) {return;}//设置DeepDoze的定时AlarmmNextAlarmTime = SystemClock.elapsedRealtime() + delay;if (idleUntil) {mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);} else {mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);}
}

当到达定时后,回调mDeepAlarmListener的onAlarm()方法,该方法如下:

void scheduleAlarmLocked(long delay, boolean idleUntil) {if (mMotionSensor == null) {//如果没有运动传感器,则返回,因为无法判断设备是否保持静止if (mMotionSensor == nullr) {return;}//设置DeepDoze的定时AlarmmNextAlarmTime = SystemClock.elapsedRealtime() + delay;if (idleUntil) {mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);} else {mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);}
}

当到达定时后,回调mDeepAlarmListener的onAlarm()方法,该方法如下:

private final AlarmManager.OnAlarmListener mDeepAlarmListener= new AlarmManager.OnAlarmListener() {@Overridepublic void onAlarm() {synchronized (DeviceIdleController.this) {///每次Doze状态转换都会在该方法中进行stepIdleStateLocked("s:alarm");}}
};

stepIdleStateLocked()方法中会通过Alarm在不同的阶段流转,该方法如下:

void stepIdleStateLocked(String reason) {final long now = SystemClock.elapsedRealtime();//说明1小时内有Alarm定时时间到,暂不进入IDLE状态,30min后再进入if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {if (mState != STATE_ACTIVE) {//将当前设备变为活动状态,LightDoze和DeepDoze都为Active状态becomeActiveLocked("alarm", Process.myUid());becomeInactiveIfAppropriateLocked();}return;}switch (mState) {case STATE_INACTIVE://启动SensorstartMonitoringMotionLocked();//设置STATE_IDLE_PENDING状态时长的定时Alarm,30minsscheduleAlarmLocked(mConstants.IDLE_AFTER_INACTIVE_TIMEOUT,false);// Reset the upcoming idle delays.mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;//5minsmNextIdleDelay = mConstants.IDLE_TIMEOUT;//60mins//此时状态变为PENDING状态mState = STATE_IDLE_PENDING;break;case STATE_IDLE_PENDING://此时状态变为SENSING状态mState = STATE_SENSING;//设置STATE_SENSING状态超时时长的定时Alarm,DEBUG?1:4minsscheduleSensingTimeoutAlarmLocked(mConstants.SENSING_TIMEOUT);//取消通用位置更新和GPS位置更新cancelLocatingLocked();mNotMoving = false;mLocated = false;mLastGenericLocation = null;mLastGpsLocation = null;//开始检测是否有移动mAnyMotionDetector.checkForAnyMotion();break;case STATE_SENSING://取消用于STATE_SENSING状态超时时长的AlarmcancelSensingTimeoutAlarmLocked();//此时状态变为LOCATINGmState = STATE_LOCATING;//设置STATE_LOCATING状态时长的AlarmscheduleAlarmLocked(mConstants.LOCATING_TIMEOUT, false);//DEBUG?15:30//请求通用位置if (mLocationManager != null&& mLocationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {mLocationManager.requestLocationUpdates(mLocationRequest,mGenericLocationListener, mHandler.getLooper());mLocating = true;} else {mHasNetworkLocation = false;}//请求GPS位置if (mLocationManager != null&& mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {mHasGps = true;mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5,mGpsLocationListener, mHandler.getLooper());mLocating = true;} else {mHasGps = false;}//如果true,则break,因为在Location的Listener中会进入下一个状态,//否则进入下一步状态if (mLocating) {break;}// Otherwise, we have to move from locating into idle maintenance.case STATE_LOCATING://取消DeepDoze的AlarmcancelAlarmLocked();//取消位置更新cancelLocatingLocked();//Sensor停止检测mAnyMotionDetector.stop();case STATE_IDLE_MAINTENANCE://设置STATE_IDLE状态时长的定时Alarm,到时后将退出IDLE状态scheduleAlarmLocked(mNextIdleDelay, true);//设置下次IDLE时间mNextIdleDelay = (long)(mNextIdleDelay * mConstants.IDLE_FACTOR);if (mNextIdleDelay < mConstants.IDLE_TIMEOUT) {mNextIdleDelay = mConstants.IDLE_TIMEOUT;}mState = STATE_IDLE;//进入DeepDoze的IDLE后,覆盖LightDozeif (mLightState != LIGHT_STATE_OVERRIDE) {mLightState = LIGHT_STATE_OVERRIDE;//取消LightDoze的定时AlarmcancelLightAlarmLocked();}//申请wakelock保持CPU唤醒mGoingIdleWakeLock.acquire();//handler中处理idle状态后各个模块的限制工作mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);break;case STATE_IDLE:mActiveIdleOpCount = 1;//表示现在有正在活动的操作//申请wakelock锁保持cpu唤醒mActiveIdleWakeLock.acquire();//设置STATE_IDLE_MAINTENANCE状态时长的定时Alarm,//到时后将退出维护状态scheduleAlarmLocked(mNextIdlePendingDelay, false);mMaintenanceStartTime = SystemClock.elapsedRealtime();mNextIdlePendingDelay = Math.min(mConstants.MAX_IDLE_PENDING_TIMEOUT,(long)(mNextIdlePendingDelay * mConstants.IDLE_PENDING_FACTOR));if (mNextIdlePendingDelay < mConstants.IDLE_PENDING_TIMEOUT) {mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;}mState = STATE_IDLE_MAINTENANCE;//Handler中处理退出idle状态进入维护状态后取消限制的工作mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);break;}
}

整个方法比较繁琐,具体作用都在代码中进行了注释,这样可能比较好理解点,这里再说明一点,由于设备是根据灭屏、设备静止来决定是否进入DeepDoze模式的,这其中有关于Sensor、AnyMotionDector相关逻辑,因此太细节的步骤就不分析了。

这里我们再根据上述方法分析,当DeepDoze进入IDLE状态时,通过Handler对网络、JobScheduler等进行限制的逻辑,Handler中DeepDoze进入IDLE状态和LightDoze进入IDLE状态的实现都在一个代码块中,在分析LightDoze时已经分析了大部分,这里删减只保留DeepDoze相关进行分析:

case MSG_REPORT_IDLE_ON:
case MSG_REPORT_IDLE_ON_LIGHT: {
.......................................deepChanged = mLocalPowerManager.setDeviceIdleMode(true);try {mNetworkPolicyManager.setDeviceIdleMode(true);mBatteryStats.noteDeviceIdleMode(msg.what == MSG_REPORT_IDLE_ON? BatteryStats.DEVICE_IDLE_MODE_DEEP: BatteryStats.DEVICE_IDLE_MODE_LIGHT, null, Process.myUid());} catch (RemoteException e) {}if (deepChanged) {getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);}
.......................................
} break;

DeepDoze进入IDLE状态时,Handler中做了三件事:

  • 1.通知PMS、NetworkPolicyManager中DeepDoze处于IDLE状态。
  • 2.BatteryStatsService中开始统计。
  • 3.发送Intent为mIdleIntent的广播。

其中第一点就可以进行网络的限制。再来看看第三点,mIdIntent如下:

mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY| Intent.FLAG_RECEIVER_FOREGROUND);

接受该广播的模块有如图所示这么多:
这里写图片描述

涉及模块有:JobScheduler,GNSS,UsageStatsService,Wifi,这些模块收到广播后,进行相应操作,从而对各自的功能进行限制。

再来看看当DeepDoze退出IDLE状态进入维护状态(matinenance)时的相关操作,和进入IDLE时的操作恰好相反,部分代码如下:

case MSG_REPORT_IDLE_OFF: {........................................final boolean deepChanged = mLocalPowerManager.setDeviceIdleMode(false);try {mNetworkPolicyManager.setDeviceIdleMode(false);mBatteryStats.noteDeviceIdleMode(BatteryStats.DEVICE_IDLE_MODE_OFF,null, Process.myUid());} catch (RemoteException e) {}if (deepChanged) {incActiveIdleOps();getContext().sendOrderedBroadcastAsUser(mIdleIntent, UserHandle.ALL,null, mIdleStartedDoneReceiver, null, 0, null, null);}........................................} break;

整个DeepDoze的原理就是这样。

1.如何忽略唤醒锁?

在进入DeepDoze Idle状态时有:

final boolean deepChanged = mLocalPowerManager.setDeviceIdleMode(true);

进入PowerManagerService中:

@Override
public boolean setDeviceIdleMode(boolean enabled) {return setDeviceIdleModeInternal(enabled);
}boolean setDeviceIdleModeInternal(boolean enabled) {synchronized (mLock) {if (mDeviceIdleMode == enabled) {return false;}mDeviceIdleMode = enabled;updateWakeLockDisabledStatesLocked();}return true;
}

再来看updateWakeLockDisabledStatesLocked()方法:


private void updateWakeLockDisabledStatesLocked() {boolean changed = false;final int numWakeLocks = mWakeLocks.size();for (int i = 0; i < numWakeLocks; i++) {final WakeLock wakeLock = mWakeLocks.get(i);if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)== PowerManager.PARTIAL_WAKE_LOCK) {//更新wakelock.disableif (setWakeLockDisabledStateLocked(wakeLock)) {changed = true;if (wakeLock.mDisabled) {// This wake lock is no longer being respected.notifyWakeLockReleasedLocked(wakeLock);} else {notifyWakeLockAcquiredLocked(wakeLock);}}}}if (changed) {mDirty |= DIRTY_WAKE_LOCKS;updatePowerStateLocked();}
}

最终通过设置wakelock.disable完成wakelock的忽略。


http://chatgpt.dhexx.cn/article/SBh4bSyb.shtml

相关文章

Android7.0 Doze模式

在Android M中&#xff0c;Google就引入了Doze模式。它定义了一种全新的、低能耗的状态。 在该状态&#xff0c;后台只有部分任务被允许运行&#xff0c;其它任务都被强制停止。 本篇博客中&#xff0c;我们就来分析一下Android 7.0中Doze模式相关的流程。 一、基本原理 Do…

Android Doze模式和app Standby模式

对低电耗模式(app Standby)和应用待机模式(Doze)进行针对性优化 从 Android 6.0&#xff08;API 级别 23&#xff09;开始&#xff0c;Android 引入了两个省电功能&#xff0c;可通过管理应用在设备未连接至电源时的行为方式为用户延长电池寿命。低电耗模式通过在设备长时间处…

adb shell dumpsys deviceidle whitelist 打盹模式(Doze)白名单

Android 6.0开始引入了打盹模式(Doze)&#xff0c;若想使自己的App不受打盹模式的影响&#xff08;推迟Alarm唤起时间、限制CPU调用、限制网络请求等&#xff09;&#xff0c;需终端手机厂商为该App添加这个白名单。 Android developer 针对低电耗模式和应用待机模式进行优化&…

Android 8.1 Doze模式分析(二)——Light Doze模式

概述 LightDoze表示轻度doze模式&#xff0c;如果设备处于未充电且屏幕关闭状态&#xff0c;但未处于静止状态时&#xff0c;就会进入Light Doze模式&#xff0c;在LightDoze模式中&#xff0c;会定期进行维护&#xff0c;这种维护会持续N分钟&#xff0c;在维护状态(maintena…

Doze模式时序调研

Doze模式 机型 Light idle Deep idle 时序 定制白名单 AppStandby BLE Scanning管控 华为P20 Pro 开启 64.5分钟进入deep idle 有 开启 禁止BLE scanning OPPO F11 Pro 开启 30分钟进入deep idle 有 开启 允许BLE scanning 小米 MI 8 Pro 开启 64.5分钟进入…

Android7.0 Doze模式分析(一)Doze介绍 DeviceIdleController

参考&#xff1a;http://blog.csdn.net/gaugamela/article/details/52981984 在Android M中&#xff0c;Google就引入了Doze模式。它定义了一种全新的、低能耗的状态。 在该状态&#xff0c;后台只有部分任务被允许运行&#xff0c;其它任务都被强制停止。 在之前的博客中分…

android 7.0低电耗Doze模式

从 Android 6.0&#xff08;API 级别 23&#xff09;开始&#xff0c;Android 引入了两个省电功能&#xff0c;可通过管理应用在设备未连接至电源时的行为方式为用户延长电池寿命。 低电耗(Doze)模式通过在设备长时间处于闲置状态时推迟应用的后台 CPU 和网络 Activity 来减少电…

Android O Doze模式的状态

现象 以下是BugReport日志 日志 STATE_ACTIVE 2,006: 11-17 10:24:59.876137 900 900 I DeviceIdleController: updateChargingLocked: chargingtrue 2,007: 11-17 10:24:59.876244 900 900 I DeviceIdleController: becomeActiveLocked, reason charging 2,25…

【Android】Doze模式识别与检测

从 Android 6.0&#xff08;API 级别 23&#xff09;开始&#xff0c;Android 引入了两个省电功能&#xff1a;Doze模式&#xff08;官方翻译为低电耗模式&#xff09;和 App Standby模式&#xff08;官方翻译为应用待机模式&#xff09;&#xff0c;可通过管理应用在设备未连接…

Android 8.1 Doze模式分析(一)——Doze简介和DeviceIdleController的启动

概述 Doze模式&#xff0c;官方翻译为低电耗模式&#xff0c;是Andoriod6.0增加的一项系统服务&#xff0c;主要目的是为了优化电池性能&#xff0c;增加电池续航时间&#xff0c;Doze模式又分两种模式&#xff1a;深度Doze模式(Deep Doze)和轻度Doze模式(Light Doze)&#xf…

Android 6.0的省电技术Doze作用影响以及避免方法

从android 6.0开始&#xff0c;谷歌引入了两项新的省电技术延长电池使用时间&#xff0c;分别是Doze&#xff08;休眠&#xff09;和App Standby&#xff08;app待命模式&#xff09;&#xff0c;只要app是运行在6.0&#xff08;api 23&#xff09;及以上的系统&#xff0c;无论…

Doze模式简介

Doze模式是自Android 6.0开始引入的两项省电功能的其中之一&#xff0c;还有一个就是appstandby&#xff0c;通过管理应用在设备未连接至电源时的行为方式&#xff0c;帮助用户延长电池寿命。当用户长时间未使用设备时&#xff0c;低电耗模式会延迟应用的后台 CPU 和网络活动&a…

Android中的Doze模式

概述 Android 6.0引入的Doze机制在于节省系统耗电量&#xff0c;保护电池&#xff0c;延长电池的使用时间。当设备未连接至电源&#xff0c;且长时间处于闲置状态时&#xff0c;系统会将应用进入Doze&#xff0c;置于App Standby模式。而最终的效果&#xff0c;能提升30%的电量…

Mock工具之Mockito实战

在实际项目中写单元测试的过程中我们会发现需要测试的类有很多依赖&#xff0c;这些依赖项又会有依赖&#xff0c;导致在单元测试代码里几乎无法完成构建&#xff0c;尤其是当依赖项尚未构建完成时会导致单元测试无法进行。为了解决这类问题我们引入了Mock的概念&#xff0c;简…

Mockito 入门

目录 1.什么是 Mock 测试&#xff1f;2.Mockito简介3.在 SpringBoot 单元测试中使用 Mockito3.1 Maven依赖&#xff1a;3.2 UserService.java3.3 User.java3.4 thenReturn系列方法&#xff08;测试桩&#xff09;3.5 thenThrow系列方法3.6 verify 系列方法 4.Spring中mock任何容…

Mock工具之Moco使用教程

目录 一、什么是Moco二、安装&配置三、接口配置&测试3.1 第一个简单的请求&#xff1a;3.2 Get请求&#xff1a;3.3 Post请求&#xff1a;3.4 返回值为Json格式的请求&#xff1a;3.5 带cookie信息才能访问的post请求&#xff1a;3.6 重定向请求&#xff1a;3.7 前后端…

mock功能

目标 了解mock的作用及使用场景&#xff1b; mock使用场景 mock&#xff1a;假的 前端程序员提到的mock数据的含义是&#xff1a;真的假数据 真的&#xff1a;符合接口规范要求的。 假数据&#xff1a;数据是人为创建出来的&#xff0c;不是真正的业务数据。 什么时候需…

mock的介绍

1.什么是mock mock测试是以可控的方式模拟真实的对象行为。程序员通常创造模拟对象来测试对象本身该具备的行为&#xff0c;很类似汽车设计者使用碰撞测试假人来模拟车辆碰撞中人的动态行为 2.为什么要使用mock 之所以使用mock测试&#xff0c;是因为真实场景很难实现或者短…

Mock介绍

mock的定义&#xff08;what&#xff09;&#xff1a; mock是在测试过程中&#xff0c;对于一些不容易构造/获取的对象&#xff0c;创建一个mock对象来模拟对象的行为 为什么要使用mock&#xff08;why&#xff09;&#xff1a; 在做单元测试过程中&#xff0c;经常会有以下的…

Mockito单元测试

文章目录 Mockito单元测试为什么要使用Mock?导入依赖import导入包使用Mock模拟测试某个类中的某个方法是否可以成功执行使用Mock模拟某个类的方法&#xff0c;自己给这个方法返回我们指定的值使用Mock模拟某个方法调用后会抛出指定的异常使用Mock模拟测试某个类中的某个方法(加…