本文结合抖音的功耗优化实践中产出了一些实验结论,优化思路,从功耗的根本知识,功耗组成,功耗剖析,功耗优化等几个方面,对 Android 运用的功耗优化做一个总结沉淀。

功耗根本知识先容

首先我们回顾一下功耗的观点,这里比较随意马虎和能耗搞混。
阐明一下为什么手机上用mA(电流值)来表征功耗水平,用 mAh(物理意义上是电荷值)来表征能耗水平。
我们先来看几个物理公式。

P = I × U, E = P × T

能耗(E):即能量损耗,指打算机系统一段韶光内总的能量花费,单位是焦耳(J)

抖音 Android 机能优化系列抖音功耗优化实践

功耗(P):即功率损耗,指单位韶光内的能量花费,反响花费能量的速率,单位是瓦特(W)

电流(I):指手机电池放电的电流值,手机常用 mA 为单位

电压(U):指手机电池放电的电压值,标准放电电压 3.7V,充电截止电压 4.35V,放电截止电压 2.75V(以范例值举例,不同设备的电池电压数值有差异)

电池容量 :常用单位 mAh,从单位意义上看是电荷数,实际表征的是电池以范例电压放电的时长。
如下面的功耗测试图所示,手机常日以恒定的范例电压事情,为了打算方便,就把电压恒定为 3.7V,那么 P = I × 3.7, E = I × 3.7 × T,即用 mA 表征功耗,mAh 表征能耗。

总结:对同一机型,我们用电池容量(mAh)变革的来表征一段韶光总能耗,用均匀电流(mA)来表征功耗水平;如 4000mAh 电池的手机刷抖音 1 小时耗电 11%,耗电量(能耗)440mAh,均匀电流 440mA

图 1. 功耗测试图

为什么要做功耗优化

从择要里我们已经理解到高功耗会引发用户的电量焦虑,也会导致糟糕的发热体验,从而降落了用户的利用意愿。
优化功耗除了可以我们带来更好的用户体验,提升用户利用时长外,降落运用耗电还具有很明显的社会代价,用一个当前比较火的词,便是可以为碳中和奇迹贡献一份力量。

如何来做功耗优化

不同于 Crash、ANR 等常见的 APM 指标,功耗是一个综合性的课题,剖析起来很随意马虎让人无从下手。
用户反馈了耗电问题,可能是 CPU 涌现高负载,又或者是后台频繁的网络访问,也可能是动画泄露导致高功耗。
或者我们自己的业务没什么变革,纯挚便是环境成分影响,导致用户以为耗电,比如低温导致的锂电池放电衰减。

我们的思路是从器件出发,运用的耗电终极都可以分解为手机器件的耗电,以是我们先对抖音做器件耗电的拆解,重视要耗电的是哪些器件,再看如何减少器件的利用,这样就做到对症下药。

下面我们先从功耗组成,功耗剖析,以及功耗优化等方面来讲述如何开展功耗优化。

功耗组成

这里列举了手机硬件的基本形态,每个模块又是由繁芜的器件构成。
如我们常说的耗电大头 SoC 里就包含 CPU 的超大核,大核,小核,GPU,DDRC(内存接口),以及外设区的各种小 IP 核等。
以是整机的功耗终极就可以拆解为各个器件的功耗,而运用的功耗便是打算其利用的器件产生的功耗。

以抖音的 Feed 流场景为例,亮度固定 120nit、7 格音量、WiFi 网络下,我们对抖音做了器件级的功耗拆解。
可以看到抖音的 feed 功耗紧张集中在 SOC(CPU,GPU,DDR),Display,Audio,WIFI 等四个模块。

器件功耗打算

那这些器件功耗是如何被拆解出来的呢?事理是:先对器件进行耗电因子拆解,建立器件功耗模型,得到一个器件耗电的打算公式。
通过运行时统计器件的利用数据,代入功耗模型,就可以打算出器件的功耗。
运用的功耗则是从器件的总功耗里按运用利用的比较进行分配,这样就得到了运用的器件耗电。
由于影响器件功耗的耗电因子浩瀚,这里繁芜的便是如何对耗电因子进行拆解以及建模。
有了精准的建模,后面便是厂商适配校准参数的过程了。

谷歌供应了一套通用的器件耗电模型和配置方案,OEM 厂商可以按通用方案对自己的产品进行参数校准和配置。
如下图里 AOSP 里的耗电配置里,以 Wifi 的耗电打算为例。
https://source.android.com/devices/tech/power/values

谷歌供应的建模方案是对 WIFI 分状态打算耗电,WIFI 不同状态下的耗电差异非常明显。
这里分为了 wifi.on(对应 wifi 打开的基准电流), wifi.active(对应 wifi 传输数据时的基准电流), wifi.scan(对应 wifi 单次扫描的基准耗电), wifi 数据传输的耗电(controller.rx,controller.tx, controller.idle)。
根据 wifi 收发数据的那打算 wifi 的耗电,通过统计这几个状态的时长或次数,乘以对应的电流,就得到 wifi 器件的耗电了。

