Android后台耗电分析及优化

2024-06-13 02:18

本文主要是介绍Android后台耗电分析及优化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文见: 在路上的blog

Android后台耗电分析及优化

  • 一、什么是耗电优化?
  • 二、耗电优化第一个方向:优化后台耗电
    • 1、唤醒锁定操作卡住(前台&后台)
    • 2、唤醒次数过多
    • 3、WLAN扫描次数过多(后台)
    • 4、后台移动网络使用量过高
  • 三、耗电优化第二个方向:让系统认为是正常耗电
    • (1)海外应用
    • (2)国内应用之华为后台资源红线标准
    • (3)经验性总结规则
  • 四、耗电监控
    • 1、google vitals不适合
    • 2、合适的耗电监控方式
      • (1)解析bugreport
      • (2)Java Hook
      • (3)插桩
  • 五、名次解释

主要参考资料:

  • Android程序性能优化之耗电优化
  • Android vitals管理中心文档

开源后台耗电分析工具: battery_alalyze
在这里插入图片描述

一、什么是耗电优化?

在实践中,如果我们的应用需要播放视频、获取GPS信息、需要拍照,这些耗电看起来是无法避免的。
如果发现某个应用没怎么使用(前台时间很少),但是耗电却非常多。这种情况会跟用户的预期差别很大,这种情况就需要优化。

二、耗电优化第一个方向:优化后台耗电

根据Android Vitals定义,影响后台耗电的动作如下:

  • 唤醒锁定操作卡住
  • 唤醒锁定操作卡住(后台)
  • 唤醒次数过多
  • WLAN 扫描次数过多(后台)
  • 网络使用量过高(后台)

1、唤醒锁定操作卡住(前台&后台)

应用会通过调用带有 PARTIAL_WAKE_LOCK 标记的 acquire() 来获取部分唤醒锁定。当您的应用在后台运行时,如果部分唤醒锁定保持了较长时间,则会变为卡住状态(用户看不到应用的任何部分)。 它会阻止设备进入低功耗状态。部分唤醒锁定仅应在必要时使用,并且在不再需要时立即释放。

Android Vitals 报告部分唤醒锁定卡住的条件是在以下任一时段内至少发生了一次时长达 1 小时的部分唤醒锁定:
(1)所有情况下至少 0.70% 的电池工作时段

(2)仅在后台运行时至少 0.10% 的电池工作时段

唤醒锁定操作卡住的问题发现和修复建议

2、唤醒次数过多

唤醒是 AlarmManagerAPI 中的一种机制,可让开发者设置闹钟以在指定时间唤醒设备。为设置唤醒闹钟,您的应用会调用 AlarmManager 中某个带有 RTC_WAKEUP 或 ELAPSED_REALTIME_WAKEUP 标记的 set() 方法。当唤醒闹钟触发时,设备会在执行闹钟的 onReceive() 或 onAlarm() 方法期间退出低功耗模式并保持部分唤醒锁定。如果唤醒闹钟触发次数过多,则可能会耗尽设备的电池电量。

唤醒次数过多标准:用户遇到每小时 10 次以上唤醒的电池工作时段数百分比。

  • Vital 详细信息:
    • 受影响的工作时段数:用户遇到每小时 10 次以上唤醒的电池工作时段数百分比。电池会话是指设备在两次充满电之间的间隔时间。Google 仅会在设备未充电时收集这项数据。
    • 会话数:系统已记录的会话的大概数量。
    • 第 90/99 个百分位:10%/1% 的每日工作时段中用户每小时遇到唤醒次数高于显示的值。
      最低 25%:如果您的应用发生问题的工作时段比例等于或高于显示的阈值,则系统会将此应用归在这项指标的最低 25% 区间(依据为 Google Play 上前 1000 个热门应用,按安装量统计)。

唤醒过多修复及建议

3、WLAN扫描次数过多(后台)

当应用在后台执行 WLAN 扫描时,它会唤醒 CPU,从而加快耗电速度。扫描次数过多时,设备的电池续航时间可能会明显缩短。如果某个应用处于 PROCESS_STATE_BACKGROUND 或 PROCESS_STATE_CACHED 状态,则会被视为在后台运行。

WLAN 扫描次数过多的标准:在后台运行时,应用在 0.10% 的电池工作时段内每小时执行的扫描超过 4 次。

建议:如果可能,您的应用执行 WLAN 扫描时应该是在前台运行。前台服务会自动显示通知;在前台执行 WLAN 扫描,从而让用户知道设备上发生 WLAN 扫描的原因和时间。

扫描次数过多优化:如果您的应用无法避免在后台运行期间执行 WLAN 扫描,则可能适合采用偷懒至上策略。“偷懒至上”包含三种可用于消减 WLAN 扫描次数的方法:“减少”、“推迟”和“合并”。如需了解这些方法,请参阅针对电池续航时间进行优化。

4、后台移动网络使用量过高

当应用在后台连接移动网络时,应用会唤醒 CPU 并开启无线装置。如果反复执行此操作,可能会耗尽设备的电池电量。如果某个应用处于 PROCESS_STATE_BACKGROUND 或 PROCESS_STATE_CACHED 状态,则会被视为在后台运行。

后台网络使用量过高的标准:在后台运行时,应用在 0.10% 的电池工作时段内每小时发送和接收的数据合计达 50 MB。

建议:可以将应用的移动网络使用量移至前台,提醒用户目前正在进行下载,并为他们提供暂停或停止下载的控件。为此,请调用 DownloadManager 并根据情况设置 setNotificationVisibility(int)。

三、耗电优化第二个方向:让系统认为是正常耗电

如何让系统认为是正常耗电呢?当耗电指标低于规则时,系统也就认为是正常耗电了。

(1)海外应用

海外应用主要参考Google Vitals的规则。
对于Google Vitals的后台耗电过多统计规则中的电池工作时段百分比,对于质量评估来看,较难把握。所以主要关注规则的具体指标,即相对更严格的质量要求:
在这里插入图片描述

(2)国内应用之华为后台资源红线标准

在这里插入图片描述

(3)经验性总结规则

对于国内应用来说,目前还没有非常通用且权威的后台耗电规则,根据经验,我们将监控的内容抽象成规则。
当然不同应用监控的事项或者参数都不太一样。由于每个应用的具体情况都不太一样。
下面是一些可以用来参考的简单规则。
在这里插入图片描述

四、耗电监控

那我们的耗电监控系统应该监控哪些内容,怎么样才能比 Android Vitals 做得更好呢?

  • 监控信息:简单来说系统关心什么,我们就监控什么,而且应该以后台耗电监控为主。类似 Alarm wakeup、WakeLock、WiFi scans、Network 都是必须的,其他的可以根据应用的实际情况。如果是地图应用,后台获取 GPS 是被允许的;如果是计步器应用,后台获取 Sensor 也没有太大问题。
  • 现场信息:监控系统希望可以获得完整的堆栈信息,比如哪一行代码发起了 WiFi scans、哪一行代码申请了 WakeLock 等。还有当时手机是否在充电、手机的电量水平、应用前台和后台时间、CPU 状态等一些信息也可以帮助我们排查某些问题。

1、google vitals不适合

缺点:

  • 耗电规则无法修改
  • 无法拿到堆栈和其他电池信息
  • 国内应用无法使用

2、合适的耗电监控方式

(1)解析bugreport

通常大家可能会使用Battery Historian来分析后台耗电,但是不够灵活。比如需要人工查看各资源使用情况及是否达标。所以用python实现了一个简单的分析bugreport文件的小工具;
核心代码是刚做测开半年左右写的,比较乱且水平有限,大家轻拍,也欢迎大家参与优化。

  • 实现逻辑:
    • 重置电池统计信息和历史记录(dumpsys batterystats --reset)
    • 打开详细的wakelock数据开关,日志量较大,一般可正常保存3个小时以内。
      • dumpsys batterystats --enable full-wake-history --启用
      • dumpsys batterystats --disable full-wake-history --关闭
    • 导出bugreport文件
      • Android 7.0 and higher: adb bugreport > bugreport.zip
      • Android 6.0 and lower: adb bugreport > bugreport.txt
    • 利用battery_analyze生成后台耗电报告
      在这里插入图片描述

(2)Java Hook

Hook 方案的好处在于使用者接入非常简单,不需要去修改自己的代码。下面我以几个比较常用的规则为例,看看如果使用 Java Hook 达到监控的目的。

  • WakeLock:WakeLock 用来阻止 CPU、屏幕甚至是键盘的休眠。类似 Alarm、JobService 也会申请 WakeLock 来完成后台 CPU 操作。WakeLock 的核心控制代码都在PowerManagerService中,实现的方法非常简单。

