Android4.3按键消息处理与之前的版本有稍微的区别,基本原理还是一样的,这里主要从两个阶段来分析:
1.前期的准备工作,即开机时启动相应的的线程,静候按键事件的来临
2.当有按键消息时,进行消息的分发等处理
先看一张类图:
从类图中看出,主要涉及到的类有PhoneWindowManager、WindowManagerService、inputManagerService、 InputManager
先看第一个问题,前期的准备工作:
1.开机时先启动inputManagerService,由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();
看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());
}
先new一个InputManagerHandler,然后调用一个native方法,把service和handler的消息队列作为参数传入,
nativeInit对应是com_android_server_input_InputManagerService.cpp中的nativeInit,,这个通过JNI的机制进行关联。
这里不多说,看nativeInit:
static jint 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<jint>(im);
}
这里主要是创建一个NativeInputManager对象,看起构造函数:
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& 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> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}
这里主要是创建一个InputManager,看起构造函数:
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
这里看到了创建对象InputDispatcher 、InputReader以及两个时刻在跑的线程对象:mReaderThread、mDispatcherThread
至此初始化的第一步是完成了,但创建的线程还没start,还开始正真的干活,看开启过程
至此前期的准备工作都做完,两线程开始干活,静候按键事件来临
2.当有按键事件时两个线程处理流程见下图:
两条主线:
a. InputReader从EventHub中获取到按键事件,并通知InputDispatcher;InputDispatcher接到通知后调用
interceptKeyBeforeQueueing方法进行相关的操作,并把按键事件加入到队列中,等待后面处理。
加入队列源码:
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(entry);
traceInboundQueueLengthLocked();
b. InputDispatcher从消息队列中获取按键消息,调用interceptKeyBeforeDispatching方法判断是否对此消息进行拦截,
根据其结果进行判断:
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;
}
其中在InputDispatcher中调用的interceptKeyBeforeQueueing和interceptKeyBeforeDispatching方法都是对应着
PhoneWindowManager中的同名方法。