Android输入系统源码分析(下)

52 阅读24分钟

上一篇Android输入系统源码分析(上) 主要讲述了输入事件的读取和分发,这里接着分析事件的接受,处理完的回传和事件ANR的流程。

5.App窗口接受事件以及传递到View/Activity

前面的章节已经分析的输入事件的读取和在server端的分发,分发最终调用的是socket发送数据。接下来我们从App窗口的初始化流程分析,重点关注于输入事件有关的api调用。稍微跟进一下App窗口的初始化逻辑,就会发现 App窗口添加时最终都会走到 ViewRootImpl.setView. 下面的 分析就从 ViewRootImpl.setView 开始,ViewRootImpl.setView整个方法比较长,核心逻辑代码也很多,这里重点关注输入事件相关的逻辑,还是截取部分相关代码来分析

 frameworks/base/core/java/android/view/ViewRootImpl.java
 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
            int userId) {
        synchronized (this) {
            if (mView == null) {
                mView = view;

                ...
                InputChannel inputChannel = null;
                if ((mWindowAttributes.inputFeatures
                        & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                    //初始化 InputChannel
                    inputChannel = new InputChannel();//注释34
                }
                

                try {
                    ...
                    //添加窗口到ws
                    res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), userId,
                            mInsetsController.getRequestedVisibleTypes(), inputChannel, mTempInsets,
                            mTempControls, attachedFrame, compatScale);//注释35
                   ...
                } catch (RemoteException | RuntimeException e) {
                  ...
                } finally {
                   ...
                }
                ...
                if (inputChannel != null) {
                    if (mInputQueueCallback != null) {
                        mInputQueue = new InputQueue();
                        mInputQueueCallback.onInputQueueCreated(mInputQueue);
                    }
                    //初始化 事件接受的 InputEventReceiver
                    mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
                            Looper.myLooper());//注释36
                    ...
                }
                ...
                view.assignParent(this);
                ...
                // Set up the input pipeline.
                // 添加 Input 事件处理器管线
                CharSequence counterSuffix = attrs.getTitle();
                mSyntheticInputStage = new SyntheticInputStage();
                InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);//注释37
                InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                        "aq:native-post-ime:" + counterSuffix);
                InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
                InputStage imeStage = new ImeInputStage(earlyPostImeStage,
                        "aq:ime:" + counterSuffix);
                InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
                InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
                        "aq:native-pre-ime:" + counterSuffix);

                mFirstInputStage = nativePreImeStage;
                mFirstPostImeInputStage = earlyPostImeStage;
                ....
            }
        }
    }

我们先看下 App 窗口上的InputChannel 是如何初始化,以及如何关联到Server端,和InputDispatcher的事件分发关联上。

主要流程如下

graph TD
    A[ViewRootImpl.setView] --> B[注释36: 创建 WindowInputEventReceiver]
    B --> C[new WindowInputEventReceiver<br/>inputChannel, Looper.myLooper]
    
    C --> D[InputEventReceiver构造函数]
    D --> E[保存 inputChannel 和 messageQueue]
    E --> F[nativeInit初始化]
    
    F --> G[获取Native层InputChannel引用]
    G --> H[获取Native层MessageQueue引用]
    H --> I[创建NativeInputEventReceiver]
    
    I --> J[NativeInputEventReceiver::initialize]
    J --> K[setFdEvents ALOOPER_EVENT_INPUT]
    
    K --> L[注释51: 获取clientSocket的fd]
    L --> M[Looper::addFd监听clientSocket]
    M --> N[设置回调NativeInputEventReceiver]
    
    N --> O[初始化完成]
    O --> P[等待InputDispatcher发送事件]
    
    P --> Q[InputDispatcher通过serverSocket发送事件]
    Q --> R[clientSocket接收到数据]
    R --> S[Looper唤醒并调用handleEvent]
    S --> T[开始事件分发]
    
    style A fill:#e1f5ff
    style B fill:#fff4e1
    style F fill:#f3e5f5
    style M fill:#e8f5e9
    style S fill:#ffebee

5.1 App 窗口 InputChannel 初始化和关联Server

  • 注释34 初始化了一个 java 的 InputChannel
  • 注释35 开始调用添加窗口的逻辑,添加窗口的整个逻辑也比较复杂,这里先不展开了,感兴趣的可以去阅读Android窗口添加流程源码分析, 还是只关注输入事件相关的逻辑,添加窗口的逻辑会来到 WMS.addWindow,这里构建了一个 WindowState对象(每个窗口都有一个WindowState对象,WMS里存在的窗口对象),然后 调用了 win.openInputChannel(outInputChannel),这里的 outInputChannel 就是我们外面在 ViewRootImpl初始化构建的 InputChannel,即 注释34 那里的 inputChannel对象。
frameworks/base/services/core/java/com/android/server/wm/Session.java
   @Override
    public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, int userId, @InsetsType int requestedVisibleTypes,
            InputChannel outInputChannel, InsetsState outInsetsState,
            InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,
            float[] outSizeCompatScale) {
            //这里的mService即 WMS(WindowManagerService)
        return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId,
                requestedVisibleTypes, outInputChannel, outInsetsState, outActiveControls,
                outAttachedFrame, outSizeCompatScale);
    }
    
    
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
            int displayId, int requestUserId, @InsetsType int requestedVisibleTypes,
            InputChannel outInputChannel, InsetsState outInsetsState,
            InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,
            float[] outSizeCompatScale) {
        outActiveControls.set(null, false /* copyControls */);
        ...
        synchronized (mGlobalLock) {
            ...
            final WindowState win = new WindowState(this, session, client, token, parentWindow,
                    appOp[0], attrs, viewVisibility, session.mUid, userId,
                    session.mCanAddInternalSystemWindow);
            ....
            final boolean openInputChannels = (outInputChannel != null
                    && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
            if  (openInputChannels) {
                win.openInputChannel(outInputChannel);
            }
            ...
        }
        ...
        return res;
    }

继续跟进 WindowState.openInputChannel,关键代码如下

frameworks/base/services/core/java/com/android/server/wm/WindowState.java
 void openInputChannel(@NonNull InputChannel outInputChannel) {
        String name = getName();
        mInputChannel = mWmService.mInputManager.createInputChannel(name);//注释38
        mInputChannelToken = mInputChannel.getToken();
        mInputWindowHandle.setToken(mInputChannelToken);//注释39
        mWmService.mInputToWindowMap.put(mInputChannelToken, this);
        mInputChannel.copyTo(outInputChannel);//注释40
    }
  • 注释38 这里的 mInputManager 就是 我们在第二章节 IMS系统初始化 中的 InputManagerService 对象,初始化 WMS时就关联了IMS,IMS.createInputChannel 一步步调用来到 native的nativeCreateInputChannel,主要逻辑如下,
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static jobject nativeCreateInputChannel(JNIEnv* env, jobject nativeImplObj, jstring nameObj) {
    NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
    ...
    //构造Native 的 InputChannel
    base::Result<std::unique_ptr<InputChannel>> inputChannel = im->createInputChannel(name);//注释41
    
    //构造Java层的 InputChannel,并且关联Native 的 InputChannel
    jobject inputChannelObj =
            android_view_InputChannel_createJavaObject(env, std::move(*inputChannel));//注释42
    ...
    //最终返回了 clientChannel 给 App 应用端
    return inputChannelObj;//注释43
}

base::Result<std::unique_ptr<InputChannel>> NativeInputManager::createInputChannel(
        const std::string& name) {
    ATRACE_CALL();
    return mInputManager->getDispatcher().createInputChannel(name);//注释44
}

看到注释44这行代码是不是有柳暗花明又一村的感觉,我们又回到了 InputDispatcher 了,原来添加窗口时会调用 InputDispatcher::createInputChannel 创建 InputChannel(关联了socket),到这里基本就快和 4.2 InputDispatcher 事件出列分发 最后的猜想对上了。继续跟进 InputDispatcher::createInputChannel 关键代码如下:

frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::string& name) {
    

    std::unique_ptr<InputChannel> serverChannel;
    std::unique_ptr<InputChannel> clientChannel;
    //创建 InputChannel 对,一个server,一个client
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);//注释45

   ...

    { // acquire lock
        std::scoped_lock _l(mLock);
        const sp<IBinder>& token = serverChannel->getConnectionToken();
        const int fd = serverChannel->getFd();
        std::shared_ptr<Connection> connection =
                std::make_shared<Connection>(std::move(serverChannel), /*monitor=*/false,
                                             mIdGenerator);
                                             
        //添加 token 和serverClient 到 mConnectionsByToken,这样 InputDispatcher 分发事件就知道 用哪个 serverClient 了
        auto [_, inserted] = mConnectionsByToken.try_emplace(token, connection);// 注释46
       
       ...

        std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,
                                                            this, std::placeholders::_1, token);
        
        //添加 serverCleint 的 socketFd 监听,监听有数据写入(即clientServer写出数据)时,
        //会调用InputDispatcher::handleReceiveCallback,这个在后面的第6章节和第7章节会重点分析
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, sp<LooperEventCallback>::make(callback),
                       nullptr);//注释47
    } // release lock

    // Wake the looper because some connections have changed.
    mLooper->wake();
    
    return clientChannel;
}


frameworks/native/libs/input/InputTransport.cpp
status_t InputChannel::openInputChannelPair(const std::string& name,
                                            std::unique_ptr<InputChannel>& outServerChannel,
                                            std::unique_ptr<InputChannel>& outClientChannel) {
    int sockets[2];
    //创建socket对
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {//注释48
        status_t result = -errno;
        ALOGE("channel '%s' ~ Could not create socket pair.  errno=%s(%d)", name.c_str(),
              strerror(errno), errno);
        outServerChannel.reset();
        outClientChannel.reset();
        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));

    sp<IBinder> token = sp<BBinder>::make();

    android::base::unique_fd serverFd(sockets[0]);
    //serverChannel 关联 serverSocket
    outServerChannel = InputChannel::create(name, std::move(serverFd), token);//注释49

    android::base::unique_fd clientFd(sockets[1]);
    //clientChannel 关联 cleintSocket
    outClientChannel = InputChannel::create(name, std::move(clientFd), token);//注释50
    return OK;
}
  • 注释45 通过 注释48 创建了socket对,并通过注释49把 serverInputChannel 关联到 serverSocket,通过注释50把clientInputChannel关联到cleintSocket。这样就完成了serverInputChannel和clientInputChannel的创建以及关系绑定.

  • 注释46 将serverChannel和token 添加到 mConnectionsByToken 集合中,然后在4.2 InputDispatcher 事件出列分发注释30 处的 findTouchedWindowTargetsLocked 会根据 窗口的token 找到对应的 serverInputChannel,将 事件、窗口、InputChannel(socket)对 三者关联上,这样最后 注释33处调用socket发送事件就能发送到对应的窗口了。findTouchedWindowTargetsLocked 的逻辑就不展开分析,感兴趣的同学可以自行跟进源码验证。

  • 注释47 这里是将 serverInputChannel的socket的fd的输入事件ALOOPER_EVENT_INPUT添加到mLooper的监听中,这样当 clientInputChannel的 socket 写入数据时,就会唤醒这里的 handleReceiveCallback,在 第六、七章节会重点分析这里。

  • 注释41 到这里基本算完成了Native层的InputChannel的创建和初始化

  • 注释42 创建Java层的InputChannel并关联InputDispatcher返回的Native层InputChannel,详细逻辑如下

frameworks/base/core/jni/android_view_InputChannel.cpp
jobject android_view_InputChannel_createJavaObject(JNIEnv* env,
                                                   std::unique_ptr<InputChannel> inputChannel) {
    std::string name = inputChannel->getName();
    //将InputDispatcher返回的 Native层的InputChannel封装成 NativeInputChannel
    jlong ptr = android_view_InputChannel_createInputChannel(env, std::move(inputChannel));
    
    //gInputChannelClassInfo.clazz = "android/view/InputChannel"
    //gInputChannelClassInfo.mCtor = "<init>"
    //这里就是调用了Java层 InputChannel 的构造函数构造了 InputChannel 对象
    jobject javaInputChannel =
            env->NewObject(gInputChannelClassInfo.clazz, gInputChannelClassInfo.mCtor);
    if (!javaInputChannel) {
        ALOGE("Failed to create a Java InputChannel for channel %s.", name.c_str());
        return nullptr;
    }
    
    //gInputChannelClassInfo.mSetNativeInputChannel = "setNativeInputChannel"
    //调用Java层的 InputChannel.mPtr的 setNativeInputChannel 将Native层的 NativeInputChannel 的引用地址传递给 Java层的 InputChannel.mPtr
    env->CallVoidMethod(javaInputChannel, gInputChannelClassInfo.mSetNativeInputChannel, ptr);
    if (env->ExceptionOccurred()) {
        ALOGE("Failed to set native ptr to the Java InputChannel for channel %s.",
              inputChannel->getName().c_str());
        return nullptr;
    }
    return javaInputChannel;
}

  • 注释43 返回Java端的 InputChannel(关联了Native的InputChannel)给App。

再回到前面的注释38,这里将IMS刚创建 的 InputChannel关联的Native的InputChannel 又传递 ViewRootImpl窗口添加时创建的InputChannel, 这样ViewRootImpl 窗口添加setView时创建的InputChannel就能关联到InputDispatcher创建的clientInputChannel(关联了cleintSocket)。到这里,基本完成了InputChannel创建和初始化以及关联Server的逻辑。

目前App窗口端已经拿到了关联Server端的InputChannel(socket), 接下来继续分析App端是如何监听这个socket读取事件并且分发到View/Activity的。

完整初始化时序图

sequenceDiagram
    participant VR as ViewRootImpl
    participant WS as WindowSession
    participant WMS as WindowManagerService
    participant WS2 as WindowState
    participant IMS as InputManagerService
    participant NIM as NativeInputManager
    participant ID as InputDispatcher
    participant IT as InputTransport
    participant Looper as Looper
    
    Note over VR: 注释34: 创建 InputChannel
    VR->>VR: new InputChannel()
    
    Note over VR: 注释35: 添加窗口
    VR->>WS: addToDisplayAsUser(window, attrs, inputChannel)
    WS->>WMS: addWindow(session, window, attrs, outInputChannel)
    
    WMS->>WS2: new WindowState(...)
    WMS->>WS2: openInputChannel(outInputChannel) [注释38]
    
    WS2->>IMS: createInputChannel(name) [注释38]
    IMS->>NIM: createInputChannel(name) [注释41]
    NIM->>ID: getDispatcher().createInputChannel(name) [注释44]
    
    ID->>IT: openInputChannelPair(name) [注释45]
    IT->>IT: socketpair(AF_UNIX, SOCK_SEQPACKET) [注释48]
    IT->>IT: 创建serverChannel关联sockets[0] [注释49]
    IT->>IT: 创建clientChannel关联sockets[1] [注释50]
    IT-->>ID: 返回serverChannel和clientChannel
    
    ID->>ID: 创建Connection(serverChannel) [注释46]
    ID->>ID: mConnectionsByToken.put(token, connection) [注释46]
    ID->>Looper: addFd(serverFd, handleReceiveCallback) [注释47]
    ID-->>NIM: 返回clientChannel
    
    NIM->>NIM: android_view_InputChannel_createJavaObject [注释42]
    NIM->>NIM: 创建NativeInputChannel
    NIM->>NIM: 创建Java层InputChannel
    NIM->>NIM: 关联Native层到Java层
    NIM-->>IMS: 返回Java层InputChannel [注释43]
    
    IMS-->>WS2: 返回Java层InputChannel
    WS2->>WS2: mInputChannel = 返回的InputChannel
    WS2->>WS2: mInputChannelToken = mInputChannel.getToken() [注释39]
    WS2->>WS2: mInputWindowHandle.setToken(token) [注释39]
    WS2->>WS2: mInputChannel.copyTo(outInputChannel) [注释40]
    
    WS2-->>WMS: 完成
    WMS-->>WS: 返回结果
    WS-->>VR: 返回结果,inputChannel已关联clientChannel
    
    Note over VR,ID: ViewRootImpl持有clientChannel<br/>InputDispatcher持有serverChannel<br/>通过socket pair通信

