1. 程式人生 > >深入淺出Android App耗電量統計

深入淺出Android App耗電量統計

在Android統計App耗電量比較麻煩,直至Android 4.4,它仍沒公開“電量統計”API或文件……額,是的,僅沒有公開,並不是沒有。平時在手機“設定- 電量”看到的資料

Image

 就是系統呼叫內部API的統計結果。

基礎概念

手機由眾多“部件”組成,所謂“部件”是指:CPU,WIFI,GPS....所以,Android App消耗總電量為 App執行過程中,涉及各部件的消耗電量的總和。 假設執行App導致CPU執行,時間:t,CPU單位時間消耗電量:w,則App的CPU耗電量為:W = w*t,而有物理公式 W = U*I*t(U:電壓值,I:電流值),在手機中,一般U恆定不變,所以,可以單獨通過 Q(電容量,單位: mAh)= I * t 表示電量
系統原始碼分析

    核心類

  • BatteryStatsImpl:提供App各部件執行時間
  • PowerProfile:提供部件電流數值

    問題

  • Android怎樣儲存與讀取App耗電量資訊(即:BatteryStatsImpl資料怎麼來的?)
  • Android怎麼儲存部件電流數值(即:PowerProfile資料怎麼來的?)
  • Android具體耗電量計算方法
    1. Android怎樣儲存與讀取App耗電量資訊

        (1)先看下PowerUsageSummary.java如何獲取BatteryStatsImpl?

Image(1)

Image(2)

Image(3)

        可見 BatteryStatsImpl 通過 系統服務“batteryinfo”獲得。

