方法指南

电池技术质量强制执行机制已推出:如何优化常见的唤醒锁定使用情形

阅读用时:8 分钟
Alice Yuan
开发者关系工程师

考虑到 Android 用户最先想到电池耗电过快的问题,Google 一直在采取重大措施,帮助开发者构建更省电的应用。自 2026 年 3 月 1 日起,Google Play 商店开始推出唤醒锁定技术质量处理,以改善电池耗电问题。我们将在未来几周内逐步向受影响的应用推出此处理方式。如果应用在 Android Vitals 中持续超出“过多的部分唤醒锁定”阈值,其商店发布可能会受到明显影响,包括商品详情中显示警告以及从推荐等发现途径中排除。

appDetails.png

如果您的应用超出了不良行为阈值,用户可能会在您的商品详情中看到一条警告。 

这项计划将电池效率提升为与崩溃和 ANR 等稳定性指标并列的核心 Vitals 指标。“不良行为阈值”是指在过去 28 天内,在超过 5% 的用户会话中,当屏幕处于关闭状态时,平均持有非豁免的部分唤醒锁定至少两小时。如果唤醒锁定是系统持有的唤醒锁定,可提供无法进一步优化的明确用户益处(例如音频播放、位置信息访问或用户发起的数据传输),则可免除此要求。您可以在 Android Vitals 文档中查看过度唤醒锁定的完整定义。

为了持续改进整个 Android 生态系统的电池续航时间,我们分析了数千个应用及其使用部分唤醒锁的方式。虽然唤醒锁定有时是必要的,但我们经常看到应用在有更高效的解决方案的情况下,仍以低效或不必要的方式持有唤醒锁定。这篇博文将介绍发生过多的唤醒锁的最常见场景,并提供有关优化唤醒锁的建议。我们已经看到,WHOOP 等合作伙伴利用这些建议优化了其后台行为,并取得了可衡量的成功。

使用前台服务与使用部分唤醒锁

我们经常看到,开发者在进行后台执行时,很难理解两个概念之间的区别:前台服务和部分唤醒锁定。

前台服务是一种生命周期 API,用于向系统发出信号,表明应用正在执行用户可感知的工作,不应为了回收内存而终止该应用,但它不会在屏幕关闭时自动阻止 CPU 进入休眠状态。相比之下,部分唤醒锁定是一种专门用于在屏幕关闭时保持 CPU 运行的机制。

虽然前台服务通常是继续执行用户操作所必需的,但只有在 CPU 活动期间,才需要与前台服务结合使用手动获取的部分唤醒锁定。此外,如果您已使用可使设备保持唤醒状态的 API,则无需使用唤醒锁定。

请参阅选择合适的 API 以保持设备唤醒状态中的流程图,确保您充分了解应使用哪种工具来避免在不必要的场景中获取唤醒锁定。

获取唤醒锁定的第三方库

应用通常会发现,由于第三方 SDK 或系统 API 代表其持有过多的唤醒锁定,该应用被标记为存在问题。如需找出并解决这些唤醒锁定问题,我们建议您按以下步骤操作:

  • 检查 Android Vitals:在“过多的部分唤醒锁定”信息中心内找到有问题的唤醒锁定的确切名称。将此名称与识别由其他 API 创建的唤醒锁指南进行交叉对比,看看它是否是由已知的系统 API 或 Jetpack 库创建的。如果是,您可能需要优化 API 用量,并可参考建议的指南。
  • 捕获系统轨迹:如果无法轻松识别唤醒锁定,请使用系统轨迹在本地重现唤醒锁定问题,然后使用 Perfetto 界面检查该轨迹。如需详细了解如何执行此操作,请参阅这篇博文的调试其他类型的过度唤醒锁定 部分
  • 评估替代方案:如果低效的第三方库是造成此问题的原因,并且无法配置为尊重电池续航时间,请考虑与 SDK 的所有者沟通此问题、寻找替代 SDK 或自行构建相应功能。

常见的唤醒锁定场景

下面列出了一些我们审核过的具体应用场景,以及优化唤醒锁定实现方式的推荐途径。

用户发起的上传或下载

应用场景示例

  • 用户触发下载大型文件以供离线访问的视频在线播放应用。
  • 媒体备份应用,用户通过通知提示触发上传近期拍摄的照片。

如何减少唤醒锁定: 

一次性或定期后台同步

应用场景示例

  • 应用会定期执行后台同步,以提取数据供离线访问。
  • 定期获取步数的计步器应用。

如何减少唤醒锁定

  • 请勿获取手动唤醒锁定。使用配置为一次性或周期性工作的 WorkManagerWorkManager 通过批处理任务来维护系统健康状况,并且具有最小周期性间隔(15 分钟),这通常足以满足后台更新的需求。
  • 如果您发现 WorkManager 或 JobScheduler 创建的唤醒锁定使用率很高,可能是因为您错误地配置了 worker,导致其在某些情况下无法完成工作。考虑分析工作器停止原因,尤其是在您发现 STOP_REASON_TIMEOUT 出现频率很高时。
  workManager.getWorkInfoByIdFlow(syncWorker.id)
  .collect { workInfo ->
      if (workInfo != null) {
        val stopReason = workInfo.stopReason
        logStopReason(syncWorker.id, stopReason)
      }
  }
  • 除了记录工作器停止原因之外,您还可以参阅有关调试工作器的文档。此外,还可以考虑收集和分析系统轨迹 ,以了解何时获取和释放唤醒锁定。
  • 最后,不妨查看我们与 WHOOP 合作的案例研究,了解他们如何发现 worker 配置方面的问题并显著降低唤醒锁定(wake lock)的影响。

