联系我们
简单又实用的WordPress网站制作教学
当前位置:网站首页 > 程序开发学习 > 正文

安卓 Input 机制(1)整体流程打通

作者:访客发布时间:2023-12-27分类:程序开发学习浏览:84


导读:前言本文目的是打通整体流程,旨在对Input系统从收到驱动数据到传递到客户端去消费的整体过程有一个整体的认识。各阶段的策略细节会在另外的文章分别讲解,以免文章过重分支过多导致混乱...

前言

本文目的是打通整体流程,旨在对Input系统从收到驱动数据到传递到客户端去消费的整体过程有一个整体的认识。各阶段的策略细节会在另外的文章分别讲解,以免文章过重分支过多导致混乱,使读者难以把握主线。

1 Input服务初始化

1Input服务初始化.png

1.1 创建并初始化IMS

InputManagerService作为Input服务存在,在SystemServer的startOtherService创建、初始化和启动。

public InputManagerService(Context context) {
    ...
    mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
    ...
}
// frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }

    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}
// frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    JNIEnv* env = jniEnv();

    mContextObj = env->NewGlobalRef(contextObj);
    mServiceObj = env->NewGlobalRef(serviceObj);

    {
        AutoMutex _l(mLock);
        mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
        mLocked.pointerSpeed = 0;
        mLocked.pointerGesturesEnabled = true;
        mLocked.showTouches = false;
        mLocked.pointerCapture = false;
    }
    mInteractive = true;

    sp<EventHub> eventHub = new EventHub();
    // NativeInputManager持有InputManager
    mInputManager = new InputManager(eventHub, this, this);
}
// frameworks/native/services/inputflinger/InputManager.cpp
InputManager::InputManager(
        const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    // 创建InputDispatcher,参数是 NativeInputManager
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    // 创建InputReader,传参EventHub NativeInputManager InputDispatcher
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
    initialize();
}
// frameworks/native/services/inputflinger/InputManager.cpp
void InputManager::initialize() {
    mReaderThread = new InputReaderThread(mReader);
    mDispatcherThread = new InputDispatcherThread(mDispatcher);
}

可以看出IMS的创建和初始化,主要创建了如下几个关键角色:

EventHub:与驱动交互,获取屏幕触摸信息数据;

InputReader:操作EventHub获取读取到的硬件触摸数据,另外与Dispatcher对接,把加工后的数据传递给Dispatcher处理;

InputReaderThread:InputReader的工作线程

InputDispatcher:接收InputReader传递的数据,与注册使用的client端通过InputChannel通信,把事件通过InputChannel传出去。

InputDispatcherThread:InputDispatcher的工作线程

1.2 启动服务

public void start() {
    Slog.i(TAG, "Starting input manager");
    nativeStart(mPtr);

    // Add ourself to the Watchdog monitors.
    // watchdog监听
    Watchdog.getInstance().addMonitor(this);
    // 这里的3个register,是注册内容观察者用以监听数据变化并对应地做更新
    // 更新动作通过调用对应updateXXX更新
    // (比如SHOW_TOUCHES对应的是Settings开发人员选项中的显示触摸点功能,切换开关会在这里触发对应监听,通知服务做处理)
    // Settings.System.POINTER_SPEED
    registerPointerSpeedSettingObserver();
    // Settings.System.SHOW_TOUCHES
    registerShowTouchesSettingObserver();
    // Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON
    registerAccessibilityLargePointerSettingObserver();

    // Intent.ACTION_USER_SWITCHED广播触发对以上三个注册的更新。
    mContext.registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            updatePointerSpeedFromSettings();
            updateShowTouchesFromSettings();
            updateAccessibilityLargePointerFromSettings();
        }
    }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
    updatePointerSpeedFromSettings();
    updateShowTouchesFromSettings();
    updateAccessibilityLargePointerFromSettings();
}
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    status_t result = im->getInputManager()->start();
    if (result) {
        jniThrowRuntimeException(env, "Input manager could not be started.");
    }
}
status_t InputManager::start() {
    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
    ...
    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
    ...
    return OK;
}

可以看出,启动IMS主要做的工作是启动了InputDispatcher和InputReader的工作线程。

小结:

本章节主要对以下三个关键角色有个第一印象即可:

  1. EventHub:与驱动交互,获取屏幕触摸信息数据;
  2. InputReader:操作EventHub获取读取到的硬件触摸数据,传递给Dispatcher;
  3. InputDispatcher:接收InputReader传递的数据,逐一分发事件给注册进来的client端。
  4. InputReaderThread和InputDispatcherThread:是两个Thread,主要任务就是循环执行业务。

2 客户端发起注册

流程如图:

2Input注册.png

Activity启动添加页面调用ViewRootImpl.setView,本文以此为入口讲解。

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    synchronized (this) {
        if (mView == null) {
            ...
            if ((mWindowAttributes.inputFeatures
                    & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                // 1 创建java层的InputChannel,此时只是个空壳
                mInputChannel = new InputChannel();
            }
            ...
            try {
                mOrigWindowType = mWindowAttributes.type;
                mAttachInfo.mRecomputeGlobalAttributes = true;
                collectViewAttributes();
                // 2 把 mInputChannel 传给WMS会有进一步操作
                res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                        getHostVisibility(), mDisplay.getDisplayId(),
                        mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                        mAttachInfo.mOutsets, mInputChannel);
            } ...
            ...
            if (mInputChannel != null) {
                if (mInputQueueCallback != null) {
                    mInputQueue = new InputQueue();
                    mInputQueueCallback.onInputQueueCreated(mInputQueue);
                }
                // 3 创建 WindowInputEventReceiver 他是服务端的input数据和客户端的交接员
                // 一方面接收服务端input数据,一方面负责将事件分发给页面消费者
                mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                        Looper.myLooper());
            }
            ...
        }
    }
}

首先在java层创建InputChannel对象,此时的InputChannel是个空壳。

然后调用mWindowSession.addToDisplay携带着InputChannel,addToDisplay最终调用到WMS的addwindow。

public int addWindow(Session session, IWindow client, int seq,
        WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
        Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
        InputChannel outInputChannel) {
    ...
    synchronized(mWindowMap) {
        ...
        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);
        }
        ...
    }
    ...
    return res;
}

接下来调WindowState的openInputChannel,入参为InputChannel空壳。(这里的WindowState在窗口系列文章中有讲,可以把他理解为当前我们添加的窗口在WMS服务端的体现,不了解的话对本文也没有太大影响,可以先忽略。)

2.1 建立客户端-服务端通信

void openInputChannel(InputChannel outInputChannel) {
    if (mInputChannel != null) {
        throw new IllegalStateException("Window already has an input channel.");
    }
    String name = getName();
    // 1 生成一对 InputChannel
    InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
    // 分别作为服务端channel
    mInputChannel = inputChannels[0];
    // 和客户端channel
    mClientChannel = inputChannels[1];
    mInputWindowHandle.inputChannel = inputChannels[0];
    if (outInputChannel != null) {
        // 2 生成的作为客户端的channel拷贝给前面我们创建的空壳InputChannel,
        // 这样ViewRootImpl处持有的InputChannel就是实实在在的InputChannel了。
        mClientChannel.transferTo(outInputChannel);
        mClientChannel.dispose();
        mClientChannel = null;
    } else { // 异常分支,省略
        ...
    }
    // 3 当前的“服务端”channel还仅仅是一个在客户端的对象,需要传递到服务端真正注册给服务端使用
    mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
}

2.1.1 创建一对 InputChannel 用于通信

public static InputChannel[] openInputChannelPair(String name) {
    ...
    return nativeOpenInputChannelPair(name);
}
static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
        jclass clazz, jstring nameObj) {
    const char* nameChars = env->GetStringUTFChars(nameObj, NULL);
    String8 name(nameChars);
    env->ReleaseStringUTFChars(nameObj, nameChars);

    sp<InputChannel> serverChannel;
    sp<InputChannel> clientChannel;
    // 1 创建一对InputChannel
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);

    ...
    // 2 生成java数组装载着两个jobject分别持有着native层InputChannel,然后返回数组给java层
    jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
    if (env->ExceptionCheck()) {
        return NULL;
    }

    jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
            std::make_unique<NativeInputChannel>(serverChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }

    jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
            std::make_unique<NativeInputChannel>(clientChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }

    env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
    env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
    return channelPair;
}
  1. 调用InputChannel::openInputChannelPair创建一对InputChannel
  2. 创建java对象分别持有他们,然后装入数组返回给java层。

openInputChannelPair:

// InputChannel.cpp
status_t InputChannel::openInputChannelPair(const String8& name,
        sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
    int sockets[2];
    // 调用socketpair函数创建一对相互连接的socket
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
        ... // 执行失败的异常处理,略
    }

    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));

    String8 serverChannelName = name;
    serverChannelName.append(" (server)");
    // 创建服务端InputChannel,持有sockets[0]
    outServerChannel = new InputChannel(serverChannelName, sockets[0]);

    String8 clientChannelName = name;
    clientChannelName.append(" (client)");
    // 创建客户端InputChannel,持有sockets[1]
    outClientChannel = new InputChannel(clientChannelName, sockets[1]);
    return OK;
}

调用socketpair函数创建一对相互连接的socket,然后创建了一对InputChannel,分别持有一个socket,一个作为客户端一个作为服务端,这样分别持有这两个InputChannel的两端就可以通过socket通信了。

返回创建的一对InputChannel

static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
        jclass clazz, jstring nameObj) {
    const char* nameChars = env->GetStringUTFChars(nameObj, NULL);
    String8 name(nameChars);
    env->ReleaseStringUTFChars(nameObj, nameChars);

    sp<InputChannel> serverChannel;
    sp<InputChannel> clientChannel;
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);

    ...
    // 生成java数组装载着两个jobject分别持有着native层InputChannel,然后返回数组给java层
    jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
    if (env->ExceptionCheck()) {
        return NULL;
    }

    jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
            std::make_unique<NativeInputChannel>(serverChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }

    jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
            std::make_unique<NativeInputChannel>(clientChannel));
    if (env->ExceptionCheck()) {
        return NULL;
    }

    env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
    env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
    return channelPair;
}

static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,
        std::unique_ptr<NativeInputChannel> nativeInputChannel) {
    jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,
            gInputChannelClassInfo.ctor);
    if (inputChannelObj) {
        android_view_InputChannel_setNativeInputChannel(env, inputChannelObj,
                 nativeInputChannel.release());
    }
    return inputChannelObj;
}

生成两个jobject分别持有native层的InputChannel,生成一个java数组装载他们,然后把数组返回给java层。

创建InputChannel完成了,接下来回到WindowState.openInputChannel处,他后续还有两个动作:

2.1.2 客户端分配InputChannel --- transferTo

public void transferTo(InputChannel outParameter) {
    if (outParameter == null) {
        throw new IllegalArgumentException("outParameter must not be null");
    }

    nativeTransferTo(outParameter);
}
// 注意是mClientChannel发起的调用,他是刚才创建的一对channel中的客户端
static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
        jobject otherObj) {
    // otherObj是那个空壳channel,这里做检查,要保证channel是“空壳”,没有持有native层channel的句柄
    if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != NULL) {
        jniThrowException(env, "java/lang/IllegalStateException",
                "Other object already has a native input channel.");
        return;
    }
    // 获取mClientChannel持有的NativeInputChannel
    NativeInputChannel* nativeInputChannel =
            android_view_InputChannel_getNativeInputChannel(env, obj);
    // 把NativeInputChannel设置给空壳channel,实际上也就是把mClientChannel“拷贝”给空壳channel
    android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);
    // 把自己置空
    android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
}

static NativeInputChannel* android_view_InputChannel_getNativeInputChannel(JNIEnv* env,
        jobject inputChannelObj) {
    jlong longPtr = env->GetLongField(inputChannelObj, gInputChannelClassInfo.mPtr);
    return reinterpret_cast<NativeInputChannel*>(longPtr);
}

可以看出transferTo就是把native层句柄做了传递,其实就是把通过openInputChannelPair创建的客户端channel拷贝给前面创建的空壳channel,使ViewRootImpl处的InputChannel就有了实权,成为真正的客户端。

2.1.3 服务端注册

看接下来的另一个调用mService.mInputManager.registerInputChannel

public void registerInputChannel(InputChannel inputChannel,
        InputWindowHandle inputWindowHandle) {
    ...
    nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
}

注意这里的入参是前面创建的服务端InputChannel,继续:

static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
        jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    if (inputChannel == NULL) {
        throwInputChannelNotInitialized(env);
        return;
    }

    sp<InputWindowHandle> inputWindowHandle =
            android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);

    status_t status = im->registerInputChannel(
            env, inputChannel, inputWindowHandle, monitor);
    ...
}
status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
        const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
    ATRACE_CALL();
    return mInputManager->getDispatcher()->registerInputChannel(
            inputChannel, inputWindowHandle, monitor);
}
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
    { // acquire lock
        AutoMutex _l(mLock);
        ...
        // 把inputChannel封装成Connection
        sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);

        int fd = inputChannel->getFd();
        // 以 fd:Connection 的结构存储
        mConnectionsByFd.add(fd, connection);

        if (monitor) {
            mMonitoringChannels.push(inputChannel);
        }
        // 注册到looper监听fd,回调为handleReceiveCallback
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock

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

实际上注册动作就是:

  1. 把InputChannel封装成Connection对象,并以 "文件描述符:Connection" 的结构存储到InputDispatcher的mConnectionsByFd容器。
  2. 注册looper监听fd

至此,InputChannel的创建和服务端注册已经完成了。回到setView的代码,继续执行,来到代码段new WindowInputEventReceiver

2.1.4 客户端接收者角色的创建和注册

final class WindowInputEventReceiver extends InputEventReceiver {
    public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
        super(inputChannel, looper);
    }
// InputEventReceiver.java
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
    ...
    mInputChannel = inputChannel;
    mMessageQueue = looper.getQueue();
    mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
            inputChannel, mMessageQueue);

    mCloseGuard.open("dispose");
}
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject inputChannelObj, jobject messageQueueObj) {
    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
            inputChannelObj);
    ...
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    ...
    sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
            receiverWeak, inputChannel, messageQueue);
    status_t status = receiver->initialize();
    ...
    receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object
    return reinterpret_cast<jlong>(receiver.get());
}

创建 NativeInputEventReceiver

NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
        jobject receiverWeak, const sp<InputChannel>& inputChannel,
        const sp<MessageQueue>& messageQueue) :
        mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
        mInputConsumer(inputChannel), mMessageQueue(messageQueue),
        mBatchedInputEventPending(false), mFdEvents(0) {
    ...
}
InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
        mResampleTouch(isTouchResamplingEnabled()),
        mChannel(channel), mMsgDeferred(false) {
}

NativeInputEventReceiver构造时创建的mInputConsumer持有mChannel

继续 initialize:

status_t NativeInputEventReceiver::initialize() {
    setFdEvents(ALOOPER_EVENT_INPUT);
    return OK;
}
void NativeInputEventReceiver::setFdEvents(int events) {
    if (mFdEvents != events) {
        mFdEvents = events;
        int fd = mInputConsumer.getChannel()->getFd();
        if (events) {
            mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
        } else {
            mMessageQueue->getLooper()->removeFd(fd);
        }
    }
}
  1. 创建了WindowInputEventReceiver 继承自 InputEventReceiver,他是服务端传递事件的接收器
  2. 它在native层创建了NativeInputEventReceiver持有mInputConsumer,mInputConsumer持有mChannel(客户端InputChannel)
  3. 把客户端channel持有的fd注册到looper监听,达成对服务端数据传输的监听

2.2 总结

(把上面的流程图拉下来,方便对照)

2Input注册.png

  1. 创建了一对相互连接的Socket,用来通信
  2. 创建了一对InputChannel,分别持有一个socket,使InputChannel成为实现两端通信的信使。
  3. 两个InputChannel分别作为客户端channel和服务端channel,服务端channel给InputDispatcher持有,客户端channel给InputEventReceiver持有。
  4. 两个socket的fd分别注册到对应端的Looper,有数据传输会唤醒对端处理。

3 事件生成与分发

3-1InputReader获取并分发.png

本文自下而上,从InputReader从驱动获得事件为起点讲起。

前文已经讲过,Input系统启动初始化时创建了几个关键角色,其中有EventHub是与驱动交互的,我们就自此讲起。

3.1 InputReader 读取、转化、传递

InputReaderThread线程启动,循环调用threadLoop

bool InputReaderThread::threadLoop() {
    mReader->loopOnce();
    return true;
}
void InputReader::loopOnce() {
    int32_t timeoutMillis;
    ...
    // 1 通过EventHub获取数据,上面已经讲解,直接获取数据mEventBuffer,数量count
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

    { // acquire lock
        AutoMutex _l(mLock);
        mReaderIsAliveCondition.broadcast();

        if (count) {
            // 2 根据获取到的数据生产客户端可用的input
            processEventsLocked(mEventBuffer, count);
        }

        ...
    } // release lock

    ...
    // 3 写数据,并唤醒InputDispatcher处理
    mQueuedListener->flush();
}

可以看到 InputReader 三大任务:

  1. 从驱动读取事件,
  2. 将驱动数据加工转化成上层使用的数据(如屏幕坐标转换等)
  3. 将数据传递给 InputDispatcher

3.1.1 事件读取

是通过调用 mEventHub->getEvents 获取的,下面就介绍一下EventHub。

前情:EventHub的创建

