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

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

前言

本文意图是打通全体流程,旨在对Input体系从收到驱动数据到传递到客户端去消费的全体过程有一个全体的知道。各阶段的战略细节会在别的的文章别离解说,以免文章过重分支过多导致混乱,使读者难以把握主线。

1 Input服务初始化

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

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 客户端建议注册

流程如图:

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

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 总结

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

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

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

3 作业生成与分发

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

本文自下而上,从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] == '' ||
            (de->d_name[1] == '.' && de->d_name[2] == '')))
            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 eventn", 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*/);
}

对作业的加工处理比较繁复,会在专门的文章中研讨,本文不讨论。

这儿只放出要害流程图,本文意图是打通首要流程,对于这部分咱们只重视下加工出的成果放在哪里。

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

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

3.1.3 把作业发送给InputDispatcher — flush

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

上一节终究生成了一个 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传递过来的作业分发出去。

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

提示:接下来的代码略长,阅读本文时可以疏忽代码细节,每段代码结尾会有简略描绘,本末节的具体细节会在别的的文章专门讨论。

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 客户端处理作业分发

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

服务端发送数据触发客户端注册的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);
    }
}

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

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

只需知道,从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服务

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

创立了InputReader和InputDispatcher,并别离创立了对应他们的Thread,发动线程开端循环作业。

2 客户端建议处理input的注册

安卓 Input 机制(1)全体流程打通
生成一堆相互连接的socket别离由两个InputDispatcher持有,一个dispatcher分配给客户端,一个分配给服务端,并注册,便是把socket增加给Looper注册监听文件描绘符,这样客户端服务端相互发送数据就可以唤醒对方处理了。

3 驱动发生input作业,怎么获取作业并加工分发

3.1 InputReader担任对接驱动和InputDispatcher,从驱动取数据并加工,然后放入行列等候InputDispatcher消费处理

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

3.2 InputDispatcher拿到InputReader加工后数据,担任分发给合适的客户端,他需求寻觅正确方针,即找出焦点窗口处理作业,然后经过InputChannel 持有的socket发送数据给方针。

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

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

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