由于Android设备的电池容量有限,而用户在使用过程中会进行各种高耗电操作,如网络连接、屏幕亮度调节、后台程序运行等,因此需要通过各种省电措施来优化电池使用,延长电池续航时间,提高用户体验,并减少因电量不足导致的设备使用中断。
而随着Android版本的迭代,都或多或少会引入或改进针对空闲设备和应用的省电优化措施。这些功能通常影响所有应用,无论应用的目标API级别为多少,因此务必在这些改动下测试我们的应用,这里将Android 6.0以来到Android14的所有相关变更按照版本顺序整理出来,方便全面了解电源管理对应用实施的各种限制,以及如何调整应用来应对这些措施。
目录
Android 6.0 API 23
低电耗模式
低电耗模式限制
使应用适应低电耗模式
应用待机模式
Android 7.0 API 24
低电耗模式改进
后台优化
用户发起的限制
Android 8.0 API 26
缓存进程
后台执行限制
后台服务限制
广播限制
迁移指南
后台位置限制
Android 9 API 28
应用待机分桶
活跃 - Active
工作集- Working set
常用 - Frequent
极少使用 - Rare
受限 - Restricted
从未使用 - Never
最佳实践
电源管理限制示例值
省电模式改进
Android 10 API 29
针对从后台启动 activity 的限制
改为显示通知
应用何时可以启动 activity
Android 11 API 30
应用休眠 - App hibernation
休眠的影响
应用停止休眠状态时的系统行为
应用使用
应用使用标准示例
例外情况
系统级休眠豁免
用户请求休眠豁免
Android 12 API 31
应用待机分桶新增“受限”分桶
Activity生命周期
Android 13 API 32
电池资源利用率
“受限”应用待机分桶变更
用户发起的限制变更
高优先级 Firebase Cloud Message (FCM) 配额变更
Android 14 API 33
应用进入缓存状态,上下文注册的广播将加入队列
可将应用放入“受限”待机分桶的新原因
Android 6.0 API 23
Android 6.0 加入了低电耗模式(Doze)和应用待机模式(App Standby)两项省电功能,用来延长电池续航时间。
低电耗模式会推迟所有apps的后台CPU和网络活动;应用待机模式则推迟近期没有被用户使用的那些apps的后台网络活动。推迟的活动会在Doze周期性提供的维护窗期间执行,以下部分提供了节能方面的详细信息。
低电耗模式
如果设备未接通电源,屏幕关闭并处于静止状态一段时间后,设备便会进入低电耗模式。
在该模式下,系统试图通过限制应用程序对网络和cpu密集型服务的访问来节省电量。它还可以阻止应用程序访问网络,并延迟它们的工作(jobs)、同步(syncs)和标准闹钟(standard alarms)。
系统会定期退出低电耗模式很短一段时间,让应用完成它们被推迟的的活动。在此维护窗口期间,系统会运行所有待处理的同步、作业和闹钟,并允许应用访问网络。
图 1. 低电耗模式提供周期性维护窗口让应用使用网络并处理待处理的活动。
当维护窗口结束后,系统会重新进入低电耗模式,重新暂停网络访问以及延迟作业、同步和闹钟。随着时间的流逝,系统会减少安排维护窗口的频率,有助于减少当设备不充电且长时间处于不活动状态时的耗电量。
低电耗模式限制
- 在低电耗模式下,系统会对您的应用施加以下限制:
- 暂停网络访问。
- 忽略唤醒锁。
- 将AlarmManager标准闹钟,包括setExact()和setWindow(),推迟到下一个维护窗口。
如果需要设置的闹钟在低电耗模式下也能触发,需要使用setAndAllowWhileIdle()或setExactAndAllowWhileIdle()。
使用setAlarmClock()设置的闹钟可以正常触发,系统会在触发前短暂退出低电耗模式。
- 不执行 WLAN 扫描。
- 不允许sync adapters运行。
- 不允许JobScheduler运行。
WorkManager内部使用的JobScheduler,所以WorkManager的任务也会不运行。
使应用适应低电耗模式
低电耗模式可能会对应用产生不同的影响,具体取决于应用提供的功能及其使用的服务。许多应用可在低电耗模式周期内正常运行而无需修改。在某些情况下,您必须优化应用程序管理网络、闹钟、作业和同步的方式。应用程序必须能够在每个维护窗口期间有效地管理活动。
设置闹钟可以使用两个AlarmManager 方法:setAndAllowWhileIdle() 和 setExactAndAllowWhileIdle(),这些方法设置的闹钟在设备即使处于低电耗模式时也会触发。
注意:对于每个应用,setAndAllowWhileIdle()和setExactAndAllowWhileIdle()都不能每9分钟触发一次以上的警报。
应用待机模式
应用待机模式让系统在用户不积极使用应用时确定应用处于空闲状态。系统会做出此判断的线索是用户在一段时间内没有触碰应用程序并且不符合以下条件之一时:
- 用户显式启动应用。
- 应用当前有一个进程位于前台,该进程要么作为 activity 或前台服务,要么被其他 activity 或前台服务使用。
注意:请仅将前台服务用于用户希望系统立即或不中断执行的任务。这类情况包括将照片上传到社交媒体,或者在音乐播放器应用程序不在前台的情况下播放音乐。不要仅仅为了防止系统判断你的应用处于空闲状态而启动前台服务。 - 应用生成一个通知,用户可以在锁定屏幕或通知托盘中看到。
如果设备未插电,系统将关闭待机应用的网络访问,并暂停同步和作业。如果设备长时间处于空闲状态,系统大约每天允许待机应用访问一次网络。
当用户将设备插入电源时,系统会将应用程序从待机状态释放出来,让它们自由地访问网络,执行任何待处理的任务和同步。
Android 7.0 API 24
Android 7.0包括一些系统行为变化来提高设备电池寿命和减少RAM使用。主要是对低电耗模式做了改进,另外对三项隐式广播进行了限制,其中网络活动广播会被很多app在清单文件中注册接收器来接收,而移动设备会经历频繁的连接变更,例如在 Wi-Fi 和移动数据网络之间的切换,每次网络切换就会导致这些app频繁唤醒来处理广播一次。可见对这类隐式广播进行限制是非常必要的。
低电耗模式改进
Android 6.0(API 级别 23)中引入,在设备未接通电源、静止不动,同时屏幕已关闭时,推迟CPU和网络活动来延长电池使用时间。Android 7.0为Doze 带来了进一步的增强,应用部分 CPU 和网络限制来增强低电耗模式。在拔下电源并关闭屏幕时启动,但不一定静止不动,例如,当手机放入口袋中时。
图 2. 低电耗模式如何应用第一级系统活动限制以延长电池续航时间的图示 。
当设备使用电池供电,屏幕关闭一定时间,设备就会进入Doze模式并应用第一部分限制:关闭app的网络访问,推迟作业和同步。如果设备进入Doze后静止了一段时间,系统会将剩下的Doze限制应用到PowerManager.WakeLock、AlarmManager闹钟、GPS和Wi-Fi扫描。无论应用的是部分或全部低电耗模式限制,系统都会唤醒设备来提供一个短暂的维护窗口期,在此期间应用允许网络访问,执行任何延迟的作业/同步。
图 3. 当设备进入低电耗模式后静止一段时间如何应用第二级系统活动限制的图示 。
请注意,激活屏幕或将设备插入电源会退出低电耗模式, 移除这些处理限制。额外的行为不会影响让你的应用适应Android 6.0 (API级别23)中引入的旧版本Doze的建议和最佳实践,正如Optimizing for Doze and App Standby 中所讨论的那样。您仍然应该遵循这些建议,例如使用 Firebase Cloud Messaging (FCM) 收发消息,并开始规划更新app以适应额外的Doze行为。
后台优化
后台进程可能会耗费大量内存和电池电量。例如,某一隐式广播可能会启动许多已注册监听它的后台进程,即使这些进程可能并没有执行很多任务。这会对设备性能和用户体验产生重大影响。
为缓解此问题,Android 7.0(API 级别 24)施加了以下限制( 移除了三项隐式广播):
- 对接收网络活动广播的限制。
如果以 Android 7.0(API 级别 24)及更高版本为目标平台的应用在清单中声明CONNECTIVITY_ACTION 广播接收器,则这些应用不会收到该广播。应用仍可以使用 Context.registerReceiver() 运行时注册 BroadcastReceiver 来接收 CONNECTIVITY_ACTION 广播。 - 对接收图片和视频广播的限制。
应用无法发送或接收 ACTION_NEW_PICTURE 或 ACTION_NEW_VIDEO 广播。此项优化会影响所有应用,而不仅仅是那些以 Android 7.0(API 级别 24)为目标平台的应用。
如果您的应用使用了其中的任何 intent,您应该尽快移除对它们的依赖,以便能正确的运行在搭载 Android 7.0 或更高版本的设备上。Android 框架提供了多种解决方案来缓解对这些隐式广播的需求。例如,JobScheduler 和新的 WorkManager 提供了强大的机制,可在满足指定条件时(例如连接到不按流量计费网络时)调度网络操作。您还可以使用 JobScheduler 来响应对 content provider 的更改。JobInfo 对象封装了 JobScheduler 用于调度作业的参数,当满足作业条件时,系统会在应用的 JobService 上执行此作业。
用户发起的限制
在系统设置中的电池用量页面上,用户可以选择以下选项:
- 无限制 - Unrestricted:允许所有后台工作,这可能会消耗更多电量。
- 优化(默认)- Optimized (default):根据用户与应用互动的方式,优化应用执行后台工作的能力。
- 受限 - Restricted:完全禁止应用在后台运行。应用可能无法正常运行。
注意:如果用户在将您的应用置于“受限”状态但之后启动了该应用,系统会暂时将该应用视为处于“无限制”状态。当用户停止与您的应用互动并开始与另一个应用互动时,系统会将您的应用重新置于“受限”状态。
如果应用出现 Android Vitals 中描述的一些不良行为,系统会提示用户限制该应用对系统资源的访问。
如果系统发现应用消耗的资源过多,就会通知用户,并为用户提供限制应用操作的选项。可触发此类通知的行为包括:
- 唤醒锁定过多:屏幕关闭时持续 1 小时的 1 次部分唤醒锁定
- 后台服务过多:应用的目标 API 级别低于 26 且后台服务过多
施加的确切限制由设备制造商决定。例如,在搭载 Android 9(API 级别 28)或更高版本的 AOSP build 中,在后台运行且处于“受限”状态的应用存在以下限制:
- 无法启动前台服务
- 现有的前台服务会从前台移除
- 不会触发闹钟
- 不会执行作业
此外,如果应用以 Android 13(API 级别 33)或更高版本为目标平台且处于“受限”状态,除非应用因其他原因启动,否则系统不会传送 BOOT_COMPLETED 广播或 LOCKED_BOOT_COMPLETED 广播。
Android 8.0 API 26
Android 8.0引入了app缓存状态来改善电池使用时间,当app没有活跃状态的组件时会进入缓存状态,系统会释放app持有的所有唤醒锁。
缓存进程
缓存的进程是当前不需要的进程,因此当其他地方需要内存等资源时,系统可以自由地杀死它。在正常运行的系统中,只有这些进程参与资源管理。
一个运行良好的系统总是有多个缓存进程可用,以便在应用程序之间进行有效切换,并根据需要定期杀死缓存的应用。只有在非常紧急的情况下,系统才会达到杀死所有缓存进程,并且必须开始杀死服务进程的地步。由于缓存的进程可以在任何时候被系统杀死,apps应该在缓存状态时停止所有工作。如果应用程序必须执行用户关键型工作,它应该从活跃进程状态运行工作。
进程按照重要性分类由高到低依次为前台进程,可见进程,服务进程,缓存进程,前三类都是活跃进程。有关详细信息请参阅进程和应用生命周期
缓存的进程通常持有一个或多个Activity实例,这些实例当前对用户不可见(它们的onStop()方法已被调用并返回)。当系统杀死这些进程时,如果它们正确地实现了它们的Activity生命周期,就不会影响用户返回到该应用程序时的体验。当关联的Activity在新进程中重新创建时,可以恢复先前保存的状态。需要注意的是,onDestroy()不能保证在进程被系统杀死的情况下被调用。
从Android 13开始,在进入上述活动生命周期状态之一之前,应用进程可能会获得有限的执行时间或没有执行时间。
缓存的进程保存在一个列表中。该列表的确切排序策略是平台的实现细节。通常,系统会尝试将更有用的进程(例如那些托管用户的主屏幕应用进程或用户看到的最后一个activity的进程)放在其他类型的进程之前。还可以应用其他杀死进程的策略,比如对允许的进程数量设置严格限制,或者限制进程可以保持缓存状态的时间。
此外,为了节约电池电量和提高设备性能,系统会限制未在前台运行的应用的行为,包括后台执行限制和后台位置限制。
后台执行限制
每当应用在后台运行时,都会消耗设备的有限资源(例如 RAM)。许多 Android 应用和服务可以同时运行。例如,用户可能在一个窗口中玩游戏,同时在另一个窗口中浏览网页,并使用第三个应用播放音乐。同时运行的应用越多,对系统造成的负担就越大。如果其他应用或服务在后台运行,这会对系统造成额外的负载,进而可能导致用户体验不好,例如,音乐应用可能会突然关闭。
为了降低出现这些问题的可能性,Android 8.0 会对用户不直接交互的应用程序可以执行的操作进行限制。应用程序在两个方面受到限制:
- 后台服务限制:应用处于空闲状态时,其后台服务的使用会受到限制。这不适用于前台服务,因为前台服务更容易被用户注意到。
- 广播限制:除了少数例外情况,应用无法使用其清单(在manifest.xml中)注册隐式广播。但仍然可以在运行时注册这些广播,并且可以使用清单注册显式广播和专门针对其应用的广播。
注意 :默认情况下,这些限制仅适用于以 Android 8.0(API 级别 26)或更高版本为目标平台的应用。不过,用户可以从设置屏幕中为任何应用启用大多数限制,即使应用以低于 26 的 API 级别为目标平台也是如此。
在大多数情况下,应用可以使用 JobScheduler 作业克服这些限制。这种方法可让应用安排在其未活跃运行时执行工作,但系统仍可在不影响用户体验的情况下调度这些作业。Android 8.0 对 JobScheduler 进行了多项改进,可让您更轻松地用计划作业取代受限的后台服务和隐式广播接收器;如需了解详情,请参阅 JobScheduler 改进。
后台服务限制
运行在后台的服务会消耗设备资源,这可能会降低用户体验。为了缓解这一问题,系统对服务施加了一些限制。
系统可以区分前台应用和后台应用。(出于服务限制目的的后台定义与内存管理所使用的定义不同;根据内存管理的规定,应用可能处于后台,但根据其启动服务的能力,处于前台。)应用满足以下任一条件即视为在前台:
- 它具有可见的 Activity,无论 Activity 处于启动还是暂停状态。
- 它具有前台服务。
- 另一个前台应用通过绑定到应用的一个服务或使用应用的一个 content provider 的方式连接到该应用。例如,如果另一个应用绑定到应用的服务,则该应用处于前台:
输入法
壁纸服务
通知侦听器
语音或文本服务
如果以上条件均不满足,应用即被视为在后台运行。
注意:这些规则不会以任何方式影响绑定服务。如果app定义了绑定服务,则无论应用是否在前台运行,其他组件都可以绑定到该服务。
处于前台时,应用可以自由创建和运行前台和后台服务。进入后台时,在一个持续数分钟的时间窗中,应用仍可以创建和使用服务。在该窗口期结束时,应用将被视为处于空闲状态。此时,系统会停止应用的所有后台服务,就像应用已经调用服务的 Service.stopSelf() 方法一样,经过测试一般1分钟左右就会杀死后台服务。
在某些情况下,系统会将后台应用列入临时许可名单,并持续几分钟。应用被列入许可名单后,可以无限制地启动服务,并且其后台服务也可以运行。当应用处理一项用户可见的任务时,系统就会将应用列入许可名单,例如:
- 处理高优先级 Firebase Cloud Messaging (FCM) 消息。
- 接收到广播,如短信/彩信消息。
- 从通知执行 PendingIntent。
- 在VPN应用程序将自己提升到前台之前启动VpnService。
Android系统通过调用startService()在后台启动VPN。在Android 8.0 (API级别26)及更高版本中,系统会在短时间内将VPN应用程序放在临时允许列表中,以便应用程序可以在后台启动。VPN应用程序启动后必须调用startForeground()将自己提升到前台,否则系统将关闭该应用程序。
在许多情况下,您的应用都可以使用 JobScheduler 作业替换后台服务。例如,CoolPhotoApp 需要检查用户是否已收到朋友分享的照片,即使该应用没有在前台运行也是如此。以前,应用使用的是后台服务,该服务会检查应用的云端存储空间。为了迁移到 Android 8.0(API 级别 26),开发者会将后台服务替换为计划作业(scheduled job),该作业将定期启动,查询服务器,然后退出。
在Android 8.0之前,创建前台服务的方式通常是先创建后台服务,然后将该服务提升到前台。Android 8.0 不允许后台应用创建后台服务,因此,Android 8.0 引入了 startForegroundService() 这一新方法,用于在前台启动新服务。系统创建服务后,应用有五秒钟的时间来调用服务的 [startForeground()]方法,以显示新服务的用户可见通知。如果应用在时间限制内未调用 startForeground(),系统会停止相应服务并声明应用为 ANR。
广播限制
如果应用注册为接收广播,则在每次发送广播时,应用的接收器都会消耗资源。如果太多应用注册为接收基于系统事件的广播,这可能会导致问题;触发广播的系统事件可能会导致所有应用快速连续消耗资源,从而影响用户体验。为了缓解这一问题,Android 7.0(API 级别 24)对广播施加了限制,如后台优化中所述。Android 8.0(API 级别 26)让这些限制更为严格。
- 以 Android 8.0 或更高版本为目标平台的应用无法再在其清单中为隐式广播注册广播接收器,除非广播仅限于该应用。隐式广播是一种不针对应用内特定组件的广播。例如,系统会向所有应用中所有已注册的监听器发送 ACTION_PACKAGE_REPLACED,让它们知道设备上的某些软件包已被替换。由于广播是隐式的,因此它不会传送到以 Android 8.0 或更高版本为目标平台的应用中在清单静态注册的接收器。ACTION_MY_PACKAGE_REPLACED 也是一种隐式广播,但由于它只会发送到软件包已被替换的应用,因此会传递给清单注册的接收器。
- 应用可以继续在它们的清单中注册显式广播。
- 应用可以在运行时使用 Context.registerReceiver() 为任何广播(无论是隐式还是显式)注册接收器。
- 需要签名权限的广播不受此限制的约束,因为这些广播只会发送到使用同一证书签名的应用,而不会发送到设备上的所有应用。
在许多情况下,之前注册隐式广播的应用可以使用 JobScheduler 作业获得类似的功能。例如,社交照片应用可能需要不时对其数据执行清理,并且倾向于在设备连接到充电器时执行此操作。以前,应用在其清单中为 ACTION_POWER_CONNECTED 注册了接收器;当应用收到该广播时,会检查是否有必要进行清理。为了迁移到 Android 8.0 或更高版本,应用将该接收器从其清单中移除。相反,应用会安排在设备处于空闲状态和充电时运行清理作业。
注意 :许多隐式广播目前都不受此限制的约束。无论应用的目标 API 级别是什么,都可以继续在其清单中注册这些广播的接收器。如需查看豁免广播的列表,请参阅隐式广播例外情况。
迁移指南
查看您的应用如何使用服务。如果你的应用依赖于在后台运行的服务,而你的应用是空闲的,您需要替换这些服务。可能的解决方法包括:
- 如果应用在后台运行时需要创建前台服务,请使用 startForegroundService() 方法,而非 startService()。
- 如果服务容易被用户注意到,请将其设为前台服务。例如,播放音频的服务应始终是前台服务。使用 startForegroundService() 方法(而非 startService())创建服务。
- 设法使用计划作业实现服务功能。如果服务没有在执行可立即被用户注意到的操作,您通常应该能够使用计划作业替代。
- 在发生网络事件时,使用 FCM 选择性地唤醒您的应用,而不是在后台轮询。
- 推迟后台工作,直到应用程序自然地出现在前台后再执行。
查看应用清单中定义的广播接收器。如果您的清单为受影响的隐式广播声明了接收器,您必须替换该接收器。可能的解决方法包括:
- 通过调用 Context.registerReceiver()(而不是在清单中声明接收器)在运行时创建接收器。
- 使用计划作业检查可能触发隐式广播的条件,如前面提到的电源已连接广播。
后台位置限制
为了降低功耗,系统会限制应用在后台运行时检索用户当前位置的频率。在此类情况下,应用每小时只能接收几次位置信息更新。
注意 :这些限制适用于在搭载 Android 8.0(API 级别 26)或更高版本的设备上使用的所有应用,无论应用的目标 SDK 版本为何。
如果您的应用在后台运行时依赖实时提醒或移动侦测,那么记住这个位置检索行为尤为重要。
前台应用行为得到保留
如果应用在搭载 Android 8.0(API 级别 26)的设备上处于前台,位置信息更新行为将与 Android 7.1.1(API 级别 25)及更低版本上相同。
优化应用的位置行为
考虑一下,如果你的应用程序接收到不频繁的位置更新,你的应用程序在后台运行的用例是否根本无法成功。如果是这种情况,您可以通过执行以下操作之一更频繁地检索位置更新:
- 将您的应用转至前台。
- 通过调用 startForegroundService() 在应用中启动前台服务。当此类前台服务处于活跃状态时,它在通知区域中显示为正在进行的通知。
注意:如果应用在搭载 Android 11(API 级别 30)或更高版本的设备上在后台运行时启动了前台服务,除非用户已向应用授予 ACCESS_BACKGROUND_LOCATION 权限,否则应用无法访问位置信息。如需了解详情,请参阅有关与前台服务关联的使用时限制的指南。
- 使用 Geofencing API 的元素(例如 GeofencingClient),这些元素经过了优化,可以最大限度地减少耗电量。
- 使用被动位置信息监听器,如果有前台应用以更快的频率请求位置信息更新,该监听器可以更快地接收位置信息更新。
注意:如果您的应用需要访问包含时间频繁更新的位置历史记录,请使用批处理版本的 Fused Location Provider API 元素,例如 FusedLocationProviderApi 接口。当您的应用在后台运行时,此 API 接收用户位置信息的频率会高于非批处理 API。但请注意,您的应用仍以每小时几次的频率批量接收更新。
受影响的API
对后台应用中位置信息检索行为的更改会影响以下 API:
一体化位置信息提供程序 (FLP)
- 如果您的应用在后台运行,位置系统服务只会每小时计算几次新位置给应用。即使您的应用更频繁地请求位置信息更新,也是如此。
不过,通过使用 批量版本的 FLP,你可以在应用程序收到批处理更新后访问更频繁的位置历史记录,这也是每小时只发生几次。
- 如果应用在前台运行,则与 Android 7.1.1(API 级别 25)相比,位置信息采样率没有变化。
地理围栏
- 与来自一体化位置信息提供程序的更新相比,后台应用可以更频繁地接收地理围栏 transition 事件。
GNSS Measurements 和 GNSS Navigation Messages
- 当您的应用位于后台时,已注册为接收 GnssMeasurement 和 GnssNavigationMessage 输出的回调会停止执行。
Location Manager
- 位置信息更新每小时仅向后台应用提供几次。
注意:如果您的应用在安装了 Google Play 服务的设备上运行,强烈建议您改用一体化位置信息提供程序 (FLP)。
Wi-Fi Manager
startScan() 方法每小时只对后台应用执行几次完整扫描。如果不久之后后台应用再次调用此方法,WifiManager 类会提供上次扫描的缓存结果。
Android 9 API 28
Android 9 引入了新功能来改进设备电源管理。这些变化,以及之前版本中已经存在的功能,有助于确保将系统资源提供给最需要它们的应用程序。
电源管理功能可以分为两个类别:
- 应用待机分桶 - App Standby Buckets
系统会根据用户的使用模式限制应用程序对设备资源的访问,比如CPU或电池。这是Android9.0新功能
- 省电模式改进 - Battery saver improvements。
当省电模式开启时,系统会对所有应用施加限制。这是一个现有的功能,在Android 9中得到了改进。
注意: 这些更改适用于所有应用,无论它们是否以 Android 9 为目标平台。
应用待机分桶
应用待机分桶有助于系统确定应用优先级基于资源请求的 以及使用应用的新近度和频率基于应用使用情况 模式时,每个应用都会归类到五个优先级之一的分桶中。系统 根据应用的分桶限制每个应用可用的设备资源 。
五个群组按照以下特性将应用分组(按优先级从高到低的顺序排列):
活跃 - Active
如果用户当前正在使用该应用,那么该应用将位于“活跃”分桶中,示例:
- 该应用启动了一个 Activity
- 该应用正在运行一项前台服务
- 该应用有一个与前台应用使用的内容提供程序相关联的同步适配器
- 用户点按了应用通知
系统不会对这些应用的作业、闹钟或 FCM 消息执行限制。
用户互动会使应用被分配到“活跃”分桶中
在 Android 9(API 级别 28)及更高版本中,当用户以某些方式与您的应用互动时,系统会暂时将您的应用放在“活跃”分桶中。当用户停止与应用互动后,系统会根据使用情况历史记录将应用放入某个分桶。
以下是触发此系统行为的互动示例:
- 用户点按您的应用发送的通知。
- 用户通过点按媒体按钮与应用的前台服务互动。
- 用户在与 Android Automotive OS 互动时连接到您的应用(您的应用在此过程中使用了前台服务或 CONNECTION_TYPE_PROJECTION)。
工作集- Working set
如果某个应用经常运行,但当前未在使用中,则会被分配到工作集分桶中。 例如,用户几乎每天都会启动的社交媒体应用就可能位于“工作集”分桶中。如果以间接的方式使用,应用也会被提升到“工作集”分桶。
系统会对这些应用的运行作业和触发闹钟的能力施加轻度限制。
常用 - Frequent
如果某个应用会定期使用,但不一定每天都使用,则会被分配到“常用”分桶中 。例如,用户在健身房运行的锻炼跟踪应用可能位于“常用”分桶中。
系统会对这些应用的运行作业和触发闹钟的能力施加更强的限制,还对应用的高优先级FCM消息设置了上限。
极少使用 - Rare
不经常使用的应用会被分配到“极少使用”分桶中。例如,用户仅在入住酒店期间才会运行的某个酒店应用就可能位于“极少使用”分桶中。
系统会对这些应用的运行作业、触发闹钟和接收高优先级FCM消息的能力施加严格限制,还会限制这些应用的连接互联网功能。
受限 - Restricted
此分桶是在 Android 12(API 级别 31)中引入的,它在所有分桶中的优先级最低,限制最高。系统会考虑应用的行为(例如,用户与之互动的频率),以决定是否要将您的应用放在“受限”分桶中。
在 Android 13(API 级别 33)及更高版本中,除非您的应用符合豁免条件,否则在以下情况下,系统会将您的应用放在“受限”分桶中:
- 用户未与您的应用互动的时间达到指定天数。在 Android 12(API 级别 31)和 12L(API 级别 32)中,此天数为 45 天。Android 13 将此天数减少到 8 天。
注意:设备处于关闭状态的时间不会计入互动限制。 - 您的应用在 24 小时内调用了过多的广播或绑定。
如果系统将您的应用放在“受限”分桶中,它会受到以下限制:
- 您每天可以在 10 分钟的批处理会话中运行作业一次。在此会话期间,系统会将该应用的作业与其他应用的作业编入一组。
- 与在其他限制较少的分桶中运行时相比,在”受限“分桶中,您的应用可以运行的加急作业更少。
- 您的应用每天可以调用一次闹钟。此 闹钟可以是 exact alarm 或 inexact alarm。
注意:与其他分桶不同,即使设备正在充电,这些电源管理限制也会对“受限”分桶起作用。不过,当设备正在充电、处于空闲状态以及使用不按流量计费的网络时,系统会放宽限制。
从未使用 - Never
已安装但从未运行的应用会被分配到“从未使用”存储分区。 系统会对这些应用施加极强的限制。
系统动态地将每个应用分配到一个优先级桶,并根据需要重新分配应用。系统可能依赖于一个预装的应用程序,该应用程序使用机器学习来确定每个应用程序被使用的可能性,并将应用程序分配到适当的桶中。如果设备上没有这样的系统应用,系统默认会根据最近使用的时间对应用进行排序。更活跃的应用被分配到更高优先级的bucket中,使应用可以使用更多的系统资源。具体而言,分桶决定了应用的作业运行频率、应用程序触发警报的频率以及应用程序接收高优先级Firebase Cloud Messaging (FCM)消息的频率。
这些限制仅适用于设备使用电池供电的情况;在设备充电时,系统不会对应用程序施加这些限制。
每个制造商都可以设置自己的标准,将非活动应用程序分配到buckets中。你不应尝试图影响你的应用被分配到哪个bucket。相反,你应该专注于确保你的应用在任何分桶里都表现良好。 应用可以调用新方法 UsageStatsManager.getAppStandbyBucket()来找出它当前在哪个bucket中。
低电耗模式许可名单中的应用不受应用待机分桶的限制。
也可以使用 ADB检查应用处于哪一个分桶
$ adb shell am get-standby-bucket [packagename]
只要您的应用被放在值大于 STANDBY_BUCKET_ACTIVE (10) 的应用待机分桶中,系统就会对您的应用加以限制。
最佳实践
如果您的应用遵循低电耗模式和应用待机模式的最佳实践,那么随后的电源管理功能并不难。不过,以前运行良好的某些应用行为现在可能会导致问题。
- 请勿试图迫使系统将您的应用放到某个分桶中。系统放置优先级的方法可能会变化,并且每个设备制造商都可能会选择使用自己的算法编写自己的分区应用。请改为确保应用无论位于哪个分桶都运行正常。
- 没有启动器 activity 的应用可能永远不会被提升到“活跃”分桶。请考虑重新设计应用,使其具有此类 activity。
- 如果用户无法与应用通知互动,则无法触发应用提升到“活跃”分桶。在这种情况下,不妨考虑重新设计一些允许用户互动的通知。如需了解一些相关准则,请参阅 Material Design 通知设计模式。
- 如果应用在收到高优先级 Firebase Cloud Messaging (FCM) 消息时不显示通知,用户便无法与应用互动,因而无法将其提升到“活跃”分桶。事实上,高优先级 FCM 消息的唯一预期用途就是向用户推送通知,因此这种情况绝不能出现。在 Android 12L(API 级别 32)及更低版本中,如果您将不会触发用户互动的 FCM 消息误标为高优先级,会导致系统降低后续消息的优先级。
注意:如果用户屡次忽略某个通知,系统会为用户提供以后屏蔽该通知的选项。请勿为了让应用保持在“活跃”分桶中而向用户发送大量通知。
- 如果应用拆分为多个软件包,这些软件包可能位于不同的分桶中,并具有不同的访问权限级别。请测试其软件包被分配到不同分桶的这些应用,以确保应用运行正常。
电源管理限制示例值
在每种情况下,生效的都是最具限制性的适用设置。例如,如果省电模式处于活跃状态且应用位于“极少使用”分桶中,则系统会对 Firebase Cloud Messaging (FCM) 应用更严格的应用待机分桶限制。
详情可查看电源管理限制
省电模式改进
Android 9 对省电模式进行了多项改进。 设备制造商可以决定施加的确切限制。例如,在 AOSP build 中,系统会应用以下限制:
- 系统会更积极地将应用置于应用待机模式,而不是等待应用进入空闲状态
- 后台执行限制适用于所有应用,无论其目标 API 为何 。
- 屏幕关闭时,位置信息服务可能会停用。
- 后台应用无法访问网络。
Android 10 API 29
针对从后台启动 activity 的限制
Android 10 (API级别29)和更高版本对应用程序在后台运行时何时可以启动activities进行了限制。这些限制有助于最大限度地减少对用户的干扰,并让用户更好地控制屏幕上显示的内容。
注意:为了启动activities,运行一项前台服务的应用也会被认为是在后台。有关详细信息,请参见 前台服务
本指南将通知作为从后台启动activities的替代方法。
改为显示通知
几乎在所有情况下,后台应用都必须 显示有时效性的通知 向用户提供紧急信息,而不是直接启动 activity。 此类通知包括处理来电或激活的闹钟。
这种基于通知的提醒系统对用户来说具有多种优势:
- 在使用设备时,用户会看到一个浮动通知,让他们做出回应。用户可以维持在当前上下文,并控制他们在屏幕上看到的内容。
- 具有时效性的通知会尊重用户的 勿扰规则。例如,当启用“请勿打扰”时,用户可能只允许来自特定联系人或重复呼叫者的呼叫。
- 当设备屏幕关闭时,全屏 intent会立即启动 。
- 在设备的设置屏幕中,用户可以查看哪些应用最近发送了通知,包括来自特定通知渠道的通知。 在该屏幕中,用户可以控制应用的通知偏好设置。
应用何时可以启动 activity
在 Android 10 或更高版本上运行的应用可以在以下情况下启动 activity(满足以下一个或多个条件):
注意: 从 Android 14 开始,除了满足这些条件外需要显式选择启用 。
- 该应用具有可见窗口,例如在前台运行的 Activity。
- 应用在前台任务的 返回堆栈 有一个Activity。
- 应用在 “最近使用的应用”屏幕上现有任务的返回堆栈中有一个Activity。
注意 : 当这样的应用试图启动一个新activity时,系统会将该activity放在应用现有任务的顶部,但不会从当前可见的任务中导航出去。当用户稍后返回到应用任务时,系统会启动新activity代替之前位于应用程序任务顶部的activity。
- 应用具有一个最近启动的 activity。
- 应用程序最近在一个活动上调用了finish()。这只适用于应用在调用finish()时要么有一个activity在前台,要么在前台任务的返回栈中有一个activity的情况。
- 应用具有以下受系统绑定的服务之一。这些 服务可能需要启动界面。
-
- AccessibilityService
- AutofillService
- CallRedirectionService
- HostApduService
- InCallService
- TileService (不适用于 Android 14 [API 级别 34] 及更高版本)
- VoiceInteractionService
- VrListenerService.
- 应用的某项服务被其他可见应用绑定了。绑定到服务的应用必须保持可见,以便在后台的应用可以成功启动activity。
注意: 从 Android 14 开始,如果绑定到服务的应用 以 Android 14 或更高版本为目标平台,则默认不再允许具有这个服务的应用从后台启动activity。应用必须传递标志 Context.BIND_ALLOW_ACTIVITY_STARTS 以允许被绑定服务应用来启动后台 activities。
- 应用收到来自系统的通知 PendingIntent。可以在意图被发送后的几秒钟内启动activity。
- 应用收到来自其他可见应用发出的PendingIntent。
- 应用收到系统广播,并被期待显示一个界面,比如 ACTION_NEW_OUTGOING_CALL 和 SECRET_CODE_ACTION。应用可在广播发送后的几秒钟内启动 Activity。
- 应用通过CompanionDeviceManager API与配套硬件设备关联。这个API允许应用启动activities来响应用户在配对设备上执行的操作。
- 应用是一个运行在设备所有者模式下的设备策略控制器。应用场景示例包括全托管式企业设备以及数字设备和自助服务终端等专用设备。
- 应用由用户授予了 SYSTEM_ALERT_WINDOW 权限。
注意 :在 Android 10(Go 版本)上运行的应用 无法获得 SYSTEM_ALERT_WINDOW 权限。
Android 11 API 30
应用休眠 - App hibernation
如果您的应用以 Android 11(API 级别 30)或更高版本为目标平台,并且用户几个月未与您的应用互动,系统会将该应用置于“休眠”状态。系统会针对存储空间而非性能进行优化,并保护用户数据。此系统行为与用户通过系统设置手动强行停止应用的操作类似。
休眠的影响
如表 1 所示,休眠的影响取决于应用的目标 SDK 版本以及运行应用的设备:
应用停止休眠状态时的系统行为
当用户下次与应用互动时,应用会停止休眠状态,并且可以再次创建作业、提醒(alerts)和通知。
不过,系统不会对应用执行以下操作:
- 重新授予应用运行时权限。
用户必须为应用重新授予这些权限。
- 重新调度在应用进入休眠状态之前调度的所有作业、提醒和通知。
为了更轻松地支持此工作流,请使用 WorkManager。您还可以在 ACTION_BOOT_COMPLETED 广播接收器中添加重新调度逻辑,系统会在您的应用停止休眠状态时以及设备启动后调用它。
应用使用
以下部分提供了应用使用示例,以及系统不会将其视为应用使用的操作示例。
应用使用标准示例
当应用中的 activity 恢复时,系统会将此事件视为一次用户互动。因此,系统会延长在将应用置于休眠状态之前需要等待的时间。
在 Android 11 及更高版本中,以下行为也会被视为用户互动:
- 用户与微件互动。
- 用户与通知互动(关闭通知除外)。
注意:如果用户关闭通知且未以其他方式与通知互动,系统不会将其视为应用使用。
需要注意的是,应用使用并不需要显示的用户互动,只要应用的某个组件被调用,系统就会将其视为应用使用。以下是这方面的一些示例:
- 应用的服务或 content provider 被设备上的其他应用或OS绑定。例如,输入法 (IMEs) 或密码管理器。
- 应用的广播接收器接收到了来自外部软件包的显式广播。
例外情况
如果应用仅表现出下表中的行为,则会在几个月后进入休眠状态:
- 使用 JobScheduler 运行计划作业。
- 接收隐式广播。
- 设置闹钟。
系统级休眠豁免
在某些用例中,Android 会授予应用休眠的系统级豁免。如果您的应用属于以下类别之一,该应用将不受应用使用标准的约束,且不会进入休眠状态。
- 应用不在启动器中显示
不在启动器中显示有效的快捷方式图块的任何应用。
- 工作资料应用
用户在工作资料上安装的任何应用。请注意,如果同一应用还位于个人资料中,只有工作资料上的应用可以免于休眠。
- 设备政策控制器
用于控制设备上的本地设备政策和系统应用的应用。
- 运营商特权应用
手机运营商在设备上预加载并认为是履行合同服务义务所必需的任何应用,例如语音信箱或客户服务应用。
- 第三方安装程序应用
可在必要时自动更新已安装应用的第三方应用商店。
用户请求休眠豁免
如果您预计应用中的核心用例会受到休眠的影响,可以向用户申请豁免,让其准许应用免于休眠。如果用户希望应用主要在后台运行,即使用户不与应用互动,应用也能正常工作,例如,当应用执行以下任一操作时,这种豁免很有用:
- 通过定期报告家庭成员的位置来保障家庭安全。
- 在设备与应用的服务器之间同步数据。
- 与智能设备(如电视)通信。
- 与配套设备(如手表)配对。
如需申请豁免,请完成以下部分中的步骤。
检查用户是否已为应用停用休眠
如需检查用户是否已为应用停用休眠,请使用 getUnusedAppRestrictionsStatus() API。
如需详细了解如何在应用中使用此 API,请参阅 API 代码示例。
请求用户为应用停用休眠
- 显示一个界面,向用户说明他们需要为应用停用休眠的原因。
- 调用 createManageUnusedAppRestrictionsIntent() API,如 API 代码示例所示。 此 API 会创建一个 intent,用于加载“设置”中的应用信息屏幕。在该页面中,用户可以为应用停用休眠。
发送此 intent 时,请务必调用 startActivityForResult(),而不是 startActivity()。
如表 2 所示,该选项的所在位置和名称取决于安装应用的设备的特征:
Android 12 API 31
应用待机分桶新增“受限”分桶
从 Android 12 开始引入了新的“受限”分桶作为一种应用待机分桶,此分桶默认处于活跃状态,受限分桶的优先级最低(限制最高),详情已经在前面应用待机分桶部分一起做了介绍。
如果您的应用更负责地使用系统资源,就不太可能被放在受限存储分区中。此外,如果用户直接与您的应用互动,系统会将其放在一个限制较少的存储分区中。
Activity生命周期
按下“返回”按钮时,根启动器 activity不再会finished
Android 12 更改了在按下“返回”按钮时系统对为其任务根的启动器 activity 的默认处理方式。在以前的版本中,系统会在按下“返回”按钮时finish这些 activity。在 Android 12 中,现在系统会将 activity 及其任务移到后台,而不是完成 activity。当使用主屏幕按钮或手势从应用中导航出应用时,新行为与当前行为一致。
注意:系统仅会将新行为应用于为其任务根的启动器 activity,即使用 ACTION_MAIN 和 CATEGORY_LAUNCHER 声明 intent 过滤器的 activity。对于其他 activity,在按下“返回”按钮时,系统会像以前一样完成 activity。
对于大多数应用而言,此变更意味着使用“返回”按钮退出应用的用户可以更快地从温状态恢复应用,而不必从冷状态完全重启应用。
如果您的应用目前替换 onBackPressed() 来处理返回导航并完成 Activity,请更新您的实现来调用 super.onBackPressed() 而不是完成 Activity。调用 super.onBackPressed() 可在适当时将 activity 及其任务移至后台,并可为不同应用中的用户提供更一致的导航体验。
Android 13 API 32
电池资源利用率
Android 13(API 级别 33)支持系统通过以下方式来更有效地管理设备电池续航时间:
“受限”应用待机分桶变更
更新了系统何时将您的应用放入“受限”应用待机分桶的相关规则,详情看前面应用待机分桶部分。
用户发起的限制变更
对于您的应用在以下情况下可以执行的操作制定了新限制:用户因您应用的后台电池用量过高而将其置于“受限”状态。这是在之前Android 7.0中介绍过的功能。
以下限制通常适用于处于“受限”状态的应用的后台电池使用:
- 无法启动前台服务
- 现有的前台服务会从前台移除
- 不会触发闹钟
- 不会执行作业
针对这些更改测试应用
可以使用以下ADB 命令将您的应用分配到“受限”应用待机分桶:
$ adb shell am set-standby-bucket PACKAGE_NAME restricted
可以使用以下 ADB 命令将您的应用放入“受限”状态
$ adb shell cmd appops set PACKAGE_NAME RUN_ANY_IN_BACKGROUND ignore
高优先级 Firebase Cloud Message (FCM) 配额变更
Android 13(API 级别 33)更新了 Firebase Cloud Messaging (FCM) 配额,以提高高优先级FCM交付的可靠性,这些应用在响应高优先级FCM时显示通知。以下内容在Android 13 (API level 33)中发生了变化:
- 应用待机分桶不再决定应用可以使用多少个高优先级 FCM。
- 高优先级 FCM 配额根据为响应高优先级 FCM 而向用户显示的通知数量按比例缩容。
FCM 在确定是否降低消息优先级或代理消息时,会使用 7 天的消息行为;它会针对您应用的每个实例单独做出这一决定。如果在响应高优先级消息时,以对用户可见的方式显示通知,那么今后的高优先级消息不会受到影响。
与以前的 Android 版本一样,超出配额的高优先级 FCM 会降级为普通优先级。为了响应 FCM 而启动前台服务 (FGS) 时,我们建议您检查 RemoteMessage.getPriority() 的结果并确认它为 PRIORITY_HIGH,并且/或者处理任何潜在的 ForegroundServiceStartNotAllowedException 异常。
如果您的应用并非始终为了响应高优先级 FCM 而发布通知,我们建议您将这些 FCM 的优先级更改为正常,这样生成通知的消息就不会降级。
Android 14 API 33
应用进入缓存状态,上下文注册的广播将加入队列
当应用位于缓存状态中,广播播传送会针对系统运行状况进行了优化,例如不太重要的系统广播 ACTION_SCREEN_ON 会在应用处于缓存状态时被延迟。当应用离开缓存状态(例如返回前台)时,系统会传递所有已加入队列的广播,某些广播的多个实例可能会合并为一个广播。
在清单中声明的广播不会加入队列,并且在清单中声明的重要广播会暂时将应用从缓存状态中移除以供交付。
可将应用放入“受限”待机分桶的新原因
Android 14引入了一个新的理由可以将一个应用放置到“受限”待机分桶。由于onStartJob、onStopJob或onBind方法超时引起应用的作业多次触发ANR错误。
注意: 请 参阅电池管理 ,以了解如果应用被放置在“受限”分桶会受到何种影响, 当用户将应用程序启动到前台时,应用程序会被移回活跃分桶,就像在以前的Android版本中一样。