系列文章目录
可跳转到下面链接查看下表所有内容https://blog.csdn.net/handsomethefirst/article/details/138226266?spm=1001.2014.3001.5501文章浏览阅读2次。系列文章大全https://blog.csdn.net/handsomethefirst/article/details/138226266?spm=1001.2014.3001.5501
目录
系列文章目录
1.简介
1.1 APP程序是如何接受普通按键事件?
1.1.1 App端代码案例
1.1.2 测试结果演示
2.流程分析
2.1 主要步骤
2.2 时序图
2.3 源码分析
2.3.1 Looper::addFd
2.3.2 pollInner
2.3.3 NativeInputEventReceiver::handleEvent
2.3.4 NativeInputEventReceiver::consumeEvents
2.3.5 InputConsumer::consume
2.3.6 dispatchInputEvent
2.3.7 onInputEvent
2.3.8 enqueueInputEvent
2.3.9 doProcessInputEvents
2.3.10 deliverInputEvent
2.3.11 InputStage
2.3.12 InputStage.deliver
2.3.13 InputStage.apply
2.3.14 NativePreImeInputStage.onProcess
2.3.15 ViewPreImeInputStage.onProcess
2.3.16 ImeInputStage.onProcess
2.3.17 EarlyPostImeInputStage.onProcess
2.3.18 NativePostImeInputStage.onProcess
2.3.19 ViewPostImeInputStage.onProcess
2.3.20 ViewPostImeInputStage.processKeyEvent
2.4 View分发流程源码分析
2.4.1 DecorView.dispatchKeyEvent
2.4.1.1 情况一:当前应用存在焦点窗口时处理流程分析
2.4.1.1.1 Activity.dispatchKeyEvent
2.4.1.1.2 PhoneWindow.superDispatchTouchEvent
2.4.1.1.3.DecorView.superDispatchTouchEvent
2.4.1.1.4 ViewGroup.dispatchKeyEvent
2.4.1.1.5 View.dispatchKeyEvent
2.4.1.1.6 ViewRootImpl.finish
2.4.1.4.7 deliver
2.4.1.4.8 ViewRootImpl.finishInputEvent
2.4.1.4.9 InputEventReceiver.finishInputEvent
2.4.1.4.10 nativeFinishInputEvent
2.4.1.4.11 finishInputEvent
2.4.1.4.12 sendFinishedSignal
2.4.1.4.13 sendUnchainedFinishedSignal
2.4.1.4.14 InputChannel::sendMessage
2.4.1.4.15 InputDispatcher::handleReceiveCallback
2.4.1.4.16 InputPublisher::receiveFinishedSignal
2.4.1.4.17 InputChannel::receiveMessage
2.4.1.4.18 finishDispatchCycleLocked
2.4.1.4.19 runCommandsLockedInterruptible
2.4.1.4.20 doDispatchCycleFinishedLockedInterruptible
2.4.1.2 情况二:当前应用没有焦点窗口,但存在Activity兜底处理的流程分析
2.4.1.2.1 Activity.dispatchKeyEvent
2.4.1.2.2 keyEvent.dispatch
2.4.1.3 情况三:当前无应用,音量加减交给PhoneWindow处理流程分析
2.4.1.3.1 PhoneWindow.onKeyDown
1.简介
通过前文我们知道了IMS会通过已经注册好的socket发送按键事件到应用程序端,那么本篇便来讲解一下应用程序端的流程。
1.1 APP程序是如何接受普通按键事件?
主要步骤:
1.控件(如activity,View)实现View.OnKeyListener接口,并实现其方法onKey
2.控件调用其setOnKeyListener方法,传入监听按键响应的listener
3.按下按键,此时onKey方法会执行。
1.1.1 App端代码案例
public class MainActivity extends AppCompatActivity implements View.OnKeyListener {
//MainActivity实现View.OnKeyListener
Button mActivitytest;
EditText mEditText;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initview();
}
//如果目标 View 没有消费掉此次事件(即返回值为 false)则会调用 Activity 的 onKeyDown或者onKeyup来处理。
public boolean onKeyDown(int keyCode, KeyEvent event) {
int keycode = event.getKeyCode();
mEditText.setText("onKeyDown按键监听到了key ="+keycode+ "按键按下");
return true;
}
public boolean onKeyUp(int keyCode, KeyEvent event)
{
int keycode = event.getKeyCode();
mEditText.setText("onKeyUp按键监听到了key ="+keycode+ "按键抬起");
return true;
}
protected void initview()
{
mEditText = (EditText) findViewById(R.id.onkeytest);
mEditText.setOnKeyListener(this);
}
@Override
//应用程序消费按键事件的地方
public boolean onKey(View view, int i, KeyEvent keyEvent) {
int keycode = keyEvent.getKeyCode();
int action = keyEvent.getAction();
if(action == 0)
{
mEditText.setText("onKey按键监听到了key ="+keycode+ "按键按下");
}else if(action == 1)
{
mEditText.setText("onKey按键监听到了key ="+keycode+ "按键抬起");
}
return true;
}
}
布局代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:id="@+id/onkeytest"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="50dp"/>
<Button
android:id="@+id/Activitytest"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="开始测试"
android:layout_weight="1"
android:textSize="50dp"/>
</LinearLayout>
</LinearLayout>
1.1.2 测试结果演示
1.当我们只打开应用(重写了Activity的onKeyDown和onKeyup函数),而不点击EditText的区域时候,即EditText此时不是焦点,当按下音量减少按键,结果如下。即此时走的是Activity的兜底的onKeyDown和onKeyup函数。
2.当我们只打开应用,然后点击EditText的区域时候,即EditText此时是焦点,当按下音量减少按键,结果如下。即此时走的是EditText的onKey函数。
3.当我们不打开应用或者不重写Activity的onKeyDown和onKeyup函数时,按下音量减少按键。如图:
2.流程分析
2.1 主要步骤
第一步:当IMS通过socket发送按键事件后,应用端的NativeInputEventReceiver::handleEvent会被调用。
第二步:然后应用端从socket下读取按键事件,然后应用端会调用WindowInputEventReceiver(ViewRootImpl 的内部类)重写的 onInputEvent 方法,此方法就是 java 层事件分发的起点。
第三步:应用端会通过InputStage责任链的方式,将按键事件进行派发,最终会派发到ViewPostImeInputStage.processKeyEvent,这个便是View派发的起点。
第四步:如果有焦点窗口,则View会派发按键事件到焦点窗口的onkey函数,如果无焦点窗口,但重写了Activity的onKeyDown和onKeyup函数,则会交给Activity的onKeyDown和onKeyup函数处理,如果当前无Activity或者不重写Activity的onKeyDown和onKeyup函数时,按下音量减少按键,此时会交给meida服务去减少音量。
第五步:当第四步无论是那种情况,处理完成后都会调用调用InputEventReceiver的finishInputEvent函数通过socket向IMS服务发送此按键事件已经完成处理的消息。此时IMS服务侧的handleReceiveCallback回调函数会被执行。
第六步:IMS服务侧的handleReceiveCallback回调函数执行中会从IMS服务端的socket下读取应用端发送的消息,然后将处理完成的事件从等待队列中删除。
2.2 时序图
(可保存到本地放大观看)
2.3 源码分析
在【android 9】【input】【8.发送按键事件2——InputDispatcher线程】篇中,我们知道当发送普通按键时,IMS最终会通过socket将按键消息发送给应用端,而在【android 9】【input】【9.发送按键事件3——Inputchannel的创建过程】篇中,我们知道应用端会监听来自IMS的消息。
2.3.1 Looper::addFd
上文中我们知道此函数的主要作用为调用epoll_ctl监听此应用的socket,即监听来自IMS的输入事件。
int Looper::addFd(int fd, int ident, int events,
const sp<LooperCallback>& callback, void* data) {
{
if (!callback.get()) {
if (! mAllowNonCallbacks) {
ALOGE("Invalid attempt to set NULL callback but not allowed for this looper.");
return -1;
}
if (ident < 0) {
ALOGE("Invalid attempt to set NULL callback with ident < 0.");
return -1;
}
} else {
ident = POLL_CALLBACK;
}
AutoMutex _l(mLock);
Request request;
request.fd = fd;
request.ident = ident;
request.events = events;
request.seq = mNextRequestSeq++;
request.callback = callback; // 是指 NativeInputEventReceiver
request.data = data;
if (mNextRequestSeq == -1) mNextRequestSeq = 0;
struct epoll_event eventItem;
request.initEventItem(&eventItem);
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex < 0) {
// 通过 epoll 监听 fd
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
......
mRequests.add(fd, request); // 该fd 的 request 加入到 mRequests 队列
} else {
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
......
mRequests.replaceValueAt(requestIndex, request);
}
}
return 1;
}
2.3.2 pollInner
Looper机制中线程循环调用pollInner函数。(后续本人会分析一篇关于Looper的机制)
int Looper::pollInner(int timeoutMillis)
{
int result = POLL_WAKE;
mResponses.clear();
mResponseIndex = 0;
mPolling = true;
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);//当无消息的时候,会阻塞在此处
//处理所有消息
for (int i = 0; i < eventCount; i++)
{
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if (fd == mWakeEventFd.get())
{
}
else
{
ssize_t requestIndex = mRequests.indexOfKey(fd);//此时mRequests不为空,因为在监听的时候添加了socket的fd和对应的回调对象,
//此时根据socket中的fd找到对应的回调对象。
if (requestIndex >= 0)
{
int events = 0;
if (epollEvents & EPOLLIN)
events |= EVENT_INPUT;
if (epollEvents & EPOLLOUT)
events |= EVENT_OUTPUT;
if (epollEvents & EPOLLERR)
events |= EVENT_ERROR;
if (epollEvents & EPOLLHUP)
events |= EVENT_HANGUP;
pushResponse(events, mRequests.valueAt(requestIndex));//往mResponses塞入了事件
}
}
}
Done:;
// Invoke all response callbacks.
for (size_t i = 0; i < mResponses.size(); i++)
{
Response &response = mResponses.editItemAt(i);
if (response.request.ident == POLL_CALLBACK)//在addFd中ident就是POLL_CALLBACK
{
int fd = response.request.fd;
int events = response.events;
void *data = response.request.data;
int callbackResult = response.request.callback->handleEvent(fd, events, data);//执行回调函数
if (callbackResult == 0)
{
removeFd(fd, response.request.seq);
}
response.request.callback.clear();
result = POLL_CALLBACK;
}
}
return result;
}
void Looper::pushResponse(int events, const Request& request) {
Response response;
response.events = events;
response.request = request;
mResponses.push(response);
}
2.3.3 NativeInputEventReceiver::handleEvent
从上面我们知道,当应用端监听的socket下有输入事件时,此函数会被调用。
主要作用是:
1.应用端调用consumeEvents消费事件数据。
此函数的ALOOPER_EVENT_INPUT代表socket可读,即应用程序要开始分发来自IMS的输入事件。
ALOOPER_EVENT_OUTPUT代表socket可写,即应用程序向IMS发送完成输入事件的处理的消息。
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
if (events & ALOOPER_EVENT_INPUT) {//socket可读
JNIEnv* env = AndroidRuntime::getJNIEnv();
status_t status = consumeEvents(env, false, -1, NULL);
mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");//调用handleReceiveCallback告诉ims此消息已经被成功消费了。
return status == OK || status == NO_MEMORY ? 1 : 0;
}
/**
if (events & ALOOPER_EVENT_OUTPUT) {//socket可写
for (size_t i = 0; i < mFinishQueue.size(); i++) {
const Finish& finish = mFinishQueue.itemAt(i);
status_t status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled);
if (status) {
mFinishQueue.removeItemsAt(0, i);
if (status == WOULD_BLOCK) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Sent %zu queued finish events; %zu left.",
getInputChannelName().c_str(), i, mFinishQueue.size());
}
return 1; // keep the callback, try again later
}
ALOGW("Failed to send finished signal on channel '%s'. status=%d",
getInputChannelName().c_str(), status);
if (status != DEAD_OBJECT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
String8 message;
message.appendFormat("Failed to finish input event. status=%d", status);
jniThrowRuntimeException(env, message.string());
mMessageQueue->raiseAndClearException(env, "finishInputEvent");
}
return 0; // remove the callback
}
}
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Sent %zu queued finish events; none left.",
getInputChannelName().c_str(), mFinishQueue.size());
}
mFinishQueue.clear();
setFdEvents(ALOOPER_EVENT_INPUT);
return 1;
}
*/
return 1;
}
2.3.4 NativeInputEventReceiver::consumeEvents
此函数的主要作用是:
1.mInputConsumer的consume()函数从Inputchannel中读取一条InputMessage
2.将c++的inputEvent生成java的事件类型。
3.通过jni调用java层的dispatchInputEvent函数开始分发。
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
//consumeBatches是 false
//outConsumedBatch是空
ScopedLocalRef<jobject> receiverObj(env, NULL);
bool skipCallbacks = false;
for (;;) {
uint32_t seq;
InputEvent* inputEvent;
int32_t displayId;
//通边mInputConsumer的consume()函数从Inputchannel中读取一条InputMessage。
//解析为InputEvent后,通过inputEvent参数传出*/
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent, &displayId);
assert(inputEvent);
if (!skipCallbacks) {
/**
if (!receiverObj.get()) {
receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal));
if (!receiverObj.get()) {
ALOGW("channel '%s' ~ Receiver object was finalized "
"without being disposed.", getInputChannelName().c_str());
return DEAD_OBJECT;
}
}
*/
jobject inputEventObj;
switch (inputEvent->getType()) {
case AINPUT_EVENT_TYPE_KEY:
inputEventObj = android_view_KeyEvent_fromNative(env,
static_cast<KeyEvent*>(inputEvent));//将c++的inputEvent生成java的事件类型
break;
default:
assert(false); // InputConsumer should prevent this from ever happening
inputEventObj = NULL;
}
if (inputEventObj) {//通过jni调用dispatchInputEvent函数开始分发inputEventObj
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj,
displayId);
if (env->ExceptionCheck()) {
ALOGE("Exception dispatching input event.");
skipCallbacks = true;
}
env->DeleteLocalRef(inputEventObj);
} else {
ALOGW("channel '%s' ~ Failed to obtain event object.",getInputChannelName().c_str());
skipCallbacks = true;
}
}
if (skipCallbacks) {//如果发送异常,则直接发送完成信号
mInputConsumer.sendFinishedSignal(seq, false);
}
}
}
2.3.5 InputConsumer::consume
主要作用是:
1.从socket中读取数据并转化为InputMessage结构体的格式。
status_t InputConsumer::consume(InputEventFactoryInterface* factory,
bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent,
int32_t* displayId) {
*outSeq = 0;
*outEvent = NULL;
*displayId = -1; // Invalid display.
// //获取下一条输入消息。
//循环,直到可以返回事件或没有接收到其他事件为止。
while (!*outEvent) {
/**
if (mMsgDeferred) {//默认false不执行
//mMsg包含上一次调用中尚未处理的有效输入消息。
mMsgDeferred = false;
}*/
else {
// 从inputchannel中接收一个数据
status_t result = mChannel->receiveMessage(&mMsg);
/**
if (result) {//ok是0
// Consume the next batched event unless batches are being held for later.
if (consumeBatches || result != WOULD_BLOCK) {
result = consumeBatch(factory, frameTime, outSeq, outEvent, displayId);
if (*outEvent) {
break;
}
}
return result;
}
*/
}
switch (mMsg.header.type) {
case InputMessage::TYPE_KEY: {
KeyEvent* keyEvent = factory->createKeyEvent();//创建了一个java层的KeyEvent对象
if (!keyEvent) return NO_MEMORY;
initializeKeyEvent(keyEvent, &mMsg);//将InputMessage保存的消息,保存到keyEvent中
*outSeq = mMsg.body.key.seq;
*outEvent = keyEvent;//赋值为keyEvent,则while循环不为空,会退出
break;
}
default:
return UNKNOWN_ERROR;
}
}
return OK;
}
status_t InputChannel::receiveMessage(InputMessage* msg) {
ssize_t nRead;
do {
nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);
//从socket对应的mFd取出数据,存储在msg中
} while (nRead == -1 && errno == EINTR);
if (nRead < 0) {//代表读取错误
int error = errno;
#if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.c_str(), errno);
#endif
if (error == EAGAIN || error == EWOULDBLOCK) {
return WOULD_BLOCK;
}
if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED) {
return DEAD_OBJECT;
}
return -error;
}
if (nRead == 0) { // check for EOF
#if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.c_str());
#endif
return DEAD_OBJECT;
}
if (!msg->isValid(nRead)) {
#if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ received invalid message", mName.c_str());
#endif
return BAD_VALUE;
}
#if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ received message of type %d", mName.c_str(), msg->header.type);
#endif
return OK;
}
void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) {
event->initialize(
msg->body.key.deviceId,
msg->body.key.source,
msg->body.key.action,
msg->body.key.flags,
msg->body.key.keyCode,
msg->body.key.scanCode,
msg->body.key.metaState,
msg->body.key.repeatCount,
msg->body.key.downTime,
msg->body.key.eventTime);
}
void KeyEvent::initialize(
int32_t deviceId,
int32_t source,
int32_t action,
int32_t flags,
int32_t keyCode,
int32_t scanCode,
int32_t metaState,
int32_t repeatCount,
nsecs_t downTime,
nsecs_t eventTime) {
InputEvent::initialize(deviceId, source);
mAction = action;
mFlags = flags;
mKeyCode = keyCode;
mScanCode = scanCode;
mMetaState = metaState;
mRepeatCount = repeatCount;
mDownTime = downTime;
mEventTime = eventTime;
}
void InputEvent::initialize(int32_t deviceId, int32_t source) {
mDeviceId = deviceId;
mSource = source;
}
2.3.6 dispatchInputEvent
主要作用为:
1.调用其子类 WindowInputEventReceiver(ViewRootImpl 的内部类)重写的 onInputEvent 方法,此方法就是 java 层事件分发的起点。
//InputEventReceiver.java
private void dispatchInputEvent(int seq, InputEvent event, int displayId) {
mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event, displayId);
}
2.3.7 onInputEvent
//接着调用其子类 WindowInputEventReceiver(ViewRootImpl 的内部类)重写的 onInputEvent 方法,此方法就是 java 层事件分发的起点。
//ViewRootImpl.java
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}
@Override
public void onInputEvent(InputEvent event, int displayId) {
enqueueInputEvent(event, this, 0, true);
}
}
2.3.8 enqueueInputEvent
主要作用为:
1.调用doProcessInputEvents进行事件的分发。
void enqueueInputEvent(InputEvent event,InputEventReceiver receiver, int flags, boolean processImmediately) {
adjustInputEventForCompatibility(event);
QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
//始终按顺序对输入事件进行排队,而不管其时间戳如何。
QueuedInputEvent last = mPendingInputEventTail;// mPendingInputEventTail 代表 QueuedInputEvent 链表尾节点
if (last == null) {//如果是首次进入,头尾节点都指向第一个构造的 QueuedInputEvent
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {//否则将事件放入队尾
last.mNext = q;
mPendingInputEventTail = q;
}
mPendingInputEventCount += 1;
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);//追踪QueuedInputEvent的长度
if (processImmediately) {
doProcessInputEvents();//处理输入事件
} else {
scheduleProcessInputEvents();
}
}
private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,InputEventReceiver receiver, int flags) {
QueuedInputEvent q = mQueuedInputEventPool;
if (q != null) {
mQueuedInputEventPoolSize -= 1;
mQueuedInputEventPool = q.mNext;
q.mNext = null;
} else {
q = new QueuedInputEvent();
}
q.mEvent = event;
q.mReceiver = receiver;
q.mFlags = flags;
return q;
}
2.3.9 doProcessInputEvents
void doProcessInputEvents() {
// 头节点不为空,代表链表中有事件处理
while (mPendingInputEventHead != null) {
//按顺序取出
QueuedInputEvent q = mPendingInputEventHead;
//头节点后移
mPendingInputEventHead = q.mNext;
if (mPendingInputEventHead == null) {
mPendingInputEventTail = null;
}
q.mNext = null;//将取出来的 QueuedInputEvent 的 mNext 置空
mPendingInputEventCount -= 1;//QueuedInputEvent 链表数量减一
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);
long eventTime = q.mEvent.getEventTimeNano();//此事件发生的时间
long oldestEventTime = eventTime;
if (q.mEvent instanceof MotionEvent) {//如果是触摸事件
MotionEvent me = (MotionEvent)q.mEvent;//转化为motion事件
if (me.getHistorySize() > 0) {
oldestEventTime = me.getHistoricalEventTimeNano(0);
}
}
mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);//更新时间
deliverInputEvent(q);//事件分发
}
//我们现在已经处理完所有可以处理的输入事件,因此可以立即清除挂起的标志。
if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}
2.3.10 deliverInputEvent
主要作用为:
1.调用InputStage的deliver分发事件。
下面我们需要先介绍一下InputStage类。
private void deliverInputEvent(QueuedInputEvent q) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",q.mEvent.getSequenceNumber());
mStartCheckTime = SystemClock.elapsedRealtime();
if (mInputEventConsistencyVerifier != null) {//用于调试信息的
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}
InputStage stage;
if (q.shouldSendToSynthesizer()) {//此时是false
stage = mSyntheticInputStage;
} else {
//shouldSkipIme 代表事件是否传递给输入法,对于按键事件,
//仅仅在主动设置了 FLAG_DELIVER_POST_IME 时返回 true,
//触摸事件则是判断其事件来源,一般情况的触摸事件都是返回 true
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;//此时是按键事件所以,nativePreImeStage值是nativePreImeStage
}
if (q.mEvent instanceof KeyEvent) {
mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
}
if (stage != null) {
handleWindowFocusChanged();//焦点窗口如果发生变化,则调整焦点窗口,如果没发生变化。则return
stage.deliver(q);//分发事件
} else {
finishInputEvent(q);
}
}
2.3.11 InputStage
首先InputStage是一个抽象的父类,此处采用的是职责链设计模式,每一个InputStage的实现类中都含有一个next变量,用于指向下一个InputStage的实现类,就像链表一样。责任链模式是一种行为型设计模式,它允许你构建一个对象链,让请求从链的一端进入,然后依次沿着链传递处理,直到链上的某个对象能够处理该请求。职责链上的每一个处理者都是一个对象,其内部会包含mNext指向下一个对象,这个对象可以对请求进行处理也可以将请求发送给下一个对象去处理。
类图如下:
那么InputStage是什么时候被初始化的呢?
是在setView函数里面会初始化成一个类似于链表的形式。
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView)
{
.......
mInputChannel = new InputChannel();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
......
mSyntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
"aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
InputStage imeStage = new ImeInputStage(earlyPostImeStage,
"aq:ime:" + counterSuffix);
InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
"aq:native-pre-ime:" + counterSuffix);
mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;
}
初始化后的InputStage的链表形式如下:
所以,如果是按键事件,则分发的起点是NativePreImeInputStage,如果是触摸事件,则分发的起点是EarlyPostImeInputStage。
2.3.12 InputStage.deliver
//InputStage的deliver处理
public final void deliver(QueuedInputEvent q) {
if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {//q.mFlags是0,所以此处不执行forward,FLAG_FINISHED代表已经处理完成的事件
forward(q);
} else if (shouldDropInputEvent(q)) {//是否丢弃事件
finish(q, false);
} else {//此处会执行
apply(q, onProcess(q));//onProcess函数返回的是FORWARD,代表交给下一个处理InputStage
}
}
2.3.13 InputStage.apply
主要作用为:
1.如果当前InputStage的返回结果是FORWARD,则调用forward传递给下一个InputStage去处理。如果返回的是FINISH_HANDLED,则调用finish表示处理完成。如果最终此链表所有的都不处理此消息,则返回的是FINISH_NOT_HANDLED。
protected void apply(QueuedInputEvent q, int result) {
if (result == FORWARD) {//FORWARD代表交给下一个InputStage处理
forward(q);
} else if (result == FINISH_HANDLED) {//代表处理完成
finish(q, true);
} else if (result == FINISH_NOT_HANDLED) {//代表未处理
finish(q, false);
} else {
throw new IllegalArgumentException("Invalid result: " + result);
}
}
//将事件转发到下一阶段。
protected void forward(QueuedInputEvent q) {
onDeliverToNext(q);
}
protected void onDeliverToNext(QueuedInputEvent q) {
if (DEBUG_INPUT_STAGES) {
Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
}
if (mNext != null) {
mNext.deliver(q);//指向下一个deliver,最终会执行到 ViewPostImeInputStage的onProcess:
} else {
finishInputEvent(q);
}
}
2.3.14 NativePreImeInputStage.onProcess
//NativePreImeInputStage
protected int onProcess(QueuedInputEvent q) {
/*
if (mInputQueue != null && q.mEvent instanceof KeyEvent) {//一般mInputQueue是空的
mInputQueue.sendInputEvent(q.mEvent, q, true, this);
return DEFER;
}*/
return FORWARD;//FORWARD代表交给下一个阶段去处理
}
2.3.15 ViewPreImeInputStage.onProcess
此时便传递给了ViewPreImeInputStage阶段。我们看看ViewPreImeInputStage的onprocess的处理。
//ViewPreImeInputStage
protected int onProcess(QueuedInputEvent q) {
if (q.mEvent instanceof KeyEvent) {
return processKeyEvent(q);
}
return FORWARD;
}
private int processKeyEvent(QueuedInputEvent q) {
final KeyEvent event = (KeyEvent)q.mEvent;
if (mView.dispatchKeyEventPreIme(event)) {//在输入法之前消费key,比如:处理back按键来更新应用程序ui界面,而不是允许输入法接受,然后关闭输入法他自己
return FINISH_HANDLED;
}
return FORWARD;
}
public boolean dispatchKeyEventPreIme(KeyEvent event) {
return onKeyPreIme(event.getKeyCode(), event);//默认onKeyPreIme返回false,除非有view控件继承自view,然后重写此函数onKeyPreIme
}
2.3.16 ImeInputStage.onProcess
接下来便传递给了输入法,ImeInputStage。
//ImeInputStage
protected int onProcess(QueuedInputEvent q) {
if (mLastWasImTarget && !isInLocalFocusMode()) {
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
final InputEvent event = q.mEvent;
if (DEBUG_IMF) Log.v(mTag, "Sending input event to IME: " + event);
int result = imm.dispatchInputEvent(event, q, this, mHandler);//派发给输入法
if (result == InputMethodManager.DISPATCH_HANDLED) {
return FINISH_HANDLED;//输入法消费事件完成
} else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
// The IME could not handle it, so skip along to the next InputStage
return FORWARD;//发送给下一个阶段
} else {
return DEFER; // callback will be invoked later
}
}
}
return FORWARD;
}
2.3.17 EarlyPostImeInputStage.onProcess
接下来便传递给了EarlyPostImeInputStage。
final class EarlyPostImeInputStage extends InputStage {
protected int onProcess(QueuedInputEvent q) {
if (q.mEvent instanceof KeyEvent) {//走这里,如果是按键事件
return processKeyEvent(q);
} else {
final int source = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
return processPointerEvent(q);
}
}
return FORWARD;
}
private int processKeyEvent(QueuedInputEvent q) {
final KeyEvent event = (KeyEvent)q.mEvent;
if (mAttachInfo.mTooltipHost != null) {
mAttachInfo.mTooltipHost.handleTooltipKey(event);
}
// 如果按键的目的是退出触摸模式,那么我们会使用它,并认为它已经处理好了。
if (checkForLeavingTouchModeAndConsume(event)) {//这里只有键盘的上下左右中方向键和enter按键,
//tab按键,空格按键,光标移动到开始按键,光标移动到末尾按键和向上翻页按键和向下翻页按键才会返回会true之外,
//其他所有按键都是fasle
return FINISH_HANDLED;
}
mFallbackEventHandler.preDispatchKeyEvent(event);
return FORWARD;
}
}
2.3.18 NativePostImeInputStage.onProcess
final class NativePostImeInputStage extends AsyncInputStage
implements InputQueue.FinishedInputEventCallback {
protected int onProcess(QueuedInputEvent q) {
if (mInputQueue != null) {
mInputQueue.sendInputEvent(q.mEvent, q, false, this);//将消息传递给NativeActivity,一般mInputQueue为空
return DEFER;
}
return FORWARD;
}
2.3.19 ViewPostImeInputStage.onProcess
最终普通的按键会走到ViewPostImeInputStage去处理。
final class ViewPostImeInputStage extends InputStage {
public ViewPostImeInputStage(InputStage next) {
super(next);
}
@Override
protected int onProcess(QueuedInputEvent q) {
if (q.mEvent instanceof KeyEvent) {//如果是按键事件
return processKeyEvent(q);
} else {//如果是motion事件
final int source = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
return processPointerEvent(q);
} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
return processTrackballEvent(q);
} else {
return processGenericMotionEvent(q);
}
}
}
}
2.3.20 ViewPostImeInputStage.processKeyEvent
//ViewPostImeInputStage.java
private int processKeyEvent(QueuedInputEvent q) {
final KeyEvent event = (KeyEvent)q.mEvent;
// Deliver the key to the view hierarchy.
if (mView.dispatchKeyEvent(event)) {//此处mView是DecorView
return FINISH_HANDLED;
}
}
mView 指向当前界面的顶层布局 DecorView,注意,此时便是走到了View的分发流程。我们放在2.4进行分析。
2.4 View分发流程源码分析
首先我们需要知道Activity的主要构成,才能梳理View的分发流程。此篇源码本人会另写一篇。此处只说结论。
一个Activity包含一个Window对象,而Window对象是抽象类,这个对象是由PhoneWindow来实现的,PhoneWindow将DecorView作为整个应用窗口的根View,然后这个DecorView又将屏幕划分为两个区域,一个是TitleView,一个是ContentView。ContentView本质是Viewgroup。然后平常我们做的布局就是展示在ContentView中的。
左边为原生的Activity结构图,右边为对应的布局。
其中左边的TitleView和右边的test是对应的。左边contentview就是右边大片空白的地方。
左边为本文测试程序中的Activity结构图,右边为对应的布局。
其中左边的TitleView和右边的Activitytest是对应的。左边的button对应右边的开始测试,左边的EditText对应右边的Activitytest和开始测试中间空白部分。左边contentview就是Activitytest以下的所有地方。
2.4.1 DecorView.dispatchKeyEvent
我们此时接着2.3.20分析。此时会走到DecorView,DecorView是当前界面的顶层布局。
此时存在三种情况:
情况一:当前应用存在焦点窗口,则最红会走到焦点窗口的Onkey函数。
情况二:当前应用不存在焦点窗口,但是重写了Activity的onKeyDown和onKeyUp,此时会走Activity的兜底函数onKeyDown和onKeyUp。
情况三:当前无应用,比如我们打开手机直接按音量加减,则页面会响应音量加减。此时会调用PhoneWindow的onKeyDown和onKeyUp。发送到meida服务,调节音量。
//DecorView.java
public boolean dispatchKeyEvent(KeyEvent event) {
final int keyCode = event.getKeyCode();
final int action = event.getAction();
final boolean isDown = action == KeyEvent.ACTION_DOWN;
if (isDown && (event.getRepeatCount() == 0)) {
/**
if ((mWindow.mPanelChordingKey > 0) && (mWindow.mPanelChordingKey != keyCode)) {
boolean handled = dispatchKeyShortcutEvent(event);
if (handled) {
return true;
}
}
//如果某个面板处于打开状态,请在没有弦面板键的情况下对其执行快捷方式
if ((mWindow.mPreparedPanel != null) && mWindow.mPreparedPanel.isOpen) {
if (mWindow.performPanelShortcut(mWindow.mPreparedPanel, keyCode, event, 0)) {
return true;
}
}
*/
}
if (!mWindow.isDestroyed()) {
final Window.Callback cb = mWindow.getCallback();//mWindow是phonewindow
//Window.Callback 指向当前 Activity,在 Activity 启动时会调用自己的 attach 方法,
//此方法中会将自己作为 callback 传给 window。
final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
: super.dispatchKeyEvent(event);//情况一和二:返回值代表目标 View 对事件的处理结果
if (handled) {
return true;
}
}
return isDown ? mWindow.onKeyDown(mFeatureId, event.getKeyCode(), event)
: mWindow.onKeyUp(mFeatureId, event.getKeyCode(), event);
//情况三:调用PhoneWindow的onKeyDown,onKeyUp 用于PhoneWindow消费音量加减等按键
}
2.4.1.1 情况一:当前应用存在焦点窗口时处理流程分析
即此时是当我们只打开应用,然后点击EditText的区域时候,会弹出输入法,此时EditText此时是焦点,当按下音量减少按键,结果如下。最终会走向焦点应用的EditText的onKey函数。
2.4.1.1.1 Activity.dispatchKeyEvent
public boolean dispatchKeyEvent(KeyEvent event) {
onUserInteraction();//空实现
//让操作栏打开菜单,以响应菜单键的优先级高于处理它的窗口
final int keyCode = event.getKeyCode();
/**
if (keyCode == KeyEvent.KEYCODE_MENU &&//如果是菜单栏
mActionBar != null && mActionBar.onMenuKeyEvent(event)) {
return true;
}
*/
Window win = getWindow();
if (win.superDispatchKeyEvent(event)) {//情况一:接着就会调用 PhoneWindow 的 superDispatchTouchEvent 方法,此处到最后的焦点窗口的onKey函数。
//其返回值代表目标 View 对事件的处理结果,
return true;
}
View decor = mDecor;//此时decor是DecorView,为根view
if (decor == null) decor = win.getDecorView();
return event.dispatch(this, decor != null? decor.getKeyDispatcherState() : null, this);
//情况二:我们可以看到如果目标 View 没有消费掉此次事件(即返回值为 false)则会调用 Activity 的 onKeyDown或者onKeyup来处理。
}
2.4.1.1.2 PhoneWindow.superDispatchTouchEvent
//PhoneWindow.superDispatchTouchEvent
public boolean superDispatchKeyEvent(KeyEvent event) {
return mDecor.superDispatchKeyEvent(event);
}
2.4.1.1.3.DecorView.superDispatchTouchEvent
DecorView 继承自 FrameLayout,而FrameLayout继承自ViewGroup,因此此时调用的是ViewGroup的dispatchKeyEvent函数。
//DecorView.superDispatchTouchEvent
public boolean superDispatchKeyEvent(KeyEvent event) {
/*
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {//如果是返回键
final int action = event.getAction();
// Back cancels action modes first.
if (mPrimaryActionMode != null) {
if (action == KeyEvent.ACTION_UP) {
mPrimaryActionMode.finish();
}
return true;
}
}*/
if (super.dispatchKeyEvent(event)) {//走这里,调用ViewGroup类的dispatchKeyEvent函数
return true;
}
/*
return (getViewRootImpl() != null) && getViewRootImpl().dispatchUnhandledKeyEvent(event);//第一种情况不走这里
*/
}
2.4.1.1.4 ViewGroup.dispatchKeyEvent
因为按键事件只需要派发给焦点窗口即可,所以相比于触摸事件,是比较简单的。触摸事件会有一个链表保存所有View。然后会遍历此View,而按键事件则不需要。
最终会调用到mFocused.dispatchKeyEvent函数。
//ViewGroup.java
//按键事件只需要派发给焦点窗口即可
public boolean dispatchKeyEvent(KeyEvent event) {
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onKeyEvent(event, 1);//一致性检验
}
if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))//PFLAG_FOCUSED代表是焦点视图,PFLAG_HAS_BOUNDS代表已经完成了布局。
//所以此处的含义是如果当前ViewGroup的视图是焦点视图并且已经完成布局拥有边界
== (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
if (super.dispatchKeyEvent(event)) {
return true;
}
} else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)//如果当前的ViewGroup代表的view不是焦点视图,则寻找到焦点窗口视图
//调用焦点视图的dispatchKeyEvent方法。
== PFLAG_HAS_BOUNDS) {
if (mFocused.dispatchKeyEvent(event)) {
return true;
}
}
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);//一致性检验
}
return false;
}
2.4.1.1.5 View.dispatchKeyEvent
此时的mListenerInfo是不为空的,因为我们在调用mEditText.setOnKeyListener(this);最终会将listener保存到mListenerInfo.mOnKeyListener中,所以,此时我们就完成了事件的派发。焦点onKey函数得到调用。
//view
//将关键事件分派到焦点路径上的下一个视图。此路径从视图树的顶部向下延伸到当前聚焦的视图。
//如果这个视图有焦点,它将分派给自己。否则,它将沿着焦点路径调度下一个节点。
public boolean dispatchKeyEvent(KeyEvent event) {
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) {//此时mListenerInfo不为空,我们在调用mEditText.setOnKeyListener(this);
//会将listener保存到li.mOnKeyListener
return true;
}
/*
if (event.dispatch(this, mAttachInfo != null
? mAttachInfo.mKeyDispatchState : null, this)) {
return true;
}
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
}
return false;
mEditText.setOnKeyListener(this)的源码分析如下:
//EditText继承自TextView
//TextView继承自View
public void setOnKeyListener(OnKeyListener l)
{
getListenerInfo().mOnKeyListener = l;
}
ListenerInfo getListenerInfo() {
if (mListenerInfo != null) {
return mListenerInfo;
}
mListenerInfo = new ListenerInfo();
return mListenerInfo;
}
此时我们仍然需要注意返回值,此时返回值是ture。
返回值链路为:
View.dispatchKeyEvent------>ViewGroup.dispatchKeyEvent----->DecorView.superDispatchTouchEvent------>PhoneWindow.superDispatchTouchEvent------>
Activity.dispatchKeyEvent------>DecorView.dispatchKeyEvent------>ViewPostImeInputStage.processKeyEvent函数。
最后processKeyEvent函数会返回FINISH_HANDLED。表示已经完成了按键事件的处理。
然后继续返回到了 2.3.13 InputStage.apply函数,此时会执行 finish(q, true)函数。
2.4.1.1.6 ViewRootImpl.finish
此时仍会传递到下一个阶段。此时就剩最后一个阶段了,是SyntheticInputStage。
protected void finish(QueuedInputEvent q, boolean handled) {
q.mFlags |= QueuedInputEvent.FLAG_FINISHED;
if (handled) {//此时会true
q.mFlags |= QueuedInputEvent.FLAG_FINISHED_HANDLED;
}
forward(q);//传递到下一个阶段
}
protected void forward(QueuedInputEvent q) {
onDeliverToNext(q);
}
protected void onDeliverToNext(QueuedInputEvent q) {
if (DEBUG_INPUT_STAGES) {
Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
}
if (mNext != null) {//走这里
mNext.deliver(q);
} else {
finishInputEvent(q);
}
}
2.4.1.4.7 deliver
主要作用为:
1.SyntheticInputStage发现按键事件已经被消费了,则不再调用apply函数,而是再次传递给下一个,此时发现mNext为空,最终会调用finishInputEvent函数。
public final void deliver(QueuedInputEvent q) {
if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
forward(q);//走这里,即当事件以及被消费了,就不用走apply了,直接再传递给下一个
} else if (shouldDropInputEvent(q)) {
finish(q, false);
} else {
apply(q, onProcess(q));
}
}
protected void forward(QueuedInputEvent q) {
onDeliverToNext(q);
}
protected void onDeliverToNext(QueuedInputEvent q) {
if (DEBUG_INPUT_STAGES) {
Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
}
if (mNext != null) {
mNext.deliver(q);
} else {
finishInputEvent(q);//此时mNext为空,会走这里
}
}
2.4.1.4.8 ViewRootImpl.finishInputEvent
主要作用为:
1.调用InputEventReceiver的finishInputEvent函数。
//当处理完后会调用 finishInputEvent() 方法结束此次分发。
private void finishInputEvent(QueuedInputEvent q) {
if (q.mReceiver != null) {
boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;//此时为true
q.mReceiver.finishInputEvent(q.mEvent, handled);//此时mReceiver是NativeInputEventReceiver
} else {
q.mEvent.recycleIfNeededAfterDispatch();
}
recycleQueuedInputEvent(q);//从队列中回收InputEvent事件
}
2.4.1.4.9 InputEventReceiver.finishInputEvent
主要作用为:
1.调用nativeFinishInputEvent函数。
public final void finishInputEvent(InputEvent event, boolean handled) {
/**
if (event == null) {
throw new IllegalArgumentException("event must not be null");
}
if (mReceiverPtr == 0) {
Log.w(TAG, "Attempted to finish an input event but the input event "
+ "receiver has already been disposed.");
}
*/
else {
int index = mSeqMap.indexOfKey(event.getSequenceNumber());//从请求队列中取出之前IMS发送过来的按键事件
/*
if (index < 0) {
Log.w(TAG, "Attempted to finish an input event that is not in progress.");
} */
else {
int seq = mSeqMap.valueAt(index);
mSeqMap.removeAt(index);//从mSeqMap移除此按键事件
nativeFinishInputEvent(mReceiverPtr, seq, handled);//向input发送event已完成发送的消息
}
}
event.recycleIfNeededAfterDispatch();//如果是MotionEvent事件,则回收,如果是KeyEvent则不回收
}
2.4.1.4.10 nativeFinishInputEvent
主要作用为:
1.调用c++层的NativeInputEventReceiver对象的finishInputEvent函数。
static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jlong receiverPtr,jint seq, jboolean handled){
sp<NativeInputEventReceiver> receiver =reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
status_t status = receiver->finishInputEvent(seq, handled);//调用c++层的NativeInputEventReceiver对象的finishInputEvent
/*
if (status && status != DEAD_OBJECT) {
String8 message;
message.appendFormat("Failed to finish input event. status=%d", status);
jniThrowRuntimeException(env, message.string());
}*/
}
2.4.1.4.11 finishInputEvent
status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
status_t status = mInputConsumer.sendFinishedSignal(seq, handled);//handled是true,seq是IMS发送到应用端的event的消息号,
//代表发送给IMS告诉此按键event已经完成处理。
//返回值是0代表成功
/*
if (status) {//如果发送失败,则生成finsh放入容器,客户端并设置ALOOPER_EVENT_OUTPUT属性,
//当下一次IMS分发线程分发下一个按键事件到达应用端的时候,客户端会重新发送此事件的完成事件。
if (status == WOULD_BLOCK) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Could not send finished signal immediately. "
"Enqueued for later.", getInputChannelName().c_str());
}
Finish finish;
finish.seq = seq;
finish.handled = handled;
mFinishQueue.add(finish);
if (mFinishQueue.size() == 1) {
setFdEvents(ALOOPER_EVENT_INPUT | ALOOPER_EVENT_OUTPUT);
}
return OK;
}
ALOGW("Failed to send finished signal on channel '%s'. status=%d",
getInputChannelName().c_str(), status);
}*/
return status;
}
2.4.1.4.12 sendFinishedSignal
1.调用sendUnchainedFinishedSignal函数。
status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
/**
if (!seq) {
ALOGE("Attempted to send a finished signal with sequence number 0.");
return BAD_VALUE;
}
// Send finished signals for the batch sequence chain first.
size_t seqChainCount = mSeqChains.size();//首先发送批次序列链的完成信号。主要用于motion事件
if (seqChainCount) {
uint32_t currentSeq = seq;
uint32_t chainSeqs[seqChainCount];
size_t chainIndex = 0;
for (size_t i = seqChainCount; i > 0; ) {
i--;
const SeqChain& seqChain = mSeqChains.itemAt(i);
if (seqChain.seq == currentSeq) {
currentSeq = seqChain.chain;
chainSeqs[chainIndex++] = currentSeq;
mSeqChains.removeAt(i);
}
}
status_t status = OK;
while (!status && chainIndex > 0) {
chainIndex--;
status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);
}
if (status) {
// An error occurred so at least one signal was not sent, reconstruct the chain.
for (;;) {
SeqChain seqChain;
seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq;
seqChain.chain = chainSeqs[chainIndex];
mSeqChains.push(seqChain);
if (!chainIndex) break;
chainIndex--;
}
return status;
}
}
*/
// Send finished signal for the last message in the batch.
return sendUnchainedFinishedSignal(seq, handled);//向input发送event已完成发送的消息
}
2.4.1.4.13 sendUnchainedFinishedSignal
主要作用为:
1.此函数会生成完成事件处理的InputMessage消息,并通过socket,发送发送消息到IMS侧。
status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
InputMessage msg;
msg.header.type = InputMessage::TYPE_FINISHED;
msg.body.finished.seq = seq;
msg.body.finished.handled = handled;
return mChannel->sendMessage(&msg);
}
2.4.1.4.14 InputChannel::sendMessage
主要作用为:
1.通过socket,向IMS发送已完成事件处理的消息,此时会触发此时会触发input端的handleReceiveCallback函数。
//向input发送event已完成发送的消息,此时会触发input端的handleReceiveCallback函数
status_t InputChannel::sendMessage(const InputMessage* msg) {
const size_t msgLength = msg->size();
InputMessage cleanMsg;
msg->getSanitizedCopy(&cleanMsg);
ssize_t nWrite;
do {
nWrite = ::send(mFd, &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
if (nWrite < 0) {
int error = errno;
if (error == EAGAIN || error == EWOULDBLOCK) {
return WOULD_BLOCK;
}
if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED || error == ECONNRESET) {
return DEAD_OBJECT;
}
return -error;
}
if (size_t(nWrite) != msgLength) {
return DEAD_OBJECT;
}
return OK;//ok的值是0
}
2.4.1.4.15 InputDispatcher::handleReceiveCallback
主要作用为:
1.IMS服务端会调用receiveFinishedSignal函数,从socket中读取信息,序列号和完成处理的标志,并保存到msg中,返回0代表成功。
2.调用finishDispatchCycleLocked函数,内部会生成一个commond命令,并放入命令队列中。
3.调用runCommandsLockedInterruptible函数,循环从mCommandQueue中取出command并执行。执行的命令是这个doDispatchCycleFinishedLockedInterruptible函数doDispatchCycleFinishedLockedInterruptible主要是将处理完成的事件从等待队列中删除。
//查看handleReceiveCallback函数
int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
InputDispatcher* d = static_cast<InputDispatcher*>(data);
{ // acquire lock
AutoMutex _l(d->mLock);
ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd);
if (connectionIndex < 0) {//如果连接不存在,则返回
ALOGE("Received spurious receive callback for unknown input channel. "
"fd=%d, events=0x%x", fd, events);
return 0; // remove the callback
}
bool notify;
sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);
if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {//如果事件不等于发生错误或者挂断
if (!(events & ALOOPER_EVENT_INPUT)) {//如果事件不是表示socket有可读
ALOGW("channel '%s' ~ 收到未处理轮询事件的虚假回调. "
"events=0x%x", connection->getInputChannelName().c_str(), events);
return 1;//如果返回的事件是未处理的poll event,则返回
}
nsecs_t currentTime = now();
bool gotOne = false;
status_t status;
//启动一个死循环,启动死循环后,会一直读取消息,并根据序列号生成命令,保存在命令数组中,
//等到无消息可读,则会返回-EAGAIN,即-11
for (;;) {
uint32_t seq;
bool handled;
status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);//从socket中读取信息,并保存到msg中,返回0代表成功
/**
if (status) {//如果返回的不是ok,则退出循环,当返回-EAGAIN,代表无数据可读,退出循环
break;
}
*/
d->finishDispatchCycleLocked(currentTime, connection, seq, handled);//内部会生成一个commond命令,并放入命令队列中。
gotOne = true;
}
if (gotOne) {
d->runCommandsLockedInterruptible();//循环从mCommandQueue中取出command并执行。执行的命令是这个doDispatchCycleFinishedLockedInterruptible函数。
//doDispatchCycleFinishedLockedInterruptible主要是将事件从等待队列中删除
if (status == WOULD_BLOCK) {
return 1;
}
}
notify = status != DEAD_OBJECT || !connection->monitor;
if (notify) {
ALOGE("channel '%s' ~ Failed to receive finished signal. status=%d",
connection->getInputChannelName().c_str(), status);
}
} else {//代表发生错误
//Monitor channels从未显式注销。
//当远程端点关闭时,我们会自动执行此操作,所以不要担心它们。
notify = !connection->monitor;
if (notify) {
ALOGW("channel '%s' ~ Consumer closed input channel or an error occurred. "
"events=0x%x", connection->getInputChannelName().c_str(), events);
}
}
//取消注册inputchannel
d->unregisterInputChannelLocked(connection->inputChannel, notify);
return 0; // remove the callback
} // release lock
}
2.4.1.4.16 InputPublisher::receiveFinishedSignal
主要作用为:
1.调用receiveMessage从socket中读取信息。
2.将消息序列和处理完成的标志取出来并赋值。
status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
InputMessage msg;
status_t result = mChannel->receiveMessage(&msg);//从socket中读取信息,并保存到msg中,返回0代表成功
/**
if (result) {
*outSeq = 0;
*outHandled = false;
return result;
}
*/
if (msg.header.type != InputMessage::TYPE_FINISHED) {//如果返回的消息类型不是成功类型
ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer",
mChannel->getName().c_str(), msg.header.type);
return UNKNOWN_ERROR;//返回,不知道的错误
}
*outSeq = msg.body.finished.seq;//从msg中取出序列号和handle
*outHandled = msg.body.finished.handled;
return OK;
}
2.4.1.4.17 InputChannel::receiveMessage
主要作用为:
1.从socket对应的mFd取出数据,存储在msg中。
status_t InputChannel::receiveMessage(InputMessage* msg) {
ssize_t nRead;
do {
nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);//从socket对应的mFd取出数据,存储在msg中
} while (nRead == -1 && errno == EINTR);
if (nRead < 0) {//代表读取错误
int error = errno;
#if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.c_str(), errno);
#endif
if (error == EAGAIN || error == EWOULDBLOCK) {
return WOULD_BLOCK;
}
if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED) {
return DEAD_OBJECT;
}
return -error;
}
if (nRead == 0) { // 检查是否有错误
#if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.c_str());
#endif
return DEAD_OBJECT;
}
if (!msg->isValid(nRead)) {
#if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ received invalid message", mName.c_str());
#endif
return BAD_VALUE;
}
#if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ received message of type %d", mName.c_str(), msg->header.type);
#endif
return OK;
}
2.4.1.4.18 finishDispatchCycleLocked
主要作用为:
1.其内部会生成一个command,并入队到mCommandQueue中,传入的函数doDispatchCycleFinishedLockedInterruptible就是命令本身。
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection, uint32_t seq, bool handled) {
connection->inputPublisherBlocked = false;
//STATUS_BROKEN表示发生了不可恢复的通信错误,STATUS_ZOMBIE表示input channel已注销。
/**
if (connection->status == Connection::STATUS_BROKEN
|| connection->status == Connection::STATUS_ZOMBIE) {
return;
}
*/
// 通知其他系统组件并准备开始下一个分发循环
onDispatchCycleFinishedLocked(currentTime, connection, seq, handled);
}
void InputDispatcher::onDispatchCycleFinishedLocked(
nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) {
//生成一个command,并入队到mCommandQueue中,传入的函数doDispatchCycleFinishedLockedInterruptible就是命令本身
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
commandEntry->connection = connection;//
commandEntry->eventTime = currentTime;
commandEntry->seq = seq;
commandEntry->handled = handled;
}
InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) {
CommandEntry* commandEntry = new CommandEntry(command);
mCommandQueue.enqueueAtTail(commandEntry);
return commandEntry;
}
2.4.1.4.19 runCommandsLockedInterruptible
主要作用为:
1.从mCommandQueue中取出刚才添加的command并执行。
bool InputDispatcher::runCommandsLockedInterruptible() {
if (mCommandQueue.isEmpty()) {
return false;
}
//循环从mCommandQueue中取出command并执行
do {
CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();
Command command = commandEntry->command;
(this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible'
commandEntry->connection.clear();
delete commandEntry;
} while (! mCommandQueue.isEmpty());
return true;
}
2.4.1.4.20 doDispatchCycleFinishedLockedInterruptible
主要作用为:
1.根据seq序列号从waitQueue队列中取出对应的dispatchEntry,然后让其出队,代表已经完成此事件的发送。
void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) {
sp<Connection> connection = commandEntry->connection;
nsecs_t finishTime = commandEntry->eventTime;
uint32_t seq = commandEntry->seq;
bool handled = commandEntry->handled;
// Handle post-event policy actions.
DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq);//根据seq序列号从waitQueue队列中取出对应的dispatchEntry
if (dispatchEntry) {
nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;//用输入事件处理完成的时间减去此事件分发的时间就得到了处理此次事件的总耗时
if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {//打印出所有分发时间超过 2s 的事件
std::string msg =
StringPrintf("Window '%s' spent %0.1fms processing the last input event: ",
connection->getWindowName().c_str(), eventDuration * 0.000001f);
dispatchEntry->eventEntry->appendDescription(msg);
ALOGI("%s", msg.c_str());
}
bool restartEvent;//restartEvent 决定是否将事件再次分发
if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
//判断事件是否需要再次分发
restartEvent = afterKeyEventLockedInterruptible(connection,dispatchEntry, keyEntry, handled);
} else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
restartEvent = afterMotionEventLockedInterruptible(connection,
dispatchEntry, motionEntry, handled);
} else {
restartEvent = false;
}
if (dispatchEntry == connection->findWaitQueueEntry(seq)) {
connection->waitQueue.dequeue(dispatchEntry);//从waitQueue队列中让此seq对应的dispatchEntry出队,代表已经完成发送。
traceWaitQueueLengthLocked(connection);//追踪队列长度
if (restartEvent && connection->status == Connection::STATUS_NORMAL) {//如果此事件需要再次分发并且连接正常
connection->outboundQueue.enqueueAtHead(dispatchEntry);//入队outboundQueue
traceOutboundQueueLengthLocked(connection);//追踪队列长度
} else {
releaseDispatchEntryLocked(dispatchEntry);//释放事件
}
}
startDispatchCycleLocked(now(), connection);//启动下一个事件处理循环。
}
}
2.4.1.2 情况二:当前应用没有焦点窗口,但存在Activity兜底处理的流程分析
即当我们只打开应用,而不点击EditText的区域时候,即EditText此时不是焦点,当按下音量减少按键,结果如下。即最终会走的是Activity的兜底的onKeyDown和onKeyup函数。
2.4.1.2.1 Activity.dispatchKeyEvent
//Activity.java
public boolean dispatchKeyEvent(KeyEvent event) {
onUserInteraction();//空实现
//让操作栏打开菜单,以响应菜单键的优先级高于处理它的窗口
final int keyCode = event.getKeyCode();
/**
if (keyCode == KeyEvent.KEYCODE_MENU &&//如果是菜单栏
mActionBar != null && mActionBar.onMenuKeyEvent(event)) {
return true;
}
Window win = getWindow();
if (win.superDispatchKeyEvent(event)) {//情况一:接着就会调用 PhoneWindow 的 superDispatchTouchEvent 方法,此处到最后的焦点窗口的onKey函数。
//其返回值代表目标 View 对事件的处理结果,
return true;
}*/
View decor = mDecor;//此时decor是DecorView,为根view
if (decor == null) decor = win.getDecorView();
return event.dispatch(this, decor != null? decor.getKeyDispatcherState() : null, this);
//情况二:我们可以看到如果目标 View 没有消费掉此次事件(即返回值为 false)则会调用 Activity 的 onKeyDown或者onKeyup来处理。
}
2.4.1.2.2 keyEvent.dispatch
主要作用为:
1.此时便会调用Activity的onKeyDown函数和onKeyUp函数进行处理。
然后返回值为true,
返回链路为DecorView.dispatchKeyEvent------>ViewPostImeInputStage.processKeyEvent函数。
最后processKeyEvent函数会返回FINISH_HANDLED。表示已经完成了按键事件的处理。
然后继续返回到了 2.3.13 InputStage.apply函数,此时会执行 finish(q, true)函数。
后续内容和2.4.1.1.6 ViewRootImpl.finish到2.4.1.1.20一样,请查看这些章节。
keyEvent.java
public final boolean dispatch(Callback receiver, DispatcherState state,
Object target) {
//此时receiver是Activity
switch (mAction) {
case ACTION_DOWN: {
mFlags &= ~FLAG_START_TRACKING;
if (DEBUG) Log.v(TAG, "Key down to " + target + " in " + state
+ ": " + this);
boolean res = receiver.onKeyDown(mKeyCode, this);//注意此处便是Activity兜底的onKeyDown函数
if (state != null) {
if (res && mRepeatCount == 0 && (mFlags&FLAG_START_TRACKING) != 0) {
if (DEBUG) Log.v(TAG, " Start tracking!");
state.startTracking(this, target);
} else if (isLongPress() && state.isTracking(this)) {//如果此key是长按
try {
if (receiver.onKeyLongPress(mKeyCode, this)) {//则调用Activity的onKeyLongPress函数
if (DEBUG) Log.v(TAG, " Clear from long press!");
state.performedLongPress(this);
res = true;
}
} catch (AbstractMethodError e) {
}
}
}
return res;
}
case ACTION_UP:
if (DEBUG) Log.v(TAG, "Key up to " + target + " in " + state
+ ": " + this);
if (state != null) {
state.handleUpEvent(this);
}
return receiver.onKeyUp(mKeyCode, this);//注意此处便是Activity兜底的onKeyUp函数
}
return false;
}
2.4.1.3 情况三:当前无应用,音量加减交给PhoneWindow处理流程分析
此时DecorView.dispatchKeyEvent会调用PhoneWindow的onKeyDown和onKeyUp处理。
//DecorView.java
public boolean dispatchKeyEvent(KeyEvent event) {
final int keyCode = event.getKeyCode();
final int action = event.getAction();
final boolean isDown = action == KeyEvent.ACTION_DOWN;
if (isDown && (event.getRepeatCount() == 0)) {
/**
if ((mWindow.mPanelChordingKey > 0) && (mWindow.mPanelChordingKey != keyCode)) {
boolean handled = dispatchKeyShortcutEvent(event);
if (handled) {
return true;
}
}
//如果某个面板处于打开状态,请在没有弦面板键的情况下对其执行快捷方式
if ((mWindow.mPreparedPanel != null) && mWindow.mPreparedPanel.isOpen) {
if (mWindow.performPanelShortcut(mWindow.mPreparedPanel, keyCode, event, 0)) {
return true;
}
}
*/
}
if (!mWindow.isDestroyed()) {
final Window.Callback cb = mWindow.getCallback();//mWindow是phonewindow
//Window.Callback 指向当前 Activity,在 Activity 启动时会调用自己的 attach 方法,
//此方法中会将自己作为 callback 传给 window。
final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
: super.dispatchKeyEvent(event);//情况一和二:返回值代表目标 View 对事件的处理结果
if (handled) {
return true;
}
}
return isDown ? mWindow.onKeyDown(mFeatureId, event.getKeyCode(), event)
: mWindow.onKeyUp(mFeatureId, event.getKeyCode(), event);
//情况三:调用PhoneWindow的onKeyDown,onKeyUp 用于PhoneWindow消费音量加减等按键
}
2.4.1.3.1 PhoneWindow.onKeyDown
主要作用为:
1.发送给media服务进行多媒体的相关操作,如调节音量大小。
protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) {
final KeyEvent.DispatcherState dispatcher =
mDecor != null ? mDecor.getKeyDispatcherState() : null;
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP://音量加
case KeyEvent.KEYCODE_VOLUME_DOWN://音量减少
case KeyEvent.KEYCODE_VOLUME_MUTE: {//扬声器静音按键
if (mMediaController != null) {
mMediaController.dispatchVolumeButtonEventAsSystemService(event);//发送给media音量加减的事件
} else {
getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(event,
mVolumeControlStreamType);
}
return true;
}
// These are all the recognized media key codes in
// KeyEvent.isMediaKey()
case KeyEvent.KEYCODE_MEDIA_PLAY://多媒体键 播放
case KeyEvent.KEYCODE_MEDIA_PAUSE://多媒体键 暂停
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: //多媒体键 播放/暂停
case KeyEvent.KEYCODE_MUTE://话筒静音按键
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_STOP://多媒体键 停止
case KeyEvent.KEYCODE_MEDIA_NEXT://多媒体键 下一首
case KeyEvent.KEYCODE_MEDIA_PREVIOUS://多媒体键 上一首
case KeyEvent.KEYCODE_MEDIA_REWIND://多媒体键 快退
case KeyEvent.KEYCODE_MEDIA_RECORD://多媒体按键 录音
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {//多媒体键 快进
if (mMediaController != null) {
if (mMediaController.dispatchMediaButtonEventAsSystemService(event)) {
return true;
}
}
return false;
}
case KeyEvent.KEYCODE_MENU: {//菜单按键
onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event);
return true;
}
case KeyEvent.KEYCODE_BACK: {//返回按键
if (event.getRepeatCount() > 0) break;
if (featureId < 0) break;
// Currently don't do anything with long press.
if (dispatcher != null) {
dispatcher.startTracking(event, this);
}
return true;
}
}
return false;
}
然后继续返回到了 2.3.13 InputStage.apply函数,此时会执行 finish(q, true)函数。
后续内容和2.4.1.1.6 ViewRootImpl.finish到2.4.1.1.20一样,请查看这些章节。
至此,普通按键事件的派发便分析完成了,下一篇,我们会对motion事件处理和分发流程做一个详细分析。