1. 程式人生 > >Android電源管理-休眠簡要分析

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