由于谷歌是按照通用性来设计的器件耗电模型,常日只能大致打算出器件的耗电水平,详细到某个产品上可能偏差很大。
各 OEM 厂商常日有基于自身硬件的耗电统计方案,可以对耗电做更加风雅准确的打算。
这里还用 wifi 举例:如 OEM 厂商可以分别按照 2.4G,5GWIFI 单独建模,并引入天线旗子暗记的变革对应的基准电流变革,以及统计 wifi 芯片所事情的频点时长,按频点细化模型等等,OEM 厂商可以设计出更符合自己设备的精准功耗模型,打算出更精准的 wifi 耗电。
这就要根据详细产品的硬件方案来确定了。

功耗剖析

通过上面的功耗组成的先容,我们可以看到功耗影响成分是多种多样。
在做运用功耗剖析时,我们既要有方法准确评估运用的耗电水平,又要有方法来分解出耗电的组成,以找到优化点。
下面就分为功耗评估和功耗归因剖析这两部分来先容。

功耗评估

如前文功耗根本知识里所说,我们利用电流值来评估运用的功耗水平。
在线了局景,我们通过掌握测试条件(如固定测试机型版本,清理后台,固定亮度,音量,稳定的网络旗子暗记条件等)来测得可信的准确电流值来评估运用的前后台功耗。
在线上场景,由于运用退后台时,用户利用场景的繁芜性(指用户运行的前台运用不同),我们只采集前台整机电流来做线上版本监控,利用其他指标,如后台 CPU 利用率来监控后台功耗。
下面我们先容一些常用功耗评估的手段。

PowerMonitor

目前业界最通用的整机耗电评估办法是通过 PowerMonitor 外接电量计的办法,高频率高精度采集电流进行评估。
常用须要风雅化确认耗电情形,尤其是后台静置,灭屏等状态下的电流输出,厂商的准入测试等。
常用的 Mosoon 公司的 PowerMonitorAAA10F,电流量程在 1uA ~ 6A 之间,电流精度 50uA,采样周期 200us (5KHZ)。

电池电量计

PowerMonitor 虽然丈量结果最准确。
但是须要拆机比较麻烦。
我们还可以通过谷歌 BatteryManager 供应的接口直接读取电池电量计的统计结果来得到电流值。

电池电量计卖力估计电池容量。
其基本功能为监测电压,充电/放电电流和电池温度,并估计电池荷电状态(SOC)及电池的完备充电容量(FCC)。
有两种范例的电量计:电压型电量计和电流型电量计,目前手机上利用的电量计紧张是电流型电量计。

电压型电量计:大略讲便是检测当前电压,然后查询电压-电池容量对应表,得到电量估算电流型电量计:也叫库仑计,事理是在电池的充电/放电路径上的连接一个检测电阻。
ADC 量测在检测电阻上的电压,转换成电池正在充电或放电的电流值。
实时计数器(RTC)则供应把该电流值对韶光作积分,从而得知流过多少库伦。

Android 供应了 BMS 的接口,通过属性供应了电池电量计的统计结果

BATTERY_PROPERTY_CHARGE_COUNTER 剩余电池容量,单位为微安时BATTERY_PROPERTY_CURRENT_NOW 瞬时电池电流,单位为微安BATTERY_PROPERTY_CURRENT_AVERAGE 均匀电池电流,单位为微安BATTERY_PROPERTY_CAPACITY 剩余电池容量,显示为整数百分比BATTERY_PROPERTY_ENERGY_COUNTER 剩余能量,单位为纳瓦时

import android.os.BatteryManager;import android.content.Context;BatteryManager mBatteryManager = (BatteryManager)Context.getSystemService(Context.BATTERY_SERVICE);Long energy = mBatteryManager.getLongProperty(BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER);Slog.i(TAG, "Remaining energy = " + energy + "nWh");

以下面的 Nexus9 为例,该机型利用了 MAX17050 电流型电量计,解析度 156.25uA,更新周期 175.8ms。

从实践结果上看,由于不同的手机利用的电量计不同,导致直接读取出来的电流值单位也不同,须要做数据转化。
为了简化电池数据的获取,我们开拓了 Thor SDK,只保留电流、电压、电量等指标的采集过程,针对不同机型做了数据归一处理,用户可以不用关心内部实现,只须要供应须要采样的数据类型、采样周期就可以定时返回所须要的功耗干系的数据,我们用 Thor 比拟 PowerMonitor 进行了数据同等性的校验,偏差<5mA,知足线上监控需求。

此外我们做了 Thor 采集功能本身的功耗影响,可以看到 1s 采集 1 次的情形下,均匀电流上涨了 0.59mA,以是说这种方案的功耗影响非常低,适宜线上采集电流值。

厂商自带耗电排行耗电排行

