在上一篇文章Android输入管理1:输入信息分发中,我们讲述了信息从获取到分发过InputChannel的过程。接下来我们再介绍一下InputChannel的创建以及如何通过InputChannel将消息分发到应用中去。
InputChannel的创建
首先生成应用进程中的InputChannel对象,看看ViewRootImpl类的setView方法
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
mForceDecorViewVisibility = (mWindowAttributes.privateFlags & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
mTempInsets);
setFrame(mTmpFrame);
} catch (RemoteException e) {
mAdded = false;
mView = null;
mAttachInfo.mRootView = null;
mInputChannel = null;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
setAccessibilityFocus(null, null);
throw new RuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}
...
}
在setView方法中如果mWindowAttributes.inputFeatures变量中没有WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL标记,表示能接收输入,则创建java层InputChannel对象,并赋值给类变量mInputChannel,在接下来调用mWindowSession.addToDisplay方法时,作为参数传入其中,然后传递到WindowManagerService中,调用它的addWindow方法。如下:
public int addWindow(Session session, IWindow client, int seq,
LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState) {
...
final boolean openInputChannels = (outInputChannel != null && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) {
//win是WindowState类的对象
win.openInputChannel(outInputChannel);
}
...
}
// WindowState 的win.openInputChannel 方法
void openInputChannel(InputChannel outInputChannel) {
if (mInputChannel != null) {
throw new IllegalStateException("Window already has an input channel.");
}
String name = getName();
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
mInputChannel = inputChannels[0];
mClientChannel = inputChannels[1];
mInputWindowHandle.token = mClient.asBinder();
if (outInputChannel != null) {
mClientChannel.transferTo(outInputChannel);
mClientChannel.dispose();
mClientChannel = null;
} else {
// If the window died visible, we setup a dummy input channel, so that taps
// can still detected by input monitor channel, and we can relaunch the app.
// Create dummy event receiver that simply reports all events as handled.
mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
}
mWmService.mInputManager.registerInputChannel(mInputChannel, mClient.asBinder());
}
addWindow方法调用WindowState类的openInputChannel方法。在openInputChannel方法中: 1.先通过InputChannel.openInputChannelPair(name)创建一个InputChannel数组对象,其中包含2个InputChannel对象。
2.inputChannels[1]赋值给mClientChannel变量,并转换成和客户端传递过来的outInputChannel对象。
3.inputChannels[0]赋值给mInputChannel变量,调用mWmService.mInputManager.registerInputChannel方法注册InputChannel对象。这个registerInputChannel方法在上篇文章《Android输入管理1:输入信息分发》中消息分发一节已经有描述,在该方法中把InputChannel对象和新创建的Connection绑定,这样就可以通过Connection找到对应的InputChannel对象来分发消息。
下面看看InputChannel.openInputChannelPair方法创建InputChannel[]数组的过程
public static InputChannel[] openInputChannelPair(String name) {
if (name == null) {
throw new IllegalArgumentException("name must not be null");
}
if (DEBUG) {
Slog.d(TAG, "Opening input channel pair '" + name + "'");
}
return nativeOpenInputChannelPair(name);
}
//nativeOpenInputChannelPair 本地方法代码
static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
jclass clazz, jstring nameObj) {
ScopedUtfChars nameChars(env, nameObj);
std::string name = nameChars.c_str();
sp<InputChannel> serverChannel;
sp<InputChannel> clientChannel;
status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
if (result) {
String8 message;
message.appendFormat("Could not open input channel pair. status=%d", result);
jniThrowRuntimeException(env, message.string());
return NULL;
}
jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
if (env->ExceptionCheck()) {
return NULL;
}
jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
std::make_unique<NativeInputChannel>(serverChannel));
if (env->ExceptionCheck()) {
return NULL;
}
jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
std::make_unique<NativeInputChannel>(clientChannel));
if (env->ExceptionCheck()) {
return NULL;
}
env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
return channelPair;
}
openInputChannelPair方法调用了本地方法nativeOpenInputChannelPair。在本地方法nativeOpenInputChannelPair中: 1.调用native方法InputChannel::openInputChannelPair创建出本地InputChannel对象serverChannel和clientChannel。 2.将serverChannel和clientChannel作为参数,调用android_view_InputChannel_createInputChannel函数创建java层的InputChannel对象 3.将创建的java层InputChannel类的对象serverChannelObj和clientChannelObj设置到数组channelPair中并返回。
在来看看InputChannel::openInputChannelPair方法是如何创建InputChannel对象的。
status_t InputChannel::openInputChannelPair(const std::string& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
status_t result = -errno;
ALOGE("channel '%s' ~ Could not create socket pair. errno=%d",
name.c_str(), errno);
outServerChannel.clear();
outClientChannel.clear();
return result;
}
int bufferSize = SOCKET_BUFFER_SIZE;
setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
std::string serverChannelName = name;
serverChannelName += " (server)";
outServerChannel = new InputChannel(serverChannelName, sockets[0]);
std::string clientChannelName = name;
clientChannelName += " (client)";
outClientChannel = new InputChannel(clientChannelName, sockets[1]);
return OK;
}
InputChannel::openInputChannelPair首先创建一对socket,sockets[0]和sockets[1]。再new InputChannel对象,并将socket对象传入其中。sockets[0]对应outServerChannel,sockets[1]对应outClientChannel。这样InputChannel对象就和socket对应起来。后续通过InputChannel类的sendMessage函数发送消息,事实上是通过socket发送数据出去,这个后面我们再分析。 生成完native层的InputChannel对象后,再来看看android_view_InputChannel_createInputChannel函数,如何创建java层InputChannel对象。
static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,
std::unique_ptr<NativeInputChannel> nativeInputChannel) {
jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,
gInputChannelClassInfo.ctor);
if (inputChannelObj) {
android_view_InputChannel_setNativeInputChannel(env, inputChannelObj,
nativeInputChannel.release());
}
return inputChannelObj;
}
//android_view_InputChannel_setNativeInputChannel函数
static void android_view_InputChannel_setNativeInputChannel(JNIEnv* env, jobject inputChannelObj,
NativeInputChannel* nativeInputChannel) {
env->SetLongField(inputChannelObj, gInputChannelClassInfo.mPtr,
reinterpret_cast<jlong>(nativeInputChannel));
}
上面代码,通过env->NewObject函数生成inputChannelObj对象,并且在android_view_InputChannel_setNativeInputChannel函数中,将传入的NativeInputChannel对象,设置inputChannelObj对象的mPtr变量中。NativeInputChannel对象在调用android_view_InputChannel_createInputChannel函数时以参数的形式传入。而NativeInputChannel对象则是根据生成的InputChannel对象,调用make_unique来构建的。 所以这时各个类的关系就很清晰了。java层的inputChannelObj对象的mPtr变量引用了native层的NativeInputChannel对象,NativeInputChannel对象则通过变量mInputChannel引用native层的InputChannel对象,而native层的InputChannel对象又通过变量mFd引用socket对象。
以上即是InputChannel的生成过程。
总结图如下:
应用程序与输入管理服务建立通信过程
应用程序如何和输入管理服务建立通信的?上面创建过程用到了一个函数socketpair,该函数用于创建一对无名的、相互连接的套接字。也就是说通过socketpair函数,创建sockets[0]和sockets[1]之后,这对socket就可以双向通信了。sockets[0]作为服务端,随着创建的InputChannel的对象,被注册到InputManager中,用于在接收到输入消息后,找到合适的InputChannel发送信息。 sockets[1]做为客户端是如何给到应用程序的?
WindowState的win.openInputChannel方法中会调用inputChannels[1]的transferTo方法,而且以客户端传递的 outlnputChannel 作为参数。代码如下:
public void transferTo(InputChannel outParameter) {
if (outParameter == null) {
throw new IllegalArgumentException("outParameter must not be null");
}
nativeTransferTo(outParameter);
}
static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
jobject otherObj) {
if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Other object already has a native input channel.");
return;
}
NativeInputChannel* nativeInputChannel =
android_view_InputChannel_getNativeInputChannel(env, obj);
android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);
android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
}
函数功能:把调用对象的mPtr中的值放到参数对象的mPtr中,并将调用对象的mPtr设置为NULL。transferTo执行后,outlnputChannel的mPtr指针保存的就是native层创建的InputChannel对象的指针。这样客户端传递的outlnputChannel对象就间接引用了socket[1]。outInputChannel是一个返回参数,我们看一下它的readFromParcel实现
public void readFromParcel(Parcel in) {
if (in == null) {
throw new IllegalArgumentException("in must not be null");
}
nativeReadFromParcel(in);
}
static void android_view_InputChannel_nativeReadFromParcel(JNIEnv* env, jobject obj,
jobject parcelObj) {
if (android_view_InputChannel_getNativeInputChannel(env, obj) != NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"This object already has a native input channel.");
return;
}
Parcel* parcel = parcelForJavaObject(env, parcelObj);
if (parcel) {
bool isInitialized = parcel->readInt32();
if (isInitialized) {
InputChannel* inputChannel = new InputChannel();
inputChannel->read(*parcel);
NativeInputChannel* nativeInputChannel = new NativeInputChannel(inputChannel);
android_view_InputChannel_setNativeInputChannel(env, obj, nativeInputChannel);
}
}
}
//InputChannel的read函数
status_t InputChannel::read(const Parcel& from) {
mName = from.readString8();
mToken = from.readStrongBinder();
int rawFd = from.readFileDescriptor();
setFd(::dup(rawFd));
if (mFd < 0) {
return BAD_VALUE;
}
return OK;
}
//InputChannel的setFd函数
void InputChannel::setFd(int fd) {
if (mFd > 0) {
::close(mFd);
}
mFd = fd;
if (mFd > 0) {
int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket "
"non-blocking. errno=%d", mName.c_str(), errno);
}
}
应用程序客户端调用outInputChannel的readFromParcel函数。其作用:
1.获取服务端传递过来的保存数据的parcel对象
2.创建客户端InputChannel对象,并且通过Parcel数据读取socket的句柄rawFd,在将rawFd复制一个设置到InputChannel对象的mFd变量中。
3.生成NativeInputChannel对象并将该对象引用设置到客户端的InputChannel对象的mPtr中。
通过上面的操作,应用客户端就获取到了来着服务端的soket句柄,而这个soket句柄即是之前在服务端设置的socket[1]。这样应用端和服务器端就建立了socket通信链接。
然后就可以通过服务端发送输入消息给应用程序客户端。
应用接收Input消息
回到InputManagerService中,输入消息会传递到InputChannel的sendMessage中(具体传递过程可以查看在上篇文章<<Android输入管理1:输入信息分发>>)
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);
...
return OK;
}
sendMessage通过系统调用send函数发送输入消息,这样输入消息通过socket就传递到用户进程中。而用户进程如何接收socket传过来的消息? 回到ViewRootImpl的setView函数在调用addToDisplay函数后,创建WindowInputEventReceiver对象
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper());
}
WindowInputEventReceiver继承了InputEventReceiver类,其构造方法如下
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null");
}
if (looper == null) {
throw new IllegalArgumentException("looper must not be null");
}
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
inputChannel, mMessageQueue);
mCloseGuard.open("dispose");
}
在这个构造方法中,将传进来的客户端inputChannel设置给mInputChannel变量。再通过当前线程的looper对象获取其消息队列。然后将它们作为参数传给nativeInit方法。nativeInit方法生成了native层的NativeInputEventReceiver对象的引用保存到mReceiverPtr变量中。
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject inputChannelObj, jobject messageQueueObj) {
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
if (inputChannel == NULL) {
jniThrowRuntimeException(env, "InputChannel is not initialized.");
return 0;
}
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
receiverWeak, inputChannel, messageQueue);
status_t status = receiver->initialize();
if (status) {
String8 message;
message.appendFormat("Failed to initialize input event receiver. status=%d", status);
jniThrowRuntimeException(env, message.string());
return 0;
}
receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object
return reinterpret_cast<jlong>(receiver.get());
}
nativeInit函数通过获取本地inputChannel 和 本地消息队列messageQueue,做为参数传递给生成的NativeInputEventReceiver。然后调用NativeInputEventReceiver的initialize函数,如下:
status_t NativeInputEventReceiver::initialize() {
setFdEvents(ALOOPER_EVENT_INPUT);
return OK;
}
//setFdEvents
void NativeInputEventReceiver::setFdEvents(int events) {
if (mFdEvents != events) {
mFdEvents = events;
int fd = mInputConsumer.getChannel()->getFd();
if (events) {
mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
} else {
mMessageQueue->getLooper()->removeFd(fd);
}
}
}
setFdEvents函数获取inputChannel对象的fd,然后调用addFd设置到消息队列对应的loop中。下面看看loop代码
int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
...
{ // acquire lock
AutoMutex _l(mLock);
Request request;
request.fd = fd;
request.ident = ident;
request.events = events;
request.seq = mNextRequestSeq++;
request.callback = callback;
request.data = data;
if (mNextRequestSeq == -1) mNextRequestSeq = 0; // reserve sequence number -1
struct epoll_event eventItem;
request.initEventItem(&eventItem);
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex < 0) {
int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, fd, &eventItem);
if (epollResult < 0) {
ALOGE("Error adding epoll events for fd %d: %s", fd, strerror(errno));
return -1;
}
mRequests.add(fd, request);
} else {
int epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_MOD, fd, &eventItem);
if (epollResult < 0) {
if (errno == ENOENT) {
// Tolerate ENOENT because it means that an older file descriptor was
// closed before its callback was unregistered and meanwhile a new
// file descriptor with the same number has been created and is now
// being registered for the first time. This error may occur naturally
// when a callback has the side-effect of closing the file descriptor
// before returning and unregistering itself. Callback sequence number
// checks further ensure that the race is benign.
//
// Unfortunately due to kernel limitations we need to rebuild the epoll
// set from scratch because it may contain an old file handle that we are
// now unable to remove since its file descriptor is no longer valid.
// No such problem would have occurred if we were using the poll system
// call instead, but that approach carries others disadvantages.
#if DEBUG_CALLBACKS
ALOGD("%p ~ addFd - EPOLL_CTL_MOD failed due to file descriptor "
"being recycled, falling back on EPOLL_CTL_ADD: %s",
this, strerror(errno));
#endif
epollResult = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, fd, &eventItem);
if (epollResult < 0) {
ALOGE("Error modifying or adding epoll events for fd %d: %s",
fd, strerror(errno));
return -1;
}
scheduleEpollRebuildLocked();
} else {
ALOGE("Error modifying epoll events for fd %d: %s", fd, strerror(errno));
return -1;
}
}
mRequests.replaceValueAt(requestIndex, request);
}
} // release lock
return 1;
}
通过Loop的addFd函数可以看到,参数fd加入到Looper对象的epoll监控中,在mRequests队列中加入Request对象。这个对象的events成员带有EPOLLIN标记,它的callback成员变量指向NativeInputEventReceiver对象,而NativeInputEventReceiver继承自LooperCallback。这就监听了接收端的socket,有消息进来就会调用对应的callback。当有消息时,线程处理消息循环会调用Looper的pollOnce()函数,pollOnce()调用pollInner()函数。
int Looper::pollInner(int timeoutMillis) {
...
// Poll.
int result = POLL_WAKE;
mResponses.clear();
mResponseIndex = 0;
// We are about to idle.
mPolling = true;
//等待事件到来
struct epoll_event eventItems[EPOLL_MAX_EVENTS];
int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
// No longer idling.
mPolling = false;
// Acquire lock.
mLock.lock();
...
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if (fd == mWakeEventFd.get()) {
if (epollEvents & EPOLLIN) {
awoken();
} else {
ALOGW("Ignoring unexpected epoll events 0x%x on wake event fd.", epollEvents);
}
} else {
//获得有消息的 fd 在 mRequests 中的 index
ssize_t requestIndex = mRequests.indexOfKey(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;
//插入到 mResponses 列表中
pushResponse(events, mRequests.valueAt(requestIndex));
} else {
ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
"no longer registered.", epollEvents, fd);
}
}
}
...
// Release lock.
mLock.unlock();
//处理 mResponses 列表中所有元素
// Invoke all response callbacks.
for (size_t i = 0; i < mResponses.size(); i++) {
Response& response = mResponses.editItemAt(i);
if (response.request.ident == POLL_CALLBACK) {
int fd = response.request.fd;
int events = response.events;
void* data = response.request.data;
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
ALOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",
this, response.request.callback.get(), fd, events, data);
#endif
// Invoke the callback. Note that the file descriptor may be closed by
// the callback (and potentially even reused) before the function returns so
// we need to be a little careful when removing the file descriptor afterwards.
//调用 callback 指针的 handleEvent
int callbackResult = response.request.callback->handleEvent(fd, events, data);
if (callbackResult == 0) {
removeFd(fd, response.request.seq);
}
// Clear the callback reference in the response structure promptly because we
// will not clear the response vector itself until the next poll.
response.request.callback.clear();
result = POLL_CALLBACK;
}
}
return result;
}
pollInner函数做了一下处理:
1.调用epoll_wait等待事件到来
2.循环处理到来的消息事件,在mRequests中根据fd得到它所属的Reuest对象的index.
3.调用pushResponse把events和根据index获取的Reuest对象加入mResponses列表中
4.处理mResponses中所有的item,并调用他们的callback对象的handleEvent函数处理消息。
callback->handleEvent中的callback即为之前传入的NativeInputEventReceiver对象,它的handleEvent函数代码如下:
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
// This error typically occurs when the publisher has closed the input channel
// as part of removing a window or finishing an IME session, in which case
// the consumer will soon be disposed as well.
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Publisher closed input channel or an error occurred. "
"events=0x%x", getInputChannelName().c_str(), events);
}
return 0; // remove the callback
}
if (events & ALOOPER_EVENT_INPUT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
return status == OK || status == NO_MEMORY ? 1 : 0;
}
...
return 1;
}
// consumeEvents 函数
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
...
for (;;) {
uint32_t seq;
InputEvent* inputEvent;
//从 InputChannel 的 socket 中读取消息
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent);
....
if (inputEventObj) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName().c_str());
}
//调用 WindowInputEventReceiver 的 dispatchInputEvent 方法
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
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;
}
}
....
}
handleEvent函数在参数 events 中带有标记 ALOOPER_EVENT_INPUT 时,调用 consumeEvents ()函数继续处理, consumeEvents中做了一下处理:
1.consumeEvents会循环调用mInputConsumer.consume函数。mInputConsumer包含了前面创建的InputChannel对象。 2.mInputConsumer.consume中调用InputChannel的receiveMessage函数,从InputChannel的socket中读取输入信息。 3.得到获取的信息后,调用java层的 WindowInputEventReceiver 的 dispatchInputEvent 方法。这个方法最终调用onInputEvent方法
//InputEventReceiver类的dispatchInputEvent 方法
// Called from native code.
@SuppressWarnings("unused")
@UnsupportedAppUsage
private void dispatchInputEvent(int seq, InputEvent event) {
mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event);
}
//WindowInputEventReceiver类的onInputEvent方法
@Override
public void onInputEvent(InputEvent event) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventForCompatibility");
List<InputEvent> processedEvents;
try {
processedEvents = mInputCompatProcessor.processInputEventForCompatibility(event);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
if (processedEvents != null) {
if (processedEvents.isEmpty()) {
// InputEvent consumed by mInputCompatProcessor
finishInputEvent(event, true);
} else {
for (int i = 0; i < processedEvents.size(); i++) {
enqueueInputEvent(processedEvents.get(i), this,
QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true);
}
}
} else {
enqueueInputEvent(event, this, 0, true);
}
}
onInputEvent调用了ViewRootImpl的enqueueInputEvent方法保存消息。这样Event消息终于到达应用中拥有焦点的Activity的ViewRootImpl对象。至此来自服务的输入消息被发送到了应用程序。后续的处理就开始了应用程序的消息分发过程,限于本文篇幅就不再详述了。
总结主要过程:
源码路径:
源码基于android 10.0
InputChannel(java):frameworks/base/core/java/android/view/InputChannel.java
NativeInputChannel(c++):在android_view_InputChannel.cpp中定义
android_view_InputChannel.cpp:frameworks/base/core/jni/android_view_InputChannel.cpp
InputChannel (c++):在InputTransport.cpp中定义
InputConsumer:在InputTransport中定义
InputTransport:frameworks/native/libs/input/InputTransport.cpp
InputEventReceiver:frameworks/base/core/java/android/view/InputEventReceiver.java
NativeInputEventReceiver: 在android_view_InputEventReceiver中定义
android_view_InputEventReceiver: frameworks/base/core/jni/android_view_InputEventReceiver.cpp