5.2 APP 窗口接受事件

继续回到ViewRootImpl的setView,上面分析了注释35是如何构造InputChannel并关联到InputDispatcher中的clientSocket。

  • 注释36 初始化InputEventReceiver,传入了上面初始化的InputChannel和App主线程的Looper,关键代码如下:
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),
            mInputChannel, mMessageQueue);
    ...
}


frameworks/base/core/jni/android_view_InputEventReceiver.cpp
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject inputChannelObj, jobject messageQueueObj) {
    //获取Java层InputChannel.mPtr 引用,即Native层的InputChannel 的引用
    std::shared_ptr<InputChannel> inputChannel =
            android_view_InputChannel_getInputChannel(env, inputChannelObj);
    
    //获取Java层MessageQueue.mPtr,即Native层的MessageQueue 的引用
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    

    sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
            receiverWeak, inputChannel, messageQueue);
    //初始化
    status_t status = receiver->initialize();
    
    return reinterpret_cast<jlong>(receiver.get());
}

status_t NativeInputEventReceiver::initialize() {
    setFdEvents(ALOOPER_EVENT_INPUT);
    return OK;
}

void NativeInputEventReceiver::setFdEvents(int events) {
    if (mFdEvents != events) {
        mFdEvents = events;
        const int fd = mInputConsumer.getChannel()->getFd();
        if (events) {
            //Android 主线程的 Looper 添加对 InputChannel 的 socket的fd的监听
            mMessageQueue->getLooper()->addFd(fd, 0, events, this, nullptr);//注释51
        } else {
            mMessageQueue->getLooper()->removeFd(fd);
        }
    }
}
  • 注释51 创建InputEventReceiver的时候调用了nativeInit初始化方法,最终通过 NativeInputEventReceiver::initialize() 调用了Looper::addFd,根据之前的传参,这里便完成App主线程Native层Looper对Native层的clientInputChannel中的socket的fd的监听,当InputDispatcher中在注释33处调用serverSocket发动消息时,App主线程的Native的Looper就会被唤醒,调用回调handleEvent开始事件的分发.

接受事件完成时序图

sequenceDiagram
    participant VR as ViewRootImpl
    participant IER as WindowInputEventReceiver
    participant IER2 as InputEventReceiver
    participant JNI as JNI层
    participant NER as NativeInputEventReceiver
    participant IC as InputChannel
    participant MQ as MessageQueue
    participant Looper as Looper
    participant ID as InputDispatcher
    
    Note over VR: 注释36: 创建 WindowInputEventReceiver
    VR->>IER: new WindowInputEventReceiver(inputChannel, Looper)
    IER->>IER2: super(inputChannel, looper)
    
    IER2->>IER2: mInputChannel = inputChannel
    IER2->>IER2: mMessageQueue = looper.getQueue()
    IER2->>JNI: nativeInit(receiverWeak, inputChannel, messageQueue)
    
    JNI->>IC: android_view_InputChannel_getInputChannel
    IC-->>JNI: 返回Native层InputChannel引用
    
    JNI->>MQ: android_os_MessageQueue_getMessageQueue
    MQ-->>JNI: 返回Native层MessageQueue引用
    
    JNI->>NER: new NativeInputEventReceiver(inputChannel, messageQueue)
    NER->>NER: initialize()
    NER->>NER: setFdEvents(ALOOPER_EVENT_INPUT)
    
    NER->>IC: getChannel()->getFd()
    IC-->>NER: 返回clientSocket的fd
    
    NER->>Looper: addFd(fd, ALOOPER_EVENT_INPUT, this) [注释51]
    Looper->>Looper: 监听clientSocket的输入事件
    Looper-->>NER: 完成
    
    NER-->>JNI: 返回receiver指针
    JNI-->>IER2: 返回mReceiverPtr
    IER2-->>IER: 初始化完成
    IER-->>VR: 创建完成
    
    Note over VR,ID: 等待InputDispatcher发送事件
    
    Note over ID: InputDispatcher分发事件 [注释33]
    ID->>ID: 通过serverSocket发送InputMessage
    ID->>IC: serverSocket写入数据
    IC->>IC: socket pair传输
    IC->>IC: clientSocket接收到数据
    
    IC->>Looper: 触发ALOOPER_EVENT_INPUT事件
    Looper->>NER: handleEvent(fd, events)
    NER->>NER: InputConsumer::consume读取事件
    NER->>IER2: onInputEvent(InputEvent)
    IER2->>IER: onInputEvent(InputEvent)
    IER->>VR: 传递给InputStage处理链

5.3 APP 窗口分发事件到View/Activity

输入事件的分发入口为 NativeInputEventReceiver::handleEvent,接下来我们分析事件是如何一步步传递到View/Activity的。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, /*consumeBatches=*/false, -1, nullptr);//注释52
        return status == OK || status == NO_MEMORY ? KEEP_CALLBACK : REMOVE_CALLBACK;
    }
   ...
    return KEEP_CALLBACK;
}

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
        bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
    ...
    ScopedLocalRef<jobject> receiverObj(env, nullptr);
    bool skipCallbacks = false;
    for (;;) {
        uint32_t seq;
        InputEvent* inputEvent;
         // 读取事件
        status_t status = mInputConsumer.consume(&mInputEventFactory,
                consumeBatches, frameTime, &seq, &inputEvent);//注释53
        ...

        if (!skipCallbacks) {
            ...
            ScopedLocalRef<jobject> inputEventObj(env);
            switch (inputEvent->getType()) {
                ...
                case InputEventType::MOTION: {
                    ...
                    // 将Native层 的 MotionEvent 传递给 Java 层 的 MotionEvent
                    inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent);//注释54
                    break;
                }
                ....
            }
            ...
            if (inputEventObj.get()) {
                ...
                //调用Java 层 InputEventReceiver.dispatchInputEvent
                env->CallVoidMethod(receiverObj.get(),
                                    gInputEventReceiverClassInfo.dispatchInputEvent, seq,
                                    inputEventObj.get());//注释55
            } else {
               ...
            }
        }
    }
}


frameworks/native/libs/input/InputConsumer.cpp
status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches,
                                nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
    ALOGD_IF(DEBUG_TRANSPORT_CONSUMER,
             "channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%" PRId64,
             mChannel->getName().c_str(), toString(consumeBatches), frameTime);

    *outSeq = 0;
    *outEvent = nullptr;

    ...
    while (!*outEvent) {
        if (mMsgDeferred) {
           ...
        } else {
            // Receive a fresh message.
            android::base::Result<InputMessage> result = mChannel->receiveMessage();//注释56
            if (result.ok()) {
                mMsg = std::move(result.value());
                //往队列中添加事件
                const auto [_, inserted] =
                        mConsumeTimes.emplace(mMsg.header.seq, systemTime(SYSTEM_TIME_MONOTONIC));
                ...
            } else {
                ...
            }
        }

        switch (mMsg.header.type) {
            ....
            case InputMessage::Type::MOTION: {
                ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
                if (batchIndex >= 0) {
                    Batch& batch = mBatches[batchIndex];
                    if (canAddSample(batch, &mMsg)) {
                        batch.samples.push_back(mMsg);
                        break;
                    } 
                }
                ....
                //创建事件 MotionEvent
                MotionEvent* motionEvent = factory->createMotionEvent();
                if (!motionEvent) return NO_MEMORY;

                updateTouchState(mMsg);
                //初始化事件
                initializeMotionEvent(*motionEvent, mMsg);//注释57
                *outSeq = mMsg.header.seq;
                *outEvent = motionEvent;
                
                break;
            }
            ...
        }
    }
    return OK;
}

