1.Doze模式概述
Doze是一种创新的低功耗状态,当设备处于非交互的静态状态时自动激活。该模式通过限制后台活动来显著降低能耗,主要分为深度Doze和浅度Doze两种状态。
1.1 深度Doze模式特点:
激活条件严格,需要较长的非活动时间
在深度IDLE状态下实施严格的应用管控措施:
禁止网络访问
忽略唤醒锁定(wake locks)
限制AlarmManager功能:
标准闹铃(包括setExact()和setWindow())将延迟至下一个维护时段
如需在Doze模式下触发闹铃,需使用setAndAllowWhileIdle()或setExactAndAllowWhileIdle()
setAlarmClock()设置的闹铃仍可触发,系统会在触发前退出Doze模式
禁用Wi-Fi扫描功能
停止同步适配器运行
暂停JobScheduler任务执行
1.2浅度Doze模式特点:
激活条件宽松,设备熄屏5分钟后即可进入
在浅度IDLE状态下实施相对宽松的限制:
限制应用网络连接
推迟后台作业执行
这种分级管理机制在保证基本功能的同时,最大限度地延长了设备的电池续航时间。
1.3 深度Doze与浅度Doze的对比
深度Doze与浅度Doze的对比
Doze | 进入条件 | 对App的限制 | 退出条件 |
Light Idle | 设备不充电,屏幕关闭 | 1.不能访问网络 2.推迟Job和Sync | 亮屏或充电 |
Deep Idle | 设备不充电,屏幕关闭,设备保持静止一段时间 | 1.不能访问网络 2.wakelock失效 3.禁止GPS与Wifi扫描 4.Job和Sync推迟 | 亮屏或充电或移动或Alarm到来 |
2.Doze的工作流程
2.1 浅度Doze流程图:
2.2 深度Doze流程图:
上述反映出了Deep idle的七个时间状态:
如果看着迷糊,可以看下Doze时序简图如下:
如上图我们可以计算出原生Doze机制最快进入deep idle需要30分钟+30分钟+4分钟+30秒=64分钟30秒才能进入deep idle。一般友商的功耗策略加强是缩短进入deep idle的时序。
3.DeviceIdleController 控制中心
DeviceIdleController 是 Device Idle Mode(即 Doze 模式)的核心驱动模块。它通过监听系统事件(如屏幕状态、充电状态、运动状态)来决定设备是否进入doze模式。开发者可以通过以下命令查看设备状态:
adb shell dumpsys battery unplug adb shell dumpsys deviceidle step
deviceidle 是一个系统服务,可通过以下命令确认:
adb shell service list | grep deviceidle deviceidle: [android.os.IDeviceIdleController]
deviceidle 是一个系统服务,可通过以下命令确认:
adb shell service list | grep deviceidle
deviceidle: [android.os.IDeviceIdleController]
3.1 DeviceIdleController 的五种状态
ACTIVE:
设备正在使用或连接电源。
不进入省电模式。
INACTIVE:
设备从 ACTIVE 退出(如屏幕关闭或拔掉电源)。
开始计时,判断是否进入省电模式。
IDLE_PENDING:
设备即将进入 Idle Mode。
设置定时器,决定何时进入 IDLE 状态。
IDLE:
设备进入 Idle Mode。
严格限制后台行为(如网络访问、唤醒锁定等)。
IDLE_MAINTENANCE:
从 IDLE 短暂退出,进入维护窗口。
允许应用处理积压任务(如同步、闹铃等)。
维护窗口结束后,重新进入 IDLE。
3.2 状态切换机制
INACTIVE → IDLE_PENDING:
设备静止一段时间(默认 30 分钟)后,进入 IDLE_PENDING。
设置定时器,决定何时进入 IDLE。
IDLE_PENDING → IDLE:
定时器触发后,进入 IDLE 状态。
严格限制后台行为。
IDLE → IDLE_MAINTENANCE:
定期打开维护窗口,允许应用处理任务。
维护窗口结束后,重新进入 IDLE。
3.3 开发者工具
我经常使用如下命令手动控制状态切换:该命令立即切换到下一个状态,无需等待定时器。
adb shell dumpsys deviceidle step
更多命令可以使用adb shell dumpsys deviceidle -h查询
4.Doze 白名单介绍
DeviceIdleController 维护着一个应用白名单,用于在 Doze 模式 下豁免特定应用的后台限制。通过 dumpsys 命令可以查看当前的白名单状态:
$ adb shell dumpsys deviceidle
Whitelist system apps:
com.android.providers.downloads
com.android.vending
com.google.android.gms
Whitelist app uids:
UID=10012: true
UID=10016: true
UID=10026: true
白名单分为两部分:系统应用 和 第三方应用。
4.1 系统应用
系统应用由平台开发者通过配置文件定义在白名单中。以下是一个来自 Nexus 6 的配置示例,它将 GMS 核心(用于 GCM)、应用商店以及一个用于电源监控的应用加入白名单:
/system/etc/sysconfig/google.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- 这些配置必须存在于所有 GMS 设备上 -->
<config>
<allow-in-power-save package="com.google.android.gms" />
<allow-in-power-save package="com.android.vending" />
<allow-in-power-save package="com.google.android.volta" />
</config>
其他系统服务可以通过 SystemConfig 实例访问这些配置值。DeviceIdleController 使用 SystemConfig.getAllowInPowerSave() 将这些系统定义的应用加入白名单。当设备处于“省电模式”时,该配置文件还决定了哪些系统应用可以在后台启动服务。
4.2 第三方应用
第三方应用的白名单由用户定义,可以通过以下3种方式添加或删除:
4.2.1 使用 dumpsys 接口
开发者可以通过 dumpsys 命令管理白名单。例如:adb shell dumpsys deviceidle whitelist +com.example.myapplication
验证白名单是否添加成功:
Whitelist system apps:
com.android.providers.downloads
com.android.vending
com.google.android.gms
Whitelist user apps:
com.example.myapplication
Whitelist app uids:
UID=10012: true
4.2.2. 通过 Intent 请求用户授权
应用可以通过以下代码请求用户将其加入白名单:
Intent it = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
it.setData(Uri.parse("package:" + getPackageName()));
startActivity(it);
同时,需要在 AndroidManifest.xml 中声明权限:
4.2.3 用户手动设置
用户也可以通过系统设置手动管理白名单:
进入 Settings -> Battery -> Battery optimization。
选择应用并设置为 Don’t optimize。
白名单的作用:白名单不仅用于 Doze 模式,还被 App Standby和JobScheduler特性使用。当设备进入空闲状态时,系统会根据白名单评估应用的行为,决定是否限制其后台活动。
5.设备处于Idle Mode时的系统服务行为
既然我们已经知道了一些基础了,让我们来测试一下当设备空闲时剩下的系统服务的反应,并且看下白名单是否有实际的用处。下面是DeviceIdleController所能涉及到的主要服务:
主要代码在:frameworks\base\services\core\java\com\android\server\DeviceIdleController
控制到的主要服务模块有联网、工作任务、同步、持锁、唤醒:
5.1 NetworkPolicyManagerService
行为:
仅允许白名单或TempWhiteList中的应用访问网络。
非白名单应用在 Idle Mode 下无法访问网络。
备注:
该服务对“省电模式”和 Idle Mode 的处理方式相同。
5.2 JobSchedulerService
行为:
取消所有应用中正在执行的作业(无论是否在白名单中)。
在 Idle Mode 下,不会启动任何等待中的作业。
备注:
即使应用在白名单中,其作业也会被暂停。
5.3 SyncManager
行为:
取消所有应用中的活跃同步(无论是否在白名单中)。
备注:
同步操作在 Idle Mode 下完全停止。
5.4 PowerManagerService
行为:
仅允许白名单中的应用持有有效的唤醒锁(Wake Lock)。
非白名单应用的唤醒锁会被禁用。
备注:
白名单是唤醒锁生效的必要条件。
5.5 AlarmManagerService
行为:
DeviceIdleController 使用私有方法 AlarmManager.setIdleUntil() 注册下一个唤醒闹钟。
当 AlarmManagerService 检测到设备处于 Idle Mode 时,所有标准应用的闹钟会被强制进入等待状态,直到下一个 DeviceIdleController 闹钟触发。
应用闹钟会被批处理,并在 IDLE_MAINTENANCE 期间由控制器统一处理。
特殊标志:
FLAG_ALLOW_WHILE_IDLE:
允许应用在 Idle Mode 下触发闹钟。
通过 setAndAllowWhileIdle() 设置。
FLAG_WAKE_FROM_IDLE:
允许应用在 Idle Mode 下唤醒设备。
通过 setAlarmClock() 设置。
FLAG_IDLE_UNTIL:
专供 DeviceIdleController 使用,用于改变设备状态。
系统特权:
UID < 10000 的进程(如系统服务)自动获得 FLAG_ALLOW_WHILE_IDLE 权限。
6.Doze的管控效果图
Doze期间提供间隔一小段窗口时间(30s)供应用程序使用网络和处理挂起的活动。系统进入Doze模式后,系统会隔一段时间处理正在挂起的任务,随着时间推移,后面间隔的时间会越来越长,以此来减少电量消耗。
上图时间相关参数定义解释如下:
(1)IDLE 阶段的持续时间
首次进入 IDLE 阶段:持续时间为 IDLE_TIMEOUT,默认值为 1 小时。
后续进入 IDLE 阶段:持续时间会乘以 IDLE_FACTOR(默认值为 2.0),即每次翻倍,直到达到 MAX_IDLE_TIMEOUT(默认值为 6 小时)。
例如:
第一次:1 小时
第二次:2 小时
第三次:4 小时
第四次:6 小时(达到最大值)
(2)IDLE_MAINTENANCE 阶段的持续时间
首次进入 IDLE_MAINTENANCE 阶段:持续时间为 IDLE_PENDING_TIMEOUT,默认值为 5 分钟。
后续进入 IDLE_MAINTENANCE 阶段:持续时间会乘以 IDLE_PENDING_FACTOR(默认值为 2.0),即每次翻倍,直到达到 MAX_IDLE_PENDING_TIMEOUT(默认值为 10 分钟)。
例如:
第一次:5 分钟
第二次:10 分钟(达到最大值)
(3)窗口期时长
IDLE_MAINTENANCE 阶段的窗口期时长是固定的,由 MIN_DEEP_MAINTENANCE_TIME 控制,默认值为 30 秒。
在 STATE_IDLE_MAINTENANCE 状态下,设备会短暂唤醒,执行必要的维护任务(如同步、接收通知等),然后再次进入 STATE_IDLE。
(4)IDLE_MAINTENANCE 阶段的持续时间和窗口期时长有什么差异?
假设设备首次进入 IDLE_MAINTENANCE 阶段:
IDLE_MAINTENANCE 阶段的持续时间:5 分钟。
窗口期时长:30 秒。
在这 5 分钟内:
设备会在前 30 秒完全唤醒,执行必要的维护任务(窗口期)。
剩余的 4 分 30 秒,设备可能处于低功耗状态,等待回到 IDLE 阶段。