該篇文章接總章,來詳細談論說明InputManagerService 體系,從初始化到事件獲取跟分發。咱們在進行前,先明確哪幾個問題需要知道,然後看看在這篇文章中是否解決了這些問題。對於InputManagerService,大家第一個想知道是他起什麼作用,這個在總章裏面有詳細說明,簡而言之就是獲得事件跟分發處理事件。那他如何或者跟其他模塊配合獲取事件?並且把這個事件進行分發?如何準確定位對應的處理事件的模塊?咱們下面開始討論這些問題,在這個文章出來的時候,android 已經到N了 ,也就是7.0。但是由於我的筆記(初稿) 在M的時候已經完成了,也就是去年。所以這篇文章還是基於M (6.0)來寫。
InputManagerService的初始化:
跟其他模塊一樣,作爲系統的核心服務初始化在SystemServer。基本系統的核心服務都是在這裏初始化,這個可以研究下系統的啓動流程,在啓動的最後就是需要啓動所有的核心服務。
代碼路徑: frameworks/base/services/java/com/android/server/SystemServer.java
在run 方法裏面,M 是在startOtherService()裏面初始化InputManagerService
上面主要是新建IMS(InputManagerService 下面都用這個替換) 對象, 然後把WindowManagerService的InputMonitor作爲參數傳給IMS,重點關注下InputMonitor,這個跟事件的分發有關。然後在這裏調用start方法啓動IMS,這裏的start 實際是調用 native 的start 方法。
看下InputManagerServices的start方法:
代碼路徑:frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
上面主要調用了com_android_service_input_InputManagerService.cpp 裏面的nativeStart方法,Java層的start方法主要做了兩個工作:一個工作就是調用nativeStart方法。另外一個就是point 跟 toucher 相關參數設置跟監聽,對應這Input事件的主要兩類:Key 跟 toucher。在nativeStart裏面的mPtr對應啥呢?首先Java層 跟 native層通信調用,主要通過JNI。這裏主要是mPtr指針強制類型轉換爲NativeInputManager對象,看下源碼:
Java層代碼:
代碼路徑:frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
- // Pointer to native input manager service object.
- private final long mPtr;
- public InputManagerService(Context context) {
- this.mContext = context;
- this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
- <span style="white-space:pre;"> </span>mUseDevInputEventForAudioJack =
- context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
- Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
- + mUseDevInputEventForAudioJack);
- <span style="white-space:pre;"> </span>//這裏對mPtr 進行初始化,調用的還是native的方法,把這個service跟 Systemcontext 傳給native對應的方法
- mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
- <span style="white-space:pre;"> </span> LocalServices.addService(InputManagerInternal.class, new LocalService());
- }
// Pointer to native input manager service object.
private final long mPtr;
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mUseDevInputEventForAudioJack =
context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
+ mUseDevInputEventForAudioJack);
//這裏對mPtr 進行初始化,調用的還是native的方法,把這個service跟 Systemcontext 傳給native對應的方法
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
Native層代碼:
代碼路徑:/frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
- static jlong 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;
- } //這裏把JAVA層的 Systemcontext 以及IMS自己 作爲參數傳過來了
- an style="white-space:pre;"> </span>NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
- messageQueue->getLooper());
- im->incStrong(0);
- return reinterpret_cast<jlong>(im);
static jlong 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;
} //這裏把JAVA層的 Systemcontext 以及IMS自己 作爲參數傳過來了
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(im);
}
這個爲什麼要把IMS 傳給NativeInputManager呢?看下NativeInputManager的構造函數
代碼路徑:frameworks/base/services/core/jni/com_android_server_input_inputmanagerservice.cpp
- NativeInputManager::NativeInputManager(jobject contextObj,
- jobject serviceObj, const sp<Looper>& looper) :
- mLooper(looper), mInteractive(true) {
- 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;
- }
- <span style="white-space:pre;"> </span>mInteractive = true;
- <span style="white-space:pre;"> </span>//這個是從底層讀取input 信息的提供者
- sp<EventHub> eventHub = new EventHub();
- mInputManager = new InputManager(eventHub, this, this);
- }
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
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;
}
mInteractive = true;
//這個是從底層讀取input 信息的提供者
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}
這裏有一個重要的對象就是EventHub,如總章所說這個對象是事件獲取的重要的對象。在這裏也對Native層的InputManager進行了初始化。前面解決了mPtr 是啥,nativeStart又幹了啥?
InputManagerService的讀取跟分發啓動:
- static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
- NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
- //這裏就是上面獲得InputManager對象調用start()方法返回的結果
- status_t result = im->getInputManager()->start();
- if (result) {
- jniThrowRuntimeException(env, "Input manager could not be started.");
- }
- }
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
//這裏就是上面獲得InputManager對象調用start()方法返回的結果
status_t result = im->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
查看下InputManager的start方法到底幹了什麼?frameworks/native/services/inputFlinger/InputManager.cpp
代碼路徑:frameworks/native/services/inputFlinger/InputManager.cpp
- status_t InputManager::start() {
- status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
- if (result) {
- ALOGE("Could not start InputDispatcher thread due to error %d.", result);
- return result;
- }
- result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
- if (result) {
- ALOGE("Could not start InputReader thread due to error %d.", result);
- mDispatcherThread->requestExit();
- return result;
- }
- return OK;
- }
status_t InputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE("Could not start InputDispatcher thread due to error %d.", result);
return result;
}
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE("Could not start InputReader thread due to error %d.", result);
mDispatcherThread->requestExit();
return result;
}
return OK;
}
嘿嘿,這裏就真正的Input 事件 消息讀取分發的工作啓動了,從上面的代碼就可以知道這裏開啓了兩個線程,這兩個線程初始化在InputManager的initialize方法裏面。
- void InputManager::initialize() {
- mReaderThread = new InputReaderThread(mReader);
- mDispatcherThread = new InputDispatcherThread(mDispatcher);
- }
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
這兩個線程主要一個是讀取事件,一個是分發事件。讀取事件從哪裏讀呢?從EventHub裏面讀,源碼說了~
代碼路徑:frameworks/native/services/inputflinger/InputReader.h
- /* Reads raw events from the event hub and processes them, endlessly. */ 這裏說明了
- class InputReaderThread : public Thread {
- public:
- InputReaderThread(const sp<InputReaderInterface>& reader);
- virtual ~InputReaderThread();
- private:
- sp<InputReaderInterface> mReader;
- virtual bool threadLoop();
- };
/* Reads raw events from the event hub and processes them, endlessly. */ 這裏說明了
class InputReaderThread : public Thread {
public:
InputReaderThread(const sp<InputReaderInterface>& reader);
virtual ~InputReaderThread();
private:
sp<InputReaderInterface> mReader;
virtual bool threadLoop();
};
那這個線程如何讀取數據呢?代碼路徑:frameworks/native/services/inputflinger/InputReader.cpp
- // --- InputReaderThread ---
- InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
- Thread(/*canCallJava*/ true), mReader(reader) {
- }
- InputReaderThread::~InputReaderThread() {
- }
- bool InputReaderThread::threadLoop() {
// --- InputReaderThread ---
InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
Thread(/*canCallJava*/ true), mReader(reader) {
}
InputReaderThread::~InputReaderThread() {
}
bool InputReaderThread::threadLoop() {
- //調用loopOnce 方法
- mReader->loopOnce();
- return true;
//調用loopOnce 方法
mReader->loopOnce();
return true;
}
InputReader 實際不直接訪問設備點,而是通過EventHub 來完成這一工作,EventHub 通過讀取/dev/input下的數據。loopOnce如何讀取事件了,前面已經反覆強調讀取數據的工作主要是EventHub,那loopOnce裏面EventHub就要一定要出現了。
- void InputReader::loopOnce() {
- int32_t oldGeneration;
- int32_t timeoutMillis;
- bool inputDevicesChanged = false;
- Vector<InputDeviceInfo> inputDevices;
- //這裏主要是 環境有關的,比如時間,比如設備的狀態等等
- { // acquire lock
- AutoMutex _l(mLock);
- oldGeneration = mGeneration;
- timeoutMillis = -1;
- uint32_t changes = mConfigurationChangesToRefresh;
- if (changes) {
- mConfigurationChangesToRefresh = 0;
- timeoutMillis = 0;
- //主要刷新環境
- refreshConfigurationLocked(changes);
- } else if (mNextTimeout != LLONG_MAX) {
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
- }
- } // release lock
- //獲得input 數據
- size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
- //這裏主要處理消息設備
- { // acquire lock
- AutoMutex _l(mLock);
- mReaderIsAliveCondition.broadcast();
- if (count) {
- //這裏主要是 添加事情的設備
- processEventsLocked(mEventBuffer, count);
- }
- if (mNextTimeout != LLONG_MAX) {
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- if (now >= mNextTimeout) {
- #if DEBUG_RAW_EVENTS
- ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
- #endif
- mNextTimeout = LLONG_MAX;
- timeoutExpiredLocked(now);
- }
- }
- if (oldGeneration != mGeneration) {
- inputDevicesChanged = true;
- getInputDevicesLocked(inputDevices);
- }
- } // release lock
- // Send out a message that the describes the changed input devices.
- if (inputDevicesChanged) {
- mPolicy->notifyInputDevicesChanged(inputDevices);
- }
- // Flush queued events out to the listener.
- // This must happen outside of the lock because the listener could potentially call
- // back into the InputReader's methods, such as getScanCodeState, or become blocked
- // on another thread similarly waiting to acquire the InputReader lock thereby
- // resulting in a deadlock. This situation is actually quite plausible because the
- // listener is actually the input dispatcher, which calls into the window manager,
- // which occasionally calls into the input reader.
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
Vector<InputDeviceInfo> inputDevices;
//這裏主要是 環境有關的,比如時間,比如設備的狀態等等
{ // acquire lock
AutoMutex _l(mLock);
oldGeneration = mGeneration;
timeoutMillis = -1;
uint32_t changes = mConfigurationChangesToRefresh;
if (changes) {
mConfigurationChangesToRefresh = 0;
timeoutMillis = 0;
//主要刷新環境
refreshConfigurationLocked(changes);
} else if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
}
} // release lock
//獲得input 數據
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
//這裏主要處理消息設備
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
//這裏主要是 添加事情的設備
processEventsLocked(mEventBuffer, count);
}
if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTS
ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
mNextTimeout = LLONG_MAX;
timeoutExpiredLocked(now);
}
}
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
getInputDevicesLocked(inputDevices);
}
} // release lock
// Send out a message that the describes the changed input devices.
if (inputDevicesChanged) {
mPolicy->notifyInputDevicesChanged(inputDevices);
}
// Flush queued events out to the listener.
// This must happen outside of the lock because the listener could potentially call
// back into the InputReader's methods, such as getScanCodeState, or become blocked
// on another thread similarly waiting to acquire the InputReader lock thereby
// resulting in a deadlock. This situation is actually quite plausible because the
// listener is actually the input dispatcher, which calls into the window manager,
// which occasionally calls into the input reader.
- //獲得數據後,刷新數據,mQueueListener,根據構造函數以及註釋可以知道是InputDispatcher的一個封裝
- //查看InputReader的構造函數, InputDispatcher 轉成了這個
- //這裏主要是刷新消息棧,進行事件的分發了
- //QueuedInputListener 定義在 InputListener.cpp裏面
- mQueuedListener->flush();
- }
//獲得數據後,刷新數據,mQueueListener,根據構造函數以及註釋可以知道是InputDispatcher的一個封裝
//查看InputReader的構造函數, InputDispatcher 轉成了這個
//這裏主要是刷新消息棧,進行事件的分發了
//QueuedInputListener 定義在 InputListener.cpp裏面
mQueuedListener->flush();
}
看下loopOnce方法EventHub果然出現了,在這個幾十行代碼裏面讀取事件EventHub,flush 分發事件都有了,基本上就走完了Input事件的讀取跟分發。現在準備進入事件分發的解讀,事件的讀取由於涉及到kernel層代碼的解讀,作爲子章進行分析說明,本篇不做過多解讀。這裏從mQueuedListener->flush(); 開始說明。
代碼路徑:frameworks/native/services/inputflinger/InputListener.cpp
- void QueuedInputListener::flush() {
- size_t count = mArgsQueue.size();
- for (size_t i = 0; i < count; i++) {
- NotifyArgs* args = mArgsQueue[i];
- args->notify(mInnerListener);
- delete args;
- }
- mArgsQueue.clear();
- }
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
args->notify(mInnerListener);
delete args;
}
mArgsQueue.clear();
}
代碼路徑:frameworks/native/services/inputflinger/inputListener.h
- /*
- * An implementation of the listener interface that queues up and defers dispatch
- * of decoded events until flushed.
- */
- class QueuedInputListener : public InputListenerInterface {
- protected:
- virtual ~QueuedInputListener();
- public:
- QueuedInputListener(const sp<InputListenerInterface>& innerListener);
- virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
- virtual void notifyKey(const NotifyKeyArgs* args);
- virtual void notifyMotion(const NotifyMotionArgs* args);
- virtual void notifySwitch(const NotifySwitchArgs* args);
- virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
- void flush();
- private:
- sp<InputListenerInterface> mInnerListener;
- Vector<NotifyArgs*> mArgsQueue;
- };
- /*
- * The interface used by the InputReader to notify the InputListener about input events.
- */
- class InputListenerInterface : public virtual RefBase {
- protected:
- InputListenerInterface() { }
- virtual ~InputListenerInterface() { }
- public:
- virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) = 0;
- virtual void notifyKey(const NotifyKeyArgs* args) = 0;
- virtual void notifyMotion(const NotifyMotionArgs* args) = 0;
- virtual void notifySwitch(const NotifySwitchArgs* args) = 0;
- virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0;
- };
/*
* An implementation of the listener interface that queues up and defers dispatch
* of decoded events until flushed.
*/
class QueuedInputListener : public InputListenerInterface {
protected:
virtual ~QueuedInputListener();
public:
QueuedInputListener(const sp<InputListenerInterface>& innerListener);
virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
virtual void notifyKey(const NotifyKeyArgs* args);
virtual void notifyMotion(const NotifyMotionArgs* args);
virtual void notifySwitch(const NotifySwitchArgs* args);
virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
void flush();
private:
sp<InputListenerInterface> mInnerListener;
Vector<NotifyArgs*> mArgsQueue;
};
/*
* The interface used by the InputReader to notify the InputListener about input events.
*/
class InputListenerInterface : public virtual RefBase {
protected:
InputListenerInterface() { }
virtual ~InputListenerInterface() { }
public:
virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) = 0;
virtual void notifyKey(const NotifyKeyArgs* args) = 0;
virtual void notifyMotion(const NotifyMotionArgs* args) = 0;
virtual void notifySwitch(const NotifySwitchArgs* args) = 0;
virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0;
};
由上可知繼承inputListenerInterface的子類,會根據情況處理相應的事件。在這裏有一個問題InputDispatcher 如何被強轉的?其實是InputReader在初始化的時候InputDispatcher作爲參數傳了過去,然後強轉了。上代碼說明下:
- 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();
- }
- // --- InputReader ---
- InputReader::InputReader(const sp<EventHubInterface>& eventHub,
- const sp<InputReaderPolicyInterface>& policy,
- //結合上面的代碼 以及 這句代碼可以知道inputdispatcher被強轉了,爲什麼可以強轉?
- //因爲inputListenerInterface這個接口繼承Refbase,Refbase是android裏面的所有對象的父類
- //詳情參考binder裏面的介紹
- const sp<InputListenerInterface>& listener) :
- mContext(this), mEventHub(eventHub), mPolicy(policy),
- mGlobalMetaState(0), mGeneration(1),
- mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
- mConfigurationChangesToRefresh(0) {
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();
}
// --- InputReader ---
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& policy,
//結合上面的代碼 以及 這句代碼可以知道inputdispatcher被強轉了,爲什麼可以強轉?
//因爲inputListenerInterface這個接口繼承Refbase,Refbase是android裏面的所有對象的父類
//詳情參考binder裏面的介紹
const sp<InputListenerInterface>& listener) :
mContext(this), mEventHub(eventHub), mPolicy(policy),
mGlobalMetaState(0), mGeneration(1),
mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
把InputDispatcher強轉說清楚,咱們就開始詳細瞭解下事情的分發過程,咱們從notifykey這方法說起
- 代碼路徑:frameworks/native/services/inputflinger/InputDispatcher.cpp
- void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
- Code 省略,前面主要檢查這個事件有沒有問題,把事件裏面的信息屬性都抽出來,重點看下面的代碼
- bool needWake;
- { // acquire lock
- mLock.lock();
- if (shouldSendKeyToInputFilterLocked(args)) {
- mLock.unlock();
- policyFlags |= POLICY_FLAG_FILTERED;
- if (!mPolicy->filterInputEvent(&event, policyFlags)) {
- return; // event was consumed by the filter
- }
- mLock.lock();
- }
- int32_t repeatCount = 0;
- KeyEntry* newEntry = new KeyEntry(args->eventTime,
- args->deviceId, args->source, policyFlags,
- args->action, flags, keyCode, args->scanCode,
- metaState, repeatCount, args->downTime);
- needWake = enqueueInboundEventLocked(newEntry);
- mLock.unlock();
- } // release lock
代碼路徑:frameworks/native/services/inputflinger/InputDispatcher.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
Code 省略,前面主要檢查這個事件有沒有問題,把事件裏面的信息屬性都抽出來,重點看下面的代碼
bool needWake;
{ // acquire lock
mLock.lock();
if (shouldSendKeyToInputFilterLocked(args)) {
mLock.unlock();
policyFlags |= POLICY_FLAG_FILTERED;
if (!mPolicy->filterInputEvent(&event, policyFlags)) {
return; // event was consumed by the filter
}
mLock.lock();
}
int32_t repeatCount = 0;
KeyEntry* newEntry = new KeyEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
args->action, flags, keyCode, args->scanCode,
metaState, repeatCount, args->downTime);
needWake = enqueueInboundEventLocked(newEntry);
mLock.unlock();
} // release lock
- if (needWake) {
if (needWake) {
- //事件分發主要在這裏,但是要分發要看needWake的值,<span style="color:rgb(72,72,76);font-size:13px;line-height:1.38462;white-space:pre-wrap;background-color:rgb(247,247,249);">enqueueInboundEventLocked 返回true,事件就開始分發了</span>
- mLooper->wake();
- }
- }
//事件分發主要在這裏,但是要分發要看needWake的值,enqueueInboundEventLocked 返回true,事件就開始分發了
mLooper->wake();
}
}
這裏looper 什麼怎麼進行分發呢?還是看源碼
- // --- InputDispatcherThread --- 這個主要在InputDispatcher.cpp裏面
- InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
- Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
- }
- InputDispatcherThread::~InputDispatcherThread() {
- }
- . bool InputDispatcherThread::threadLoop() {
- //開始調用dispatchOnce方法
- mDispatcher->dispatchOnce();
- return true;
- . }
- . } // namespace android
// --- InputDispatcherThread --- 這個主要在InputDispatcher.cpp裏面
InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}
InputDispatcherThread::~InputDispatcherThread() {
}
. bool InputDispatcherThread::threadLoop() {
//開始調用dispatchOnce方法
mDispatcher->dispatchOnce();
return true;
. }
. } // namespace android
- void InputDispatcher::dispatchOnce() {
- nsecs_t nextWakeupTime = LONG_LONG_MAX;
- { // acquire lock
- AutoMutex _l(mLock);
- mDispatcherIsAliveCondition.broadcast();
- // Run a dispatch loop if there are no pending commands.
- // The dispatch loop might enqueue commands to run afterwards.
- if (!haveCommandsLocked()) {
- //調用下面的方法
- dispatchOnceInnerLocked(&nextWakeupTime);
- }
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
AutoMutex _l(mLock);
mDispatcherIsAliveCondition.broadcast();
// Run a dispatch loop if there are no pending commands.
// The dispatch loop might enqueue commands to run afterwards.
if (!haveCommandsLocked()) {
//調用下面的方法
dispatchOnceInnerLocked(&nextWakeupTime);
}
到這裏就開始說明分發事件了,TouchEvent的消息分發結構來分析Input 在Framework的使用
- Code In InputDispatcher.cpp 裏面
- void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
- Code 省略
- case EventEntry::TYPE_MOTION: {
- MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
- if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
- dropReason = DROP_REASON_APP_SWITCH;
- }
- if (dropReason == DROP_REASON_NOT_DROPPED
- && isStaleEventLocked(currentTime, typedEntry)) {
- dropReason = DROP_REASON_STALE;
- }
- if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
- dropReason = DROP_REASON_BLOCKED;
- }
- //跳轉到下面個函數,去處理motion相關操作
- done = dispatchMotionLocked(currentTime, typedEntry,
- &dropReason, nextWakeupTime);
- break;
- }
Code In InputDispatcher.cpp 裏面
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
Code 省略
case EventEntry::TYPE_MOTION: {
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
dropReason = DROP_REASON_APP_SWITCH;
}
if (dropReason == DROP_REASON_NOT_DROPPED
&& isStaleEventLocked(currentTime, typedEntry)) {
dropReason = DROP_REASON_STALE;
}
if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DROP_REASON_BLOCKED;
}
//跳轉到下面個函數,去處理motion相關操作
done = dispatchMotionLocked(currentTime, typedEntry,
&dropReason, nextWakeupTime);
break;
}
- bool InputDispatcher::dispatchMotionLocked(
- nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
- //進行motion事件,進行處理
- // Preprocessing.
- if (! entry->dispatchInProgress) {
- entry->dispatchInProgress = true;
- //這個函數把motion的相關值打出來
- logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
- }
- // Clean up if dropping the event.
- 把舊有的數據清楚掉
- if (*dropReason != DROP_REASON_NOT_DROPPED) {
- //這個方法就是設置插入結果,根據不同InjectionRest彈出不同LOG
- setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
- ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
- return true;
- }
- //判斷時間的類型
- bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
- //獲得事件的接受者或者實際響應者
- // Identify targets.
- Vector<InputTarget> inputTargets;
- bool conflictingPointerActions = false;
- int32_t injectionResult;
- if (isPointerEvent) {
- // Pointer event. (eg. touchscreen)
- // 獲得對應的window 是 touch 事件,這裏是重點
- injectionResult = findTouchedWindowTargetsLocked(currentTime,
- entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
- } else {
- // Non touch event. (eg. trackball)
- // 是軌跡事件
- injectionResult = findFocusedWindowTargetsLocked(currentTime,
- entry, inputTargets, nextWakeupTime);
- }
- // 是否延遲處理
- if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
- return false;
- }
- // 設置延遲處理
- setInjectionResultLocked(entry, injectionResult);
- if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
- if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) {
- CancelationOptions::Mode mode(isPointerEvent ?
- CancelationOptions::CANCEL_POINTER_EVENTS :
- CancelationOptions::CANCEL_NON_POINTER_EVENTS);
- CancelationOptions options(mode, "input event injection failed");
- synthesizeCancelationEventsForMonitorsLocked(options);
- }
- return true;
- }
- //支持 發送二次輸入顯示器的顯示事件
- // TODO: support sending secondary display events to input monitors
- if (isMainDisplay(entry->displayId)) {
- addMonitoringTargetsLocked(inputTargets);
- }
- // Dispatch the motion.
- if (conflictingPointerActions) {
- CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
- "conflicting pointer actions");
- synthesizeCancelationEventsForAllConnectionsLocked(options);
- }
- dispatchEventLocked(currentTime, entry, inputTargets);
- return true;
- }
bool InputDispatcher::dispatchMotionLocked(
nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
//進行motion事件,進行處理
// Preprocessing.
if (! entry->dispatchInProgress) {
entry->dispatchInProgress = true;
//這個函數把motion的相關值打出來
logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
}
// Clean up if dropping the event.
把舊有的數據清楚掉
if (*dropReason != DROP_REASON_NOT_DROPPED) {
//這個方法就是設置插入結果,根據不同InjectionRest彈出不同LOG
setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
return true;
}
//判斷時間的類型
bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
//獲得事件的接受者或者實際響應者
// Identify targets.
Vector<InputTarget> inputTargets;
bool conflictingPointerActions = false;
int32_t injectionResult;
if (isPointerEvent) {
// Pointer event. (eg. touchscreen)
// 獲得對應的window 是 touch 事件,這裏是重點
injectionResult = findTouchedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
} else {
// Non touch event. (eg. trackball)
// 是軌跡事件
injectionResult = findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime);
}
// 是否延遲處理
if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
return false;
}
// 設置延遲處理
setInjectionResultLocked(entry, injectionResult);
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) {
CancelationOptions::Mode mode(isPointerEvent ?
CancelationOptions::CANCEL_POINTER_EVENTS :
CancelationOptions::CANCEL_NON_POINTER_EVENTS);
CancelationOptions options(mode, "input event injection failed");
synthesizeCancelationEventsForMonitorsLocked(options);
}
return true;
}
//支持 發送二次輸入顯示器的顯示事件
// TODO: support sending secondary display events to input monitors
if (isMainDisplay(entry->displayId)) {
addMonitoringTargetsLocked(inputTargets);
}
// Dispatch the motion.
if (conflictingPointerActions) {
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
"conflicting pointer actions");
synthesizeCancelationEventsForAllConnectionsLocked(options);
}
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
這裏大概就是touch事件的處理流程, findTouchedWindowTargetsLocked 是找到對應的事件響應者的重要方法,下面開始詳細說明- Code In InputDispatcher
- int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
- const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
- int32_t injectionResult;
- String8 reason;
Code In InputDispatcher
int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
int32_t injectionResult;
String8 reason;
- ALOGI("Dropping event because there is no focused window or focused application.");
- injectionResult = INPUT_EVENT_INJECTION_FAILED;
- goto Failed;
- }
- // Check permissions. 檢查權限
- if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {
- injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
- goto Failed;
- }
// Check permissions. 檢查權限
if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {
injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
goto Failed;
}
- // Check whether the window is ready for more input.
// Check whether the window is ready for more input.
- // 檢查窗口的狀態,比如是否pause 等等
- reason = checkWindowReadyForMoreInputLocked(currentTime,
- mFocusedWindowHandle, entry, "focused");
- if (!reason.isEmpty()) {
- injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.string());
- goto Unresponsive;
- }
// 檢查窗口的狀態,比如是否pause 等等
reason = checkWindowReadyForMoreInputLocked(currentTime,
mFocusedWindowHandle, entry, "focused");
if (!reason.isEmpty()) {
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.string());
goto Unresponsive;
}
- // Success! Output targets.
// Success! Output targets.
- // 這裏主要是Input 跟 目標窗口相關信息複製跟綁定,重點關注裏面的InputChannel,這個跟窗口年消息通信有關
- injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
- addWindowTargetLocked(mFocusedWindowHandle,
- InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),
- inputTargets);
// 這裏主要是Input 跟 目標窗口相關信息複製跟綁定,重點關注裏面的InputChannel,這個跟窗口年消息通信有關
injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
addWindowTargetLocked(mFocusedWindowHandle,
InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),
inputTargets);
- // Done.
- Failed:
- Unresponsive:
- nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
- updateDispatchStatisticsLocked(currentTime, entry,
- injectionResult, timeSpentWaitingForApplication);
- #if DEBUG_FOCUS
// Done.
Failed:
Unresponsive:
nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
updateDispatchStatisticsLocked(currentTime, entry,
injectionResult, timeSpentWaitingForApplication);
#if DEBUG_FOCUS
- ALOGD("findFocusedWindow finished: injectionResult=%d, "
- "timeSpentWaitingForApplication=%0.1fms",
- injectionResult, timeSpentWaitingForApplication / 1000000.0);
- #endif
- return injectionResult;
ALOGD("findFocusedWindow finished: injectionResult=%d, "
"timeSpentWaitingForApplication=%0.1fms",
injectionResult, timeSpentWaitingForApplication / 1000000.0);
#endif
return injectionResult;
上面重點要關注的就是mFocusedWindowHandle 跟 mFocusedApplicationHandle 。他們是誰複製的呢?如何複製的呢?起什麼作用了。明白了他們兩個就可以明白了Input
跟對應的window的通信。下面就主要從這兩個對象進行研究展開。findFocusedWindowTargetsLocked 的方法裏面其他就是檢查窗口狀態等相關信息。mFocusedWindowHandler 誰複製的呢?經過查詢在InputDispatcher 裏面就如下的方法
- void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
- Code 省略
- // newFocusedWindowHandler
- sp<InputWindowHandle> newFocusedWindowHandle;
- //mFocusedWindowHandler 是被賦值爲newFocusedWindowHandle
- mFocusedWindowHandle = newFocusedWindowHandle;
- Code 省略
void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
Code 省略
// newFocusedWindowHandler
sp<InputWindowHandle> newFocusedWindowHandle;
//mFocusedWindowHandler 是被賦值爲newFocusedWindowHandle
mFocusedWindowHandle = newFocusedWindowHandle;
Code 省略
這裏就是InputDispatcher 設置對應的消息輸出窗口的地方,但是到底這個方法到底誰在用?什麼地方用?由於咱們討論的是IMS 整個體系,InputDispatcher跟InputReader 是IMS 的左膀右臂。InputReader是負責的讀取的數據然後應該是給IMS 去處理,InputDispatcher 是分發的,應該也是由IMS 去具體處理。咱們去IMS看看是否有設置窗口的調用
看下InputManagerService.java
代碼路徑:frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public void setInputWindows(InputWindowHandle[] windowHandles) {
- //這裏調用com_android_server_input_InputManagerService.cpp
- nativeSetInputWindows(mPtr, windowHandles);
- }
//這裏調用com_android_server_input_InputManagerService.cpp
nativeSetInputWindows(mPtr, windowHandles);
}
代碼路徑:frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
- void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
- Vector<sp<InputWindowHandle> > windowHandles;
- if (windowHandleObjArray) {
- jsize length = env->GetArrayLength(windowHandleObjArray);
- for (jsize i = 0; i < length; i++) {
- jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i);
- if (! windowHandleObj) {
- break; // found null element indicating end of used portion of the array
- }
- sp<InputWindowHandle> windowHandle =
- android_server_InputWindowHandle_getHandle(env, windowHandleObj);
- if (windowHandle != NULL) {
- windowHandles.push(windowHandle);
- }
- env->DeleteLocalRef(windowHandleObj);
- }
- }
- //這裏會調用InputManager.cpp裏面的方法
- mInputManager->getDispatcher()->setInputWindows(windowHandles);
- CODE 省略
void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
Vector<sp<InputWindowHandle> > windowHandles;
if (windowHandleObjArray) {
jsize length = env->GetArrayLength(windowHandleObjArray);
for (jsize i = 0; i < length; i++) {
jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i);
if (! windowHandleObj) {
break; // found null element indicating end of used portion of the array
}
sp<InputWindowHandle> windowHandle =
android_server_InputWindowHandle_getHandle(env, windowHandleObj);
if (windowHandle != NULL) {
windowHandles.push(windowHandle);
}
env->DeleteLocalRef(windowHandleObj);
}
}
//這裏會調用InputManager.cpp裏面的方法
mInputManager->getDispatcher()->setInputWindows(windowHandles);
CODE 省略
代碼路徑:frameworks/native/services/inputflinger/inputManager.cpp
- sp<InputDispatcherInterface> InputManager::getDispatcher() {
- //獲得InputDispatcheer.cpp 對象
- return mDispatcher;
sp<InputDispatcherInterface> InputManager::getDispatcher() {
//獲得InputDispatcheer.cpp 對象
return mDispatcher;
從上面可以知道IMS 到 InputDispather 如何層層調用setInputWindow的流程,但是這個方法還是在IMS 體系裏面調用,外面別人如何調用呢?既然從IMS 體系找不到,就從外面找,window 的管理者WMS。
代碼路徑:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
看下WMS 的 addWindow方法
- Code In WindowManagerService.java
- public int addWindow(Session session, IWindow client, int seq,
- WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
- Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
- InputChannel outInputChannel) {
- Code 省略
- if (focusChanged) {
- //調用InputMonitor的方法設置接收窗口
- mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);
- }
- mInputMonitor.updateInputWindowsLw(false /*force*/);
- Code 省略
Code In WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
InputChannel outInputChannel) {
Code 省略
if (focusChanged) {
//調用InputMonitor的方法設置接收窗口
mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);
}
mInputMonitor.updateInputWindowsLw(false /*force*/);
Code 省略
來看下InputMonitor 在幹啥
代碼路徑:frameworks/base/services/core/java/com/android/server/wm/inputMonitor.java
- /* Called when the current input focus changes.
- * Layer assignment is assumed to be complete by the time this is called.
- */
- public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
- if (WindowManagerService.DEBUG_FOCUS_LIGHT || WindowManagerService.DEBUG_INPUT) {
- Slog.d(WindowManagerService.TAG, "Input focus has changed to " + newWindow);
- }
- if (newWindow != mInputFocus) {
- if (newWindow != null && newWindow.canReceiveKeys()) {
- // Displaying a window implicitly causes dispatching to be unpaused.
- // This is to protect against bugs if someone pauses dispatching but
- // forgets to resume.
- newWindow.mToken.paused = false;
- }
- mInputFocus = newWindow;
- setUpdateInputWindowsNeededLw();
- if (updateInputWindows) {
- //更新當前焦點窗口
- updateInputWindowsLw(false /*force*/);
- }
- }
- }
/* Called when the current input focus changes.
* Layer assignment is assumed to be complete by the time this is called.
*/
public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
if (WindowManagerService.DEBUG_FOCUS_LIGHT || WindowManagerService.DEBUG_INPUT) {
Slog.d(WindowManagerService.TAG, "Input focus has changed to " + newWindow);
}
if (newWindow != mInputFocus) {
if (newWindow != null && newWindow.canReceiveKeys()) {
// Displaying a window implicitly causes dispatching to be unpaused.
// This is to protect against bugs if someone pauses dispatching but
// forgets to resume.
newWindow.mToken.paused = false;
}
mInputFocus = newWindow;
setUpdateInputWindowsNeededLw();
if (updateInputWindows) {
//更新當前焦點窗口
updateInputWindowsLw(false /*force*/);
}
}
}
- /* Updates the cached window information provided to the input dispatcher. */
- public void updateInputWindowsLw(boolean force) {
- if (!force && !mUpdateInputWindowsNeeded) {
- return;
- }
- Code 省略
- //在這個方法裏面會調用InputManagerService的setInputWindow方法傳入
- //inputWindowHandlers
- // Send windows to native code.
- mService.mInputManager.setInputWindows(mInputWindowHandles);
- // Clear the list in preparation for the next round.
- clearInputWindowHandlesLw();
- if (false) Slog.d(WindowManagerService.TAG, "<<<<<<< EXITED updateInputWindowsLw");
- }
/* Updates the cached window information provided to the input dispatcher. */
public void updateInputWindowsLw(boolean force) {
if (!force && !mUpdateInputWindowsNeeded) {
return;
}
Code 省略
//在這個方法裏面會調用InputManagerService的setInputWindow方法傳入
//inputWindowHandlers
// Send windows to native code.
mService.mInputManager.setInputWindows(mInputWindowHandles);
// Clear the list in preparation for the next round.
clearInputWindowHandlesLw();
if (false) Slog.d(WindowManagerService.TAG, "<<<<<<< EXITED updateInputWindowsLw");
}
到這裏就實現了WMS 通過InputMonitor 跟IMS 再 InputDispather的溝通,也就是Window 跟 Input事件的溝通了。說完他們之間的關係,就說最後一部分他們的通信渠道了。先說結論對應的window 跟 IMS 通信實際是用InputChannel。InputChannel是一個pipe,底層實際是通過socket進行通信。
看下inputChannel的源碼:
代碼路徑:frameworks\base\core\java\android\view\InputChannel.java
- Creates a new input channel pair. One channel should be provided to the input
- * dispatcher and the other to the application's input queue.
- * @param name The descriptive (non-unique) name of the channel pair.
- * @return A pair of input channels. The first channel is designated as the
- * server channel and should be used to publish input events. The second channel
- * is designated as the client channel and should be used to consume input events.
- public static InputChannel[] openInputChannelPair(String name) {
- if (name == null) {
- throw new IllegalArgumentException("name must not be null");
- }
- if (DEBUG) {
- Slog.d(TAG, "Opening input channel pair '" + name + "'");
- }
Creates a new input channel pair. One channel should be provided to the input
* dispatcher and the other to the application's input queue.
* @param name The descriptive (non-unique) name of the channel pair.
* @return A pair of input channels. The first channel is designated as the
* server channel and should be used to publish input events. The second channel
* is designated as the client channel and should be used to consume input events.
public static InputChannel[] openInputChannelPair(String name) {
if (name == null) {
throw new IllegalArgumentException("name must not be null");
}
if (DEBUG) {
Slog.d(TAG, "Opening input channel pair '" + name + "'");
}
- //這裏還要走底層的代碼
- return nativeOpenInputChannelPair(name);
- }
//這裏還要走底層的代碼
return nativeOpenInputChannelPair(name);
}
代碼路徑:frameworks\base\core\jni\android_view_InputChannel.cpp
- static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
- jclass clazz, jstring nameObj) {
- const char* nameChars = env->GetStringUTFChars(nameObj, NULL);
- String8 name(nameChars);
- env->ReleaseStringUTFChars(nameObj, nameChars);
- //這裏主要是建立了一堆通信的inputchannel
- sp<InputChannel> serverChannel;
- sp<InputChannel> clientChannel;
- status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
jclass clazz, jstring nameObj) {
const char* nameChars = env->GetStringUTFChars(nameObj, NULL);
String8 name(nameChars);
env->ReleaseStringUTFChars(nameObj, nameChars);
//這裏主要是建立了一堆通信的inputchannel
sp<InputChannel> serverChannel;
sp<InputChannel> clientChannel;
status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
- 代碼省略
代碼省略
上面代碼說明了爲了通信,建立了一對inputChannel,那如何跟socket關聯了?看下面的代碼
代碼路徑:frameworks\native\libs\input\InputTransport.cpp
- status_t InputChannel::openInputChannelPair(const String8& name,
- sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
- int sockets[2];
- if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
- status_t result = -errno;
- ALOGE("channel '%s' ~ Could not create socket pair. errno=%d",
- name.string(), errno);
- outServerChannel.clear();
- outClientChannel.clear();
- return result;
- }
- int bufferSize = SOCKET_BUFFER_SIZE;
- setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
- setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
- setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
- setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
- String8 serverChannelName = name;
- serverChannelName.append(" (server)");
- outServerChannel = new InputChannel(serverChannelName, sockets[0]);
- String8 clientChannelName = name;
- clientChannelName.append(" (client)");
- outClientChannel = new InputChannel(clientChannelName, sockets[1]);
- return OK;
status_t InputChannel::openInputChannelPair(const String8& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
status_t result = -errno;
ALOGE("channel '%s' ~ Could not create socket pair. errno=%d",
name.string(), errno);
outServerChannel.clear();
outClientChannel.clear();
return result;
}
int bufferSize = SOCKET_BUFFER_SIZE;
setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
String8 serverChannelName = name;
serverChannelName.append(" (server)");
outServerChannel = new InputChannel(serverChannelName, sockets[0]);
String8 clientChannelName = name;
clientChannelName.append(" (client)");
outClientChannel = new InputChannel(clientChannelName, sockets[1]);
return OK;
這個其實說明了inputChannel的open方法其實就是建立了socket通信
IMS體系建立了inputChannel,那WMS也相應的做了InputChannel的相關操作
代碼路徑:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
- public int addWindow(Session session, IWindow client, int seq,
- WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
- Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
- InputChannel outInputChannel) {
- int[] appOp = new int[1];
- int res = mPolicy.checkAddPermission(attrs, appOp);
- if (res != WindowManagerGlobal.ADD_OKAY) {
- CODE 省略
- if (outInputChannel != null && (attrs.inputFeatures
- & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
- /** M: [ALPS00044207] @{ */
- try {
- //設置當前通道的名字
- String name = win.makeInputChannelName();
- //打開一對通道
- InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
- win.setInputChannel(inputChannels[0]);
- inputChannels[1].transferTo(outInputChannel);
- mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
- } catch (IllegalArgumentException e) {
- Slog.w(TAG, "handle Input channel erorr", e);
- return WindowManagerGlobal.ADD_INPUTCHANNEL_NOT_ALLOWED;
- }
- /** @} */
- }
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
InputChannel outInputChannel) {
int[] appOp = new int[1];
int res = mPolicy.checkAddPermission(attrs, appOp);
if (res != WindowManagerGlobal.ADD_OKAY) {
CODE 省略
if (outInputChannel != null && (attrs.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
/** M: [ALPS00044207] @{ */
try {
//設置當前通道的名字
String name = win.makeInputChannelName();
//打開一對通道
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
win.setInputChannel(inputChannels[0]);
inputChannels[1].transferTo(outInputChannel);
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
} catch (IllegalArgumentException e) {
Slog.w(TAG, "handle Input channel erorr", e);
return WindowManagerGlobal.ADD_INPUTCHANNEL_NOT_ALLOWED;
}
/** @} */
}
到了這裏基本IMS 關於消息的處理至少在framework層講得差不多了。做個總結吧,也把開頭的問題回答下,其實文中已經說得很清楚了。
重點的幾個問題概述下:
InputManager初始化跟其他的核心service一樣都是在systemServer裏面進行(這裏估計有問題),初始化後,會調用start方法。其實調用的是native層inputmanager的start方法,這裏初始化了兩個線程。native層的inputmanager的構造函數裏面會對InputReader/
InputDispatcher進行初始化,Eventhub(讀取dev/input裏面的事件)和InputDispatcher作爲參數傳給了InputReader
Work
一:消息處理,inputReader通過EventHub獲得數據後,會通知QueuedInputListener調用flush方法,由上面的詳細筆記可以知道QueuedInputListener繼承InputListenerInterface,InputListenerInterface 是繼承Refbase,InputDispatcher作爲參數傳給了QueuedInputListener。
二:QueuedInputListener.flush方法會調用子類的notify方法,至於notify是key,還是其他,具體情況具體處理。
Inputdispatcher跟WMS的交互,主要在findfocuswindow函數裏面實現,關鍵在setWindow方法傳遞windowHandler。
setWindow方法都是通過成員變量調方法,進行windowHandler傳遞。WMS裏面有inputmonitor作爲成員變量在裏面,在InputMonitor裏面會調用native InputManagerService的setInputWindow方法,在這個方法裏面會通過InputManager調用inputDispatcher方法裏面的setInputWindow方法,完成windowHandler的傳遞。
三:可以知道windowHandler上面有inputChannel,inputChannel是android裏面的pipe 管道通信。實現了應用程序跟InputDispatcher的通信
注:mQueuedListener->flush();如何跟InputDispatcher聯繫上?
在InputRead.cpp的構造函數裏面,inputDispatcher作爲參數傳給了QueuedInputListener裏。
QueuedInputListener定義在InputListener.h 裏面,InputDispatcher作爲參數,到了QueuedInputListener的構造函數裏,傳給mInnerListener()這個方法裏面
問題:那他如何或者跟其他模塊配合獲取事件?並且把這個事件進行分發?如何準確定位對應的處理事件的模塊?
1.其實通過調用,裏面有對應的對象調用相對的方法,進行配合使用。
2.分發其實找到對應的window ,然後會建立對應的一對inputchannel進行通信。
Ok,寫完了,其實去年就寫完了,一直沒時間整理髮博客。今天大概全部整理了下發出來了。希望能跟各位多多交流。吐槽一句CSDN的博客真不好編輯代碼的。