这里也涉及到很多事件消息的入列和出列逻辑,还有一些拦截以及异常处理流程,我们直接跳过。

  • 注释56 从cleintSocket中读取InputDispatcher中的serverSocket发送的事件数据
  • 注释57 初始化和组装读取到的事件消息到MotionEvent中
  • 注释54 将Native层 的 MotionEvent 传递给 Java 层 的 MotionEvent
  • 注释55 调用Java 层 InputEventReceiver.dispatchInputEvent,Native层调用Java层逻辑和上面的注释42 的 子流程很类似,大家可以自行去分析。

这样经过 事件也是经过了读取、组装、分发的流程,跟InputFlinger(InputReader/InputDispatcher/EventHub)中的流程基本类似,只是过程的繁简。接下来看下Java层的事件传递流程,关键代码如下:

frameworks/base/core/java/android/view/InputEventReceiver.java
// Called from native code.
@SuppressWarnings("unused")
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private void dispatchInputEvent(int seq, InputEvent event) {
    ...
    onInputEvent(event);
    ...
}


@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void onInputEvent(InputEvent event) {
    finishInputEvent(event, false);
}

InputEventReceiver.dispatchInputEvent方法直接调用 onInputEvent,onInputEvent的默认是现实 finishInputEvent,而我们 在 ViewRootImpl中初始化构造的是 WindowInputEventReceiver(注释36), WindowInputEventReceiver的实现如下:

frameworks/base/core/java/android/view/ViewRootImpl.java
final class WindowInputEventReceiver extends InputEventReceiver {
    ...
    @Override
    public void onInputEvent(InputEvent event) {
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "processInputEventForCompatibility");
        List<InputEvent> processedEvents;
        try {
            processedEvents =
                mInputCompatProcessor.processInputEventForCompatibility(event);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
        if (processedEvents != null) {
            if (processedEvents.isEmpty()) {
                // InputEvent consumed by mInputCompatProcessor
                finishInputEvent(event, true);
            } else {
                for (int i = 0; i < processedEvents.size(); i++) {
                    //事件入列
                    enqueueInputEvent(
                            processedEvents.get(i), this,
                            QueuedInputEvent.FLAG_MODIFIED_FOR_COMPATIBILITY, true);
                }
            }
        } else {
            enqueueInputEvent(event, this, 0, true);
        }
    }
    ...
}

 QueuedInputEvent enqueueInputEvent(InputEvent event,
            InputEventReceiver receiver, int flags, boolean processImmediately) {
        QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
        ...
        if (processImmediately) {
            doProcessInputEvents();
        } else {
            //异步处理,最终还是 调用  doProcessInputEvents
            scheduleProcessInputEvents();
        }
        return q;
    }
    

private void scheduleProcessInputEvents() {
    if (!mProcessInputEventsScheduled) {
        mProcessInputEventsScheduled = true;
        Message msg = mHandler.obtainMessage(MSG_PROCESS_INPUT_EVENTS);
        msg.setAsynchronous(true);//开启同步屏障
        mHandler.sendMessage(msg);//主线程looper
    }
}

void doProcessInputEvents() {
    // Deliver all pending input events in the queue.
    while (mPendingInputEventHead != null) {
        ...
        //传递事件
        deliverInputEvent(q);
    }
    ...
}

 private void deliverInputEvent(QueuedInputEvent q) {
    ...
    try {
        ...
        if (stage != null) {
            handleWindowFocusChanged();
            //传递事件
            stage.deliver(q);
        } else {
            finishInputEvent(q);
        }
    } finally {
    }
}

 public final void deliver(QueuedInputEvent q) {
            if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
                forward(q);
            } else if (shouldDropInputEvent(q)) {
                finish(q, false);
            } else {
                traceEvent(q, Trace.TRACE_TAG_VIEW);
                final int result;
                try {
                    //处理事件
                    result = onProcess(q);//注释58
                } finally {
                    Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                }
                apply(q, result);
            }
        }

拿到事件后也还是要经历入列,出列,过滤等判断,最后到注释58

  • 注释58 InputState.onProcess 处理事件,由子类去实现,子类决定是传递事件,处理事件还是结束事件。InputState 的子类有好几个,初始化在setView中的 注释37
  • 注释37 setView时初始化了好多个事件处理器InputState管线,串行处理,从后往前传递,这里我们分析下触摸事件的处理器 ViewPostImeInputStage,关键代码如下:
frameworks/base/core/java/android/view/ViewRootImpl.java
final class ViewPostImeInputStage extends InputStage {
    public ViewPostImeInputStage(InputStage next) {
        super(next);
    }

    @Override
    protected int onProcess(QueuedInputEvent q) {
        if (q.mEvent instanceof KeyEvent) {
            return processKeyEvent(q);
        } else {
            final int source = q.mEvent.getSource();
            if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
                return processPointerEvent(q);
            } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
                return processTrackballEvent(q);
            } else {
                return processGenericMotionEvent(q);
            }
        }
    }
    
    private int processPointerEvent(QueuedInputEvent q) {
        final MotionEvent event = (MotionEvent)q.mEvent;
        final int action = event.getAction();
        ...
        // to the view tree.
        //分发到 View 树
        handled = handled || mView.dispatchPointerEvent(event);//注释59
        ...
        return handled ? FINISH_HANDLED : FORWARD;
    }
}


frameworks/base/core/java/android/view/View.java
public final boolean dispatchPointerEvent(MotionEvent event) {
    if (event.isTouchEvent()) {
        return dispatchTouchEvent(event);
    } else {
        return dispatchGenericMotionEvent(event);
    }
}

frameworks/base/core/java/com/android/internal/policy/DecorView.java
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    final Window.Callback cb = mWindow.getCallback();
    //传递给Activity
    return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
            ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}

  • 注释59 到这里从EventHub读取到的事件经socket遍传递到我们的mView(DecorView), 然后再调用到DecorView.dispatchTouchEvent 这里就会到 Activity.dispatchTouchEvent,后面就是App 窗口的事件传递流程,这一块大家应该都很熟悉,就不在这里赘述了。

完整事件分发时序图

sequenceDiagram
    participant ID as InputDispatcher
    participant Socket as Socket Pair
    participant Looper as Looper
    participant NER as NativeInputEventReceiver
    participant IC as InputConsumer
    participant JNI as JNI层
    participant IER as WindowInputEventReceiver
    participant VR as ViewRootImpl
    participant Stage as InputStage
    participant VPS as ViewPostImeInputStage
    participant View as DecorView
    participant Act as Activity
    
    Note over ID: InputDispatcher分发事件 [注释33]
    ID->>Socket: serverSocket写入InputMessage
    Socket->>Socket: socket pair传输
    Socket->>Looper: clientSocket接收到数据
    
    Looper->>NER: handleEvent(fd, events) [注释52]
    NER->>NER: consumeEvents(env, false, -1) [注释52]
    
    loop 循环处理事件
        NER->>IC: consume(factory, false, frameTime) [注释53]
        IC->>Socket: receiveMessage() [注释56]
        Socket-->>IC: 返回InputMessage
        
        IC->>IC: 初始化MotionEvent [注释57]
        IC-->>NER: 返回MotionEvent和seq
        
        NER->>JNI: android_view_MotionEvent_obtainAsCopy [注释54]
        JNI-->>NER: 返回Java层MotionEvent对象
        
        NER->>IER: dispatchInputEvent(seq, event) [注释55]
    end
    
    IER->>IER: onInputEvent(event)
    IER->>IER: processInputEventForCompatibility
    IER->>VR: enqueueInputEvent(event, receiver, flags, true) [注释58]
    
    VR->>VR: doProcessInputEvents()
    VR->>VR: deliverInputEvent(q)
    VR->>Stage: stage.deliver(q)
    
    Stage->>Stage: onProcess(q) [注释58]
    Stage->>VPS: onProcess(q)
    
    VPS->>VPS: processPointerEvent(q)
    VPS->>View: mView.dispatchPointerEvent(event) [注释59]
    
    View->>View: dispatchTouchEvent(event)
    View->>Act: cb.dispatchTouchEvent(ev)
    
    Act-->>View: 返回处理结果
    View-->>VPS: 返回handled
    VPS-->>Stage: 返回FINISH_HANDLED或FORWARD
    Stage-->>VR: 完成
    VR-->>IER: 完成
    IER-->>NER: 完成

