概述
Doze模式,官方翻译为低电耗模式,是Andoriod6.0增加的一项系统服务,主要目的是为了优化电池性能,增加电池续航时间,Doze模式又分两种模式:深度Doze模式(Deep Doze)和轻度Doze模式(Light Doze),如果用户长时间没有主动使用其设备,处于静止状态且屏幕已关闭,则系统会使设备进入Doze模式,也就是深度Doze模式。如果用户关闭设备屏幕但仍处于移动状态时,则设备进入轻度Doze模式,此外,轻度Doze模式只适合Android7.0及以上版本。
当用户长时间未使用设备时,设备进入Doze模式,Doze模式会延迟应用后台 CPU 和网络活动,从而延长电池续航时间。处于Doze模式的设备会定期进入维护时段,在此期间,应用可以完成待进行的活动。然后,Doze模式会使设备重新进入较长时间的休眠状态,接着进入下一个维护时段。在达到几个小时的休眠时间上限之前,平台会周而复始地重复Doze模式休眠/维护的序列,且每一次都会延长Doze模式时长。处于Doze模式的设备始终可以感知到动作,且会在检测到动作时立即退出Doze模式。整个Doze图示如下:
Deep Doze 和Light Doze模式对比如下:
操作 | 低电耗模式 | 轻度低电耗模式 |
---|---|---|
触发因素 | 屏幕关闭、电池供电、静止 | 屏幕关闭、电池供电(未插电) |
时间 | 随维护时段依次增加 | 随维护时段反复持续 N 分钟 |
限制 | 无法进行网络访问、唤醒锁忽略、 GPS/WLAN无法扫描、闹钟和SyncAdapter/JobScheduler被延迟。 | 无法进行网络访问、SyncAdapter/JobScheduler |
行为 | 仅接收优先级较高的推送通知消息。 | 接收所有实时消息(即时消息、来电等)。优先级较高的推送通知消息可以暂时访问网络。 |
退出 | 设备有移动、和用户有交互、屏幕开启、闹钟响铃 | 屏幕开启。 |
接下来就分析Doze的实现原理。Doze模式是通过DeviceIdleController来实现的。
1.DeviceIdleController的启动流程
DeviceIdleController(以下简称DIC)继承于SystemService,因此也是一个系统服务,在分析PMS的时候说过,继承于SytemService的服务启动有以下几个共同点:
- 1.在SystemServer中实例化并启动,启动时会执行SytemService的生命周期方法:
Constructor()->onStart()->onBootPhase()
; - 2.内部维护一个Binder和其他服务进行IPC通讯;
- 3.内部维护一个Internal类用于和System进程进行交互;
下面就从SystemServer开始分析DIC的启动流程。
在SystemServer启动其他服务时启动DIC:
private void startOtherServices() {
.............
mSystemServiceManager.startService(DeviceIdleController.class);
............
}
在SystemServiceManager中,通过反射的方式获取了DIC对象,并且调用了onStart()方法:
public <T extends SystemService> T startService(Class<T> serviceClass) {
try {
....................
final String name = serviceClass.getName();
Slog.i(TAG, "Starting " + name);
final T service;
try {
//通过反射获取实例
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext);
} catch (InstantiationException ex) {
}
//调用同名重载方法
startService(service);
return service;
}
....................
}
public void startService(@NonNull final SystemService service) {
// 加入到mServices列表中
mServices.add(service);
long time = SystemClock.elapsedRealtime();
try {
//调用onStart()开始服务
service.onStart();
} catch (RuntimeException ex) {
}
}
执行到这里,DIC的启动就开始了,再来看看最后一个生命周期方法onBootPhase()
的调用,这个方法表示启动服务的过程,在SystemServer中会调用多次,从而在不同的启动阶段完成不同的工作,代码如下:
private void startOtherServices() {
.............
mSystemServiceManager.startBootPhase(SystemService.
PHASE_LOCK_SETTINGS_READY);
.............
mSystemServiceManager.startBootPhase(SystemService.
PHASE_SYSTEM_SERVICES_READY);
.............
mSystemServiceManager.startBootPhase(
SystemService.PHASE_ACTIVITY_MANAGER_READY);
.............
mSystemServiceMana