Android: Wakelocks and TuxOnIce

最近為了把 TuxOnIce 整到 Android 上面,著實把 Linux 的電源管
理系統中關於 suspend 與 hibernation 的部份研究了一下。而 Android 為了增
加待機時間加入了 wakelock 的機制,讓情況變得更加複雜。

TuxOnIce

TOI Patch

TuxOnIce 簡稱 TOI,前身是 Software Suspend 2,是一個長期在 linux
upstream 以外耕耘的一個休眠補釘,相較於早期整合到 linux kernel 內的
swsusp,TOI 的功能非常豐富,可以指定把記憶體內容儲存到多種不同的位置,
如檔案或置換空間,還可以選擇不同的壓縮方法。

首先幫 ARM 平台加上基本的休眠功能,使用 Hiroshi DOYU 的 patch:

http://article.gmane.org/gmane.linux.power-management.general/20543

然後到 TOI 網站下載最新的 3.2 補釘,打上去的時候會有一些衝突但是都還滿
容易解決,要注意的是某些衝突是看不出來的,例如因為函式移動位置而造成重
複定義,要小心檢查。

然後因為 TOI 對於非 x86 平台有一些假設現在已經不適用,所以需要修改

https://gitorious.org/0xlab-kernel/kernel/commit/e551caf

OMAPFB

使用 Pandaboard 加上 Android 測試才發現從休眠醒來後 LCD 不會自動點亮,
通常在 x86 平台上有 pm-utils 或是 hibernate script 來幫忙處理這種關閉打
開 LCD 的問題,這次我是先在 kernel 內幫 OMAPFB 加上一個電源管理的呼叫,
讓 kernel 醒來的時候自己重新設定 LCD。

https://gitorious.org/0xlab-kernel/kernel/commit/21e0f14

Pandaboard & Beagleboard xM

在 Pandaboard 或 Beagleboard xM 上面沒有 NAND 可以當作儲存空間,所以一
般都是把檔案放在MMC 上面,第一個 patch 讓 kernel 在開機的時候不要初始化
不存在的 NAND 空間

https://gitorious.org/0xlab-kernel/kernel/commit/3ae6b4c

然後因為 MMC 的 probe 需要時間,第二個 patch 讓 TOI 等待指定的 resume
device 已經偵測到之後才開始進行 resume

https://gitorious.org/0xlab-kernel/kernel/commit/1078bd7

Wakelock

wakelock 是 Android 為了讓裝置可以更積極的休眠又不妨礙正常工作的進行而
加入的機制,究竟是好是壞已經在 LKML 與 LWN 上面討論過非
常多次,可以參考:

失眠症

開始測試 TOI 的效果時遇到的第一個問題就是失眠症,因為 wakelock 從中作
梗,導致每次休眠到一半就被取消掉。原來是因為 TOI 的休眠途徑會先強制檔
案系統把內容寫回,而 MMC 子系統會在寫入/讀取一段時間後嘗試進入低耗電模
式,偏偏 Android 在這裡安插了一個 wakelock,導致之後要凍結所有執行緒的
時候失敗。

解法,首先因為休眠的後半段路徑其實就是要準備進行關機,而一般來說休眠都
是人為啟動,因此可以假設此時使用者了解工作可能還未完成,可以忽略
wakelock,所以第一個 patch 就是讓休眠的路徑不去檢查 wakelock,避免像
MMC 這樣的問題。

https://gitorious.org/0xlab-kernel/kernel/commit/3bb5d6f

接下來是一般的待機路徑,似乎是因為新的 kernel 會積極的嘗試把 MMC 變成
低耗電模式,但 OMAP 預設的 MMC timeout 是 100 毫秒,把工作放在 Queue
裡面反而不斷鎖住 wakelock 讓 Android 無法休眠,第二個 patch 就是讓 MMC
子系統在準備休眠的時候就不要作無謂的掙扎,直接進入低耗電模式。

https://gitorious.org/0xlab-kernel/kernel/commit/88823b9

嗜睡症

解決了失眠症沒想到接下來遇到嗜睡症,因為手機插著 USB 的時候是不會真正
睡著的,所以一直沒機會觀察 Android 睡著是怎麼樣,原來只把 kernel 叫醒
是沒用的,Android 還會檢查目前的 input event 是否屬於 user activity 的
範圍,是的話才會把整個系統帶醒,不然因為 wakelock 的機制,馬上就會又睡
著。

參考: