【Android】Doze模式识别与检测

从 Android 6.0(API 级别 23)开始,Android 引入了两个省电功能:Doze模式(官方翻译为低电耗模式)和 App Standby模式(官方翻译为应用待机模式),可通过管理应用在设备未连接至电源时的行为方式为用户延长电池寿命。Doze模式通过在设备长时间处于闲置状态时推迟应用的后台 CPU 和网络 Activity 来减少电池消耗。App Standby模式可推迟用户近期未与之交互的应用的后台网络 Activity。

Doze模式

满足以下条件的设备会进入Doze低电耗模式。

  • 用户设备未插接电源
  • 处于静止状态一段时间
  • 屏幕关闭

在低电耗模式下,系统会尝试通过限制应用对网络和 CPU 密集型服务的访问来节省电量。 这还可以阻止应用访问网络并推迟其作业、同步和标准闹铃。

系统会定期退出Doze低电耗模式一会儿,好让应用完成其已推迟的 Activity。在此维护时段内,系统会运行所有待定同步、作业和闹铃并允许应用访问网络。

图 1. 低电耗模式提供了定期维护时段,可供应用使用网络并处理待定 Activity。

在每个维护时段结束后,系统会再次进入低电耗模式,暂停网络访问并推迟作业、同步和闹铃。 随着时间的推移,系统安排维护时段的次数越来越少,这有助于在设备未连接至充电器的情况下长期处于不活动状态时降低电池消耗。

一旦用户有以下行为,系统就会立即退出低电耗模式,并且所有应用都将返回到正常 Activity。

  • 移动手机设备(通过运动检测传感器识别)
  • 打开屏幕
  • 连接到充电器唤醒设备

Doze模式下的限制

在低电耗模式下,您的应用会受到以下限制:

  • 暂停访问网络。
  • 系统将忽略 wake locks
  • 标准 AlarmManager 闹铃(包括 setExact()setWindow())推迟到下一维护时段。
    • 如果您需要设置在低电耗模式下触发的闹铃,请使用 setAndAllowWhileIdle()setExactAndAllowWhileIdle()
    • 一般情况下,使用 setAlarmClock() 设置的闹铃将继续触发 — 但系统会在这些闹铃触发之前不久退出低电耗模式。
  • 系统不执行 Wi-Fi 扫描。
  • 系统不允许运行同步适配器
  • 系统不允许运行 JobScheduler

在Doze模式下测试

可按以下步骤测试doze模式:

  1. 使用 Android 6.0(API 级别 23)或更高版本的系统映像配置硬件设备或虚拟设备。
  2. 将设备连接到开发计算机并安装应用
  3. 运行应用并使其保持活动状态
  4. 关闭设备屏幕。(应用保持活动状态。)
  5. 通过运行以下命令强制系统在Doze低电耗模式之间循环切换:

    1
    2
    3
    4
    5
    $ adb shell dumpsys battery unplug
    $ adb shell dumpsys deviceidle step

    # 如果没有生效,可以尝试以下命令
    $ adb shell dumpsys deviceidle force-idle

    您可能需要多次运行第二个命令。不断地重复,直到设备变为空闲状态。

  6. 在重新激活设备后观察应用的行为。确保应用在设备退出Doze低电耗模式时正常恢复。

App Standby 模式

App Standby 模式(也称为应用待机模式)允许系统判定应用在用户未主动使用它时处于空闲状态。 当用户有一段时间未触摸应用时,系统便会作出此判定,以下条件均不适用:

  • 用户显式启动应用。
  • 应用当前有一个进程位于前台(表现为 Activity 或前台服务形式,或被另一 Activity 或前台服务占用)。
  • 应用生成用户可在锁屏或通知托盘中看到的通知。

当用户将设备插入电源时,系统将从待机状态释放应用,从而让它们可以自由访问网络并执行任何待定作业和同步。 如果设备长时间处于空闲状态,系统将按每天大约一次的频率允许空闲应用访问网络。

在 App Standby 模式下测试

要在App Standby模式下测试应用,可以执行以下操作:

  1. 使用 Android 6.0(API 级别 23)或更高版本的系统映像配置硬件设备或虚拟设备。
  2. 将设备连接到开发计算机并安装应用
  3. 运行应用并使其保持活动状态
  4. 通过运行以下命令强制应用进入应用待机模式:

    1
    2
    $ adb shell dumpsys battery unplug
    $ adb shell am set-inactive <packageName> true
  5. 使用以下命令模拟唤醒应用:

    1
    2
    $ adb shell am set-inactive <packageName> false
    $ adb shell am get-inactive <packageName>
  6. 观察唤醒后的应用行为。确保应用从待机模式中正常恢复。 特别地,您应检查应用的通知和后台作业是否按预期继续运行