至此,InputDispatcher 分发事件到 APP的 VIewRootImpl流程已经打通了。

image.png

6.事件结束标记回传及处理

经过上面章节的分析,输入事件由EventReader从EventHub读取后传递到InputDispatcher,再由socket分发到App的窗口,而后传递到我们的View树,这样就可以正常消费事件了。但是事件消费完之后,还需要通知InputDispatcher的,这里也是 通过socket对来通知,由clientInputChannel写入数据,而后唤醒到InputDispatcher的mEpollFd的监听,下面从关键代码上捋一下这部分流程

6.1 事件结束标记回传

继续跟进 InputState.onProcess 处理流程,你会发现所有的事件处理完了都会调用 finishInputEvent,接下来从这个方法开始分析 事件结束标记的回传,关键代码如下:

frameworks/base/core/java/android/view/ViewRootImpl.java
 private void finishInputEvent(QueuedInputEvent q) {
      
       if (q.mReceiver != null) {
           // 事件结束标记回传
           q.mReceiver.finishInputEvent(q.mEvent, handled);
       } else {
           q.mEvent.recycleIfNeededAfterDispatch();
       }
       //事件对象回收
       recycleQueuedInputEvent(q);
   }
   
   
frameworks/base/core/java/android/view/InputEventReceiver.java
public final void finishInputEvent(InputEvent event, boolean handled) {
   
   if (mReceiverPtr == 0) {
       
   } else {
       int index = mSeqMap.indexOfKey(event.getSequenceNumber());
       if (index < 0) {
       } else {
           int seq = mSeqMap.valueAt(index);
           mSeqMap.removeAt(index);
           //调用native方法
           nativeFinishInputEvent(mReceiverPtr, seq, handled);
       }
   }
   event.recycleIfNeededAfterDispatch();
}


frameworks/base/core/jni/android_view_InputEventReceiver.cpp
static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jlong receiverPtr,
       jint seq, jboolean handled) {
   sp<NativeInputEventReceiver> receiver =
           reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
   //调用receiver 的 finishInputEvent
   status_t status = receiver->finishInputEvent(seq, handled);
   if (status == OK || status == WOULD_BLOCK) {
       return; // normal operation
   }
   ...
}

status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {

   Finish finish{
           .seq = seq,
           .handled = handled,
   };
   //数据入列 
   mOutboundQueue.push_back(finish);
   return processOutboundEvents();//处理数据
}



frameworks/base/core/jni/android_view_InputEventReceiver.cpp
status_t NativeInputEventReceiver::processOutboundEvents() {
   while (!mOutboundQueue.empty()) {
       //数据出列
       OutboundEvent& outbound = *mOutboundQueue.begin();
       status_t status;

       if (std::holds_alternative<Finish>(outbound)) {
           const Finish& finish = std::get<Finish>(outbound);
           //发送事件结束标记
           status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled);//注释60
       } else if (std::holds_alternative<Timeline>(outbound)) {
           const Timeline& timeline = std::get<Timeline>(outbound);
           status = mInputConsumer.sendTimeline(timeline.inputEventId, timeline.timeline);
       } else {
          
       }
       ...
       return status;
   }
   ...
   // The queue is now empty. Tell looper there's no more output to expect.
   setFdEvents(ALOOPER_EVENT_INPUT);
   return OK;
}



frameworks/native/libs/input/InputConsumer.cpp
status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {

   // Send finished signals for the batch sequence chain first.
   size_t seqChainCount = mSeqChains.size();
      

   // Send finished signal for the last message in the batch.
   // 发送结束标记,这里是按批处理,因为接受数据时也是按 批接受的,
   return sendUnchainedFinishedSignal(seq, handled);
}

status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
   InputMessage msg;
   msg.header.type = InputMessage::Type::FINISHED;
   msg.header.seq = seq;
   msg.body.finished.handled = handled;
   msg.body.finished.consumeTime = getConsumeTime(seq);
   //发送数据
   status_t result = mChannel->sendMessage(&msg); //注释61
   ....
   return result;
}

这里逻辑不是很复杂,主要是对象池的回收处理,一步步调用到Native层的finishInputEvent,然后又是 数据入列,出列,再处理数据

  • 注释60 调用了之前接收事件的 InputConsumer的sendFinishedSignal来发送数据,由于之前接收事件是一批一批接受的,这边发送接鼠标也只需要一批发送一次就可以了
  • 注释61 调用了接收数据的 clientInputChannel 的sendMessage,即clientSocket 写入了数据

完整事件结束标记回传时序图

sequenceDiagram
    participant Stage as InputStage
    participant VR as ViewRootImpl
    participant IER as InputEventReceiver
    participant JNI as JNI层
    participant NER as NativeInputEventReceiver
    participant IC as InputConsumer
    participant Socket as Socket Pair
    participant ID as InputDispatcher
    
    Note over Stage: 事件处理完成
    Stage->>VR: finishInputEvent(q, handled)
    
    VR->>VR: finishInputEvent(QueuedInputEvent q)
    VR->>IER: q.mReceiver.finishInputEvent(event, handled)
    
    IER->>IER: 查找事件序列号
    IER->>IER: 从mSeqMap获取seq
    IER->>JNI: nativeFinishInputEvent(receiverPtr, seq, handled)
    
    JNI->>NER: finishInputEvent(seq, handled)
    NER->>NER: 创建Finish对象
    NER->>NER: mOutboundQueue.push_back(Finish)
    NER->>NER: processOutboundEvents()
    
    NER->>NER: 从队列取出Finish对象
    NER->>IC: sendFinishedSignal(seq, handled) [注释60]
    
    IC->>IC: sendUnchainedFinishedSignal(seq, handled)
    IC->>IC: 构造InputMessage FINISHED类型
    IC->>Socket: mChannel->sendMessage(&msg) [注释61]
    
    Socket->>Socket: clientSocket写入InputMessage
    Socket->>Socket: socket pair传输
    Socket->>ID: serverSocket接收到数据
    
    ID->>ID: handleReceiveCallback处理结束标记
    ID->>ID: 更新Connection状态
    ID->>ID: 从waitQueue移除事件
    
    Note over Stage,ID: 事件结束标记回传完成

此时client端的数据结束标记已经通过clientSocket发送出去了,接下来看下server端(inpuDispatcher)的接收数据和处理流程。

6.2 InputDispatcher接收到事件结束标记后处理

我们回到注释47,在InputChannel初始化时,InputDispatcher 就添加了对 serverSocket的fd的监听,当 clientServer端有数据写入时,就会触发这里的回调函数 handleReceiveCallback,InputDispatcher就从这里开始处理事件结束标记,我们还是从关键代码入手分析:

frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
int InputDispatcher::handleReceiveCallback(int events, sp<IBinder> connectionToken) {
      ...
    if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
        nsecs_t currentTime = now();
        bool gotOne = false;
        status_t status = OK;
        ...
        for (;;) {
            //从serverSocket中接收数据
            Result<InputPublisher::ConsumerResponse> result =
                    connection->inputPublisher.receiveConsumerResponse();//注释62
            if (!result.ok()) {
                status = result.error().code();
                break;
            }

            if (std::holds_alternative<InputPublisher::Finished>(*result)) {
                //事件结束
                const InputPublisher::Finished& finish =
                        std::get<InputPublisher::Finished>(*result);
                //添加事件结束处理的指令到队列中
                finishDispatchCycleLocked(currentTime, connection, finish.seq, finish.handled,
                                          finish.consumeTime);//63
            } else if (std::holds_alternative<InputPublisher::Timeline>(*result)) {
                ...
            }
            gotOne = true;
        }
        if (gotOne) {
            //从队列中拿出指令处理
            runCommandsLockedInterruptable();
            if (status == WOULD_BLOCK) {
                return 1;
            }
        }

        notify = status != DEAD_OBJECT || !connection->monitor;
        
    } else {
        ...
    }
    ...
    return 0; // remove the callback
}

void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
                                                const std::shared_ptr<Connection>& connection,
                                                uint32_t seq, bool handled, nsecs_t consumeTime) {
    ...
    // Notify other system components and prepare to start the next dispatch cycle.
    auto command = [this, currentTime, connection, seq, handled, consumeTime]() REQUIRES(mLock) {
        doDispatchCycleFinishedCommand(currentTime, connection, seq, handled, consumeTime);
    };
    //指令入列
    postCommandLocked(std::move(command));
}


void InputDispatcher::doDispatchCycleFinishedCommand(nsecs_t finishTime,
                                                     const std::shared_ptr<Connection>& connection,
                                                     uint32_t seq, bool handled,
                                                     nsecs_t consumeTime) {
   ...
    // Dequeue the event and start the next cycle.
    // Because the lock might have been released, it is possible that the
    // contents of the wait queue to have been drained, so we need to double-check
    // a few things.
   
    auto entryIt = std::find_if(connection->waitQueue.begin(), connection->waitQueue.end(),
                                [seq](auto& e) { return e->seq == seq; });
     //遍历 connection->waitQueue 所有的分发事件
    if (entryIt != connection->waitQueue.end()) {//注释64
        std::unique_ptr<DispatchEntry> dispatchEntry = std::move(*entryIt);
        //从waitQueue中移除消息
        connection->waitQueue.erase(entryIt);//注释65

        const sp<IBinder>& connectionToken = connection->getToken();
        //移除记录anr 的时间
        mAnrTracker.erase(dispatchEntry->timeoutTime, connectionToken);//注释66
        ...
    }

    // Start the next dispatch cycle for this connection.
    // 开始下一个循环(若outboundQueue中还有元素)
    startDispatchCycleLocked(now(), connection);//注释67
}
  • 注释62 通过inputPublisher 从serverSocket 中读取 clientServer发送过来的数据
  • 注释63 判断接收的数据是否是事件结束的标记,如果是的话,塞入到待处理的 指令集合 mCommandQueue 中,紧接着从集合中获取指令并执行
  • 注释64 遍历connect->waitQueue中所有已分发事件,这个集合中的事件是在InputDispatcher中分发事件的方法startDispatchCycleLocked内添加的,参考注释32
  • 注释65 从connect->waitQueue 移除事件,此时才说明这个事件是处理完了的,这个集合是否为空 也是后续判断是否有ANR的依据之一
  • 注释66 擦除mAnrTracker中的ANR超时时间,这个也是在InputDispatcher中分发事件的方法:startDispatchCycleLocked内添加,参考注释32
  • 注释67 遍历完所有已分发的事件后,就开始下一个循环(如果connection-->outboundQueue中还有待分发事件),此时就又开始了事件的分发,流程就又回到了 4.2 InputDispatcher 事件出列分发

到这里,从InputState.finishInputEvent 一步步调用到Native层由clientSocket发送到InputDispatcher中的事件结束标记的接收和处理流程基本结束了,后续就会进入到下一批次是事件分发。

InputDispatcher 和 App窗口之间的交互过程如下 image.png

完整事件结束标记接收时序图

sequenceDiagram
    participant App as 应用端
    participant CSocket as clientSocket
    participant SSocket as serverSocket
    participant Looper as Looper
    participant ID as InputDispatcher
    participant IP as InputPublisher
    participant Cmd as CommandQueue
    participant Conn as Connection
    
    Note over App: 事件处理完成
    App->>CSocket: 发送FINISHED消息 [注释61]
    CSocket->>SSocket: socket pair传输
    SSocket->>Looper: 触发ALOOPER_EVENT_INPUT
    
    Note over ID: 注释47: handleReceiveCallback回调
    Looper->>ID: handleReceiveCallback(events, token)
    
    ID->>ID: 获取Connection对象
    ID->>ID: 循环读取数据
    
    loop 循环读取
        ID->>IP: receiveConsumerResponse() [注释62]
        IP->>SSocket: 从serverSocket读取InputMessage
        SSocket-->>IP: 返回InputMessage
        IP-->>ID: 返回ConsumerResponse
        
        alt 消息类型为Finished
            ID->>ID: finishDispatchCycleLocked(...) [注释63]
            ID->>ID: 创建command对象
            ID->>Cmd: postCommandLocked(command)
            Cmd->>Cmd: 添加到mCommandQueue
        else 其他类型
            ID->>ID: 处理其他消息类型
        end
    end
    
    ID->>Cmd: runCommandsLockedInterruptable()
    Cmd->>ID: doDispatchCycleFinishedCommand(...)
    
    ID->>Conn: 遍历waitQueue查找seq [注释64]
    Conn-->>ID: 返回DispatchEntry
    
    ID->>Conn: 从waitQueue移除 [注释65]
    ID->>ID: mAnrTracker.erase(...) [注释66]
    
    ID->>ID: startDispatchCycleLocked(...) [注释67]
    ID->>Conn: 检查outboundQueue
    
    alt outboundQueue有事件
        ID->>ID: 开始下一轮分发
    else outboundQueue为空
        ID->>ID: 等待新事件
    end
    
    Note over App,ID: 事件结束标记处理完成

7.ANR流程

为了规避ANR,大家都知道View树里接收事件处理逻辑时时不做耗时操作。接下来我们就从源码的角度分析一下这种ANR是如何产生和处理的。

7.1 事件分发ANR的产生

完整ANR检查流程

事件分发ANR的产生.png

整个InputDispatcher的事件分发是从 dispatchOnce 开始的,上面的章节分析了注释20出的事件分发、App窗口事件接收以及结束标记回传。但是 dispatchOnce 下面还有关于ANR判断的关键调用逻辑注释21

  • 注释21 分发完一批事件后 判断是否有ANR产生,关键代码如下:
frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
nsecs_t InputDispatcher::processAnrsLocked() {
    const nsecs_t currentTime = now();
    nsecs_t nextAnrCheck = LLONG_MAX;
    // Check if we are waiting for a focused window to appear. Raise ANR if waited too long
    //无焦点窗口的ANR
    if (mNoFocusedWindowTimeoutTime.has_value() && mAwaitedFocusedApplication != nullptr) {
        if (currentTime >= *mNoFocusedWindowTimeoutTime) {//注释68
            //ANR事件处理
            processNoFocusedWindowAnrLocked();//注释69
            mAwaitedFocusedApplication.reset();
            mNoFocusedWindowTimeoutTime = std::nullopt;
            return LLONG_MIN;
        } else {
            // Keep waiting. We will drop the event when mNoFocusedWindowTimeoutTime comes.
            nextAnrCheck = *mNoFocusedWindowTimeoutTime;
        }
    }

    // Check if any connection ANRs are due
    nextAnrCheck = std::min(nextAnrCheck, mAnrTracker.firstTimeout());
    // 事件分发时的ANR
    if (currentTime < nextAnrCheck) { // 注释70
        return nextAnrCheck;          // everything is normal. Let's check again at nextAnrCheck
    }

    // If we reached here, we have an unresponsive connection.
    std::shared_ptr<Connection> connection = getConnectionLocked(mAnrTracker.firstToken());
    if (connection == nullptr) {
        ALOGE("Could not find connection for entry %" PRId64, mAnrTracker.firstTimeout());
        return nextAnrCheck;
    }
    connection->responsive = false;
    // Stop waking up for this unresponsive connection
    mAnrTracker.eraseToken(connection->getToken());
    onAnrLocked(connection);//注释71
    return LLONG_MIN;
}

