按电源键屏幕唤醒和屏幕睡眠流程(从上层到kernel)

复制于http://blog.csdn.net/shadow_dance/article/details/8070252

粘贴如下:

一. 屏幕的唤醒

  首先inputread在读取到有keyboard事件上报后,会调用到keydispatch的notifykey,去询问wm是否会对这次按键特殊处理,如果WM不处理,则此处会点亮或者熄灭屏幕。

 inputReader.cpp                                 KeyboardInputMapper::processKey

                                                                   getDispatcher()->notifyKey

 inputDispacher.cpp                            InputDispatcher::notifyKey

                                                                  mPolicy->interceptKeyBeforeQueueing

com_android_server_inputManager.cpp                NativeInputManager::interceptKeyBeforeQueueing

                                                                                         env->CallIntMethod(mCallbacksObj,
                                                                                        gCallbacksClassInfo.interceptKeyBeforeQueueing,
                                                                                         when, action, flags, keyCode, scanCode, policyFlags, isScreenOn);             //此处gCallbacksClassInfo中的各种方法就是InputManager的对应的方法,在JNI初始化的时候就注册了,详情请参看register_android_server_InputManager函数,通过jniRegisterNativeMethods将inputmanager的各种callback注册到gCallbacksClassInfo中。

返回的wmaction就是后面WM对此次按键事件的policy,通过此返回值,此处会决定下一步的动作。

InputManager.java interceptKeyBeforeQueueing

                                                                              mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing

WindowmanagerService.java InputMonitor::interceptKeyBeforeQueueing

                                                                              mPolicy.interceptKeyBeforeQueueing

PhonewindowManager.java interceptKeyBeforeQueueing

                                                                              //摘录部分代码:

[java] view plain copy
public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
final boolean down = action == KeyEvent.ACTION_DOWN;
final boolean canceled = (flags & KeyEvent.FLAG_CANCELED) != 0;

    final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;  

    // If screen is off then we treat the case where the keyguard is open but hidden  
    // the same as if it were open and in front.  
    // This will prevent any keys other than the power button from waking the screen  
    // when the keyguard is hidden by another activity.  

    final boolean keyguardActive = (isScreenOn ?  
                                    mKeyguardMediator.isShowingAndNotHidden() :  
                                    mKeyguardMediator.isShowing());  

    int result; //result即为返回到wmaction  
    if (isScreenOn || isInjected) {  
        // When the screen is on or if the key is injected pass the key to the application.  
        result = ACTION_PASS_TO_USER;  
    } else {//我们现在走的应该是这个  
        // When the screen is off and the key is not injected, determine whether  
        // to wake the device but don't pass the key to the application.  
        result = 0;  

        final boolean isWakeKey = (policyFlags  
                & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;  
        if (down && isWakeKey) {  
            if (keyguardActive) {  

[java] view plain copy
//也就是说,如果当前屏幕是灭的,且按的键是可以唤醒屏幕的,那么WM会首先将此次按键传递给keyguard,由keyguard来唤醒屏幕,并作出相应的动作,否则就自己点亮屏幕,通过返回的policy来通知下层。

                // If the keyguard is showing, let it decide what to do with the wake key.  
              <span style="color:#ff0000;"> </span> mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);  
            } else {  
                // Otherwise, wake the device ourselves.  

                result |= ACTION_POKE_USER_ACTIVITY;  
            }  
        }  
    }<span style="font-weight: bold; ">  


}
keyguarViewMediator.java onWakeKeyWhenKeyguardShowingTq
wakeWhenReadyLocked

                                                                                       mHandler.obtainMessage(WAKE_WHEN_READY, keyCode, 0);

                                                                         mHandler.handleMessage

                                                                       handleWakeWhenReady

                                                                       mKeyguardViewManager.wakeWhenReadyTq

    KeyguardViewManager.java                mKeyguardView.wakeWhenReadyTq

    LockpatternKeyguardView.java            wakeWhenReadyTq

                                                                         getCallback().pokeWakelock();

    KeyguardViewMediator.java                  pokeWakelock

                                                                        mWakeLock.acquire();        // mWakeLock即为:mWakeLock = mPM.newWakeLock(
            PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
            "keyguard");      具有ACQUIRE_CAUSE_WAKUPQ权限的唤醒锁,上层就是通过此锁来唤醒屏幕,接下来就是powermanager的流程了。

    PowerManager.java                              acquire

                                                                       mService.acquireWakeLock

     PowermanagerService.java                acquireWakeLock

                                                                        acquireWakeLockLocked//此处会检查唤醒锁的标志位,作出对应的处理。

                                                                         setPowerState       //此函数为powermanager的核心函数之一,会对屏幕背光/唤醒,睡眠等作出相应的处理

                                                                       setScreenStateLocked //此函数很关键

                                                                       Power.setScreenState

    power.java                                                setScreenState

   android_os_Power.cpp                          setScreenState

    power.c                                                      set_screen_state//此函数作为上层的最后一个函数,会打印出标志性的log,*** set_screen_state %d,如果打出这个log,至少证明从APP-HAL都是在正常干活的,那么问题只能是kernel的了,贴出代码看看:

