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.