Android电量/功耗优化指南

基础知识

电能 = 电压 * 电流 * 时长
模块电量(mAh) = 模块电流(mA) * 时长(h)

系统电量优化红线规则
image.png
华为电量优化红线规则
image.png

电量分析

Android 系统电量计算

Android 系统的电量统计工作,是由一个叫 BatteryStatsService 的系统服务完成的。
其中四个比较关键的角色:

  • 功率:power_profile.xml,Android 系统使用此文件来描述设备各个硬件模块的额定功率,包括上面提到的多档位功率和 CPU 电量算需要到的各种参数值。

Android 系统要求不同的厂商必须在 /frameworks/base/core/res/res/xml/power_profile.xml 中提供组件的电源配置文件。

  • 从手机中导出 /system/framework/framework-res.apk 文件。
  • 使用反编译工具(如 apktool)对导出文件 framework-res.apk 进行反编译。
  • 查看 power_profile.xml 文件在 framework-res 反编译目录路径:/res/xml/power_profile.xml。
<?xml version="1.0" encoding="utf-8"?>
<device name="Android"><!-- 显示相关配置 --><!-- 环境模式的平均电流消耗,包含背光 --><!-- 环境模式主要应用在 TV 上,类似电脑中的屏幕保护。 --><item name="ambient.on.display0">0.1</item>  <!-- ~100mA --><!-- 环境模式的平均电流消耗,不包含背光 --><item name="screen.on.display0">0.1</item>  <!-- ~100mA --><!-- 全亮度时背光的平均电流消耗 --><item name="screen.full.display0">0.1</item>  <!-- ~100mA --><!-- 蓝牙数据传输 --><item name="bluetooth.active">0.1</item> <!-- ~10mA --><!-- 蓝牙开启并可连接,但未连接状态 --><item name="bluetooth.on">0.1</item> <!-- ~0.1mA --><!-- WIFI 开启 --><item name="wifi.on">0.1</item> <!-- ~3mA --><!-- WIFI 数据传输 --><item name="wifi.active">0.1</item> <!-- ~200mA --><!-- WIFI 扫描 --><item name="wifi.scan">0.1</item> <!-- ~100mA --><!-- 音频 --><item name="audio">0.1</item> <!-- ~10mA --><!-- 视频 --><item name="video">0.1</item> <!-- ~50mA --><!-- 相机闪光灯 --><item name="camera.flashlight">0.1</item> <!-- ~160mA --><!-- 相机平均值 --><item name="camera.avg">0.1</item> <!-- ~550mA --><!-- GPS 开启 --><item name="gps.on">0.1</item> <!-- ~50mA --><!-- 移动通信模块相关值。对于固件中没有能源报告支持的调制解调器,请使用 radio.active、radio.scanning 和 radio.on。 --><!-- 移动通信模块传输 --><item name="radio.active">0.1</item> <!-- ~200mA --><!-- 移动通信模块信号扫描 --><item name="radio.scanning">0.1</item> <!-- ~10mA --><!-- 移动通信模块传输时不同信号强度下的电流消耗 --><array name="radio.on"> <!-- 信号强度 0 到 BINS-1 --><value>0.2</value> <!-- ~2mA --><value>0.1</value> <!-- ~1mA --></array><!--CPU 运行时的额外功耗(不包括集群和核心)--><array name="cpu.active"><value>0.1</value></array><!-- 每个 CPU 集群的核心数 --><!-- CPU 集群就是常说的 CPU 大小核。例如下面就列举了,有两个 CPU 集群(暂时可以理解为 大核+小核,4个大核,2个小核)。<array name="cpu.clusters.cores"><value>4</value> // cluster 0 has cpu0, cpu1, cpu2, cpu3<value>2</value> // cluster 1 has cpu4, cpu5</array>--><array name="cpu.clusters.cores"><value>1</value> <!-- cluster 0 has cpu0 --></array><!-- 不同 CPU 集群的运行速率--><array name="cpu.speeds.cluster0"><value>400000</value> <!-- 400 MHz CPU speed --></array><!--- CPU 集群运行时电流消耗 --> <array name="cpu.active.cluster0"><value>0.1</value>  <!-- ~100mA --></array><!-- CPU 空闲时电流消耗 --><item name="cpu.idle">0.1</item><!-- 内存组件(内存总线、内存控制器、RAM 等)电流消耗 --><array name="memory.bandwidths"><value>22.7</value> <!-- mA for bucket: 100mb/s-1.5 GB/s memory bandwidth --></array><!-- 标压下电池容量,单位 mAh --><item name="battery.capacity">1000</item><!-- WIFI 相关配置 --><!-- WIFI 控制器(负责管理 Wi-Fi 连接、数据传输和接收等操作)空闲时电流消耗,默认为 0 --><item name="wifi.controller.idle">0</item><!-- WIFI 控制器接收时电流消耗,默认为 0 --><item name="wifi.controller.rx">0</item><!-- WIFI 控制器传输时电流消耗,默认为 0 --><item name="wifi.controller.tx">0</item><!-- WIFI 控制器在不同传输功率下的电流消耗,默认为空 --><!-- 不同传输功率通常与 WIFI 信号强度、距离有关 --><array name="wifi.controller.tx_levels"> <!-- mA --></array><!-- WIFI 控制器工作电压,单位 mV,默认为 0 --><item name="wifi.controller.voltage">0</item><!-- WIFI 控制器在批量扫描时的电流消耗 --><array name="wifi.batchedscan"> <!-- mA --><value>.0002</value> <!-- 1-8/hr --><value>.002</value>  <!-- 9-64/hr --><value>.02</value>   <!-- 65-512/hr --><value>.2</value>    <!-- 513-4,096/hr --><value>2</value>    <!-- 4097-/hr --></array><!-- 移动通信模块(如蜂窝网络、LTE、5G)相关配置--><modem><!-- 睡眠状态电流消耗,单位 mA --><sleep>0</sleep><!-- 空闲状态电流消耗,单位 mA --><idle>0</idle><!-- 可根据不用模式指定多个 <active> 标签 --><!-- 可用属性:rat: 指定移动通信技术:LTE、NR、DEFAULTnrFrequency: NR 处于活动状态时频率级别:"LOW"、"MID"、"HIGH"、"MMWAVE"、"DEFAULT",LOW 表示 <1GHzMID 表示 1GHz - 3GHzHIGH 表示 3GHz - 6GHzMMWAVE 表示 >6GHz--><active rat="DEFAULT"><!-- 接收时电流消耗,单位 mA --><receive>0</receive><!-- 传输时电流消耗,单位 mA。必须定义所有级别(0 到 4) --><transmit level="0">0</transmit><transmit level="1">0</transmit><transmit level="2">0</transmit><transmit level="3">0</transmit><transmit level="4">0</transmit></active></modem><!-- 移动通信模块(调制解调器)工作电压,单位 mV --><item name="modem.controller.voltage">0</item><!-- GPS 相关配置 --><!-- GPS 信号强度 --><array name="gps.signalqualitybased"> <!-- 强度 0 to 1 --><value>0</value><value>0</value></array><!-- GPS 工作电压,单位 mV --><item name="gps.voltage">0</item>
</device>
  • 时长:StopWatch & SamplingCounter,其中 StopWatch ⏱ 是用来计算 App 各种硬件模块的使用时长,而 SamplingCounter 则是用来采样统计 App 在不同 CPU Core 和不同 CpuFreq 下的工作时长。
  • 计算:PowerCalculators,每个硬件模块都有一个相应命名的 PowerCalculator 实现,主要是用来完成具体的电量统计算法。
  • 存储:batterystats.bin,电量统计服务相关数据的持久化文件。