[cpp] view plain copy
int
set_screen_state(int on)
{
//QEMU_FALLBACK(set_screen_state(on));

LOGI("*** set_screen_state %d", on); //神奇的log标志  

initialize_fds();  

//LOGI("go_to_sleep eventTime=%lld now=%lld g_error=%s\n", eventTime,  
  //      systemTime(), strerror(g_error));  

if (g_error) return g_error;  

char buf[32];  
int len;  

if(on)  
    len = sprintf(buf, "%s", on_state);  
else  
    len = sprintf(buf, "%s", off_state);  

len = write(g_fds[REQUEST_STATE], buf, len);//此处就是写了kernel的设备文件接口。
if(len < 0) {
LOGE(“Failed setting last user activity: g_error=%d\n”, g_error);
}
return 0;
}
在此函数中写了底层的power控制的设备文件接口,对应的设备文件为:/sys/power/state
接下来的流程就是到了内核空间。

kernel/kernel/power/main.c state_store

//此函数被宏power_attr(state)声明为设备文件接口 sys/power/state,宏power_attr的定义为(power.h):

                                                                                                                   #define power_attr(_name) \

static struct kobj_attribute _name##_attr = {
.attr = {
.name = __stringify(_name),
.mode = 0644,
},
.show = _name##_show,
.store = _name##_store,
}

[cpp] view plain copy
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
#ifdef CONFIG_SUSPEND
#ifdef CONFIG_EARLYSUSPEND
suspend_state_t state = PM_SUSPEND_ON;
#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();  

goto Exit;
}

#ifdef CONFIG_SUSPEND
for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
break;

}  
printk("##: enter %s\n", pm_states[state]);  
if (state < PM_SUSPEND_MAX && *s)  

#ifdef CONFIG_EARLYSUSPEND // android对linux的睡眠唤醒机制做了一些优化,也就是earlysuspen,laterresume机制,此处宏是有定义的,所以会先走android的那一套
if (state == PM_SUSPEND_ON || valid_state(state)) {
error = 0;
printk(“##: entering request_suspend_state()…\n”);
request_suspend_state(state);
}
#else

    error = enter_state(state);  

#endif
#endif

Exit:
printk(“##: state_store() returns back.\n”);
return error ? error : n;
}

kernel/kernel/power/erlysuspend.c request_suspend_state

[cpp] view plain copy
void request_suspend_state(suspend_state_t new_state)
{
unsigned long irqflags;
int old_sleep;

/* when we get here, means userspace service work well, stop reboot watchdog */  
powerkey_wdt_stop();  

spin_lock_irqsave(&state_lock, irqflags);  
old_sleep = state & SUSPEND_REQUESTED;  
if (debug_mask & DEBUG_USER_STATE) {  
    struct timespec ts;  
    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);  

}  
if (!old_sleep && new_state != PM_SUSPEND_ON) {  
    state |= SUSPEND_REQUESTED;  
    queue_work(suspend_work_queue, &early_suspend_work);  
}<span style="color: rgb(255, 0, 0); background-color: rgb(255, 255, 255);"> </span><span style="background-color: rgb(255, 255, 255); ">else if (old_sleep && new_state == PM_SUSPEND_ON) {  
    state &= ~SUSPEND_REQUESTED;  
    wake_lock(&main_wake_lock); //acquire    main ——wakelock  
    queue_work(suspend_work_queue, &late_resume_work); //将唤醒的work起来,开始执行之前声明的late_resume_work  

}</span>  
requested_suspend_state = new_state;  
spin_unlock_irqrestore(&state_lock, irqflags);  

}
而 之前有声明static DECLARE_WORK(late_resume_work, late_resume); 故实际执行的函数是:late_resume。

