Android手機功耗


極力推薦Android 開發大總結文章:歡迎收藏
程序員Android 力薦 ,Android 開發者需要的必備技能

本篇文章主要介紹手機開發中的功耗部分知識點,功耗直接影響到手機的待機時間,通過閱讀本篇文章,您將收獲以下內容:

一、手機功耗問題淺析博文
二、Sleep 、suspend
三、SPM (System Power Manager)
四、Deep idle
五、SODI (screen on deep idle)
六、systrace/ftrace
七、wireshark
八、layerdump
九、如何確定阻止進入suspend的原因
十、如何分析wakelock(wakeup source)持鎖問題
十一、如何看SPM的狀態是否正確
十二、如何查找待機喚醒源
十三、如何找到阻止進入deep idle / SODI的元凶

一、手機功耗問題淺析博文

手機功耗問題直接影響到手機的待機時長,因此,解決功耗篇問題對於智能機十分必要。
之前有寫過一個功耗淺析的文章,可以先參考下:
手機功耗問題淺析博文

二、Sleep 、suspend

這里的suspend確切的說是MCU(ARM )suspend,也就是cpu進入Wait for interrupt 狀態(WFI);因為對整個系統來說,CPUWFI是整個系統睡眠的先決條件,我們debug也是從CPU是否進入WFI開始,從Linux的角度來說,CPU進入suspend就是SW完全不跑了,停在suspend workqueue里面。

從滅屏到CPU進入suspend的大體流程框架如下:

從滅屏到進入suspend的大體流程框架

相關code路徑:

/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

/frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp

/system/core/libsuspend/

/kernel-x.x/kernel/power/

三、SPM (System Power Manager)

因為整個系統不只是AP(MCU),還包括modem、connectivity等子系統;
CPU 進入 WFI 后,整個系統就依靠一顆 SCP:SPM 來控制睡眠/喚醒的流程,它會去關注各個子系統的狀態

SPM =System Power Manager
它掌控着cpu suspend之后系統是否能掉到最小電流的關鍵邏輯,你可以把它理解成一個投票機制,當系統的關鍵資源(memory、clock)沒有任何人使用的時候,它就會讓系統進入一個真正的深睡狀態(最小電流)只要它檢測到有任何資源請求還沒釋放,系統就無法降到底電

所以在底電問題上的debug流程中,我們不僅僅要看cpu有沒有suspend成功,還要看SPM的狀態是否正確,SPM里面有一個可編程控制器PCM(Programmable Command Master)CPU在進去WFI之前會把SPMfirmware寫入PCM,然后PCM就依據firmware的邏輯來控制SPM的工作

SPM強相關的一個東西就是系統中的時鍾請求信號,也就是26M時鍾開關的控制邏輯;因為系統工作在最小電流的時候,SPM只依靠32K時鍾工作;因此要判斷系統是不是已經到深睡狀態,就要看26M有沒有關閉

26M時鍾的控制邏輯概要如下圖

26M 時鍾控制邏輯

所以從上圖我們就可以看到, 26M有沒有關,就只要看SCLKENA這個信號有沒有關閉;而SPM對這個信號的輸出以及子系統的信號輸入,都會記錄在SPM的寄存器里面,這個就是我們通過log排查的依據

代碼路徑
/kernel-x.x/drivers/misc/mediatek/base/power/spm_vx/

四、Deep idle

Deep idle 基本概念

首先顧名思義,這是一種CPU進入空閑后的狀態,也就是在idle進程中執行的

簡單地說,Mediatek會在CPU進入空閑的情況下,再去關閉一些不必要的power domain,以達到最省電的目的,因為CPU空閑的時候,其實系統中有不少的domain也是不需要運行的,不這樣做的話,就僅僅是CPU這塊的電省下來 ,達不到省電的目的。

Mediatek的做法是在CPU在進入idle進程后,會去判斷當前系統的狀態是否滿足進入更省電狀態的條件,首先就會檢查是否能進入deep idle,因為dpidle最省電

