深入Android 'M' Doze

本文详细介绍了Android M中引入的Doze模式,探讨了其如何帮助设备进入低功耗状态,以及DeviceIdleController如何管理和控制这一过程。此外,文章还讨论了哪些应用和服务在设备处于Doze模式时仍能保持活跃。

原文链接:https://newcircle.com/s/post/1739/2015/06/12/diving-into-android-m-doze

注意:这篇博文的所有描述都是基于Android‘M’开发者预览的第一版本。因为新的版本(包括码代码)已经发布,一些东西发生了改变,这篇博文的内容也可能会随之发生改变。

什么是Doze?

我第一次看到”doze”被用在Android上,其实是它作为一个display state在搭载了KitKat(Android 4.4, API 20)的穿戴设备上,之后我在搭载了Lollipop(Android 5.0)的设备上又看到了它。Doze是当设备暂时呈现出静态(不交互的)内容(想象一下Nexus 6,响应重要手势时出现的时钟,实际上并没有更新)时所处的一种全新的、低耗能的状态。在新的Android‘M’预览中,Doze Mode的含义发生了轻微的变化,现在是指“强制空闲”状态,这时只有很少的后台处理被允许。

评论:“Doze”对于这个新特性而言其实是一个糟糕的名字。因为这个名词在已经在framework层中存在了,是由DreamManager掌管,而与Doze Mode没有任何关系。

你好,DeviceIdleController

DeviceIdleController是Doze模式的主要驱动。接下来,我将使用device idle mode而不是doze mode来描述“Doze”,因为它更符合代码的实际情况。如果你已经阅读了官方文档,你可能已经注意到下面的命令,开发者可以通过这些命令得知当下设备的应用行为:

$ adb shell dumpsys battery unplug
$ adb shell dumpsys deviceidle step

对于上面的命令你可能并不熟悉,dumpsys是用来与系统服务交互的(查看它们的状态),deviceidle是我们之前没有看到过的,它是一个新的系统服务。

$ adb shell service list | grep deviceidle
59  deviceidle: [android.os.IDeviceIdleController]

这个新的服务常驻以监听下面的系统事件,这些事件会触发系统是否进入idle mode:

  1. 亮屏/暗屏
  2. 充电状态
  3. 重要的手势检测

DeviceIdleController维持着设备包含的五种状态:

  1. ACTIVE – 设备在使用中,或者连接着电源。
  2. INACTIVE – 设备已经从ACTIVE状态中出来一段时间了(使用者关闭了屏幕或者拔掉了电源)
  3. IDLE_PENDING – 请留意,我们将进入idle mode.
  4. IDLE – 设备进入idle mode.
  5. IDLE_MAINTENANCE – 应用窗口已经打开去做处理.

当设备被唤醒和正在使用中,控制器就处于ACTIVE状态,外部的事件(不活跃时间超时,用户关闭屏幕,等等)将会使设备状态进入到INACTIVE. 那时,DeviceIdleController将会通过AlarmManager来设置他自己的alarm来驱动进程:

  1. 一个alarm会被设置在一个预设的时刻(这个时间在M的预览中是30分钟)。
  2. 当这个alarm生效后,DeviceIdleController 会进入到IDLE_PENDING然后再次设置同样的alarm。
  3. 当触发下一个alarm后,控制器会进入到IDLE 状态,进入到这个状态后,应用特性会被完全限制。
  4. 再向前推进这个服务会在IDLE IDLE_MAINTENANCE两个状态之间周期性的跳转,后者在服务完全被禁前,等待的应用事件被触发。

正如上面提到的,开发者能够使用下面的命令,手动地改变设备的这些状态:

$ adb shell dumpsys deviceidle step

我们可以使用‘-h’看到所有的deviceidle的所有选项:

$ adb shell dumpsys deviceidle -h
Device idle controller (deviceidle) dump options:
  [-h] [CMD]
  -h: print this help text.
