Android耗電優化

1.爲什麼要進行耗電優化

如果一個app使用的很少,但是app的耗電量卻很高,這時候用戶肯定想直接卸載這個app。那麼如何降低自己app的耗電量就是一個很重要的事情了。

2.耗電的因素有那些呢?

(1)、Alarm Manager wakeup 喚醒過多
(2)、頻繁使用局部喚醒鎖
(3)、後臺網絡使用量過高
(4)、後臺 WiFi scans 過多
在這裏插入圖片描述
以上的因素都是耗電的因素。
(5)、系統耗電規則
在這裏插入圖片描述
Android 系統目前比較關心後臺 Alarm 喚醒、後臺網絡、後臺 WiFi 掃描以及部分長時間 WakeLock 阻止系統後臺休眠。

3.如何對耗電量進行監控

電量消耗的計算與統計是一件麻煩而且矛盾的事情,記錄電量消耗本身也是一個費電量的事情。唯一可行的方案是使用第三方監測電量的設備,這樣才能夠獲取到真實的電量消耗。

(1)、通過hook的方式
Hook 方案的好處在於使用者接入非常簡單,不需要去修改自己的代碼。下面我以幾個比較常用的規則爲例,看看如果使用 Java Hook 達到監控的目的。
例如:WakeLock 是用來阻止 CPU、屏幕甚至是鍵盤的休眠。類似 Alarm、JobService 也會申請 WakeLock 來完成後臺 CPU 操作。WakeLock 的核心控制代碼都在PowerManagerService中,實現的方法非常簡單,下面我們對WakeLock進行監控

// 代理 PowerManagerService
ProxyHook().proxyHook(context.getSystemService(Context.POWER_SERVICE), "mService", this);

@Override
public void beforeInvoke(Method method, Object[] args) {
    // 申請 Wakelock
    if (method.getName().equals("acquireWakeLock")) {
        if (isAppBackground()) {
            // 應用後臺邏輯,獲取應用堆棧等等     
         } else {
            // 應用前臺邏輯,獲取應用堆棧等等
         }
    // 釋放 Wakelock
    } else if (method.getName().equals("releaseWakeLock")) {
       // 釋放的邏輯    
    }
}

通過 Hook,我們可以在申請資源的時候將堆棧信息保存起來。當我們觸發某個規則上報問題的時候,可以將收集到的堆棧信息、電池是否充電、CPU 信息、應用前後臺時間等輔助信息也一起帶上。

(2)、插樁
雖然使用 Hook 非常簡單,但是某些規則可能不太容易找到合適的 Hook 點。而且在 Android P 之後,很多的 Hook 點都不支持了。

出於兼容性考慮,我首先想到的是寫一個基礎類,然後在統一的調用接口中增加監控邏輯。以 WakeLock 爲例:

public class WakelockMetrics {
    // Wakelock 申請
    public void acquire(PowerManager.WakeLock wakelock) {
        wakeLock.acquire();
        // 在這裏增加 Wakelock 申請監控邏輯
    }
    // Wakelock 釋放
    public void release(PowerManager.WakeLock wakelock, int flags) {
        wakelock.release();
        // 在這裏增加 Wakelock 釋放監控邏輯
    }
}

(3)、Facebook 也有一個耗電監控的開源庫Battery-Metrics,它監控的數據非常全,包括 Alarm、WakeLock、Camera、CPU、Network 等,而且也有收集電量充電狀態、電量水平等信息。

4.如何進行優化

(1)、假設你的手機裏面裝了大量的社交類應用,即使手機處於待機狀態,也會經常被這些應用喚醒用來檢查同步新的數據信息。Android會不斷關閉各種硬件來延長手機的待機時間,首先屏幕會逐漸變暗直至關閉,然後CPU進入睡眠,這一切操作都是爲了節約寶貴的電量資源。但是即使在這種睡眠狀態下,大多數應用還是會嘗試進行工作,他們將不斷的喚醒手機。一個最簡單的喚醒手機的方法是使用PowerManager.WakeLock的API來保持CPU工作並防止屏幕變暗關閉。這使得手機可以被喚醒,執行工作,然後回到睡眠狀態。知道如何獲取WakeLock是簡單的,可是及時釋放WakeLock也是非常重要的,不恰當的使用WakeLock會導致嚴重錯誤。

所以我們應該及時的釋放WakeLock來解決這種情況。

(2)、網絡請求的數據返回時間不確定,導致本來只需要10s的事情一直等待了1個小時,這樣會使得電量白白浪費了。這也是爲何使用帶超時參數的wakelock.acquice()方法是很關鍵的。

但是僅僅設置超時並不足夠解決問題,例如設置多長的超時比較合適?什麼時候進行重試等等?解決上面的問題,正確的方式可能是使用非精準定時器。通常情況下,我們會設定一個時間進行某個操作,但是動態修改這個時間也許會更好。例如,如果有另外一個程序需要比你設定的時間晚5分鐘喚醒,最好能夠等到那個時候,兩個任務捆綁一起同時進行,這就是非精確定時器的核心工作原理。我們可以定製計劃的任務,可是系統如果檢測到一個更好的時間,它可以推遲你的任務,以節省電量消耗。

在這裏插入圖片描述
這正是JobScheduler API所做的事情。它會根據當前的情況與任務,組合出理想的喚醒時間,例如等到正在充電或者連接到WiFi的時候,或者集中任務一起執行。我們可以通過這個API實現很多免費的調度算法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章