kernel/kernel/power/erlysuspend.c late_resume
[cpp] view plain copy
static void late_resume(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 == SUSPENDED)  
    state &= ~SUSPENDED;  
else  
    abort = 1;  
spin_unlock_irqrestore(&state_lock, irqflags);  

if (abort) {  
    if (debug_mask & DEBUG_SUSPEND)  
        pr_info("late_resume: abort, state %d\n", state);  
    goto abort;  
}  

if (debug_mask & DEBUG_SUSPEND)  
    pr_info("late_resume: call handlers\n");  
list_for_each_entry_reverse(pos, &early_suspend_handlers, link)  
    if (pos->resume != NULL) {  
        print_name_offset(NULL, pos->resume);  
        pos->resume(pos);       //此处会调用到之前注册了laterresume的drv的对应的函数,调用到fb_resume之后,屏幕就唤醒刷屏,屏幕上夜就有了数据,屏幕唤醒的流程就结束了。  
    }  
if (debug_mask & DEBUG_SUSPEND)  
    pr_info("late_resume: done\n");  

abort:
mutex_unlock(&early_suspend_lock);
}

总结: 屏幕点亮过程是由inputread捕获后交由WM处理,由keyguard去申请唤醒锁,powermanagerservice去调用kernel的唤醒的过程,其中弯弯绕还是比较多的,涉及的东西也很多,wakelock机制我还没有搞的很清楚。

二、 屏幕睡眠

和屏幕唤醒的过程很类似,如下:

inputReader.cpp KeyboardInputMapper::processKey

                                                                   getDispatcher()->notifyKey

 inputDispacher.cpp                            InputDispatcher::notifyKey

                                                               mPolicy->interceptKeyBeforeQueueing

com_android_server_inputManager.cpp                NativeInputManager::interceptKeyBeforeQueueing

InputManager.java interceptKeyBeforeQueueing

                                                                              mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing

WindowmanagerService.java InputMonitor::interceptKeyBeforeQueueing

                                                                              mPolicy.interceptKeyBeforeQueueing

PhonewindowManager.java interceptKeyBeforeQueueing

                                                                                 //同上面的分析,此处返回的action是被或上了ACTION_GO_TO_SLEEP的(见1975行对KeyEvent.KEYCODE_POWER的处理).......一级一级的返回后.....

com_android_server_inputManager.cpp NativeInputManager::interceptKeyBeforeQueueing //返回值中含有gotosleep的flag,故走到gotosleep分支

                                                                                                      android_server_PowerManagerService_goToSleep

com_android_server_PowerManagerService.cpp android_server_PowerManagerService_goToSleep //同上面的inputmanager,此处也会调用到PowerManagerService的gotosleep,也是用register_android_server_PowerManagerService方法来对应起来。

                                                                                                      env->CallVoidMethod(gPowerManagerServiceObj, gPowerManagerServiceClassInfo.goToSleep,
            nanoseconds_to_milliseconds(eventTime));

PowermanagerService.java goToSleep

                                                                                                    goToSleepWithReason

goToSleepLocked

                                         setPowerState(SCREEN_OFF, false, reason);

                                                                                                    setPowerState

                                                                                                    setScreenStateLocked

                                                                                                      Power.setScreenState(false)

power.java setScreenState

android_os_power.java setScreenState

power.c set_screen_state

kernel/kernel/power/main.c state_store

kernel/kernel/power/earlysuspend.c request_suspend_state //此处流程和唤醒大同小异,不在赘述

                                                                                                          early_suspend

[cpp] view plain copy
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 |= SUSPENDED;  
else  
    abort = 1;  
spin_unlock_irqrestore(&state_lock, irqflags);  

if (abort) {  
    if (debug_mask & DEBUG_SUSPEND)  
        pr_info("early_suspend: abort, state %d\n", state);  
    mutex_unlock(&early_suspend_lock);  
    goto abort;  
}  

if (debug_mask & DEBUG_SUSPEND)  
    pr_info("early_suspend: call handlers\n");  
list_for_each_entry(pos, &early_suspend_handlers, link) {  
    if (pos->suspend != NULL) {  
        print_name_offset(NULL, pos->suspend);  
        <span style="background-color: rgb(204, 204, 204);">pos->suspend(pos); //调用注册了earlysuspend的drv的suspend函数,调用到了fb_suspend,屏幕就会进入睡眠,睡眠的过程就结束了</span>  
    }  

}  
mutex_unlock(&early_suspend_lock);  

if (debug_mask & DEBUG_SUSPEND)  
    pr_info("early_suspend: sync\n");  

