一. 屏幕的唤醒
首先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
//摘录部分代码:
-
"font-weight: bold; "> 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;
-
-
-
-
-
-
-
final boolean keyguardActive = (isScreenOn ?
-
mKeyguardMediator.isShowingAndNotHidden() :
-
mKeyguardMediator.isShowing());
-
-
int result;
-
if (isScreenOn || isInjected) {
-
-
result = ACTION_PASS_TO_USER;
-
} else {
-
-
-
result = 0;
-
-
final boolean isWakeKey = (policyFlags
-
& (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
-
if (down && isWakeKey) {
-
if (keyguardActive) {
-
-
-
-
"color:#ff0000;"> mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);
-
} else {
-
-
-
result |= ACTION_POKE_USER_ACTIVITY;
-
}
-
}
-
}"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的了,贴出代码看看:
-
int
-
set_screen_state(int on)
-
{
-
-
-
LOGI("*** set_screen_state %d", on);
-
-
initialize_fds();
-
-
-
-
-
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);
-
"color:#cc0000;"> len = write(g_fds[REQUEST_STATE], buf, len);
-
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, \
}
-
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;
-
-
-
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
-
void request_suspend_state(suspend_state_t new_state)
-
{
-
unsigned long irqflags;
-
int old_sleep;
-
-
-
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);
-
}"color: rgb(255, 0, 0); background-color: rgb(255, 255, 255);"> "background-color: rgb(255, 255, 255); ">else if (old_sleep && new_state == PM_SUSPEND_ON) {
-
state &= ~SUSPEND_REQUESTED;
-
wake_lock(&main_wake_lock);
-
queue_work(suspend_work_queue, &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
-
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);
-
}
-
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
-
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);
-
"background-color: rgb(204, 204, 204);">pos->suspend(pos);
-
}
-
-
}
-
mutex_unlock(&early_suspend_lock);
-
-
if (debug_mask & DEBUG_SUSPEND)
-
pr_info("early_suspend: sync\n");
-
-
-
abort:
-
spin_lock_irqsave(&state_lock, irqflags);
-
if (state == SUSPEND_REQUESTED_AND_SUSPENDED)
-
wake_unlock(&main_wake_lock);
-
spin_unlock_irqrestore(&state_lock, irqflags);
-
}
下面我们继续跟下代码,简单看看earlysuspend到deepsleep的过程,从wake_unlock开始
kernel/kernel/power/wakelock.c wake_unlock
-
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);
-
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);
-
}
-
-
}
-
}
-
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
-
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
-
int pm_suspend(suspend_state_t state)
-
{
-
if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)
-
return enter_state(state);
-
return -EINVAL;
-
}
接下来就是linux的suspend了,没有再仔细看过,惭愧惭愧。
总的来说,屏幕的睡眠是和上层的keyguard没有关系,是在WM和PMS以及相关的JNI的配合下对kernel的操作完成的。
屏幕唤醒和睡眠就写到这里,而背光的点亮过程,大部分处理是在PMS中,是在HAL层操作了lights的设备文件并不涉及到唤醒和睡眠,显得比较简单,有时间也写出来分享。