InputManagerService源码分析三:事件分发
前言
android源码晦涩、难以阅读私以为主要有以下三点:
- 代码内部包含很多小的内部逻辑,阅读的过程很难抓住重点。这个尚可通过精简流程,日志分析等手段来解决。
- 涉及到未知的知识领域。作为一个应用开发这些知识点包括:JNI、Linux操作系统API、OpenGL、Skia等。有些可以通过查找文章,解决迅速;有些就涉及到专业领域了,非专业不可达。
- 是涉及到其他复杂源代码阅读。以InputManagerService事件分发,获取当前焦点View为例。这个流程涉及到WindowManagerService、Looper的源码阅读,如果WindowManagerService源码阅读起来比较困难的话,关于InputManagerService的事件分发就不能说理解透彻。本章节进行InputManagerService事件分发亦遇到此问题,所以本章关于Window的焦点变更逻辑这里只做简要分析,后续WindowManagerService章节会做详细分析。
本人愚见:android手机是一堆零部件、软件的堆砌,android系统Service亦可以这么理解。源码阅读过程就是一个化繁为简的过程。后面的章节会通过一个简单的C程序,简要的理解这句话。
一、事件注册
本章事件分发主要介绍的是:InputManagerSevice将数据分发到应用程序,关于InputManagerService如何接受数据,可以参考InputManagerService初始化。
我们知道InputManagerService是运行在system_process这个进程中的,客户应用程序是运行在独立的进程中的,所以事件分发是跨进程的通信。
本节分五部分介绍应用程序与InputManagerService建立双边通信链路。为方便理解,附上一张从网上截图的图片说明Client与Server的关系。为了方便理解下文Cllient端指客户端进程,Server端指系统system_process进程。
1. Session创建
客户进程与服务进程建立双边通信链路是基于AIDL实现的,Client端通过调用WindowManagerService的OpenSession()获取服务端Session代理,代码如下:
//frameworks\base\core\java\android\view\ViewRootImpl.java
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();
...
}
//frameworks\base\core\java\android\view\WindowManagerGlobal.java
//一个应用程序只有一个WindowSession
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
IWindowManager windowManager = getWindowManagerService();
//通过WindowManagerService代理调用Service服务
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
});
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
//frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
@Override
public IWindowSession openSession(IWindowSessionCallback callback) {
return new Session(this, callback);
}
frameworks\base\services\core\java\com\android\server\wm\Session.java
//Session继承IWindowSession.Stub,返回客户的IWindowSession为Binder代理
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
}
获取远程Session代理时序图如下所示。
2. WindowState创建
获取Session代理后,通过调用其addToDisplay()方法与远程进行通信。分析止于java层WindowState调用openInputChannel(),后续的native层代码分析我们下一节进行分析。本节主要通过四步做简要分析
Step 1: Client端InputChannel创建
在setView()方法内部创建InputChannel,它是一个可序列化的对象。通过new创建的InputChannel为一个空方法,无native层实例对应。后续会分析将其传送到远程服务,并回传有效值。
//frameworks\base\core\java\android\view\ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
}
Step 2: 调用addToDisplay()调用WMS远程服务
通过AIDL接口最终调用了WindowManagerService中的addWindow()方法。
//frameworks\base\core\java\android\view\ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
mTempInsets);
}
//frameworks\base\services\core\java\com\android\server\wm\Session.java
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel,
outInsetsState);
}
Step 3: 创建WindowState
在addWindow()方法中我们会创建WindowState(为了便于分析我们略去了属性、token校验)。WindowState可以翻译成窗口状态,内部会存储Window显示区域、Client端对应的InputChannel等信息,Client端的ViewRootImpl均有一个Sever端的WindowState对应。
//frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
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 WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], seq, attrs, viewVisibility, session.mUid,
session.mCanAddInternalSystemWindow);
...
final boolean openInputChannels = (outInputChannel != null
&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) {
win.openInputChannel(outInputChannel);
}
}
Step 4: 调用WindowState的openInputChannel()代码如下:
//frameworks\base\services\core\java\com\android\server\wm\WindowState.java
void openInputChannel(InputChannel outInputChannel) {
if (mInputChannel != null) {
throw new IllegalStateException("Window already has an input channel.");
}
String name = getName();
//创建一对InputChannel
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 {
mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
}
//Server端监听
mWmService.mInputManager.registerInputChannel(mInputChannel, mClient.asBinder());
}
接下来的一节我们介绍InputChannel.openInputChannelPair()创建InputChannel[]。后续会在Server监听、Client端监听两节分别介绍这一对InputChannel使用。
下面为addToDisplay() java层调用时序图:
3. InputChannel创建
InputChannel.openInputChannelPair()核心方法为native层的nativeOpenInputChannelPair,代码如下:
//frameworks\base\core\jni\android_view_InputChannel.cpp
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;
//Step 1 建立一对相互链接的InputChannel
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;
}
//Step 2 创建java层InputChannel
jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
if (env->ExceptionCheck()) {
return NULL;
}
//Step 3 创建C层NativeInputChannel
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;
}
//Step 3 创建C层NativeInputChannel
env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
return channelPair;
}
可以分接下来三步分析这端代码。
Step 1: 建立一对相互链接的套接字,封装成native层的InputChannel实例。
//frameworks\native\libs\input\InputTransport.cpp
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));
//建立Native层的InputChannel实例
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;
}
Step 2: 创建java层InputChannel数组
创建数组类型为InputChannel的空数组,即空数组,后面在创建NativeInputChannel的时候会赋值。
//frameworks\base\core\jni\android_view_InputChannel.cpp
status_t InputChannel::openInputChannelPair(const std::string& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
...
jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
...
}
Step 3: 创建C层NativeInputChannel
//frameworks\base\core\jni\android_view_InputChannel.cpp
status_t InputChannel::openInputChannelPair(const std::string& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
...
jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
std::make_unique<NativeInputChannel>(clientChannel));
...
}
//frameworks\base\core\jni\android_view_InputChannel.cpp
static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,
std::unique_ptr<NativeInputChannel> nativeInputChannel) {
//调用初始化方法,创建java层InputChannel
jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,
gInputChannelClassInfo.ctor);
if (inputChannelObj) {
android_view_InputChannel_setNativeInputChannel(env, inputChannelObj,
nativeInputChannel.release());
}
return inputChannelObj;
}
//frameworks\base\core\jni\android_view_InputChannel.cpp
static void android_view_InputChannel_setNativeInputChannel(JNIEnv* env, jobject inputChannelObj,
NativeInputChannel* nativeInputChannel) {
//将NativeInputChannel对象指针复制给InputChannel中mPtr
env->SetLongField(inputChannelObj, gInputChannelClassInfo.mPtr,
reinterpret_cast<jlong>(nativeInputChannel));
}
C++层创建一对InputChannel时序图如下:
4. Server端监听
上一小节介绍了Server端创建一对InputChannel,本节主要分析sever端添加socket监听。Server监听流程分析止于Looper方法中addFd方法。我们会简要的介绍下addFd方法的作用现在从第一部开始分析:
step 1: 获取Server端InputChannel对应的native层InputChannel实例。
//frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp
static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
jlong ptr, jobject inputChannelObj, jint displayId) {
//step 1:获取native层的NativeManager
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
//step 1:获取java层对应的native层InputChannel
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
//step 2:注册InputChannel
status_t status = im->registerInputChannel(env, inputchannel, displayId)
}
//frameworks\base\core\jni\android_view_InputChannel.cpp
sp<InputChannel> android_view_InputChannel_getInputChannel(JNIEnv* env, jobject inputChannelObj) {
NativeInputChannel* nativeInputChannel =
android_view_InputChannel_getNativeInputChannel(env, inputChannelObj);
return nativeInputChannel != NULL ? nativeInputChannel->getInputChannel() : NULL;
}
//frameworks\base\core\jni\android_view_InputChannel.cpp
//获取java层InputChannel对用的native层NativeInputChannel
static NativeInputChannel* android_view_InputChannel_getNativeInputChannel(JNIEnv* env,
jobject inputChannelObj) {
jlong longPtr = env->GetLongField(inputChannelObj, gInputChannelClassInfo.mPtr);
return reinterpret_cast<NativeInputChannel*>(longPtr);
}
step 2: 注册InputChannel,注册InputChannel主要有两部分工作:
- 封装Connection,负责事件发送:server端InputChannel的封装类。后续会根据激活窗口获取对应的Connection实例,将事件分发到客户进程。
- 将Server端InputChannel添加到Looper中,负责事件接收。后续Client端事件处理完会发finish信号,会调用handleReceiveCallback()方法进行Server端事件清理工作。
后续Server端事件发送,Client端事件接收两个章节会涉及,这两个流程非常重要。
//frameworks\base\services\core\jni\com_android_server_input_InputManagerService.cpp
status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
const sp<InputChannel>& inputChannel, int32_t displayId) {
ATRACE_CALL();
return mInputManager->getDispatcher()->registerInputChannel(
inputChannel, displayId);
}
//frameworks\native\services\inputflinger\InputDispatcher.cpp
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
int32_t displayId) {
{ // acquire lock
std::scoped_lock _l(mLock);
if (getConnectionIndexLocked(inputChannel) >= 0) {
ALOGW("Attempted to register already registered input channel '%s'",
inputChannel->getName().c_str());
return BAD_VALUE;
}
// 1. 封装Connection,
sp<Connection> connection = new Connection(inputChannel, false /*monitor*/);
int fd = inputChannel->getFd();
mConnectionsByFd.add(fd, connection);
mInputChannelsByToken[inputChannel->getToken()] = inputChannel;
//2. 使用Looper机制,监听fd对应Client的输入
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
// Wake the looper because some connections have changed.
mLooper->wake();
return OK;
}
Server端InputChannel注册流程图如下所示:
5. Client事件监听
Step 1:将Server端生成的InputChannel拷贝返回Client端。
主要通过transerTo()和writeToParcel()进行数据拷贝,实现核心代码均在native层,因为篇幅的原因,这里不做分析。
//frameworks\base\services\core\java\com\android\server\wm\WindowState.java
void openInputChannel(InputChannel outInputChannel) {
...
if (outInputChannel != null) {
//拷贝
mClientChannel.transferTo(outInputChannel);
mClientChannel.dispose();
mClientChannel = null;
} else {
...
}
...
}
//frameworks\base\core\java\android\view\InputChannel.java
//复写writeToParcel,将Server端生成的InputChannel拷贝,并序列化返回客户端
public void writeToParcel(Parcel out, int flags) {
if (out == null) {
throw new IllegalArgumentException("out must not be null");
}
//native层拷贝
nativeWriteToParcel(out);
if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0) {
dispose();
}
}
Step 2: 第二节介绍addToDisplay()远程调用,现在分析AIDL返回后Client端对Server端传回的InputChannel进行处理。
//frameworks\base\core\java\android\view\ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
mTempInsets);
...
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
//对返回的InputChannel封装成WindowInputReceiver
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
...
}
//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);
...
}
//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) {
//添加客户端socket fd epoll监听。
//Clien端Looper一直在进行消息队列循环读取,循环都会通过epoll_wait获取数据
mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
} else {
mMessageQueue->getLooper()->removeFd(fd);
}
}
}
Looper的addFd方法这里暂不做分析,后续分析Looper的时候会详细分析addFd内部逻辑。这里简要介绍下addFd的内部逻辑:使用epoll_ctl方法对socket fd进行监听。Server端发送事件,客户端通过epoll_wait获取到事件,通过handleEvent方法将事件上抛到native 层NativeInputEventReceiver,后续Client事件接收会详细的描述这个流程。
Client端添加事件监听流程如下:
可以看出Server和Client端进行事件监听都是通过Looper中的addFd方法实现的。
二、事件分发
InputManagerService源码分析二分析了InputReader处理新增、删除设备事件。本节我们分析InputReader另外一种类型:输入设备数据。
2.1 设备介绍
分析之前先介绍下我这边的输入设备:蝙蝠2游戏手柄
2.1.1 手柄信息
Device 2: HJC Game BETOP BFM GAMEPAD
Generation: 6
IsExternal: true
AssociatedDisplayPort: 0
HasMic: false
Sources: 0x01000511
KeyboardType: 1
Motion Ranges:
...
//按键
Keyboard Input Mapper:
Parameters:
OrientationAware: false
HandlesKeyRepeat: false
KeyboardType: 1
Orientation: 0
KeyDowns: 0 keys currently down
MetaState: 0x0
DownTime: 4930839688000
//遥感
Joystick Input Mapper:
...
2.1.2 按压日志(getEvent)
从设备信息我们可以看出我们的游戏手柄支持按键、和遥感操作,我们这里以游戏手柄按键分析事件分发。通过getevent命令捕获到我们手边B键按压一次的日志如下:
zhangmajian:~ zhangmajian$ adb shell getevent -l
add device 1: /dev/input/event0
name: "Semidrive Safe TouchScreen"
add device 2: /dev/input/event2
name: "HJC Game BETOP BFM GAMEPAD"
add device 3: /dev/input/event1
name: "Semidrive Safe TouchScreen"
//按压
/dev/input/event2: EV_MSC MSC_SCAN 00090002
/dev/input/event2: EV_KEY BTN_EAST DOWN
/dev/input/event2: EV_SYN SYN_REPORT 00000000
//抬起
/dev/input/event2: EV_MSC MSC_SCAN 00090002
/dev/input/event2: EV_KEY BTN_EAST UP
/dev/input/event2: EV_SYN SYN_REPORT 00000000
2.1.3 按压日志分析(InputManagerService)
对应于android端日志(含自己添加,仅包含按下,抬起未列)显示如下:
//Step 1:InputReader线程处理事件
08-25 17:24:55.900 2640-2871/? D/InputReader: BatchSize: 3 Count: 3
Input event: device=2 type=0x0004 code=0x0004 value=0x00090002 when=6413385826000
Input event: device=2 type=0x0001 code=0x0131 value=0x00000001 when=6413385826000
Input event: device=2 type=0x0000 code=0x0000 value=0x00000000 when=6413385826000
//Step 2:InputDispatcher线程处理事件
08-25 17:24:55.900 2640-2871/? D/InputDispatcher: notifyKey - eventTime=6413385826000, deviceId=2, source=0x501, displayId=0policyFlags=0x1, action=0x0, flags=0x8, keyCode=0x61, scanCode=0x131, metaState=0x0, downTime=6413385826000
08-25 17:24:55.901 2640-2870/? D/InputDispatcher: Resetting ANR timeouts.
dispatchKeyLocked dropReason: 0
dispatchKey - eventTime=6413385826000, deviceId=2, source=0x501, displayId=0, policyFlags=0x62000001, action=0x0, flags=0x8, keyCode=0x61, scanCode=0x131, metaState=0x0, repeatCount=0, downTime=6413385826000
08-25 17:24:55.915 2640-2870/? D/InputDispatcher: dispatchKeyLocked dropReason: 0
dispatchKeyLocked
// 获取当前可以分发的Window
findFocusedWindow finished: injectionResult=0, timeSpentWaitingForApplication=0.0ms
dispatchKeyLocked injectionResult: 0
dispatchEventToCurrentInputTargets
channel '1d2cd74 com.android.launcher3/com.android.launcher3.Launcher (server)' ~ prepareDispatchCycle - flags=0x00000101, xOffset=0.000000, yOffset=0.000000, globalScaleFactor=1.000000, windowScaleFactor=(1.000000, 1.000000), pointerIds=0x0
channel '1d2cd74 com.android.launcher3/com.android.launcher3.Launcher (server)' ~ startDispatchCycle
//Server端分发:目的是用户端可以收到
08-25 17:24:55.915 2640-2870/? D/InputTransport: channel '1d2cd74 com.android.launcher3/com.android.launcher3.Launcher (server)' publisher ~ publishKeyEvent: seq=2527, deviceId=2, source=0x501, action=0x0, flags=0x8, keyCode=97, scanCode=305, metaState=0x0, repeatCount=0,downTime=6413385826000, eventTime=6413385826000
channel '1d2cd74 com.android.launcher3/com.android.launcher3.Launcher (server)' ~ sent message of type 1
//Step 4:Server端分发:目的是全局监听listener可以收到
08-25 17:24:55.915 2640-2870/? D/InputDispatcher: channel 'PointerEventDispatcher0 (server)' ~ prepareDispatchCycle - flags=0x00000100, xOffset=0.000000, yOffset=0.000000, globalScaleFactor=1.000000, windowScaleFactor=(1.000000, 1.000000), pointerIds=0x0
channel 'PointerEventDispatcher0 (server)' ~ startDispatchCycle
08-25 17:24:55.915 2640-2870/? D/InputTransport: channel 'PointerEventDispatcher0 (server)' publisher ~ publishKeyEvent: seq=2528, deviceId=2, source=0x501, action=0x0, flags=0x8, keyCode=97, scanCode=305, metaState=0x0, repeatCount=0,downTime=6413385826000, eventTime=6413385826000
...
08-25 17:24:55.915 2640-2870/? D/InputTransport: channel 'PointerEventDispatcher0 (server)' ~ sent message of type 1
2.2 事件解析
Step 1: InputReader线程收到事件,进行事件解析,封装传送到InputDispatcher
1.1:在processEventsLocked方法中识别输入设备输入事件:
//frameworks\native\services\inputflinger\InputReader.cpp
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
for (const RawEvent* rawEvent = rawEvents; count;) {
int32_t type = rawEvent->type;
size_t batchSize = 1;
if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
int32_t deviceId = rawEvent->deviceId;
while (batchSize < count) {
if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
|| rawEvent[batchSize].deviceId != deviceId) {
break;
}
batchSize += 1;
}
#if DEBUG_RAW_EVENTS
ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
...
}
//确保一次按压只会调用一次processEventsForDeviceLocked方法
count -= batchSize;
rawEvent += batchSize;
}
}
1.2 :根据设备id获取对应的InputDevice(设备挂载的时候会封装InputDevice,包含事件可以接收的实体Mapper)
//frameworks\native\services\inputflinger\InputReader.cpp
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
#if DEBUG_RAW_EVENTS
ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64,
rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
rawEvent->when);
#endif
if (mDropUntilNextSync) {
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
mDropUntilNextSync = false;
#if DEBUG_RAW_EVENTS
ALOGD("Recovered from input event buffer overrun.");
#endif
} else {
#if DEBUG_RAW_EVENTSA
ALOGD("Dropped input event while waiting for next input sync.");
#endif
}
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
ALOGI("Detected input event buffer overrun for device %s.", getName().c_str());
mDropUntilNextSync = true;
reset(rawEvent->when);
} else {
for (InputMapper* mapper : mMappers) {
//设备添加的时候会解析,本例中设备包含KeyboardInputMapper和JoystickInputMapper,这里按键只需分析KeyboardInputMapper
mapper->process(rawEvent);
}
}
--count;
}
}
1.3: 事件解析、封装传送到InputDispatcher
//frameworks\native\services\inputflinger\InputReader.cpp
void KeyboardInputMapper::process(const RawEvent* rawEvent) {
switch (rawEvent->type) {
case EV_KEY: {
int32_t scanCode = rawEvent->code;
int32_t usageCode = mCurrentHidUsage;
mCurrentHidUsage = 0;
if (isKeyboardOrGamepadKey(scanCode)) {
processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);
}
break;
}
case EV_MSC: {
if (rawEvent->code == MSC_SCAN) {
mCurrentHidUsage = rawEvent->value;
}
break;
}
case EV_SYN: {
if (rawEvent->code == SYN_REPORT) {
mCurrentHidUsage = 0;
}
}
}
}
//frameworks\native\services\inputflinger\InputReader.cpp
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
int32_t usageCode) {
int32_t keyCode;
int32_t keyMetaState;
uint32_t policyFlags;
//键盘映射,这里暂不做分析
if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState,
&keyCode, &keyMetaState, &policyFlags)) {
keyCode = AKEYCODE_UNKNOWN;
keyMetaState = mMetaState;
policyFlags = 0;
}
...
//事件封装将事件传送到InputDiapatcher
NotifyKeyArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
getDisplayId(), policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
getListener()->notifyKey(&args);
}
Step 2: InputDispatcher事件处理。主要有两个工作:
- JNI调用java层InputManagerService做全局事件处理。后续2.3节分析。
- 将事件封装成KeyEntry压入队列,InputDispatcher线程轮询处理。后续2.4节分析。
//frameworks\native\services\inputflinger\InputDispatcher.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("notifyKey - eventTime=%" PRId64
", deviceId=%d, source=0x%x, displayId=%" PRId32 "policyFlags=0x%x, action=0x%x, "
"flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64,
args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
args->action, args->flags, args->keyCode, args->scanCode,
args->metaState, args->downTime);
#endif
...
//封装成KeyEvent
KeyEvent event;
event.initialize(args->deviceId, args->source, args->displayId, args->action,
flags, keyCode, args->scanCode, metaState, repeatCount,
args->downTime, args->eventTime);
android::base::Timer t;
//通过JNI调用Java InputManagerService。
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
...
bool needWake;
{ // acquire lock
mLock.lock();
...
//封装成KeyEntry
KeyEntry* newEntry = new KeyEntry(args->sequenceNum, args->eventTime,
args->deviceId, args->source, args->displayId, policyFlags,
args->action, flags, keyCode, args->scanCode,
metaState, repeatCount, args->downTime);
//压入队列中,InputDispatcher线程轮询会做事件分发,分发给Server,继而分发给Client
needWake = enqueueInboundEventLocked(newEntry);
mLock.unlock();
} // release lock
...
}
//frameworks\native\services\inputflinger\InputDispatcher.cpp
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.isEmpty();
//将事件封装的对象压入队列
mInboundQueue.enqueueAtTail(entry);
traceInboundQueueLengthLocked();
...
}
2.3 全局事件分发
JNI调用java层InputManagerService方法interceptKeyBeforeQueueing,最终调用PhoneWindowManager(有些可以是CarWindowManager)interceptKeyBeforeQueueing方法。interceptKeyBeforeQueueing方法中我们主要做一些全局处理,有些已知的按键功能(显示最近后台、调节音量、来电拒接)是在这一层级处理,或者调用到系统应用(比如SystemUI)处理的。
参考系统方案,系统全局按键可以在PhoneWindowManager做处理。最近车载项目有个方控需求(系统上层拦截方控按键,将按键广播给各个应用,各个应用做各自处理)就是在PhoneWindowManager客制化的,部分代码如下所示。
frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
if (!mSystemBooted) {
// If we have not yet booted, don't let key events do anything.
return 0;
}
if (mSaicInputManager.isInterceptHardKey(event)) {
Log.i(SaicInputManager.TAG, "interceptKeyBeforeQueueing");
return 0;
}
...
}
全局按键事件流程图如下所示:
2.4 Server端事件分发
android系统通过socketpair创建一对无名的、相互连接的套接子:Client端发送,Server端接口。因为android系统使用了双向通信,所以互为client端、server端。为了避免歧义,本节所指的Server端事件分发是指:在android系统System_process进程内部的socket发送(发送给客户进程)和接收(接受客户进程处理事件的结果)。
下面主要介绍Server端事件分发的简要步骤:
step 1: 获取压入队列的事件
//frameworks\native\services\inputflinger\InputDispatcher.cpp
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
if (! mPendingEvent) {
if (mInboundQueue.isEmpty()) {
...
} else {
// Inbound queue has at least one entry.
//获取mInboundQueue头事件
mPendingEvent = mInboundQueue.dequeueAtHead();
traceInboundQueueLengthLocked();
}
...
switch (mPendingEvent->type) {
...
case EventEntry::TYPE_KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
...
ALOGD("dispatchKeyLocked dropReason"+dropReason);
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
case EventEntry::TYPE_MOTION: {
...
}
default:
ALOG_ASSERT(false);
break;
}
...
}
//frameworks\native\services\inputflinger\InputDispatcher.cpp
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
...
// Identify targets.
std::vector<InputTarget> inputTargets;
//step 2 :获取当前获取焦点的Window
int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime);
if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
return false;
}
setInjectionResult(entry, injectionResult);
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
return true;
}
// step 3:添加屏幕全局监听
addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry));
// step 4、5、6: 事件分发
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
step 2: 检索事件需要发送的客户Window并封装成InputTarget对象
//frameworks\native\services\inputflinger\InputDispatcher.cpp
int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
const EventEntry* entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
int32_t injectionResult;
std::string reason;
int32_t displayId = getTargetDisplayId(entry);
sp<InputWindowHandle> focusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
sp<InputApplicationHandle> focusedApplicationHandle =
getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
...
// Success! Output targets.
injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
//封装InputTarget,添加到inputTargets中
//后续事件压入事件处理队列涉及到:属性值InputTarget::FLAG_DISPATCH_AS_IS判断
addWindowTargetLocked(focusedWindowHandle,
InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),
inputTargets);
// Done.
Failed:
Unresponsive:
...
#if DEBUG_FOCUS
ALOGD("findFocusedWindow finished: injectionResult=%d, "
"timeSpentWaitingForApplication=%0.1fms",
injectionResult, timeSpentWaitingForApplication / 1000000.0);
#endif
return injectionResult;
}
//frameworks\native\services\inputflinger\InputDispatcher.cpp
void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds, std::vector<InputTarget>& inputTargets) {
sp<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken());
if (inputChannel == nullptr) {
ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str());
return;
}
const InputWindowInfo* windowInfo = windowHandle->getInfo();
InputTarget target;
target.inputChannel = inputChannel;
target.flags = targetFlags;
target.xOffset = - windowInfo->frameLeft;
target.yOffset = - windowInfo->frameTop;
target.globalScaleFactor = windowInfo->globalScaleFactor;
target.windowXScale = windowInfo->windowXScale;
target.windowYScale = windowInfo->windowYScale;
target.pointerIds = pointerIds;
inputTargets.push_back(target);
}
step 3: 添加全局监听,可做系统级的事件处理比如: 负一屏、全局手势操作
//frameworks\native\services\inputflinger\InputDispatcher.cpp
void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets,
int32_t displayId, float xOffset, float yOffset) {
std::unordered_map<int32_t, std::vector<Monitor>>::const_iterator it =
mGlobalMonitorsByDisplay.find(displayId);
if (it != mGlobalMonitorsByDisplay.end()) {
const std::vector<Monitor>& monitors = it->second;
for (const Monitor& monitor : monitors) {
addMonitoringTargetLocked(monitor, xOffset, yOffset, inputTargets);
}
}
}
//frameworks\native\services\inputflinger\InputDispatcher.cpp
void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor,
float xOffset, float yOffset, std::vector<InputTarget>& inputTargets) {
InputTarget target;
target.inputChannel = monitor.inputChannel;
//将属性设置为FLAG_DISPATCH_AS_IS,后续Step 5事件进入队列会涉及
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
target.xOffset = xOffset;
target.yOffset = yOffset;
target.pointerIds.clear();
target.globalScaleFactor = 1.0f;
inputTargets.push_back(target);
}
从代码中可以看出有一个mGlobalMonitorsByDisplay对象,它的添加逻辑可参考Server端事件监听一节。受篇幅限制这里暂不做赘述。
step 4: 获取Connection
//frameworks\native\services\inputflinger\InputDispatcher.cpp
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const std::vector<InputTarget>& inputTargets) {
ATRACE_CALL();
#if DEBUG_DISPATCH_CYCLE
ALOGD("dispatchEventToCurrentInputTargets");
#endif
...
//遍历inputTargets:包括当前foucus的窗口和全局监听的
for (const InputTarget& inputTarget : inputTargets) {
//遍历获取InputTarget对应的Server端存储Connection,
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
//Step 5: 事件分发
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
} else {
#if DEBUG_FOCUS
ALOGD("Dropping event delivery to target with channel '%s' because it "
"is no longer registered with the input dispatcher.",
inputTarget.inputChannel->getName().c_str());
#endif
}
}
}
//frameworks\native\services\inputflinger\InputDispatcher.cpp
ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {
if (inputChannel == nullptr) {
return -1;
}
for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
sp<Connection> connection = mConnectionsByFd.valueAt(i);
if (connection->inputChannel->getToken() == inputChannel->getToken()) {
return i;
}
}
return -1;
}
step 5: 事件压入队列
介绍Step 4时候,我们提及了 prepareDispatchCycleLocked这个方法,该方法内的主要方法为enqueueDispatchEntriesLocked,代码如下。现在就以enqueueDispatchEntriesLocked为使介绍事件分发。
//frameworks\native\services\inputflinger\InputDispatcher.cpp
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
...
bool wasEmpty = connection->outboundQueue.isEmpty();
// Enqueue dispatch entries for the requested modes.
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
//全局监听和Focus的window对应的InputTarget属性为FLAG_DISPATCH_AS_IS,
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_IS);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
// If the outbound queue was previously empty, start the dispatch cycle going.
if (wasEmpty && !connection->outboundQueue.isEmpty()) {
startDispatchCycleLocked(currentTime, connection);
}
}
//frameworks\native\services\inputflinger\InputDispatcher.cpp
void InputDispatcher::enqueueDispatchEntryLocked(
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
int32_t dispatchMode) {
...
int32_t inputTargetFlags = inputTarget->flags;
//不满足flag直接返回,不会新增DispatchEntry压入outboundQueue队列
if (!(inputTargetFlags & dispatchMode)) {
return;
}
inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode;
// This is a new event.
// Enqueue a new dispatch entry onto the outbound queue for this connection.
DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref
inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
inputTarget->globalScaleFactor, inputTarget->windowXScale,
inputTarget->windowYScale);
...
// Enqueue the dispatch entry.
connection->outboundQueue.enqueueAtTail(dispatchEntry);
}
enqueueDispatchEntryLocked方法将需要分发的事件封装成DispatchEntry,添加到队列outboundQueue末尾。outboundQueue不为空,接着进入Step 6事件发送。
step 6: 事件发送
startDispatchCycleLocked方法最终调用socket api将事件发送到Server端对应的句柄fd。
//frameworks\native\services\inputflinger\InputDispatcher.cpp
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
...
while (connection->status == Connection::STATUS_NORMAL
&& !connection->outboundQueue.isEmpty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.head;
dispatchEntry->deliveryTime = currentTime;
// Publish the event.
status_t status;
EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
case EventEntry::TYPE_KEY: {
KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
// sd add start for multidisplay emulator input
if(mIsEmulator && keyEntry->displayId == 0)
mShouldSwitchDisplay = true;
// sd add end
// 调用Connection内部的publishKeyEvent将事件发送到Server端对应的fd
status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
keyEntry->deviceId, keyEntry->source, keyEntry->displayId,
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
keyEntry->keyCode, keyEntry->scanCode,
keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
keyEntry->eventTime);
break;
}
case EventEntry::TYPE_MOTION: {
...
}
default:
ALOG_ASSERT(false);
return;
}
// Check the result.
if (status) {
...
}
//出队列
connection->outboundQueue.dequeue(dispatchEntry);
traceOutboundQueueLength(connection);
//将需要等待处理结果的事件压入waitQueue,后续客户端事件处理完成后会将处理完的事件出队列
connection->waitQueue.enqueueAtTail(dispatchEntry);
traceWaitQueueLength(connection);
}
//frameworks\native\libs\input\InputTransport.cpp
status_t InputChannel::sendMessage(const InputMessage* msg) {
const size_t msgLength = msg->size();
InputMessage cleanMsg;
...
ssize_t nWrite;
do {
//socket通讯
nWrite = ::send(mFd, &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
if (nWrite < 0) {
...
}
...
return OK;
}
step 6: 接受客户端事件处理的结果
事件处理完了会调用Looper的pollOnce方法,读取事件的处理结果。
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{
//
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}
...
}
...
//获取队列中已经处理完成的事件
mLooper->pollOnce(timeoutMillis);
}
server端事件分发流程图如下所示
看时序图有点绕,可以结合类图方便类与类之间的关系,sever端事件分发设计到的类图如下所示:
2.3 Client端事件接收
Step 1: 读取Server端发送的事件
第一章第5节Client注册 简要的介绍了Looper的addFd方法的作用,这一节主要介绍Server端发送事件后,Client接收事件的逻辑。由handleEvent方法开始(Looper核心逻辑,这里咱不做介绍):
//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;
}
...
ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
"events=0x%x", getInputChannelName().c_str(), events);
return 1;
}
//frameworks\base\core\jni\android_view_InputEventReceiver.cpp
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
...
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 (status) {
...
assert(inputEvent);
if (!skipCallbacks) {
...
jobject inputEventObj;
switch (inputEvent->getType()) {
case AINPUT_EVENT_TYPE_KEY:
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Received key event.", getInputChannelName().c_str());
}
//事件封装
inputEventObj = android_view_KeyEvent_fromNative(env,
static_cast<KeyEvent*>(inputEvent));
break;
case AINPUT_EVENT_TYPE_MOTION: {
...
break;
}
default:
assert(false); // InputConsumer should prevent this from ever happening
inputEventObj = NULL;
}
if (inputEventObj) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName().c_str());
}
//Step 2: 调用Java层方法,进入View事件分发逻辑
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;
}
}
...
}
}
从代码中可以看到事件读取主要是调用了InputConsumer的consume方法,他最终也是调用socket recv方法实现。
Step 2: 将读取的事件上抛到Java层进行View的事件分发
dispatchInputEvent方法这里不做介绍,一般面试会涉及的View的事件分发开始于这一步。
Step 3: 事件处理结束将事件处理结果发送给Server端
View事件分发完成,会将处理结果发送给Server端。Server端会通过Looper的pollOnce方法获取,今儿进行事件清理工作。View结果发送使用了InputConsusmer的sendFinishedSignal方法,最终调用了socket API send方法将事件发送给Server端。
//frameworks\base\core\jni\android_view_InputEventReceiver.cpp
status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Finished input event.", getInputChannelName().c_str());
}
status_t status = mInputConsumer.sendFinishedSignal(seq, handled);
if (status) {
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;
}
Client端接收事件时序图如下所示:
总结
InputManagerService事件分发,到这里就结束了,仍留有不少问题未分析:
- [1 ] focus窗口的切换
- [2] Looper addFd监听方法、和pollOnce方法分析
- [3] 事件处理完后Server端对waitQueue的处理。
- [4] View事件分发,怎样将事件分发到各个View的。
- [5] 按键映射
从这里可以看出Input系统是相当复杂的,后续会通过其他章节分析存疑的问题[1][2]。其他问题后续有合适的时机亦会如此。