美文网首页
电量统计原理以及电量优化实践

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

作者: ahking17 | 来源:发表于2016-08-05 18:39 被阅读1562次

    "
    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===

    相关文章

      网友评论

          本文标题:电量统计原理以及电量优化实践

          本文链接:https://www.haomeiwen.com/subject/ehzhsttx.html