Android源码分析:系统进程中事件的读取与分发

266 阅读20分钟

之前分析的是从InputChannel中读取Event,并且向后传递,进行消费和处理的过程。但是之前的部分呢,事件如何产生,事件怎么进入到InputChanel当中的,事件又是如何跨进程到达App进程,这里继续来分析。

以上为system进程的流程的简化图,这里我们可以看到几个重要的组件,这里以触摸事件来进行分析(后文的分析也将会以触摸事件为主进行分析)并且简单的描绘了事件从EventHub到服务端的InputChannel发送事件的全部过程。具体内容一起来看下面的代码。

InputManagerService的创建

因为事件的分发涉及到不少类,我们先从InputManagerService(IMS)的初始化出发,进行分析。入口代码在SystemServer.java中,代码如下:

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
WindowManagerService wm = null;  
InputManagerService inputManager = null;
inputManager = new InputManagerService(context);
wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,  
        new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);  
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,  
        DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);  
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,  
        /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);

inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());  
inputManager.start();
}

这里我们可以看到WMS的创建我们传入了IMS,并且IMS也依赖WindowMnagerCallbacks,我们先看一下IMS的构造方法。

public InputManagerService(Context context) {  
    this(new Injector(context, DisplayThread.get().getLooper()));  
}  
  
@VisibleForTesting  
InputManagerService(Injector injector) {  
    ... 
    mHandler = new InputManagerHandler(injector.getLooper());  
    mNative = injector.getNativeService(this);  
    ...
}

我们主要关注这个mNative的构建,它是NativeImpl,它的创建过程如下:

new NativeInputManagerService.NativeImpl(service, mContext, mLooper.getQueue());

这里的Looper是前面传进来的DisplayThread的Looper。在NativeImpl的构造方法中调用了init方法,并获取到了它的native指针,这里需要看com_android_server_input_InputManagerService.cpp中的natvieInit方法,代码如下:

static jlong nativeInit(JNIEnv* env, jclass /* clazz */,  
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {  
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);  
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,  
            messageQueue->getLooper());  
    im->incStrong(0);  
    return reinterpret_cast<jlong>(im);  
}

这里创建了NativeInputManager

NativeInputManager初始化

NativeInputManager::NativeInputManager(jobject contextObj,  
        jobject serviceObj, const sp<Looper>& looper) :  
        mLooper(looper), mInteractive(true) {  
    JNIEnv* env = jniEnv();  
  
    mServiceObj = env->NewGlobalRef(serviceObj);  
  
    {  
        AutoMutex _l(mLock);  
        mLocked.systemUiLightsOut = false;  
        mLocked.pointerSpeed = 0;  
        mLocked.pointerAcceleration = android::os::IInputConstants::DEFAULT_POINTER_ACCELERATION;  
        mLocked.pointerGesturesEnabled = true;  
        mLocked.showTouches = false;  
        mLocked.pointerDisplayId = ADISPLAY_ID_DEFAULT;  
    }  
    mInteractive = true;  
  
    InputManager* im = new InputManager(this, this);  
    mInputManager = im;  
    defaultServiceManager()->addService(String16("inputflinger"), im);  
}

这个构造方法中,传入的jobject为我们之前的NativeImpl,后面有需要调用java层的时候会用到它。除此之外我们看到又创建了一个InputManger,并且把它注册到了ServiceManger当中,名称为inputflinger

我们继续看InputManager的初始化代码,它传如的两个参数readerPolicydispatcherPolicy的实现都在NativeInputManager当中。它的代码如下:

InputManager::InputManager(  
        const sp<InputReaderPolicyInterface>& readerPolicy,  
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {  
    mDispatcher = createInputDispatcher(dispatcherPolicy);  
    mClassifier = std::make_unique<InputClassifier>(*mDispatcher);  
    mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mClassifier);  
    mReader = createInputReader(readerPolicy, *mBlocker);  
}

这里首先创建了InputDispatcher,之后创建的mClassifiermBlockerInputDispatcher一样都是继承自InputListenerInterface,它们的作用为在事件经过InputDispatcher分发之前,可以做一些预处理。最后创建InputReader,事件会经由它传递到InputDispatcher,最后再由InputDispatcher分到到InputChannel。下面来详细分析。

事件源的初始化

因为InputDispatcher初始化代码比较简单,我们从createInputReader的源码开始看起来:

std::unique_ptr<InputReaderInterface> createInputReader(  
        const sp<InputReaderPolicyInterface>& policy, InputListenerInterface& listener) {  
    return std::make_unique<InputReader>(std::make_unique<EventHub>(), policy, listener);  
}

我们可以看到在创建InputReader之前首先创建了一个EventHub,看名字我们就知道它是一个事件的收集中心。我们看它的构造方法,代码如下:

EventHub::EventHub(void)  
      : mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD),  
        mNextDeviceId(1),  
        ...
        mPendingINotify(false) {  
    ensureProcessCanBlockSuspend();  
  
    mEpollFd = epoll_create1(EPOLL_CLOEXEC);  //创建epoll实例,flag表示执行新的exec时候会自动关闭
  
    mINotifyFd = inotify_init1(IN_CLOEXEC);  //创建inotify实例,该实例用于监听文件的变化
  
    if (std::filesystem::exists(DEVICE_INPUT_PATH, errorCode)) {  
        addDeviceInputInotify();  
    } else {  
        addDeviceInotify();  
        isDeviceInotifyAdded = true;  
    
    }  
  
    struct epoll_event eventItem = {};  
    eventItem.events = EPOLLIN | EPOLLWAKEUP;  
    eventItem.data.fd = mINotifyFd;  
    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);  
    int wakeFds[2];  
    result = pipe2(wakeFds, O_CLOEXEC);  
    
    mWakeReadPipeFd = wakeFds[0];  
    mWakeWritePipeFd = wakeFds[1];  
  
    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);  
    
    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);  
    
    eventItem.data.fd = mWakeReadPipeFd;  
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);  
}

从上面的代码我们可以看到这里主要为创建inotify并且通过epoll去监听文件的变化,其中还是用管道创建了wakeReadPipewakeReadPipe的文件描述,用于接收回调。我们先看一下addDeviceInputInotify()方法:

void EventHub::addDeviceInputInotify() {  
    mDeviceInputWd = inotify_add_watch(mINotifyFd, DEVICE_INPUT_PATH, IN_DELETE | IN_CREATE);  
    
}

其中DEVICE_INPUT_PATH的值为/dev/input,也就是说把这个path放到mINofiyFd的监控当中。对于了解Linux的人应该知道,在Linux中万物结尾文件,因此我们的输入也是文件,当事件发生的时候便会写入到/dev/input下面,文件变化我们也会得到通知。我这里使用ls命令打印了一下我的手机,/dev/input下面有如下文件:

event0  event1  event2  event3  event4  event5

具体这些文件的写入,那就是内核和驱动相关的东西了,我们这里不再讨论。而事件的读取,我们后面再进行分析。

IMS的启动

各个对象都构建完成之后,IMS要进行启动,才能够对事件进行处理并且分发。SystemServer中已经调用了IMS的start方法,它其中又会调用NativeInputMangerstart方法,最终会调用 native层的InputManagerstart方法。而其中分别又调用了Dispatcher的start方法和Reader的start方法。我们分别分析。

InputDispater 调用start

