I have read some good articles, and I have written them very well. Let's take a closer look.
From: http://blog.csdn.net/lizhiguo0532/article/details/6453581
Note:
1. Based on Linux 2.6.32 and Android 2.2, only support SDR (MEM ).
2. References:
Http://2695477.blog.51cto.com/blog/2685477/484751
Http://www.docin.com/p-115475680.html
Http://blogold.chinaunix.net/u3/113927/showart_2447111.html
Http://www.cnmsdn.com/html/201003/1269407632ID2530.html
1. Introduction to new features
In fact, Android still uses the standard Linux sleep wake-up system, but adds some new features, early suspend, late resume, and wake lock.
Early suspend-this mechanism defines that some display-related devices, such as backlights, gravity sensors, and touch screens, should be turned off when the display is turned off early in suspend, however, at this time, the system may still run tasks that hold the wake lock, such as playing music, making a phone call, or scanning files on the SD card. At this time, the whole system cannot go to sleep, until all the wake locks are released. In embedded devices, pessimism is a huge power consumption. All Android devices use this mechanism.
Late resume-this mechanism defines that in the later stages of resume, that is, the wake-up source has awakened the processor, and the wake-up process for standard Linux has been completed, the android upper-layer system identifies that the physical wake-up source is defined by the upper-layer, so the upper layer will issue the late resume command to the lower layer, at this time, the late resume callback function registered by the relevant device will be called.
Wake lock-wakelock plays a core role in the android power management system. wakelock is a lock mechanism. As long as a task holds this lock, the system cannot enter sleep, it can be obtained by user-State processes and kernel threads. The lock can be time-out or not time-out. The lock will be automatically unlocked after the time expires. If there is no lock or timeout, the kernel will start the sleep mechanism of standard Linux to enter sleep.
Ii. kernel layer source code parsing-implementation of early suspend and late resume
Source code:
Kernel/power/Main. c
Kernel/power/earlysuspend. c
Kernel/power/wakelock. c
Kernel/power/userwakelock. c
Kernel/power/suspend. c
In the previous standard Linux sysfs interface, only one State is required. Now, at least three interface files are required: State, wake_lock, and wake_unlock. Now, in combination with the new features added by Android for sleep wake-up, you can enter another mode of file state: on. The standard Android system only supports the on And mem modes of state, the rest are currently not supported. The read/write functions corresponding to the wake_lock and wake_unlock interfaces are encapsulated in the file userwakelock. C. The create wakelock or release wakelock in wakelock. C is used by the user space.
If the upper-layer user executes echo XXX (on or MEm)> sys/power/State, the following function is called:
Static ssize_t state_store (struct kobject * kobj, struct kobj_attribute * ATTR,
Const char * Buf, size_t N)
{
# Ifdef config_suspend // set
# Ifdef config_earlysuspend // set
Suspend_state_t state = pm_suspend_on; // for early suspend and late resume
# Else
Suspend_state_t state = pm_suspend_standby;
# Endif
Const char * const * s;
# Endif
Char * P;
Int Len;
Int error =-einval;
P = memchr (BUF, '/N', N );
Len = P? P-Buf: N;
/* First, check if we are requested to hibernate */
If (LEN = 4 &&! Strncmp (BUF, "disk", Len )){
Error = hibernate (); // check whether the disk power-saving mode is required. Currently, this mode is not supported.
Goto exit;
}
# Ifdef config_suspend // def
For (S = & pm_states [State]; State <pm_suspend_max; s ++, State ++ ){
If (* S & Len = strlen (* s )&&! Strncmp (BUF, * s, Len ))
Break;
}
If (State <pm_suspend_max & * s)
# Ifdef config_earlysuspend
If (State = pm_suspend_on | valid_state (State )){
// The PM must go through the platform. the Mode defined in the C file supports checking functions. MTK only supports mem. If the late resume command (on) sent by Android is used, it will be released and executed.
Error = 0;
Request_suspend_state (State); // Android sleep wake-up Route
}
# Else
Error = enter_state (State); // the path of standard Linux sleep wake-up
# Endif
# Endif
Exit:
Return Error? Error: N;
}
@ Kernel/power/earlysuspend. c
Enum {
Debug_user_state = 1u <0,
Debug_suspend = 1u <2,
};
Int earlysuspend_debug_mask = debug_user_state;
Module_param_named (earlysuspend_debug_mask, earlysuspend_debug_mask, Int, s_irugo | s_iwusr | s_iwgrp );
Static define_mutex (early_suspend_lock );
Static list_head (early_suspend_handlers );
Static void early_sys_sync (struct work_struct * work );
Static void early_suspend (struct work_struct * work );
Static void late_resume (struct work_struct * work );
Static declare_work (early_sys_sync_work, early_sys_sync );
Static declare_work (early_suspend_work, early_suspend );
Static declare_work (late_resume_work, late_resume );
Static define_spinlock (state_lock );
Enum {
Suspend_requested = 0x1,
Suincluded = 0x2,
Suspend_requested_and_suincluded = suspend_requested | suincluded,
};
Static int state; // The initialization value is 0.
Static declare_completion (fb_drv_ready );
Void request_suspend_state (suspend_state_t new_state)
{
Unsigned long irqflags;
Int old_sleep;
Spin_lock_irqsave (& state_lock, irqflags );
Old_sleep = State & suspend_requested; // state = 1 or 3
// The State value changes cyclically at 0-> 1-> 3-> 2-> 0. The analysis code below shows the current stage of the system, simply put: Normal-> prepare to enter early suspend-> Start Early suspend and unlock the wakelock named mian. If no other wakelock is locked at this time, then, the system uses the sleep wake-up path of Linux to truly sleep the entire system until the source is awakened and then the processor and Linux layer are awakened. After that, does the android layer determine that the underlying wake-up is caused by the wake-up source I defined? If not, Android will ignore it. After a period of time there is no wakelock lock, the system will go to the sleep path of Linux again. If yes, the upper Android layer will write an on command to the state interface, which will also call the request_suspend_state ()-> prepare to execute late
Resume-> start to execute late resume, and then the entire system will be awakened.
If (earlysuspend_debug_mask & debug_user_state ){
Struct timespec ts; // print the debug information
Struct rtc_time TM;
Getnstimeofday (& TS );
Rtc_time_to_tm (TS. TV _sec, & TM );
Pr_info ("[request_suspend_state]: % s (% d-> % d) at % LLD"
"(% D-% 02d-% 02d % 02d: % 02d: % 02d. % 09lu UTC)/n ",
New_state! = Pm_suspend_on? "Sleep": "Wakeup ",
Requested_suspend_state, new_state,
Ktime_to_ns (ktime_get ()),
TM. tm_year + 1900, TM. tm_mon + 1, TM. tm_mday,
TM. tm_hour, TM. tm_min, TM. tm_sec, ts. TV _nsec );
}
// Eg: [request_suspend_state]: Sleep (0-> 3) at 97985478409 (09:52:59. 637902305 UTC). Here we get and process the time. For details, refer
// Ready to enter earlysuspend
If (! Old_sleep & new_state! = Pm_suspend_on) {// susepnd will enter here
State | = suspend_requested; // state = 1
Pr_info ("[request_suspend_state]:
Sys_sync_work_queue early_sys_sync_work/N ");
Queue_work (sys_sync_work_queue, & early_sys_sync_work );
Pr_info ("[request_suspend_state]: suspend_work_queue early_suspend_work/N ");
Queue_work (suspend_work_queue, & early_suspend_work );
// In the wakelocks_init () function (wakelock. c), these two working queues and worker threads are created to handle sys_sync and early suspend tasks. For details about the work queue, refer to my work queue article
}
// Ready to enter lateresume
Else if (old_sleep & new_state = pm_suspend_on ){
State & = ~ Suspend_requested; // state = 2
Wake_lock (& main_wake_lock); // lock main wakelock
Pr_info ("[request_suspend_state]: suspend_work_queue late_resume_work/N ");
If (queue_work (suspend_work_queue, & late_resume_work )){
// Submit the work item of late resume
//
// In order to synchronize the backlight turn on timing,
// Block the thread and wait for FB driver late_resume ()
// Callback function is completed
//
Wait_for_completion (& fb_drv_ready );
// Wait for the completion of fb_drv_ready, which will be completed after the end of late resume
}
}
Requested_suspend_state = new_state;
// Stores the sleep or sleep state for the next sleep or sleep.
Spin_unlock_irqrestore (& state_lock, irqflags );
}
The two work items submitted in the system suspend will be executed one after another, so let's take a look at the key functions for executing early suspend.
Static void early_sys_sync (struct work_struct * Work)
{
Wake_lock (& sys_sync_wake_lock );
Printk ("[sys_sync work] Start/N ");
Sys_sync (); // synchronize the File System
Printk ("[sys_sync wrok] Done/N ");
Wake_unlock (& sys_sync_wake_lock );
}
Static void early_suspend (struct work_struct * Work)
{
Struct early_suspend * Pos;
Unsigned long irqflags;
Int abort = 0;
Mutex_lock (& early_suspend_lock );
Spin_lock_irqsave (& state_lock, irqflags );
If (State = suspend_requested)
State | = suincluded; // state = 3
Else
Abort = 1;
Spin_unlock_irqrestore (& state_lock, irqflags );
If (abort) {// suspend stop and quit
If (earlysuspend_debug_mask & debug_suspend)
Pr_info ("[early_suspend]: abort, State % d/N", State );
Mutex_unlock (& early_suspend_lock );
Goto abort;
}
If (earlysuspend_debug_mask & debug_suspend)
Pr_info ("[early_suspend]: Call handlers/N ");
List_for_each_entry (Pos, & early_suspend_handlers, link ){
If (POS-> suspend! = NULL)
Pos-> suspend (POS );
}
// The register_early_suspend () function registers each early suspend item to the chain table early_suspend_handlers with a priority value. Here, the corresponding early suspend callback function is executed.
Mutex_unlock (& early_suspend_lock );
// Remove sys_sync from early_suspend,
// And use work queue to complete sys_sync
Abort:
Spin_lock_irqsave (& state_lock, irqflags );
If (State = suspend_requested_and_suspended)
{
Pr_info ("[early_suspend]: wake_unlock (main)/n ");
Wake_unlock (& main_wake_lock );
// Unlock main wakelock. It seems that after the system executes early suspend, the standard Linux suspend process is not executed. In fact, the android method is, if you finish the early suspend callback, you can immediately follow the standard Linux suspend process. Instead, you will check whether wakelock is held. If all wakelock is unlocked, then the suspend step of the standard Linux is executed.
}
Spin_unlock_irqrestore (& state_lock, irqflags );
}
Static void late_resume (struct work_struct * Work)
{
Struct early_suspend * Pos;
Unsigned long irqflags;
Int abort = 0;
Int completed = 0;
Mutex_lock (& early_suspend_lock );
Spin_lock_irqsave (& state_lock, irqflags );
// Return back from suspend
If (State = susponded)
State & = ~ Suincluded; // state = 0
Else
Abort = 1;
Spin_unlock_irqrestore (& state_lock, irqflags );
If (abort ){
If (earlysuspend_debug_mask & debug_suspend)
Pr_info ("[late_resume]: abort, State % d/N", State );
Goto abort;
}
If (earlysuspend_debug_mask & debug_suspend)
Pr_info ("[late_resume]: Call handlers/N ");
List_for_each_entry_reverse (Pos, & early_suspend_handlers, link)
{
If (! Completed & Pos-> level <early_suspend_level_disable_fb ){
Complete (& fb_drv_ready );
Completed = 1;
}
If (POS-> resume! = NULL)
Pos-> resume (POS );
}
// Execute the late resume callback function on the chain table early_suspend_handlers in reverse order with early suspend
If (earlysuspend_debug_mask & debug_suspend)
Pr_info ("[late_resume]: done/N ");
Abort:
If (! Completed)
Complete (& fb_drv_ready); // set the completion quantity. OK
Mutex_unlock (& early_suspend_lock );
}