EventHub::EventHub(void) :
        mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
        mOpeningDevices(0), mClosingDevices(0),
        mNeedToSendFinishedDeviceScan(false),
        mNeedToReopenDevices(false), mNeedToScanDevices(true),
        mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
    acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
    mEpollFd = epoll_create(EPOLL_SIZE_HINT);

    mINotifyFd = inotify_init();
    // 1 创建inotify 监听 DEVICE_PATH 变化
    int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);

    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;
    eventItem.data.u32 = EPOLL_ID_INOTIFY;
    // 2 epoll 添加 inotify 监听DEVICE_PATH的变更
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);

    // 3 创建管道,这对管道是用来唤醒epoll_wait的
    int wakeFds[2];
    result = pipe(wakeFds);

    mWakeReadPipeFd = wakeFds[0];
    mWakeWritePipeFd = wakeFds[1];
    // 设置管道非阻塞
    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);

    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);

    eventItem.data.u32 = EPOLL_ID_WAKE;
    // 3mWakeReadPipeFd添加到epoll作为读端
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);

    int major, minor;
    getLinuxRelease(&major, &minor);
    // EPOLLWAKEUP was introduced in kernel 3.5
    mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
}

void EventHub::wake() {
    ALOGV("wake() called");

    ssize_t nWrite;
    do {
        // 3通过写管道唤醒epoll_wait
        nWrite = write(mWakeWritePipeFd, "W", 1);
    } while (nWrite == -1 && errno == EINTR);

    if (nWrite != 1 && errno != EAGAIN) {
        ALOGW("Could not write wake signal, errno=%d", errno);
    }
}

从代码中可以看出EventHub构造做了几件事情:

  1. 创建epoll
  2. 通过inotify监听DEVICE_PATH,添加到epoll事件
  3. 创建管道,一端添加给epoll,通过另一端写事件就可以唤醒epoll_wait,由wake()函数写唤醒epoll;这样的话需要唤醒epoll_wait直接调用wake函数即可。

EventHub从驱动读取 --- getEvents

分为两部分:1 检查设备状态变更相关事件,2 input事件的获取

1 检查设备状态变更相关事件

在获取事件之前,先检查是否有设备状态变更、配置变化等需要处理。

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    ALOG_ASSERT(bufferSize >= 1);

    AutoMutex _l(mLock);

    struct input_event readBuffer[bufferSize];

    RawEvent* event = buffer;
    size_t capacity = bufferSize;
    bool awoken = false;
    for (;;) {
        // 第一部分:
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);

        // Reopen input devices if needed.
        // 1 reopen处理策略就是关闭所有设备再重新扫描、添加
        if (mNeedToReopenDevices) {
            mNeedToReopenDevices = false;

            closeAllDevicesLocked();
            mNeedToScanDevices = true;
            break; // return to the caller before we actually rescan
        }

        // Report any devices that had last been added/removed.
        while (mClosingDevices) {
            // 2 有设备关闭事件发生
            // 遍历关闭设备链表mClosingDevices构建对应的RawEvent事件,并删除device
            Device* device = mClosingDevices;
            mClosingDevices = device->next;
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
            event->type = DEVICE_REMOVED;
            event += 1;
            delete device;
            mNeedToSendFinishedDeviceScan = true;
            if (--capacity == 0) {
                break;
            }
        }
        // need to reopen设置设置true,reopen的策略就是关闭所有,然后再重新扫描添加设备
        if (mNeedToScanDevices) {
            // 3 需要扫描设备
            mNeedToScanDevices = false;
            scanDevicesLocked();
            mNeedToSendFinishedDeviceScan = true;
        }

        while (mOpeningDevices != NULL) { 
            // 4 有添加设备的事件发生,生成对应event事件
            Device* device = mOpeningDevices;
            mOpeningDevices = device->next;
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
            event->type = DEVICE_ADDED;
            event += 1;
            mNeedToSendFinishedDeviceScan = true;
            if (--capacity == 0) {
                break;
            }
        }

        if (mNeedToSendFinishedDeviceScan) {
            // 生成以上设备相关事件的结束标记事件
            mNeedToSendFinishedDeviceScan = false;
            event->when = now;
            event->type = FINISHED_DEVICE_SCAN;
            event += 1;
            if (--capacity == 0) {
                break;
            }
        }

        ...
1.1 发生reopen的处理过程
        if (mNeedToReopenDevices) {
            mNeedToReopenDevices = false;

            closeAllDevicesLocked();
            mNeedToScanDevices = true;
            break; // return to the caller before we actually rescan
        }

关闭所有设备:

void EventHub::closeAllDevicesLocked() {
    while (mDevices.size() > 0) {
        closeDeviceLocked(mDevices.valueAt(mDevices.size() - 1));
    }
}

void EventHub::closeDeviceLocked(Device* device) {
    ...
    // 从epoll移除对该device的监听
    unregisterDeviceFromEpollLocked(device);

    releaseControllerNumberLocked(device);
    // 从 mDevices 中移除
    mDevices.removeItem(device->id);
    // 关闭 device
    device->close();

    Device* pred = NULL;
    bool found = false;
    // 清理 mOpeningDevices 列表,查找mOpeningDevices中是不是有该device
    for (Device* entry = mOpeningDevices; entry != NULL; ) {
        if (entry == device) {
            found = true;
            break;
        }
        pred = entry;
        entry = entry->next;
    }
    // 查找到就从 mOpeningDevices 去除
    if (found) {
        if (pred) {
            pred->next = device->next;
        } else {
            mOpeningDevices = device->next;
        }
        delete device;
    } else {
        // 加入 mClosingDevices 链表
        device->next = mClosingDevices;
        mClosingDevices = device;
    }
}
  1. epoll移除对该device的监听
  2. 从 mDevices 中移除该device
  3. 关闭 device
  4. 检查mOpeningDevices中是不是有这个待删除的device
  5. 4中查找到了就从 mOpeningDevices 去除,否则就把他加入 mClosingDevices 链表
1.2 检查close device并处理
        while (mClosingDevices) {
            // 2 有设备关闭事件发生
            // 根据关闭设备链表构建对应的RawEvent事件,删除对应的device
            Device* device = mClosingDevices;
            mClosingDevices = device->next;
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
            event->type = DEVICE_REMOVED;
            event += 1;
            delete device;
            mNeedToSendFinishedDeviceScan = true;
            if (--capacity == 0) {
                break;
            }
        }

mClosingDevices有元素就代表有close发生,这里遍历mClosingDevices链表,根据元素信息组织被关闭设备对应的event事件,并删除该元素。

1.3 检查是否扫描设备
        if (mNeedToScanDevices) {
            // 3 需要扫描设备
            mNeedToScanDevices = false;
            scanDevicesLocked();
            mNeedToSendFinishedDeviceScan = true;
        }

在EventHub创建时mNeedToScanDevices初始值为true,也就是说首次启动EventHub.getEvents就需要先扫描设备。另外在发生reopen事件时,也会设置mNeedToScanDevices为true,因为reopen就是关闭所有设备再重新扫描。

接下来就是scanDevicesLocked做了什么事情:

void EventHub::scanDevicesLocked() {
    // DEVICE_PATH: /dev/input
    status_t res = scanDirLocked(DEVICE_PATH);
    ...
    if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) {
        createVirtualKeyboardLocked();
    }
}
status_t EventHub::scanDirLocked(const char *dirname)
{
    char devname[PATH_MAX];
    char *filename;
    DIR *dir;
    struct dirent *de;
    dir = opendir(dirname);
    if(dir == NULL)
        return -1;
    strcpy(devname, dirname);
    filename = devname + strlen(devname);
    *filename++ = '/';
    // 遍历目录中的所有节点
    while((de = readdir(dir))) {
        if(de->d_name[0] == '.' &&
           (de->d_name[1] == '\0' ||
            (de->d_name[1] == '.' && de->d_name[2] == '\0')))
            continue;
        strcpy(filename, de->d_name);
        // open
        openDeviceLocked(devname);
    }
    closedir(dir);
    return 0;
}
status_t EventHub::openDeviceLocked(const char *devicePath) {
    char buffer[80];
    // 调用驱动open打开设备
    int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK);
    ...
    // 创建描述设备的Device
    Device* device = new Device(fd, deviceId, String8(devicePath), identifier);

    ...
    // 注册设备到epoll
    if (registerDeviceForEpollLocked(device) != OK) {
        delete device;
        return -1;
    }

    ...
    // 添加device到对应存储列表(mDevices和mOpeningDevices)
    addDeviceLocked(device);
    return OK;
}
status_t EventHub::registerDeviceForEpollLocked(Device* device) {
    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;
    if (mUsingEpollWakeup) {
        eventItem.events |= EPOLLWAKEUP;
    }
    eventItem.data.u32 = device->id;
    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, device->fd, &eventItem)) {
        ALOGE("Could not add device fd to epoll instance.  errno=%d", errno);
        return -errno;
    }
    return OK;
}
void EventHub::addDeviceLocked(Device* device) {
    // 放入mDevices
    mDevices.add(device->id, device);
    // 插入mOpeningDevices链表头部
    device->next = mOpeningDevices;
    mOpeningDevices = device;
}

