Do you know how an event is transmitted to an Activity? Ps: I am in the telephone that meng πŸ™ˆ, a moment of words, is to build a rocket? Analysis based on Android11 source code

Back to the point, whether we build rockets or not, let’s look at this problem, this thing: understand

We use thread.dumpStack () to print the stack information for the current Thread in the dispatchTouchEvent method we copy inside the Activity:

java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1523)
at com.melody.demo.MainActivity.dispatchTouchEvent(MainActivity.kt:31)
at androidx.appcompat.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:69)
at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:679)
at android.view.View.dispatchPointerEvent(View.java:13961)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:6402)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:6197)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5586)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5639)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5605)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5763)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5613)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:5820)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5586)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5639)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5605)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5613)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:5586)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:8680)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:8600)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:8553)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:8938)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:239)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:363)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:8668)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1109)
Copy the code

We refer to the stack information above to analyze the source code inside: note: do not look at the line number, we need to look at the source code before and after

1. ZygoteInit. The main function

The main function is the opening entry:

//com.android.internal.os.ZygoteInit

public static void main(String argv[]) {
        // Replace some code with ellipses....try{...if (startSystemServer) {
                // Fork out the child process SystemServer
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
                if(r ! =null) {
                    r.run();
                    return; }}//caller.run() executes the internal method
            // Loop to read the message and get the message sent by the child process
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            throw ex;
        } finally{... }if(caller ! =null) { caller.run(); }}Copy the code

RuntimeInit$methodAndargScaller. run = “forkSystemServer”; RuntimeInit$methodAndargScaller. run = “forkSystemServer”

//com.android.internal.os.ZygoteInit

private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        ....
        // Hardcode the parameter string args to start the System Server
        String args[] = ...
        ZygoteArguments parsedArgs = null;
        try {
            // the zygote command line arguments parse args into the required argumentsparsedArgs = new ZygoteArguments(args); ./ / create SystemServer forkpid = Zygote.forkSystemServer(....) ; }catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }
        if (pid == 0) {// Indicates child process execution.return handleSystemServerProcess(parsedArgs);
        }
        return null;
    }
Copy the code

Then playing music and dance, and we see handleSystemServerProcess do?

//com.android.internal.os.ZygoteInit

private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
        ....
        if(parsedArgs.mInvokeWith ! =null) { String[] args = parsedArgs.mRemainingArgs; .// Start application process
            WrapperInit.execApplication(parsedArgs.mInvokeWith,
                    parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(), null, args);
        } else {
            ClassLoader cl = null;
            if(systemServerClasspath ! =null) {
                // Create a classloader
                cl = createPathClassLoader(systemServerClasspath, parsedArgs.mTargetSdkVersion);
                // Assign the current thread
                Thread.currentThread().setContextClassLoader(cl);
            }
            returnZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion, parsedArgs.mDisabledCompatChanges, parsedArgs.mRemainingArgs, cl); }}Copy the code

Let’s look at what zygoteInit does:

//com.android.internal.os.ZygoteInit

public static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {...// Redirect System.out and System.err to the Android log.
        RuntimeInit.redirectLogStreams();
        // General initialization: exception capture, reset log configuration, network traffic statistics, etc
        RuntimeInit.commonInit();
        // Don't understand, ha ha ha
        ZygoteInit.nativeZygoteInit();
        // The ActivityThread's main method is finally entered
        return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
                classLoader);
    }
Copy the code

2. Main function of ActivityThread

ApplicationInit: applicationInit: applicationInit: applicationInit

protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {...return findStaticMain(args.startClass, args.startArgs, classLoader);
    }
Copy the code

Watch out, little brother findStaticMain:

//com.android.internal.os.RuntimeInit