厂商供应的耗电排行也可以用来查看一段韶光内的运用耗电情形。
如下面华为的耗电排行里,对硬件和软件耗电进行了分拆,并给出了运用的详细耗电量。
其他厂商 OV 也是支持详细的耗电量,小米则是供应耗电占比,并不会供应详细耗电量。

入口:设置->电池->耗电排行

功耗归因

从功耗评估我们可以判断运用的整体耗电情形,但详细到某个 case 高耗电的缘故原由是什么,就要详细问题选择不同的工具来进行剖析了。
目前可以直接归因到业务代码的紧张是 CPU 干系的工具,这也是我们目前剖析问题的紧张方向,后续我们也会培植流量归因等能力,下面我列举了常用的剖析工具。

Battery Historian

谷歌官方供应的剖析工具,须要前辈行功耗测试,再通过 adb 抓取 bugreport.zip,再通过网页工具打开,可供应粗粒度的功耗归因。

实质上是对 systemserver 里的各种做事统计信息+手机状态+内核统计信息(kernel 唤醒)的展示,运用耗电的估算依赖厂商配置的 power_profile.xml。
比较适宜对整机耗电问题做耗电归因,如归因到某运用耗电较高。

对付单个运用,由于对 wakelock,alarm,gps,job,syncservice,后台做事运行时长等统计的比较详细,比较适宜做后台耗电的归因。
对付网络非常,CPU 非常,只能看到花费较多,无法归因到详细业务。
https://developer.android.com/topic/performance/power/setup-battery-historian?hl=zh-cn

AS Profiler

比较于 BatteryHistorian 须要先手动测试,再 adb 抓取的操作繁琐,AS 自带的 Profiler 供应了 Energy 的可视化展示。
利用 debug 版本的运用,可以直不雅观的看到功耗的花费情形,方便了线下测试。
须要把稳的是这里展示的功耗值是通过 GPS+网络+CPU 打算的拟合值,并不是真实功耗值,只表征功耗水平。

Profiler 同步展示了 CPU 利用率,网络耗电,内存信息。
支持 CPU 和线程级别的跟踪。
通过主动录制 Trace,可以剖析各线程的 CPU 利用情形,以及耗时函数。
对付随意马虎复现的 CPU 高负载问题或者固定场景的耗时问题,这种办法可以很随意马虎看到根因。
但 trace 的展示办法并不适宜偶现的 CPU 高负载,信息量特殊多反而让人难以捉住重点。

网络耗电可以很方便抓取到上行下行的网络要求,可以展示网络要求的 api 细节,并且划分到线程上。
对付频繁的网络访问,很随意马虎找到问题点。
但目前只支持通过 HttpURLConnection 和 OkHttp 的网络要求,利用其他的网络库,Profiler 追踪不到。

可以看到官方出品的工具,功能比较完善,但只支持 debug 版本的 app 剖析,如果要剖析 release 版本的 app,须要利用 root 手机。
总体而言,Profiler 比较适宜于线下固定某个业务场景的剖析。
https://developer.android.com/studio/profile/energy-profiler

线程池监控

利用上面的工具监控单个线程的 CPU 非常是可以的。
但是对付线程池,Handler,AsyncTask 等异步任务不太随意马虎归因详细的业务,尤其是网络库的线程池,由于实行的网络要求逻辑是一样的,只靠抓线程堆栈是不能归因到详细业务的。
须要统计提交任务的源头代码才能抓到真正问题点。

我们可以通过多种机制,如改造线程池,java hook 等,对提交任务方进行了详细记录和聚合,可以帮忙我们剖析线程池里的耗时任务。

线上 CPU 非常精准监控

除了线下的 CPU 剖析,我们在进行线上 CPU 非常监控的培植时,我们考虑到纯挚利用 CPU 利用率阈值不能精准的判断进程是否处于 CPU 非常。
比如不同的 CPU 型号本身的性能不同,在某些低端 CPU 上的利用率便是比较高。
又比如系统有不同的温控策略,省电策略,会对手机进行限频,对任务进行 CPU 核心迁移。
在这种情形下,运用也会有更高的 CPU 利用率。

因此我们基于不同的变量成分(如 CPU 型号,进程/线程的 CPU 时长在不同核,不同频点的分布,充电,电量,内存,网络状态等),将 CPU 的利用阈值进行风雅剖断,针对不同场景、不同设备、不同业务制订风雅化的 CPU 非常阈值,从而实现了高精度的 CPU 非常抓取。

此外还有业界的一些归因框架,在这里不展开先容了。

Facebook BatteryMetrics:从 CPU/IO/Location 等多种归因点采集数据,和系统 BatteryStatsService 的统计行为类似,侧重于线下做 App 的耗电评估和器件分解。
WeChat BatteryCanary:供应了线程和线程池归因能力,相对付其他工具,增加前后台,亮灭屏,充放电,前台做事统计的统计。
功耗优化实践