Commands:
  step
    Immediately step to next state, without waiting for alarm.
  disable
    Completely disable device idle mode.
  enable
    Re-enable device idle mode after it had previously been disabled.
  whitelist
    Add (prefix with +) or remove (prefix with -) packages.

这些服务的公共API(由IDeviceIdleController 接口展现)持有全部方法访问白名单。应用(系统应用或其它第三方应用)任何情况下都不能驱动控制器状态。

你在这个名单中吗?

正如你在上面的帮助菜单中看到的一样,DeviceIdleController 维护着一个应用白名单,不需要额外的参数,通过dump服务的状态,我们能够看到现在的这个列表:

$ 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
  …

这个名单分为两个部分:系统应用和第三方应用。

系统应用

系统应用会被平台制作者通过配置定义列在白名单中。下面这个是从Nexus 6中得到的一个配置定义例子,它将GMS核心(在GCM中使用),应用商店,以及一个任意的用于电源监控的app白名单化:
/system/etc/sysconfig/google.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- These are configurations that must exist on all GMS devices. -->
<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()将这些系统定义的元素放到白名单中。

注意:当设备处于“省电模式”时,同样也是这个配置文件决定哪个系统应用可以在后台开启服务。

第三方应用

白名单中剩下的部分是用户定义的,这些项可以通过两种方式被增加和删除。
第一种方式,开发者可以通过dumpsys接口使用白名单命令:

$ adb shell dumpsys deviceidle whitelist +com.example.myapplication
$ adb shell dumpsys deviceidle
  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

第二种方式,用户可以通过设置(Settings -> Battery -> Ignore optimizations)来修改白名单。
BatteryIgnoreMenu BatteryIgnoreMenu
这个用户设置存在是因为白名单也被Android‘M’新的App Standby 特征使用。白名单只是当评估设备的空闲行为时被部分使用。

设备处于Idle Mode时的系统服务行为

既然我们已经知道了一些基础了,让我们来测试一下当设备空闲时剩下的系统服务的反应,并且看下白名单是否有实际的用处。下面是DeviceIdleController所能涉及到的主要服务的列表:

NetworkPolicyManagerService

Lollipop引入了“省电模式”,它只允许白名单应用才能在后台运行。Idle mode有着相同的逻辑,只对白名单中的应用授予访问网络的权限。这个服务对于“省电模式”和idle mode是等同的。

JobSchedulerService

所有应用(没有例外)中,现在正在执行的作业会被取消。Idle mode的时候没有等待中的作业被开启。

SyncManager

所有应用(没有例外)中的活跃的同步会被取消。

PowerManagerService

应用白名单意味着唤醒锁(wake locks)是有效的。没有在这个名单中的应用及时禁用的唤醒锁(wake locks)

AlarmManagerService

DeviceIdleController是使用一个特殊的私有方法(AlarmManager.setIdleUntil())来注册下一个唤醒alarm。当AlarmManagerService 看到它时,所有的标准应用alarm都强制进入到一个等待状态直到直到下一个DeviceIdleControlleralarm触发。以这种方式,应用alarm被批处理并且在IDLE_MAINTENANCE时期被控制器驱动。有三个标志允许alarm退出。

  • FLAG_ALLOW_WHILE_IDLE – 任何应用可以使用new setAndAllowWhileIdle() 对其进行设置。
  • FLAG_WAKE_FROM_IDLE – 任何应用可以使用setAlarmClock()来进行设置。
  • FLAG_IDLE_UNTIL – 为被DeviceIdleController使用的alarm保留,以改变机器的状态。
    UID<10000的进程(例如系统服务)他们设置的每个alarm会自动被授予FLAG_ALLOW_WHILE_IDLE

最后总结

许多开发者询问,文档中提到应用在空闲时期,如果接收到更高优先级的使用GCM推送的消息,应用会被授予“短暂的网络访问”。在我看来,在framework层的实现中没有任何与GCM的关联(谢天谢地,如果是那样就太愚蠢了,不是吗?)因为GMS是闭源的,我们只能推测在谷歌设备上会不会发生。