//sys_sync();//let screen up faster   

abort:
spin_lock_irqsave(&state_lock, irqflags);
if (state == SUSPEND_REQUESTED_AND_SUSPENDED)
wake_unlock(&main_wake_lock); //earlysuspend完毕后,检查当前是否还有wakelock是active状态,如果没有,则会进入深睡眠(linux的suspend)
spin_unlock_irqrestore(&state_lock, irqflags);
}

下面我们继续跟下代码,简单看看earlysuspend到deepsleep的过程,从wake_unlock开始
kernel/kernel/power/wakelock.c wake_unlock

[cpp] view plain copy
void wake_unlock(struct wake_lock *lock)
{
int type;
unsigned long irqflags;
spin_lock_irqsave(&list_lock, irqflags);
type = lock->flags & WAKE_LOCK_TYPE_MASK;
#ifdef CONFIG_WAKELOCK_STAT
wake_unlock_stat_locked(lock, 0);
#endif
if (debug_mask & DEBUG_WAKE_LOCK)
pr_info(“wake_unlock: %s\n”, lock->name);
lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
list_del(&lock->link);
list_add(&lock->link, &inactive_locks);
if (type == WAKE_LOCK_SUSPEND) {
long has_lock = has_wake_lock_locked(type); //判断当前是否还有wake_lock是active的
if (has_lock > 0) {
if (debug_mask & DEBUG_EXPIRE)

            pr_info("wake_unlock: %s, start expire timer, "  
                "%ld\n", lock->name, has_lock);  
        mod_timer(&expire_timer, jiffies + has_lock);  
    } else {  
        if (del_timer(&expire_timer))  
            if (debug_mask & DEBUG_EXPIRE)  
                pr_info("wake_unlock: %s, stop expire "  
                    "timer\n", lock->name);  
        if (has_lock == 0) {  
            if (sprd_suspend_enable) {    
                queue_work(suspend_work_queue, &suspend_work); //起suspend_work,根据声明,此处的work对应的函数即是suspend  
            }  

        }  
    }  
    if (lock == &main_wake_lock) {  
        if (debug_mask & DEBUG_SUSPEND)  
            print_active_locks(WAKE_LOCK_SUSPEND);  

#ifdef CONFIG_WAKELOCK_STAT
update_sleep_wait_stats_locked(0);
#endif
}
}
spin_unlock_irqrestore(&list_lock, irqflags);
}

kernel/kernel/power/wakelock.c suspend
[cpp] view plain copy
static void suspend(struct work_struct *work)
{
int ret;
int entry_event_num;

add_pm_message(get_sys_cnt(), "suspend--enter: ", 0, 0, 0);  

if (has_wake_lock(WAKE_LOCK_SUSPEND)) {  
    if (debug_mask & DEBUG_SUSPEND)  
        pr_info("suspend: abort suspend\n");  
    return;  
}  

entry_event_num = current_event_num;  
sys_sync();  
if (debug_mask & DEBUG_SUSPEND)  
    pr_info("suspend: enter suspend\n");  
ret = pm_suspend(requested_suspend_state);  
if (debug_mask & DEBUG_EXIT_SUSPEND) {  

    struct timespec ts;  
    struct rtc_time tm;  
    getnstimeofday(&ts);  
    rtc_time_to_tm(ts.tv_sec, &tm);  
    pr_info("suspend: exit suspend, ret = %d "  
        "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,  
        tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,  
        tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);  
}  

if (current_event_num == entry_event_num) {  
    if (debug_mask & DEBUG_SUSPEND)  
        pr_info("suspend: pm_suspend returned with no event\n");  
    wake_lock_timeout(&unknown_wakeup, HZ / 2);  
}  
add_pm_message(get_sys_cnt(), "suspend--leave: ", 0, 0, 0);  

}

kernel/kernel/power/suspend.c pm_suspend
[cpp] view plain copy
int pm_suspend(suspend_state_t state)
{
if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)
return enter_state(state); //是不是和main.c里的state_store函数中liunx的suspend一样?豁然开朗。
return -EINVAL;
}

接下来就是linux的suspend了,没有再仔细看过,惭愧惭愧。

总的来说,屏幕的睡眠是和上层的keyguard没有关系,是在WM和PMS以及相关的JNI的配合下对kernel的操作完成的。

屏幕唤醒和睡眠就写到这里,而背光的点亮过程,大部分处理是在PMS中,是在HAL层操作了lights的设备文件并不涉及到唤醒和睡眠,显得比较简单,有时间也写出来分享

