There is a slight difference between the processing of Android key messages and the previous versions. The basic principle is the same. Here we mainly analyze the two phases:
1. preparations in the early stage, that is, start the corresponding thread at startup and wait for the arrival of the button event
2. When a key message exists, the message is distributed and processed.
First look at a class diagram:
The main classes involved are PhoneWindowManager, WindowManagerService, inputManagerService, and InputManager.
First, let's take a look at the first question. preparations in the early stage:
1. Start inputManagerService at startup, Which is started by ServerThread;
inputManager = new InputManagerService(context, wmHandler); Slog.i(TAG, "Window Manager"); wm = WindowManagerService.main(context, power, display, inputManager, uiHandler, wmHandler, factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL, !firstBoot, onlyCore); ServiceManager.addService(Context.WINDOW_SERVICE, wm); ServiceManager.addService(Context.INPUT_SERVICE, inputManager); ActivityManagerService.self().setWindowManager(wm); inputManager.setWindowManagerCallbacks(wm.getInputMonitor()); inputManager.start();
See the constructor of inputManagerService:
public InputManagerService(Context context, Handler handler) { this.mContext = context; this.mHandler = new InputManagerHandler(handler.getLooper()); mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack=" + mUseDevInputEventForAudioJack); mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue()); }First, a new InputManagerHandler is created, and then a native method is called to pass in the message queue of the service and handler as parameters,
NativeInit corresponds to nativeInit in com_android_server_input_InputManagerService.cpp, Which is associated through the JNI mechanism.
For more information, see nativeInit:
static jint nativeInit(JNIEnv* env, jclass clazz, jobject serviceObj, jobject contextObj, jobject messageQueueObj) { sp
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
(im);}
Here we mainly create an NativeInputManager object, which can be seen as a constructor:
NativeInputManager::NativeInputManager(jobject contextObj, jobject serviceObj, const sp
& looper) : mLooper(looper) { 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; } sp
eventHub = new EventHub(); mInputManager = new InputManager(eventHub, this, this);}
Here we mainly create an InputManager, which looks at the constructor:
InputManager::InputManager( const sp
& eventHub, const sp
& readerPolicy, const sp
& dispatcherPolicy) { mDispatcher = new InputDispatcher(dispatcherPolicy); mReader = new InputReader(eventHub, readerPolicy, mDispatcher); initialize();}void InputManager::initialize() { mReaderThread = new InputReaderThread(mReader); mDispatcherThread = new InputDispatcherThread(mDispatcher);}
Here we can see the creation object InputDispatcher, InputReader, and the two thread objects running at the same time: mReaderThread, mDispatcherThread
At this point, the first step of initialization is completed, but the created thread has not been started, and it is still working. Check whether the process is enabled.
Now the preparations have been completed, and the two threads have started to work, waiting for the arrival of the button event
2. When there is a button event, the processing process of the two threads is as follows:
Two main lines:
A. InputReader obtains the key event from EventHub and notifies InputDispatcher. InputDispatcher is called after receiving the notification.
InterceptKeyBeforeQueueing method to perform related operations, and add the key events to the queue, waiting for subsequent processing.
Source code for adding a queue:
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { bool needWake = mInboundQueue.isEmpty(); mInboundQueue.enqueueAtTail(entry); traceInboundQueueLengthLocked();
B. InputDispatcher obtains the key message from the message queue and calls the interceptKeyBeforeDispatching method to determine whether to intercept the message,
Judge based on the result:
nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle, &event, entry->policyFlags); mLock.lock(); if (delay < 0) { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP; } else if (!delay) { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; } else { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER; entry->interceptKeyWakeupTime = now() + delay; }
The interceptKeyBeforeQueueing and interceptKeyBeforeDispatching methods called in InputDispatcher correspond
Method of the same name in PhoneWindowManager.