天天看點

揭秘window mobile power management關于device power state的管理

由深入淺的幫你揭開mobile power manager(也就是pm.dll)是如何排程裝置的power state。先分析power manager的内部結構,再從API的角度幫你了解power management API的不同。他們是:

DevicePowerNotify()

SetDevicePower()

SetPowerRequirement()

ReleasePowerRequirement()

這幾個函數,如果你不聽我講,光想通過看看microsoft的官方文檔來了解,那是不可能的!信不信由你。

重要的資料結構

power manager為每一個被管理的裝置維護着一個資料結構,它的定義簡化後如下:

// this structure describes a power-manageable device

typedef struct _DeviceState_tag {

。。。

CEDEVICE_POWER_STATE curDx; // current official power state (not necessarily supported by the device)

CEDEVICE_POWER_STATE floorDx; // minimum device power state, or PwrDeviceUnspecified

CEDEVICE_POWER_STATE ceilingDx; // maximum device power state, or PwrDeviceUnspecified

CEDEVICE_POWER_STATE setDx; // power state if explicitly set, or PwrDeviceUnspecified

CEDEVICE_POWER_STATE lastReqDx; // last state requested by the device

CEDEVICE_POWER_STATE actualDx; // current actual device power state

CEDEVICE_POWER_STATE pendingDx; // Pending DX for updating

DWORD dwNumPending; // Number of Pending for updating.

。。。

} DEVICE_STATE, *PDEVICE_STATE;

居 然有這麼多的device power state來影響最後的一個power state的結果。也就是說power manager是個排程中心,當它最後決定某個裝置最終該是什麼power state(D0/D1/D2/D3/D4)的時候,要參考上面這些成員變量。是以我們第一件事是要搞清楚power manager的排程原則。

power manager的排程原則 設 備的電源狀态總共有D0,D1,D2,D3,D4 (D0〈D1〈D2〈D3〈D4)。ceilingDx與floorDx聽名字就知道是天花闆和地闆的意思(ceilingDx〈floorDx),人是 生活在天花闆和地闆之間的空間的。在電源管理裡面,意思就是天花闆和地闆之間的電源狀态為有效狀态。 例如: ceilingDx=D1 floorDx=D3 那麼D0,D4就是power manager不用考慮的狀态,D1,D2,D3就是有效的電源狀态。 setDx是最厲害的一個狀态,它預設是PwrDeviceUnspecified,隻要它不是PwrDeviceUnspecified,那麼這個裝置的最終狀态就等于setDx。 那麼setDx是誰設定的呢? 從名字我們一猜就知道,那就是 SetDevicePower()。也就是說,隻要這個函數一出馬,那麼不管系統目前是什麼狀态,或者這個裝置是什麼狀态,這個對應的裝置會立即切換到你指定的狀态。是以,call這個函數的時候一定要三思而後行。白屏現象就很有可能是他造成的。 例如: SetDevicePower(_T("BKL1:"),POWER_NAME,D4); 這句話就好像在說:“power manager,我指令你把 BKL1:變成D4!!” 如 果setDx是PwrDeviceUnspecified,那麼power manager就開始考慮lastReqDx。lastReqDx的氣勢就要虛弱很多,也正如microsoft的文檔所說,如果你想改變一個裝置的系統 狀态,同時還想争得power manager的同意,不想太強制,那麼call DevicePowerNotify()是再合适不過的了。 例如: DevicePowerNotify(_T(" BKL1:"),D4,POWER_NAME); 這句話就好像在說:“power manager,你看我現在把 BKL1:變成D4如何?!” power manager接到這樣的請求,它也是需要掂量一下的,那麼它的原則是什麼呢?隻要是有效狀态就可以啦!也就是說ceilingDx〈 lastReqDx〈floorDx。 如果ceilingDx=D1,lastReqDx=D0,那麼裝置最終也隻能是D1。 再如floorDx=D3,astReqDx=D4,那麼裝置最終也隻能是D3。 如果 ceilingDx=D1,floorDx=D3,你請求D2,那麼裝置最終就是D2。 以上原則很簡單吧!可是你有沒有注意到我沒有提到ceilingDx與floorDx是如何确定的。說到這個就不得不說說SetPowerRequirement()和 ReleasePowerRequirement()兩個函數。 例如: SetPowerRequirement(_T(" BKL1:"),D1,POWER_NAME,NULL,0); 好像再說在說:“power manager,幫我把 BKL1:變成D1”。你覺得呢?當然不是! 其實你的真正意思是在說:“power manager,至少幫我把 BKL1:變成D1”。 然後power manager問你,“D0可以麼?(背光更亮一點可以麼?)”。 然後你會說,“當然也可以。” 從這個對話中,我們可以知道SetPowerRequirement()實際在設定我們的地闆-floorDx。至少是floorDx,不能更低了。floorDx的預設值是D4,是以如果你不去call這個函數,那麼就沒什麼限制。 至于ceilingDx 系統資料庫HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Power/[ on | BacklightOff | Unattended | xxx ]的下面你可以定義: " bkl1:"=D2 這樣的定義,就好像你在規定:“系統在on的時候, bkl1:最高是D2”。是以 bkl1:如果是D3,那麼也是可以的。這實際就是在定義裝置電源狀态的天花闆-ceilingDx。同時,如果你沒有特别為某個裝置指定,那麼這個裝置的ceilingDx就是用系統資料庫項default的定義值。 綜上,floorDx,ceilingDx,setDx,lastReqDx這四個值是power manager排程時要參考的重要參數。 設定裝置的電源狀态 curDx,actualDx是一對,意思非常接近。 curDx 是power manager經過排程算法,最後決定的,該裝置的電源狀态。可是這個狀态,此裝置不一定支援。裝置聲明自己所支援的所有狀态是通過 IOCTL_POWER_CAPABILITIES做到的。是以萬一不支援還需要經過mapping,那麼mapping的結果就是actualDx,這 個結果就直接通過IOCTL_POWER_SET下達給裝置驅動。mapping的過程當然就要參考IOCTL_POWER_CAPABILITIES 了。 pendingDx和dwNumPending是用于處理競争問題設計的計數器。

繼續閱讀