InputManagerService源码分析三:事件分发


前言

android源码晦涩、难以阅读私以为主要有以下三点:

  1. 代码内部包含很多小的内部逻辑,阅读的过程很难抓住重点。这个尚可通过精简流程,日志分析等手段来解决。
  2. 涉及到未知的知识领域。作为一个应用开发这些知识点包括:JNI、Linux操作系统API、OpenGL、Skia等。有些可以通过查找文章,解决迅速;有些就涉及到专业领域了,非专业不可达。
  3. 是涉及到其他复杂源代码阅读。以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代理时序图如下所示。
远程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主要有两部分工作:

  1. 封装Connection,负责事件发送:server端InputChannel的封装类。后续会根据激活窗口获取对应的Connection实例,将事件分发到客户进程。
  2. 将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注册流程图如下所示:
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端添加事件监听流程如下:
Client端Input监听

可以看出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事件处理。主要有两个工作:

  1. JNI调用java层InputManagerService做全局事件处理。后续2.3节分析。
  2. 将事件封装成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端事件分发流程图如下所示
Server端事件分发
看时序图有点绕,可以结合类图方便类与类之间的关系,sever端事件分发设计到的类图如下所示:
Server端事件分发关键勒图

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端接收事件时序图如下所示:
Client事件接收

总结

InputManagerService事件分发,到这里就结束了,仍留有不少问题未分析:

  • [1 ] focus窗口的切换
  • [2] Looper addFd监听方法、和pollOnce方法分析
  • [3] 事件处理完后Server端对waitQueue的处理。
  • [4] View事件分发,怎样将事件分发到各个View的。
  • [5] 按键映射
    从这里可以看出Input系统是相当复杂的,后续会通过其他章节分析存疑的问题[1][2]。其他问题后续有合适的时机亦会如此。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值