標籤:android4.3 按鍵訊息處理
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中的同名方法。