系統進入dpidle需要滿足的條件是

  • 單核(BY_CPU)
  • 預設的能block deep idle的所有clock都已經關閉(BY_CLOCK)
  • CPU在2ms內沒有從idle task調度出去的需求(BY_TMR)
  • BY_VTG / BY_OTH的case很少(BY_OTH在個別平台跟TEE(SPI指紋模塊)有關)

我們可以從波形上檢查系統是否進入deep idle

下圖中電流的底部就是deep idle的狀態,在MP3播放的狀態大約20mA
如果沒有進deep idle,這個底部會被抬高

deep idle的狀態

deep idle也是由SPM來控制它的執行邏輯,跟suspend一樣, CPU在進去WFI之前會把SPMfirmware寫入PCM,這個firmwaresuspend是完全不一樣的。

五、SODI (screen on deep idle)

SODI:Screen On Deep Idle
SODIdeep idle類似,是SPM的另外一種工作模式.SODI的進入條件跟 deep idle是類似的,區別只是要檢查的clockdeep idle不完全一樣 ,SODIdisplay功耗的影響相對於CMD / VDO mode是不一樣的

前面講過了CMD / VDO的差別,其實就很容易理解這一點:因為CMD mode下,CPU不用送數據出去,因此MIPI clock可以不用送,這整條clock路徑上的東西(PLL/clock)都可以關閉,而且memory跟VDO相比也可以做更多省電的action;所以SODICMD mode的省電效果會比VDO的效果更明顯,是否進入SODI也可以從波形上明顯地看到:

下圖示SODI enable/disableidle mode波形比較

CMD mode:SODI on(左) vs SODI off(右)

CMD mode

VDO mode:SODI on(左) vs SODI off(右)

VDO mode

重點關注波形的形狀,電流下降的數值不同平台不一樣

六、systrace/ftrace

systrace/ftrace 也是我們分析功耗問題常用的工具,systrace/ftrace可以幫你定位到是誰在使用CPU,也可以用來分析idle狀態下的毛刺波形是誰觸發的,來定位root cause

七、wireshark

為什么要使用wireshark
wireshark是我們用來分析netlog的一個工具.通常用來定位開數據連接的待機功耗問題,查找是哪個APP/Process在使用數據.wireshark可以在公共網絡上下載到,一般公司負責協議/TCP/Wifi這些部門也會有這個工具

怎么使用wireshark
首先需要在抓log時,打開mtklog中的netlog,就可以找到netlog對應的文件
 netlog

wireshark打開這個.cap文件,界面如下

用wireshark打開這個.cap文件

有時候最前面的【時間戳】格式會不對,會跟mobile log對不上,如果遇到了,可以通過如下菜單調整[View]->[Time Display Format]

時間戳格式

八、layerdump

查看圖層的 adb 命令:
adb shell dumpsys SurfaceFlinger

下面是launcher界面的圖層:

launcher的圖層

九、如何確定阻止進入suspend的原因

系統沒有進入suspend,主要的原因是 因為系統有鎖導致.

鎖一般分為:

  • APP通過PowerManager拿鎖,
  • 以及kernel wakelock.

分析上層持鎖的問題:
目前PowerManagerService的log 默認不會打開,可以通過修改:
/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

    private static final boolean DEBUG = true;
    private static final boolean DEBUG_SPEW = DEBUG && false;
修改為:
    private static final boolean DEBUG = true;
    private static final boolean DEBUG_SPEW = true;
打開上層的log

通過 syslog:搜索關鍵字:total_time= 來確定持鎖的時間.

PowerManagerService: releaseWakeLockInternal: lock=31602562 
[job/DownloadManager:com.android.providers.downloads], flags=0x0, 
total_time=600051ms

十、如何分析wakelock(wakeup source)持鎖問題

