粘贴如下:

一. 屏幕的唤醒

首先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

//摘录部分代码:

publicintinterceptKeyBeforeQueueing(longwhenNanos,intaction,intflags,

intkeyCode,intscanCode,intpolicyFlags,booleanisScreenOn) {

finalbooleandown = action == KeyEvent.ACTION_DOWN;

finalbooleancanceled = (flags & KeyEvent.FLAG_CANCELED) !=0;

finalbooleanisInjected = (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.

finalbooleankeyguardActive = (isScreenOn ?

mKeyguardMediator.isShowingAndNotHidden() :

mKeyguardMediator.isShowing());

intresult;//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;

finalbooleanisWakeKey = (policyFlags

& (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;

if(down && isWakeKey) {

if(keyguardActive) {

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

// If the keyguard is showing, let it decide what to do with the wake key.

mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);

} else{

// Otherwise, wake the device ourselves.

result |= ACTION_POKE_USER_ACTIVITY;

}

}

}

....................

}

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的了,贴出代码看看:

int

set_screen_state(inton)

{

//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)returng_error;

charbuf[32];

intlen;

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

LOGE("Failed setting last user activity: g_error=%d\n", g_error);

}

return0;

}

在此函数中写了底层的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,\

}

staticssize_t state_store(structkobject *kobj,structkobj_attribute *attr,

constchar*buf,size_tn)

{

#ifdef CONFIG_SUSPEND

#ifdef CONFIG_EARLYSUSPEND

suspend_state_t state = PM_SUSPEND_ON;

#else

suspend_state_t state = PM_SUSPEND_STANDBY;

#endif

constchar*const*s;

#endif

char*p;

intlen;

interror = -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();

gotoExit;

}

#ifdef CONFIG_SUSPEND

for(s = &pm_states[state]; state

if(*s && len == strlen(*s) && !strncmp(buf, *s, len))

break;

}

printk("##: enter %s\n", pm_states[state]);

if(state

#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");

returnerror ? error : n;

}

kernel/kernel/power/erlysuspend.c                                                              request_suspend_state

voidrequest_suspend_state(suspend_state_t new_state)

{

unsigned longirqflags;

intold_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) {

structtimespec ts;

structrtc_timetm;

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);

} elseif(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

}

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

staticvoidlate_resume(structwork_struct *work)

{

structearly_suspend *pos;

unsigned longirqflags;

intabort = 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);

gotoabort;

}

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

staticvoidearly_suspend(structwork_struct *work)

{

structearly_suspend *pos;

unsigned longirqflags;

intabort = 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);

gotoabort;

}

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);

pos->suspend(pos);//调用注册了earlysuspend的drv的suspend函数,调用到了fb_suspend,屏幕就会进入睡眠,睡眠的过程就结束了

}

}

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

voidwake_unlock(structwake_lock *lock)

{

inttype;

unsigned longirqflags;

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) {

longhas_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

staticvoidsuspend(structwork_struct *work)

{

intret;

intentry_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) {

structtimespec ts;

structrtc_timetm;

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

intpm_suspend(suspend_state_t state)

{

if(state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)

returnenter_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

//摘录部分代码:

publicintinterceptKeyBeforeQueueing(longwhenNanos,intaction,intflags,

intkeyCode,intscanCode,intpolicyFlags,booleanisScreenOn) {

finalbooleandown = action == KeyEvent.ACTION_DOWN;

finalbooleancanceled = (flags & KeyEvent.FLAG_CANCELED) !=0;

finalbooleanisInjected = (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.

finalbooleankeyguardActive = (isScreenOn ?

mKeyguardMediator.isShowingAndNotHidden() :

mKeyguardMediator.isShowing());

intresult;//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;

finalbooleanisWakeKey = (policyFlags

& (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;

if(down && isWakeKey) {

if(keyguardActive) {

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

// If the keyguard is showing, let it decide what to do with the wake key.

mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);

} else{

// Otherwise, wake the device ourselves.

result |= ACTION_POKE_USER_ACTIVITY;

}

}

}

....................

}

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的了,贴出代码看看:

int

set_screen_state(inton)

{

//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)returng_error;

charbuf[32];

intlen;

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

LOGE("Failed setting last user activity: g_error=%d\n", g_error);

}

return0;

}

在此函数中写了底层的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,\

}

staticssize_t state_store(structkobject *kobj,structkobj_attribute *attr,

constchar*buf,size_tn)

{

#ifdef CONFIG_SUSPEND

#ifdef CONFIG_EARLYSUSPEND

suspend_state_t state = PM_SUSPEND_ON;

#else

suspend_state_t state = PM_SUSPEND_STANDBY;

#endif

constchar*const*s;

#endif

char*p;

intlen;

interror = -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();

gotoExit;

}

#ifdef CONFIG_SUSPEND

for(s = &pm_states[state]; state

if(*s && len == strlen(*s) && !strncmp(buf, *s, len))

break;

}

printk("##: enter %s\n", pm_states[state]);

if(state

#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");

returnerror ? error : n;

}

kernel/kernel/power/erlysuspend.c                                                              request_suspend_state

voidrequest_suspend_state(suspend_state_t new_state)

{

unsigned longirqflags;

intold_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) {

structtimespec ts;

structrtc_timetm;

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);

} elseif(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

}

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

staticvoidlate_resume(structwork_struct *work)

{

structearly_suspend *pos;

unsigned longirqflags;

intabort = 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);

gotoabort;

}

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

staticvoidearly_suspend(structwork_struct *work)

{

structearly_suspend *pos;

unsigned longirqflags;

intabort = 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);

gotoabort;

}

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);

pos->suspend(pos);//调用注册了earlysuspend的drv的suspend函数,调用到了fb_suspend,屏幕就会进入睡眠,睡眠的过程就结束了

}

}

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