实际做了如下事情:

遍历目录“/dev/input”中的所有节点,对每个设备逐一做下面的动作:

  1. 调用驱动open打开设备
  2. 创建描述设备的Device
  3. 注册设备到epoll
  4. 添加device到对应存储列表(mDevices和mOpeningDevices)
1.4 如果有添加设备事件发生,需要生成对应的event事件
        while (mOpeningDevices != NULL) { 
            // 4 有添加设备的事件发生,生成对应event事件
            Device* device = mOpeningDevices;
            mOpeningDevices = device->next;
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
            event->type = DEVICE_ADDED;
            event += 1;
            mNeedToSendFinishedDeviceScan = true;
            if (--capacity == 0) {
                break;
            }
        }
小结

这一块内容包括四个检查处理

  1. 检查reopen请求,如果有,就关闭所有设备,并标记需要重新扫描设备
  2. 检查是否有closeing device,如果有,需要生成对应的关闭设备事件用以反馈给调用者处理,并删除该device
  3. 检查扫描设备标记,如果有(首次调用、和发生reopen会有次标记true),需要扫描设备
  4. 检查是否有opening device,如果有,需要生成对应的open设备的事件反馈给调用者。
2 input事件的获取:
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
    ALOG_ASSERT(bufferSize >= 1);

    AutoMutex _l(mLock);

    struct input_event readBuffer[bufferSize];

    RawEvent* event = buffer;
    size_t capacity = bufferSize;
    bool awoken = false;
    for (;;) {
        // 第一部分
        ...
        // 第二部分:
        // Grab the next input event.
        bool deviceChanged = false;
        while (mPendingEventIndex < mPendingEventCount) {
            // mPendingEventItems 是从epoll接收的事件
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
            // 1 eventItem.data.u32 总共有三类,
            // EPOLL_ID_INOTIFY监听设备变化,EPOLL_ID_WAKE接收管道唤醒,第三类是存储的设备id

            // EventHub创建的时候注册的监听DEVICE_PATH变化的inotify,如果是该事件走此分支
            if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {
                // 做一个mPendingINotify = true标记并跳出进入下一次循环
                if (eventItem.events & EPOLLIN) {
                    mPendingINotify = true;
                } else {
                    ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
                }
                continue;
            }
            // 通过管道写wake的事件
            if (eventItem.data.u32 == EPOLL_ID_WAKE) {
                if (eventItem.events & EPOLLIN) {
                    ALOGV("awoken after wake()");
                    awoken = true;
                    char buffer[16];
                    ssize_t nRead;
                    do {
                        nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
                    } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
                } else {
                    ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
                            eventItem.events);
                }
                continue;
            }
            // 2 开始处理设备产生的事件
            // 前两个分支都未命中,eventItem.data.u32 就是设备id了
            ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
            ...
            // 通过设备id找到device
            Device* device = mDevices.valueAt(deviceIndex);
            if (eventItem.events & EPOLLIN) {
                // 读取事件内容
                int32_t readSize = read(device->fd, readBuffer,
                        sizeof(struct input_event) * capacity);
                if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
                    // 错误分支,略
                    ...
                }... else {
                    int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;

                    size_t count = size_t(readSize) / sizeof(struct input_event);
                    // 遍历所有事件
                    for (size_t i = 0; i < count; i++) {
                        struct input_event& iev = readBuffer[i];
                        ...

                        // 开始组织 RawEvent
                        event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL
                                + nsecs_t(iev.time.tv_usec) * 1000LL;
                        ...
                        if (event->when >= now + 10 * 1000000000LL) {
                            // Double-check.  Time may have moved on.
                            nsecs_t time = systemTime(SYSTEM_TIME_MONOTONIC);
                            if (event->when > time) {
                                ...
                                event->when = time;
                            } else {
                                ...
                            }
                        }
                        event->deviceId = deviceId;
                        event->type = iev.type;
                        event->code = iev.code;
                        event->value = iev.value;
                        event += 1;
                        capacity -= 1;
                    }
                    // buffer满了跳出,下次处理
                    if (capacity == 0) {
                        // The result buffer is full.  Reset the pending event index
                        // so we will try to read the device again on the next iteration.
                        mPendingEventIndex -= 1;
                        break;
                    }
                }
            } ... // 略

        }

        // readNotify() will modify the list of devices so this must be done after
        // processing all other events to ensure that we read all remaining events
        // before closing the devices.
        // 3
        if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
            mPendingINotify = false;
            readNotifyLocked();
            deviceChanged = true;
        }

        // Report added or removed devices immediately.
        if (deviceChanged) {
            continue;
        }

        // Return now if we have collected any events or if we were explicitly awoken.
        if (event != buffer || awoken) {
            break;
        }

        mPendingEventIndex = 0;

        mLock.unlock(); // release lock before poll, must be before release_wake_lock
        release_wake_lock(WAKE_LOCK_ID);
        // 4 没有事件时阻塞等待
        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);

        acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
        mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock

        if (pollResult == 0) {
            // Timed out.
            mPendingEventCount = 0;
            break;
        }

        if (pollResult < 0) {
            // An error occurred.
            mPendingEventCount = 0;

            // Sleep after errors to avoid locking up the system.
            // Hopefully the error is transient.
            if (errno != EINTR) {
                ALOGW("poll failed (errno=%d)\n", errno);
                usleep(100000);
            }
        } else {
            // Some events occurred.
            mPendingEventCount = size_t(pollResult);
        }
    }

    // All done, return the number of events we read.
    return event - buffer;
}

这部分开始处理input事件

  1. 我们是从epoll_wait唤醒后进入的循环,能得到epoll事件。前面代码我们有讲解唤醒epoll的eventItem.data.u32共有三种:

    • EPOLL_ID_INOTIFY 监听设备变化,命中该分支会标记 mPendingINotify = true
    • EPOLL_ID_WAKE 说明是被管道唤醒的,有人调用wake()函数唤醒
    • 存储的设备id:表明是设备产生了事件
  2. 如果eventItem.data.u32是设备id,表示接收到的是设备产生的事件:read读取设备产生的事件内容,遍历所有事件,把事件内容封装成RawEvent。

  3. mPendingINotify 标记的处理,主要是 openDeviceLocked 添加设备(前面已讲)或关闭设备

    status_t EventHub::readNotifyLocked() {
        int res;
        char devname[PATH_MAX];
        char *filename;
        char event_buf[512];
        int event_size;
        int event_pos = 0;
        struct inotify_event *event;
        // 读出事件
        res = read(mINotifyFd, event_buf, sizeof(event_buf));
        ...
    
        strcpy(devname, DEVICE_PATH);
        filename = devname + strlen(devname);
        *filename++ = '/';
        // 遍历所有inotify_event
        while(res >= (int)sizeof(*event)) {
            event = (struct inotify_event *)(event_buf + event_pos);
            if(event->len) {
                strcpy(filename, event->name);
                // 如果是IN_CREATE设备添加,调用openDeviceLocked,否则是关闭
                if(event->mask & IN_CREATE) {
                    // 前面已讲过
                    openDeviceLocked(devname);
                } else {
                    ALOGI("Removing device '%s' due to inotify event\n", devname);
                    closeDeviceByPathLocked(devname);
                }
            }
            event_size = sizeof(*event) + event->len;
            res -= event_size;
            event_pos += event_size;
        }
        return 0;
    }
    

最终通过getEvents得到读取的事件数据mEventBuffer,事件数量count

3.1.2 数据转化

提醒:本段的处理比较复杂,本文没有详细展示甚至去掉了一些代码段没有粘贴,阅读者可以主要关注流程,具体细节会另起文章专门探讨。

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;
            ...
            // 主流程走这里进一步处理
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else { // 这里是设备状态发生变化的相关事件的处理
            switch (rawEvent->type) {
            // 这里看一下 addDeviceLocked
            case EventHubInterface::DEVICE_ADDED:
                addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            case EventHubInterface::DEVICE_REMOVED:
                removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            case EventHubInterface::FINISHED_DEVICE_SCAN:
                handleConfigurationChangedLocked(rawEvent->when);
                break;
            default:
                ALOG_ASSERT(false); // can't happen
                break;
            }
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
}

创建Device和Mapper

注意这里不是在本次触摸事件的流程触发的,是添加设备的流程的处理

在看处理input事件的流程前简单看一下添加设备 addDeviceLocked。因为我们有一些关键角色是在这里创建的。至于他的调用时机,在前面EventHub讲解时有说过,扫描到新设备就会open设备,对于open设备要创建对应的事件传递给调用者。这里就是open事件的处理。

