iOS 电量相关问题一直是测试人员头疼的事情,电量测试怎么开展、问题怎么复现和跟进定位、用户反馈电量相关的问题我们如果获取更多的信息等等,一直都没有一个好的解决方案,以至于我们面对电量相关的问题时,总是束手无策。整个项目组经常收到这样的一种反馈:你看,你们开发的 APP,我还没怎么用呢,耗电量就排第一了。对于这样的反馈,我们能做些什么呢?之前我们是迷茫的,但经过一段时间的尝试和努力之后,事情有了一些改观。
在之前很长一段时间,我们都是用这种可怜的方式进行电量测试的:
1、选定测试场景以及时长;
2、给手机充放电,让手机剩余电量在我们预设的值,比如 90%,每个场景测试开始时,保证手机都是这一电量;
3、手机系统设置,一般要关注屏幕亮度、蓝牙、定位、通知消息、音量、后台应用等等,为保证简单,通常是全部关闭或调到最小即可;
4、记录开始时的剩余电量,并执行测试,在测试结束后再记录一次剩余电量,两个电量差,就为该场景在一定时长内的耗电量;剩余电量嘛,直接读手机上展示的值或是通过接口获取(后面会介绍)均可以,几乎没有区别;
真是够简陋,但并非完全没有用,明显的电量消耗问题,还是可以发现,只要选得场景对了就可以。要是发现不了问题也不会一直用这个方法了不是。嘿嘿。
后面我们还将这种方案做了优化,流程不变,但是全自动化,人工只参与数据出来后的整理即可。具体的方法是,在手机和 mac 之前,加了一块 Arduino 开发板,通过 mac 端的指令,可以智得控制开发板通电或是断电,以达到手机充电或是放电的效果。
但不管怎么全自动化都好,终归还是最粗放的方式,没有具体的数据,没法帮助定位,如果还是个偶现的问题,那就更加束手无策,只能作罢。
慢慢得,我们开始去做一些新的尝试,能不能获取到更多更详细的电量数据,是我们的主要目标。
我们想得也比较简单,执着得认为,肯定是有一些我们没有发现的接口,可以获取到一些详细的数据,要不然系统是怎么计算每个 APP 的耗电量的呢?其实在某一段时间之内,确实如我们所想,但并非一直如此。
最初我们用到的是 UIDevice 类 batteryLevel 接口。这个接口只能获取到剩余电量百分比,目前世面上能见到的所有 iOS 系统版本都可用,如上文所提到的,他和系统界面上展示的值几乎没有区别,唯一不同的是,他是以 mAh 为单位计的,以这个值计算的剩余电量百分比,就是系统上显示的那个值。这样看来,这个接口也没有什么多大的意义。还得继续尝试。
接着我们使用到的是 IOKit 中的 IOPMPowerSource 接口,私有接口,调用方式如下:
在 iOS 10 及以上的系统上,能获取到的信息如下:
看看关键信息:
第三行 CurrentCapacity 是当前的剩余电量;
第六行 FullyCharged 是否满电量;
第八行 IsCharging 是否正在充电;
第九行 MaxCapacity 最大电池容量;
第十行 Voltage 当前电压。
信息是多了一些,有当前电压值,有剩余电量。这个有什么用呢?我们先科普一点点小知识。
首先,某一设备的电压,基本是在一定范围之内变动的,相对稳定的一个值。就像 iPhone 6P 的电压,基本是在 4V 上下。当电池剩余电量越少时,电压值会变得越小,但波动不大。电压过小时,可能会引起手机直接关机,这也是为什么有时还有 20% 电量,但手机却开不了机了。新的电池,电压波动会小一些,越是老化,电压波动可能越大。所以电压这个值能用来判断当前电池的健康度。
然后是剩余电量 2548,他的单位是 mAh。手机电池常用类似 1000mAh 这样的标识,这不是具体的电量,光看这个值,能解理到的含义是,以 1000mA 的电流来放电,能放 1 小时。或者说,以 200mA 的稳定电流放电,能放 5 小时。但明显这样意义并不大。因为我们还不知道电池在工作时,会以多少 mA 的电流工作,所以也就不知道能用多久,我们想知道的是,电池到底还有多少电,这个才是一个具体的值。上面提过,电压是相对固定的,我们可以算出具体剩余多少电,以 1000mAh,粗略计电压稳定为 4V,根据公式计算得出 W=U*I*t=4v*1000mAh=4000mWh。这个就是当前电池剩余的电量。当计算剩余电量的百分比的时候,用哪个值去算都一样了。
以上是 IOPMPowerSource 接口在 iOS10 及以上系统上获取的信息。但事实上,在 iOS 9 及以前的系统上,能获取到更多更详细的信息,大部分是一些硬件的固定信息,对我们测试没有帮助。但也有一些其他有用的信息,比如说当前的温度,电流,都是很有用的信息,如下图:
温度能用来直接判断当前的发热情况,电流能直接判断当前的电池发电功率,都可以有效判断当前电池的使用状态。
但是这个接口拿到的数据,仍然是不够具体,全是整机的电池情况,没有具体到某一个应用或是其他维度的电量统计。所以,还得继续摸索。
这一次我们应用到的是 BatteryUsageUI.bundle 中 PLBatteryUsageUIQuery,也是个私有接口。这里卖个关子,实现就不帖了,有心的同学可以根据我的关键字找到具体的东西。这个接口就厉害了,具体得说,他能拿到每一个 APP 的 CPU\GPU\显示\网络\存储等前后台所有详细信息,一个巨大的表。
当我们探索到这一步时,激动不已,以为光明就在眼前了。可是事实却是,这个接口早在 iOS9 的第一个版本,就完全被封了,只能在 iOS 8 上的机子上拿到数据。而且经过多次确认后,我们发现,这个数据是每个小时才会更新一次,并不是实时的。
但尽管如此,还是大大得增强了我们继续探索的信心,我们第一次获取到了每一个 App 的电量消耗情况,而且我们很确信,苹果 iOS 的电量排行榜,就是根据这些数据计算出来的。因为,我们在这之前,已经发现在越狱环境下有个工具,叫 DetailedBatteryUsage,这个插件只做了一件事情,就是把系统设置里,电池的显示方式设置成了 “2”,而默认的显示方式是 “0”。设置为 “2” 以后,就可以在电池设置里看到很详细的信息,如下图:
跟我们用接口拿到的数据是一致的,所以我们确认电量排行榜数据来至于这个接口,而且,系统一直在调用这个接口在统计电量相关的信息,只是对用户而言不可见,而且接口也不可见。在越狱环境下能拿到这些数据,对我们定位问题已经有很大的帮助了,但是一方面这些数据是系统显示出来的,我们处理很不方便,效率也低,另一方面,这些数据只能在越狱的机器上拿到,而目前主流的系统都还是不能越狱的。我们不得不再进一步。
经过长时间的探索,我们的目标越来越清晰,但是路却越来越窄,因为能用的接口都被官方给屏蔽了,很长一段时间内,我们都没有任何进展。直到无意中发现了官方的工具 sysdiagnose。这是苹果日志系统的统称,苹果经常会询问是否要官方帮忙诊断和定位问题时,上传的就是 sysdiagnose 的各种日志。
Sysdiagnose 很庞大,每天上几百 M 的日志,记录电池、第三方 APP、各种系统功能和应用的所有运行情况。
Sysdiagnose 怎么使用呢?简单得说,就是需要一个开发者账号,然后到苹果开发者网下载对应的证书。不需要越狱,没有系统限制,这个特别关键。关于怎么使用,有明确的说明:
当然每一类不同的日志,都对应不同的证书,以上说明是针对电池电量的。
电量日志是 sysdiagnose 系统中最庞大的一块。电量日志每天有几十到一百 M,他是一个庞大的数据库,里面有 267 张表,记录了电池电量的各维度信息。看来要弄懂电量的数据来源,必须要弄明白这些表之前的联系以及各自的意思。
经过几周的折腾,我们弄明白了几个关键的顶部的表格,下面列出来分享给大家:
通过这些表格数据,我们能明白,系统记录了哪一些数据,他们之前的关系,哪些是对我们有用的。数据非常全面,我只能说苹果威武。
有了这样全面的官方数据,我们的测试怎么做呢?
1、首先,上线前的电量测试,只要装上对应的证书,便可开始执行测试,只要记下哪个时间段对应的是哪个场景,然后测试完后,取下系统的数据库,便可以对当次的电量做较全面的评价,例如,某个 APP 在某场景下,20 分钟运行时间,显示耗电 100mWh,CPU 耗电 20mWh,运行温度是 32 度,平均电流是 110mA,是不是很酷?这样的数据,一旦异常,对于问题的定位帮助也比较大,点个赞。
2、用户反馈的问题,不再没有头绪,只需要装证书发送给他,让他装上,半小时后便可以获取到最近几天的所有电量信息,用于跟进和定位问题。酷不酷?想不想学?
不仅如此,这些关键数据,还让我们弄清了两个关键问题,一个是剩余电量是怎么计算的,另一个是电量排行榜是怎么计算的,我一一列举。
iOS 系统每 20 秒会读取一次系统电量相关数据记录入整机电量数据库,主要内容有当前电流,电压,剩余电量,最大电量,温度,是否在充电,充放电次数。
1、电流以 mA 计,直接通过硬件测得,是计算其他数据的基础,iPhone 工作时,电流一般在 1mA 到 700mA 之间。超过 500mA 电池很容易发热。
2、电压以 mV 计,通过硬件测得,是计算其他数据的基础,iPhone 工作时,电压几乎一直恒定在 4V 左右。测试过程中出现过的最高电压是 4.3V。
3、剩余电量是以 mAh 计,他和最大电量是相对值,我们看到的电量百分比是这两个值的比值。电量最大值是一个理论值,1000mAh 的意义是,以 1000mA 的恒定电流放电时,能放 1 小时。他最大值并不固定,他会随着电压而发生一些波动。
4、温度也通过硬件接口获得,可以作为一个参考值,测试过程中出现的最高温度是 37 度,能明显感觉到发热了。
5、是否在充电,如果是在充电过程中,使用的任何应用,具体电量都不作统计,不入数据库,而只统计整机的电量。
6、充放电次数,以充放一次最大电池容量记为一次,充放电次数可以作为电池老化程度的一个根据。
下面再来说说到底是怎么计算的。
假如充满电是 1000mAh,系统会每 20 秒读一次电流值,以及判断是在充电还是放电,记算这段时间的功耗,逐步累加。如半小时后还有 800mAh,剩余电量就是 80%。
1、首先要说明的是,电量排行榜显示的不是实时的数据,他有 1 小时内的延迟。同时他与系统显示的剩余电量百分比也不是同一套计算体系。
2、iPhone 用来记录电量相关数据的数据库极为庞大,有在概 265 张表,每天超 10M 的数据。
3、每一个安装到 iPhone 的应用,在系统级都会有一个 ID 标注,称作结点 ID。
4、系统电量的消耗分为主要以下大类,每一种都作为电量消耗的根结点。isp\apsocbase \display\wifi data\GPU venc\venc\CPU\restofsoc\GPS\DRAM。
5、系统中每个应用都有几种状态,分别是不运行、前台活跃、前台不活跃(一般应用间切换时出现)、后台、暂停(在后台但没有运行,程序还在内存中)。
6、系统每小时记录了每一个根结点被哪些应用占用,应用的状态是怎么样的,每应用消耗了多少能量,总共消耗了多少,比如某一小时内,某个 APPCPU\GPU\GPS\DRAM\显示各耗电 20mAh,共 100mAh,这小时内所有 APP 耗电 200mAh,那么该 APP 耗电占比 50%。
总结一下,电量测试从农业时代,到工业时代,再进大数据时代,是量变到质量的过程。我们做了长时间的探索,最终还是站在巨人的肩膀上,实现了最初预想的目标,走了很多弯路,由于研究的人很少,经常一些关键词,google 出来的信息就两三条,很容易走进死胡同里,但也正因为这样,也没有在一条错的路上一直走,总算是有点收获,很是感慨。
搜索微信公众号:腾讯移动品质中心 TMQ,获取更多测试干货!