Friday, February 21, 2014

Debug Android and Linux suspend and resume (中文)

資料來源: http://blog.csdn.net/laojing123/article/details/7874221

攢了一些關於調試Android和Linux下面的suspend 和 resume的經驗, 在這裡和大家分享一下。
希望可以有些幫助, (下面沒有寫Android專用的, 就是Linux通用的)。
1. no_console_suspend 
在kernel啟動參數里面加上no_console_suspend, 這個是最基本的, 因為kernel在把console suspend掉以後, 不管裡面出了什麼事情, 從串口上都看不到。 大部分在suspend/resume時候的死機都可以通過串口看到kernel Panic的信息, 這樣才會知道是哪裡出了問題。因為有的時候resume出錯, 或者suspend到很後面出錯的console不加這個參數都看不到。
2. initcall_debug
這個也許知道的人不多, 其實有的時候你不知道哪個driver在suspend/resume的時候出錯的時候,很迷茫, 就想在哪裡加上一些調試信息來看看是哪裡的driver, 其實有些時候加的不合適的話, 會看不到很多有用的信息。其實kernel本身已經有這樣的功能了(只不過不是很人性化)。
 
echo 1 > /sys/module/kernel/parameters/initcall_debug echo 9 > /proc/sys/kernel/printk 
第一條命令是打開initcall_debug, 這個是所有的kernel都會有的, 也可以在啟動參數里面加initcall_debug來默認打開這個參數, 這樣可以調試系統啟動。
因為這些信息都是KERN_DEBUG級別的, 所以需要提高printk的級別才可以看到, 要不然suspend/resume的時候死掉了,你就沒有機會看到這些信息了。
3. suspend_test
這個方法可以用rtc這種軟件的方式來做循環的suspend/resume, 儘管對於Android這樣並不是很足夠, (你得模擬一個POWER_KEY上去才夠), 但是對於調試Driver的穩定性, 還是有一定用處的。 不要以為suspend了幾次可以, 那麼就可以通過幾千次的測試。 這個suspend是5秒鐘用RTC喚醒, 然後對於Android, 5秒鐘又會自動睡下去, 但是對於通用Linux, 你得寫個小腳本來讓他一會再睡下去, 或許這個工具比較有用rtcwakeup(google rtcwakeup)。
使用方法:
編譯一個有這個功能的kernel, make menuconfig 以後選上
CONFIG_PM_DEBBUG=y
CONFIG_PM_TEST_SUSPEND=y
這兩個選項
燒寫新的kernel,然後打開你需要測試的東東, 比如WIFI,3G
echo "core" > /sys/power/pm_test
echo "mem" > /sys/power/state
這樣, 它就會循環休眠和喚醒了。
4. wakelock
輪到Android的調試了, Android裡面和Power相關最大的就是wakelock,  有時候會碰到睡不下去,或者睡到最後彈起來的問題, 就是wakelock引起的,或者說是wakelock的使用者引起的。
怎麼調試呢,用一下兩個:
echo 15 > /sys/module/wakelock/parameters/debug_mask
echo 15 > /sys/module/userwakelock/parameters/debug_mask
15是代表16進制的F, 在wakelock裡面就是把所有的debug信息打開, 起碼現在是。如果以後不夠了,估計得輸入255.
這樣你能看到kernel和frameworks層對於wakelock的操作, 申請和釋放。 這樣看申請和釋放成對否就可以了。注意: wakelock有一種是timeout的, 就是說多少毫秒以後, 會自動釋放, 對於這些wakelock, 申請和釋放可能是不成對的。。
5. power.0
有的時候你會看到系統suspend到了最後, 然後遇到power.0 suspend失敗,然後整個系統都又resume起來了。 這個是android專有的,因為power.0是android註冊到suspend最後的一個回調, 它會在CPU進入suspend之前檢查一下有沒有wakelock, 如果這時候還有沒有釋放的wakelock, 那麼它會返回-EBUSY然後導致整個suspend失敗。 調試這個問題的方法就是把上面wakelock的debug信息打開, 然後看看是哪個傢伙去申請了wakelock,然後幹掉它。
這個錯誤的錯誤信息大概是這樣的:
pm_noirq_op(): platform_pm_suspend_noirq+0x0/0x38 returns -11
PM: Device power.0 failed to suspend late: error -11
6. earlysuspend
差點忘掉這個哥們, android裡面另外一個pm相關的大東東, 同樣可以加:
echo 15 > /sys/module/earlysuspend/parameters/debug_mask
來把相關的debug信息打印出來, 比如那個earlysuspend要被call之類的。
7. suspend/resume time.
有的時候你要調試suspend/resume的時間太慢的問題。 一種方法是用initcall_debug, 然後把printk的時間戳打上, 然後看哪個很慢。
但是這樣會讓你的生活很枯燥:)
我有一個patch,專門用來調試這個問題的,但是upstream不接受, 說非要用這種折磨人的方法才行, 但是如果你想用可以下下來打上去用一下。
地址在這裡:http://www.spinics.net/lists/linux-pm/msg24063.html
用法是, 打上這個PATCH以後, 在KERNEL裡面選擇上PM_DEBUG, SUSPEND_DEVICE_TIME_DEBUG 這兩個選項。
然後
echo 微秒 > /sys/power/device_suspend_time_threshold
比如
echo 50000  > /sys/power/device_suspend_time_threshold
注意這裡是微秒哦。。。 它會把在suspend/resume的時候慢的那些driver打出來,然後你去幹掉它。。。