蓝牙通信

应用场景示例

  • 配套设备配套应用会提示用户配对蓝牙外部设备。
  • 配套设备应用会监听外部设备上的硬件事件以及通知中用户可见的更改。
  • 配套设备应用的用户在移动设备和蓝牙设备之间发起文件传输。
  • 配套设备应用通过蓝牙偶尔会更新外部设备的固件。

如何减少唤醒锁定

  • 使用配套设备配对来配对蓝牙设备,以避免在蓝牙配对期间获取手动唤醒锁定。
  • 请参阅 在后台通信指南,了解如何进行后台蓝牙通信。
  • 如果延迟沟通不会对用户造成影响,通常使用 WorkManager 就足够了。如果认为手动唤醒锁定是必要的,则仅在蓝牙活动或处理活动数据期间持有唤醒锁定。

地理位置跟踪

应用场景示例

  • 缓存位置数据以供日后上传(例如绘制跑步路线)的健身应用
  • 以高频提取位置数据,以便在通知或 widget 界面中更新配送进度的外卖应用。

如何减少唤醒锁定

  override fun onCreate(savedInstanceState: Bundle?) {
    locationCallback = object : LocationCallback() {
        override fun onLocationResult(locationResult: LocationResult?) {
            locationResult ?: return
            // System wakes up CPU for short duration
            for (location in locationResult.locations){
                // Store data in memory to process at another time
            }
        }
    }
}

高频传感器监控

应用场景示例

  • 被动收集步数或行走距离的计步器应用。
  • 安全应用,可实时监控设备传感器,以检测快速变化,从而提供车祸检测或跌倒检测等功能。

如何减少唤醒锁定

  • 如果使用 SensorManager,请将使用频率降低到定期间隔,并且仅在用户通过界面互动明确授予访问权限时使用。高频传感器监控会因 CPU 唤醒次数和处理次数过多而严重消耗电池电量。
  • 如果您要跟踪步数或行进距离,请使用 Recording API,而不是使用 SensorManager;或者考虑使用 健康数据共享 来访问历史和汇总的设备步数,以便以省电的方式捕获数据。
  • 如果您要使用 SensorManager 注册传感器,请指定 30 秒或更长的 maxReportLatencyUs,以利用传感器批处理来最大限度地减少 CPU 中断的频率。当设备随后因用户互动、位置信息检索或预定作业等其他触发因素而被唤醒时,系统会立即调度缓存的传感器数据。
  val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)

sensorManager.registerListener(this,
                 accelerometer,
                 samplingPeriodUs, // How often to sample data
                 maxReportLatencyUs // Key for sensor batching 
              )
  • 如果您的应用需要位置数据和传感器数据,请同步其事件检索和处理。通过将传感器读数搭载到系统为位置信息更新而持有的短暂唤醒锁定上,您可以避免需要唤醒锁定来保持 CPU 唤醒。使用工作线程或短时唤醒锁定来处理此组合数据的上传和处理。

远程消息传递

应用场景示例

  • 需要监控通过本地网络连接的外部设备上发生的事件的视频或声音监控配套应用。
  • 与桌面版保持网络套接字连接的即时通讯应用。

如何减少唤醒锁定

  • 如果可以在服务器端处理网络事件,请使用 FCM 在客户端接收信息。如果需要对 FCM 数据进行额外处理,您可以选择安排加急处理程序
  • 如果必须通过套接字连接在客户端处理事件,则无需唤醒锁定来监听事件中断。当数据包到达 Wi-Fi 或移动网络无线装置时,无线装置硬件会以内核唤醒锁的形式触发硬件中断。然后,您可以选择安排工作器或获取唤醒锁定来处理数据。
  • 例如,如果您使用 ktor-network 侦听网络套接字上的数据包,则仅当数据包已传递到客户端并需要处理时,才应获取唤醒锁定。
  val readChannel = socket.openReadChannel()
while (!readChannel.isClosedForRead) {
    // CPU can safely sleep here while waiting for the next packet
    val packet = readChannel.readRemaining(1024) 
    if (!packet.isEmpty) {
         // Data Arrived: The system woke the CPU and we should keep it awake via manual wake lock (urgent) or scheduling a worker (non-urgent)
         performWorkWithWakeLock { 
              val data = packet.readBytes()
              // Additional logic to process data packets
         }
    }
}

摘要

通过针对后台同步、位置跟踪、传感器监控和网络通信等常见用例采用这些推荐的解决方案,开发者可以努力减少不必要的唤醒锁定使用。如需继续学习,请阅读我们的其他技术博文,或观看我们的技术视频,了解如何发现和调试唤醒锁定:使用 Android Vitals 唤醒锁定指标优化应用电池用量另请参阅我们更新的唤醒锁定文档。为帮助我们不断改进技术资源,请在文档反馈调查问卷中分享您对我们指南的任何其他反馈。

作者:

继续阅读