voidwake_unlock(structwake_lock *lock)

{

inttype;

unsigned longirqflags;

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) {

longhas_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

staticvoidsuspend(structwork_struct *work)

{

intret;

intentry_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) {

structtimespec ts;

structrtc_timetm;

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

intpm_suspend(suspend_state_t state)

{

if(state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)

returnenter_state(state);//是不是和main.c里的state_store函数中liunx的suspend一样?豁然开朗。

return-EINVAL;

}

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

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

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

linux 点亮屏幕,按电源键屏幕唤醒和屏幕睡眠流程(从上层到kernel)相关推荐

  1. 音量键唤醒屏幕--解决电源键坏掉的情况

    键盘布局映射文件通常放在/system/usr/keylayout下 文件格式: 键映射文件通常以UTF8文本文件格式存储于设备,通常有如下特性: 注释:用#表示,以#开头的内容都将被忽略. 空白:所 ...

  2. 小米6 双击亮屏 NO是三击亮屏 解放电源键

    小米6 双击亮屏 NO是三击亮屏 解放电源键 我们不生产代码,我们知识代码的搬运工,如有侵权,本人将第一时间删除 邮箱:zhf6751134@163.com QQ交流群:336237986

  3. 手机电源键关不了屏幕_手机死机关不了机怎么办

    手机死机关不了机怎么办 在我们平时使用手机的过程中,难免会遇到死机的情况.为什么会死机卡住呢? 这时因为有的软件与系统的兼容性不好,或是系统的运行不稳定导致的.一旦死机卡住了的话,不管我们怎么点击屏幕 ...

  4. 电脑锁屏按什么键解锁_手机屏幕密码忘了怎么解锁

    现在基本智能手机居多,无论什么牌子都可以设置屏幕密码,但是现在什么都要密码,导致密码太多,一时记不住,下面为大家介绍手机屏幕密码忘了怎么解锁. 手机屏幕密码忘了怎么解锁 步骤1.在关机状态下同时按住[ ...

  5. windows8怎么关机_按下电源键后发生了什么?电脑是如何关机的?

    在Windows启动后,最自然的关机方式是什么呢?当然是按下电源键了.有没有好奇,当我们按下电源键,会发生什么呢?为什么Windows可以选择关机或者睡眠?背后的机理又是什么呢? 历史 如果你曾经使用 ...

  6. 红米k40怎样取消电源键唤醒小爱

    红米k40一般都可以利用电源键来唤醒语音助手小爱.但很多用户不喜欢这个功能该怎么关闭呢?不要着急快来看看换换带来的详细教程吧.相信一定对你有所帮助! 红米k40关闭电源键唤醒小爱方法分享 1.在手机设 ...

  7. android屏幕唤醒函数,android学习笔记 按电源键屏幕唤醒和屏幕睡眠流程(从上层到kernel)...

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

  8. Android 按电源键亮屏/息屏流程分析

    上一篇介绍了Android 电源键事件流程分析,其中分析了,在按电源键,长按的时候,弹出系统菜单,以及点击其中的关机按键,都执行了哪些操作.这一篇,作为上一篇的补充,主要分析一下,Android按键亮 ...

  9. 针对xps13无法开机,按下电源键亮几秒无反应的问题

    背景:2018.3.24晚我初学git后,关机睡觉.第二天,起来第一件事就是打开电脑继续我的学习.这个时候,TM的电脑出问题了,怎么都无法开机.我慌了,长按1分钟,30秒......都快要把电源键按烂 ...

最新文章

  1. 【Qt】QAudioDeviceInfo获取不到音频设备
  2. 这一行代码,很有温度!
  3. python中字符串格式化%与.format
  4. OpenSSL生成自签名的sha256泛域名证书
  5. antd form rules字数限制_【React】antd的form表单的自定义校验规则的用法
  6. 在Word XP中也能插入国际音标、拼音
  7. 2021“MINIEYE杯”中国大学生算法设计超级联赛(1)zoto(二维数颜色)
  8. c语言二叉树的构造输出,C语言数据结构树状输出二叉树,谁能给详细的解释一下...
  9. 租房新体验:AI机器人中介带你看房
  10. 6个面的骰子 标上1 2 3 4 5 6 投掷8次 求出现和的概率最大的数 ,就是这8次的和最有可能是多少...
  11. python3 协程_Python3 异步神器-协程(Coroutine)
  12. 怎样使用U盘启动盘安装乌班图系统
  13. 树莓派获取SHT20温湿度
  14. 拓嘉辰丰电商:拼多多店铺如何成功拼单
  15. Day 10 - Anticipation | RIPS 2017 PHP代码安全审计挑战(RIPSTECH PRESENTS PHP SECURITY CALENDAR)/ Writeup
  16. 2017-2018-2 《密码与安全新技术》第一周作业
  17. 【Java语言】项目实践:汽车租赁系统(源码)(面向对象方法)
  18. 海康、大华、华为等GB28181国标平台向上级联给LiveGBS GB28181平台的操作示例
  19. 洛谷 P1796 汤姆斯的天堂梦_NOI导刊2010提高(05)
  20. 大学英语b和计算机三级,大学英语三级

热门文章

  1. 中国作家维权联盟向苹果和百度发出律师函
  2. OGC服务标准(地图资料篇.3)
  3. 百慕大将于下周宣布推出加密货币友好银行
  4. NASA WIND卫星观测数据作图——origin
  5. IDC服务商开启行业自律新篇章
  6. css轮播箭头怎么隐藏,CSS——轮播图中的箭头
  7. 《摄氏华氏温度转换》
  8. Python网络编程及WebServer
  9. Lambda 表达式(一)-码住
  10. [案例3-2]银行存取款程序设计