protected static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) { Class<? > cl;try {
            / / by className (" android. App. ActivityThread ") reflection ActivityThread class
            //className is passed from somewhere else, such as AMS, and is not unique
            cl = Class.forName(className, true, classLoader);
        } catch (ClassNotFoundException ex) {
            throw newRuntimeException(....) ; } Method m;try {
            // Get the main function of ActivityThread
            m = cl.getMethod("main".new Class[] { String[].class });
        } catch (NoSuchMethodException ex) {
            throw newRuntimeException(...) ; }catch (SecurityException ex) {
            throw newRuntimeException(...) ; }int modifiers = m.getModifiers();
        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
            throw newRuntimeException(...) ; }return new MethodAndArgsCaller(m, argv);
    }
    

static class MethodAndArgsCaller implements Runnable {
    public MethodAndArgsCaller(Method method, String[] args) {
      mMethod = method;
      mArgs = args;
    }
    public void run(a) {
            try {
                // Start executing the main method of ActivityThread
                mMethod.invoke(null.new Object[] { mArgs });
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InvocationTargetException ex) {
                Throwable cause = ex.getCause();
                if (cause instanceof RuntimeException) {
                    throw (RuntimeException) cause;
                } else if (cause instanceof Error) {
                    throw (Error) cause;
                }
                throw newRuntimeException(ex); }}}Copy the code

RuntimeInit$methodAndArgscaller. run, which will execute activityThread.main (args) via invoke

3.InputEventReceiver.dispatchInputEvent

When we print the stack information at the beginning of this article, we can see that the order of execution is:

Looper.loop() -> Message.getNext() -> nativePollOnce(ptr,nextPollTimeoutMillis)
-> InputEventReceiver.dispatchInputEvent
Copy the code

3.1 Looper.nativePollOnce

Click to view the source code of android_os_MessageQueue. CPP

//frameworks/base/core/jni/android_os_MessageQueue.cpp
// Partial implementation
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj, jlong ptr, jint timeoutMillis) {
    NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
    nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}
Copy the code

The MessageQueue of the Java layer corresponds to the NativeMessageQueue of the Native layer

void NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
    mPollEnv = env;
    mPollObj = pollObj;
    // Native Looper pollOnce() is called
    mLooper->pollOnce(timeoutMillis);
    mPollObj = NULL;
    mPollEnv = NULL; . }Copy the code

Click to view looper.cpp source code

//system/core/libutils/Looper.cpp

int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) {
    int result = 0;
    for(;;) {... result =pollInner(timeoutMillis); }}// If you like to see more details, you can click on the above link to see the source code yourself
int Looper::pollInner(int timeoutMillis) {
    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    // Block until ePoll returns an event, and then process the Message and fd event
    int eventCount = epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis); .for (int i = 0; i < eventCount; i++) {
        // Process each event read
        int fd = eventItems[i].data.fd;
        uint32_tepollEvents = eventItems[i].events; .ssize_t requestIndex = mRequests.indexOfKey(fd); .// Process the request and generate the corresponding reponse object and push it into the mResponses array
        pushResponse(events, mRequests.valueAt(requestIndex)); } Done: ; .// Invoke all response callbacks.
    for (size_t i = 0; i < mResponses.size(a); i++) { Response& response = mResponses.editItemAt(i);
        if (response.request.ident == POLL_CALLBACK) {
            int fd = response.request.fd;
            int events = response.events;
            void* data = response.request.data;
            HandleEvent = handleEvent = handleEvent = handleEvent
            int callbackResult = response.request.callback->handleEvent(fd, events, data); . result = POLL_CALLBACK; }}return result;
}

// If Looper is blocked, wake() can be used to wake it.
// Writing "1" to mWakeEventFd causes epoll_WAIT to return, thus canceling the polling status.
void Looper::wake(a) {
    uint64_t inc = 1;
   /* * write data to mWakeEventFd to wake up the queue * when this method is called, epoll_wait returns, Up the call chain * pollInner->pollOnce->pollOnce->android_os_MessageQueue_nativePollOnce->nativePollOnce->next * Next () of looper.loop () is returned, and the body of the loop continues executing */
    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mWakeEventFd.get(), &inc, sizeof(uint64_t)));
}
Copy the code

Callback – > 3.2 handleEvent

Have a look at the response. The request. The callback – > handleEvent (fd, events, data)

//system/core/libutils/Looper.cpp

