相關文章鏈接:
1. Android Framework - 學習啓動篇
2. Android FrameWork - 開機啓動 SystemServer 進程
相關源碼文件:
/frameworks/base/services/java/com/android/server/SystemServer.java
/frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
/frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
/frameworks/native/services/inputflinger/InputDispatcher.cpp
/frameworks/native/services/inputflinger/InputReader.cpp
/frameworks/native/services/inputflinger/InputManager.cpp
/frameworks/native/services/inputflinger/EventHub.cpp
1. 梳理概述
對於 Android 上層事件分發的過程,大家應該都是比較熟悉的,因爲這是自定義 View 的一個知識點,也是前幾年面試常問的一個問題。但只是知道上層的事件分發過程可能還不夠,因爲很多高級功能開發需要依賴底層的一些知識。我們應該都知道事件一般會傳遞到 activity 根佈局 view 的 dispatchTouchEvent 方法,那麼我們有沒有思考過事件的源頭在哪裏?這個事件最初到底是從哪裏發出來的?
這裏我們先梳理做一個整體的總結,手機點擊屏幕首先從硬件傳遞到驅動,我們之前提到過在 linux 內核系統中一切皆文件,因此我們只需要監聽 /dev/input 驅動文件的變化就能讀取到事件;所以在 Android 系統中會有一個 InputReader 專門來負責讀取 Input 事件,還有一個 InputDispatcher 專門把讀取到的 Input 事件分發出來。
2. IMS 的啓動過程
/**
* Starts a miscellaneous grab bag of stuff that has yet to be refactored
* and organized.
*/
private void startOtherServices() {
final Context context = mSystemContext;
...
// 創建 InputManagerService
InputManagerService inputManager = new InputManagerService(context);
// 創建 WindowManagerService
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);
// 註冊系統服務
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
// 設置管理的 callback
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
}
public InputManagerService(Context context) {
this.mContext = context;
// 創建 InputManagerHandler
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
...
// native 層初始化,這裏會用到 handler 的 looper 的底層通信機制,handler 也是可以跨進程通信的
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
}
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
// 拿到 native 層的 MessageQueue 對象
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
// 創建 native 層的 NativeInputManager
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
return reinterpret_cast<jlong>(im);
}
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
...
// 創建 EventHub 與 InputManager
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
// 創建 InputDispatcher 與 InputReader
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
void InputManager::initialize() {
// 創建 InputDispatcher 與 InputReader 線程
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
status_t InputManager::start() {
// 分別啓動 InputDispatcher 與 InputReader 線程
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
...
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
...
return OK;
}
IMS 的啓動入口在 SystemServer 進程中,InputManagerService 在構建對象的時候會創建 native 層的 NativeInputManager 對象,NativeInputManager 中又會構建 EventHub 與 InputManager 對象,最後 InputManager 會分別創建和啓動 InputDispatcher 與 InputReader 線程。
2. Input 事件讀取
EventHub::EventHub(void) :
mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
mOpeningDevices(0), mClosingDevices(0),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false), mNeedToScanDevices(true),
mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
// 創建 epoll
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
mINotifyFd = inotify_init();
// 此處 DEVICE_PATH 爲"/dev/input",監聽該設備路徑,這個代碼在驅動層,感興趣大家自己跟一下
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.u32 = EPOLL_ID_INOTIFY;
// 添加 INotify 到 epoll 實例
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
int wakeFds[2];
result = pipe(wakeFds); // 創建管道
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
// 將 pipe 的讀和寫都設置爲非阻塞方式
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
eventItem.data.u32 = EPOLL_ID_WAKE;
// 添加管道的讀端到 epoll 實例
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
...
}
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) :
mContext(this), mEventHub(eventHub), mPolicy(policy),
mGlobalMetaState(0), mGeneration(1),
mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
// 創建輸入監聽對象 QueuedInputListener 就是 InputDispatcher
mQueuedListener = new QueuedInputListener(listener);
...
}
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
...
// 從 mEventHub 中獲取 Events 事件 ,EVENT_BUFFER_SIZE = 256
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
// 處理事件
if (count) {
processEventsLocked(mEventBuffer, count);
}
...
} // release lock
// 發送事件到 InputDispatcher
mQueuedListener->flush();
}
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
struct input_event readBuffer[bufferSize];
// 原始事件
RawEvent* event = buffer;
// 容量大小
size_t capacity = bufferSize;
for (;;) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
...
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
// 掃描設備
scanDevicesLocked();
mNeedToSendFinishedDeviceScan = true;
}
// Grab the next input event.
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
// 從設備不斷讀取事件,放入到 readBuffer
// 獲取 readBuffer 的數據, 將 input_event 信息, 封裝成 RawEvent
}
// 等待input事件的到來
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
}
// 返回所讀取的事件個數
return event - buffer;
}
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) {
int32_t deviceId = rawEvent->deviceId;
while (batchSize < count) {
if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
|| rawEvent[batchSize].deviceId != deviceId) {
break;
}
batchSize += 1;
}
// 真正分發事件
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
// 添加設備類型有:獲取鍵盤源類型,鍵盤類設備類型, 鼠標類設備類型,觸摸屏設備類型
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
...
}
}
count -= batchSize;
rawEvent += batchSize;
}
}
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
// 這裏主要分析觸摸事件
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
InputDevice* device = mDevices.valueAt(deviceIndex);
device->process(rawEvents, count);
}
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
int32_t action, int32_t actionButton, int32_t flags,
int32_t metaState, int32_t buttonState, int32_t edgeFlags,
const PointerProperties* properties, const PointerCoords* coords,
const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId,
float xPrecision, float yPrecision, nsecs_t downTime) {
...
// 封裝成 NotifyMotionArgs 通知給 InputDispatcher
NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
action, actionButton, flags, metaState, buttonState, edgeFlags,
mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
xPrecision, yPrecision, downTime);
getListener()->notifyMotion(&args);
}
InputReader 線程啓動後會不斷的通過 EventHub 去讀取事件信息,然後再把事件信息解析封裝成不同的對象,最後再通過回掉的方式通知 InputDispatcher 。其中添加設備類型有:鍵盤類設備類型, 鼠標類設備類型,觸摸屏設備類型等。
3. Input 事件分發
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
mPolicy(policy),
mPendingEvent(NULL), mLastDropReason(DROP_REASON_NOT_DROPPED),
mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(NULL),
mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
// 創建 Looper 對象
mLooper = new Looper(false);
// 獲取分發超時參數
policy->getDispatcherConfiguration(&mConfig);
}
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{
AutoMutex _l(mLock);
// 喚醒等待線程,monitor() 用於監控 dispatcher 是否發生死鎖
mDispatcherIsAliveCondition.broadcast();
if (!haveCommandsLocked()) {
// 當 mCommandQueue 不爲空時處理
dispatchOnceInnerLocked(&nextWakeupTime);
}
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}
}
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
// 進入等待,需要調用 mLooper.wake 方法來喚醒
mLooper->pollOnce(timeoutMillis);
}
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
...
if (! mPendingEvent) {
if (mInboundQueue.isEmpty()) {
// Nothing to do if there is no pending event.
if (!mPendingEvent) {
// 沒有事件需要處理直接返回
return;
}
} else {
// Inbound queue has at least one entry.
mPendingEvent = mInboundQueue.dequeueAtHead();
traceInboundQueueLengthLocked();
}
}
switch (mPendingEvent->type) {
...
case EventEntry::TYPE_KEY: {
...
// 分發 key 事件
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
case EventEntry::TYPE_MOTION: {
// 分發觸摸事件
done = dispatchMotionLocked(currentTime, typedEntry,
&dropReason, nextWakeupTime);
break;
}
}
...
}
bool InputDispatcher::dispatchMotionLocked(
nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
...
if (isPointerEvent) {
// Pointer event. (eg. touchscreen)
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;
}
// 最後開始分發
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
const MotionEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
bool* outConflictingPointerActions) {
if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
// 遍歷所有的 mWindowHandles
size_t numWindows = mWindowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
const InputWindowInfo* windowInfo = windowHandle->getInfo();
if (windowInfo->displayId != displayId) {
continue; // wrong display
}
int32_t flags = windowInfo->layoutParamsFlags;
if (windowInfo->visible) {
// 可見,並且 flags 屬性不是 InputWindowInfo::FLAG_NOT_TOUCHABLE
if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
| InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
// 點擊的是不是當前 window 的覆蓋
if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
// found touched window, exit window loop
// 找到了當前觸摸的 window
newTouchedWindowHandle = windowHandle;
break;
}
}
}
}
mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
} else {
...
}
// 再把 mTempTouchState 收集到的 windows 添加到 inputTargets 中
for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i);
addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
touchedWindow.pointerIds, inputTargets);
}
...
return injectionResult;
}
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
for (size_t i = 0; i < inputTargets.size(); i++) {
const InputTarget& inputTarget = inputTargets.itemAt(i);
// 根據 inputChannel 的 fd 從 mConnectionsByFd 隊列中查詢目標 connection.
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
// 找到目標連接
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
// 準備分發事件出去了
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
} else {
...
}
}
}
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
bool wasEmpty = connection->outboundQueue.isEmpty();
// Enqueue dispatch entries for the requested modes.
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_IS);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
// If the outbound queue was previously empty, start the dispatch cycle going.
if (wasEmpty && !connection->outboundQueue.isEmpty()) {
startDispatchCycleLocked(currentTime, connection);
}
}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
while (connection->status == Connection::STATUS_NORMAL
&& !connection->outboundQueue.isEmpty()) {
...
switch (eventEntry->type) {
case EventEntry::TYPE_KEY: {
...
break;
}
case EventEntry::TYPE_MOTION: {
MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
...
// 通過 connection 的 inputPublisher 發佈出去了
// Publish the motion event.
status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
motionEntry->deviceId, motionEntry->source,
dispatchEntry->resolvedAction, motionEntry->actionButton,
dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
motionEntry->metaState, motionEntry->buttonState,
xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount, motionEntry->pointerProperties,
usingCoords);
break;
}
...
}
}
InputDispatcher 採用的是 Looper 的喚醒與等待,這個跟之前分析 Handler 的底層原理是一樣的。收到事件後首先會找到分發的目標窗口信息,然後通過 inputTarget 的 inputChannel 找到通信連接,最後再把事件通過 connection 發佈出來,至於發到哪裏去了?我們需要熟悉後面的 WindowManagerService 的源碼。
視頻地址:https://pan.baidu.com/s/1vY_Vb3AaIB9UUWJdPMLOQQ
視頻密碼:566q