Android按键消息传播流程
主要涉及的文件有:
WindowManagerService.java frameworks\base\services\java\com\android\server\
PhoneWindow.java frameworks\policies\base\phone\com\android\internal\policy\impl
KeyInputQueue.java frameworks\base\services\java\com\android\server
com_android_server_KeyInputQueue.cpp frameworks\base\services\jni
EventHub.cpp frameworks\base\libs\ui
WindowManagerService.java主要有两个线程,一个负责分发按键的InputDisapath Thread,另一个负责从底层读取按键消息InputDeviceRender Thread。
WindowManagerService.java的成员类KeyQ(),负责获取各种按键设备的状态,它继承于KeyInputQueue类。通过线程InputDeviceRender Thread的readEvent对按键消息不停读取,然后调用KeyQ实例化后的processEvent函数告诉该按键是否应该传给上层。接着WindowManagerService通过InputDisPatch Thread在按键消息队列里取出,并进行分发。
由此可知,InputDisapath线程负责分发,InputDeviceRender线程通过jni方式调用android_server_KeyInputQueue_readEvent(),在这里负责转化C++的按键消息为java的格式,android_server_KeyInputQueue_readEvent在EventHub.cpp中获取按键消息。
具体一些细节代码如下:
WindowManagerService中的KeyQ()类,preporcessEvent函数负责对按键进行预处理, 主要的事件类型包括EV_KEY(按键事件)、EV_REL(相对值,如鼠标移动,报告相对于最后一次位置的偏移)和EV_ABS(绝对值,如触摸屏)。
-
@Override
-
boolean preprocessEvent(InputDevice device, RawInputEvent event) {
-
if (mPolicy.preprocessInputEventTq(event)) {
-
return true;
-
}
-
-
switch (event.type) {
-
case RawInputEvent.EV_KEY: {
-
-
if (DEBUG) {
-
if (event.keycode == KeyEvent.KEYCODE_G) {
-
if (event.value != 0) {
-
-
mPolicy.screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
-
}
-
return false;
-
}
-
if (event.keycode == KeyEvent.KEYCODE_D) {
-
if (event.value != 0) {
-
-
}
-
return false;
-
}
-
}
-
-
-
boolean screenIsOff = !mPowerManager.isScreenOn();
-
boolean screenIsDim = !mPowerManager.isScreenBright();
-
int actions = mPolicy.interceptKeyTq(event, !screenIsOff);/
-
-
if ((actions & WindowManagerPolicy.ACTION_GO_TO_SLEEP) != 0) {
-
mPowerManager.goToSleep(event.when);
-
}
-
-
if (screenIsOff) {
-
event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
-
}
-
if (screenIsDim) {
-
event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
-
}
-
if ((actions & WindowManagerPolicy.ACTION_POKE_USER_ACTIVITY) != 0) {
-
mPowerManager.userActivity(event.when, false,
-
LocalPowerManager.BUTTON_EVENT, false);
-
}
-
-
if ((actions & WindowManagerPolicy.ACTION_PASS_TO_USER) != 0) {
-
if (event.value != 0 && mPolicy.isAppSwitchKeyTqTiLwLi(event.keycode)) {
-
filterQueue(this);
-
mKeyWaiter.appSwitchComing();
-
}
-
return true;
-
} else {
-
return false;
-
}
-
}
-
-
case RawInputEvent.EV_REL: {
-
boolean screenIsOff = !mPowerManager.isScreenOn();
-
boolean screenIsDim = !mPowerManager.isScreenBright();
-
if (screenIsOff) {
-
if (!mPolicy.isWakeRelMovementTq(event.deviceId,
-
device.classes, event)) {
-
-
return false;
-
}
-
event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
-
}
-
if (screenIsDim) {
-
event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
-
}
-
return true;
-
}
-
-
case RawInputEvent.EV_ABS: {
-
boolean screenIsOff = !mPowerManager.isScreenOn();
-
boolean screenIsDim = !mPowerManager.isScreenBright();
-
if (screenIsOff) {
-
if (!mPolicy.isWakeAbsMovementTq(event.deviceId,
-
device.classes, event)) {
-
-
return false;
-
}
-
event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
-
}
-
if (screenIsDim) {
-
event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
-
}
-
return true;
-
}
-
-
default:
-
return true;
-
}
-
}
preporcessEvent调用了InterceptKeyTQ
PhoneWindowManager.java中的InterceptKeyTQ判断该按键是否应该送给上层,还是在此层进行截取,如待机休眠唤醒则在此层进行截取。
-
-
public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) {
-
int result = ACTION_PASS_TO_USER;
-
final boolean isWakeKey = isWakeKeyTq(event);
-
-
-
-
-
final boolean keyguardActive = (screenIsOn ?
-
mKeyguardMediator.isShowingAndNotHidden() :
-
mKeyguardMediator.isShowing());
-
-
-
if (false) {
-
Log.d(TAG, "interceptKeyTq event=" + event + " keycode=" + event.keycode
-
+ " screenIsOn=" + screenIsOn + " keyguardActive=" + keyguardActive);
-
}
-
-
-
if (keyguardActive) {
-
if (screenIsOn) {
-
-
result |= ACTION_PASS_TO_USER;
-
} else {
-
-
result &= ~ACTION_PASS_TO_USER;
-
-
-
final boolean isKeyDown =
-
(event.type == RawInputEvent.EV_KEY) && (event.value != 0);
-
if (isWakeKey && isKeyDown) {
-
-
-
-
-
-
if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(event.keycode)
-
&& (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN
-
|| event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {
-
-
-
if (isInCall()) {
-
handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);
-
} else if (isMusicActive()) {
-
handleVolumeKey(AudioManager.STREAM_MUSIC, event.keycode);
-
}
-
}
-
}
-
}
-
} else if (!screenIsOn) {
-
-
-
-
-
if (isInCall() && event.type == RawInputEvent.EV_KEY &&
-
(event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN
-
|| event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {
-
result &= ~ACTION_PASS_TO_USER;
-
handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);
-
}
-
if (isWakeKey) {
-
-
-
result |= ACTION_POKE_USER_ACTIVITY;
-
result &= ~ACTION_PASS_TO_USER;
-
}
-
}
-
-
-
int type = event.type;
-
int code = event.keycode;
-
boolean down = event.value != 0;
-
-
-
if (type == RawInputEvent.EV_KEY) {
-
if (code == KeyEvent.KEYCODE_ENDCALL
-
|| code == KeyEvent.KEYCODE_POWER) {
-
if (down) {
-
boolean handled = false;
-
boolean hungUp = false;
-
-
-
-
ITelephony phoneServ = getPhoneInterface();
-
if (phoneServ != null) {
-
try {
-
if (code == KeyEvent.KEYCODE_ENDCALL) {
-
handled = hungUp = phoneServ.endCall();
-
} else if (code == KeyEvent.KEYCODE_POWER) {
-
if (phoneServ.isRinging()) {
-
-
-
phoneServ.silenceRinger();
-
handled = true;
-
} else if (phoneServ.isOffhook() &&
-
((mIncallPowerBehavior
-
& Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP)
-
!= 0)) {
-
-
-
handled = hungUp = phoneServ.endCall();
-
}
-
}
-
} catch (RemoteException ex) {
-
Log.w(TAG, "ITelephony threw RemoteException" + ex);
-
}
-
} else {
-
Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
-
}
-
-
-
if (!screenIsOn
-
|| (handled && code != KeyEvent.KEYCODE_POWER)
-
|| (handled && hungUp && code == KeyEvent.KEYCODE_POWER)) {
-
mShouldTurnOffOnKeyUp = false;
-
} else {
-
-
mShouldTurnOffOnKeyUp = true;
-
mHandler.postDelayed(mPowerLongPress,
-
ViewConfiguration.getGlobalActionKeyTimeout());
-
result &= ~ACTION_PASS_TO_USER;
-
}
-
} else {
-
mHandler.removeCallbacks(mPowerLongPress);
-
if (mShouldTurnOffOnKeyUp) {
-
mShouldTurnOffOnKeyUp = false;
-
boolean gohome, sleeps;
-
if (code == KeyEvent.KEYCODE_ENDCALL) {
-
gohome = (mEndcallBehavior
-
& Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0;
-
sleeps = (mEndcallBehavior
-
& Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0;
-
} else {
-
gohome = false;
-
sleeps = true;
-
}
-
if (keyguardActive
-
|| (sleeps && !gohome)
-
|| (gohome && !goHome() && sleeps)) {
-
-
-
Log.d(TAG, "I'm tired mEndcallBehavior=0x"
-
+ Integer.toHexString(mEndcallBehavior));
-
result &= ~ACTION_POKE_USER_ACTIVITY;
-
result |= ACTION_GO_TO_SLEEP;
-
}
-
result &= ~ACTION_PASS_TO_USER;
-
}
-
}
-
} else if (isMediaKey(code)) {
-
-
-
-
if ((result & ACTION_PASS_TO_USER) == 0) {
-
-
-
-
KeyEvent keyEvent = new KeyEvent(event.when, event.when,
-
down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
-
code, 0);
-
mBroadcastWakeLock.acquire();
-
mHandler.post(new PassHeadsetKey(keyEvent));
-
}
-
} else if (code == KeyEvent.KEYCODE_CALL) {
-
-
-
-
-
-
-
-
-
if (down) {
-
try {
-
ITelephony phoneServ = getPhoneInterface();
-
if (phoneServ != null) {
-
if (phoneServ.isRinging()) {
-
Log.i(TAG, "interceptKeyTq:"
-
+ " CALL key-down while ringing: Answer the call!");
-
phoneServ.answerRingingCall();
-
-
-
-
-
result &= ~ACTION_PASS_TO_USER;
-
}
-
} else {
-
Log.w(TAG, "CALL button: Unable to find ITelephony interface");
-
}
-
} catch (RemoteException ex) {
-
Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);
-
}
-
}
-
} else if ((code == KeyEvent.KEYCODE_VOLUME_UP)
-
|| (code == KeyEvent.KEYCODE_VOLUME_DOWN)) {
-
-
-
-
-
-
-
-
-
if (down) {
-
try {
-
ITelephony phoneServ = getPhoneInterface();
-
if (phoneServ != null) {
-
if (phoneServ.isRinging()) {
-
Log.i(TAG, "interceptKeyTq:"
-
+ " VOLUME key-down while ringing: Silence ringer!");
-
-
-
phoneServ.silenceRinger();
-
-
-
-
-
result &= ~ACTION_PASS_TO_USER;
-
}
-
} else {
-
Log.w(TAG, "VOLUME button: Unable to find ITelephony interface");
-
}
-
} catch (RemoteException ex) {
-
Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex);
-
}
-
}
-
}
-
}
-
-
-
return result;
-
}
WindowManagerService中的InputDispatcherThread线程process,在里头调用mQueue(KeyQ类)的getEvent函数来获取队列中的消息,处理后分发。
-
private void process() {
-
android.os.Process.setThreadPriority(
-
android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
-
-
-
KeyEvent lastKey = null;
-
-
-
long lastKeyTime = SystemClock.uptimeMillis();
-
long nextKeyTime = lastKeyTime+LONG_WAIT;
-
long downTime = 0;
-
-
-
int keyRepeatCount = 0;
-
-
-
boolean configChanged = false;
-
-
while (true) {
-
long curTime = SystemClock.uptimeMillis();
-
-
if (DEBUG_INPUT) Slog.v(
-
TAG, "Waiting for next key: now=" + curTime
-
+ ", repeat @ " + nextKeyTime);
-
-
-
-
-
-
QueuedEvent ev = mQueue.getEvent(
-
(int)((!configChanged && curTime < nextKeyTime)
-
? (nextKeyTime-curTime) : 0));
-
-
if (DEBUG_INPUT && ev != null) Slog.v(
-
TAG, "Event: type=" + ev.classType + " data=" + ev.event);
-
-
if (MEASURE_LATENCY) {
-
lt.sample("2 got event ", System.nanoTime() - ev.whenNano);
-
}
-
-
if (lastKey != null && !mPolicy.allowKeyRepeat()) {
-
-
lastKey = null;
-
downTime = 0;
-
lastKeyTime = curTime;
-
nextKeyTime = curTime + LONG_WAIT;
-
}
-
try {
-
if (ev != null) {
-
curTime = SystemClock.uptimeMillis();
-
int eventType;
-
if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {
-
eventType = eventType((MotionEvent)ev.event);
-
} else if (ev.classType == RawInputEvent.CLASS_KEYBOARD ||
-
ev.classType == RawInputEvent.CLASS_TRACKBALL) {
-
eventType = LocalPowerManager.BUTTON_EVENT;
-
} else {
-
eventType = LocalPowerManager.OTHER_EVENT;
-
}
-
try {
-
if ((curTime - mLastBatteryStatsCallTime)
-
>= MIN_TIME_BETWEEN_USERACTIVITIES) {
-
mLastBatteryStatsCallTime = curTime;
-
mBatteryStats.noteInputEvent();
-
}
-
} catch (RemoteException e) {
-
-
}
-
-
if (ev.classType == RawInputEvent.CLASS_CONFIGURATION_CHANGED) {
-
-
} else if (eventType != TOUCH_EVENT
-
&& eventType != LONG_TOUCH_EVENT
-
&& eventType != CHEEK_EVENT) {
-
mPowerManager.userActivity(curTime, false,
-
eventType, false);
-
} else if (mLastTouchEventType != eventType
-
|| (curTime - mLastUserActivityCallTime)
-
>= MIN_TIME_BETWEEN_USERACTIVITIES) {
-
mLastUserActivityCallTime = curTime;
-
mLastTouchEventType = eventType;
-
mPowerManager.userActivity(curTime, false,
-
eventType, false);
-
}
-
-
switch (ev.classType) {
-
case RawInputEvent.CLASS_KEYBOARD:
-
KeyEvent ke = (KeyEvent)ev.event;
-
if (ke.isDown()) {
-
lastKey = ke;
-
downTime = curTime;
-
keyRepeatCount = 0;
-
lastKeyTime = curTime;
-
nextKeyTime = lastKeyTime
-
+ ViewConfiguration.getLongPressTimeout();
-
if (DEBUG_INPUT) Slog.v(
-
TAG, "Received key down: first repeat @ "
-
+ nextKeyTime);
-
} else {
-
lastKey = null;
-
downTime = 0;
-
-
lastKeyTime = curTime;
-
nextKeyTime = curTime + LONG_WAIT;
-
if (DEBUG_INPUT) Slog.v(
-
TAG, "Received key up: ignore repeat @ "
-
+ nextKeyTime);
-
}
-
dispatchKey((KeyEvent)ev.event, 0, 0);
-
mQueue.recycleEvent(ev);
-
break;
-
case RawInputEvent.CLASS_TOUCHSCREEN:
-
-
dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
-
break;
-
case RawInputEvent.CLASS_TRACKBALL:
-
dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);
-
break;
-
case RawInputEvent.CLASS_CONFIGURATION_CHANGED:
-
configChanged = true;
-
break;
-
default:
-
mQueue.recycleEvent(ev);
-
break;
-
}
-
-
} else if (configChanged) {
-
configChanged = false;
-
sendNewConfiguration();
-
-
} else if (lastKey != null) {
-
curTime = SystemClock.uptimeMillis();
-
-
-
-
if (DEBUG_INPUT) Slog.v(
-
TAG, "Key timeout: repeat=" + nextKeyTime
-
+ ", now=" + curTime);
-
if (curTime < nextKeyTime) {
-
continue;
-
}
-
-
lastKeyTime = nextKeyTime;
-
nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY;
-
keyRepeatCount++;
-
if (DEBUG_INPUT) Slog.v(
-
TAG, "Key repeat: count=" + keyRepeatCount
-
+ ", next @ " + nextKeyTime);
-
KeyEvent newEvent;
-
if (downTime != 0 && (downTime
-
+ ViewConfiguration.getLongPressTimeout())
-
<= curTime) {
-
newEvent = KeyEvent.changeTimeRepeat(lastKey,
-
curTime, keyRepeatCount,
-
lastKey.getFlags() | KeyEvent.FLAG_LONG_PRESS);
-
downTime = 0;
-
} else {
-
newEvent = KeyEvent.changeTimeRepeat(lastKey,
-
curTime, keyRepeatCount);
-
}
-
dispatchKey(newEvent, 0, 0);
-
-
} else {
-
curTime = SystemClock.uptimeMillis();
-
-
lastKeyTime = curTime;
-
nextKeyTime = curTime + LONG_WAIT;
-
}
-
-
} catch (Exception e) {
-
Slog.e(TAG,
-
"Input thread received uncaught exception: " + e, e);
-
}
-
}
-
}
-
}