效能優化系列
電量優化 - battery-historian
簡介
現在基本上都是人手一部智慧手機,你可以發現不管走在街上,公交地鐵上,等等任何娛樂辦公地方,隨處可見有人正在低著頭玩手機,有的還隨身攜帶充電寶。由此可見,現在智慧手機的電量有多麼的不經用,當然我們是優化不了電池的,不過我們可以從 APP 中著手優化,我相信一線大廠也有自己電量分析工具,我相信只要是能夠分析電量的工具,都是好工具 (^▽^)。那麼該我們的主角上場了 Google 開源電量分析工具 battery-historian 下面就讓我們一起來了解下 BatteryHistonian 吧!
Battery-Historian
Battery Historian 背景
Battery Historian 是在執行 Android 5.0 Lollipop(API級別21)及更高版本的 Android 裝置上檢查電池相關資訊和事件的工具,而裝置未插入。它允許應用程式開發人員在時間線上視覺化系統和應用程式級事件通過平移和縮放功能,可以輕鬆檢視自裝置上次完全充電以來的各種彙總統計資訊,並選擇一個應用程式並檢查影響所選應用程式特定電池的指標。 它還允許對兩個錯誤報告進行A / B比較,突出顯示關鍵電池相關指標的差異
Battery Historian 安裝
Battery Historian 安裝是一個複雜的工程,需要配置一大堆的環境。不過官方給我們們提供了 2 中安裝方式,下面讓我們一起來了解下吧。
快速安裝 - 百度雲
battery historian 原始碼及 JS 環境 :pan.baidu.com/s/1D3Guq0WW… 提取碼:g1cx
使用方式:
- 解壓在 GO 的 $GOPATH/目錄 執行 5.2 -> 5.4 步驟
- IE 瀏覽器 或者 Google 瀏覽器輸入 http://localhost:9999/
原始碼安裝 (推薦)
原始碼安裝雖然配置的環境很多,但是用起來還是比較穩定,下面就跟我的步伐來一起安裝吧。
-
安裝配置 GO 語言
-
安裝 注意更改路徑
-
配置環境
系統變數中新建 GOROOT GOPATH 變數,然後配置 Path 環境變數
-
檢查是否安裝成功
在 cmd 命令列中輸入 go version 檢視是否成功安裝及當前版本
-
python 安裝
由於 historian.py 指令碼是 python2 寫的,所以需要安裝 python2.7 環境。
下載安裝: www.python.org/
雲盤提供安裝: pan.baidu.com/s/103GXARgc… 提取碼:sm8p
-
官網下載 2.7 版本
-
安裝 py
-
配置環境
-
檢驗 root 許可權輸入 python -V
顯示版本號,就說明安裝成功了
-
-
配置 JAVA 環境
這個就自己百度配置了哈。
-
配置 Git 環境
這個也自己百度吧,很簡單。
-
下載 Battery Historian 原始碼
-
在 Git Bash 中輸入命令 go get -d -u github.com/google/battery-historian/...(即下載到GOPATH配置目錄下)
-
進入到$GOPATH/src/github.com/google/battery-historian目錄下
-
執行 Battery Historian:輸入命令列 go run setup.go
-
執行 Battery Historian.go
在 battery-historian 目錄下執行 go run cmd/battery-historian/battery-historian.go
-
瀏覽器輸入
-
MAC 原始碼安裝(推薦)
安裝步驟跟 win 一樣,下面直接介紹 mac 下的 battery historian 需要的環境配置
-
Go 環境配置
-
vim .brash_profile 配置 go 環境
-
儲存編輯的環境
sorce .brash_profile 複製程式碼
-
Docker 安裝
docker 我這裡就粗略的說下,因為在 win10 下安裝 坑太多了。還有點不穩定,導致最後使用 原始碼安裝。
準備工作
官網下載 Docker : docs.docker.com/engine/inst…
win 10 家庭版本缺少 Hyper-V 元件需升級企業版密碼鑰匙也可以百度: NPPR9-FWDCX-D2C8J-H872K-2YT43
-
安裝 Docker for Windows Installer 安裝步驟直接下一步,安裝過程中會出現自動重啟電腦。
-
命令輸入執行 docker
docker run --name=battery -d -p 9999:9999 bhaavan/battery-historian 複製程式碼
-
驗證: 在瀏覽器上輸入 http://localhost:9999
注意:
-
如果 win10 企業版安裝失敗,可以看看官網提示
-
如果升級了企業版 那麼 VMware 虛擬機器用不了,下面給出解決辦法。
-
關閉 Hyper-V 元件
bcdedit /set hypervisorlaunchtype off 複製程式碼
-
開啟
bcdedit /set hypervisorlaunchtype auto 複製程式碼
-
Battery Historian 使用及資料分析
adb 對手機的操作
-
重置內部資料,相當於清空
adb shell dumpsys batterystats --reset 複製程式碼
-
獲取完整的 wakelock 資訊
adb shell dumpsys batterystats --enable full-wake-history 複製程式碼
-
拔掉 USB 等待一段時間建議長一點,現在隨意使用 APP
-
獲得電量報告
// > 6.0 adb bugreport bugreport.zip // <= 6.0 adb bugreport > bugreport.txt //匯出 adb pull /data/user_de/0/com.android.shell/files/bugreports/[電量報告].zip [匯出目錄] 複製程式碼
-
提交電量報告,並檢視
資料引數詳細說明
-
WakeLock 級別
-
PARTIAL_WAKE_LOCK: 保證 CPU 保持高效能執行,而螢幕和鍵盤背光(也可能是觸控按鍵的背光)關閉。一般情況下都會使用這個 WakeLock 。
-
ACQUIRE_CAUSES_WAKEUP: 這個WakeLock除了會使 CPU 高效能執行外還會導致螢幕亮起,即使螢幕原先處於關閉的狀態下。
-
ON_AFTER_RELEASE: 如果釋放 WakeLock 的時候螢幕處於亮著的狀態,則在釋放WakeLock 之後讓螢幕再保持亮一小會。如果釋放 WakeLock 的時候螢幕本身就沒亮,則不會有動作。
-
API17 被棄用的 WakeLock:保持螢幕長亮
-
SCREEN_DIM_WAKE_LOCK:保證螢幕亮起,但是亮度可能比較低。同時鍵盤背光也可以不亮。 SCREEN_BRIGHT_WAKE_LOCK :保證螢幕全亮,同時鍵盤背光也亮。 FULL_WAKE_LOCK:表現和SCREEN_BRIGHT_WAKE_LOCK 類似,但是區別在於這個等級的WakeLock使用的是最高亮度 複製程式碼
-
-
推薦使用
-
//在Activity中: getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); //或者在佈局中新增這個屬性: android:keepScreenOn="true" 複製程式碼
-
剩下引數由表格說明
引數 說明 CPU runing cpu 執行的狀態, 是否被喚醒 Kernel only uptime 只有核心執行時間 Activity Manager Proc 活躍的使用者程式 Mobile network type 網路型別 Mobile radio active 移動蜂窩訊號 比 wifi 耗電 Crashes(logcat) Crashes(logcat) 某個時間點出現 crash 的應用 Doze 是否進入doze 模式 JobScheduler 非同步作業排程,延遲操作,父類 Service SyncManager 同步操作 Temp White List 電量優化白名單 Phone call 是否打電話 GPS 是否使用 GPS Network connectivity 網路連線狀態 (wifi、mobile是否連線) Mobile signal strength 移動訊號強度 (great\good\moderate\poor) Wifi scan 是否在掃描 wifi 訊號 Wifi supplicant 是否有 wifi 請求 Wifi radio 是否正在通過 wifi 傳輸資料 Wifi running wifi 元件是否在工作(未傳輸資料) Wifi on wifi 元件是否在工作(未傳輸資料) Audio 音訊是否開啟 Camera 相機是否在工作 Video 是否在播放視訊 Foreground process 前臺程式 Package install 是否在進行包安裝 Package active 包管理在工作 Battery level 電池當前電量 Temperature 電池溫度 Logcat misc 是否在匯出日誌 Plugged 是否是充電狀態 -
當前 APP Stats
分析當前 APP 電量詳細資訊
- 從上圖可以看出 早上 11:00 - 下午 12: 00 這一個小時內電量下降的最快,耗電量最多的罪魁禍首就是 GPS 和 wakelock
- 在 APP Stats -> Device estimated power 中可以檢視在這一小時耗電時常,(由上圖 Battery Level 得知電量變化過程是 69 - 61 ,1h 下降 8 )APP 1h 耗電為 5.38 % 還是挺耗電的。
當前 APP 優化建議:
GPS :GPS 可以間斷獲取,或者使用第三方(高德、百度)它們提供省電模式定位,有 wifi 地方切換 wifi 定位,少用 高精準定位模式。
網路連線: 有 wifi 地方建議切換 wifi
wakelock : 儘量不要使用。
總結-優化方案
1. 加入電量優化白名單
/**
* 加入電量白名單
*
* @param activity
* @param type 1: 啟動 設定頁面 2:觸發系統對話方塊
*/
public static void addWhite(Activity activity, int type) {
if (activity == null)return;
WeakReference<Activity> activityWeakReference = new WeakReference<Activity>(activity);
PowerManager packageManager = (PowerManager) activityWeakReference.get().getApplication()
.getSystemService(Context.POWER_SERVICE);
//應用是否在 白名單中
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!packageManager.isIgnoringBatteryOptimizations(activityWeakReference.get().getApplication().getPackageName())) {
if (type == 1) {
//方法1、啟動一個 ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS Intent
Intent intent = new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
activityWeakReference.get().getApplication().startActivity(intent);
} else {
//方法2、觸發系統對話方塊
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + activityWeakReference.get().getApplication().getPackageName()));
activityWeakReference.get().getApplication().startActivity(intent);
}
}
}
}
複製程式碼
2. GPS 優化建議
定位是 App 中常用的功能,但是定位不能千篇一律,不同的場景以及不同型別的 App 對定位更加需要個性化的區分。
-
選擇合適的 Location Provider Android系統支援多個 Location Provider:
GPS_PROVIDER: GPS 定位,利用 GPS 晶片通過衛星獲得自己的位置資訊。定位精準度高,一般在 10 米左右,耗電量大;但是在室內,GPS 定位基本沒用。
NETWORK_PROVIDER: 網路定位,利用手機基站和 WIFI 節點的地址來大致定位位置,這種定位方式取決於伺服器,即取決於將基站或 WIFI 節點資訊翻譯成位置資訊的伺服器的能力。
PASSIVE_PROVIDER: 被動定位,就是用現成的,當其他應用使用定位更新了定位資訊,系統會儲存下來,該應用接收到訊息後直接讀取就可以了。比如如果系統中已經安裝了百度地圖,高德地圖(室內可以實現精確定位),你只要使用它們定位過後,再使用這種方法在你的程式肯定是可以拿到比較精確的定位資訊。
使用 Criteria,設定合適的模式、功耗、海拔、速度等需求,系統會返回合適的 Location Provider。 例如你的 App 只是需要一個粗略的定位那麼就不需要使用 GPS 進行定位,既耗費電量,定位的耗時也久。
-
及時登出定位監聽 在獲取到定位之後或者程式處於後臺時,登出定位監聽,此時監聽GPS感測器相當於執行no-op(無操作指令),使用者不會有感知但是卻耗電。
//如果對定位要求不那麼嚴格的話 可以在關閉螢幕的時候可以暫停 public void onPause() { super.onPause(); if(locationManager != null) locationManager.removeListener() } 複製程式碼
-
多模組使用定位儘量複用 多個模組使用定位,儘量複用上一次的結果,而不是都重新走定位的過程,節省電量損耗;例如:在應用啟動的時候獲取一次定位,儲存結果,之後再用到定位的地方都直接去取。
3.網路切換建議 上傳下載儘量用 WIFI
//優化方案 二 :網路資料切換
if (!BatteryUtils.isPlugged(getApplicationContext())){
//如果沒有充電,提醒使用者是否有可用 wifi
}
複製程式碼
4. WakeLock 亮屏,喚醒 CPU 建議
-
亮屏替換者
//在Activity中: getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); //或在佈局中新增這個屬性: android:keepScreenOn="true" 複製程式碼
-
alarm 鬧鐘讓 CPU 間斷式工作
/** * 開啟一個鬧鐘 * @param context * @param action * @param requestId * @param interval */ public static void startTimer(Context context,String action,int requestId,int interval) { Intent intent = new Intent(action); PendingIntent sender = PendingIntent.getBroadcast(context, requestId, intent, PendingIntent.FLAG_CANCEL_CURRENT); AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Calendar calendar = Calendar.getInstance(); int second = calendar.get(Calendar.SECOND); //延遲一分鐘執行 int delay = 60 - second + 1; calendar.add(Calendar.SECOND, delay); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { String format = new SimpleDateFormat("HH:mm:ss", Locale.CHINA).format(calendar.getTimeInMillis()); Log.d("下次鬧鐘執行的時間--》","delay: " + delay +", startMillis: " +format); alarmManager.setWindow(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 100, sender); } else { alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), interval, sender); } } 複製程式碼
5. JobScheduler (Service 替代者。 8.0 以後 Google 推薦使用)
-
把工作任務放到合適的時間再去執行,比如充電時間,wifi 連線後
-
也可以把多個任務合併到一起,再選擇時間去執行
//需求 現在我需要在充電的狀態下並且連線上 wifi 在上傳 gps 資料 //jobScheduler 會自動把資料新增到一個佇列中 //存入資料 @Override public int enqueue(JobInfo job, JobWorkItem work) { try { return mBinder.enqueue(job, work); } catch (RemoteException e) { return JobScheduler.RESULT_FAILURE; } } //在適當的時候取出所有資料 @Override public List<JobInfo> getAllPendingJobs() { try { return mBinder.getAllPendingJobs(); } catch (RemoteException e) { return null; } } 複製程式碼
也許有的對這個 jobSchedler 合併任務執行還不是那麼清晰,現在看下一個(5 .3 )的錄屏
-
在充電並且連線 wifi 的狀態下傳送資料(這裡旋轉螢幕是為了傳送資料用的)。
-
先說一下演示流程 連線 wifi + 充電 正常傳送資料
-
關閉 wifi 傳送資料,在開啟 wifi 合併傳送資料
-
到這裡 我們們電量優化講的差不多了 最後實際優化了 2% 下去。也還是不錯的了。