. 屏幕的唤醒

  首先inputread在读取到有keyboard事件上报后,会调用到keydispatch的notifykey,去询问wm是否会对这次按键特殊处理,如果WM不处理,则此处会点亮或者熄灭屏幕。

 inputReader.cpp                                 KeyboardInputMapper::processKey

                                                                   getDispatcher()->notifyKey

 inputDispacher.cpp                            InputDispatcher::notifyKey

                                                                  mPolicy->interceptKeyBeforeQueueing

com_android_server_inputManager.cpp                NativeInputManager::interceptKeyBeforeQueueing

                                                                                         env->CallIntMethod(mCallbacksObj,
                                                                                        gCallbacksClassInfo.interceptKeyBeforeQueueing,
                                                                                         when, action, flags, keyCode, scanCode, policyFlags, isScreenOn);             //此处gCallbacksClassInfo中的各种方法就是InputManager的对应的方法,在JNI初始化的时候就注册了,详情请参看register_android_server_InputManager函数,通过jniRegisterNativeMethods将inputmanager的各种callback注册到gCallbacksClassInfo中。

返回的wmaction就是后面WM对此次按键事件的policy,通过此返回值,此处会决定下一步的动作。

InputManager.java interceptKeyBeforeQueueing

                                                                              mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing

WindowmanagerService.java InputMonitor::interceptKeyBeforeQueueing

                                                                              mPolicy.interceptKeyBeforeQueueing

PhonewindowManager.java interceptKeyBeforeQueueing

                                                                              //摘录部分代码:

[java] view plain copy
public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
final boolean down = action == KeyEvent.ACTION_DOWN;
final boolean canceled = (flags & KeyEvent.FLAG_CANCELED) != 0;

    final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;  

    // If screen is off then we treat the case where the keyguard is open but hidden  
    // the same as if it were open and in front.  
    // This will prevent any keys other than the power button from waking the screen  
    // when the keyguard is hidden by another activity.  

    final boolean keyguardActive = (isScreenOn ?  
                                    mKeyguardMediator.isShowingAndNotHidden() :  
                                    mKeyguardMediator.isShowing());  

    int result; //result即为返回到wmaction  
    if (isScreenOn || isInjected) {  
        // When the screen is on or if the key is injected pass the key to the application.  
        result = ACTION_PASS_TO_USER;  
    } else {//我们现在走的应该是这个  
        // When the screen is off and the key is not injected, determine whether  
        // to wake the device but don't pass the key to the application.  
        result = 0;  

        final boolean isWakeKey = (policyFlags  
                & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;  
        if (down && isWakeKey) {  
            if (keyguardActive) {  

[java] view plain copy
//也就是说,如果当前屏幕是灭的,且按的键是可以唤醒屏幕的,那么WM会首先将此次按键传递给keyguard,由keyguard来唤醒屏幕,并作出相应的动作,否则就自己点亮屏幕,通过返回的policy来通知下层。

                // If the keyguard is showing, let it decide what to do with the wake key.  
              <span style="color:#ff0000;"> </span> mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);  
            } else {  
                // Otherwise, wake the device ourselves.  

                result |= ACTION_POKE_USER_ACTIVITY;  
            }  
        }  
    }<span style="font-weight: bold; ">  


}
keyguarViewMediator.java onWakeKeyWhenKeyguardShowingTq
wakeWhenReadyLocked

                                                                                       mHandler.obtainMessage(WAKE_WHEN_READY, keyCode, 0);

                                                                         mHandler.handleMessage

                                                                       handleWakeWhenReady

                                                                       mKeyguardViewManager.wakeWhenReadyTq

    KeyguardViewManager.java                mKeyguardView.wakeWhenReadyTq

    LockpatternKeyguardView.java            wakeWhenReadyTq

                                                                         getCallback().pokeWakelock();

    KeyguardViewMediator.java                  pokeWakelock

                                                                        mWakeLock.acquire();        // mWakeLock即为:mWakeLock = mPM.newWakeLock(
            PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
            "keyguard");      具有ACQUIRE_CAUSE_WAKUPQ权限的唤醒锁,上层就是通过此锁来唤醒屏幕,接下来就是powermanager的流程了。

    PowerManager.java                              acquire

                                                                       mService.acquireWakeLock

     PowermanagerService.java                acquireWakeLock

                                                                        acquireWakeLockLocked//此处会检查唤醒锁的标志位,作出对应的处理。

                                                                         setPowerState       //此函数为powermanager的核心函数之一,会对屏幕背光/唤醒,睡眠等作出相应的处理

                                                                       setScreenStateLocked //此函数很关键

                                                                       Power.setScreenState

    power.java                                                setScreenState

   android_os_Power.cpp                          setScreenState

    power.c                                                      set_screen_state//此函数作为上层的最后一个函数,会打印出标志性的log,*** set_screen_state %d,如果打出这个log,至少证明从APP-HAL都是在正常干活的,那么问题只能是kernel的了,贴出代码看看:

[cpp] view plain copy
int
set_screen_state(int on)
{
//QEMU_FALLBACK(set_screen_state(on));

LOGI("*** set_screen_state %d", on); //神奇的log标志  

initialize_fds();  

//LOGI("go_to_sleep eventTime=%lld now=%lld g_error=%s\n", eventTime,  
  //      systemTime(), strerror(g_error));  

if (g_error) return g_error;  

char buf[32];  
int len;  

if(on)  
    len = sprintf(buf, "%s", on_state);  
else  
    len = sprintf(buf, "%s", off_state);  

len = write(g_fds[REQUEST_STATE], buf, len);//此处就是写了kernel的设备文件接口。
if(len < 0) {
LOGE(“Failed setting last user activity: g_error=%d\n”, g_error);
}
return 0;
}
在此函数中写了底层的power控制的设备文件接口,对应的设备文件为:/sys/power/state
接下来的流程就是到了内核空间。

kernel/kernel/power/main.c state_store

//此函数被宏power_attr(state)声明为设备文件接口 sys/power/state,宏power_attr的定义为(power.h):

                                                                                                                   #define power_attr(_name) \

static struct kobj_attribute _name##_attr = {
.attr = {
.name = __stringify(_name),
.mode = 0644,
},
.show = _name##_show,
.store = _name##_store,
}

[cpp] view plain copy
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
#ifdef CONFIG_SUSPEND
#ifdef CONFIG_EARLYSUSPEND
suspend_state_t state = PM_SUSPEND_ON;
#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();  

goto Exit;
}

#ifdef CONFIG_SUSPEND
for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
break;

}  
printk("##: enter %s\n", pm_states[state]);  
if (state < PM_SUSPEND_MAX && *s)  

#ifdef CONFIG_EARLYSUSPEND // android对linux的睡眠唤醒机制做了一些优化,也就是earlysuspen,laterresume机制,此处宏是有定义的,所以会先走android的那一套
if (state == PM_SUSPEND_ON || valid_state(state)) {
error = 0;
printk(“##: entering request_suspend_state()…\n”);
request_suspend_state(state);
}
#else

    error = enter_state(state);  

#endif
#endif

Exit:
printk(“##: state_store() returns back.\n”);
return error ? error : n;
}

kernel/kernel/power/erlysuspend.c request_suspend_state

[cpp] view plain copy
void request_suspend_state(suspend_state_t new_state)
{
unsigned long irqflags;
int old_sleep;

/* when we get here, means userspace service work well, stop reboot watchdog */  
powerkey_wdt_stop();  

spin_lock_irqsave(&state_lock, irqflags);  
old_sleep = state & SUSPEND_REQUESTED;  
if (debug_mask & DEBUG_USER_STATE) {  
    struct timespec ts;  
    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);  

}  
if (!old_sleep && new_state != PM_SUSPEND_ON) {  
    state |= SUSPEND_REQUESTED;  
    queue_work(suspend_work_queue, &early_suspend_work);  
}<span style="color: rgb(255, 0, 0); background-color: rgb(255, 255, 255);"> </span><span style="background-color: rgb(255, 255, 255); ">else if (old_sleep && new_state == PM_SUSPEND_ON) {  
    state &= ~SUSPEND_REQUESTED;  
    wake_lock(&main_wake_lock); //acquire    main ——wakelock  
    queue_work(suspend_work_queue, &late_resume_work); //将唤醒的work起来,开始执行之前声明的late_resume_work  

}</span>  
requested_suspend_state = new_state;  
spin_unlock_irqrestore(&state_lock, irqflags);  

}
而 之前有声明static DECLARE_WORK(late_resume_work, late_resume); 故实际执行的函数是:late_resume。

kernel/kernel/power/erlysuspend.c late_resume
[cpp] view plain copy
static void late_resume(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 == SUSPENDED)  
    state &= ~SUSPENDED;  
