Android输入子系统之应用程序注册消息监听过程分析
来源:互联网 发布:ssm项目源码 编辑:程序博客网 时间:2024/06/06 09:31
应用程序注册消息监听过程分析
CPP层InputManagerService启动后就需要监听按键输入了,当InputManagerService监听到键盘输入的事件后就需要分发键盘事件,但是分发给谁呢?这里首先应该是分发给当前激活的Window窗口,但是当前激活的window窗口怎么才能接受到消息呢,window窗口需要注册一个键盘消息接收通道到InputManagerService中,那么如何注册的呢?我们知道一个Activity对应一个ViewRootImpl对象,在Activity启动时会创建一个ViewRootImpl对象,并调用其setView函数把Activity的DecorView设置到ViewRootImpl中,而Activity正是在setView函数中注册键盘消息的接收通道的。
Step 1. ViewRootImpl.setView
该函数定义在frameworks/base/core/java/android/view/ViewRootImpl.java中
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { //调用requestLayout来通知InputManagerService当前的窗口是激活的窗口 requestLayout(); if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { //如果该窗口没有指定INPUT_FEATURE_NO_INPUT_CHANNEL属性,则创建消息接收通道InputChannel mInputChannel = new InputChannel(); } try { //通过binder调用,调用server端的Session对象来跟WindowManagerService通信,该函数最后会调 //用到WindowManagerService的addWindow函数,函数中会创建一对InputChannel(server/client), //这样在函数调用结束后,mInputChannel就变成了client端的对象。在 //frameworks/base/core/java/android/view/IWindowSession.aidl的 //addToDisplay函数的声明中,InputChannel指定的数据流的流向是out,因此 //WindowManagerService修改了mInputChannel,客户端就能拿到这个对象的数据了。 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mInputChannel); } catch (Exception e) { ... } if (mInputChannel != null) { if (mInputQueueCallback != null) { mInputQueue = new InputQueue(); mInputQueueCallback.onInputQueueCreated(mInputQueue); //初始化WindowInputEventReceiver,按键消息会从native层传到该对象的onInputEvent函数 //中,onInputEvent函数是按键在应用端java层分发的起始端。 mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper()); } }}
这个函数与注册键盘消息通道的相关主要有三个功能:
一是调用requestLayout函数来通知InputManagerService,这个Activity窗口是当前被激活的窗口,同时将所有的窗口注册到InputDispatcher中
二是调用mWindowSession的add成员函数来把键盘消息接收通道的server端注册端注册到CPP层的InputManagerService中,client端注册到本应用程序的消息循环Looper中,这样当InputManagerService监控到有键盘消息的时候,就会找到当前被激活的窗口,然后找到其在InputManagerService中对应的键盘消息接收通道(InputChannel),通过这个通道在InputManagerService的server端来通知应用程序消息循环的client端,这样就把键盘消息分发给当前激活的Activity窗口了
三是应用程序这一侧注册消息接收通道
Step 2. ViewRootImpl.requestLayout
该函数定义在frameworks/base/core/java/android/view/ViewRootImpl.java中
@Overridepublic void requestLayout() { if (!mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested = true; scheduleTraversals(); } }
这里调用了scheduleTraversals函数来做进一步的操作,该函数调用mChoreographer来post一个Runnable到Looper中,之后会执行mTraversalRunnable中的run方法,即调用doTraversal函数
Step 3. ViewRootImpl.doTraversal
该函数定义在frameworks/base/core/java/android/view/ViewRootImpl.java中
void doTraversal() { if (mTraversalScheduled) { mTraversalScheduled = false; mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier); performTraversals(); }}
该函数主要是执行performTraversals()函数,进而调用relayoutWindow函数,在该函数中又会调用mWindowSession的relayout进入到java层的WindowManagerService的relayoutWindow函数,该函数会调用mInputMonitor.updateInputWindowsLw(true /force/);mInputMonitor是InputMonitor对象。
Step 4. InputMonitor.updateInputWindowsLw
该函数定义在frameworks/base/core/java/android/view/ViewRootImpl.java中
public void updateInputWindowsLw(boolean force) { boolean addInputConsumerHandle = mService.mInputConsumer != null; // Add all windows on the default display. final int numDisplays = mService.mDisplayContents.size(); for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { WindowList windows = mService.mDisplayContents.valueAt(displayNdx).getWindowList(); for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { final WindowState child = windows.get(winNdx); final InputChannel inputChannel = child.mInputChannel; final InputWindowHandle inputWindowHandle = child.mInputWindowHandle; if (inputChannel == null || inputWindowHandle == null || child.mRemoved) { // Skip this window because it cannot possibly receive input. continue; } if (addInputConsumerHandle && inputWindowHandle.layer <= mService.mInputConsumer.mWindowHandle.layer) { addInputWindowHandleLw(mService.mInputConsumer.mWindowHandle); addInputConsumerHandle = false; } final int flags = child.mAttrs.flags; final int privateFlags = child.mAttrs.privateFlags; final int type = child.mAttrs.type; final boolean hasFocus = (child == mInputFocus); final boolean isVisible = child.isVisibleLw(); if ((privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS) != 0) { disableWallpaperTouchEvents = true; } final boolean hasWallpaper = (child == mService.mWallpaperTarget) && (privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD) == 0 && !disableWallpaperTouchEvents; final boolean onDefaultDisplay = (child.getDisplayId() == Display.DEFAULT_DISPLAY); // If there's a drag in progress and 'child' is a potential drop target, // make sure it's been told about the drag if (inDrag && isVisible && onDefaultDisplay) { mService.mDragState.sendDragStartedIfNeededLw(child); } addInputWindowHandleLw(inputWindowHandle, child, flags, type, isVisible, hasFocus, hasWallpaper); } } // Send windows to native code. mService.mInputManager.setInputWindows(mInputWindowHandles);}
这个函数将当前系统中带有InputChannel的Activity窗口都设置为InputManagerService的输入窗口,但是后面我们会看到,只有当前激活的窗口才会响应键盘消息。
Step 5. InputManagerService.setInputWindows
该函数定义在frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public void setInputWindows(InputWindowHandle[] windowHandles) { nativeSetInputWindows(mPtr, windowHandles);}
这个函数调用了本地方法nativeSetInputWindows来进一步执行操作,mPtr是native层NativeInputManager实例,在调用InputManagerService.nativeInit函数时会在native层构造NativeInputManager对象并将其保存在mPtr中。nativeSetInputWindows会调用NativeInputManager的setInputWindows函数
Step 6. NativeInputManager.setInputWindows
这个函数定义在frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) { Vector<sp<InputWindowHandle> > windowHandles; if (windowHandleObjArray) { jsize length = env->GetArrayLength(windowHandleObjArray); for (jsize i = 0; i < length; i++) { jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i); if (! windowHandleObj) { break; // found null element indicating end of used portion of the array } sp<InputWindowHandle> windowHandle = android_server_InputWindowHandle_getHandle(env, windowHandleObj); if (windowHandle != NULL) { windowHandles.push(windowHandle); } env->DeleteLocalRef(windowHandleObj); } } mInputManager->getDispatcher()->setInputWindows(windowHandles); // Do this after the dispatcher has updated the window handle state. bool newPointerGesturesEnabled = true; size_t numWindows = windowHandles.size(); for (size_t i = 0; i < numWindows; i++) { const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i); const InputWindowInfo* windowInfo = windowHandle->getInfo(); if (windowInfo && windowInfo->hasFocus && (windowInfo->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES)) { newPointerGesturesEnabled = false; } }}
这个函数首先将Java层的InputWindowHandle转换成C++层的NativeInputWindowHandle,然后放在windowHandles向量中,最后将这些输入窗口设置到InputDispatcher中去。
Step 7. InputDispatcher.setInputWindows
这个函数定义在frameworks/native/services/inputflinger/InputDispatcher.cpp 文件中:
void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) { { // acquire lock AutoMutex _l(mLock); Vector<sp<InputWindowHandle> > oldWindowHandles = mWindowHandles; mWindowHandles = inputWindowHandles; sp<InputWindowHandle> newFocusedWindowHandle; bool foundHoveredWindow = false; for (size_t i = 0; i < mWindowHandles.size(); i++) { const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i); if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == NULL) { mWindowHandles.removeAt(i--); continue; } if (windowHandle->getInfo()->hasFocus) { newFocusedWindowHandle = windowHandle; } } if (mFocusedWindowHandle != newFocusedWindowHandle) { mFocusedWindowHandle = newFocusedWindowHandle; } } // release lock // Wake up poll loop since it may need to make new input dispatching choices. mLooper->wake();}
这里InputDispatcher的成员变量mFocusedWindowHandle 就代表当前激活的窗口的。这个函数遍历inputWindowHandles,获取获得焦点的窗口,并赋值给mFocusedWindowHandle 这样,InputManagerService就把当前激活的窗口保存在InputDispatcher中了,后面就可以把键盘消息分发给它来处理。
Step 8. 在前面的ViewRootImpl的setView中,下一步是server端注册接收通道
if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { mInputChannel = new InputChannel(); } try { res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mInputChannel); } catch (Exception e) { ... }
这里会调用到WindowManagerService的addWindow接口
Step 9. WindowManagerService.addWindow
该函数定义在frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { if (outInputChannel != null && (attrs.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { String name = win.makeInputChannelName(); InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); win.setInputChannel(inputChannels[0]); inputChannels[1].transferTo(outInputChannel); mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle); }}
这里的outInputChannel即为前面创建的InputChannel,它不为NULL,因此,这里会通过InputChannel.openInputChannelPair函数来创建一对输入通道,其中一个位于WindowManagerService中,另外一个通过outInputChannel参数返回到应用程序中。WindowManagerService会为每个窗口创建一个WindowState对象,然后将该InputChannel对的service端保存到WindowState中
Step 10. 下面看下InputChannel.openInputChannelPair的实现
函数定义在frameworks/base/core/java/android/view/InputChannel.java
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函数,在native创建一个InputChannel对
Step 11. InputChannel.nativeOpenInputChannelPair
函数定义在frameworks/base/core/jni/android_view_InputChannel.cpp
static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env, jclass clazz, jstring nameObj) { const char* nameChars = env->GetStringUTFChars(nameObj, NULL); String8 name(nameChars); env->ReleaseStringUTFChars(nameObj, nameChars); sp<InputChannel> serverChannel; sp<InputChannel> clientChannel; status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel); ... return channelPair;}
nativeOpenInputChannelPair函数调用InputChannel的openInputChannelPair函数创建一对InputChannel,该对象是Native层的InputChannel,跟java层是一一对应的。
Step 12. InputChannel.openInputChannelPair
该函数定义在frameworks/native/libs/input/InputTransport.cpp中
status_t InputChannel::openInputChannelPair(const String8& 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.string(), errno); outServerChannel.clear(); outClientChannel.clear(); return result; } int bufferSize = SOCKET_BUFFER_SIZE; //设置server端和client端的接收缓冲区和发送缓冲区 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)); String8 serverChannelName = name; serverChannelName.append(" (server)"); outServerChannel = new InputChannel(serverChannelName, sockets[0]); String8 clientChannelName = name; clientChannelName.append(" (client)"); outClientChannel = new InputChannel(clientChannelName, sockets[1]); return OK; }
这里调用了socketpair系统调用创建了一对已经连接的UNIX租socket,这里可以把这一对socket当成pipe返回的文件描述符一样使用,pipe返回的管道是单向管道,即只能从一端写入,一端读出,但是socketpair是创建的管道是全双工的,可读可写。
创建好了server端和client端通道后,在WindowManagerService.addWindow函数中,一方面它把刚才创建的Client端的输入通道通过outInputChannel参数返回到应用程序中:
inputChannels[1].transferTo(outInputChannel);
另外还需要把server端的InputChannel注册到InputManagerService中:
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
Step 13. InputManagerService.registerInputChannel
函数定义在frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public void registerInputChannel(InputChannel inputChannel, InputWindowHandle inputWindowHandle) { if (inputChannel == null) { throw new IllegalArgumentException("inputChannel must not be null."); } nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);}
通过调用nativeRegisterInputChannel来将InputChannel注册到native层
Step 14. InputManagerService.nativeRegisterInputChannel
这个函数定义在frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */, jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj); sp<InputWindowHandle> inputWindowHandle = android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj); status_t status = im->registerInputChannel( env, inputChannel, inputWindowHandle, monitor);}
根据java层的InputWindowHandle获得native层的InputWindowHandle对象,根据java层的InputChannel获得native层的InputChannel对象,然后调用NativeInputManager的resgiterInputChannel,该函数又调用了InputDispatcher的registerInputChannel
Step 15. InputDispatcher.registerInputChannel
该函数定义在frameworks/native/services/inputflinger/InputDispatcher.cpp
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, const sp<InputWindowHandle>& inputWindowHandle, bool monitor) { { // acquire lock AutoMutex _l(mLock); sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor); int fd = inputChannel->getFd(); mConnectionsByFd.add(fd, connection); if (monitor) { mMonitoringChannels.push(inputChannel); } mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); } // release lock // Wake the looper because some connections have changed. mLooper->wake(); return OK;}
将InputWindowHandle, InputChanel封装成Connection对象,然后fd作为key,Connection作为Value,保存在mConnectionsByFd中,如果传入的monitor是true,则需要将InputChannel放到mMonitoringChannels中,从上面的InputManagerService的registerInputChannel函数里传入的monitor是false,所以这里不加入到mMonitoringChannels。同时把fd加入到mLooper的监听中,并指定当该fd有内容可读时,Looper就会调用handleReceiveCallback函数。至此server端的InputChannel注册完成,InputDispatcher睡眠在监听的fds上,当有按键事件发生时,InputDispatcher就会往这些fd写入InputMessage对象,进而回调handleReceiveCallback函数。//TODO这里当客户端的进程读取完事件后会往InputChannel的client端写入????,而server端可以收到,这时InputDispatcher就会被唤醒,然后调用handleReceiveCallback来表明按键接收结束。
至此,server端的InputChannel就注册完成了,再回到前面的WindowManagerService.addWindow上的第二步inputChannels[1].transferTo(outInputChannel);,这个是将创建的一对InputChannel的client端复制到传入的参数InputChannel上,当addWindow返回时,就回到ViewRootImpl.setView函数中,执行应用程序这一侧的键盘消息接收通道。
if (mInputChannel != null) { mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper());}
WindowInputEventReceiver继承自InputEventReceiver类。
Step 16. InputEventReceiver.init
构造函数定义在frameworks/base/core/java/android/view/InputEventReceiver.java
public InputEventReceiver(InputChannel inputChannel, Looper looper) { mInputChannel = inputChannel; mMessageQueue = looper.getQueue(); mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this), inputChannel, mMessageQueue); mCloseGuard.open("dispose");}
调用了nativeInit执行native层的初始化
Step 17. InputEventReceiver.nativeInit
定义在frameworks/base/core/jni/android_view_InputEventReceiver.cpp
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject inputChannelObj, jobject messageQueueObj) { sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj); sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env, receiverWeak, inputChannel, messageQueue); status_t status = receiver->initialize(); receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object return reinterpret_cast<jlong>(receiver.get());}
函数创建了一个NativeInputEventReceiver对象,并调用其initialize函数
Step 18. NativeInputEventReceiver.initialize
该函数定义在frameworks/base/core/jni/android_view_InputEventReceiver.cpp
status_t NativeInputEventReceiver::initialize() { setFdEvents(ALOOPER_EVENT_INPUT); return OK;}
调用setFdEvents函数
Step 19. NativeInputEventReceiver.setFdEvents
该函数定义在frameworks/base/core/jni/android_view_InputEventReceiver.cpp
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); } }}
这里调用传入的MessageQueue获取Looper对象,如果events是0,则表示要移除监听fd,如果events不为0,表示要监听fd,这个fd是前面WindowManagerService创建的一对InputChannel的client端,这样当Server端写入事件时,client端的looper就能被唤醒,并调用handleEvent函数(Looper::addFd函数可以指定LooperCallback对象,当fd可读时,会调用LooperCallback的handleEvent,而NativeInputEventReceiver继承自LooperCallback,所以这里会调用NativeInputEventReceiver的handleEvent函数)
Step 20. NativeInputEventReceiver.handleEvent
该函数定义在frameworks/base/core/jni/android_view_InputEventReceiver.cpp
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) { 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; } }
该函数调用consumeEvents函数来处理接收一个按键事件
Step 21. NativeInputEventReceiver.consumeEvents
该函数定义在frameworks/base/core/jni/android_view_InputEventReceiver.cpp
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) { if (kDebugDispatchCycle) { ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s, frameTime=%lld.", getInputChannelName(), consumeBatches ? "true" : "false", (long long)frameTime); } if (consumeBatches) { mBatchedInputEventPending = false; } if (outConsumedBatch) { *outConsumedBatch = false; } ScopedLocalRef<jobject> receiverObj(env, NULL); bool skipCallbacks = false; for (;;) { uint32_t seq; InputEvent* inputEvent; status_t status = mInputConsumer.consume(&mInputEventFactory, consumeBatches, frameTime, &seq, &inputEvent); if (!skipCallbacks) { jobject inputEventObj; switch (inputEvent->getType()) { case AINPUT_EVENT_TYPE_KEY: inputEventObj = android_view_KeyEvent_fromNative(env, static_cast<KeyEvent*>(inputEvent)); break; } if (inputEventObj) { env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj); env->DeleteLocalRef(inputEventObj); } } if (skipCallbacks) { mInputConsumer.sendFinishedSignal(seq, false); } }}
函数首先调用mInputConsumer.consume接收一个InputEvent对象,mInputConsumer在NativeInputEventReceiver构造函数中初始化
Step 22. InputConsumer.consume
该函数定义在frameworks/native/libs/input/InputTransport.cpp
status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) { *outSeq = 0; *outEvent = NULL; // Fetch the next input message. // Loop until an event can be returned or no additional events are received. while (!*outEvent) { if (mMsgDeferred) { // mMsg contains a valid input message from the previous call to consume // that has not yet been processed. mMsgDeferred = false; } else { // Receive a fresh message. status_t result = mChannel->receiveMessage(&mMsg); if (result) { // Consume the next batched event unless batches are being held for later. if (consumeBatches || result != WOULD_BLOCK) { result = consumeBatch(factory, frameTime, outSeq, outEvent); if (*outEvent) { break; } } return result; } } switch (mMsg.header.type) { case InputMessage::TYPE_KEY: { KeyEvent* keyEvent = factory->createKeyEvent(); if (!keyEvent) return NO_MEMORY; initializeKeyEvent(keyEvent, &mMsg); *outSeq = mMsg.body.key.seq; *outEvent = keyEvent; break; } } return OK;}
函数首先调用InputChannel的receiveMessage函数接收InputMessage对象,然后根据InputMessage对象调用initializeKeyEvent来构造KeyEvent对象。拿到可KeyEvent对象后,再对到consumeEvents中调用java层的InputEventReceiver.java的dispatchInputEvent函数
env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
Step 23. InputEventReceiver.dispatchInputEvent
该函数定义在frameworks/base/core/java/android/view/InputEventReceiver.java
// Called from native code.@SuppressWarnings("unused")private void dispatchInputEvent(int seq, InputEvent event) { mSeqMap.put(event.getSequenceNumber(), seq); onInputEvent(event);}
进而调用onInputEvent函数。至此按键就开始了java层的分发。
参考
http://blog.csdn.net/luoshengyang/article/details/6882903
- Android输入子系统之应用程序注册消息监听过程分析
- Android输入子系统之InputReader读取键盘消息过程分析
- Android输入子系统之InputDispatcher分发键盘消息过程分析
- Android输入子系统之启动过程分析
- 输入子系统匹配过程之list_for_each_entry()函数分析
- 输入子系统之触摸屏分析
- android输入子系统模型分析:
- android输入子系统模型分析:
- Android Input输入子系统分析
- 输入子系统之events消息数据传递
- Android应用程序注册广播接收器(registerReceiver)的过程分析
- Android应用程序注册广播接收器(registerReceiver)的过程分析
- Android应用程序注册广播接收器(registerReceiver)的过程分析
- Android应用程序注册广播接收器(registerReceiver)的过程分析
- Android应用程序注册广播接收器(registerReceiver)的过程分析
- Android应用程序注册广播接收器(registerReceiver)的过程分析
- Android应用程序注册广播接收器(registerReceiver)的过程分析
- Android应用程序注册广播接收器(registerReceiver)的过程分析
- 从1到n整数中1出现的次数
- [翻译]Play2 整合akka
- 基于Java构建微服务
- git基本使用
- THINKPHP发送邮件功能梳理
- Android输入子系统之应用程序注册消息监听过程分析
- SqueezeNet论文笔记
- com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException问题
- PHP基础知识总结02(常用的数组函数)
- OpenGL shader编程
- 表单验证
- 腾讯云直播相关问题处理
- mybatis多表查询报java.lang.IllegalArgumentException: argument type mismatch
- Java中webService的几种调用方法