前言
上一篇文章中调违,對(duì)于事件的監(jiān)控和獲取做了分析穿撮,在拿到事件之后签赃,后續(xù)是如何處理分發(fā)的呢忽妒?本篇文章主要針對(duì)在通過getEvent獲取到事件之后,后續(xù)的相關(guān)分發(fā)處理流程姜挺。
InputReaderThread函數(shù)不斷地調(diào)用looperOnce函數(shù),不斷的從中讀取事件彼硫,那么下一個(gè)問題來了炊豪,讀取到事件要放置到哪里,又在哪里被消耗掉了呢拧篮?也就是事件接下來的流向問題词渤。讓我們回到looperOnce之前。
事件分發(fā)
processEventsLocked
在調(diào)用了getEvent之后串绩,獲得了事件之后缺虐,接著調(diào)用了相應(yīng)的處理函數(shù)processEventsLocked
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;
}
}
首先對(duì)于事件類型進(jìn)行了判斷,如果事件不是合成事件礁凡,則會(huì)對(duì)其DeviceID進(jìn)行判斷高氮,通過對(duì)其判斷來確定batchSize等慧妄,如果是合成事件,則會(huì)具體判斷剪芍,判斷是設(shè)備的添加塞淹,設(shè)備的移除,完成設(shè)備掃描等等罪裹,然后對(duì)事件分別進(jìn)行處理饱普,這里我們只關(guān)心對(duì)于設(shè)備自身產(chǎn)生的事件。也就是觸摸屏相關(guān)的事件状共。也就是processEventsForDeviceLocked
函數(shù)中所進(jìn)行的操作套耕。
事件派發(fā)到InputDevice
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex < 0) {
return;
}
InputDevice* device = mDevices.valueAt(deviceIndex);
if (device->isIgnored()) {
return;
}
device->process(rawEvents, count);
}
根據(jù)事件獲得相應(yīng)的設(shè)備類型,然后將事件交給相應(yīng)的設(shè)備處理峡继。判斷是否忽略該事件冯袍,如果不是忽略該事件,則會(huì)調(diào)用相應(yīng)設(shè)備的process方法進(jìn)行處理鬓椭。
事件派發(fā)到InputMapper
InputDevice的process方法
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
....
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
mapper->process(rawEvent);
}
....
}
這里的事件又交給了InputMapper來處理
InputMapper對(duì)應(yīng)了很多的子類颠猴,這里根據(jù)事件的類型進(jìn)行相應(yīng)的派發(fā),處理小染。事件到了這里之后翘瓮,這里來看一下對(duì)于觸摸屏事件的處理的相關(guān)類和處理函數(shù)。
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);
}
}
通過這里的函數(shù)處理裤翩,我們繼續(xù)追蹤函數(shù)的數(shù)據(jù)流向资盅。對(duì)于相關(guān)事件會(huì)調(diào)用TouchInputMapper的sync方法來進(jìn)行處理。
void TouchInputMapper::sync(nsecs_t when) {
.....
processRawTouches(false /*timeout*/);
}
void TouchInputMapper::processRawTouches(bool timeout) {
....
cookAndDispatch(mCurrentRawState.when);
....
}
在相關(guān)的函數(shù)調(diào)用之后踊赠,最終調(diào)用了dispatchTouches
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
....
dispatchMotion();
....
}
對(duì)于dispatchTouches中呵扛,會(huì)根據(jù)記錄的上一次的觸摸位置,對(duì)事件的類型進(jìn)行判斷筐带,然后做相應(yīng)的分發(fā)今穿,事件類型有抬起,下落伦籍,移動(dòng)等蓝晒,然后對(duì)相應(yīng)的事件進(jìn)行分發(fā)。無論是對(duì)于何種類型的事件派發(fā)帖鸦,最終被調(diào)用到的都是dispatchMotion()
方法芝薇。
對(duì)于相關(guān)事件的分發(fā)最終調(diào)用到了dispatchMotion(),對(duì)事件數(shù)據(jù)進(jìn)行組裝之后作儿,調(diào)用了
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);
}
這里對(duì)于事件進(jìn)行了封裝洛二,構(gòu)造出一個(gè)NotifyMotionArgs,在整個(gè)傳遞流程做的比較多的就是通過對(duì)于事件進(jìn)行一系列的判斷,然后進(jìn)行一系列的封裝晾嘶。接下來的執(zhí)行是調(diào)用QueuedInputListener的notifyMotion妓雾,將構(gòu)造的事件添加到其中的一個(gè)Args隊(duì)列之中。
InputListenerInterface* InputReader::ContextImpl::getListener() {
return mReader->mQueuedListener.get();
}
notifyMotion函數(shù)實(shí)現(xiàn)
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
mArgsQueue.push(new NotifyMotionArgs(*args));
}
之后又調(diào)用了QueuedInputListener
的flush
方法变擒。遍歷事件的隊(duì)列君珠,然后對(duì)其逐一調(diào)用notify函數(shù)。
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();
}
NotifyArgs的notify函數(shù)實(shí)現(xiàn)
void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyMotion(this);
}
對(duì)于這個(gè)listener的創(chuàng)建來自于InputReader構(gòu)建的時(shí)候娇斑。
mQueuedListener = new QueuedInputListener(listener);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
而這里的Listener則是InputDispatcher
策添,InputDispatcher 的notifyMotion實(shí)現(xiàn)源碼。
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();
}
}
在該函數(shù)中毫缆,所做的事情是對(duì)于所傳遞的參數(shù)唯竹,構(gòu)造MotionEntry,然后將其加入到enqueueInboundEventLocked之中苦丁。然后喚醒其中的looper浸颓。
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(entry);
...
//進(jìn)行一些事件和窗口相關(guān)的判斷處理
}
Dispatcher開啟的線程中,每次循環(huán)的操作如何旺拉?
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
Dispatcher下dispatchOnce的實(shí)現(xiàn)
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;
}
....
}
}
從mInboudQueue中产上,獲取到事件,然后對(duì)事件類型進(jìn)行判斷蛾狗,判斷之后調(diào)用了dispatchMotionLocked函數(shù)晋涣,來繼續(xù)進(jìn)行事件的傳遞。
bool InputDispatcher::dispatchMotionLocked(
nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
....
Vector<InputTarget> inputTargets;
if (isPointerEvent) {
// Pointer event. (eg. touchscreen)
//尋找目標(biāo)窗口
injectionResult = findTouchedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
} else {
// Non touch event. (eg. trackball)
injectionResult = findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime);
}
....
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
- dispatchEventLocked
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);
}
}
}
獲得目標(biāo)輸入沉桌,根據(jù)InputChannel獲取相應(yīng)的連接谢鹊,然后調(diào)用prepareDispatchCycleLocked(),進(jìn)行事件的派發(fā)留凭。
enqueueDispatchEntriesLocked佃扼,在該方法中又調(diào)用了startDispatchCycleLocked方法。其實(shí)現(xiàn)為
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;
}
....
}
...
}
至此調(diào)用了connection 的inputPublisher的publishMotionEvent方法將事件分發(fā)消耗蔼夜。
InputPublisher定義在InputTransport.cpp中
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);
}
該方法所執(zhí)行的操作是利用傳入的觸摸信息兼耀,構(gòu)建點(diǎn)擊消息,然后通過InputChannel將消息發(fā)送出去求冷。這里引出了InputChannel翠订,在此,我們通InputPublisher的創(chuàng)建反推出InputChannel是何時(shí)被引入的遵倦,何時(shí)被創(chuàng)建的。從而進(jìn)一步分析其作用官撼。在分析之前先讓我們來對(duì)上述的分析過程做一個(gè)總結(jié)梧躺。
ReaderThread開啟后會(huì)從EventHub中輪詢獲取時(shí)間,獲取到事件之后,將進(jìn)行一系列的處理掠哥,對(duì)事件進(jìn)行加工包裝巩踏,然后傳遞給相應(yīng)的InputDevice,InputMapper续搀,然后將包裝的事件添加到一個(gè)事件隊(duì)列中塞琼,InputDispatcher的線程則會(huì)在輪詢讀取該線程中的事件,然后將其再次進(jìn)行做判斷處理后禁舷,傳遞彪杉,最終到達(dá)InputChannel,通過InputChannel牵咙,來將數(shù)據(jù)發(fā)送出去派近。
到此,對(duì)于輸入事件洁桌,我們已經(jīng)分析到了InputChannel渴丸,對(duì)于其上的具體分析轉(zhuǎn)化,將是接下來分析的核心另凌。
InputChannel
從上面分析可以看到事件傳遞部分最后是通過InputChannel所發(fā)送出去的谱轨,那么InputChannel是在何時(shí)被創(chuàng)建的呢?何時(shí)被InputManager所使用的呢吠谢?同時(shí)土童,對(duì)于InputReaderThread和InputDispatcherThread是運(yùn)行在SystemServer進(jìn)程中的,而我們的應(yīng)用進(jìn)程是和其不在同一個(gè)進(jìn)程中的囊卜。這之間一定也是有進(jìn)程間的通信機(jī)制在里面娜扇。具體是如何實(shí)現(xiàn)的呢?這里我們從InputChannel的創(chuàng)建著手來看栅组。
InputChannel的創(chuàng)建是在 ViewRootImpl
中setView
方法中雀瓢。
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
....
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
....
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
....
}
這里對(duì)于ViewRootImpl和WindowSession相關(guān)暫且不介紹,對(duì)于這方面的知識(shí)玉掸,需要很大的篇幅來介紹刃麸,這里先只是講到是在這里創(chuàng)建的,對(duì)于其相關(guān)的內(nèi)容將在后續(xù)的文章中介紹司浪。這里首先是創(chuàng)建了一個(gè)InputChannel泊业,然后將其調(diào)用了WindowSession
的addToDisplay
方法將其作為參數(shù)傳遞。
public InputChannel() {
}
在InputChannel中的方法都為調(diào)用了相應(yīng)的native方法啊易。這里調(diào)用的addToDisplay將會(huì)把InputChannel添加到WindowManagerService中吁伺。會(huì)調(diào)用WMS的addWindow
方法。
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
InputChannel outInputChannel) {
....
final boolean openInputChannels = (outInputChannel != null
&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) {
win.openInputChannel(outInputChannel);
}
....
}
對(duì)于InputChannel的相關(guān)處理調(diào)用了WindowState的openInputChannel方法租谈。
void openInputChannel(InputChannel outInputChannel) {
if (mInputChannel != null) {
throw new IllegalStateException("Window already has an input channel.");
}
String name = makeInputChannelName();
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
mInputChannel = inputChannels[0];
mClientChannel = inputChannels[1];
mInputWindowHandle.inputChannel = inputChannels[0];
if (outInputChannel != null) {
mClientChannel.transferTo(outInputChannel);
mClientChannel.dispose();
mClientChannel = null;
} else {
mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
}
mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle);
}
首先調(diào)用了InputChannel的openInputChannelPair
方法篮奄,該方法調(diào)用了InputChannel的native方法nativeOpenInputChannelPair
,創(chuàng)建了兩個(gè)InputChannel
捆愁,對(duì)其中一個(gè)通過InputManager
進(jìn)行了InputChannel的注冊(cè)。對(duì)于InputChannel
的相關(guān)Native的實(shí)現(xiàn)是在InputTransport中窟却,nativeOpenInputChannelPair
的源碼如下昼丑。
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;
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::sendMessage(const InputMessage* msg) {
size_t msgLength = msg->size();
ssize_t nWrite;
do {
nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
if (nWrite < 0) {
int error = errno;
if (error == EAGAIN || error == EWOULDBLOCK) {
return WOULD_BLOCK;
}
if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED || error == ECONNRESET) {
return DEAD_OBJECT;
}
return -error;
}
if (size_t(nWrite) != msgLength) {
return DEAD_OBJECT;
}
return OK;
}
接收消息,通過讀socket的方式來讀取消息夸赫。
status_t InputChannel::receiveMessage(InputMessage* msg) {
ssize_t nRead;
do {
nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);
} while (nRead == -1 && errno == EINTR);
if (nRead < 0) {
int error = errno;
if (error == EAGAIN || error == EWOULDBLOCK) {
return WOULD_BLOCK;
}
if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED) {
return DEAD_OBJECT;
}
return -error;
}
if (nRead == 0) { // check for EOF
return DEAD_OBJECT;
}
if (!msg->isValid(nRead)) {
return BAD_VALUE;
}
return OK;
}
接收端的消息由誰來觸發(fā)呢菩帝?是如何觸發(fā)開始接受消息,消息如何在傳到InputChannel之后茬腿,進(jìn)行的進(jìn)一步的數(shù)據(jù)傳遞呢呼奢?這是接下來所要去分析的,這里先對(duì)上面InputChannel進(jìn)行一個(gè)總結(jié)滓彰。
之前的setView
中控妻,我們創(chuàng)建了InputChannel之后,開啟了對(duì)于InputChannel中輸入事件的監(jiān)聽揭绑。
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
WindowInputEventReceiver的構(gòu)造函數(shù)如下弓候,其繼承自InputEventReceiver。
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}
....
}
InputEventReceiver的構(gòu)造函數(shù)源碼如下
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
....
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
inputChannel, mMessageQueue);
}
這里調(diào)用了native方法來做初始化他匪,相關(guān)的native方法的實(shí)現(xiàn)在android_view_InputEventReceiver.cpp
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject inputChannelObj, jobject messageQueueObj) {
....
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
receiverWeak, inputChannel, messageQueue);
status_t status = receiver->initialize();
.....
}
根據(jù)傳入的InputChannel
和MessageQueue
菇存,創(chuàng)建一個(gè)NativeInputEventReceiver,然后調(diào)用其initialize
方法邦蜜。
status_t NativeInputEventReceiver::initialize() {
setFdEvents(ALOOPER_EVENT_INPUT);
return OK;
}
在initialize()
方法中依鸥,只調(diào)用了一個(gè)函數(shù)setFdEvents
,
void NativeInputEventReceiver::setFdEvents(int events) {
if (mFdEvents != events) {
mFdEvents = events;
int fd = mInputConsumer.getChannel()->getFd();
if (events) {
mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
} else {
mMessageQueue->getLooper()->removeFd(fd);
}
}
}
從InputConsumer中獲取到channel的fd悼沈,然后調(diào)用Looper的addFd
方法贱迟。
int ALooper_addFd(ALooper* looper, int fd, int ident, int events,
ALooper_callbackFunc callback, void* data) {
return ALooper_to_Looper(looper)->addFd(fd, ident, events, callback, data);
}
Looper的addFd的實(shí)現(xiàn)如下
int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
Request request;
request.fd = fd;
request.ident = ident;
request.events = events;
request.seq = mNextRequestSeq++;
request.callback = callback;
request.data = data;
if (mNextRequestSeq == -1) mNextRequestSeq = 0;
struct epoll_event eventItem;
request.initEventItem(&eventItem);
ssize_t requestIndex = mRequests.indexOfKey(fd);
if (requestIndex < 0) {
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
if (epollResult < 0) {
return -1;
}
mRequests.add(fd, request);
}
}
該方法所執(zhí)行的操作就是對(duì)傳遞的fd添加epoll監(jiān)控,Looper會(huì)循環(huán)調(diào)用pollOnce
方法絮供,而pollOnce
方法的核心實(shí)現(xiàn)就是pollInner
衣吠。其代碼大致實(shí)現(xiàn)內(nèi)容為等待消息的到來,當(dāng)有消息到來后壤靶,根據(jù)消息類型做一些判斷處理缚俏,然后調(diào)用其相關(guān)的callback。我們當(dāng)前是對(duì)于開啟的socket的一個(gè)監(jiān)聽贮乳,當(dāng)有數(shù)據(jù)到來忧换,我們便會(huì)執(zhí)行相應(yīng)的回調(diào)。這里對(duì)于InputChannel的回調(diào)是在調(diào)用了NativeInputEventReceiver的handleEvent
方法向拆。
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
.....
if (events & ALOOPER_EVENT_INPUT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
return status == OK || status == NO_MEMORY ? 1 : 0;
}
....
return 1;
}
對(duì)于Event的處理亚茬,這里調(diào)用consumeEvents來對(duì)事件進(jìn)行處理。
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
...
for(;;) {
...
InputEvent* inputEvent;
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent);
...
}
...
}
InputConsumer是在InputTransport中做的聲明浓恳。
status_t InputConsumer::consume(InputEventFactoryInterface* factory,
bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
while (!*outEvent) {
....
status_t result = mChannel->receiveMessage(&mMsg);
....
}
}
調(diào)用consume方法會(huì)持續(xù)的調(diào)用InputChannel的receiveMessage方法來從socket中讀取數(shù)據(jù)刹缝。到這里葡兑,我們已經(jīng)將寫入socket的事件讀出來了。
public void registerInputChannel(InputChannel inputChannel,
InputWindowHandle inputWindowHandle) {
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null.");
}
nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
}
nativeRegisterInputManger
static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
if (inputChannel == NULL) {
throwInputChannelNotInitialized(env);
return;
}
sp<InputWindowHandle> inputWindowHandle =
android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
status_t status = im->registerInputChannel(
env, inputChannel, inputWindowHandle, monitor);
if (status) {
String8 message;
message.appendFormat("Failed to register input channel. status=%d", status);
jniThrowRuntimeException(env, message.string());
return;
}
if (! monitor) {
android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
handleInputChannelDisposed, im);
}
}
NativeInputManager的registerInputChannel
還會(huì)調(diào)用到InputDispatcher的registerInputChannel赞草,會(huì)通過InputChannel創(chuàng)建相應(yīng)的Connection,同時(shí)將InputChannel加入到相應(yīng)的監(jiān)控之中吆鹤。在上面對(duì)代碼的分析之中厨疙,獲取InputChannel,就是通過這個(gè)Connection來獲取的疑务。
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
{ // acquire lock
AutoMutex _l(mLock);
if (getConnectionIndexLocked(inputChannel) >= 0) {
return BAD_VALUE;
}
sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
int fd = inputChannel->getFd();
mConnectionsByFd.add(fd, connection);
if (monitor) {
mMonitoringChannels.push(inputChannel);
}
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
// Wake the looper because some connections have changed.
mLooper->wake();
return OK;
}
ViewRootImpl
事件在從socket讀出之后沾凄,經(jīng)過傳遞,最終會(huì)調(diào)用到ViewRootImpl的enqueueInputEvent
方法知允。
void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
adjustInputEventForCompatibility(event);
QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
QueuedInputEvent last = mPendingInputEventTail;
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
mPendingInputEventCount += 1;
if (processImmediately) {
doProcessInputEvents();
} else {
scheduleProcessInputEvents();
}
}
enqueueInputEvent方法從InputEventReceiver中獲取到InputEvent撒蟀,然后將其加入到當(dāng)前的事件隊(duì)列之中,最后調(diào)用doProcessInputEvents
來進(jìn)行處理温鸽。
void doProcessInputEvents() {
while (mPendingInputEventHead != null) {
QueuedInputEvent q = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
if (mPendingInputEventHead == null) {
mPendingInputEventTail = null;
}
q.mNext = null;
mPendingInputEventCount -= 1;
long eventTime = q.mEvent.getEventTimeNano();
long oldestEventTime = eventTime;
if (q.mEvent instanceof MotionEvent) {
MotionEvent me = (MotionEvent)q.mEvent;
if (me.getHistorySize() > 0) {
oldestEventTime = me.getHistoricalEventTimeNano(0);
}
}
mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
deliverInputEvent(q);
}
// We are done processing all input events that we can process right now
// so we can clear the pending flag immediately.
if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}
遍歷所有的消息保屯,如果事件類型為觸摸屏事件,對(duì)其進(jìn)行相應(yīng)的時(shí)間修改涤垫,最后對(duì)于每一個(gè)處理完成的事件調(diào)用deliverInputEvent
,
private void deliverInputEvent(QueuedInputEvent q) {
q.mEvent.getSequenceNumber());
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}
InputStage stage;
if (q.shouldSendToSynthesizer()) {
stage = mSyntheticInputStage;
} else {
stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
}
if (stage != null) {
stage.deliver(q);
} else {
finishInputEvent(q);
}
}
在事件分發(fā)環(huán)節(jié)姑尺,首先進(jìn)行事件的一個(gè)判斷,通過shouldSkipIme來判斷是否傳遞給輸入法蝠猬,然后決定使用何種InputStage進(jìn)行消息的繼續(xù)傳遞切蟋,這里實(shí)現(xiàn)了多種InputStage,對(duì)于每一個(gè)類型的InputStage都實(shí)現(xiàn)了一個(gè)方法process
方法來針對(duì)不同類型的事件做處理榆芦,如果是觸摸屏類的消息柄粹,最終會(huì)將事件的處理轉(zhuǎn)交到View的身上。
InputStage中的事件如何傳遞處理匆绣,傳遞處理之后驻右,如何進(jìn)行
對(duì)于InputStage涉及的篇幅較多,這里也不再展開犬绒,當(dāng)消息到達(dá)ViewRootImpl中后旺入,接下來就是在View間的派發(fā)。
View的事件派發(fā)
對(duì)于View層的事件派發(fā)凯力,我們最常見的就是dispatchTouchEvent
茵瘾,onTouch
,onInterceptTouchEvent
,onClick
,onTouchEvent
等咐鹤。對(duì)于View樹上事件的派發(fā)拗秘,就是在對(duì)樹的遍歷傳遞中,主要起作用的就是這幾個(gè)函數(shù)祈惶。這里我們先從View的相關(guān)事件函數(shù)開始分析雕旨,由于ViewGroup具有子View的原因扮匠,其相關(guān)的事件派發(fā)邏輯和View有所區(qū)別,這里我們先進(jìn)行View的事件分析凡涩。
public boolean dispatchTouchEvent(MotionEvent event) {
....
if (onFilterTouchEventForSecurity(event)) {
if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
result = true;
}
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
}
....
return result棒搜;
}
對(duì)于在View上的事件派發(fā),核心操作是兩點(diǎn)活箕,一個(gè)是調(diào)用監(jiān)聽器的onTouch方法力麸,然后判斷事件是否被消耗,如果沒有被消耗育韩,則會(huì)調(diào)用onTouchEvent方法克蚂。在onTouchEvent中根據(jù)消息類型進(jìn)行一些處理。
根據(jù)事件類型來更新內(nèi)部的一些狀態(tài)筋讨。這里比較復(fù)雜的還是在ViewGroup中的事件分發(fā)邏輯埃叭,這里在分發(fā)的過程中,需要判斷是否對(duì)事件進(jìn)行攔截悉罕,如果不攔截赤屋,是否自身可處理,如果需要考慮到其中的子View蛮粮。這里對(duì)其中的關(guān)鍵代碼進(jìn)行逐步分析益缎。
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
} else {
intercepted = true;
}
判斷是否進(jìn)行攔截,調(diào)用自身的onInterceptTouchEvent
然想,開發(fā)者可以重載這個(gè)方法進(jìn)行自己的一些操作莺奔。返回true表示攔截事件。如果要對(duì)事件進(jìn)行攔截变泄,則不再進(jìn)行子View的遍歷令哟。否則將會(huì)進(jìn)行子View的遍歷,事件傳遞妨蛹,在子View的事件傳遞結(jié)束之后屏富,如果子View將事件消耗了則會(huì)將其加入到mFirstTouchTarget,如果遍歷完成沒有任何被添加
if (mFirstTouchTarget == null) {
// No touch targets so treat this as an ordinary view.
handled = dispatchTransformedTouchEvent(ev, canceled, null,
TouchTarget.ALL_POINTER_IDS);
}
接下來進(jìn)行的是對(duì)于事件在子View中的派發(fā)蛙卤,這里我們也只是針對(duì)其中的核心代碼進(jìn)行分析狠半。
final View[] children = mChildren;
for (int i = childrenCount - 1; i >= 0; i--) {
final int childIndex = getAndVerifyPreorderedIndex(
childrenCount, i, customOrder);
final View child = getAndVerifyPreorderedView(
preorderedList, children, childIndex);
....
dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign);
....
}
在對(duì)子View進(jìn)行遍歷的處理的時(shí)候,如果子View的事件被消耗颤难,那么我們就會(huì)將其TouchTarget賦值給mFirstTouchTarget
神年,當(dāng)檢測(cè)到mFirstTouchTarget為空時(shí)會(huì)再調(diào)用Viewgroup自身的dispatchTransformedTouchEvent方法,這個(gè)時(shí)候就會(huì)調(diào)用其onTouchEvent行嗤,然后繼續(xù)View中的事件傳遞流程已日。
if (mFirstTouchTarget == null) {
// No touch targets so treat this as an ordinary view.
handled = dispatchTransformedTouchEvent(ev, canceled, null,
TouchTarget.ALL_POINTER_IDS);
}
對(duì)于dispatchTransformedTouchEvent
函數(shù)
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
View child, int desiredPointerIdBits) {
if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
event.setAction(MotionEvent.ACTION_CANCEL);
if (child == null) {
handled = super.dispatchTouchEvent(event);
} else {
handled = child.dispatchTouchEvent(event);
}
event.setAction(oldAction);
return handled;
}
....
}
這里事件的派發(fā)也是在調(diào)用了每一個(gè)子View的dispatchTouchEvent方法,根據(jù)返回結(jié)果來判斷是否被消耗栅屏,一旦事件被消耗則會(huì)停止傳遞飘千。