上面先容了功耗的组成,以及如何剖析我们运用的耗电。
这里我们对功耗优化做一个整体性先容。
我们把优化思路从器件角度展开,列举我们有哪些优化的思路和方法,可以减少器件的利用情形,进而降落功耗。
此外对付一些用户可感知的有损业务的降级,我们通过低功耗模式来做,在低电量时通过更激进的降级手段,缓解用户的电量焦虑,带来用户的利用时长的提升。

下图列举了各器件上的优化思路,有一些优化思路会对多个器件都有收益,在这里没有特殊详细的区分,就划分在紧张影响的器件上,如减少刷新区域,对 GPU,CPU,DDR 都有收益,紧张收益在 GPU 绘制上,不才图里就列举在 GPU 上了。

同时我们列举了厂商侧的一些优化方案,运用常日无需关注,比如降落屏幕刷新率,TP 扫描频率,整机低分辨率等,这种可以通过厂商互助的办法进行更细致的调优,如分场景动态调度屏幕刷新率,在搜索列表场景利用 90HZ 高刷,在短视频场景结合帧率对齐进行刷新率降落为 30HZ,以得到更平衡的功耗和性能体验。

DISPLAY

显示功耗的优化紧张环绕对屏幕,GPU,CPU,视频解码器,TP 等器件降级利用或者减少处理,只管即便利用硬件处理等实现的。
对付屏幕而言紧张是降落亮度,刷新率,TP 扫描频率等。

屏幕亮度

屏幕亮度是屏幕功耗的最大来源,亮度和功耗险些是正比的关系,拜会下图:

可以看出无论是 IPS 屏幕还是 OLED 屏幕,随着屏幕亮度增加,功耗险些是线性增加。
针对 OLED 屏幕则是白色内容的功耗更高,深色内容则功耗相对更低。
运用通用的降落亮度的办法有进入运用后主动降落亮度,或者利用深色的 UI 模式,来达到屏幕亮度降落的效果。
厂商会通过 FOSS 或者 CABC 的方案,降落屏幕亮度。

深色模式

利用 AMOLED 屏幕本身的事理,玄色功耗最低,以是可以只管即便采取较暗的主题颜色等,终极获取较低的功耗,可以保持用户利用韶光更长。

为什么说 AMOLED 屏幕显示玄色界面会花费更少的电量呢?这要从它与传统的 LCD 屏幕之间的发光事理差异上来说。

LCD 背光显示屏,紧张是靠背光层,发光层由大量 LED 灯泡组成,显示白光,通过液晶层偏振掌握,显示出 RGB 颜色。
在这种情形下,玄色与其它颜色的像素并没有什么不同,虽然看起来并没有光亮,但是依然还是处于发光的状态。

AMOLED 屏幕根本就没有背光一说。
相反,每个小的亚像素只是发出微弱的 RGB 光,如果屏幕须要显示玄色,只须要通过调度电压使得液晶分子排列旋转从而遮蔽住背光就可以实现玄色的效果,不会额外点亮任何颜色。

下面引用测试运用为 Reddit Sync 的不同场景下彩色和玄色模式功耗比拟。
(参考链接:https://m.zol.com.cn/article/4895723.html#p4)

从上面的图表我们可以很清楚的看到,在玄色背景的情形下,AMOLED 屏幕在能耗上的确要比普通颜色背景少了很多,在 Reddit Sync 的测试中,均匀耗电量要降落 40%旁边。

运用可以设计自己的深色模式主题,同步手机系统深色模式开关的切换。
目前抖音背景设置有两种模式如下图,可以看到经典模式便是深色模式,恰好对应于深色主题,这个也可以和手机平台的深色模式也结合起来。

FOSS

FOSS (Fidelity Optimized Signal Scaling,保真优化旗子暗记缩放)是芯片厂商供应的一种对 AMOLED 屏幕调节的低功耗方案。
LCD 屏幕上对应的是 CABC (Content Adaptive Brightness Control,内容适应背光掌握)。
一方面降落屏幕亮度,一方面调节显示内容灰度值,从而使显示效果差异不大,由于降落了屏幕亮度,以是获取的功耗收益较大。
一样平常大约是 0.2 小时旁边,即均匀可延长手机利用韶光 0.2 小时旁边。

已知的情形是厂商的 FOSS 方案在某些参数情形下会导致个别场景涌现变色或闪烁问题。
如果碰着未确认闪烁问题,在内部定位无法确认缘故原由时,可以跟厂商咨询进行打消。

降落刷新率

目前市情上部分手机支持 60HZ,90HZ,120HZ,144HZ 等,高的刷新率带来了流畅度提高,用户的体验更好,但是功耗更高。
常日来讲在系统运用界面比如桌面,设置,刷新率会跟当前系统设置保持同等,而在详细运用中,刷新率会根据不同场景做调度。
比如抖音,纵然在高刷屏幕上,平台系统一样平常选择让抖音运行在 60HZ 刷新率,从而相对功耗较低。

针对不同的刷新率,PhoneArena 就做了一个比较有参考性的数据来验证这个不雅观点。
他们选取了两个品牌四款产品,都是高刷新率的机型,在同一条件下进行 60Hz 刷新率和 120Hz 刷新率的测试,结果 120HZ 刷新率下手机续航比较 60HZ 下的确缩短了至少 10%,即便是支持 90Hz 的一加 8 也是比 60HZ 刷新率要差。

图片来源:https://www.sohu.com/a/394532665_115511

降落 TP 扫描频率

常日游戏中为了提高点击相应速率会提高 TP 扫描频率,其他场景都采取默认的扫描频率。
抖音一样平常利用默认的 TP 扫描帧率。

GPU

GPU 的优化思路紧张在减少不必要的绘制或者降落绘制面积,这表示在更低的分辨率,更低的帧率,更少的绘制图层等方面。
此外视频运用利用 SurfaceView 更换 TextureView 也有显著的功耗收益。
对付繁芜的运算,我们可以选择更高能效比的器件来进行,比如利用硬件绘制代替软件绘制,利用 NPU 代替 GPU 实行繁芜算法,对整体功耗都有明显降落。

降落分辨率

运用低分辨率

常日该模式下贱戏和特定运用一样平常以较低分辨率运行。
缩小了 GPU 绘制区域和传输区域大小,降落了 GPU 和 CPU 以及传输 DDR 的功耗。
功耗收益在游戏场景下比较大,线下测试特定平台下1080p->720p约20mA旁边,1440p->720p约40mA旁边。

其事理如下,运用图层在低分辨率下绘制,通过 HWC 通道放大到屏幕分辨率并跟别的图层合成后送显。

该功能常日平台侧设置,非游戏运用无需关注,游戏运用可以自己选择设置低分辨率。

部分游戏比如腾讯系游戏(如 QQ 飞车、王者光彩和和平精英等)内部也有不同分辨率的设置,默认以低分辨率运行,从而可以实现较低功耗。

整机低分辨率

所有运用都运行在低分辨率下。
同样也缩小了 GPU 绘制区域和传输区域大小,降落了 GPU 和 CPU 以及传输 DDR 的功耗。
功耗收益跟运用低分辨率相同,普通运用在该模式下也有功耗收益。
用户从系统设置菜单中切换,运用本身常日无需关注。

其事理如下,所有图层都在低分辨率下绘制,并在低分辨率下进行合成。
合成后经由 scaler 一次性放大到屏幕分辨率,然后进行送显。
个中 scaler 是放缩硬件,由芯片平台供应。

减少刷新区域

运用布局动画位置附近,布局出来一个较小的区域,绘制区域最小,刷新区域最小, 从而功耗最低。
不同场景,收益不同。

如下图两种情形,可以看到左侧图,有 3 个动画区域(赤色框住区域),终极形成的 Dirty 区域为大的红框区域,全体面积较大。
而比拟中间图,动画两个赤色区域,经由运算后形成的 Dirty 大红框区域就较小,GPU 的绘制区域跟刷新的传输区域都较小,从而相对而言,功耗较低。
从最右侧功耗数据图中可以看出收益较大。

可以在开拓者选项中打开:设置 -> 开拓者选项 -> 显示GPU视图更新,当刷新范围与动画范围明显不一致时便是动画布局不合理。
这种情形须要详细到代码层面剖析写法的问题并修正。

降落绘制频率

常日在游戏或运用动画中利用,可以降落 GPU 绘制频率和后面的刷新频率。
通过降落动画绘制频率,可以降落 GPU,CPU 及 DDR 功耗。

不同帧率功耗情形比拟如下,可以看到低帧率下比较高帧率,功耗明显低了很多。

在抖音运用中,低绘制帧率可以通过在抖音内部主动降落动画等帧率实现。
在抖音推举界面音乐转盘动画和音符动画中降落帧率,可以显著的降落功耗。
此外也可以通过厂商侧供应 soft vsync 实现 30HZ 绘制,这部分抖音与厂商互助,SurfaceFlinger 掌握 APP vsync,降帧时 SurfaceFlinger vsync 输出降为 30fps,在特定条件下主动降落帧率,以延长利用时长。

帧率对齐

在抖音推举页面中,通过视频和降落频率后的动画达到同步,可以实现全体界面以30HZ 绘制和刷新。
否则,如果视频30hz和动画30帧恰好交错,终极形成的绘制/刷新频率还是60帧,没有达到最优。
我们通过调节各种动画的绘制流程,将动画整体绘制对齐,整体帧率明显降落。

减少过度绘制

过度绘制(Overdraw)描述的是屏幕上的某个像素在同一帧的韶光内被绘制了多次。
在多层次重叠的 UI 构造里面,如果不可见的 UI 也在做绘制的操作,会导致某些像素区域被绘制了多次,同时也会摧残浪费蹂躏大量的 CPU 以及 GPU 资源。

可以通过如下来调试过度绘制:打开手机,设置 -> 开拓者选项 -> 调试 GPU 过度绘制 -> 显示 GPU 过度绘制。
过度绘制的存在会导致界面显示时摧残浪费蹂躏不必要的资源去渲染看不见的背景,或者对某些像素区域多次绘制,就会导致界面加载或者滑动时的不流畅、掉帧,对付用户体验来说便是 App 特殊的卡顿。
为了提升用户体验,提升运用的流畅性,优化过度绘制的事情还是很有必要做的。

抖音的 feed 页的过度绘制非常的严重,抖音存在 5 层过度绘制。
下图左侧是优化前的过渡绘制情形,右侧是优化后的过度绘制情形,可以看出优化后明显改进。

利用 SurfaceView 视频播放

TextureView 和 SurfaceView 是两个最常用的播放视频控件。
TextureView 控件位于主图层上,解码器将视频帧通报到 TextureView 工具还须要 GPU 做一次绘制才能在屏幕上显示,以是其功耗更高,花费内存更大,CPU 占用率也更高。

控件位置差异如下,可以看出 SurfaceView 拥有独立的 Surface 位于单独的图层上,而 TextureView 位于主图层上。

BufferQueue 是 Android 图形架构的核心,其一侧是生产者,另一侧是消费者。
从这方面看,SurfaceView 和 TextureView 的差异如下。
随意马虎看出,SurfaceView 流程更短,内存利用更少,也没有 GPU 绘制,功耗更省。

下面是一些 SurfaceView 更换 TextureView 后的收益数据:

CPU 数据上看,SurfaceView 要比 TextureView 优化 8%-13%功耗数据上看,SurfaceView 要比 TextureView 均匀功耗低 20mA 旁边。
硬件绘制和软件绘制

硬件绘制是指通过 GPU 绘制,Android 从 3.0 开始支持硬件加速绘制,它在 UI 显示和绘制效率方面远高于软件绘制,但是 GPU 功耗相对较高。
目前是系统默认的绘制办法。

软件绘制是指通过 CPU 实现绘制,Android 上面利用 Skia 图形库来进行绘制。
两者差异拜会下图。

目前默认是开硬件加速的,可以通过设置 Activity,Application,窗口,View 等办法来指定软件绘制。
如果运用须要单独指定某些场景的软件绘制办法,须要对性能、功耗等做好评估。
参考链接:https://developer.android.com/guide/topics/graphics/hardware-accel

繁芜算法用 NPU 代替 GPU

现在的较新的 SoC 平台都带有专门进行 AI 运算的 NPU 芯片,利用 NPU 代替 GPU 运行一些繁芜算法,可以有效的节省 GPU 功耗。
如视频的超分算法,可以给用户带来很好的体验。
但是超分开启对 GPU 的耗电影响很大,在某些平台测试整机功耗可以赶过 100mA,选择用 NPU 更换 GPU 是一种优化办法。

CPU

CPU 的优化是功耗优化里最常见的,我们碰着的大部分的 CPU 非常都是涌现了去世循环。
这里利用上面先容过的功耗归因工具,都可以很随意马虎的创造去世循环问题。
此外高频的耗时函数,效果和去世循环类似,很随意马虎让 CPU 大核跑到高频点,带来 CPU 功耗增加。
其余一个范例的 CPU 问题,便是动画泄露,泄露动画大概能带来 20mA 的功耗增加。

由于 CPU 事情耗电很高,手机平台大多会增加各种低功耗的 DSP 来分担 CPU 的事情,减少耗电,如常见视频解码,利用硬解会有更好的功耗表现。

CPU 高负载优化

去世循环管理

去世循环是我们碰着的最明显的 CPU 非常,常日表现为某一个线程占满了一个大核。
线程利用率达到了 100%,手机会很随意马虎发热,卡顿。

这里举一个实际修复的去世循环例子,在一段循环打包日志的代码逻辑里,所有 log打包完了,才会break跳出循环。
当db query涌现了非常,非常处理分支并没有做break,导致涌现了去世循环。

// 方法逻辑有裁剪,仅贴出紧张逻辑private JSONArray packMiscLog() { do { ...... try { cursor = mDb.query(......); int n = cursor.getCount(); ...... if (start_id >= max_id) { break; } } catch (Exception e) { } finally { safeCloseCursor(cursor); } } while (true); return ret;}

对付去世循环管理,我们通过实际办理的问题,总结了几种常见的去世循环套路。

// 边界条件未知足,无法breakwhile (true) { ... if (shouldExit()) { break }}// 非常处理欠妥当,导致去世循环while (true) { try { do someting; break; } catch (e) { }}// 处理不当,导致Handler线程去世循环void handleMessage(Message msg) { //do something handler.sendEmptyMessage(MSG)}

高频耗时函数管理

除了去世循环问题,我们碰着的其余一种常见的便是高频的耗时函数。
通过线上监控 CPU 非常,我们也找到很多可优化的点。
如 md5 压缩算法的耗时,正则表达式的不合理利用,利用 cmd 实行系统命令的耗时等。
这种就 case by case 的修复,就有很不错的收益。

后台资源规范利用

Alarm,Wakelock,JobScheduler 的规范利用

最常见的后台 CPU 耗电便是对后台资源的不合理利用。
Alarm 的频繁唤醒,wakelock 的永劫光不开释,JobScheduler 的频繁实行,都会使 CPU 保持唤醒状态,造成后台耗电。
这种行为很随意马虎让系统判断运用为后台非常耗电,常日会被系统清理,或者发出高耗电提醒。

我们可以通过 dumpsys alarm & dumpsys power & dumpsys jobscheduler 查看干系的统计信息,也可以通过 BH 的后台统计来剖析自身的利用情形。

参考绿盟的功耗标准,灭屏 Alarm 触发小于过 12 次/h,即 5min 一次,5min 一次在数据业务下可以担保长链接存活,厂商的后台功耗优化也常日会逼迫对齐 Alarm 为 5min 触发一次。

后台的 Partial Wakelock 常日会被重点限定,非可感知的场景(音乐,导航,运动)等会被厂商逼迫开释 wakelock。
按照绿盟的标准,灭屏下每小时累计持锁小于 5min,从实际履历上看,持 Partial 锁超过 1min 就会被标为 Long 的 wakelock,如果是运用在后台无可感知业务并且频繁持锁,导致系统无法休眠的,系统会触发 forcestop 清理。

某些定时任务可以利用 JobScheduler 来替代 Alarm,Job 的好处是可以组合多种触发条件,选择一个最恰当的时候让系统调度自己的后台任务。
这里建议利用充电+网络可用状态下处理自己的后台任务,对功耗体验是最好的。
如果是非充电场景下,设置条件频繁触发 job,同样会带来耗电问题。
值得一提的是 Job 实行完要及时结束。
由于 JobScheduler 在实行时会持有一个job/开头的 wakelock,最长实行韶光 10min,如果一贯在实行状态不绝止,就会导致系统无法休眠。

视频硬解更换软解

硬解常日是用手机平台自带的硬件解码器来做解码从而实现视频播放,基于专用芯片的硬解码速率快、功耗低;软解码方面,常日利用 FFMPEG 内置的 H.264 和 H.265 的软件解码库来做解码。

下表是三星手机和苹果手机分别在软硬解情形下的功耗,可以看出硬解功耗比软解功耗显著降落,目前抖音默认利用硬解。

图片来源:http://www.noobyard.com/article/p-eedllxrr-qz.html

NETWORK

网络耗电是运用耗电的一个主要部分,一个数据包的收发,会同步拉动 CPU 和 Modem/WIFI 两大系统。
由于 LTE 的 CDRX 特性(即没有数据包吸收,坚持一定韶光的激活态,再进入就寝,依赖运营商配置,常日为 10s),以是批量进行网络访问,减少频繁的网络唤醒对网络功耗很有帮忙。
此外优化压缩算法,减少数据传输量也从根本上减少了网络耗电。

此外弱旗子暗记条件下的网络要求会提高天线的功率,也会触发频繁的搜网,带来更高的网络功耗。
根据网络质量进行网络要求调度,提前预缓存网络资源,可以减少网络耗电。

长链接心跳优化

对付运用的后台 PUSH 来说,利用厂商稳定的 push 链路替代自己的长链接可以减少功耗。
如果不能更换,也可以优化长链接保活的心跳,根据不同的网络条件动态的调度心跳。
根据履历,数据业务下常日是 5min,WIFI 网络下常日可以达到 20min 或更久。

抖音对付长链接进行了的心跳优化,进入后台的长链接心跳韶光间隔 [4min, 28min],初始心跳 4min。
采取动态心跳试探策略,每次步进 2min,确定最大心跳间隔。

Doze 模式适配

由于系统对后台运用有多种网络限定策略,最常见的是 Doze 模式,手机灭屏一段韶光后会进入 doze,限定非白名单运用访问网络,并在窗口期解除限定,窗口期为每 10min 放开 30s。
以是在后台进行网络访问前要特殊把稳进行网络可用的判断,选择窗口期进行网络访问,避免由于被限网而摧残浪费蹂躏了 CPU 资源。

这里举一个 Doze 未适配的后台耗电例子,用户反馈抖音自上次手机充满电(24h)后,没有在前台利用过,耗电占比 31%,剖析日志创造 I 在 Doze 限定网络期间,会触发轮询判断网络是否及时规复,此逻辑在后台未适配 Doze 的窗口期模式,导致了后台频繁考试测验网络要求带来的 CPU 耗电。

AUDIO降落音量

音频的耗电终极表示在 Codec 和 SmartPA(连接喇叭的功率放大器)两部分。
减少 Audio 耗电最明显的便是减少音频的音量,这直接反应到喇叭的响度上。

用 0-15 级的音量进行测试,可以看到音量对功耗的影响巨大,尤其是超过 10 之后,整体增幅非常巨大。
每一级险些与功耗成百分比上涨。

10-15 :1:30ma5-10:1:1.62ma0-5:1:1.36ma调度音频参数

由于用户对音量的感想熏染很明显,直接全局降落音量会带来不好的体验。
厂商常日会针对不同的场景,设计不同的音频参数,如电影场景,游戏场景,导航场景,动态调节音频的高低频配置参数,兼顾了效果和功耗。

从这个角度出发,可以选择和厂商互助,根据播放视频的内容,风雅化调度音频参数,如电影剪辑类型视频就利用电影场景的参数,游戏视频就切换为游戏场景的配置参数,从而达到用户无感调节音量节省功耗的目的。

CAMERA

Camera 是功耗大户,尤其是高分辨率高帧率的录制会带来快速的功耗花费和温升。
经由线下测算,开播场景,Camera 功耗 200mA+,占整机的 25%以上。

优化Camera功耗的思路紧张是从业务降级的角度上进行,如降落录制的分辨率,降落录制帧率等。
之前抖音直播和生产端都是利用30帧,但终极只利用15帧,在开播端主动下调采集帧率,按需设置帧率为15帧,功耗显著降落了120ma。

SENSOR

sensor 的范例功耗值很低,如我们常用到的 accelerometer(加速度计)的范例功耗只有 180uA。
但 sensor 的开启会导致 cpu 的唤醒与负载增加,尤其是在运用退到后台,sensor 的滥用会显著增加待机功耗。
可以在低电量时关闭不必要的 sensor,减少耗电。

GPS

精确度,频率,间隔是影响 GPS 耗电的三个紧张成分。
个中精度影响定位的事情模式,频率和间隔是影响事情时长,我们可以通过优化这三者来减少 GPS 的耗电

降落精度

Android 原生定位供应 GPS 定位和网络定位两种模式。
GPS 定位支持离线定位,依赖卫星,没有网络也能定位,精度高,但功耗大,因须要开启移动设备中的 GPS 定位模块,会花费较多电量。

Network 定位(网络定位),定位速率快,只要具备网络或者基站哀求,在任何地方都可实现瞬间定位,室内同样知足;功耗小,耗电量小;但定位精度差,随意马虎受滋扰,在基站或者 WiFi 数量少、旗子暗记弱的地方定位质量较差,或者无法定位;必须连接网络才能实现定位。

我们可以在知足定位哀求的情形下,主动利用低精度的网络定位,减少定位耗电,抖音在进入低功耗模式时,进行了 GPS 降级为网络定位,并且扩大了定位间隔。

降落频率&提高间隔

这里除了业务上主动掌握频率与间隔外,还推举利用厂商的定位做事。
为了优化定位耗电,外洋 gms 以及海内厂商都供应了位置做事 SDK,实质上是通过系统做事统一管理位置要求,根据电量,旗子暗记,要求方的延迟精度哀求,进行动态调度,达到功耗与定位需求的平衡。
供应了诸如被动位置更新,获取最近一次定位的位置信息,批量后台位置要求等低功耗定位能力。

https://developer.android.com/guide/topics/location/battery https://developer.huawei.com/consumer/cn/doc/development/HMSCore-References/location-description-0000001088559417

低功耗模式

上述的优化方法,有些在常规模式下已经履行。
但有一部分是有损用户体验的,我们选择在低电量场景下去做,降落功耗,减少用户的电量焦虑,得到用户在低电量下更多利用时长。

在低功耗模式预研中,我们列举了很多可做的方法,通过 AB 实验,我们去掉了业务负向的降级手段,比如亮度降落,音量降落等。
此外在功能触发的策略上,我们通过比拟了低电量弹窗提醒,设置里增加开关+Toast 提醒,以及低电量自动进入,终极选择了对用户体验最好的 30%电量无打扰自动进入的触发办法。

经由实验创造,一些高发热机型,通过低功耗模式全程开启,也可以拿到业务收益。
解释部分有损的降级,用户在易发热的情形下也是接管的,可以置换出业务收益,目前低功耗模式线下测试功耗收益稳定在 20mA 以上。

总结

功耗优化是一个繁芜的综合课题,既包含了利用工具对功耗做拆解评估,对非常的监控管理,也包含了主动挖掘优化点进行优化。
上面列举的优化思路,我们也只是做了部分,还有部分待开展,包括功耗归因的工具培植上,我们也还有很多可以优化的点。
我们会持续发力,产出更多的方案,在知足利用需求的条件下,花费更少的物理资源,给抖音用户带来更好的功耗体验。

加入我们

抖音 Android 根本技能团队是一个深度追求极致的团队,我们专注于性能、架构、包大小、稳定性、根本库、编译构建等方向的深耕,保障超大规模团队的研发效率和数亿用户的利用体验。
目前北京、上海、杭州、深圳都有大量人才须要,欢迎有志之士与我们共同培植亿级用户的 APP!
感兴趣的同学可以点击“阅读原文”,进入字节跳动招聘官网查询「抖音根本技能 Android」干系职位,也可以邮件联系:gaoyuan.mmm@bytedance.com 咨询干系信息或者直接发送简历内推!