// 代理 PowerManagerService
ProxyHook().proxyHook(context.getSystemService(Context.POWER_SERVICE), "mService", this)@Override
public void beforeInvoke(Method method, Object[] args) {// 申请 Wakelockif (method.getName().equals("acquireWakeLock")) {if (isAppBackground()) {// 应用后台逻辑,获取应用堆栈等等     } else {// 应用前台逻辑,获取应用堆栈等等}// 释放 Wakelock} else if (method.getName().equals("releaseWakeLock")) {// 释放的逻辑    }
}
  • Alarm:Alarm 用来做一些定时的重复任务,它一共有四个类型,其中ELAPSED_REALTIME_WAKEUP和RTC_WAKEUP类型都会唤醒设备。同样,Alarm 的核心控制逻辑都在AlarmManagerService中,实现如下:
// 代理 AlarmManagerService
new ProxyHook().proxyHook(context.getSystemService
(Context.ALARM_SERVICE), "mService", this)public void beforeInvoke(Method method, Object[] args) {// 设置 Alarmif (method.getName().equals("set")) {// 不同版本参数类型的适配,获取应用堆栈等等// 清除 Alarm} else if (method.getName().equals("remove")) {// 清除的逻辑}
}
  • 其他:对于后台 CPU,我们可以使用卡顿监控相关的方法。对于后台网络,同样我们可以通过网络监控相关的方法。对于 GPS 监控,我们可以通过 Hook 代理LOCATION_SERVICE。对于 Sensor,我们通过 Hook SENSOR_SERVICE中的“mSensorListeners”,可以拿到部分信息。

通过 Hook,我们可以在申请资源的时候将堆栈信息保存起来。当我们触发某个规则上报问题的时候,可以将收集到的堆栈信息、电池是否充电、CPU 信息、应用前后台时间等辅助信息也一起带上。

(3)插桩

虽然使用 Hook 非常简单,但是某些规则可能不太容易找到合适的 Hook 点。而且在 Android P 之后,很多的 Hook 点都不支持了。
出于兼容性考虑,我首先想到的是写一个基础类,然后在统一的调用接口中增加监控逻辑。以 WakeLock 为例:

public class WakelockMetrics {// Wakelock 申请public void acquire(PowerManager.WakeLock wakelock) {wakeLock.acquire();// 在这里增加 Wakelock 申请监控逻辑}// Wakelock 释放public void release(PowerManager.WakeLock wakelock, int flags) {wakelock.release();// 在这里增加 Wakelock 释放监控逻辑}
}

Facebook 也有一个耗电监控的开源库Battery-Metrics,它监控的数据非常全,包括 Alarm、WakeLock、Camera、CPU、Network 等,而且也有收集电量充电状态、电量水平等信息。
Battery-Metrics 只是提供了一系列的基础类,在实际使用中,接入者可能需要修改大量的源码。但对于一些第三方 SDK 或者后续增加的代码,我们可能就不太能保证可以监控到了。这些场景也就无法监控了,所以 Facebook 内部是使用插桩来动态替换。
遗憾的是,Facebook 并没有开源它们内部的插桩具体实现方案。大家可以自行搜索不同插桩方案的实现。
插桩方案使用起来兼容性非常好,并且使用者也没有太大的接入成本。但是它并不是完美无缺的,对于系统的代码插桩方案是无法替换的,例如 JobService 申请 PARTIAL_WAKE_LOCK 的场景。

五、名次解释

  • 电池工作时段:是指两次电池充满电的时间间隔。

这篇关于Android后台耗电分析及优化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1056008

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

HDFS—存储优化(纠删码)

纠删码原理 HDFS 默认情况下,一个文件有3个副本,这样提高了数据的可靠性,但也带来了2倍的冗余开销。 Hadoop3.x 引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。 此种方式节约了空间,但是会增加 cpu 的计算。 纠删码策略是给具体一个路径设置。所有往此路径下存储的文件,都会执行此策略。 默认只开启对 RS-6-3-1024k

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

MySQL高性能优化规范

前言:      笔者最近上班途中突然想丰富下自己的数据库优化技能。于是在查阅了多篇文章后,总结出了这篇! 数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来) 数据库对象的命名要能做到见名识意,并且最后不要超过32个字符 临时库表必须以tmp_为前缀并以日期为后缀,备份

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存