工作需要,需要對這一塊深入學習。故在此做一點分析記錄,存疑解惑。
一、開篇
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()函數代碼如下:

1 void request_suspend_state(suspend_state_t new_state) 2 { 3 unsigned long irqflags; 4 int old_sleep; 5 6 #ifdef CONFIG_PLAT_RK 7 if (system_state != SYSTEM_RUNNING) 8 return; 9 #endif 10 11 spin_lock_irqsave(&state_lock, irqflags); 12 old_sleep = state & SUSPEND_REQUESTED; 13 if (debug_mask & DEBUG_USER_STATE) { 14 struct timespec ts; 15 struct rtc_time tm; 16 getnstimeofday(&ts); 17 rtc_time_to_tm(ts.tv_sec, &tm); 18 pr_info("request_suspend_state: %s (%d->%d) at %lld " 19 "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", 20 new_state != PM_SUSPEND_ON ? "sleep" : "wakeup", 21 requested_suspend_state, new_state, 22 ktime_to_ns(ktime_get()), 23 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 24 tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); 25 } 26 if (!old_sleep && new_state != PM_SUSPEND_ON) { 27 state |= SUSPEND_REQUESTED; 28 //進入Early suspend處理,執行函數early_suspend 29 queue_work(suspend_work_queue, &early_suspend_work); 30 } else if (old_sleep && new_state == PM_SUSPEND_ON) { 31 state &= ~SUSPEND_REQUESTED; 32 wake_lock(&main_wake_lock); 33 //進入Late resume處理,執行函數late_resume 34 queue_work(suspend_work_queue, &late_resume_work); 35 } 36 requested_suspend_state = new_state; 37 spin_unlock_irqrestore(&state_lock, irqflags); 38 }
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