Doze 模式和 App Standby 模式的区别

Doze模式需要屏幕关闭(通常晚上睡觉或长时间屏幕关闭才会进入),而App Standby不需要屏幕关闭,App进入后台一段时间也会受到连接网络等限制。

Doze 模式和休眠模式的区别

可以参考 StackOverflow 中的回答: Difference between Doze Mode and Sleep Mode in Android Marshmallow

Sleep Mode - means CPU will be sleeping and will not accept any command except from RIL(Radio Interface Layer) and alarms. CPU will go to sleep mode with in fraction of seconds after LCD is turned off.

Doze Mode - means that apps on your phone will have no network access, the system will ignore “wakelocks” when apps try to keep the device from going to sleep, and no background tasks will be allowed to run. That certainly makes it sound like your phone won’t do you much good, but there are a few ways Doze preserves functionality. While apps can’t wake the device up to run sync jobs and other background tasks, high-priority push messages will still show up. So for example, a Hangouts message will appear on a device that’s in Doze mode.

App Standby - an app that goes into standby loses all network access and all its background sync jobs are suspended. These restrictions are temporarily lifted when your phone is plugged in and for a few minutes every day or two. This gives suspended apps a chance to run any pending sync jobs, but they won’t be allowed to continue running. A high-priority push notification will also be able to wake an app from standby for a short time.

Doze 模式源码分析

在Android M版本中为了实现Doze模式,新增了一个DeviceIdle的服务,其实现的代码位于frameworks/base/services/core/java/com/android/server/DeviceIdleController.java中。SystemServer在开机时会启动这个服务。

1
mSystemServiceManager.startService(DeviceIdleController.class);

关于doze模式的控制逻辑都是在这个新增的服务中实现的,进入doze之后的几个功耗策略:限制网络连接、阻止partial类型的wakelock、阻止Alarm、系统不扫描wifi热点、阻止sync任务、不允许JobScheduler进行任务调度。所以除了控制逻辑之外,还在NetworkPolicyManagerService、JobSchedulerService、SyncManager、PowerManagerService和AlarmManagerService中加入了对doze状态的监听和查询接口来进行响应的操作。其控制逻辑和策略实现的代码关系如下图所示。在DeviceIdleController中实现对设备状态的控制和改变,并且通知其他相关注册了AppIdleStateChangeListener接口的服务进行处理,而反过来这些服务也可以向DeviceIdleController查询device的状态,是一种交互的关系。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/** Device is currently active. */
private static final int STATE_ACTIVE = 0;
/** Device is inactive (screen off, no motion) and we are waiting to for idle. */
private static final int STATE_INACTIVE = 1;
/** Device is past the initial inactive period, and waiting for the next idle period. */
private static final int STATE_IDLE_PENDING = 2;
/** Device is currently sensing motion. */
private static final int STATE_SENSING = 3;
/** Device is currently finding location (and may still be sensing). */
private static final int STATE_LOCATING = 4;
/** Device is in the idle state, trying to stay asleep as much as possible. */
private static final int STATE_IDLE = 5;
/** Device is in the idle state, but temporarily out of idle to do regular maintenance. */
private static final int STATE_IDLE_MAINTENANCE = 6;

Doze模式具体包含了7种状态:

  1. ACTIVE:当设备亮屏或者处于正常使用状态时其就为ACTIVE状态;
  2. INACTIVE:ACTIVE状态下不插充电器或者usb且灭屏设备就会切换到INACTIVE状态;
  3. IDLE_PENDING:INACTIVE状态经过30分钟,期间检测没有打断状态的行为Doze就切换到IDLE_PENDING的状态;
  4. SENSING:然后再经过30分钟以及一系列的判断,状态切换到SENSING;
  5. LOCATION:在SENSING状态下会去检测是否有地理位置变化,没有的话就切到LOCATION状态;
  6. IDLE:LOCATION状态下再经过30s的检测时间之后就进入了Doze的核心状态IDLE;
  7. IDLE_MAINTANCE:在IDLE模式下每隔一段时间就会进入一次IDLE_MAINTANCE,此间用来处理之前被挂起的一些任务;
  8. IDLE_MAINTANCE状态持续5分钟之后会重新回到IDLE状态;
  9. 在除ACTIVE以外的所有状态中,检测到打断的行为如亮屏、插入充电器,位置的改变等状态就会回到ACTIVE,重新开始下一个轮回。

参考资料

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2019 iTimeTraveler All Rights Reserved.

访客数 : | 访问量 :