Android 上层电量管理统计

转载 2013年12月06日 11:44:00
      现在诸多关于电池管理的应用做的极其绚烂,可实现如耗电应用排行、剩余时间计算、关闭耗电程序以节省电量等功能,这两天对此模块进行了研究,总结如下。

        首先解释下各软硬件耗电量的计算。假设设备(如WIFI)单位时间内消耗的电量为w,运行时间为t,则其在这段时间内的耗电量为W=w*t。根据物理学中的知识,电功率(即所谓电量)计算公式为W=UIt,其中U为电压值,I为电流值,t为运行时间。由于在一部机器中,电压值U是恒定不变的(一般如此),因此可以忽略掉参数U,单独通过电流及时间即可表示电量(比如电池容量为2000mA、2500mA等,以mA为单位进行恒量)。根据以上描述,只要我们获得了某程序或某设备运行的时间,以及其运行时所需要电流值,则可以计算出其消耗的电量(以上理论会在代码中体现)。

        某程序或硬件设备的运行时间可以分别通过BatteryStats.Uid.Proc和BatteryStatsImpl中的相关接口获得(后文分析代码时会见到),本文主要讲下电流值(即单位时间消耗电量)的获取。

        1. PowerProfile.java

        OK,不多废话,直接给出系统中提供的接口--./frameworks/base/core/java/com/android/internal/os/PowerProfile.java。此类提供了如下接口:

        (1)public double getAveragePower(String type)

        此方法返回在type子系统下消耗的电流值,单位为mA。type可取PowerProfile中定义的常量值,包括POWER_CPU_IDLE(CPU空闲时),POWER_CPU_ACTIVE(CPU处于活动时),POWER_WIFI_ON(WIFI开启时)等各种状态。例如,如下调用getAveragePower(POWER_CPU_ACTIVE)将返回CPU处于活动时的电流值;getAveragePower(POWER_WIFI_ON)将返回维持WIFI启动状态所需的电流值。结合之前的描述,假设WIFI开启的时间为t(假设此段时间未使用WIFI传输数据,因为WIFI传输数据需要额外的电能消耗),那么在此段时间内WIFI所消耗的电量为W=t*getAveragePower(POWER_WIFI_ON)。

        type可取如下值:

  1. /** 
  2.  * No power consumption, or accounted for elsewhere. 
  3.  */  
  4. public static final String POWER_NONE = "none";  
  5. /** 
  6.  * Power consumption when CPU is in power collapse mode. 
  7.  */  
  8. public static final String POWER_CPU_IDLE = "cpu.idle";  
  9. /** 
  10.  * Power consumption when CPU is awake (when a wake lock is held).  This 
  11.  * should be 0 on devices that can go into full CPU power collapse even 
  12.  * when a wake lock is held.  Otherwise, this is the power consumption in 
  13.  * addition to POWERR_CPU_IDLE due to a wake lock being held but with no 
  14.  * CPU activity. 
  15.  */  
  16. public static final String POWER_CPU_AWAKE = "cpu.awake";  
  17. /** 
  18.  * Power consumption when CPU is in power collapse mode. 
  19.  */  
  20. public static final String POWER_CPU_ACTIVE = "cpu.active";  
  21. /** 
  22.  * Power consumption when WiFi driver is scanning for networks. 
  23.  */  
  24. public static final String POWER_WIFI_SCAN = "wifi.scan";  
  25. /** 
  26.  * Power consumption when WiFi driver is on. 
  27.  */  
  28. public static final String POWER_WIFI_ON = "wifi.on";  
  29. /** 
  30.  * Power consumption when WiFi driver is transmitting/receiving. 
  31.  */  
  32. public static final String POWER_WIFI_ACTIVE = "wifi.active";  
  33. /** 
  34.  * Power consumption when GPS is on. 
  35.  */  
  36. public static final String POWER_GPS_ON = "gps.on";  
  37. /** 
  38.  * Power consumption when Bluetooth driver is on. 
  39.  */  
  40. public static final String POWER_BLUETOOTH_ON = "bluetooth.on";  
  41. /** 
  42.  * Power consumption when Bluetooth driver is transmitting/receiving. 
  43.  */  
  44. public static final String POWER_BLUETOOTH_ACTIVE = "bluetooth.active";  
  45. /** 
  46.  * Power consumption when Bluetooth driver gets an AT command. 
  47.  */  
  48. public static final String POWER_BLUETOOTH_AT_CMD = "bluetooth.at";  
  49. /** 
  50.  * Power consumption when screen is on, not including the backlight power. 
  51.  */  
  52. public static final String POWER_SCREEN_ON = "screen.on";  
  53. /** 
  54.  * Power consumption when cell radio is on but not on a call. 
  55.  */  
  56. public static final String POWER_RADIO_ON = "radio.on";  
  57. /** 
  58.  * Power consumption when cell radio is hunting for a signal. 
  59.  */  
  60. public static final String POWER_RADIO_SCANNING = "radio.scanning";  
  61. /** 
  62.  * Power consumption when talking on the phone. 
  63.  */  
  64. public static final String POWER_RADIO_ACTIVE = "radio.active";  
  65. /** 
  66.  * Power consumption at full backlight brightness. If the backlight is at 
  67.  * 50% brightness, then this should be multiplied by 0.5 
  68.  */  
  69. public static final String POWER_SCREEN_FULL = "screen.full";  
  70. /** 
  71.  * Power consumed by the audio hardware when playing back audio content. This is in addition 
  72.  * to the CPU power, probably due to a DSP and / or amplifier. 
  73.  */  
  74. public static final String POWER_AUDIO = "dsp.audio";  
  75. /** 
  76.  * Power consumed by any media hardware when playing back video content. This is in addition 
  77.  * to the CPU power, probably due to a DSP. 
  78.  */  
  79. public static final String POWER_VIDEO = "dsp.video";  