事实是这样,任何系统应用能够暂时修改app白名单或者特殊应用的网络策略。这会在不修改放下设备的空闲状态的情况下,为每个应用基础的网络访问打破限制。在当前的预览中,是否仍然存在漏洞于SyncManager,这点仍然不清楚。现存的同步被取消,但是我们不能确定新的会不会被允许。应用也许仍然能够在GCM的触发下执行新的同步(这是在这种状态下仅有的app允许的网络访问)
好吧,当然,这纯属推测。

这篇博文是Android M Development Tips 的部分。

(由于本人翻译水平有限,因此译文中不免出现错误和不当之处。还请各位看官不吝指正,以提高译文水平,使更多同学受益)

<think>嗯,用户想在Android上关闭Doze模式,我得先回忆一下Doze模式的作用机制。Doze模式是Android6.0(API23)引入的省电功能,当设备长时间未使用时,会限制网络访问延迟后台任务,从而延长电池寿命。但有些应用可能需要持续运行,比如实时通讯或后台服务,这时候用户可能需要关闭Doze。首先,我需要确认关闭Doze的方法。通常有两种途径:通过ADB命令临时禁用,或者在代码中配置。不过根据Android的权限限制,普通应用可能无法直接修改系统设置,所以ADB方法可能更可行,尤其是对于开发或测试环境。 接下来,ADB命令的具体操作。我记得正确的命令可能是`adbshell dumpsysdeviceidledisable`,这样可以关闭Doze模式。但用户可能需要启用时,用`enable`参数。另外,检查当前状态的命令是`adbshell dumpsysdeviceidle`,这样可以看到Doze是否处于活动状态。然后是代码层面的解决方案。应用可以请求忽略电池优化,这需要请求用户授权。使用`ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS`意图打开设置页面,或者检查是否有`IGNORE_BATTERY_OPTIMIZATION_WHITELIST`权限。但要注意,Google Play对滥用此权限的应用有严格限制,可能会拒绝上架。另外,用户可能需要将应用加入白名单。系统设置中的电池优化部分,用户可以手动将应用设为“不优化”。但这个过程需要用户手动操作,无法通过代码自动完成。还要考虑不同Android版本的变化。比如Android9引入了应用待机分组,可能会影响Doze的行为,需要测试不同版本的兼容性。最后,需要提醒用户,关闭Doze模式可能会增加电池消耗,建议仅在必要时使用,并遵循最佳实践,比如使用前台服务或WorkManager来处理关键任务。现在需要验证这些步骤是否正确,尤其是ADB命令是否有效,以及权限请求的正确流程。同时,确保提供的代码示例准确,比如使用Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS是否正确。可能还需要提到AndroidManifest中的权限声明,比如`REQUEST_IGNORE_BATTERY_OPTIMIZATIONS`。总结一下,回答应该分步骤说明ADB方法代码方法,指出各自的适用场景限制,并提醒用户注意事项。同时生成相关问题,帮助用户深入理解Doze模式的相关配置优化策略。</think>### Android禁用Doze模式的配置方法 在Android系统中,Doze模式是系统级省电机制,完全关闭需要系统权限。开发者可通过以下两种方式实现部分禁用: **1. ADB命令临时禁用(需USB调试)** ```bash adb shell dumpsys deviceidle disable ``` 此命令会使Doze进入`INACTIVE`状态[^1],重启后失效。验证状态: ```bash adb shell dumpsys deviceidle | grep -i enabled ``` **2. 代码配置白名单(需用户授权)** ```java // AndroidManifest.xml添加权限 <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/> // 检查当前状态 if (!powerManager.isIgnoringBatteryOptimizations(packageName)) { Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); intent.setData(Uri.parse("package:" + packageName)); startActivity(intent); } ``` 此方法需要用户手动确认授权,且Google Play禁止滥用此权限[^2]。 **注意事项:** - Android 9+引入应用待机分组机制,会影响Doze行为 - 前台服务(Foreground Service)可部分绕过Doze限制 - 使用WorkManager的加急任务(exact worker)可提升任务优先级
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值