SimpleLooperCallback::SimpleLooperCallback(Looper_callbackFunc callback) :
        mCallback(the callback) {} πŸ‘† πŸ‘† πŸ‘† πŸ‘†int SimpleLooperCallback::handleEvent(int fd, int events, void* data) {
    return mCallback(fd, events, data);
}
Copy the code

The source code to here, just feeling is broken, so what’s triggering InputEventReceiver. DispatchInputEvent? So we’re going to have to start with InputEvent. We know that Android has a class called InputManagerService. How do you create that? Take a look at the SystemServer.java code

3.3 SystemServer

//com.android.server.SystemServer

public final class SystemServer{
    public static void main(String[] args) {
        new SystemServer().run();
    }
    private void run(a) {.../ / create InputManagerService
        // Give it to the ServiceManager
        // Bind the WMS InputManagerCallback
        / / execution inputMagerService. Start ()startOtherServices(t); }}Copy the code

3.4 new InputManagerService

The constructor will call: nativeInit() to initialize InputManagerService at the Native layer: click to view the source inputManagerService.cpp

//frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {...//NativeInputManager internally created [InputManager], interested in self view source learning
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}
Copy the code

Now what does InputManager start with? Click to view the InputManager source code

//platform/frameworks/native/services/inputflinger/InputManager.cpp
InputManager::InputManager(
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    // Initialize InputDispatcher
    mDispatcher = createInputDispatcher(dispatcherPolicy);
    // Initialize InputReader
    mReader = createInputReader(readerPolicy, mClassifier);
}
Copy the code

Inside the main function of SystemServer performed InputManagerService. Start ()

//platform/frameworks/native/services/inputflinger/InputManager.cpp

status_t InputManager::start(a) {
    //InputDispatcher.start()
    status_t result = mDispatcher->start(a);if (result) {
        return result;
    }
    //InputReader.start()
    result = mReader->start(a);if (result) {
        //InputDispatcher.stop()
        mDispatcher->stop(a);return result;
    }
    return OK;
}
Copy the code

Click to view the inputDispatcher.cpp source code

//frameworks/native/services/inputflinger/InputDispatcher.cpp
status_t InputDispatcher::start(a) {
    if (mThread) {
        return ALREADY_EXISTS;
    }
    mThread = std::make_unique<InputThread>(
            "InputDispatcher"[this] () {dispatchOnce(a); },this]() { mLooper->wake(a); });return OK;
}
Copy the code

Click to view the inputreader.cpp source code

//platform/frameworks/native/services/inputflinger/reader/InputReader.cpp
status_t InputReader::start(a) {
    if (mThread) {
        return ALREADY_EXISTS;
    }
    mThread = std::make_unique<InputThread>(
            "InputReader"[this] () {loopOnce(a); },this]() { mEventHub->wake(a); });return OK;
}
Copy the code

Code see here, it is not clear which will go to the back, found a new thing click to view EventHub. CPP source good guy, feel do system layer development is too helpless pain, a lot of things πŸ€”

//platform/frameworks/native/services/inputflinger/reader/EventHub.cpp

void EventHub::wake(a) {
    ssize_t nWrite;
    do {
        //EventHub::getEvents ΒΆ
        //int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis)
        MWakeWritePipeFd = "wake writepipefd";
        / / wake epoll_wait
        nWrite = write(mWakeWritePipeFd, "W".1);
    } while (nWrite == - 1&& errno == EINTR); . }Copy the code

Going back to loopOnce() above, EventHub::wake() is executed only after this method is executed

//platform/frameworks/native/services/inputflinger/reader/InputReader.cpp

void InputReader::loopOnce(a) {...size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
    {
        mReaderIsAliveCondition.broadcast(a);if (count) {
            // Handle the event
            processEventsLocked(mEventBuffer, count); }... }... mQueuedListener->flush(a); }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) {
            ...
            // Data event processing
            processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
        } else{... }... }}void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,size_t count) {
    ...
     std::shared_ptr<InputDevice>& device = deviceIt->second;
    device->process(rawEvents, count);
}
Copy the code