image.png

统计

BatteryStatsService 持有 BatteryStats 类,BatteryStats 又持有一个 Uid [] 数组,每一个 Uid 对应一个 App,安装或者卸载 App ,BatteryStats 会更新相应的 Uid 元素的映射关系。同时 BatteryStats 持有一系列的 StopWatch 和 SamplingCounter,当 App 开始使用某些硬件模块的功能时,BatteryStats 就会调用相应 Uid 的 StopWatch 或 SamplingCounter 来统计其硬件使用时长。
以 Wifi 模块来举例:

  • 当 App 通过 WifiManager 系统服务调用 Wifi 模块开始扫描的时候,实际上会通过 WifiManager#startScan () --> WifiScanningServiceImp --> BatteryStatsService#noteWifiScanStartedFromSource () --> BatteryStats#noteWifiScanStartedLocked (uid) 等一连串的调用,通知 BatteryStats 开启 App 相应 Uid 的 Wifi 模块的 StopWatch 开始计时。
  • 当 App 通过 WifiManager 停止 Wifi 扫描的时候又会通过类似的流程调用 BatteryStats#noteWifiScanStoppedLocked (uid) 结束 StopWatch 的计时,这样一来就通过 StopWatch 完成 App 对 Wifi 模块使用时长的统计。

计算

BatteryStats 是通过依赖的一个 BatteryStatsHelper 的辅助类来完成的。BatteryStatsHelper 通过组合使用 Uid 里的时长数据、PoweProfile 里的功率数据(power_profile.xml 的解析实例)以及具体各个模块的 PowerCalculator 算法,计算出每一个 App 的综合电量消耗,并把计算结果保存在 BatterySipper [] 数组里(按计算值从大到小排序)。
以 Wifi 模块来举例:

  • 当需要计算 App 电量消耗的时候,BatteryStats 会通过调用 BtteryStatsHelper#refreshStats () --> #processAppUsage () 来刷新 BatterySipper [] 数组以计算最新的 App 电量消耗数据。
  • 其中 Wifi 模块单独的电量统计就是在 processAppUsage 方法中通过 WifiPowerCalculator 来完成的:Wifi 模块电量 = PowerProfile 预置的 Idle 功率 + Uid 统计的 Wifi Idle 时间 + 上行功率 × 上行时间 + 下行功率 × 下行时间。