Image(4)

        系統服務“batteryinfo”其實就是BatteryStatsService,而BatteryStatsService“唯一的”建構函式提供了一個很重要的資訊:filename!

        (3)BatteryStatsService在哪裡建立?filename是什麼?(見:ActivityManagerService.java

Image(5)

        filename檔案是:/data/system/batterystats.bin,關於batterystats.bin,之前民間很多文章說它用作電池校正,但Android工程師Dianne Hackborn在google+上明確:

Image(6)

        betterystats.bin檔案僅僅是一個記錄不同app使用電量的一個檔案。

        (4)再看看 BatteryStatsImpl(String filename) 建構函式(見:BatteryStatsImpl.java

Image(7)

        這裡只做了些基本的初始化。真正載入betterystats.bin資料是在(ActivityManagerService.java)mBatteryStatsService.getActiveStatistics().readLocked();

Image(8)

Image(9)

        至此,Android怎樣儲存與讀取App耗電量資訊分析結束。

        總結:

  • ActivityManagerService 建立並初始化 BatteryStatsService,並傳入耗電量記錄檔案batterystats.bin
  • BatteryStatsService 在內部建立 BatteryStatsImpl 例項,並傳入耗電記錄檔案batterystats.bin
  • ActivityManagerService 執行 mBatteryStatsService.getActiveStatistics().readLocked();導致 BatteryStatsService 的 BatteryStatsImpl 載入batterystats.bin資料
  • 在PowerUsageSummary計算App耗電量時,PowerUsageSummary從BatteryStatsService 中獲取BatteryStatsImpl 例項,從而獲得App的相關資料

    2. Android怎麼儲存部件電流數值

Image(10)

        PowerProfile讀取資源 com.android.internal.R.xml.power_profile,並把資料載入到sPowerMap。

        (2)com.android.internal.R.xml.power_profile在哪裡?

        在官方文件《Power Profiles for Android》明確了power_profile.xml位置:device///frameworks/base/core/res/res/xml/power_profile.xml。

Image(11)

        (3)每個OEM廠商有自己獨立的power_profile.xml配置

        官方文件表明:OEM廠商應該有自己的power_profile.xml,因為部件(如:cpu, wifi…)耗電量應與具體硬體相關,這個只有OEM廠商清楚……

Image(12)

        (4)PowerProfile關鍵API:

  • public double getAveragePower(String type):返回type的電流值(mA),type表示power_profile.xml中的某關鍵字(如:gps.on)
  • public double getAveragePower(String type, int level) :返回type的電流值(mA),level表示xml中array的第幾個value

        至此,Android怎麼儲存部件電流數值分析結束。

        總結:

        (1)Android部件電流資訊存於:power_profile.xml

        (2)每個OEM廠商有私有power_profile.xml

        (2)PowerProfile讀取power_profile.xml,並提供API訪問部件電流數值。

    3. Android具體耗電量計算方法

        App耗電量統計:processAppUsage()  

        硬體耗電量統計:processMiscUsage()

        processAppUsage()分析

            【1】processAppUsage耗電量統計的 時間段 是?

Image(13)

Image(14)

            關於統計的 時間段,BatteryStats有4個選項:

Image(15)

            可見,processAppUsage 是 上一次拔掉裝置後 ~ 至今 的App耗電量統計。

            【2】processAppUsage 的統計物件真的是App?

Image(16)

            具體的 統計流程 都在for迴圈裡,額……所以processAppUsage真實統計粒度是Uid。

            Uid與App關係:2個App簽名和sharedUserId相同,則在執行時,他們擁有相同Uid。就是說processAppUsage統計的可能是多個App的耗電量資料,對於普通App,出現這種情況的機率較少,而對於Android系統應用則較為常見。

            【3】耗電量計算公式 - 部分1:計算Uid屬下每個Process的耗電量資料,並求和。

            Uid_Power1 = (Process1_Power + … + ProcessN_Power);

            Process_Power = (CPUSpeed_Time * POWER_CPU_ACTIVE);

Image(17)

            【4】耗電量計算公式 - 部分2:計算Uid的wake lock耗電量

            這裡,Android只計算了partial wake lock的耗電量。

            Uid_Power2 = PartialWakeLock_Time * POWER_CPU_WAKE

Image(18)

            【5】耗電量計算公式 - 部分3:計算Uid的資料流量(data traffic)耗電量

            Uid_Power3 = ( tcpBytesReceived + tcpBytesSent ) * averageCostPerByte

Image(19)

Image(20)

            【6】耗電量計算公式 - 部分4:計算Uid WIFI耗電量。

            Uid_Power4 = wifiRunningTimeMs * POWER_WIFI_ON

Image(21)

            【7】耗電量計算公式 - 部分5:計算Uid其他感測器耗電量。

            Uid_Power5 = (Sensor1_Power + … + SensorN_Power)

            Sensor_Power = Sensor_Time * Power_Sensor

            至此,App耗電量計算方法分析結束。硬體耗電量統計(processMiscUsage())亦類似。

            總結App耗電量計算公式:

                Uid_Power(App耗電量,單位:mAh) = Uid_Power1 + Uid_Power2 + Uid_Power3 + Uid_Power4 + Uid_Power5

                    Uid_Power1 = (Process1_Power + … + ProcessN_Power);

                        - Process_Power = (CPUSpeed_Time * POWER_CPU_ACTIVE);

                    Uid_Power2 = PartialWakeLock_Time * POWER_CPU_WAKE              

                    Uid_Power3 = ( tcpBytesReceived + tcpBytesSent ) * averageCostPerByte

                    Uid_Power4 = wifiRunningTimeMs * POWER_WIFI_ON

                    Uid_Power5 = (Sensor1_Power + … + SensorN_Power)

                        - Sensor_Power = Sensor_Time * Power_Sensor

            說這麼多,來一發……不,來一個統計耗電量的App吧,其實,之前已有人把這段Android系統程式碼摳出來,做了一個App,可以到 這裡下載             有一個好訊息是:android5.0後,獲取電量資料不用這麼痛苦了,dumpsys batterystats資料中。包含:Estimated power use (mAh):,下面就是每個uid的耗電量,只要把app下所有uid耗電量加起來即可!