void InputDispatcher::processNoFocusedWindowAnrLocked() {
     ...
    onAnrLocked(mAwaitedFocusedApplication);//注释72
}
  • 注释68 判断当前的时候是否大于无焦点窗口ANR超时时间,如果大于,就是无焦点ANR,
  • 注释69 无焦点ANR的处理流程,这里会再次校验是否还是获取不到焦点窗口,若还是没有,则会进入真正的ANR处理流程
  • 注释70 获取mAnrTracker中最前面的事件分发(有焦点窗口)的ANR超时时间,时判断当前时间是否小于ANR超时时间,如果小于就是正常流程,大于就是事件分发ANR
  • 注释71、注释72 ANR的处理流程

看到这里大家发现没有事件分发ANR并不是严格遵守超时逻辑的,假设事件分发ANR超时时间是5秒,但是超时判断是要分发完一批事件后才会判断没有收到结束事件标记的事件队列中最前面那个事件的超时逻辑,如果超时了,就会产生ANR,如果只有一个点击事件,我们在里面直接延时10秒,点击完10秒内不做任何操作,不要再输入和分发其他事件,此时并不会产生ANR的。但是如果在10秒内再次触摸/点击就会产生ANR并弹窗告知App。

7.2 ANR消息传递到App及弹窗

完整ANR事件传递和处理流程

ANR消息传递到App及弹窗.png

接下来我们继续分析这个ANR事件是如何传递到应用并弹窗处理的。接着上面的代码继续分析

frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
//有焦点窗口无响应ANR处理流程
void InputDispatcher::onAnrLocked(const std::shared_ptr<Connection>& connection) {
   
    // Since we are allowing the policy to extend the timeout, maybe the waitQueue
    // is already healthy again. Don't raise ANR in this situation
    // 会再次校验 connection->waitQueue,
    if (connection->waitQueue.empty()) {//注释73
        ALOGI("Not raising ANR because the connection %s has recovered",
              connection->getInputChannelName().c_str());
        return;
    }
    ...
    processConnectionUnresponsiveLocked(*connection, std::move(reason));
    ...
}

void InputDispatcher::processConnectionUnresponsiveLocked(const Connection& connection,
                                                          std::string reason) {
    const sp<IBinder>& connectionToken = connection.getToken();
    std::optional<gui::Pid> pid;
    ...
    sendWindowUnresponsiveCommandLocked(connectionToken, pid, std::move(reason));
}

void InputDispatcher::sendWindowUnresponsiveCommandLocked(const sp<IBinder>& token,
                                                          std::optional<gui::Pid> pid,
                                                          std::string reason) {
    auto command = [this, token, pid, r = std::move(reason)]() REQUIRES(mLock) {
        scoped_unlock unlock(mLock);
        mPolicy.notifyWindowUnresponsive(token, pid, r);//注释74
    };
    postCommandLocked(std::move(command));
}

//无焦点窗口ANR处理流程
void InputDispatcher::onAnrLocked(std::shared_ptr<InputApplicationHandle> application) {
    std::string reason =
            StringPrintf("%s does not have a focused window", application->getName().c_str());
    updateLastAnrStateLocked(*application, reason);

    auto command = [this, app = std::move(application)]() REQUIRES(mLock) {
        scoped_unlock unlock(mLock);
        mPolicy.notifyNoFocusedWindowAnr(app);//注释75
    };
    postCommandLocked(std::move(command));
}
  • 注释73 这里还会再次校验 connection->waitQueue 是否为空,如果为空,则不认为是ANR,和 事件结束标记处理中的 注释65 关联。
  • 注释74 有焦点窗口无响应ANR处理流程
  • 注释75 无焦点窗口ANR处理流程

这里的ANR分为无焦点窗口ANR和有焦点无响应ANR,两个流程都差不多,我们以常见的有焦点无响应ANR为例进行分析,最终调用到 mPolicy.notifyWindowUnresponsive。mPolicy 是在 IMS 初始化时传入的NativeInputManager 对象

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
void NativeInputManager::notifyWindowUnresponsive(const sp<IBinder>& token,
                                                  std::optional<gui::Pid> pid,
                                                  const std::string& reason) {
#if DEBUG_INPUT_DISPATCHER_POLICY
    ALOGD("notifyWindowUnresponsive");
#endif
    ATRACE_CALL();

    JNIEnv* env = jniEnv();
    ScopedLocalFrame localFrame(env);

    jobject tokenObj = javaObjectForIBinder(env, token);
    ScopedLocalRef<jstring> reasonObj(env, env->NewStringUTF(reason.c_str()));

    env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyWindowUnresponsive, tokenObj,
                        pid.value_or(gui::Pid{0}).val(), pid.has_value(), reasonObj.get());//注释76
    checkAndClearExceptionFromCallback(env, "notifyWindowUnresponsive");
}

  • 注释76 这里调回了Java端的InputManagerService.otifyWindowUnresponsive,此时事件已经传递到Java端的IMS了,继续往下跟进,摘取了ANR事件流转相关的代码如下:
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
    // Native callback
    @SuppressWarnings("unused")
    private void notifyWindowUnresponsive(IBinder token, int pid, boolean isPidValid,
            String reason) {
        //IMS中转ANR
        mWindowManagerCallbacks.notifyWindowUnresponsive(token,
                isPidValid ? OptionalInt.of(pid) : OptionalInt.empty(), reason);
    }
    
frameworks/base/services/core/java/com/android/server/wm/InputManagerCallback.java
@Override
public void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull OptionalInt pid,
        String reason) {
    TimeoutRecord timeoutRecord = TimeoutRecord.forInputDispatchWindowUnresponsive(
            timeoutMessage(pid, reason));
    //ANR事件中转到AnrController
    mService.mAnrController.notifyWindowUnresponsive(token, pid, timeoutRecord);
}

frameworks/base/services/core/java/com/android/server/wm/AnrController.java
void notifyWindowUnresponsive(@NonNull IBinder token, @NonNull OptionalInt pid,
        @NonNull TimeoutRecord timeoutRecord) {
    try {
        timeoutRecord.mLatencyTracker.notifyWindowUnresponsiveStarted();
        if (notifyWindowUnresponsive(token, timeoutRecord)) {
            return;
        }
        ...
    } finally {
        timeoutRecord.mLatencyTracker.notifyWindowUnresponsiveEnded();
    }
}

 private boolean notifyWindowUnresponsive(@NonNull IBinder inputToken,
            TimeoutRecord timeoutRecord) {
        ...
        if (activity != null) {
            //这里最终也是调用 mService.mAmInternal.inputDispatchingTimedOut
            activity.inputDispatchingTimedOut(timeoutRecord, pid);
        } else {
            //ANR事件中转到AMS
            mService.mAmInternal.inputDispatchingTimedOut(pid, aboveSystem, timeoutRecord);
        }
        dumpAnrStateAsync(activity, windowState, timeoutRecord.mReason);
        return true;
    }

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@Override
public long inputDispatchingTimedOut(int pid, boolean aboveSystem,
        TimeoutRecord timeoutRecord) {
    //ANR事件来到 AMS
    return ActivityManagerService.this.inputDispatchingTimedOut(pid, aboveSystem,
            timeoutRecord);
}

