Android電源管理-休眠簡要分析
轉自https://www.cnblogs.com/tangdoudou/p/3807936.html
工作需要,需要對這一塊深入學習。故在此做一點分析記錄,存疑解惑。
一、開篇
1.Linux 描述的電源狀態
- On(on) S0 - Working
- Standby (standby) S1 - CPU and RAM are powered but not executed
- Suspend to RAM(mem) S3 - RAM is powered and the running content is saved to RAM
- Suspend to Disk,Hibernation(disk) S4 - All content is saved to Disk and power down
S3 aka STR(suspend to ram),掛起到記憶體,簡稱待機。計算機將目前的執行狀態等資料存放在記憶體,關閉硬 盤、外設等裝置,進入等待狀態。此時記憶體仍然需要電力維持其資料,但整機耗電很少。恢復時計算機從記憶體讀出資料,回到掛起前的狀態,恢復速度較快。對 DDR的耗電情況進行優化是S3效能的關鍵,大多數手持裝置都是用S3待機。
S4 aka STD(suspend to disk),掛起到硬碟,簡稱休眠。把執行狀態等資料存放在硬碟上某個檔案或者某個特定的區域,關閉硬碟、外設等裝置,進入關機狀態。此時計算機完全關閉,不耗電。恢復時計算機從休眠檔案/分割槽中讀出資料,回到休眠前的狀態,恢復速度較慢。電子書專案中,見過一款索尼的電子書,沒有定義關機狀態,只定義了S4,從而提高開機速度。
以上摘錄自:http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece763104
6893b4c4380147d8c8c4668d4e419ce3b4c413037bfa6663f405a8e906b6075fc
4d5bedfb6079370123b598938f4a85ac925f75ce786a6459db0144dc5bf0dc475
5d627e44de8df4aa0fcad7384afa28d880311dd52756d87849c5b704f9634b6&p
=c933cc16d9c116f51ebd9b7d0a13cd&newp=8366c54ad5c444e411b3c22d0214cf2
31610db2151d6db10349dcd1e&user=baidu&fm=sc&query=pm_autosleep_init&qid=&p1=1
在閱讀下面的內容之前,強烈建議閱讀下。
Android在Linux核心原有的睡眠喚醒機制上面新增了三個,如下:
• Wake Lock 喚醒鎖機制;
• Early Suspend 預掛起機制;
• Late Resume 遲喚醒機制;
我們來看一張Android睡眠喚醒機制的框架圖:
• Android特有的earlysuspend: request_suspend_state(state)
• Linux標準的suspend: enter_state(state)
二、相關程式碼涉及檔案
• Frameworks
// 供給上層應用程式呼叫的介面
frameworks/base/core/java/android/os/PowerManager.java
// 具體實現PowerManager類中的介面
frameworks/base/services/java/com/android/server/PowerManagerService.java
// 被PowerManagerService類呼叫
frameworks/base/core/java/android/os/ Power.java
• JNI
// 實現Power類中的JNI介面
frameworks/base/core/jni/android_os_Power.cpp
• HAL
// 進行sysfs使用者介面的操作
hardware/libhardware_legacy/power/power.c
• Kernel
kernel/kernel/power/main.c
kernel/kernel/power/earlysuspend.c
kernel/kernel/power/suspend.c
kernel/kernel/power/wakelock.c
kernel/kernel/power/userwakelock.c
在應用程式框架層中,PowerManager類是面向上層應用程式的介面類,提供了Wake Lock機制(同時也是睡眠喚醒子系統)的基本介面(喚醒鎖的獲取和釋放)。上層應用程式通過呼叫這些介面,實現對系統電源狀態的監控。
• PowerManager類通過IBinder這種Android中特有的通訊模式,與PowerManagerService 類進行通訊。
• PowerManagerService 是PowerManager 類中定義的介面的具體實現,並進一步呼叫Power 類來與下一層進行通訊。PowerManagerService 類是WakeLock 機制在應用程式框架層的核心,他們對應用程呼叫PowerManager類介面時所傳遞的引數進行初步的分析和對應的設定,並管理一個喚醒鎖佇列,然後配合其他模組(例如WatchDog、BatteryService、ShutdownThread 等)的狀態資訊,做出決策,呼叫Power類的對應介面,最終通過JNI 介面,呼叫到硬體抽象層中的函式,對sysfs 的使用者介面進行操作,從而觸發核心態實現的功能。
三、Kernel使用者空間介面分析
1. sysfs的屬性檔案
電源管理核心層給應用層提供的介面就是sysfs 檔案系統,所有的相關介面都通過sysfs實現。Android上層frameworks也是基於sysfs做了包裝,最終提供給Android java應用程式的是java類的形式。
Android系統會在sysfs裡面建立以entry:
/sys/power/state
/sys/power/wake_lock
/sys/power/wake_unlock
echo mem > /sys/power/state或echo standby > /sys/power/state: 命令系統進入earlysuspend狀態,那些註冊了early suspend handler的驅動將依次進入各自的earlysuspend 狀態。
echo on > /sys/power/state: 將退出early suspend狀態
echo disk > /sys/power/state: 命令系統進入hibernation狀態
echo lockname > /sys/power/wake_lock: 加鎖“lockname”
echo lockname > /sys/power/wake_unlock: 解鎖“lockname”
上述是分別加鎖和解鎖的命令,一旦系統中所有wakelock被解鎖,系統就會進入suspend狀態,可見Linux中原本使系統 suspend 的操作(echo mem > /sys/power/state 等)在Android被替換成使系統進入early suspend;而wake lock 機制成為使用者命令系統進入suspend狀態的唯一途徑。
Kernel與HAL介面是通過/sys/power下面的一系統檔案來實現的,如:/sys/power/state.在使用者空間介面中,定義了一組sysfs的屬性檔案,其中一個定義是:
1 power_attr(state)
這個巨集的程式碼如下:
1 #define power_attr(_name) \ 2 static struct kobj_attribute _name##_attr = { \ 3 .attr = { \ 4 .name = __stringify(_name), \ 5 .mode = 0644, \ 6 }, \ 7 .show = _name##_show, \ 8 .store = _name##_store,
展開後的程式碼是:
1 #define power_attr(state) \ 2 static struct kobj_attribute state_attr = { \ 3 .attr = { \ 4 .name = "state", \ 5 .mode = 0644, \ 6 }, \ 7 .show = state_show, \ 8 .store = state_store,
2. 建立sysfs檔案
1 static int __init pm_init(void) 2 { 3 int error = pm_start_workqueue(); 4 if (error) 5 return error; 6 hibernate_image_size_init(); 7 hibernate_reserved_size_init(); 8 power_kobj = kobject_create_and_add("power", NULL); 9 if (!power_kobj) 10 return -ENOMEM; 11 error = sysfs_create_group(power_kobj, &attr_group); //建立sys檔案介面 12 if (error) 13 return error; 14 pm_print_times_init(); 15 return pm_autosleep_init(); //建立auto_sleep工作佇列,也把使用者態向autosleep 寫入當作wakeup_source 16 } 17 18 core_initcall(pm_init) //呼叫pm_init
pm_init函式執行後,會建立/sys/power目錄,且目錄下會建立一系列屬性檔案,其中一個是/sys/power/state檔案。使用者空間寫該檔案將會導致state_store被呼叫,讀該檔案將會導致state_show函式被呼叫。
2. 標準的Linux核心呼叫suspend流程
1 static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, 2 const char *buf, size_t n) 3 { 4 suspend_state_t state; 5 int error; 6 7 error = pm_autosleep_lock(); 8 if (error) 9 return error; 10 11 if (pm_autosleep_state() > PM_SUSPEND_ON) { // autosleep是android核心為了跟主線核心相容所引入的 12 error = -EBUSY; 13 goto out; 14 } 15 16 state = decode_state(buf, n); 17 if (state < PM_SUSPEND_MAX) 18 error = pm_suspend(state); // 進入suspend 的模式 19 else if (state == PM_SUSPEND_MAX) 20 error = hibernate(); // 進入冬眠模式 21 else 22 error = -EINVAL; 23 24 out: 25 pm_autosleep_unlock(); 26 return error ? error : n;
當底層接受到上層傳遞到的值進行一些列的操作,有很多的state 狀態:
1 #define PM_SUSPEND_ON ((__force suspend_state_t) 0) // S0 2 #define PM_SUSPEND_STANDBY ((__force suspend_state_t) 1) // S1 3 #define PM_SUSPEND_MEM ((__force suspend_state_t) 3) // S2 4 #define PM_SUSPEND_MAX ((__force suspend_state_t) 4) // S3
在state_store中,若定義了CONFIG_EARLYSUSPEND,則執行 request_suspend_state(state)以先進入earlysuspend,然後根據wake_lock的狀態決定是否進入 suspend;否則直接執行enter_state(state)以進入suspend狀態。我們來看下pm_suspend的原生程式碼:
1 int pm_suspend(suspend_state_t state) 2 { 3 int error; 4 5 if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX) // state引數無效 6 return -EINVAL; 7 8 pm_suspend_marker("entry"); 9 error = enter_state(state); 10 if (error) { 11 suspend_stats.fail++; 12 dpm_save_failed_errno(error); 13 } else { 14 suspend_stats.success++; 15 } 16 pm_suspend_marker("exit"); 17 return error;
三、Android 休眠(suspend)
1. 相關檔案
• kernel/kernel/power/main.c
• kernel/kernel/power/earlysuspend.c
• kernel/kernel/power/wakelock.c
2. 特性介紹
1) Early Suspend
Early suspend 是android 引進的一種機制,這種機制在上游備受爭議,這裡不做評論。 這個機制作用是在關閉顯示的時候,一些和顯示有關的裝置,比如LCD背光、重力感應器、 觸控式螢幕都會關掉,但是系統可能還是在執行狀態(這時候還有wake lock)進行任務的處理,例如在掃描 SD卡上的檔案等。 在嵌入式裝置中,背光是一個很大的電源消耗,所以android會加入這樣一種機制。
2) Late Resume
Late Resume 是和suspend 配套的一種機制,是在核心喚醒完畢開始執行的。主要就是喚醒在Early Suspend時休眠的裝置。
3) Wake Lock
wake_lock 在Android的電源管理系統中扮演一個核心的角色。wake_lock是一種鎖的機制,只要有人拿著這個鎖,系統就無法進入休眠,可以被使用者態程式和 核心獲得。這個鎖可以是有超時的或者是沒有超時的,超時的鎖會在超時以後自動解鎖。如果沒有鎖了或者超時了,核心就會啟動休眠的那套機制來進入休眠。
3. Android Suspend
main.c檔案是整個框架的入口。使用者可以通過讀寫sys檔案/sys/power/state實現控制系統進入低功耗狀態。使用者對於/sys /power/state的讀寫會呼叫到main.c中的state_store(),使用者可以寫入const char * const pm_states[] 中定義的字串, 比如“on”,“mem”,“standby”,“disk”。
1 const char *const pm_states[PM_SUSPEND_MAX] = { 2 [PM_SUSPEND_FREEZE] = "freeze", 3 [PM_SUSPEND_STANDBY] = "standby", 4 [PM_SUSPEND_MEM] = "mem", 5 }
state_store()首先判斷使用者寫入的是否是“disk”字串,如果是則呼叫hibernate()函式命令系統進入hibernation狀 態。如果是其他字串則呼叫request_suspend_state()(如果定義 CONFIG_EARLYSUSPEND)或者呼叫enter_state()(如果未定義CONFIG_EARLYSUSPEND)。 request_suspend_state()函式是android相對標準linux改動的地方,它實現在earlysuspend.c中。在標準 linux核心中,使用者通過 sysfs 寫入“mem”和“standby”時,會直接呼叫enter_state()進入suspend模式,但在android中則會呼叫request_suspend_state()函式進入early suspend狀態。request_suspend_state()函式程式碼如下:
View Code
TAG:
1 const char * const OLD_PATHS[] = { 2 "/sys/android_power/acquire_partial_wake_lock", 3 "/sys/android_power/release_wake_lock", 4 }; 5 6 const char * const NEW_PATHS[] = { 7 "/sys/power/wake_lock", 8 "/sys/power/wake_unlock", 9 };
1 static inline void 2 initialize_fds(void) 3 { 4 // XXX: should be this: 5 //pthread_once(&g_initialized, open_file_descriptors); 6 // XXX: not this: 7 if (g_initialized == 0) { 8 if(open_file_descriptors(NEW_PATHS) < 0) 9 open_file_descriptors(OLD_PATHS); 10 g_initialized = 1; 11 }
未完待續......
本文很多內容參考且摘錄自:
http://blog.csdn.net/myarrow/article/details/8136691
http://blog.csdn.net/myarrow/article/details/8137952
http://blog.csdn.net/myarrow/article/details/8137566
http://blog.csdn.net/sunweizhong1024/article/details/17102047