电量统计原理以及电量优化实践

"
Free apps like Free Chess and Angry Birds spend under 25-35 percent of their energy on game play, but over 65-75 percent on user tracking, uploading user information and downloading ads.
"
android电量统计的原理可以参看这篇文章:
http://duanqz.github.io/2015-07-21-batterystats-part1

大致原理摘录如下:
电量记录
1. Android在进行电量统计时,并不是采用直接记录电流消耗量的方式,而是跟踪硬件模块在不同状态下的使用时间,收集一些可用信息,用来近似的计算出电池消耗量。

举一个例子,假定某个APK的使用了GPS,使用时间用 t 表示。GPS模块单位时间的耗电量用 w 表示,那么,这个APK使用GPS的耗电量就可以按照如下方式计算:
耗电量 = 单位时间耗电量(w) × 使用时间(t)
frameworks.jar里的frameworks/base/core/res/res/xml/power_profile.xml这个文件,记录着各个模块单位时间的耗电量, 由厂商定义。
以下是Nexus 5(hammerhead)耗电参数配置的代码片段:

<device name="Android">
    <!-- All values are in mAh except as noted -->
    <item name="none">0</item>
    ...
    <item name="wifi.on">3.5</item>
    <item name="wifi.active">73.24</item>
    <item name="wifi.scan">75.48</item>
    ...
    <item name="battery.capacity">2300</item>
</device>
2. Android框架层通过一个名为batterystats的系统服务,实现了电量统计的功能。

收集信息被组织起来,在内存中的数据结构是由BatteryStats类描述的。 为了能够从不同维度统计耗电量,这个数据结构设计得比较复杂,我们不在这里展开讨论,仅通过一个收集应用程序前台运行时间的例子,来说明信息收集过程。
记录应用程序中所有Activity从显示状态(Resumed)到消失状态(Paused)的时间,就能够统计应用程序的前台运行时间。Activity状态的切换是由AMS掌控的,因此AMS需要将Activity的状态信息通知给batterystats服务。
当Activity要切换到显示状态(Resumed)时,
会调用ActivityStackSupervisor.resumeTopActivitiesLocked()方法,
接下来会调用ActivityStack.resumeTopActivityInnerLocked()方法来完成Activity的状态切换,在完成状态切换后, 会调用
ActivityStackSupervisor.reportResumedActivityLocked()方法,从这里开始,就开始通报了:“本Activity已经进入了显示状态”。
在ActivityStackSupervisor.reportResumedActivityLocked()中得到BatteryStatsImpl对象, 并启动一个计时器(StopwatchTimer),记录下了启动时间.在Activity pause时, 再得到结束时间, 这样就得到了应用程序的acitiviy在前台的运行时间了。

除了应用程序前台运行时间,还有很多信息是batterystats服务关注的,包括WakeLock、Sendor、Wifi、Audio、Video等,这些信息的采集方式与上述过程雷同,都会经过以下步骤:

  1. 由相应的模块发起状态变更的通知
  2. BatteryStats使用定时器记录起止时间
电量信息的储存

Android支持历史电量信息的显示的,如果重新启动Android,那内存中的数据就丢失了, 所以需要把这些信息存储到磁盘上,磁盘上的 /data/system/batterystats.bin 文件中就是电量信息的序列化数据。
batterystats服务启动时,会从 batterystats.bin 这个文件中读取数据,来初始化BatteryStats这个数据结构。

电量计算

BatteryStatsHelper.refreshStats()承载了电量计算的全部过程,在需要显示电量统计信息的地方,就可以通过BatteryStatsHelper这个类,来获取统计完成的电量信息。 Setting.apk就引用了这个类。电量计算大体可以分为两块:

1. AppUsage:应用程序耗电量计算,是指每一个应用程序使用硬件模块所产生的耗电量

在BatteryStatsHelper.processAppUsage()这个方法中,实现了应用程序的电量计算(实际上统计的粒度是uid,不同的apk可以运行在同一个uid)。

2. MiscUsage:其他杂项耗电量计算

所谓杂项,其实就是用户比较关心的一大类,包括:待机的耗电量、亮屏的耗电量、通话的耗电量、Wifi的耗电量等,这个统计是系统层面的, 作为app的开发人员可以忽略掉这部分内容。

我们来总结一下应用程序的电量计算过程。Android通过一个名为BatteryStats.Uid的数据结构来维护一个应用程序的电量统计信息。 这个数据结构中,又包含很多子结构:

Proc:表示属于Uid的进程,一个Uid中可能会有多个进程,每个进程都有CPU占用时间
WakeLock:表示Uid持有的WakeLock锁的电量统计,一个Uid也可能会持有多个锁
Mobile Radio:表示Uid使用数据流量的电量统计,譬如3G流量、4G流量
Wifi:表示Uid使用wifi的电量统计
Sendor:表示Uid使用传感器的电量统计

Android提供的dumpsys命令用于查看系统服务的信息, 将batterystats作为参数,就能输出完整的电量统计信息。

adb shell dumpsys batterystats
App电量优化实践
1. 打点网络优化

现在用户操作的打点信息是实时上报, 每单击一次菜单项就有大概1k的数据上传. 可以把这打点上传的执行封装起来, 间隔一段时间统一上传, 或是在特殊时间点统一上传, 可以有效减少频繁地使用wifi和mobile radio模块。

dotting_network.png
TXD 发送数据 Transmit(tx) Data 的简写形式
RXD 接收数据 Receive(rx) Data 的简写形式
2. 尽量减少wakeLock的使用

例如现在的下载文件的逻辑, 应该使用带超时参数的acquire() API, 避免长时间使用wake lock.

DownloadThread.java
PowerManager.WakeLock wakeLock = null; 
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, Constants.TAG);
wakeLock.acquire();
3. 使用prepn profile 工具实时检测应用的耗电量
trepn_profile.png

===DONE===

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容