文章內(nèi)容主要從 https://segmentfault.com/a/1190000011826846 而來
1,InputManagerService
Android Framework 層的 service,大部分都是在 SystemServer 進程中創(chuàng)建,InputManagerService 即是如此,創(chuàng)建完 Service 后,便把它加入到 ServiceManager 中,并同時設置了 InputMonitor,如下
inputManager = new InputManagerService(context);
WindowManagerService wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore, new PhoneWindowManager());
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
mActivityManagerService.setWindowManager(wm);
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
看一下InputManagerservice 的構造函數(shù)
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 = nativeInit(this, mContext, mHandler.getLooper().getQueue());
String doubleTouchGestureEnablePath = context.getResources().getString(
R.string.config_doubleTouchGestureEnableFile);
mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
new File(doubleTouchGestureEnablePath);
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
nativeInit 的實現(xiàn)如下
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;
}
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(im);
}
首先是獲取 MessageQueue, 接著創(chuàng)建 NativeInputManager ,NativeInputManager 的實現(xiàn)如下
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
...
mInteractive = true;
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}
NativeInputManager 中創(chuàng)建了 EventHub,并利用 EventHub 創(chuàng)建了InputManger, InputManager 實現(xiàn)如下
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();
}
代碼中創(chuàng)建了 InputDispatcher,接著創(chuàng)建了 InputReader,接著是 initialize 方法
void InputManager::initialize()
{
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
分別將 reader 和 dispatcher 封裝到相應的 Thread 中,此時對 SystemServer 來說,InputManager 基本創(chuàng)建完成,接著便是 start Service ,對應的 native 方法便是 nativeStart(mPtr)
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
status_t result = im->getInputManager()->start();
}
status_t InputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
}
2,小結
整體流程如下
InputManger 通過 InputReaderThread 讀和處理未加工的輸入事件然后分發(fā)到 DispatcherThread 隊列中, InputDispatcherThread 將接收的隊列發(fā)送給相應的應用程序
3,epoll
這里首先了解一下 epoll,之前我們處理輸入流的時候,我們會對每一個流進行遍歷,然后檢測到有修改的數(shù)據(jù),將其取出來,這其中存在大量的資源消耗,尤其是在流比較多的時候,epoll 便在這里優(yōu)化,當無數(shù)據(jù)的時候會阻塞隊列,當有數(shù)據(jù)的時候,只將其中有變化的進行分發(fā)。
epoll更詳細的分析
4,EventHub
在 NativeInputManager 中,曾經(jīng)創(chuàng)建的EventHub,并作為參數(shù)傳遞給了 InputManger。EventHub是將不同來源的消息轉化為統(tǒng)一類型并交給上層處理。先查看其構造函數(shù)
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);
//創(chuàng)建一個epoll句柄
mEpollFd = epoll_create(EPOLL_SIZE_HINT);
mINotifyFd = inotify_init();
//監(jiān)視dev/input目錄的變化刪除和創(chuàng)建變化
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監(jiān)測
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
//創(chuàng)建匿名管道
int wakeFds[2];
result = pipe(wakeFds);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
//將管道的讀寫端設置為非阻塞
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
eventItem.data.u32 = EPOLL_ID_WAKE;
//將管道的讀端加入到epoll監(jiān)測
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
int major, minor;
getLinuxRelease(&major, &minor);
// EPOLLWAKEUP was introduced in kerel 3.5
mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
}
其中創(chuàng)建了 epoll 句柄、inotify 句柄、匿名管道(非阻塞),inotify負責監(jiān)控目錄和文件的變化,這里監(jiān)控的是/dev/input 目錄。
EventHub 負責監(jiān)控,相關事件的處理由 ReaderThread 處理。ReaderThread 是繼承Android 的 Thread
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
這個方法返回 true , 表示 threadLoop會被循環(huán)調(diào)用,也就是 loopOnce 會被循環(huán)調(diào)用,下面是 loopOnce
void InputReader::loopOnce() {
.....
//從EventHub中獲取事件
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
//如果讀到數(shù)據(jù),處理事件數(shù)據(jù)
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
//將排隊的事件隊列發(fā)送給監(jiān)聽者,實際上這個監(jiān)聽者就是Input dispatcher
mQueuedListener->flush();
}
我們要分析的是其中的兩個方法 getEvents 和 processEventsLocked
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
RawEvent* event = buffer;
size_t capacity = bufferSize;
for(;;) {
....
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
.....
ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
if (eventItem.events & EPOLLIN) {
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity);
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
// 設備被移除,關閉設備
deviceChanged = true;
closeDeviceLocked(device);
} else if (readSize < 0) {
//無法獲得事件
if (errno != EAGAIN && errno != EINTR) {
ALOGW("could not get event (errno=%d)", errno);
}
} else if ((readSize % sizeof(struct input_event)) != 0) {
//獲得事件的大小非事件類型整數(shù)倍
ALOGE("could not get event (wrong size: %d)", readSize);
} else {
int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
//計算讀入了多少事件
size_t count = size_t(readSize) / sizeof(struct input_event);
for (size_t i = 0; i < count; i++) {
struct input_event& iev = readBuffer[i];
if (iev.type == EV_MSC) {
if (iev.code == MSC_ANDROID_TIME_SEC) {
device->timestampOverrideSec = iev.value;
continue;
} else if (iev.code == MSC_ANDROID_TIME_USEC) {
device->timestampOverrideUsec = iev.value;
continue;
}
}
//事件時間相關計算,時間的錯誤可能會導致ANR和一些bug。這里采取一系列的防范
.........
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
}
if (capacity == 0) {
//每到我們計算完一個事件,capacity就會減1,如果為0。則表示 結果緩沖區(qū)已經(jīng)滿了,
//需要重置開始讀取時間的索引值,來讀取下一個事件迭代
mPendingEventIndex -= 1;
break;
}
}
//表明讀到事件了,跳出循環(huán)
if (event != buffer || awoken) {
break;
}
mPendingEventIndex = 0;
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
if (pollResult == 0) {
mPendingEventCount = 0;
break;
}
//判斷是否有事件發(fā)生
if (pollResult < 0) {
mPendingEventCount = 0;
} else {
//產(chǎn)生的事件的數(shù)目
mPendingEventCount = size_t(pollResult);
}
}
//產(chǎn)生的事件數(shù)目
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;
case EventHubInterface::DEVICE_REMOVED:
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN:
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
ALOG_ASSERT(false); // can't happen
break;
}
}
count -= batchSize;
rawEvent += batchSize;
}
}
getEvents 方法會進行一些新增設備和移除設備的更新操作。至于點擊事件是通過指針參數(shù) RawEvent, 其作為起始地址記錄事件,在循環(huán)體中,處理獲取時間、檢測相關設備類型、讀取事件,如果檢測到事件,則跳出循環(huán)。更新 mPendingEventCount 和 mPendingEventIndex 來控制事件的讀取,epoll_wait 來得到事件的來源。
在 looperOnce 獲取到事件后,就會調(diào)用 processEventsLocked。其負責事件添加、設備移除等,事件相關還是 processEventsForDeviceLocked 方法,根據(jù)事件獲取相應的設備類型,并交給相應的設備處理,即 InputMapper 。
在這里,事件會被 mapper->process 處理
void TouchInputMapper::process(const RawEvent* rawEvent) {
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
mTouchButtonAccumulator.process(rawEvent);
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
sync(rawEvent->when);
}
}
void TouchInputMapper::sync(nsecs_t when) {
.....
processRawTouches(false /*timeout*/);
}
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
....
dispatchMotion();
....
}
void TouchInputMapper::dispatchMotion() {
....
NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
action, actionButton, flags, metaState, buttonState, edgeFlags,
mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
xPrecision, yPrecision, downTime);
getListener()->notifyMotion(&args);
}
InputListenerInterface* InputReader::ContextImpl::getListener() {
return mReader->mQueuedListener.get();
}
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
mArgsQueue.push(new NotifyMotionArgs(*args));
}
此時數(shù)據(jù)被加入到參數(shù)隊列中,此時回到 loopOnce 中,調(diào)用 QueuedInputListener 的 flush 方法
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 NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyMotion(this);
}
void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
.....
MotionEvent event;
event.initialize(args->deviceId, args->source, args->action, args->actionButton,
args->flags, args->edgeFlags, args->metaState, args->buttonState,
0, 0, args->xPrecision, args->yPrecision,
args->downTime, args->eventTime,
args->pointerCount, args->pointerProperties, args->pointerCoords);
....
MotionEntry* newEntry = new MotionEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
args->action, args->actionButton, args->flags,
args->metaState, args->buttonState,
args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
args->displayId,
args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
needWake = enqueueInboundEventLocked(newEntry);
....
if (needWake) {
mLooper->wake();
}
}
在 notifyMotion 中將參數(shù)包裝成 MotionEntry,加入到 enqueueInboundEventLocked 中,然后喚醒 looper。
Dispatcher 下的 dispatchOnce
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
void InputDispatcher::dispatchOnce() {
...
dispatchOnceInnerLocked(&nextWakeupTime);
...
}
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
....
mPendingEvent = mInboundQueue.dequeueAtHead();
....
switch (mPendingEvent->type) {
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;
}
done = dispatchMotionLocked(currentTime, typedEntry,
&dropReason, nextWakeupTime);
break;
}
....
}
}
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
....
pokeUserActivityLocked(eventEntry);
.....
for (size_t i = 0; i < inputTargets.size(); i++) {
const InputTarget& inputTarget = inputTargets.itemAt(i);
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
}
}
}
prepareDispatchCycleLocked 調(diào)用 enqueueDispatchEntriesLocked 調(diào)用 startDispatchCycleLocked
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
EventEntry* eventEntry = dispatchEntry->eventEntry;
....
switch (eventEntry->type) {
....
case EventEntry::TYPE_MOTION: {
status = connection->inputPublisher.publishMotionEvent( ....);
break;
}
....
}
...
}
status_t InputPublisher::publishMotionEvent(...) {
....
InputMessage msg;
msg.header.type = InputMessage::TYPE_MOTION;
msg.body.motion.seq = seq;
msg.body.motion.deviceId = deviceId;
msg.body.motion.source = source;
msg.body.motion.action = action;
msg.body.motion.actionButton = actionButton;
msg.body.motion.flags = flags;
msg.body.motion.edgeFlags = edgeFlags;
msg.body.motion.metaState = metaState;
msg.body.motion.buttonState = buttonState;
msg.body.motion.xOffset = xOffset;
msg.body.motion.yOffset = yOffset;
msg.body.motion.xPrecision = xPrecision;
msg.body.motion.yPrecision = yPrecision;
msg.body.motion.downTime = downTime;
msg.body.motion.eventTime = eventTime;
msg.body.motion.pointerCount = pointerCount;
for (uint32_t i = 0; i < pointerCount; i++) {
msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
}
return mChannel->sendMessage(&msg);
}
ReaderThread 開啟后會從EventHub輪訓獲取時間,獲取事件后,經(jīng)過一系列的封裝,通過 InputChannel 發(fā)送出去