void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
    ...
    InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);
    uint32_t classes = mEventHub->getDeviceClasses(deviceId);
    int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);

    InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);
    ...
}

InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
        const InputDeviceIdentifier& identifier, uint32_t classes) {
    ...
    // 本函数会添加很多种类设备,本文是以TouchInputMapper为例子,这里就只粘贴这两个
    // Touchscreens and touchpad devices.
    if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
        device->addMapper(new MultiTouchInputMapper(device));
    } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
        device->addMapper(new SingleTouchInputMapper(device));
    }
    ...
}

可以看到,不同的设备类型对应不同的事件,我们把不同的设备类型对应抽象出不同的InputMapper,添加到device的mMappers容器。

回到input事件处理流程

void InputReader::processEventsForDeviceLocked(int32_t deviceId,
        const RawEvent* rawEvents, size_t count) {
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
    ...
    InputDevice* device = mDevices.valueAt(deviceIndex);
    ...
    // 根据设备号找到device,执行process
    device->process(rawEvents, count);
}
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
    size_t numMappers = mMappers.size();
    for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
        if (mDropUntilNextSync) {
            if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
                mDropUntilNextSync = false;
            } else {
                ...
            }
        } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
            mDropUntilNextSync = true;
            reset(rawEvent->when);
        } else {
            // 遍历所有的inputMapper,调用其process
            for (size_t i = 0; i < numMappers; i++) {
                InputMapper* mapper = mMappers[i];
                mapper->process(rawEvent);
            }
        }
    }
}

从 mMappers 里遍历找出目标mapper处理,本文以SingleTouchInputMapper为例

void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
    TouchInputMapper::process(rawEvent);

    mSingleTouchMotionAccumulator.process(rawEvent);
}

void TouchInputMapper::process(const RawEvent* rawEvent) {
    ...
    if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
        sync(rawEvent->when);
    }
}

void TouchInputMapper::sync(nsecs_t when) {
    const RawState* last = mRawStatesPending.isEmpty() ?
            &mCurrentRawState : &mRawStatesPending.top();

    // Push a new state.
    mRawStatesPending.push();
    RawState* next = &mRawStatesPending.editTop();
    next->clear();
    next->when = when;
    ...
    // Sync touch
    syncTouch(when, next);
    ...
    processRawTouches(false /*timeout*/);
}

...

对事件的加工处理比较繁复,会在专门的文章中研究,本文不探讨。

这里只放出关键流程图,本文目的是打通主要流程,对于这部分我们只关注下加工出的结果放在哪里。

3-1-2加工事件.png

可以看到,从TouchInputMapper::sync开始,最终生成了一个 NotifyMotionArgs 放入QueuedInputListener的成员变量mArgsQueue队列。

3.1.3 把事件发送给InputDispatcher --- flush

3-1InputReader获取并分发.png

上一节最终生成了一个 NotifyMotionArgs 放入了mArgsQueue,这里就能从mArgsQueue取出NotifyMotionArgs,调用其notify。

void QueuedInputListener::flush() {
    size_t count = mArgsQueue.size();
    for (size_t i = 0; i < count; i++) {
        // 从mArgsQueue取出NotifyMotionArgs
        NotifyArgs* args = mArgsQueue[i];
        args->notify(mInnerListener);
        delete args;
    }
    mArgsQueue.clear();
}
// 该listener是InputDispatcher
void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
    listener->notifyMotion(this);
}
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
    if (!validateMotionEvent(args->action, args->actionButton,
                args->pointerCount, args->pointerProperties)) {
        return;
    }

    uint32_t policyFlags = args->policyFlags;
    policyFlags |= POLICY_FLAG_TRUSTED;
    mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags);

    bool needWake;
    { // acquire lock
        mLock.lock();

        if (shouldSendMotionToInputFilterLocked(args)) {
            mLock.unlock();

            MotionEvent event;
            event.initialize(args->deviceId, args->source, args->action, args->actionButton,
                    args->flags, args->edgeFlags, args->metaState, args->buttonState,
                    0, 0, args->xPrecision, args->yPrecision,
                    args->downTime, args->eventTime,
                    args->pointerCount, args->pointerProperties, args->pointerCoords);

            policyFlags |= POLICY_FLAG_FILTERED;
            if (!mPolicy->filterInputEvent(&event, policyFlags)) {
                return; // event was consumed by the filter
            }

            mLock.lock();
        }

        // Just enqueue a new motion event.
        MotionEntry* newEntry = new MotionEntry(args->eventTime,
                args->deviceId, args->source, policyFlags,
                args->action, args->actionButton, args->flags,
                args->metaState, args->buttonState,
                args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
                args->displayId,
                args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
        // 封装的MotionEntry数据入队
        needWake = enqueueInboundEventLocked(newEntry);
        mLock.unlock();
    } // release lock

    if (needWake) {
    // 如需要,唤醒InputDispatcher的线程的等待(注意当前调用是从InputReader层层调用过来的,还处于InputReader的线程)
        mLooper->wake();
    }
}

enqueueInboundEventLocked:

bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
    bool needWake = mInboundQueue.isEmpty();
    mInboundQueue.enqueueAtTail(entry);
    traceInboundQueueLengthLocked();

    switch (entry->type) {
    case EventEntry::TYPE_KEY: {
        ...
        break;
    }

    case EventEntry::TYPE_MOTION: {
        MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
        if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN
                && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
                && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
                && mInputTargetWaitApplicationHandle != NULL) {
            int32_t displayId = motionEntry->displayId;
            int32_t x = int32_t(motionEntry->pointerCoords[0].
                    getAxisValue(AMOTION_EVENT_AXIS_X));
            int32_t y = int32_t(motionEntry->pointerCoords[0].
                    getAxisValue(AMOTION_EVENT_AXIS_Y));
            // 根据displayid和事件的坐标找出事件位置对应的应该分配给的窗口
            // 具体实现比较复杂,为了不影响流程介绍本文不讲解,理解为这里是找出了事件点到了哪个有效窗口即可。
            sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y);
            if (touchedWindowHandle != NULL
                    && touchedWindowHandle->inputApplicationHandle
                            != mInputTargetWaitApplicationHandle) {
                // User touched a different application than the one we are waiting on.
                // Flag the event, and start pruning the input queue.
                mNextUnblockedEvent = motionEntry;
                needWake = true;
            }
        }
        break;
    }
    }

    return needWake;
}

flush函数最终把封装的MotionEntry放入到mInboundQueue队列

3.2 InputDispatcher 寻找目标client传输数据

InputDispatcher 负责遍历注册进来的客户端寻找正确的目标客户端,将InputReader传递过来的事件分发出去。

3-2-InputDispatcher分发.png

提醒:接下来的代码略长,阅读本文时可以忽略代码细节,每段代码末尾会有简单描述,本小节的具体细节会在另外的文章专门探讨。

dispatchOnce:

void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    { // acquire lock
        AutoMutex _l(mLock);
        mDispatcherIsAliveCondition.broadcast();

        // Run a dispatch loop if there are no pending commands.
        // The dispatch loop might enqueue commands to run afterwards.
        if (!haveCommandsLocked()) {
            dispatchOnceInnerLocked(&nextWakeupTime);
        }

        // Run all pending commands if there are any.
        // If any commands were run then force the next poll to wake up immediately.
        if (runCommandsLockedInterruptible()) {
            nextWakeupTime = LONG_LONG_MIN;
        }
    } // release lock

    // Wait for callback or timeout or wake.  (make sure we round up, not down)
    nsecs_t currentTime = now();
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
    mLooper->pollOnce(timeoutMillis);
}

dispatchOnceInnerLocked:

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    nsecs_t currentTime = now();
    ...
    bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
    if (mAppSwitchDueTime < *nextWakeupTime) {
        *nextWakeupTime = mAppSwitchDueTime;
    }

    if (! mPendingEvent) {
        if (mInboundQueue.isEmpty()) {
            ...
        } else {
            // 从mInboundQueue取事件,就是3.1.3入队的事件
            mPendingEvent = mInboundQueue.dequeueAtHead();
            traceInboundQueueLengthLocked();
        }
        ...
    }

    bool done = false;
    ...
    if (mNextUnblockedEvent == mPendingEvent) {
        mNextUnblockedEvent = NULL;
    }

    switch (mPendingEvent->type) {
        ...
        case EventEntry::TYPE_MOTION: {
            MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
            ...
            done = dispatchMotionLocked(currentTime, typedEntry,
                    &dropReason, nextWakeupTime);
            break;
        }

        default:
            ALOG_ASSERT(false);
            break;
    }
    ...
}

取出3.1.3放入队列的数据,继续分发处理

dispatchMotionLocked:

bool InputDispatcher::dispatchMotionLocked(
        nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
    ...
    bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;

    // Identify targets.
    Vector<InputTarget> inputTargets;

    bool conflictingPointerActions = false;
    int32_t injectionResult;
    if (isPointerEvent) {
        // Pointer event.  (eg. touchscreen)
        // 寻找应该处理本事件的目标
        injectionResult = findTouchedWindowTargetsLocked(currentTime,
                entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
    } else {
        // Non touch event.  (eg. trackball)
        injectionResult = findFocusedWindowTargetsLocked(currentTime,
                entry, inputTargets, nextWakeupTime);
    }
    ...

    // Dispatch the motion.
    if (conflictingPointerActions) {
        CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
                "conflicting pointer actions");
        synthesizeCancelationEventsForAllConnectionsLocked(options);
    }
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}

为不使文章分支太多太过庞大影响展示整体流程,findTouchedWindowTargetsLocked 如何寻找目标窗口放在另外的文章单独讲解。了解本函数就是寻找目标然后继续分发即可。

继续分发 dispatchEventLocked:

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
        EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
    pokeUserActivityLocked(eventEntry);

    for (size_t i = 0; i < inputTargets.size(); i++) {
        const InputTarget& inputTarget = inputTargets.itemAt(i);
        // 从mConnectionsByFd根据inputChannel找到封装inputChannel的Connection在容器中的坐标(mConnectionsByFd容器在服务端注册inputchannel的时候讲过)
        ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
        if (connectionIndex >= 0) {
            // 取出Connection
            sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
            prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
        } else {
            ...
        }
    }
}

这里的 mConnectionsByFd 就是存储服务端InputChannel的容器(回看2.1.3小节服务端注册),一个服务端InputChannel对应一个客户端InputChannel,拿到他就可以向目标客户端发起通信了。

prepareDispatchCycleLocked:

void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {

    // Skip this event if the connection status is not normal.
    // We don't want to enqueue additional outbound events if the connection is broken.
    if (connection->status != Connection::STATUS_NORMAL) {
        ...
        return;
    }

    // Split a motion event if needed.
    if (inputTarget->flags & InputTarget::FLAG_SPLIT) {
        MotionEntry* originalMotionEntry = static_cast<MotionEntry*>(eventEntry);
        if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) {
            MotionEntry* splitMotionEntry = splitMotionEvent(
                    originalMotionEntry, inputTarget->pointerIds);
            if (!splitMotionEntry) {
                return; // split event was dropped
            }
            enqueueDispatchEntriesLocked(currentTime, connection,
                    splitMotionEntry, inputTarget);
            splitMotionEntry->release();
            return;
        }
    }

    // Not splitting.  Enqueue dispatch entries for the event as is.
    enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}

enqueueDispatchEntriesLocked:

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);
    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);
    }
}

> enqueueDispatchEntryLocked 入队:

void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection,
                                                 EventEntry* eventEntry,
                                                 const InputTarget& inputTarget,
                                                 int32_t dispatchMode) {
    int32_t inputTargetFlags = inputTarget.flags;
    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.
    std::unique_ptr<DispatchEntry> dispatchEntry =
            createDispatchEntry(inputTarget, eventEntry, inputTargetFlags);

    // Use the eventEntry from dispatchEntry since the entry may have changed and can now be a
    // different EventEntry than what was passed in.
    EventEntry* newEntry = dispatchEntry->eventEntry;
    // Apply target flags and update the connection's input state.
    switch (newEntry->type) {
        ...
        case EventEntry::Type::MOTION: {
            const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*newEntry);
            // Assign a default value to dispatchEntry that will never be generated by InputReader,
            // and assign a InputDispatcher value if it doesn't change in the if-else chain below.
            constexpr int32_t DEFAULT_RESOLVED_EVENT_ID =
                    static_cast<int32_t>(IdGenerator::Source::OTHER);
            dispatchEntry->resolvedEventId = DEFAULT_RESOLVED_EVENT_ID;
            if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
                dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE;
            } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) {
                dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT;
            } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) {
                dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
            } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
                dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL;
            } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) {
                dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN;
            } else {
                dispatchEntry->resolvedAction = motionEntry.action;
                dispatchEntry->resolvedEventId = motionEntry.id;
            }
            if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE &&
                !connection->inputState.isHovering(motionEntry.deviceId, motionEntry.source,
                                                   motionEntry.displayId)) {
                dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
            }

            dispatchEntry->resolvedFlags = motionEntry.flags;
            if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {
                dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
            }
            if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) {
                dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
            }

            if (!connection->inputState.trackMotion(motionEntry, dispatchEntry->resolvedAction,
                                                    dispatchEntry->resolvedFlags)) {
                return; // skip the inconsistent event
            }

            dispatchEntry->resolvedEventId =
                    dispatchEntry->resolvedEventId == DEFAULT_RESOLVED_EVENT_ID
                    ? mIdGenerator.nextId()
                    : motionEntry.id;
            if (ATRACE_ENABLED() && dispatchEntry->resolvedEventId != motionEntry.id) {
                std::string message = StringPrintf("Transmute MotionEvent(id=0x%" PRIx32
                                                   ") to MotionEvent(id=0x%" PRIx32 ").",
                                                   motionEntry.id, dispatchEntry->resolvedEventId);
                ATRACE_NAME(message.c_str());
            }

            dispatchPointerDownOutsideFocus(motionEntry.source, dispatchEntry->resolvedAction,
                                            inputTarget.inputChannel->getConnectionToken());

            break;
        }
        ...
    }

    // Remember that we are waiting for this dispatch to complete.
    if (dispatchEntry->hasForegroundTarget()) {
        incrementPendingForegroundDispatches(newEntry);
    }

    // Enqueue the dispatch entry.
    // DispatchEntry 放入 Connection的outboundQueue队列
    connection->outboundQueue.push_back(dispatchEntry.release());
    traceOutboundQueueLength(connection);
}

根据事件数据封装一个DispatchEntry,放入Connection的outboundQueue队列。

继续分发 startDispatchCycleLocked:

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_MOTION: {
                MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);

                PointerCoords scaledCoords[MAX_POINTERS];
                const PointerCoords* usingCoords = motionEntry->pointerCoords;

                // Set the X and Y offset depending on the input source.
                float xOffset, yOffset, scaleFactor;
                if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
                        && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
                    scaleFactor = dispatchEntry->scaleFactor;
                    xOffset = dispatchEntry->xOffset * scaleFactor;
                    yOffset = dispatchEntry->yOffset * scaleFactor;
                    if (scaleFactor != 1.0f) {
                        for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
                            scaledCoords[i] = motionEntry->pointerCoords[i];
                            scaledCoords[i].scale(scaleFactor);
                        }
                        usingCoords = scaledCoords;
                    }
                } else {
                    xOffset = 0.0f;
                    yOffset = 0.0f;
                    scaleFactor = 1.0f;

                    // We don't want the dispatch target to know.
                    if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
                        for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
                            scaledCoords[i].clear();
                        }
                        usingCoords = scaledCoords;
                    }
                }

                // Publish the motion event.
                status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
                        motionEntry->deviceId, motionEntry->source, motionEntry->displayId,
                        dispatchEntry->resolvedAction, motionEntry->actionButton,
                        dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
                        motionEntry->metaState, motionEntry->buttonState,
                        xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
                        motionEntry->downTime, motionEntry->eventTime,
                        motionEntry->pointerCount, motionEntry->pointerProperties,
                        usingCoords);
                break;
            }

            default:
                ALOG_ASSERT(false);
                return;
        }

        // Check the result.
        if (status) {
            if (status == WOULD_BLOCK) {
                if (connection->waitQueue.isEmpty()) {
                    ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "
                            "This is unexpected because the wait queue is empty, so the pipe "
                            "should be empty and we shouldn't have any problems writing an "
                            "event to it, status=%d", connection->getInputChannelName(), status);
                    abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
                } else {
                    // Pipe is full and we are waiting for the app to finish process some events
                    // before sending more events to it.
                    connection->inputPublisherBlocked = true;
                }
            } else {
                ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
                        "status=%d", connection->getInputChannelName(), status);
                abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
            }
            return;
        }

        // Re-enqueue the event on the wait queue.
        connection->outboundQueue.dequeue(dispatchEntry);
        traceOutboundQueueLengthLocked(connection);
        connection->waitQueue.enqueueAtTail(dispatchEntry);
        traceWaitQueueLengthLocked(connection);
    }
}

publishMotionEvent:

status_t InputPublisher::publishMotionEvent(
        uint32_t seq,
        int32_t deviceId,
        int32_t source,
        int32_t action,
        int32_t actionButton,
        int32_t flags,
        int32_t edgeFlags,
        int32_t metaState,
        int32_t buttonState,
        float xOffset,
        float yOffset,
        float xPrecision,
        float yPrecision,
        nsecs_t downTime,
        nsecs_t eventTime,
        uint32_t pointerCount,
        const PointerProperties* pointerProperties,
        const PointerCoords* pointerCoords) {
    ...
    InputMessage msg;
    msg.header.type = InputMessage::TYPE_MOTION;
    msg.body.motion.seq = seq;
    msg.body.motion.deviceId = deviceId;
    msg.body.motion.source = source;
    msg.body.motion.action = action;
    msg.body.motion.actionButton = actionButton;
    msg.body.motion.flags = flags;
    msg.body.motion.edgeFlags = edgeFlags;
    msg.body.motion.metaState = metaState;
    msg.body.motion.buttonState = buttonState;
    msg.body.motion.xOffset = xOffset;
    msg.body.motion.yOffset = yOffset;
    msg.body.motion.xPrecision = xPrecision;
    msg.body.motion.yPrecision = yPrecision;
    msg.body.motion.downTime = downTime;
    msg.body.motion.eventTime = eventTime;
    msg.body.motion.pointerCount = pointerCount;
    for (uint32_t i = 0; i < pointerCount; i++) {
        msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
        msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
    }
    return mChannel->sendMessage(&msg);
}

sendMessage:

status_t InputChannel::sendMessage(const InputMessage* msg) {
    size_t msgLength = msg->size();
    ssize_t nWrite;
    do {
        // mFd是那对用于通信的socket,这里作为服务端,发送数据,紧接着客户端
        nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
    } while (nWrite == -1 && errno == EINTR);

    if (nWrite < 0) {
        int error = errno;
        if (error == EAGAIN || error == EWOULDBLOCK) {
            return WOULD_BLOCK;
        }
        if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED || error == ECONNRESET) {
            return DEAD_OBJECT;
        }
        return -error;
    }

    if (size_t(nWrite) != msgLength) {
        return DEAD_OBJECT;
    }

    return OK;
}

这里是服务端InputChannel的调用,通过socket发送数据,紧接着目标客户端就要被唤醒开始处理数据了。

小结:

InputDispatcher主要做了接收InputReader端发来的数据,寻找正确的消费目标客户端,然后使用InputChannel发送数据给目标。

3.3 客户端处理事件分发

3-3客户端处理.png

服务端发送数据触发客户端注册的Looper回调 handleEvent

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, nullptr);
        mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
        return status == OK || status == NO_MEMORY ? 1 : 0;
    }

    if (events & ALOOPER_EVENT_OUTPUT) {
        for (size_t i = 0; i < mFinishQueue.size(); i++) {
            const Finish& finish = mFinishQueue.itemAt(i);
            status_t status = mInputConsumer.sendFinishedSignal(finish.seq, finish.handled);
            if (status) {
                mFinishQueue.removeItemsAt(0, i);

                ...
                if (status != DEAD_OBJECT) {
                    JNIEnv* env = AndroidRuntime::getJNIEnv();
                    String8 message;
                    message.appendFormat("Failed to finish input event.  status=%d", status);
                    jniThrowRuntimeException(env, message.string());
                    mMessageQueue->raiseAndClearException(env, "finishInputEvent");
                }
                return 0; // remove the callback
            }
        }
        ...
        mFinishQueue.clear();
        setFdEvents(ALOOPER_EVENT_INPUT);
        return 1;
    }

    return 1;
}
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
        bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
    ...
    if (consumeBatches) {
        mBatchedInputEventPending = false;
    }
    if (outConsumedBatch) {
        *outConsumedBatch = false;
    }

    ScopedLocalRef<jobject> receiverObj(env, nullptr);
    bool skipCallbacks = false;
    for (;;) {
        uint32_t seq;
        InputEvent* inputEvent;
        // 1 读取InputDispatcher端发送过来的数据
        status_t status = mInputConsumer.consume(&mInputEventFactory,
                consumeBatches, frameTime, &seq, &inputEvent);
        ...

        if (!skipCallbacks) {
            if (!receiverObj.get()) {
                receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal));
                if (!receiverObj.get()) {
                    ALOGW("channel '%s' ~ Receiver object was finalized "
                            "without being disposed.", getInputChannelName().c_str());
                    return DEAD_OBJECT;
                }
            }

            jobject inputEventObj;
            switch (inputEvent->getType()) {
                ...
                case AINPUT_EVENT_TYPE_MOTION: {
                    ...
                    MotionEvent* motionEvent = static_cast<MotionEvent*>(inputEvent);
                    if ((motionEvent->getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) {
                        *outConsumedBatch = true;
                    }
                    // 为java准备jobject的事件
                    inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent);
                    break;
                }
                ...
            }

            if (inputEventObj) {
                ...
                // 2 调用java层 InputEventReceiver dispatchInputEvent
                env->CallVoidMethod(receiverObj.get(),
                        gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
                if (env->ExceptionCheck()) {
                    ALOGE("Exception dispatching input event.");
                    skipCallbacks = true;
                }
                env->DeleteLocalRef(inputEventObj);
            } else {
                ALOGW("channel '%s' ~ Failed to obtain event object.",
                        getInputChannelName().c_str());
                skipCallbacks = true;
            }
        }

        if (skipCallbacks) {
            mInputConsumer.sendFinishedSignal(seq, false);
        }
    }
}
  1. 读取InputDispatcher端发送过来的数据
  2. 调用java层 InputEventReceiver dispatchInputEvent继续分发

3.3.1 读取服务端发送过来的数据

status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches,
                                nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
    ...
    *outSeq = 0;
    *outEvent = nullptr;

    while (!*outEvent) {
        if (mMsgDeferred) {
            mMsgDeferred = false;
        } else {
            // Receive a fresh message.
            // 1 接收InputDispatcher端发送过来的数据
            status_t result = mChannel->receiveMessage(&mMsg);
            ...
        }

        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.editItemAt(batchIndex);
                    if (canAddSample(batch, &mMsg)) {
                        batch.samples.push(mMsg);
                        ...
                    break;
                    } else if (isPointerEvent(mMsg.body.motion.source) &&
                               mMsg.body.motion.action == AMOTION_EVENT_ACTION_CANCEL) {
                        // No need to process events that we are going to cancel anyways
                        const size_t count = batch.samples.size();
                        for (size_t i = 0; i < count; i++) {
                            const InputMessage& msg = batch.samples.itemAt(i);
                            sendFinishedSignal(msg.body.motion.seq, false);
                        }
                        batch.samples.removeItemsAt(0, count);
                        mBatches.removeAt(batchIndex);
                    } else {
                        // We cannot append to the batch in progress, so we need to consume
                        // the previous batch right now and defer the new message until later.
                        mMsgDeferred = true;
                        status_t result = consumeSamples(factory, batch, batch.samples.size(),
                                                         outSeq, outEvent);
                        mBatches.removeAt(batchIndex);
                        if (result) {
                            return result;
                        }
                        ...
                    break;
                    }
                }

                // Start a new batch if needed.
                if (mMsg.body.motion.action == AMOTION_EVENT_ACTION_MOVE ||
                    mMsg.body.motion.action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
                    mBatches.push();
                    Batch& batch = mBatches.editTop();
                    batch.samples.push(mMsg);
                    if (DEBUG_TRANSPORT_ACTIONS) {
                        ALOGD("channel '%s' consumer ~ started batch event",
                              mChannel->getName().c_str());
                    }
                    break;
                }

                MotionEvent* motionEvent = factory->createMotionEvent();
                if (!motionEvent) return NO_MEMORY;

                updateTouchState(mMsg);
                // 根据从服务端接收到的数据mMsg,初始化触摸事件motionEvent,赋给outEvent传递给调用者
                initializeMotionEvent(motionEvent, &mMsg);
                *outSeq = mMsg.body.motion.seq;
                *outEvent = motionEvent;

                ...
                break;
            }
            ...
        }
    }
    return OK;
}

1) 接收数据

status_t InputChannel::receiveMessage(InputMessage* msg) {
    ssize_t nRead;
    do {
        nRead = ::recv(mFd.get(), msg, sizeof(InputMessage), MSG_DONTWAIT);
    } while (nRead == -1 && errno == EINTR);
    ...
    return OK;
}

2) 创建MotionEvent

void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) {
    uint32_t pointerCount = msg->body.motion.pointerCount;
    PointerProperties pointerProperties[pointerCount];
    PointerCoords pointerCoords[pointerCount];
    for (uint32_t i = 0; i < pointerCount; i++) {
        pointerProperties[i].copyFrom(msg->body.motion.pointers[i].properties);
        pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
    }

    event->initialize(msg->body.motion.eventId, msg->body.motion.deviceId, msg->body.motion.source,
                      msg->body.motion.displayId, msg->body.motion.hmac, msg->body.motion.action,
                      msg->body.motion.actionButton, msg->body.motion.flags,
                      msg->body.motion.edgeFlags, msg->body.motion.metaState,
                      msg->body.motion.buttonState, msg->body.motion.classification,
                      msg->body.motion.xScale, msg->body.motion.yScale, msg->body.motion.xOffset,
                      msg->body.motion.yOffset, msg->body.motion.xPrecision,
                      msg->body.motion.yPrecision, msg->body.motion.xCursorPosition,
                      msg->body.motion.yCursorPosition, msg->body.motion.downTime,
                      msg->body.motion.eventTime, pointerCount, pointerProperties, pointerCoords);
}