status_t InputDispatcher::start() {  
    if (mThread) {  
        return ALREADY_EXISTS;  
    }  
    mThread = std::make_unique<InputThread>(  
            "InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });  
    return OK;  
}

这个方法中主要创建了InputThread,并且给它传了两个lambda,分别执行InputDispatchdispatchOnce方法和执行Looper的wake方法。我们看InputThread的构造方法:

InputThread::InputThread(std::string name, std::function<void()> loop, std::function<void()> wake)  
      : mName(name), mThreadWake(wake) {  
    mThread = new InputThreadImpl(loop);  
    mThread->run(mName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY);  
}

可以看到其中创建了InputThreadImpl,这个类才是真的继承的系统的Thread类,这里构建完成它就继续调用了它的run方法,这样它就会启动了。这里我们需要注意这个 线程的优先级,为PRIORITY_URGEN_DISPLAY,可以看到优先级是非常高了。

bool threadLoop() override {  
    mThreadLoop();  
    return true;  
}

另外就是我们传进来的loop传入了这个对象,并且在它的threadLoop中会执行它。对于native中的线程,我们在threadLoop中实现逻辑就可以了,并且这里我们返回值为true,它会继续循环执行 。而我们传入的另一个lambda,则是在线程推出的时候调用。这个线程循环中执行的就是我们的InputDispatch中 的dispatchOnce方法,也就是消息的投递,后面再来分析。

InputReader调用start方法

status_t InputReader::start() {  
    if (mThread) {  
        return ALREADY_EXISTS;  
    }  
    mThread = std::make_unique<InputThread>(  
            "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });  
    return OK;  
}

这里的初始化,我们可以看到跟前面的InputDispatch很类似,连InputThread用的都是同一个类,内部也就一样有InputThreadImpl了。这里则是调用了InputReader内部的loopOnce方法。到这里系统就完成了输入事件分发的初始化了。

我们在看事件的分发之前,先看一下应用中的接收和系统的InputDispatch进行连接的过程。

InputChannel的注册

我们之前分析应用层的事件传递的时候,只是谈到了InputChannel是在WMS调用如下代码生成的:

mInputChannel = mWmService.mInputManager.createInputChannel(name); 

但是内部如何创建InputChannel的,以及 这个InputChannel是如何收到消息的我们都没有涉及,我们现在继续分析它一下。这个createInputChannel内部最终会调用到native层的InputDispatchercreateInputChannel方法, 代码如下:

Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::string& name) {  
    std::unique_ptr<InputChannel> serverChannel;  
    std::unique_ptr<InputChannel> clientChannel;  
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);  
    ...
    { // acquire lock  
        std::scoped_lock _l(mLock);  
        const sp<IBinder>& token = serverChannel->getConnectionToken();  
        int fd = serverChannel->getFd();  
        sp<Connection> connection =  
                n1ew Connection(std::move(serverChannel), false /*monitor*/, mIdGenerator);  
        ...
        mConnectionsByToken.emplace(token, connection);  
  
        std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback, this, std::placeholders::_1, token);  
  
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr);  
    } // release lock  
  
    // Wake the looper because some connections have changed.    
    mLooper->wake();  
    return clientChannel;  
}