工具

工具优点缺点
手机耗电排行直观没有详细数据
监听电池状态可知电池状态、电量只是整体耗电情况、非实时
dumpsys batterystats可知App整体耗电量、各功能模块耗电量可读性比较差、非实时
Battery Historian结果直观、有耗电量详情适应 Android 5.0 及以上系统、无堆栈信息、非实时
BatteryCanary实时监测、支持问题堆栈

手机耗电排行

image.png

监听电池状态

获取充电状态、电池电量
监控电池电量和充电状态

IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryState = registerReceiver(null, intentFilter);
int chargeType = batteryState.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
Log.e("qingshan","充电方式 = " + chargeType); //1.交流电;2.USB;4.无线充电
int batteryPower = batteryState.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
Log.e("qingshan","电量 = " + batteryPower);

dumpsys batterystats

通过 dumpsys batterystats 导出。

$ adb shell dumpsys batterystats your.package.name > battery.txt# 各个Uid的总耗电量,而且是粗略的电量计算估计。
# Estimated power use (mAh):
#     Capacity: 3450, Computed drain: 501, actual drain: 552-587
#     ...
#     Idle: 41.8
#     Uid 0: 135 ( cpu=103 wake=31.5 wifi=0.346 )
#     Uid u0a208: 17.8 ( cpu=17.7 wake=0.00460 wifi=0.0901 )
#     Uid u0a65: 17.5 ( cpu=12.7 wake=4.11 wifi=0.436 gps=0.309 )
#    ...# reset电量统计
$ adb shell dumpsys batterystats --reset

Battery Historian

  • docker 部署
docker run -p <port>:9999 gcr.io/android-battery-historian/stable:3.0
  • 获取 bugreport

# 重置电量信息
adb shell dumpsys batterystats --reset
# 开始记录电量
adb shell dumpsys batterystats --enable full-wake-history
# 导出电量信息
$ adb bugreport bugreport.zip # 7.0和7.0以后
$ adb bugreport > bugreport.txt # 6.0和6.0之前:
  • 分析

打开 http://localhost:,上传 bugreport.zip,等待分析结果
image.png
实战:通过场景前后对比耗电差异 -> 大众点评App的短视频耗电量优化实战

BatteryCanary

Matrix-Battery Canary-Demo参考配置
image.png
image.png

优化

重点模块:CPU、屏幕、WIFI、数据网络、GPS、音视频通话

WakeLock

  • acquire 与 release 成对出现,一定要及时释放。
  • 使用带参数的 acquire,设置超时时间。
  • 在 try-catch 中,确保在 finally 中释放。

GPS

  • 根据业务场景,区分精度定位和粗略定位,非强需求推荐粗略定位。
  • 根据业务场景,区分网络定位与 GPS 定位,非强需求推荐网络定位。
  • 降低 GPS 请求频率,及时关闭。

蓝牙

  • 避免后台频繁扫描。
  • startScan 与 stopScan 成对出现,添加超时停止。

网络

  • 监听网络连接,网络可用时发起请求。
  • 添加网络缓存,避免重复请求。
  • 推荐在 WIFI 场景下进行大数据传输、请求。
  • 使用 JSON、Protobuf、gzip 压缩请求数据。
  • 避免后台频繁 WIFI 扫描。
  • 推荐使用厂商 push 替换长链接,或优化长链接,数据业务下通常是 5min,WIFI 网络下通常可以达到 20min 或更久。
  • 禁止轮询。

后台任务调度

合理使用后台任务框架。
Android后台调度任务与省电
后台工作概览 | Background work | Android Developers

前台交互

  • 及时释放资源,如停止动画、释放音频。
  • 推荐使用暗黑模式(即深色系)。
  • 减少页面刷新区域、过度绘制。
  • 使用 SurfaceView 替代 TextureView 播放视频。
  • 对 App、Activity、Windows、View 精确控制硬件绘制(硬件绘制功耗更高)。

参考

  • Android App 电量统计原理与优化-腾讯云开发者社区-腾讯云
  • 19 | 耗电优化(下):耗电的优化方法与线上监控-Android开发高手课-极客时间
  • 抖音功耗优化实践
  • 功耗优化 · 方案篇 · Android功耗优化指导规范 - 掘金
  • 【Android 电量优化】xxxx -阿里云开发者社区