@Override
public boolean inputDispatchingTimedOut(Object proc, String activityShortComponentName,
        ApplicationInfo aInfo, String parentShortComponentName, Object parentProc,
        boolean aboveSystem, TimeoutRecord timeoutRecord) {
    return ActivityManagerService.this.inputDispatchingTimedOut((ProcessRecord) proc,
            activityShortComponentName, aInfo, parentShortComponentName,
            (WindowProcessController) parentProc, aboveSystem, timeoutRecord);
}

 boolean inputDispatchingTimedOut(ProcessRecord proc, String activityShortComponentName,
            ApplicationInfo aInfo, String parentShortComponentName,
            WindowProcessController parentProcess, boolean aboveSystem,
            TimeoutRecord timeoutRecord) {
        try {
            ...
            if (proc != null) {
                ...
                timeoutRecord.mLatencyTracker.waitingOnAMSLockStarted();
                 //ANR事件中转 AnrHelper
                mAnrHelper.appNotResponding(proc, activityShortComponentName, aInfo,
                        parentShortComponentName, parentProcess, aboveSystem, timeoutRecord,
                        /*isContinuousAnr*/ true); //注释77
            }
            return true;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        }
    }

几经周转ANR事件来到了AMS

  • 注释77 调用 AnrHelper.appNotResponding来统一处理ANR
frameworks/base/services/core/java/com/android/server/am/AnrHelper.java
void appNotResponding(ProcessRecord anrProcess, String activityShortComponentName,
            ApplicationInfo aInfo, String parentShortComponentName,
            WindowProcessController parentProcess, boolean aboveSystem,
            TimeoutRecord timeoutRecord, boolean isContinuousAnr) {
    try {
        timeoutRecord.mLatencyTracker.appNotRespondingStarted();
        final int incomingPid = anrProcess.mPid;
        timeoutRecord.mLatencyTracker.waitingOnAnrRecordLockStarted();
        synchronized (mAnrRecords) {
            ...
            //添加anr事件(包含anr事件数据和当前ANR的应用信息)到list中
            mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo,
                    parentShortComponentName, parentProcess, aboveSystem, timeoutRecord,
                    isContinuousAnr, firstPidDumpPromise));//注释78
        }
        //开始消费ANR事件
        startAnrConsumerIfNeeded();//注释79
    } finally {
        timeoutRecord.mLatencyTracker.appNotRespondingEnded();
    }
}
    
private void startAnrConsumerIfNeeded() {
    if (mRunning.compareAndSet(false, true)) {
        new AnrConsumerThread().start();
    }
}


private class AnrConsumerThread extends Thread {
    AnrConsumerThread() {
        super("AnrConsumer");
    }

    ...

    @Override
    public void run() {
        AnrRecord r;
        while ((r = next()) != null) {
            scheduleBinderHeavyHitterAutoSamplerIfNecessary();
            final int currentPid = r.mApp.mPid;
            if (currentPid != r.mPid) { // 匹配pid
                // The process may have restarted or died.
                Slog.i(TAG, "Skip ANR with mismatched pid=" + r.mPid + ", current pid="
                        + currentPid);
                continue;
            }
            //继续分发
            r.appNotResponding(onlyDumpSelf);
        }

        mRunning.set(false);
        synchronized (mAnrRecords) {
            mProcessingPid = -1;
            // The race should be unlikely to happen. Just to make sure we don't miss.
            if (!mAnrRecords.isEmpty()) {
                //继续处理剩下的ANR 事件
                startAnrConsumerIfNeeded();
            }
        }
    }
}

 void appNotResponding(boolean onlyDumpSelf) {
    try {
        mTimeoutRecord.mLatencyTracker.anrProcessingStarted();
        //交由ProcessErrorStateRecord处理
        mApp.mErrorState.appNotResponding(mActivityShortComponentName, mAppInfo,
                mParentShortComponentName, mParentProcess, mAboveSystem,
                mTimeoutRecord, mAuxiliaryTaskExecutor, onlyDumpSelf,
                mIsContinuousAnr, mFirstPidFilePromise);//注释80
    } finally {
        mTimeoutRecord.mLatencyTracker.anrProcessingEnded();
    }
}

  • 注释78 将 InputDispatcher 传递过来的 ANR 的事件数据和当前ANR的进程信息封装到一起 并添加到集合list 中
  • 注释79 开启子线程 遍历处理所有的ANR事件,因为后面还要收集 ANR应用的调用堆栈/内存/CPU/Trace等信息,所以这里是在子线程中处理ANR事件
  • 注释80 交由ProcessErrorStateRecord.appNotResponding 在子线程开始真正处理ANR,方法 appNotResponding 的逻辑也很多,我们挑一些关键代码分析:
frameworks/base/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
 void appNotResponding(String activityShortComponentName, ApplicationInfo aInfo,
            String parentShortComponentName, WindowProcessController parentProcess,
            boolean aboveSystem, TimeoutRecord timeoutRecord,
            ExecutorService auxiliaryTaskExecutor, boolean onlyDumpSelf,
            boolean isContinuousAnr, Future<File> firstPidFilePromise) {
        ...

    final boolean isSilentAnr;
    final int pid;
    final UUID errorId;
    latencyTracker.waitingOnAMSLockStarted();

    // Build memory headers for the ANRing process.
    // 收集 ANR的内存信息
    LinkedHashMap<String, String> memoryHeaders = buildMemoryHeadersFor(pid); //注释81

    ...

    // We push the native pids collection task to the helper thread through
    // the Anr auxiliary task executor, and wait on it later after dumping the first pids
    // 收集native 信息
    Future<ArrayList<Integer>> nativePidsFuture =
            auxiliaryTaskExecutor.submit(
                () -> {
                   ...
                    return nativePids;
                });

    // For background ANRs, don't pass the ProcessCpuTracker to
    // avoid spending 1/2 second collecting stats to rank lastPids.
    StringWriter tracesFileException = new StringWriter();
    // To hold the start and end offset to the ANR trace file respectively.
    final AtomicLong firstPidEndOffset = new AtomicLong(-1);
    //构造trace file 文件 并dump trace 信息
    File tracesFile = StackTracesDumpHelper.dumpStackTraces(firstPids,
            isSilentAnr ? null : processCpuTracker, isSilentAnr ? null : lastPids,
            nativePidsFuture, tracesFileException, firstPidEndOffset, annotation,
            criticalEventLog, memoryHeaders, auxiliaryTaskExecutor, firstPidFilePromise,
            latencyTracker);// 注释82

    ...
    synchronized (mService) {
        ...
        //后台应用ANR直接kill掉
        if (isSilentAnr() && !mApp.isDebugging()) {
            mApp.killLocked("bg anr", ApplicationExitInfo.REASON_ANR, true);、、注释83
            return;
        }
        ...
        if (mService.mUiHandler != null) {
            // Bring up the infamous App Not Responding dialog
            Message msg = Message.obtain();
            msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
            msg.obj = new AppNotRespondingDialog.Data(mApp, aInfo, aboveSystem,
                    isContinuousAnr);
            // 发送消息SHOW_NOT_RESPONDING_UI_MSG 到主线程 处理
            mService.mUiHandler.sendMessageDelayed(msg, anrDialogDelayMs);//注释84
        }
    }
}

  • 注释81 收集ANR的内存信息
  • 注释82 这里是通过守护进程Debugger来收集Trace 信息并生成Trace文件,这里的细节后续会在内存优化的系列文章中讲解。
  • 注释83 如果发生ANR的进程不在前台,则直接kill掉
  • 注释84 发送 SHOW_NOT_RESPONDING_UI_MSG 类型的消息到AMS的主线程做弹窗处理,后面的逻辑就比较简单了,这里也不展开了,大家可以自行阅读源码。

8.总结

InputReader负责一直读取EventHub中监听到的设备的事件输入和事件封装,并将事件传递给InputDispatcher的队列中,而InputDispatcher则负责读取队列中的事件并通过socket传递给IMSWMS对应的窗口的ViewRootImpl绑定的InpuChannelsocket,再经由InputState进行事件的处理,InputState处理完再通过 InputChannelsocket将结束标记回传给InputDispatcher,此时InputDispatcher更新ANR标记和分发下一批事件.

这里再来一张完整的流程图

image.png