首先是第4行代码,这里创建了InputChannel,而它又分为serverChannelclientChannel,返回调用方的是`clientChannel。

我们先进去看看其源码:

status_t InputChannel::openInputChannelPair(const std::string& name,  
                                            std::unique_ptr<InputChannel>& outServerChannel,  
                                            std::unique_ptr<InputChannel>& outClientChannel) {  
    int sockets[2];  
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {  //创建socket对
	    ..
        return result;  
    }  
    ..
    sp<IBinder> token = new BBinder();  
  
    std::string serverChannelName = name + " (server)";  
    android::base::unique_fd serverFd(sockets[0]);  //获取server socket fd
    outServerChannel = InputChannel::create(serverChannelName, std::move(serverFd), token);  //创建server InputChannel
  
    std::string clientChannelName = name + " (client)";  
    android::base::unique_fd clientFd(sockets[1]);  
    outClientChannel = InputChannel::create(clientChannelName, std::move(clientFd), token);  //创建Client InputChannel
    return OK;  
}

以上代码我们可以看到就是创建了一对socket,分别放到两个InputChannel当中,并且这里创建了一个BBinder作为两个InputChannel的token,具体用处我们后面会再提到。此时可以继续回看前面的createInputChannel方法,在11行,创建了一个 Connection对象,并且以前面创建的BBinder为key放到了mConnectionsByToken当中,Connection的用处留到后面继续讲。

在15行创建了一个callback,其中会执行InputDispatcherhandleReceiveCallback方法,并且这个callback被添加looper的addFd的时候设置进去了,这里的fd就是之前创建的ServerInputChannel的socket的文件描述符。到这里就完成了初始化,添加了服务端InputChannel的文件描述符监听。

事件触发

我们之前在分析InputManger的启动的时候,已经看到了事件是通过/dev/input来通知到EventHub,而InputReader通过Looper监听了/dev/input的文件描述符,从而让我们事件传递的系统动起来。那么我们首先就从InputReaderloopOnce开始看起来。

void InputReader::loopOnce() {  
	...
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);  
  
    { // acquire lock  
        std::scoped_lock _l(mLock);  
        mReaderIsAliveCondition.notify_all();  
  
        if (count) {  
            processEventsLocked(mEventBuffer, count);  
        }  
        ...
    } // release lock  
    ...
    mQueuedListener.flush();  
}

我们这里省略了设备变化,超时等相关的代码,仅仅保留了事件读取相关的部分。我们看到,首先在第3行中,从EventHub中去获取新的事件,之后在第10行,去处理这些事件,第15行会清楚所有的事件,我们分别看看各个里面的逻辑。

从EventHub读取事件

首先是getEvents方法:

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {  
    std::scoped_lock _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);  

        bool deviceChanged = false;  
        //pendingIndex小于PendingCount,说明之前有事件还为处理完
        while (mPendingEventIndex < mPendingEventCount) {  
            const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];  
            ...
            Device* device = getDeviceByFdLocked(eventItem.data.fd);  
            if (device == nullptr) {  //未能找到device,报错跳出
                continue;  
            }  
            
            // EPOLLIN表示有事件可以处理
            if (eventItem.events & EPOLLIN) {  
                int32_t readSize =  
                        read(device->fd, readBuffer, sizeof(struct input_event) * capacity);  
                if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {  
                    // 接收到通知之前,设备以及不见了
                    deviceChanged = true;  
                    closeDeviceLocked(*device);  
                } else if() { //其中的错误情况,忽略掉
                } else {  
                    int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;  
  
                    size_t count = size_t(readSize) / sizeof(struct input_event);  //根据一个事件的大小,来算同一个设备上面读取到的事件的个数
                    //以下为具体保存事件到event当中
                    for (size_t i = 0; i < count; i++) {  
                        struct input_event& iev = readBuffer[i];  
                        event->when = processEventTimestamp(iev);  
                        event->readTime = systemTime(SYSTEM_TIME_MONOTONIC);  
                        event->deviceId = deviceId;  
                        event->type = iev.type;  
                        event->code = iev.code;  
                        event->value = iev.value;  
                        event += 1;  
                        capacity -= 1;  
                    }  
                    if (capacity == 0) {  //缓冲区已经满了,无法在记录事件,跳出
                        mPendingEventIndex -= 1;  
                        break;  
                    }  
                }  
            } else if (eventItem.events & EPOLLHUP) {  
               ... 
            } else {  
	            ...
            }  
        }  
        ...
        //event和buffer地址不同说明已经拿到事件了,可以跳出循环 
        if (event != buffer || awoken) {  
            break;  
        }  

        mPendingEventIndex = 0;  
        mLock.unlock(); // poll之前先加锁
        int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);  
        mLock.lock(); // poll完之后从新加锁
  
        if (pollResult == 0) {  
            // Timed out.  
            mPendingEventCount = 0;  
            break;  
        }  
  
        if (pollResult < 0) {  
            mPendingEventCount = 0;  
            if (errno != EINTR) {  
                usleep(100000);  
            }  
        } else {  
            mPendingEventCount = size_t(pollResult);  
        }  
    }  
  
    // event为填充之后的指针地址,而buffer为开始的地址,相减获得count
    return event - buffer;  
}

这个方法是很复杂的,但是我们主要分析事件的分发,因此其中关于设备变化,设备响应,错误处理等等相关的代码都省略了。这个方法,我们传入了一个RawEvent的指针用来接收事件,另外传了bufferSize来表示我们所能接收的事件数量。这个方法使用了两层循环来进行逻辑的处理,外层的为无限循环。当我们第一次进入这个方法当中,mPendingEventCountmPendingEventIndex都是0,因此不会进入第二层的循环,这个时候会执行到64行,调用epoll_wait系统调用,去读取事件,读取的结果会放到mPendingEventItems当中,之后会算出pendingCount。这样继续循环,我们就可以进入内存循环当中了。 在刚刚的PendingEventItem中并没有存储具体的事件,而是存储的事件发生的设备文件描述符,在内存的循环中,首先会根据设备的描述符查找设备,并对其进行检查。之后再从设备当中读取事件,拼装成为需要向后分发的事件。 这里的count有点让人迷糊,我画了个图如下所示:

其中我们真正读取的事件的数量,是要看有几个设备,每个设备有多少个事件,对其进行计算。 到这里我们就获取到了事件,这里可以回到InputReader中继续往下看了。

InputReader对事件进行处理

在这里的处理调用的是processEventsLocked,代码如下:

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {  
    for (const RawEvent* rawEvent = rawEvents; count;) {  
        int32_t type = rawEvent->type;  
        size_t batchSize = 1;  
        //如果不是设备处理相关的事件,则执行。
        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {  
            int32_t deviceId = rawEvent->deviceId;  
            while (batchSize < count) {   
                if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT ||  
                    rawEvent[batchSize].deviceId != deviceId) {  
                    //当遇到设备整删除事件,或者不是当前设备的事件,就不能进行批量处理,跳过。
                    break;  
                }  
                batchSize += 1;  
            }  
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);  
        } else {  
            //设备添加删除之类的事件处理,跳过
        }  
        count -= batchSize;  
        rawEvent += batchSize;  
    }  
}

这个方法中主要是对与设备增加删除事件和普通事件进行分别处理,如果是普通的事件,会对同一个设备上的事件进行批量处理,批量处理则会调用processEventsForDeviceLocked方法:

void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,  
                                               size_t count) {  
    auto deviceIt = mDevices.find(eventHubId);  
    if (deviceIt == mDevices.end()) {  
        //没有找到设备,返回
        return;  
    }  
  
    std::shared_ptr<InputDevice>& device = deviceIt->second;  
    if (device->isIgnored()) {  //是被忽略的设备,跳过
        return;  
    }  
  
    device->process(rawEvents, count);  
}

这个方法中主要是查找设备,找到未忽略的设备则会调用设备的process方法进行处理。 InputDevice只是设备的抽象,而其中的处理又会调用InputMapper的方法,InputMapper是抽象类,它有许多的实现,比如我们的触摸事件就会有TouchuInputMapperMultiTouchInputMapper,各种不同的InputMapper会对事件进行处理,拼装成符合相关类型的事件,其中逻辑我们就不继续进行追踪了。

对于touch事件,这个process处理完成,在TouchInputMapper中最终会调用dispatchMotion,这个方法代码如下:

void TouchInputMapper::dispatchMotion(...) {  
    PointerCoords pointerCoords[MAX_POINTERS];  
    PointerProperties pointerProperties[MAX_POINTERS];  
    uint32_t pointerCount = 0;  
    ...
    const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE);  
    const int32_t deviceId = getDeviceId();  
    std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();  
    std::for_each(frames.begin(), frames.end(),  
                  [this](TouchVideoFrame& frame) { frame.rotate(this->mInputDeviceOrientation); });  
    NotifyMotionArgs args(getContext()->getNextId(), when, readTime, deviceId, source, displayId,  
                          policyFlags, action, actionButton, flags, metaState, buttonState,  
                          MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties,  
                          pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition,  
                          downTime, std::move(frames));  
    getListener().notifyMotion(&args);  
}

其中有许多关于多点触控,事件处理的判断,这里只关注最后的部分,就是将事件组装成一个NotifyMotionArgs对象,并调用ListenernotifyMotion方法。这里的getListener()内部首先会调用getContenxt获取Context,而这个Context就是InputReader的内部成员mContext,这这个Listener也就是我们之前在初始化InputReader时候它的成员变量mQueuedListener,那我们下面继续去看它的notifyMotion

notifyMotion

void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {  
    traceEvent(__func__, args->id);  
    mArgsQueue.emplace_back(std::make_unique<NotifyMotionArgs>(*args));  
}

这里是直接把之前的那个变量放到mArgsQueue当中了。这个时候,我们需要留意一下之前InputReadeloopOnce的15行,这里调用的 flush方法,也是这个QueuedInputListener内部的:

void QueuedInputListener::flush() {  
    for (const std::unique_ptr<NotifyArgs>& args : mArgsQueue) {  
        args->notify(mInnerListener);  
    }  
    mArgsQueue.clear();  
}

这里这是掉用了我们传进来的NotifyArgs的notify方法,并且传过来的参数mInnerListener是我们之前创建InputManager时候创建的,这里会有三层嵌套,首先是UnWantedInteractionBlocker先处理,之后它会按情况传递给InputClassifier处理,最后是在InputDispatcher当中处理。

我们先看看看notify当中做了什么,再继续往后看。

void NotifyMotionArgs::notify(InputListenerInterface& listener) const {  
    listener.notifyMotion(this);  
}

这里也是比较简单,就是直接调用了linster的notifyMotion方法,我们可以直接去看了。因为我们主要关注 传递,而不关注处理,这里就跳过,直接看InputDispatcher中的这个方法。

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;  
  
    android::base::Timer t;  
   
    bool needWake = false;  
    { // acquire lock  
        mLock.lock();  
        ...
        std::unique_ptr<MotionEntry> newEntry =  
                std::make_unique<MotionEntry>(args->id, args->eventTime, args->deviceId,  
                                              args->source, args->displayId, policyFlags,  
                                              args->action, args->actionButton, args->flags,  
                                              args->metaState, args->buttonState,  
                                              args->classification, args->edgeFlags,  
                                              args->xPrecision, args->yPrecision,  
                                              args->xCursorPosition, args->yCursorPosition,  
                                              args->downTime, args->pointerCount,  
                                              args->pointerProperties, args->pointerCoords);  
        ...
        needWake = enqueueInboundEventLocked(std::move(newEntry));  
        mLock.unlock();  
    } // release lock  
  
    if (needWake) {  
        mLooper->wake();  
    }  
}

在这里则是执行完一些检查之后,把事件封装成为MotionEntry,调用enqueueInboundEventLocked,最后调用looperwake方法。enqueueInboundEventLocked代码如下:

bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newEntry) {  
    bool needWake = mInboundQueue.empty();  
    mInboundQueue.push_back(std::move(newEntry));  
    EventEntry& entry = *(mInboundQueue.back());  
    switch (entry.type) {  
        case EventEntry::Type::MOTION: {  
            if (shouldPruneInboundQueueLocked(static_cast<MotionEntry&>(entry))) {   //返回true的时候,事件会被移除不处理
                mNextUnblockedEvent = mInboundQueue.back();  
                needWake = true;  
            }  
            break;  
        }  
        ...
    }  
  
    return needWake;  
}

在这里,首先把事件放入mInboundQueue这个deque当中,最后根据事件的类型和信息要不要唤醒looper,如果事件不被移除needWake就为false,前面的wake也不会被调用。但是这个是否调用,不影响我们的后续分析,因为InputDispatch中的Thead会一直循环调用。

InputDispatcher分发消息

说到这里,我们就该来看看InputDispatcherdispatchOnce方法了:

void InputDispatcher::dispatchOnce() {  
    nsecs_t nextWakeupTime = LONG_LONG_MAX;  
    { // acquire lock  
        std::scoped_lock _l(mLock);  
        mDispatcherIsAlive.notify_all();  
  
        if (!haveCommandsLocked()) {  
            dispatchOnceInnerLocked(&nextWakeupTime);  
        }  
  
        if (runCommandsLockedInterruptable()) {  
            nextWakeupTime = LONG_LONG_MIN;  
        }  
        ...
    } // release lock  
  
    //等待下一次调用
    mLooper->pollOnce(timeoutMillis);  
}

这里有不少处理下一次唤醒的逻辑,我们都跳过,主要就看一下第8行,进行这一次的实际执行内容:

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {  
	...
    if (!mPendingEvent) {  //当前没有待处理的pending事件
        if (mInboundQueue.empty()) {  //如果事件列表为空
            ... 
            if (!mPendingEvent) {  
                return;  
            }  
        } else {  
            // 列表中拿一个事件
            mPendingEvent = mInboundQueue.front();  
            mInboundQueue.pop_front();  
            traceInboundQueueLengthLocked();  
        }  
        ...
    }  
  
    bool done = false;  
    ..
    switch (mPendingEvent->type) {  
		...
        case EventEntry::Type::MOTION: {  
            std::shared_ptr<MotionEntry> motionEntry =  
                    std::static_pointer_cast<MotionEntry>(mPendingEvent);  
            ...
            done = dispatchMotionLocked(currentTime, motionEntry, &dropReason, nextWakeupTime);  
            break;  
        }  
        ...
    }  
  
    if (done) {  
        ...
        releasePendingEventLocked();  
        *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately  
    }  
}

我们将这个方法进行了简化,仅仅保留了触摸事件的部分代码。首先判断mPendingEvent是否为空,为空的时候我们需要到mPendingEvent中去拿一个,我们之前插入的是尾部,这里是从头部取的。拿到事件进行完种种处理和判断之后,会调用dispatchMotionLocked进行触摸事件的分发:

bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr<MotionEntry> entry,  
                                           DropReason* dropReason, nsecs_t* nextWakeupTime) {  
    if (!entry->dispatchInProgress) {   //设置事件正在处理中
        entry->dispatchInProgress = true;  

    }  
  
    if (*dropReason != DropReason::NOT_DROPPED) {  
        //对于要抛弃的事件这里进行处理,返回
        return true;  
    }  
  
    const bool isPointerEvent = isFromSource(entry->source, AINPUT_SOURCE_CLASS_POINTER);  //读取是否为POINTER
    std::vector<InputTarget> inputTargets;  
  
    bool conflictingPointerActions = false;  
    InputEventInjectionResult injectionResult;  
    if (isPointerEvent) {  
	    //如果屏幕触摸事件则去找到对应的window
        injectionResult =  
                findTouchedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime,  
                                               &conflictingPointerActions);  
    } else {  
        // Non touch event.  (eg. trackball)  
        injectionResult =  
                findFocusedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime);  
    }  
    if (injectionResult == InputEventInjectionResult::PENDING) {  
        return false;  
    }  
  
    setInjectionResult(*entry, injectionResult);  
    ...
  
    // Dispatch the motion.  
    dispatchEventLocked(currentTime, entry, inputTargets);  
    return true;  
}

这个方法中依然是对于事件做很多的处理和判断,比如否要抛弃等。但是其中最终要的是调用findFocusedWIndowTargetsLocked来找到我们的事件所对应的Window,并且保存相关信息到inputTargets当中,这里获取inputTargets的过程比较复杂,但是简单来说呢就是从之前我们保存在InputDispatcher中的mConnectionsByToken中查找到对应的条目,这里暂不深入分析。拿到这个之后就是调用dispatchEventLocked去分发,代码如下:

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,  
                                          std::shared_ptr<EventEntry> eventEntry,  
                                          const std::vector<InputTarget>& inputTargets) {  
    ...
    for (const InputTarget& inputTarget : inputTargets) {  
        sp<Connection> connection =  
                getConnectionLocked(inputTarget.inputChannel->getConnectionToken());  
        if (connection != nullptr) {  
            prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);  
        } else {  
            
        }  
    }  
}

通过这里我们可以看到首先是通过inputTarget去拿到connectionToken,再通过它拿到Connection。最后通过调用prepareDispatchCycleLocked

void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,  
                                                 const sp<Connection>& connection,  
                                                 std::shared_ptr<EventEntry> eventEntry,  
                                                 const InputTarget& inputTarget) {  
    ...
    enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);  
}

这个方法简化的化,这是调用第6行的这个方法,代码如下:

void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,  
                                                   const sp<Connection>& connection,  
                                                   std::shared_ptr<EventEntry> eventEntry,  
                                                   const InputTarget& inputTarget) {  
  
    bool wasEmpty = connection->outboundQueue.empty();  
  
    // 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.empty()) {  
        startDispatchCycleLocked(currentTime, connection);  
    }  
}

其中对于消息会尝试按照每一种mode都调用enqueueDIspatchEntryLocked方法,代码如下:

void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection,  
                                                 std::shared_ptr<EventEntry> eventEntry,  
                                                 const InputTarget& inputTarget,  
                                                 int32_t dispatchMode) {  
    
    int32_t inputTargetFlags = inputTarget.flags;  
    if (!(inputTargetFlags & dispatchMode)) {  
        return;  
    }  
    inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode;  
  
    std::unique_ptr<DispatchEntry> dispatchEntry =  
            createDispatchEntry(inputTarget, eventEntry, inputTargetFlags);  
  
    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);  
            constexpr int32_t DEFAULT_RESOLVED_EVENT_ID =  
                    static_cast<int32_t>(IdGenerator::Source::OTHER);  
            dispatchEntry->resolvedEventId = DEFAULT_RESOLVED_EVENT_ID;  
            ...
            
            
            if ((motionEntry.flags & AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE) &&  
                (motionEntry.policyFlags & POLICY_FLAG_TRUSTED)) {  
                break;  
            }  
  
            dispatchPointerDownOutsideFocus(motionEntry.source, dispatchEntry->resolvedAction,  
                                            inputTarget.inputChannel->getConnectionToken());  
            break;  
        }  
        ...
    }  
    connection->outboundQueue.push_back(dispatchEntry.release());  
    traceOutboundQueueLength(*connection);  
}

在这个方法中,又把事件封装成为dispatchEntry,并放到Connection内部的outboundQueue这个队列当中。

到这里我们可以回看上面的enqueueDispatchEntriesLocked的最后一块代码,那里有判断了如果这个outboundQueue队列不为空,则会执行最后的startDispatchCycleLocked,代码如下:

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,  
                                               const sp<Connection>& connection) {  
    
    while (connection->status == Connection::Status::NORMAL && !connection->outboundQueue.empty()) {  
        DispatchEntry* dispatchEntry = connection->outboundQueue.front();  
        dispatchEntry->deliveryTime = currentTime;  
        ...
        // Publish the event.  
        status_t status;  
        const EventEntry& eventEntry = *(dispatchEntry->eventEntry);  
        switch (eventEntry.type) {   
            ...
            case EventEntry::Type::MOTION: {  
                const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry);  
                ... 
  
                std::array<uint8_t, 32> hmac = getSignature(motionEntry, *dispatchEntry);  
  
                status = connection->inputPublisher  
                                 .publishMotionEvent(dispatchEntry->seq,  
                                                     dispatchEntry->resolvedEventId,  
                                                     motionEntry.deviceId, motionEntry.source,  
                                                     motionEntry.displayId, std::move(hmac),  
                                                     dispatchEntry->resolvedAction,  
                                                     motionEntry.actionButton,  
                                                     dispatchEntry->resolvedFlags,  
                                                     motionEntry.edgeFlags, motionEntry.metaState,  
                                                     motionEntry.buttonState,  
                                                     motionEntry.classification,  
                                                     dispatchEntry->transform,  
                                                     motionEntry.xPrecision, motionEntry.yPrecision,  
                                                     motionEntry.xCursorPosition,  
                                                     motionEntry.yCursorPosition,  
                                                     dispatchEntry->rawTransform,  
                                                     motionEntry.downTime, motionEntry.eventTime,  
                                                     motionEntry.pointerCount,  
                                                     motionEntry.pointerProperties, usingCoords);  
                break;  
            }  
        }  
        ... 
        
    }  
}

在这个方法中,则是从outboundQueue把所有的事件一条一条的取出来,解包成它要的类型,比如触摸事件就是MotionEntry,经过判断和一些处理之后,调用connection中的inputPublisherpublishMotionEvent方法,这里的inputPublisher我们之前分析创建InputChannel的时候有所了解,创建它所传的InputChannel为Server端的那个。 我们这里看一下它的publishMotionEvent方法:

status_t InputPublisher::publishMotionEvent(...) {  
    
    InputMessage msg;  
    msg.header.type = InputMessage::Type::MOTION;  
    msg.header.seq = seq;  
    msg.body.motion.eventId = eventId;  
    ...
    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);  
}

这里主要创建了InputMessage,将之前MotionEvent的所有参数放进去,通过ServerInputChannel调用sendMessage发送出去,sendMessage的代码如下:

status_t InputChannel::sendMessage(const InputMessage* msg) {  
    const size_t msgLength = msg->size();  
    InputMessage cleanMsg;  
    msg->getSanitizedCopy(&cleanMsg);  
    ssize_t nWrite;  
    do {  
        nWrite = ::send(getFd(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);  
    } while (nWrite == -1 && errno == EINTR);  

    return OK;  
}

我们知道,InputChannel内部的文件描述符为socket的标记,这里调用send方法,也就是通过socket把信息发送出去,这样的话,我们Client端的的socket也就会接收到,通过Looper,Client端的EventListener就可以接收到消息,我们的应用便可以接收到,到这里便把事件分发,完整的串起来了。

总结

以上就是事件在系统进程中的处理,包括它的事件获取,事件处理,最后通过socket发送,这样我们在客户端进程的InputChannel就能够接收到通知,客户端能够处理事件。配合我们之前分析过应用层的事件分发,到这里,不算事件的驱动相关的部分,事件分发的整个流程我们都有所了解了。

在这里事件从系统system_server通过Server的InputChannel发送的客户端的InputChannel,所采用的是unix的socket功能,而不是使用的binder或者其他的跨进程服务。这一块,结合我在网上查找的资料,以及我自己的想法,我想这里这样做的原因是,unix的sockt pair使用上很简单,并且运行效率很高效,不需要像binder一样涉及到进程和线程的切换。另外就是socket使用了fd,目标进程可以直接监听到事件的来临,而不是向binder一样需要有相应的接口涉及,可以更加实时的接收到事件,也不会因为binder线程阻塞而卡顿。

当然这是我的一些想法,也欢迎读者朋友说说你对于这块的想法。