kernel的鎖默認不會打印出來,一般是待機結束后通過節點來獲取:
adb shell cat /sys/kernel/debug/wakeup_sources > wakeup_sources.log

名稱 解釋
active_count: 對應wakeup source被激活的次數.
event_count: 被信號喚醒的次數
wakeup_count: 中止suspend的次數.
expire_count: 對應wakeup source超時的次數.
active_since: 上一次還活躍的時間點.時間單位跟kernel log前綴時間是一樣(kernel單調遞增時間).
total_time: 對應wakeup source活躍的總時長.
max_time: 對應的wakeup source持續活躍最長的一次時間.
last_change: 上一次wakeup source變化的時間(從持鎖到釋放or釋放到持鎖),時間單位跟kernel log前綴時間是一樣(kernel單調遞增時間).
prevent_suspend_time: 對應wakeup source阻止進入autosleep的總累加時間.

一般情況下:
如果是復現機,前面沒有捉log,也沒有dump log,只有一份wakeup_sources.log
可以看下prevent_suspend_time,一般時間越大越可能是阻止系統進入suspendwakeup sources.

如果測試前后,都有捉 wakeup_sources.log 請對比兩份wakeup_sources.logtotal time的差值.
差值時間跟滅屏的時間對得上,一般就是這個鎖引起的問題.

比兩份的的差值

把捉出來的wakeup_sources.log復制到excel表格中,比較好對齊,一個是比較好計算.

image.png

其中dispsys_wakelock, total_time的時間有697614mS 也就是總共有697s.

image.png

或者在待機測試結束后通過命令:
adb bugreport > bugreport.txt

底層的鎖:

All kernel wake locks: 
Kernel Wake lock ttyC0 : 1h 33m 15s 668ms (3856 times) realtime 
Kernel Wake lock radio-interface: 1h 20m 56s 210ms (3995 times) realtime 
Kernel Wake lock ccci3_at : 1h 9m 43s 491ms (2932 times) realtime 
Kernel Wake lock ccci_fs : 1h 0m 52s 818ms (3432 times) realtime 
Kernel Wake lock ccci3_at2 : 41m 16s 938ms (2465 times) realtime

上層的鎖:

All partial wake locks: 
Wake lock 1001 RILJ: 5m 29s 768ms (13118 times) realtime 
Wake lock 1000 *alarm*: 4m 7s 823ms (2330 times) realtime 
Wake lock 1000 ConnectivityService: 59s 513ms (1 times) realtime 
Wake lock u0a111 *alarm*: 50s 334ms (751 times) realtime 
Wake lock u0a111 WakerLock:999603354: 28s 655ms (125 times) realtime 
Wake lock 1000 NetworkStats: 11s 434ms (569 times) realtime

十一、如何看SPM的狀態是否正確

待機被喚醒之后,確認:大部分debug_flag最后的bit位是不是 f or ff, 說明系統還有模塊咬住26M,系統並沒有最后進入真正的suspend.

譬如下面的log 最后bit 位是 0 都是有問題的:

<4>[ 250.874040] -(0)[1244:system_server][SPM] wake up byCONN2AP, timer_out = 8635, r13 = 0x20045038, debug_flag = 0x9 0

<4>[ 600.704307] -(0)[2722:system_server][SPM] wake up by R12_EINT_EVENT_B, timer_out = 81779, r13 = 0xe040000, debug_flag = 0x113f 0

十二、如何查找待機喚醒源

系統場景的喚醒源如下:

  • EINT
  • CONN
  • CLDMA

EINT:

PMIC的喚醒.

  • a.Powerkey
    喚醒后面的log會有 pwrkey_int_handler

  • b. rtc alarm
    喚醒后面的log會有 alarm time is up

 rtc alarm

具體類型的喚醒包,可以確認:
syslog里面搜索關鍵字 wakeup alarm:

01-25 01:23:04.026 830 898 D AlarmManager: wakeup alarm = Alarm{3e671462 type 2 when 27213196 com.android.phone}; package = com.android.phoneneedGrouping = true