Hi,我是“青杉”,您可以通过如下方式关注我:

  • 公众号:ByteStefan
  • 掘金:https://juejin.cn/user/3175045310722119
  • 博客:https://101wr.cn

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/529477.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++的类与对象(五):赋值运算符重载与日期类的实现

目录 比较两个日期对象 运算符重载 赋值运算符重载 连续赋值 日期类的实现 Date.h文件 Date.cpp文件 Test.cpp文件 const成员 取地址及const取地址操作符重载 比较两个日期对象 问题描述&#xff1a;内置类型可直接用运算符比较&#xff0c;自定义类型的对象是多个…

卷积神经网络必备基础

卷积神经网络&#xff08;Convolutional Neural Network, CNN&#xff09; 传统的全连接神经网络并不适用于图像处理&#xff0c;这是因为&#xff1a;每个像素点都是一个输入特征&#xff0c;随着层数的增加&#xff0c;参数以指数级增长&#xff0c;而图片的像素点往往非常…

2024年,如何使用chatgpt4.0为工作赋能?

ChatGPT 4.0的工作原理和功能 ChatGPT 4.0的工作原理和功能可以从以下几个方面进行详细说明&#xff1a; 工作原理 ChatGPT 4.0的工作原理主要基于深度学习技术&#xff0c;特别是Transformer模型的应用。它通过大量的文本数据进行训练&#xff0c;学习语言的模式和规律&…

Unity类银河恶魔城学习记录9-7 p88 Crystal instead of Clone源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili Blackhole_Skill_Controller.cs using System.Collections; using System…

基与HTML5的塔防游戏设计与实现

目 录 摘 要 I Abstract II 引 言 1 1 项目背景与相关技术 3 1.1 背景与发展简介 3 1.2 HTML5技术及其优势 4 1.3 JavaScript开发的优势与劣势 4 1.4 CSS样式表在开发中的用处 5 1.5 本章小结 6 2 系统分析 7 2.1 需求分析 7 2.2 问题分析 7 2.3 流程设计 7 2.3 功能分析 8 2.…

Vue3实现页面跳转功能

目标&#xff1a; 首页&#xff1a; 点击About后&#xff1a; 第一步&#xff1a;安装 Vue Router和创建你先 npm install vue-router4第二步&#xff1a;在router.js中设置路由 import { createRouter, createWebHistory } from vue-router; import Home from ./views/Home…

C#/.NET/.NET Core拾遗补漏合集(持续更新)

前言 在这个快速发展的技术世界中&#xff0c;时常会有一些重要的知识点、信息或细节被忽略或遗漏。《C#/.NET/.NET Core拾遗补漏》专栏我们将探讨一些可能被忽略或遗漏的重要知识点、信息或细节&#xff0c;以帮助大家更全面地了解这些技术栈的特性和发展方向。 GitHub开源地…

基于ACM32 MCU的两轮车充电桩方案介绍,有利于打造高效安全的电池管理

随着城市化进程的加快、人们生活水平的提高和节能环保理念的普及&#xff0c;越来越多的人选择了电动车作为代步工具&#xff0c;而两轮电动车的出行半径较短&#xff0c;需要频繁充电&#xff0c;因此在城市中设置两轮车充电桩就非常有必要了。城市中的充电桩不仅能解决两轮车…

伦敦银价实时行情趋势的4种技术

在伦敦银实时行情趋势的判断中&#xff0c;很多人认为找到趋势就好了&#xff0c;其实并不是这样。找到趋势只是我们踏出的first step&#xff0c;实际上找到趋势后还有更多的东西我们需要做&#xff0c;下面我们就要介绍一下找到伦敦银价实时行情趋势后的4种技术。 判断趋势的…

华为数通方向HCIP-DataCom H12-821题库(多选题:121-140)

第121题 以下哪些事件会导致IS-IS产生一个新的LSP? A、引入的IP路由发送变化 B、周期性更新 C、接口开销发生了变化 D、邻接Up或Down 【参考答案】ABCD 【答案解析】 第122题 以下哪些协议既支持网络配置管理又支持网络监控管理? A、Telemetry B、NETCONF C、SNMP D、LLDP …

vscode设置setting.json

{ // vscode默认启用了根据文件类型自动设置tabsize的选项 "editor.detectIndentation": false, // 重新设定tabsize "editor.tabSize": 2, // #每次保存的时候自动格式化 // "editor.formatOnSave": true, // #每次保存的时候将代码按eslint格式…

QX320F280049C,国产DSP,替代TI 的C2000系列

独立双核&#xff0c;32位CPU 主频150MHz flash 1MB , SRAM 1MB 单精度浮点运算FPU 三角函数运算TMU 24个增强型外设ePWM 16个高分辨率HRPWM&#xff08;150PS&#xff09; 3个12位ADC&#xff0c;采样率3MSPS