極力推薦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
);因為對整個系統來說,CPU
進WFI
是整個系統睡眠的先決條件,我們debug
也是從CPU
是否進入WFI
開始,從Linux
的角度來說,CPU
進入suspend
就是SW
完全不跑了,停在suspend workqueue
里面。
從滅屏到CPU
進入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
之前會把SPM
的firmware
寫入PCM
,然后PCM
就依據firmware
的邏輯來控制SPM
的工作
跟SPM
強相關的一個東西就是系統中的時鍾請求信號,也就是26M
時鍾開關的控制邏輯;因為系統工作在最小電流的時候,SPM
只依靠32K
時鍾工作;因此要判斷系統是不是已經到深睡狀態,就要看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
也是由SPM
來控制它的執行邏輯,跟suspend
一樣, CPU
在進去WFI
之前會把SPM
的firmware
寫入PCM
,這個firmware
跟suspend
是完全不一樣的。
五、SODI (screen on deep idle)
SODI:Screen On Deep Idle
SODI
跟deep idle
類似,是SPM的另外一種工作模式.SODI
的進入條件跟 deep idle
是類似的,區別只是要檢查的clock
跟deep idle
不完全一樣 ,SODI
對display
功耗的影響相對於CMD / VDO mode
是不一樣的
前面講過了CMD / VDO
的差別,其實就很容易理解這一點:因為CMD mode
下,CPU不用送數據出去,因此MIPI clock
可以不用送,這整條clock
路徑上的東西(PLL/clock)
都可以關閉,而且memory
跟VDO相比也可以做更多省電的action
;所以SODI
對CMD mode
的省電效果會比VDO的效果更明顯,是否進入SODI也可以從波形上明顯地看到:
下圖示SODI enable/disable
的idle mode
波形比較
CMD mode:SODI on(左) vs SODI off(右)
VDO mode:SODI on(左) vs SODI off(右)
重點關注波形的形狀,電流下降的數值不同平台不一樣
六、systrace/ftrace
systrace/ftrace
也是我們分析功耗問題常用的工具,systrace/ftrace
可以幫你定位到是誰在使用CPU,也可以用來分析idle狀態下的毛刺波形是誰觸發的,來定位root cause
。
七、wireshark
為什么要使用wireshark
wireshark
是我們用來分析netlog
的一個工具.通常用來定位開數據連接的待機功耗問題,查找是哪個APP/Process
在使用數據.wireshark
可以在公共網絡上下載到,一般公司負責協議/TCP/Wifi
這些部門也會有這個工具
怎么使用wireshark
首先需要在抓log
時,打開mtklog
中的netlog
,就可以找到netlog
對應的文件
用wireshark
打開這個.cap
文件,界面如下
有時候最前面的【時間戳】格式會不對,會跟mobile log
對不上,如果遇到了,可以通過如下菜單調整[View]->[Time Display Format]
八、layerdump
查看圖層的 adb
命令:
adb shell dumpsys SurfaceFlinger
下面是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
,一般時間越大越可能是阻止系統進入suspend
的wakeup sources
.
如果測試前后,都有捉 wakeup_sources.log
請對比兩份wakeup_sources.log
的total time
的差值.
差值時間跟滅屏的時間對得上,一般就是這個鎖引起的問題.
把捉出來的wakeup_sources.log
復制到excel
表格中,比較好對齊,一個是比較好計算.
其中dispsys_wakelock
, total_time
的時間有697614mS
也就是總共有697s.
或者在待機測試結束后通過命令:
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
具體類型的喚醒包,可以確認:
從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:
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
常用的喚醒的channel:
[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]
數據連接的喚醒.
使用winshark
打開netlog:
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]
WIFI
跟4G
有部分頻段是重疊的,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的元凶
如果是由於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,
至此,本篇已結束,如有不對的地方,歡迎您的建議與指正。同時期待您的關注,感謝您的閱讀,謝謝!