代码段1 PowerProfile.java中定义的子系统类型

        (2) public double getAveragePower(String type, int level)

        相比于方法(1),此接口需要传入参数level,现在来解释下level的含义。我们知道,android系统中CPU可以以多种速度运行(假设分别为600MHz,800MHz,1GHZ等),速度不同时CPU消耗的电量也不同,参数level即代表不同的运行频率,显然,方法getAveragePower(String type, int level)将返回type子系统在CPU运行速度级别为level时单位时间内所消耗的电量(即电流值)。

        (3)public double getBatteryCapacity()       获取电池总电量。

        (4)public int getNumSpeedSteps()        获取CPU可以以几种速度运行。

 

        2. power_profile.xml

        事实上,通过阅读PowerProfile.java代码及相关注释即可知,此类中各接口返回的电流等数值都是通过读取power_profile.xml文件获得的,即各种子系统消耗的电量值、CPU运行速度值、总电量等信息都是以固定值的形式存储在power_profile.xml中。由于硬件之间的差异,各子系统耗电信息是不同的,因此此文件需要各生产厂商进行定制。android系统原生的power_profile.xml文件的存放路径为:frameworks/base/core/java/com/android/internal/os/PowerProfile.java,经过各硬件厂商定制后,存放路径可能发生变化,如三星某型号的power_profile.xml路径:device/samsung/maguro/overlay/frameworks/base/core/res/res/xml/power_profile.xml,其内容如下:

  1. <device name="Android">  
  2.   <!-- All values are in mA except as noted -->  
  3.   <item name="none">0</item>  
  4.   <item name="screen.on">200</item> <!-- min brite -->  
  5.   <item name="bluetooth.active">150</item>  
  6.   <item name="bluetooth.on">1</item>  
  7.   <item name="bluetooth.at">1</item> <!-- TBD -->  
  8.   <item name="screen.full">160</item> <!-- 360 max on calendar -->  
  9.   <item name="wifi.on">1</item>    <!-- wifi处于开启状态,但未传输数据 -->  
  10.   <item name="wifi.active">150</item>    <!-- wifi处于传输数据状态 -->  
  11.   <item name="wifi.scan">200</item>    <!-- wifi处于搜索热点状态 -->  
  12.   <item name="dsp.audio">150</item>  
  13.   <item name="dsp.video">200</item>  
  14.   <item name="radio.active">150</item>  
  15.   <item name="gps.on">55</item>  
  16.   <item name="battery.capacity">1750</item>  
  17.   <item name="radio.scanning">90</item> <!-- TBD -->  
  18.   <!-- Current consumed by the radio at different signal strengths, when paging  -->  
  19.    <array name="radio.on"> <!-- 1 entry per signal strength bin, TBD -->  
  20.       <value>3.0</value>  
  21.       <value>3.0</value>  
  22.   </array>  
  23.   <array name="cpu.speeds">  
  24.     <value>350000</value>    <!-- 3.5MHz -->  
  25.     <value>700000</value>    <!-- 7.0MHz -->  
  26.     <value>920000</value>    <!-- 9.2MHz -->  
  27.     <value>1200000</value>   <!-- 1.2GHz -->   
  28.   </array>  
  29.   <!-- Power consumption in suspend -->  
  30.   <item name="cpu.idle">7</item>  
  31.   <!-- Power consumption due to wake lock held -->  
  32.   <item name="cpu.awake">20</item>  
  33.   <!-- Power consumption at different speeds -->  
  34.   <array name="cpu.active">  
  35.       <value>120</value>  
  36.       <value>228</value>  
  37.       <value>299</value>  
  38.       <value>397</value>  
  39.   </array>  
  40. </device>  