else  
    abort = 1;  
spin_unlock_irqrestore(&state_lock, irqflags);  

if (abort) {  
    if (debug_mask & DEBUG_SUSPEND)  
        pr_info("late_resume: abort, state %d\n", state);  
    goto abort;  
}  

if (debug_mask & DEBUG_SUSPEND)  
    pr_info("late_resume: call handlers\n");  
list_for_each_entry_reverse(pos, &early_suspend_handlers, link)  
    if (pos->resume != NULL) {  
        print_name_offset(NULL, pos->resume);  
        pos->resume(pos);       //此处会调用到之前注册了laterresume的drv的对应的函数,调用到fb_resume之后,屏幕就唤醒刷屏,屏幕上夜就有了数据,屏幕唤醒的流程就结束了。  
    }  
if (debug_mask & DEBUG_SUSPEND)  
    pr_info("late_resume: done\n");  

abort:
mutex_unlock(&early_suspend_lock);
}

总结: 屏幕点亮过程是由inputread捕获后交由WM处理,由keyguard去申请唤醒锁,powermanagerservice去调用kernel的唤醒的过程,其中弯弯绕还是比较多的,涉及的东西也很多,wakelock机制我还没有搞的很清楚。

二、 屏幕睡眠

和屏幕唤醒的过程很类似,如下:

inputReader.cpp KeyboardInputMapper::processKey

                                                                   getDispatcher()->notifyKey

 inputDispacher.cpp                            InputDispatcher::notifyKey

                                                               mPolicy->interceptKeyBeforeQueueing

com_android_server_inputManager.cpp                NativeInputManager::interceptKeyBeforeQueueing

InputManager.java interceptKeyBeforeQueueing

                                                                              mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing

WindowmanagerService.java InputMonitor::interceptKeyBeforeQueueing

                                                                              mPolicy.interceptKeyBeforeQueueing

PhonewindowManager.java interceptKeyBeforeQueueing

                                                                                 //同上面的分析,此处返回的action是被或上了ACTION_GO_TO_SLEEP的(见1975行对KeyEvent.KEYCODE_POWER的处理).......一级一级的返回后.....

com_android_server_inputManager.cpp NativeInputManager::interceptKeyBeforeQueueing //返回值中含有gotosleep的flag,故走到gotosleep分支

                                                                                                      android_server_PowerManagerService_goToSleep

com_android_server_PowerManagerService.cpp android_server_PowerManagerService_goToSleep //同上面的inputmanager,此处也会调用到PowerManagerService的gotosleep,也是用register_android_server_PowerManagerService方法来对应起来。

                                                                                                      env->CallVoidMethod(gPowerManagerServiceObj, gPowerManagerServiceClassInfo.goToSleep,
            nanoseconds_to_milliseconds(eventTime));

PowermanagerService.java goToSleep

                                                                                                    goToSleepWithReason

goToSleepLocked

                                         setPowerState(SCREEN_OFF, false, reason);

                                                                                                    setPowerState

                                                                                                    setScreenStateLocked

                                                                                                      Power.setScreenState(false)

power.java setScreenState

android_os_power.java setScreenState

power.c set_screen_state

kernel/kernel/power/main.c state_store

kernel/kernel/power/earlysuspend.c request_suspend_state //此处流程和唤醒大同小异,不在赘述

                                                                                                          early_suspend

[cpp] view plain copy
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 |= SUSPENDED;  
else  
    abort = 1;  
spin_unlock_irqrestore(&state_lock, irqflags);  

if (abort) {  
    if (debug_mask & DEBUG_SUSPEND)  
        pr_info("early_suspend: abort, state %d\n", state);  
    mutex_unlock(&early_suspend_lock);  
    goto abort;  
}  

if (debug_mask & DEBUG_SUSPEND)  
    pr_info("early_suspend: call handlers\n");  
list_for_each_entry(pos, &early_suspend_handlers, link) {  
    if (pos->suspend != NULL) {  
        print_name_offset(NULL, pos->suspend);  
        <span style="background-color: rgb(204, 204, 204);">pos->suspend(pos); //调用注册了earlysuspend的drv的suspend函数,调用到了fb_suspend,屏幕就会进入睡眠,睡眠的过程就结束了</span>  
    }  

}  
mutex_unlock(&early_suspend_lock);  

if (debug_mask & DEBUG_SUSPEND)  
    pr_info("early_suspend: sync\n");  

//sys_sync();//let screen up faster   