Click to view the source code of InputDevice.cpp

//platform/hardware/libhardware/modules/input/evdev/InputDevice.cpp

void InputDevice::process(const RawEvent* rawEvents, size_t count) {
    for (constRawEvent* rawEvent = rawEvents; count ! =0; rawEvent++) {
        ...
        if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
            mDropUntilNextSync = true;
            reset(rawEvent->when);
        } else {
            for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) {
                // Call the specific InputMapper
                mapper.process(rawEvent); }); } --count; }}Copy the code

Mapper.process (event) directly after the execution of some methods in order to execute: click to see touchinputmapper.cpp source code

//platform/frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp

void TouchInputMapper::process(const RawEvent* rawEvent)
void TouchInputMapper::sync(nsecs_t when) 
void TouchInputMapper::processRawTouches(bool timeout)
void TouchInputMapper::cookAndDispatch(nsecs_t when)
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags)
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
int32_t action, int32_t actionButton, int32_t flags,...)
Copy the code

TouchInputMapper: : dispatchMotion method finally is called:

void TouchInputMapper::dispatchMotion(...).{...getListener() - >notifyMotion(&args);
}

getListener() is actuallyInputDispatcher

void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) 
Copy the code

The inputDispatcher.start () method is called in the sequence of the methods that are called in the inputDispatcher.start () method.

//frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::dispatchOnce(a)
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime)
bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry,DropReason* dropReason, nsecs_t* nextWakeupTime)
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry,const std::vector<InputTarget>& inputTargets) 
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,const sp<Connection>& connection,EventEntry* eventEntry,const InputTarget& inputTarget)
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,const sp<Connection>& connection,EventEntry* eventEntry,const InputTarget& inputTarget)
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,const sp<Connection>& connection)
Copy the code

Let’s look at the last method startDispatchCycleLocked:

//frameworks/native/services/inputflinger/InputDispatcher.cpp

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,const sp<Connection>& connection) {...case EventEntry::Type::MOTION: {
         ....
         // Publish the motion event.
         status = connection->inputPublisher.publishMotionEvent(..) . }}Copy the code

Where is the InputPublisher? Click here to see the inputTransport.cpp source code

//frameworks/native/libs/input/InputTransport.cpp

status_t InputPublisher::publishMotionEvent(...). {... InputMessage msg; msg.header.type = InputMessage::Type::MOTION; . msg.body.motion.downTime = downTime; msg.body.motion.eventTime = eventTime; msg.body.motion.pointerCount = pointerCount; .// Communicate across processes
    return mChannel->sendMessage(&msg);
}
Copy the code

Do not abandon, do not give up, the closer to the truth, πŸ˜‚ more distressed to do framework development programmers πŸ‘¨πŸ’»

//frameworks/native/libs/input/InputTransport.cpp