代码段2 power_profile.xml内容

显然,从power_profile.xml可知,此型号机器可以以3.5MHz、7.0MHz、9.2MHz、1.2GHz四种速度运行(<array name="cpu.speeds">定义),且在此四种运行速度下CPU的耗电量分别为120mAh,228mAh,299mAh及397mAh(<array name="cpu.active">)。通过对比代码段1可知,PowerProfile.java中定义的常量即对应于power_profile.xml中各属性名。因此,PowerProfile.java只是用于读取power_profile.xml的接口而已,后者才是存储系统耗电信息的核心文件。

        通过上述分析可知,android系统对于电池电量信息统计还是提供了数据与接口的(本人菜鸟,之前一直认为耗电及剩余时间信息是由先前一定时间内的耗电量统计而来的,分析了settings中的电池相关的代码后才知是有据可依的)。根据PowerProfile.java及power_profile.xml,我们可以计算出各应用或设备的耗电量、电池剩余时间等信息,相关内容将在后续文章中描述。

PowerProfile.java与power_profile.xml

现在诸多关于电池管理的应用做的极其绚烂,可实现如耗电应用排行、剩余时间计算、关闭耗电程序以节省电量等功能,这两天对此模块进行了研究,总结如下。         首先解释下各软硬件耗电量的计算。假...
  • green1900
  • green1900
  • 2015年01月05日 19:47
  • 1135

BatteryStatsService电池电量统计服务分析

BatteryStatsService主要负责电池电量的统计信息,首先我们简单的看下电量统计服务的启动过程。 BatteryStatsService启动过程 从BatteryStatsServ...
  • zhenjie_chang
  • zhenjie_chang
  • 2016年09月12日 14:39
  • 2534

Android7.0 BatteryStatsService

BatteryStasService的主要功能是收集系统中各模块和应用进程的用电情况。 因此,我们可以认为BatteryStatsService是Android中的“电表”。 只不过这个电表比较智...
  • Gaugamela
  • Gaugamela
  • 2016年10月30日 16:57
  • 4492

一个简单的android电池显示layout

思想:progressbar控制电量显示,再加上一个imageview覆盖再上层用于表示充电状态,右边加一个imageview表示电池头部 其实直接在view上自己画会更简单一些,同时也好控制各种位...
  • a102111
  • a102111
  • 2015年09月05日 23:30
  • 1335

Android——个性化Progress电池显示视图

项目中需要用到的效果,图示如下: 既一个显示电量槽的ProgressBar。 一开始没想到可以通过ProgressBar直接实现,想的是通过一个电池图的遮盖,然后再用canvas画内部的红...
  • qq_22770457
  • qq_22770457
  • 2017年02月11日 19:24
  • 1207

Android性能优化之电量优化

1、在android framework里面有专门负责电量统计的Service:BatteryStatsSerive ①这个Service在ActivityManagerService中创建,代...
  • zhaodecang
  • zhaodecang
  • 2016年11月26日 00:40
  • 16204

Android6.0电池图标外显示电量百分比

众所周知Android6.0进入界面后电池电量百分比被隐藏进了调谐者模式里面,即使打开调谐者模式显示电量数字也在电池图标里,对于某些习惯于5.1电量显示的人来说这是一个很难受的事情,那么这里我来提供一...
  • yumu921021
  • yumu921021
  • 2017年03月03日 18:46
  • 1352

巧用 Drawable 之实现一个最简单的自定义电池图标

在 Android 中自定义一个电池图标,一般是采用自定义 View,在 onDraw 中采用 Canvas 去绘制 Bitmap 或者各种几何图形。但是自定义 View 对初学者来说可能会有一点难度...
  • leandom
  • leandom
  • 2016年09月23日 00:43
  • 1158

Android自定义电池控件

一个Android开发中可能会使用到电池控件view,有水平和垂直两个方向,同时根据电池电量更改电池中的电量颜色。...
  • donkor_
  • donkor_
  • 2016年11月15日 19:47
  • 2186

Android根据电量变化为不同图片的方法【电池电量提示】

1 主类 package com.jli.battery; import android.app.Activity; import android.app.Service; import andro...
  • jintianhen1
  • jintianhen1
  • 2013年08月16日 13:52
  • 1179
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android 上层电量管理统计
举报原因:
原因补充:

(最多只允许输入30个字)