abort:
spin_lock_irqsave(&state_lock, irqflags);
if (state == SUSPEND_REQUESTED_AND_SUSPENDED)
wake_unlock(&main_wake_lock); //earlysuspend完毕后,检查当前是否还有wakelock是active状态,如果没有,则会进入深睡眠(linux的suspend)
spin_unlock_irqrestore(&state_lock, irqflags);
}

下面我们继续跟下代码,简单看看earlysuspend到deepsleep的过程,从wake_unlock开始
kernel/kernel/power/wakelock.c wake_unlock

[cpp] view plain copy
void wake_unlock(struct wake_lock *lock)
{
int type;
unsigned long irqflags;
spin_lock_irqsave(&list_lock, irqflags);
type = lock->flags & WAKE_LOCK_TYPE_MASK;
#ifdef CONFIG_WAKELOCK_STAT
wake_unlock_stat_locked(lock, 0);
#endif
if (debug_mask & DEBUG_WAKE_LOCK)
pr_info(“wake_unlock: %s\n”, lock->name);
lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
list_del(&lock->link);
list_add(&lock->link, &inactive_locks);
if (type == WAKE_LOCK_SUSPEND) {
long has_lock = has_wake_lock_locked(type); //判断当前是否还有wake_lock是active的
if (has_lock > 0) {
if (debug_mask & DEBUG_EXPIRE)

            pr_info("wake_unlock: %s, start expire timer, "  
                "%ld\n", lock->name, has_lock);  
        mod_timer(&expire_timer, jiffies + has_lock);  
    } else {  
        if (del_timer(&expire_timer))  
            if (debug_mask & DEBUG_EXPIRE)  
                pr_info("wake_unlock: %s, stop expire "  
                    "timer\n", lock->name);  
        if (has_lock == 0) {  
            if (sprd_suspend_enable) {    
                queue_work(suspend_work_queue, &suspend_work); //起suspend_work,根据声明,此处的work对应的函数即是suspend  
            }  

        }  
    }  
    if (lock == &main_wake_lock) {  
        if (debug_mask & DEBUG_SUSPEND)  
            print_active_locks(WAKE_LOCK_SUSPEND);  

#ifdef CONFIG_WAKELOCK_STAT
update_sleep_wait_stats_locked(0);
#endif
}
}
spin_unlock_irqrestore(&list_lock, irqflags);
}

kernel/kernel/power/wakelock.c suspend
[cpp] view plain copy
static void suspend(struct work_struct *work)
{
int ret;
int entry_event_num;

add_pm_message(get_sys_cnt(), "suspend--enter: ", 0, 0, 0);  

if (has_wake_lock(WAKE_LOCK_SUSPEND)) {  
    if (debug_mask & DEBUG_SUSPEND)  
        pr_info("suspend: abort suspend\n");  
    return;  
}  

entry_event_num = current_event_num;  
sys_sync();  
if (debug_mask & DEBUG_SUSPEND)  
    pr_info("suspend: enter suspend\n");  
ret = pm_suspend(requested_suspend_state);  
if (debug_mask & DEBUG_EXIT_SUSPEND) {  

    struct timespec ts;  
    struct rtc_time tm;  
    getnstimeofday(&ts);  
    rtc_time_to_tm(ts.tv_sec, &tm);  
    pr_info("suspend: exit suspend, ret = %d "  
        "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,  
        tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,  
        tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);  
}  

if (current_event_num == entry_event_num) {  
    if (debug_mask & DEBUG_SUSPEND)  
        pr_info("suspend: pm_suspend returned with no event\n");  
    wake_lock_timeout(&unknown_wakeup, HZ / 2);  
}  
add_pm_message(get_sys_cnt(), "suspend--leave: ", 0, 0, 0);  

}

kernel/kernel/power/suspend.c pm_suspend
[cpp] view plain copy
int pm_suspend(suspend_state_t state)
{
if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)
return enter_state(state); //是不是和main.c里的state_store函数中liunx的suspend一样?豁然开朗。
return -EINVAL;
}

接下来就是linux的suspend了,没有再仔细看过,惭愧惭愧。

总的来说,屏幕的睡眠是和上层的keyguard没有关系,是在WM和PMS以及相关的JNI的配合下对kernel的操作完成的。

屏幕唤醒和睡眠就写到这里,而背光的点亮过程,大部分处理是在PMS中,是在HAL层操作了lights的设备文件并不涉及到唤醒和睡眠,显得比较简单,有时间也写出来分享

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值