// Send the message
status_t InputChannel::sendMessage(const InputMessage* msg) {
    const size_t msgLength = msg->size(a); InputMessage cleanMsg; msg->getSanitizedCopy(&cleanMsg);
    ssize_t nWrite;
    do {
        / / write Fd
        nWrite = ::send(mFd.get(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
    } while (nWrite == - 1&& errno == EINTR); .return OK;
}

// Receive the message
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;
}
Copy the code

3.5 Where is an InputChannel Created?

I don’t know how many people can see this, but at the beginning of the article we prompt you: Note: don’t look at the line count, we need to look at the source before and after

We look at this line: ViewRootImpl $WindowInputEventReceiver onInputEvent (), enter ViewRootImpl discovery: setView (…). Method initializes InputChannel internally

//android.view.ViewRootImpl

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,int userId) {... InputChannel inputChannel =null;
     if ((mWindowAttributes.inputFeatures &  WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
        inputChannel = newInputChannel(); }.../ / WindowInputEventReceiver inherited from InputEventReceiver
     // Listen for input events in InputChannel
     mInputEventReceiver = newWindowInputEventReceiver(inputChannel, Looper.myLooper()); . }Copy the code

After the WindowInputEventReceiver is initialized, the constructor executes nativeInit(..).

3.6 How Do I Trigger dispatchInputEvent?

Click to see the InputEventReceiver. CPP source code

//platform/frameworks/base/core/jni/android_view_InputEventReceiver.cpp

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

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

void NativeInputEventReceiver::setFdEvents(int events) {
    if(mFdEvents ! = events) { mFdEvents = events;int fd = mInputConsumer.getChannel() - >getFd(a);if (events) {
            // The addFd method can be found in πŸ‘†πŸ‘† looper. CPP source address πŸ‘†πŸ‘†
            // Call looper.addfd () to complete the assignment
            // callback = "this here" in looper.cpp
            / / so: stars. The inside of the CPP handleEvent = NativeInputEventReceiver: : handleEvent (...).
            // See the Looper::pollInner method above
            mMessageQueue->getLooper() - >addFd(fd, 0, events, this.nullptr);
        } else {
            mMessageQueue->getLooper() - >removeFd(fd); }}}Copy the code

Look at the NativeInputEventReceiver: : handleEvent (..)

//platform/frameworks/base/core/jni/android_view_InputEventReceiver.cpp

int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {...if (events & ALOOPER_EVENT_INPUT) {
        JNIEnv* env = AndroidRuntime::getJNIEnv(a);// Handle the event
        status_t status = consumeEvents(env, false /*consumeBatches*/.- 1.nullptr);
        mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
        return status == OK || status == NO_MEMORY ? 1 : 0; }...return 1;
}

status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
        bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {...ScopedLocalRef<jobject> receiverObj(env, nullptr);
    bool skipCallbacks = false;
    for (;;) {
        uint32_t seq;
        InputEvent* inputEvent;
        status_t status = mInputConsumer.consume(&mInputEventFactory, consumeBatches, frameTime, &seq, &inputEvent); .if(! skipCallbacks) { .... jobject inputEventObj;switch (inputEvent->getType()) {...if (inputEventObj) {
                / / execute Java class InputEventReceiver dispachInputEvent ()
                env->CallVoidMethod(receiverObj.get(),
                        gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
                if (env->ExceptionCheck()) {
                    skipCallbacks = true;
                }
                env->DeleteLocalRef(inputEventObj); }... }... }}Copy the code

Perform πŸ‘‡ πŸ‘‡ the following lines of code, performs to InputEventReceiver. DispachInputEvent ()

//😩 not easy, finally can jump out
CallVoidMethod(receiverObj.get(),
       gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj)
Copy the code

4.enqueueInputEvent

When dispatchInputEvent is triggered, call back onInputEvent

//android.view.ViewRootImpl.WindowInputEventReceiver

final class WindowInputEventReceiver extends InputEventReceiver {
  public void onInputEvent(InputEvent event) {... enqueueInputEvent(...) . }}Copy the code

5.doProcessInputEvents

//android.view.ViewRootImpl

void enqueueInputEvent(InputEvent event,
            InputEventReceiver receiver, int flags, boolean processImmediately) {...// Finally doProcessInputEvents() will be executed
        if (processImmediately) {
            // Execute immediately
            doProcessInputEvents();
        } else {
            DoProcessInputEvents () ΒΆ doProcessInputEvents() ΒΆscheduleProcessInputEvents(); }}Copy the code

6.doProcessInputEvents

//android.view.ViewRootImpl
void doProcessInputEvents(a) {
        // Pass all the pending events in the queue
        while(mPendingInputEventHead ! =null) {
            QueuedInputEvent q = mPendingInputEventHead;
            mPendingInputEventHead = q.mNext;
            if (mPendingInputEventHead == null) {
                mPendingInputEventTail = null;
            }
            q.mNext = null;
            mPendingInputEventCount -= 1; . deliverInputEvent(q); }... }Copy the code

7.deliverInputEvent

//android.view.ViewRootImpl
private void deliverInputEvent(QueuedInputEvent q) {... InputStage stage;if (q.shouldSendToSynthesizer()) {
         stage = mSyntheticInputStage;
      } else{ stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage; }...if(stage ! =null) {
         handleWindowFocusChanged();
         / / use the chain of responsibility pattern, began to pass, will eventually perform to ViewPostImeInputStage. OnProcess
         stage.deliver(q);
      } else{ finishInputEvent(q); }... }Copy the code

8.ViewPostImeInputStage.onProcess

//android.view.ViewRootImpl.ViewPostImeInputStage
final class ViewPostImeInputStage extends InputStage {
    @Override
    protected int onProcess(QueuedInputEvent q) {...final int source = q.mEvent.getSource();
        if((source & InputDevice.SOURCE_CLASS_POINTER) ! =0) {
            // Pass it to the view
            returnprocessPointerEvent(q); }... }}Copy the code

9.ViewPostImeInputStage.processPointerEvent

private int processPointerEvent(QueuedInputEvent q) {
    finalMotionEvent event = (MotionEvent)q.mEvent; .// Execute the view's dispatchPointerEvent and return whether the event is handled by the view
    boolean handled = mView.dispatchPointerEvent(event);
    maybeUpdatePointerIcon(event);
    maybeUpdateTooltip(event);
    mAttachInfo.mHandlingPointerEvent = false; .return handled ? FINISH_HANDLED : FORWARD;
}
Copy the code

10.View.dispatchPointerEvent

//android.view.View

public final boolean dispatchPointerEvent(MotionEvent event) {
    if (event.isTouchEvent()) {// 100% true for touch events
        return dispatchTouchEvent(event);
    } else {
        returndispatchGenericMotionEvent(event); }}Copy the code

11.DecorView.dispatchTouchEvent

We enter ViewRootImpl to glance at inside, just above the analysis of the dispatchPointerEvent, this View if it is a ViewGroup, then it is DecorView

//com.android.internal.policy.DecorView
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
   // This mWindow is PhoneWindow
   final Window.Callback cb = mWindow.getCallback();
   / / call: WindowCallbackWrapper dispatchTouchEvent
   returncb ! =null && !mWindow.isDestroyed() && mFeatureId < 0
                ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
Copy the code

11.1 How Does PhoneWindow Come about?

When you open the Activity source code, you can see that the Activity.attatch method initializes PhoneWindow internally

//android.app.Activity

final void attach(Context context, ActivityThread aThread,...) {
        attachBaseContext(context);
        mFragments.attachHost(null /*parent*/);
        // Initialize PhoneWindow
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(mWindowControllerCallback);
        / / set the Callback
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this); . mWindowManager = mWindow.getWindowManager(); . }Copy the code

How do decorViews relate to Windows?

Open up PhoneWindow and look at the setContentView method inside. It calls installDecor() internally.

//com.android.internal.policy.PhoneWindow
private void installDecor(a) {...// This is connected
    mDecor.setWindow(this); . }Copy the code

12.WindowCallbackWrapper.dispatchTouchEvent

//curtains.internal.WindowCallbackWrapper
override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
    return if(event ! =null) {
      val iterator = listeners.touchEventInterceptors.iterator()
      val dispatch: (MotionEvent) -> DispatchState = object : (MotionEvent) -> DispatchState {
        override fun invoke(interceptedEvent: MotionEvent): DispatchState {
          return if (iterator.hasNext()) {
            val nextInterceptor = iterator.next()
            nextInterceptor.intercept(interceptedEvent, this)}else {
            DispatchState.from(delegate.dispatchTouchEvent(interceptedEvent))
          }
        }
      }
      // If OnTouchEventListener is set, then the iterator is executed
      if (iterator.hasNext()) {
        val firstInterceptor = iterator.next()
        firstInterceptor.intercept(event, dispatch)
      } else {
        // The OnTouchEventListener is not set
        //delegate = Activity
        DispatchState.from(delegate.dispatchTouchEvent(event))
      } is Consumed
    } else {
      //delegate = Activity
      delegate.dispatchTouchEvent(event)
    }
  }
Copy the code

Eventually executed to the Activity. The dispatchTouchEvent, end of analysis, finally to the Activity.