void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId,
                             std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton,
                             int32_t flags, int32_t edgeFlags, int32_t metaState,
                             int32_t buttonState, MotionClassification classification, float xScale,
                             float yScale, float xOffset, float yOffset, float xPrecision,
                             float yPrecision, float rawXCursorPosition, float rawYCursorPosition,
                             nsecs_t downTime, nsecs_t eventTime, size_t pointerCount,
                             const PointerProperties* pointerProperties,
                             const PointerCoords* pointerCoords) {
    InputEvent::initialize(id, deviceId, source, displayId, hmac);
    mAction = action;
    mActionButton = actionButton;
    mFlags = flags;
    mEdgeFlags = edgeFlags;
    mMetaState = metaState;
    mButtonState = buttonState;
    mClassification = classification;
    mXScale = xScale;
    mYScale = yScale;
    mXOffset = xOffset;
    mYOffset = yOffset;
    mXPrecision = xPrecision;
    mYPrecision = yPrecision;
    mRawXCursorPosition = rawXCursorPosition;
    mRawYCursorPosition = rawYCursorPosition;
    mDownTime = downTime;
    mPointerProperties.clear();
    mPointerProperties.appendArray(pointerProperties, pointerCount);
    mSampleEventTimes.clear();
    mSamplePointerCoords.clear();
    addSample(eventTime, pointerCoords);
}

3.3.2 继续分发,进入java层InputEventReceiver

dispatchInputEvent:

private void dispatchInputEvent(int seq, InputEvent event) {
    mSeqMap.put(event.getSequenceNumber(), seq);
    onInputEvent(event);
}
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);
    }
}
void enqueueInputEvent(InputEvent event,
        InputEventReceiver receiver, int flags, boolean processImmediately) {
    QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);

    QueuedInputEvent last = mPendingInputEventTail;
    if (last == null) {
        mPendingInputEventHead = q;
        mPendingInputEventTail = q;
    } else {
        last.mNext = q;
        mPendingInputEventTail = q;
    }
    mPendingInputEventCount += 1;
    Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
            mPendingInputEventCount);

    if (processImmediately) {
        doProcessInputEvents();
    } else {
        scheduleProcessInputEvents();
    }
}
void doProcessInputEvents() {
    // Deliver all pending input events in the queue.
    while (mPendingInputEventHead != null) {
        QueuedInputEvent q = mPendingInputEventHead;
        mPendingInputEventHead = q.mNext;
        if (mPendingInputEventHead == null) {
            mPendingInputEventTail = null;
        }
        q.mNext = null;

        mPendingInputEventCount -= 1;
        Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
                mPendingInputEventCount);

        long eventTime = q.mEvent.getEventTimeNano();
        long oldestEventTime = eventTime;
        if (q.mEvent instanceof MotionEvent) {
            MotionEvent me = (MotionEvent)q.mEvent;
            if (me.getHistorySize() > 0) {
                oldestEventTime = me.getHistoricalEventTimeNano(0);
            }
        }
        mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);

        deliverInputEvent(q);
    }

    // We are done processing all input events that we can process right now
    // so we can clear the pending flag immediately.
    if (mProcessInputEventsScheduled) {
        mProcessInputEventsScheduled = false;
        mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
    }
}

接下来的处理是若干个阶段的责任链式处理,我在另外的文章专门讲解,本文略过

3-3-1责任链.png

只需知道,从deliver进入,经过几个阶段的处理,最终调用View.DispatchPointerEvent继续分发

private void deliverInputEvent(QueuedInputEvent q) {
    Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
            q.mEvent.getId());

    if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent src=0x"
                + Integer.toHexString(q.mEvent.getSource()) + " eventTimeNano="
                + q.mEvent.getEventTimeNano() + " id=0x"
                + Integer.toHexString(q.mEvent.getId()));
    }
    try {
        if (mInputEventConsistencyVerifier != null) {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "verifyEventConsistency");
            try {
                mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
        }

        InputStage stage;
        if (q.shouldSendToSynthesizer()) {
            stage = mSyntheticInputStage;
        } else {
            stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
        }

        if (q.mEvent instanceof KeyEvent) {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "preDispatchToUnhandledKeyManager");
            try {
                mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }
        }

        if (stage != null) {
            handleWindowFocusChanged();
            stage.deliver(q);
        } else {
            finishInputEvent(q);
        }
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}
// ViewRootImpl.java
private int processPointerEvent(QueuedInputEvent q) {
    final MotionEvent event = (MotionEvent)q.mEvent;

    mAttachInfo.mUnbufferedDispatchRequested = false;
    mAttachInfo.mHandlingPointerEvent = true;
    // 这里的mView是DecorView,这里不再赘述
    boolean handled = mView.dispatchPointerEvent(event);
    maybeUpdatePointerIcon(event);
    maybeUpdateTooltip(event);
    mAttachInfo.mHandlingPointerEvent = false;
    if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
        mUnbufferedInputDispatch = true;
        if (mConsumeBatchedInputScheduled) {
            scheduleConsumeBatchedInputImmediately();
        }
    }
    return handled ? FINISH_HANDLED : FORWARD;
}

这里是DecorView对象,dispatchPointerEvent实现在父类View中

// View.java
public final boolean dispatchPointerEvent(MotionEvent event) {
    if (event.isTouchEvent()) {
        return dispatchTouchEvent(event);
    } else {
        return dispatchGenericMotionEvent(event);
    }
}
// DecorView.java
public boolean dispatchTouchEvent(MotionEvent ev) {
    // 这里的 Window.Callback 是Activity,在Activity创建过程中的attach时,把自己注册给Window的,
    final Window.Callback cb = mWindow.getCallback();
    return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
            ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}

可以看到,DecorView的dispatchTouchEvent没有直接向子View分发,而是调用了Activity的dispatchTouchEvent把主动权让给Activity。

Activity的拦截和分发

// Activity.java
/**
 * Called to process touch screen events.  You can override this to
 * intercept all touch screen events before they are dispatched to the
 * window.  Be sure to call this implementation for touch screen events
 * that should be handled normally.
 *
 * @param ev The touch screen event.
 *
 * @return boolean Return true if this event was consumed.
 */
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        onUserInteraction();
    }
    if (getWindow().superDispatchTouchEvent(ev)) {
        return true;
    }
    return onTouchEvent(ev);
}

public void onUserInteraction() {
}

如果子类重写dispatchTouchEvent可以实现从根源拦截掉事件。

// PhoneWindow.java
public boolean superDispatchTouchEvent(MotionEvent event) {
    return mDecor.superDispatchTouchEvent(event);
}
// DecorView.java
public boolean superDispatchTouchEvent(MotionEvent event) {
    return super.dispatchTouchEvent(event);
}

调用PhoneWindow的superDispatchTouchEvent最终重新回到DecorView,分发事件。

接下来调用 ViewGroup dispatchTouchEvent,就是View的消息分发策略了,在《安卓 触摸事件分发机制》一文中讲解,这里就不再赘述。

// ViewGroup.java
public boolean dispatchTouchEvent(MotionEvent ev) {
    ...
}

至此,整体流程介绍完毕。

总结:

本文整理了服务的启动、客户端向服务注册处理input和服务对驱动产生的事件的获取加工分发三部分

1 启动Input服务

1Input服务初始化.png

创建了InputReader和InputDispatcher,并分别创建了对应他们的Thread,启动线程开始循环工作。

2 客户端发起处理input的注册

2Input注册.png 生成一堆相互连接的socket分别由两个InputDispatcher持有,一个dispatcher分配给客户端,一个分配给服务端,并注册,就是把socket添加给Looper注册监听文件描述符,这样客户端服务端相互发送数据就能够唤醒对方处理了。

3 驱动产生input事件,如何获取事件并加工分发

3.1 InputReader负责对接驱动和InputDispatcher,从驱动取数据并加工,然后放入队列等待InputDispatcher消费处理

3-1InputReader获取并分发.png

3.2 InputDispatcher拿到InputReader加工后数据,负责分发给合适的客户端,他需要寻找正确目标,即找出焦点窗口处理事件,然后通过InputChannel 持有的socket发送数据给目标。

3-2-InputDispatcher分发.png

3.3 客户端InputReceiver收到数据,根据数据类型、特征等进行分发。

3-3客户端处理.png


标签:流程机制Input


程序开发学习排行
最近发表
网站分类
标签列表