一般alarm的喚醒,除了第三方APK之外,有時會遇到類似android/phone APK的喚醒.
確認具體android的喚醒的原因,需要確定喚醒后,緊接着發下來的intent事件.

01-24 19:50:30.031 830 898 D AlarmManager: wakeup alarm = Alarm{9ba1b41 type 2 when 7259546 android}; package = androidneedGrouping = false 01-24 19:50:30.031 830 898 V ActivityManager: Broadcast: Intent { act=android.content.syncmanager.SYNC_ALARM· flg=0x114 (has extras) } ordered=true userid=0 callerApp=null·

搜索:android.content.syncmanager.SYNC_ALARM ,可以定位到:/frameworks/base/services/core/java/com/android/server/content/SyncManager.java
進一步找對應owner確認.

phone apk的喚醒:

數據網絡的定時恢復.

  • c. others

kernel log有關鍵字:EINT.*is pending
序號:206,EINT 206 is pending,需要結合DCT跟cat /proc/interrupts

1.通過DCT:

通過DCT

2.cat /proc/interrupts :pmic-eint對應的序號是150.

289: 149 mt-eint 1 TOUCH_PANEL-eint
291: 0 mt-eint 3 11240000.msdc1 cd
294: 0 mt-eint 6 ALS-eint
295: 0 mt-eint 7 mrdump_ext_rst-eint
314: 73 mt-eint 26 irq_nfc-eint
332: 246 mt-eint 44
432: 0 mt-eint 144 iddig_eint
438: 341 mt-eint **150** pmic-eint
440: 0 mt-eint 152 spm_vcorefs_start_eint
441: 0 mt-eint 153 spm_vcorefs_end_eint
442: 0 mt-eint 154 spm_vcorefs_err_eint

<5>[30640.939329] -(0)[1191:system_server]EINT **150** is pending
......
<3>[30640.942131] (0)[69:pmic_thread]kpd: Power Key generate, pressed=1
<3>[30640.942189] (0)[69:pmic_thread]kpd: kpd: (pressed) HW keycode =116 using PMIC

CLDMA:
確認喚醒的channel ID關鍵字CLDMA_MD, wakeup source
CLDMA 喚醒源確認

常用的喚醒的channel:

[channel 10]
channel 10

常見的AT command的喚醒:參考下面【常見AT 命令解析】

命令 解釋
AT +ECOPS PLMN信息變化.
搜網的次數 AT: CREG   CGREG   (一個是CS,一個是PS)
網絡PDP狀態變化的次數 AT:CGEV  (PDN activate/deactivate)
VOLTE功能導致喚醒的次數 AT: CIREPI   CIREPH CNEMS1  CIREG EIMS
LTE數據連接 AT: EDRBSTATE

[channel 14]
一般是跟channel10一起產生,modem小區消息變化,會記錄小區的信息到nvram.

[channel20/24]
數據連接的喚醒.

channel20/24

使用winshark打開netlog:

winshark

main log里面搜索IP 地址:

112.17.251.148
01-06 21:47:58.060   313 25080 D libc-netbsd: res_queryN name =** push.hexin.cn **succeed
01-06 21:47:58.060 25056 25081 I AppStore.StorageManager: ab:e:150407-372=>in removeSpuriousFiles
01-06 21:47:58.060 21561 25079 D libc-netbsd: getaddrinfo: push.hexin.cn get result from proxy >>
01-06 21:47:58.060 21561 25079 I System.out: [propertyValue:true](http://propertyvaluetrue/)
01-06 21:47:58.061 21561 25079 I System.out: [CDS]connect[[**push.hexin.cn**/112.17.251.148:8887](http://push.hexin.cn/112.17.251.148:8887)] tm:90

[channel32]
modem SIM driver獲取sim GPIO狀態所造成的喚醒. 這部分情況比較少,確認review 貴司sim driver是否有相關的design.

[channel34]
WIFI4G 有部分頻段是重疊的,modem 需要把頻段的信息通知WIFI所造成的喚醒. 這部分屬於正常的design.

[channel55]
VOLTE 網絡的喚醒.

[channel6/42]
這是打開modem log造成的,分析功耗問題除非發現跟modem有關系,否則捉log時,不要打開modem log

具體的channel 對應的定義可以參考:

N版本:

  N版本:
 /kernel-4.4/drivers/misc/mediatek/eccci/ccci_core.h 

  M版本:
 /kernel-3.18/drivers/misc/mediatek/include/mt-plat/mt_ccci_common.h 

  L版本:
 /kernel-3.10/include/mach/mt_ccci_common.h

L版本:
/kernel-3.10/include/mach/mt_ccci_common.h

[channel 14與10]常見AT 命令解析,注意紅色字體部分字段

網絡切換狀態AT:

命令1:AT+EDRBSTATE

命令2:AT< +COPS(運營商信息)

命令4: AT< +CGREG

命令6:AT+EGTYPE(attach狀態)

命令8:AT+EI3GPPIRAT(C2K切網)

信號強度相關AT:

命令7:AT< +ECSQ(信號強度)

網絡注冊狀態AT:

命令3:AT< +CREG(NEWORK REGISTER)

命令4: AT< +CGREG

網絡VOLTE支持情況上報:

命令5:AT+CIREP (IMS網絡支持情況)

十三、如何找到阻止進入deep idle / SODI的元凶

image.png

如果是由於CLOCK 卡住,請參考下面的flow:

Debug節點:/sys/kernel/debug/cpuidle/

-rw-r--r-- 1 root root 0 1970-01-01 00:00 dpidle_state
-rw-r--r-- 1 root root 0 1970-01-01 00:00 idle_state
-rw-r--r-- 1 root root 0 1970-01-01 00:00 mcidle_state
-rw-r--r-- 1 root root 0 1970-01-01 00:00 reg_dump
-rw-r--r-- 1 root root 0 1970-01-01 00:00 slidle_state
-rw-r--r-- 1 root root 0 1970-01-01 00:00 soidle3_state
-rw-r--r-- 1 root root 0 1970-01-01 00:00 soidle_state

從節點中確認:/sys/kernel/debug/cpuidle/dpidle_state

其中dpidle_block_mask 里面的數值對應的bit位為1的,代表對應的clock卡住系統進入省電idle了.
從上圖看:

INFRA 的CG group占用的clock是從bit 0到bit31

PERI 的CG group 占用的clock是從bit32 到bit63

DISP0的CG group 占用的clock是從bit64到bit95

以此類推

N版本對應平台的clock ID:

6735/6737:
kernel-3.18/drivers/misc/mediatek/include/mt-plat/mt6735/include/mach/mt_clkmgr1_legacy.h
6735M:
kernel-3.18/drivers/misc/mediatek/include/mt-plat/mt6735/include/mach/mt_clkmgr2.h
6753:
kernel-3.18/drivers/misc/mediatek/include/mt-plat/mt6735/include/mach/mt_clkmgr3.h

cg_clk_id

enum cg_clk_id {
MT_CG_INFRA_DBGCLK = 0,
MT_CG_INFRA_GCE = 1,
MT_CG_INFRA_TRBG = 2,
MT_CG_INFRA_CPUM = 3,
MT_CG_INFRA_DEVAPC = 4,
MT_CG_INFRA_AUDIO = 5,
MT_CG_INFRA_GCPU = 6,
MT_CG_INFRA_L2C_SRAM = 7,
MT_CG_INFRA_M4U = 8,
MT_CG_INFRA_CLDMA = 12,

至此,本篇已結束,如有不對的地方,歡迎您的建議與指正。同時期待您的關注,感謝您的閱讀,謝謝!

微信關注公眾號:  程序員Android,領福利


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM