努比亞技術(shù)團(tuán)隊(duì)原創(chuàng)內(nèi)容枢劝,轉(zhuǎn)載請務(wù)必注明出處。
- Native層傳遞過程
- InputEventReceiver的事件來源于哪里
- InputConsumer
- InputConsumer處理事件
- InputConsumer的構(gòu)建
- InputChannel
- InputChannel的創(chuàng)建
- server端InputChannel的注冊
- client端InputChannel讀取事件并傳遞
- 小結(jié)
- InputManagerService
- IMS的創(chuàng)建
- IMS的啟動
- 小結(jié)
- InputDispatcher
- InputDispatcher啟動
- InputDispatcher分發(fā)事件
- InputReader(InputDispatcher事件的來源)
- InputReader啟動
- InputReader處理事件
- EventHub
- EventHub的創(chuàng)建
- EventHub如何獲取輸入事件
- EventHub處理reopen設(shè)備
- EventHub處理close設(shè)備
- EventHub掃描設(shè)備
- EventHub處理open設(shè)備
- EventHub處理event
- EventHub處理inotify事件
- 小結(jié)
Native層傳遞過程
此小節(jié)主要介紹輸入事件是如何從InputReader獲取卜壕,然后InputDispatcher又是如何將它們分發(fā)出去您旁,這個過程中使用什么技術(shù)進(jìn)行事件的傳遞的。
InputEventReceiver的事件來源于哪里
上節(jié)中有介紹在Native層NativeInputEventReceiver的consumeEvents方法中會通過jni方式調(diào)用Java層的InputEventReceiver的dispatchInputEvent方法將事件傳遞到上層轴捎。那consumeEvents的事件又來源于哪里呢鹤盒?我們繼續(xù)看這個consumeEvents方法。
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
// 省略若干行
for (;;) {
// 省略若干行
InputEvent* inputEvent;
// 這里調(diào)用了InputConsumer的consume方法來獲取輸入事件
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent,
&motionEventType, &touchMoveNum, &flag);
// 省略若干行
if (skipCallbacks) {
mInputConsumer.sendFinishedSignal(seq, false);
}
}
}
InputConsumer
consume方法中主要是從InputChannel獲取輸入事件的信息侦副,然后根據(jù)消息中獲取的事件類型構(gòu)造出對應(yīng)的event侦锯,并將消息中的事件信息賦值給event對象。
InputConsumer處理事件
從上面分析我們能夠看到秦驯,再NativeInputEventReceiver的consumeEvents方法中尺碰,會循環(huán)調(diào)用InputConsumer的consume方法獲取事件并進(jìn)行處理。InputConsumer的consume方法中會通過InputChannel從socket中通過recv系統(tǒng)調(diào)用獲取下層傳遞的事件译隘,獲取到事件后就會通過jni向Java層傳遞亲桥。
status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches,
nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent,
int* motionEventType, int* touchMoveNumber, bool* flag) {
// 省略若干行
*outSeq = 0;
*outEvent = nullptr;
// Fetch the next input message.
// Loop until an event can be returned or no additional events are received.
while (!*outEvent) {
if (mMsgDeferred) {
// mMsg contains a valid input message from the previous call to consume
// that has not yet been processed.
mMsgDeferred = false;
} else {
// Receive a fresh message.
// 這里通過調(diào)用InputChannel的receiveMessage來獲取消息
status_t result = mChannel->receiveMessage(&mMsg);
// 省略若干行
}
// 根據(jù)消息的類型生成不同的Event
switch (mMsg.header.type) {
case InputMessage::Type::KEY: {
// 構(gòu)造一個KeyEvent
KeyEvent* keyEvent = factory->createKeyEvent();
if (!keyEvent) return NO_MEMORY;
// 從msg中獲取事件的各屬性,并賦值給構(gòu)造出的Event對象
initializeKeyEvent(keyEvent, &mMsg);
*outSeq = mMsg.body.key.seq;
*outEvent = keyEvent;
if (DEBUG_TRANSPORT_ACTIONS) {
ALOGD("channel '%s' consumer ~ consumed key event, seq=%u",
mChannel->getName().c_str(), *outSeq);
}
break;
}
case InputMessage::Type::MOTION: {
// 構(gòu)造一個MotionEvent
MotionEvent* motionEvent = factory->createMotionEvent();
if (!motionEvent) return NO_MEMORY;
updateTouchState(mMsg);
// 從msg中獲取事件的各屬性固耘,并賦值給構(gòu)造出的Event對象
initializeMotionEvent(motionEvent, &mMsg);
*outSeq = mMsg.body.motion.seq;
*outEvent = motionEvent;
if (DEBUG_TRANSPORT_ACTIONS) {
ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
mChannel->getName().c_str(), *outSeq);
}
break;
}
// 省略若干行
}
}
return OK;
}
這里我們先看下event的構(gòu)造和初始化题篷,輸入消息的獲取隨后再介紹。先看下factory->createMotionEvent玻驻,這里factory是PreallocatedInputEventFactory的實(shí)例悼凑。
class PreallocatedInputEventFactory : public InputEventFactoryInterface {
public:
PreallocatedInputEventFactory() { }
virtual ~PreallocatedInputEventFactory() { }
// 可以看到這里返回的是全局變量的地址
virtual KeyEvent* createKeyEvent() override { return &mKeyEvent; }
virtual MotionEvent* createMotionEvent() override { return &mMotionEvent; }
virtual FocusEvent* createFocusEvent() override { return &mFocusEvent; }
private:
// 這里定義不同類型的事件變量
KeyEvent mKeyEvent;
MotionEvent mMotionEvent;
FocusEvent mFocusEvent;
};
好了,我們繼續(xù)看event的初始化璧瞬。這里主要是從msg中獲取對應(yīng)事件的詳細(xì)信息然后賦值給對應(yīng)的event對象上户辫。
// 對key事件進(jìn)行初始化
void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) {
event->initialize(msg->body.key.eventId, msg->body.key.deviceId, msg->body.key.source,
msg->body.key.displayId, msg->body.key.hmac, msg->body.key.action,
msg->body.key.flags, msg->body.key.keyCode, msg->body.key.scanCode,
msg->body.key.metaState, msg->body.key.repeatCount, msg->body.key.downTime,
msg->body.key.eventTime);
}
// 對motion事件進(jìn)行初始化
void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) {
// 省略若干行
event->initialize(msg->body.motion.eventId, msg->body.motion.deviceId, msg->body.motion.source,
msg->body.motion.displayId, msg->body.motion.hmac, msg->body.motion.action,
msg->body.motion.actionButton, msg->body.motion.flags,
msg->body.motion.edgeFlags, msg->body.motion.metaState,
msg->body.motion.buttonState, msg->body.motion.classification,
msg->body.motion.xScale, msg->body.motion.yScale, msg->body.motion.xOffset,
msg->body.motion.yOffset, msg->body.motion.xPrecision,
msg->body.motion.yPrecision, msg->body.motion.xCursorPosition,
msg->body.motion.yCursorPosition, msg->body.motion.downTime,
msg->body.motion.eventTime, pointerCount, pointerProperties, pointerCoords);
}
然后我們繼續(xù)看msg的獲取方法:InputChannel的receiveMessage方法。
status_t InputChannel::receiveMessage(InputMessage* msg) {
ssize_t nRead;
do {
// 這里通過recv系統(tǒng)調(diào)用從socket中讀取消息
nRead = ::recv(mFd.get(), msg, sizeof(InputMessage), MSG_DONTWAIT);
} while (nRead == -1 && errno == EINTR);
// 省略若干行
return OK;
}
可以看到這個方法主要是從socket中讀取消息嗤锉。那這里的socket是什么時候建立的呢渔欢?我們繼續(xù)向下看。
InputConsumer的構(gòu)建
在NativeInputEventReceiver的構(gòu)造方法中瘟忱,會創(chuàng)建出NativeInputEventReceiver奥额,并將InputChannel傳入苫幢。而NativeInputEventReceiver的構(gòu)建是在Java層InputEventReceiver的native方法nativeInit中創(chuàng)建,并且能夠看到垫挨,這里的InputChannel是從Java層傳遞下來的韩肝。
InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
mResampleTouch(isTouchResamplingEnabled()),
// 初始化InputChannel
mChannel(channel), mMsgDeferred(false) {
}
我們發(fā)現(xiàn)在InputConsumer構(gòu)造時對InputChannel進(jìn)行了初始化,那就繼續(xù)超前看InputConsumer在哪里構(gòu)建的九榔。
NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
jobject receiverWeak, const sp<InputChannel>& inputChannel,
const sp<MessageQueue>& messageQueue) :
mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
mInputConsumer(inputChannel), mMessageQueue(messageQueue),
mBatchedInputEventPending(false), mFdEvents(0) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName().c_str());
}
}
回到NativeInputEventReceiver中哀峻,發(fā)現(xiàn)它的構(gòu)造方法中傳入了InputChannel,那么繼續(xù)看NativeInputEventReceiver的構(gòu)建哲泊。
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject inputChannelObj, jobject messageQueueObj) {
// 通過jni獲取java創(chuàng)建的InputChannel
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
// 省略若干行
// 構(gòu)建出NativeInputEventReceiver
sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
receiverWeak, inputChannel, messageQueue);
// 初始化Receiver
status_t status = receiver->initialize();
// 省略若干行
receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object
return reinterpret_cast<jlong>(receiver.get());
}
通過上述分析剩蟀,我們發(fā)現(xiàn)NativeInputEventReceiver中獲取底層事件的InputChannel是來自于Java層的傳遞,那么切威,InputChannel又是如何創(chuàng)建的呢育特?
InputChannel
InputChannel會作為句柄傳遞到下層,后面分發(fā)事件的時候會通過它來進(jìn)行先朦。而且這里會創(chuàng)建出兩個缰冤,一個作為server端注冊到InputManagerService,最終會注冊到InputDispatcher中去喳魏,另一個則作為client端來接收server端的事件锋谐。
InputChannel的創(chuàng)建
通過前面分析,我們發(fā)現(xiàn)NativeInputEventReceiver中的InputChanel來源于Java層的InputChannel截酷。上述nativeInit是Java層InputEventReceiver的native方法涮拗,繼續(xù)看Java層的InputEventReceiver。
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
// 省略若干行
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue();
// 將Java層的inputChannel向下層傳遞
mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
inputChannel, mMessageQueue);
mCloseGuard.open("dispose");
}
Java層InputEventReceiver構(gòu)造時傳入了InputChannel迂苛。在ViewRootImpl的setView方法中會創(chuàng)建InputChannel三热,然后會調(diào)用Session的addToDisplayAsUser方法初始化InputChannel
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId) {
synchronized (this) {
if (mView == null) {
// 省略若干行
InputChannel inputChannel = null;
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
inputChannel = new InputChannel();
}
// 省略若干行
// 調(diào)用Session的addToDisplayAsUser方法來添加window,
// 會初始化InputChannel
res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mDisplayCutout, inputChannel,
mTempInsets, mTempControls);
// 省略若干行
if (inputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
// 將InputChannel傳入InputEventReceiver
mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
Looper.myLooper());
}
// 省略若干行
}
}
}
Session的addToDisplayAsUser方法會繼續(xù)調(diào)用WindowManagerService的addWindow方法三幻。
public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, int userId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
// 直接調(diào)用WindowManagerService的addWindow方法
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
outInsetsState, outActiveControls, userId);
}
addWindow方法中會調(diào)用WindowState打開InputChannel就漾。
public int addWindow(Session session, IWindow client, int seq,
LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState, InsetsSourceControl[] outActiveControls,
int requestUserId) {
// 省略若干行
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], seq, attrs, viewVisibility, session.mUid, userId,
session.mCanAddInternalSystemWindow);
// 省略若干行
final boolean openInputChannels = (outInputChannel != null
&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) {
// 這里會調(diào)用WindowState的openInputChannel來打開inputChannel
win.openInputChannel(outInputChannel);
}
// 省略若干行
return res;
}
繼續(xù)看WindowState的openInputChannel方法。首先會通過調(diào)用InputChannel的靜態(tài)方法openInputChannelPair來創(chuàng)建兩個InputChannel念搬,一個作為client一個作為server抑堡;然后還會調(diào)用InputManagerService的registerInputChannel來注冊server端的InputChannel;最后將client端的InputChannel設(shè)置到outInputChannel中朗徊。
void openInputChannel(InputChannel outInputChannel) {
if (mInputChannel != null) {
throw new IllegalStateException("Window already has an input channel.");
}
String name = getName();
// 通過openInputChannelPair方法創(chuàng)建出兩個InputChannel
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
mInputChannel = inputChannels[0];
mClientChannel = inputChannels[1];
// 注冊server端的InputChannel到InputManagerService中
mWmService.mInputManager.registerInputChannel(mInputChannel);
mInputWindowHandle.token = mInputChannel.getToken();
if (outInputChannel != null) {
// 將client端的InputChannel設(shè)置到outInputChannel
mClientChannel.transferTo(outInputChannel);
mClientChannel.dispose();
mClientChannel = null;
} else {
// If the window died visible, we setup a dummy input channel, so that taps
// can still detected by input monitor channel, and we can relaunch the app.
// Create dummy event receiver that simply reports all events as handled.
mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
}
mWmService.mInputToWindowMap.put(mInputWindowHandle.token, this);
}
上述openInputChannelPair方法中會直接調(diào)用InputChannel的native方法nativeOpenInputChannelPair來創(chuàng)建出一對InputChannel首妖。
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 + "'");
}
// 繼續(xù)調(diào)用natvie方法創(chuàng)建出兩個InputChannel
return nativeOpenInputChannelPair(name);
}
jni方法nativeOpenInputChannelPair中會繼續(xù)調(diào)用InputChannel的openInputChannelPair靜態(tài)方法。然后將創(chuàng)建出的兩個inputChannel分別添加到數(shù)組中爷恳,然后返回給上層有缆。
static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
jclass clazz, jstring nameObj) {
ScopedUtfChars nameChars(env, nameObj);
std::string name = nameChars.c_str();
sp<InputChannel> serverChannel;
sp<InputChannel> clientChannel;
// 創(chuàng)建出server端和client端的InputChannel
status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
// 省略若干行
// 添加到數(shù)組中,然后返回給上層
env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
return channelPair;
}
openInputChannelPair方法中會首先通過socketpair創(chuàng)建一對相互連接的套接字,然后分別給socket設(shè)置相應(yīng)的選項(xiàng)值棚壁;然后通過InputChannel的create方法創(chuàng)建出兩個分別與socket關(guān)聯(lián)的inuptChannel杯矩。
status_t InputChannel::openInputChannelPair(const std::string& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
int sockets[2];
// 創(chuàng)建一對相互連接的socket
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
status_t result = -errno;
// 創(chuàng)建失敗做相應(yīng)的處理
ALOGE("channel '%s' ~ Could not create socket pair. errno=%d",
name.c_str(), errno);
outServerChannel.clear();
outClientChannel.clear();
return result;
}
// 分別設(shè)置兩個socket的可讀可寫buffer
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));
sp<IBinder> token = new BBinder();
std::string serverChannelName = name + " (server)";
android::base::unique_fd serverFd(sockets[0]);
// 創(chuàng)建出server端InputChannel,并于socket關(guān)聯(lián)
outServerChannel = InputChannel::create(serverChannelName, std::move(serverFd), token);
std::string clientChannelName = name + " (client)";
android::base::unique_fd clientFd(sockets[1]);
// 創(chuàng)建出client端InputChannel袖外,并于socket關(guān)聯(lián)
outClientChannel = InputChannel::create(clientChannelName, std::move(clientFd), token);
return OK;
}
通過InputChannel的create方法構(gòu)建出InputChannel并返回史隆。
sp<InputChannel> InputChannel::create(const std::string& name, android::base::unique_fd fd,
sp<IBinder> token) {
// 設(shè)置文件描述符fd的狀態(tài)屬性為O_NONBLOCK
const int result = fcntl(fd, F_SETFL, O_NONBLOCK);
if (result != 0) {
LOG_ALWAYS_FATAL("channel '%s' ~ Could not make socket non-blocking: %s", name.c_str(),
strerror(errno));
return nullptr;
}
// 創(chuàng)建出InputChannel并返回
return new InputChannel(name, std::move(fd), token);
}
至此,InputChannel便創(chuàng)建并關(guān)聯(lián)上socket上了曼验。并且通過前面的介紹逆害,我們知道了獲取輸入事件時是從client端的socket中讀取消息并進(jìn)行事件封裝,然后傳遞到上層蚣驼。但是這里我們發(fā)現(xiàn)有一個問題展哭,就是client端socket中的數(shù)據(jù)是從哪里來的呢票腰?我們繼續(xù)看一下WindowState的openInputChannel方法。
server端InputChannel的注冊
在通過openInputChannel開啟InputChannel后政溃,會調(diào)用了InputManagerService的registerInputChannel方法注冊server端的InputChannel
void openInputChannel(InputChannel outInputChannel) {
// 省略若干行
// 通過openInputChannelPair方法創(chuàng)建出兩個InputChannel
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
mInputChannel = inputChannels[0];
mClientChannel = inputChannels[1];
// 注冊server端的InputChannel到InputManagerService中
mWmService.mInputManager.registerInputChannel(mInputChannel);
// 省略若干行
}
我們發(fā)現(xiàn)server端的InputChannel被注冊到了InputManagerService中去了坛芽,那么留储,我們繼續(xù)向下看。
public void registerInputChannel(InputChannel inputChannel) {
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null.");
}
// 調(diào)用native方法繼續(xù)注冊
nativeRegisterInputChannel(mPtr, inputChannel);
}
在InputManagerService的registerInputChannel方法中直接調(diào)用了native方法nativeRegisterInputChannel咙轩,我們繼續(xù)获讳。
static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
jlong ptr, jobject inputChannelObj) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
// 獲取InputChannel
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
if (inputChannel == nullptr) {
throwInputChannelNotInitialized(env);
return;
}
// 將inputChannel注冊到NativeInputManager中
status_t status = im->registerInputChannel(env, inputChannel);
// 設(shè)置dispose的callback,在inputChannel
// dispose之后會調(diào)用函數(shù)指針handleInputChannelDisposed
// 來調(diào)用NativeInputManager的unregisterInputChannel
// 解注冊inputChannel
android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
handleInputChannelDisposed, im);
}
在native方法中活喊,先調(diào)用了NativeInputManager的registerInputChannel方法注冊inputChannel丐膝,然后會給inputChannel設(shè)置dispose callback,并且callback中執(zhí)行了inputChannel的解注冊钾菊。在NativeInputManager的registerInputChannel方法中帅矗,會獲取InputDispatcher,并將inputChannel注冊到其中去煞烫。
status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */,
const sp<InputChannel>& inputChannel) {
ATRACE_CALL();
return mInputManager->getDispatcher()->registerInputChannel(inputChannel);
}
在InputDispatcher的registerInputChannel方法中浑此,會通過InputChannel構(gòu)建出Connection,然后將其添加到注冊列表當(dāng)中滞详。
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel) {
#if DEBUG_REGISTRATION
ALOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().c_str());
#endif
{ // acquire lock
std::scoped_lock _l(mLock);
// 省略若干行
// 創(chuàng)建connection并添加的注冊列表中
sp<Connection> connection = new Connection(inputChannel, false /*monitor*/, mIdGenerator);
int fd = inputChannel->getFd();
mConnectionsByFd[fd] = connection;
mInputChannelsByToken[inputChannel->getConnectionToken()] = inputChannel;
// 將inputChannel的fd添加到looper中凛俱,并且對應(yīng)的event是ALOOPER_EVENT_INPUT
// 傳入的looper callback為handleReceiveCallback方法,
// 因此當(dāng)事件到來時料饥,會觸發(fā)此callback
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
// Wake the looper because some connections have changed.
mLooper->wake();
return OK;
}
好了蒲犬,到這里我們就知道了,server端的inputChannel最終被注冊到了InputDispatcher的注冊列表中去了岸啡,所以InputDispatcher中就可以通過向server端的socket中寫入消息暖哨,然后client端就可以讀取到了。但是,這里還發(fā)現(xiàn)存在一個問題:那就是server端寫入事件消息后篇裁,怎么通知到client去開始處理呢沛慢?我們在回過頭來看一下前面介紹的InputEventReceiver的構(gòu)造函數(shù)。
client端InputChannel讀取事件并傳遞
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
// 省略若干層
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue();
// 將Java層的inputChannel向下層傳遞
mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
inputChannel, mMessageQueue);
mCloseGuard.open("dispose");
}
在InputEventReceiver的構(gòu)造方法中調(diào)用了native方法nativeInit進(jìn)行native層的初始化
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject inputChannelObj, jobject messageQueueObj) {
// 省略若干行
sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
receiverWeak, inputChannel, messageQueue);
// 初始化Receiver
status_t status = receiver->initialize();
// 省略若干行
return reinterpret_cast<jlong>(receiver.get());
}
在NativeInputEventReceiver初始化時达布,會將inputChannel的文件描述符fd添加到looper中去团甲,并且添加了looper callback為NativeInputEventReceiver實(shí)例自身,所以黍聂,當(dāng)server端寫入事件消息時躺苦,就會觸發(fā)callback,于是便調(diào)用到NativeInputEventReceiver的handleEvent方法产还。
status_t NativeInputEventReceiver::initialize() {
// 設(shè)置文件描述符對應(yīng)的event為ALOOPER_EVENT_INPUT
setFdEvents(ALOOPER_EVENT_INPUT);
return OK;
}
void NativeInputEventReceiver::setFdEvents(int events) {
if (mFdEvents != events) {
mFdEvents = events;
int fd = mInputConsumer.getChannel()->getFd();
if (events) {
// 將inputChannel的文件描述符添加到looper中
// 對應(yīng)的event為ALOOPER_EVENT_INPUT
// 并傳入了this作為loopercallback
mMessageQueue->getLooper()->addFd(fd, 0, events, this, nullptr);
} else {
mMessageQueue->getLooper()->removeFd(fd);
}
}
}
我們發(fā)現(xiàn)在handleEvent方法中匹厘,調(diào)用了consumeEvents方法來處理事件,而consumeEvents方法便是我們前面介紹過了的脐区,在其內(nèi)部會通過jni的方式將事件向Java層傳遞到InputEventReceiver的dispatchInputEvent愈诚,從而便實(shí)現(xiàn)了事件的分發(fā)。
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
// 省略若干行
// 接收添加的ALOOPER_EVENT_INPUT事件
if (events & ALOOPER_EVENT_INPUT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
// 調(diào)用consumeEvents方法處理事件
status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr);
mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
return status == OK || status == NO_MEMORY ? 1 : 0;
}
// 省略若干行
return 1;
}
小結(jié)
通過以上分析牛隅,我們便明白了InputDispatcher是如果通過InputChannel將事件向上層進(jìn)行分發(fā)的整個過程炕柔。首先是創(chuàng)建一對InputChannel,并且會開啟一對相互連接的socket作為事件傳遞的媒介媒佣。server端的InputChannel會注冊到InputDispatcher中去以完成事件的分發(fā)匕累,并且會將其fd添加到looper中,而client端的InputChannel會在InputEventReceiver初始化時也會將其fd添加到looper中默伍,并傳入callback類接收server端寫入的事件欢嘿,這樣整個過程便串聯(lián)起來了。但是也糊,這里還存在一個問題:InputDispatcher的事件從哪里來呢际插?
InputManagerService
InputManagerService簡稱IMS,和其他系統(tǒng)服務(wù)一樣显设,是在SystemServer中創(chuàng)建并啟動框弛,它主要是用來監(jiān)測和加工輸入事件,并向上層傳遞捕捂。而且瑟枫,上文所說的InputDispatcher以及InputReader均是在InputManagerService中構(gòu)建出來的。
IMS的創(chuàng)建
在SystemServer的startOtherServices方法中指攒,直接通過new的方式創(chuàng)建出IMS實(shí)例慷妙。
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
// 省略若干行
t.traceBegin("StartInputManagerService");
// 創(chuàng)建IMS
inputManager = new InputManagerService(context);
t.traceEnd();
// 省略若干行
}
InputManagerService的構(gòu)造方法中,會先創(chuàng)建出Handler允悦,然后通過native方法nativeInit來實(shí)現(xiàn)IMS的初始化膝擂,主要是構(gòu)建native層的IMS。
public InputManagerService(Context context) {
this.mContext = context;
// 創(chuàng)建出handler
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
// 省略若干行
// 調(diào)用native方法來構(gòu)建native層IMS
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
// 省略若干行
}
native方法中先獲取到上層傳下來的messageQueue,然后獲取對應(yīng)的Looper架馋,并構(gòu)建出NativeInputManager狞山。
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
// 獲取上層傳遞的MessageQueue
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == nullptr) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
// 構(gòu)建NativeInputManager
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(im);
}
NativeInputManager構(gòu)造中,先創(chuàng)建出native層IMS實(shí)例叉寂,然后將其添加到serviceManager中萍启。
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
// 省略若干行
// 構(gòu)建出native層的IMS,即InputManager
mInputManager = new InputManager(this, this);
// 將IMS添加到serviceManager中
defaultServiceManager()->addService(String16("inputflinger"),
mInputManager, false);
}
在InputManager構(gòu)建時屏鳍,會分別創(chuàng)建出InputDispatcher勘纯、InputListener以及InputReader實(shí)例。這里將InputDispatcher作為InputListener傳遞到InputClassifier钓瞭,并最終傳遞到InputReader中去驳遵。
InputManager::InputManager(
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = createInputDispatcher(dispatcherPolicy);
mClassifier = new InputClassifier(mDispatcher);
mReader = createInputReader(readerPolicy, mClassifier);
}
通過以上分析,我們發(fā)現(xiàn)在IMS創(chuàng)建的最后山涡,會創(chuàng)建出InputDispatcher和InputReader堤结,InputDispatcher我們前面已經(jīng)介紹了,主要是用于分發(fā)事件佳鳖;而InputReader是用來獲取底層輸入事件的,這個我們后面會介紹到媒惕。
IMS的啟動
我們繼續(xù)來看SystemServer的startCoreServices方法系吩,在創(chuàng)建出IMS實(shí)例后,會調(diào)用其的start方法來啟動服務(wù)妒蔚。
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
// 省略若干行
t.traceBegin("StartInputManager");
// 將WindowCallback傳遞給IMS
inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
// 調(diào)用start啟動服務(wù)
inputManager.start();
t.traceEnd();
// 省略若干行
}
start方法中會直接調(diào)用native的nativeStart方法來啟動native層的IMS穿挨。
public void start() {
Slog.i(TAG, "Starting input manager");
// 調(diào)用native方法來啟動底層IMS
nativeStart(mPtr);
// 省略若干行
}
nativeStart方法中會獲取到InputManager,然后調(diào)用它的start方法肴盏。
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
// 調(diào)用InputManager的start方法
status_t result = im->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
在InputManager的start方法中科盛,先調(diào)用了InputDispatcher的start方法來啟動InputDispatcher,然后調(diào)用InputReader的start方法啟動InputReader菜皂。
status_t InputManager::start() {
status_t result = mDispatcher->start();
if (result) {
ALOGE("Could not start InputDispatcher thread due to error %d.", result);
return result;
}
result = mReader->start();
if (result) {
ALOGE("Could not start InputReader due to error %d.", result);
mDispatcher->stop();
return result;
}
return OK;
}
小結(jié)
通過以上IMS的創(chuàng)建和啟動過程分析贞绵,我們能夠看到在IMS的創(chuàng)建和啟動都是在SystemServer的startCoreServices方法中觸發(fā)的,另外在創(chuàng)建的時候也會分別創(chuàng)建出InputDispatcher和InputReader恍飘;而且榨崩,在調(diào)用start方法啟動的時候,最終也會觸發(fā)調(diào)用InputDispatcher和InputReader的start方法來啟動各自實(shí)例章母。
InputDispatcher
通過上述分析母蛛,知道了InputDispatcher的創(chuàng)建是在IMS創(chuàng)建時創(chuàng)建,那么它是如何啟動起來的呢乳怎?我們繼續(xù)看InputDispatcher的start方法彩郊。
InputDispatcher啟動
在InputDispatcher的start方法中,會創(chuàng)建出InputThread線程,并傳入了兩個函數(shù)指針:dispatchOnce以及mLooper->wake秫逝。
status_t InputDispatcher::start() {
if (mThread) {
return ALREADY_EXISTS;
}
// 直接構(gòu)造出Thread恕出,傳入兩個回調(diào)函數(shù)
mThread = std::make_unique<InputThread>(
"InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
return OK;
}
繼續(xù)看InputThread的構(gòu)造過程,發(fā)現(xiàn)初始化列表中對傳入的回調(diào)函數(shù)進(jìn)行了保存筷登,然后構(gòu)建InputThreadImpl并調(diào)用其run方法將線程啟動起來剃根。
InputThread::InputThread(std::string name, std::function<void()> loop, std::function<void()> wake)
// 這里保存wake回調(diào)函數(shù)
: mName(name), mThreadWake(wake) {
// 將loop函數(shù)傳入InputThreadImpl
mThread = new InputThreadImpl(loop);
mThread->run(mName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY);
}
InputThread::~InputThread() {
mThread->requestExit();
// 調(diào)用wake函數(shù)
if (mThreadWake) {
mThreadWake();
}
mThread->requestExitAndWait();
}
class InputThreadImpl : public Thread {
public:
explicit InputThreadImpl(std::function<void()> loop)
// 保存loop函數(shù)
: Thread(/* canCallJava */ true), mThreadLoop(loop) {}
~InputThreadImpl() {}
private:
std::function<void()> mThreadLoop;
bool threadLoop() override {
// 在線程的loop循環(huán)中調(diào)用了傳入的loop函數(shù)。
mThreadLoop();
// 返回true線程會一直運(yùn)行前方,直到requestExit被調(diào)用時退出
return true;
}
};
通過以上分析狈醉,我們發(fā)現(xiàn)InputThread構(gòu)造時會創(chuàng)建出線程并將其啟動起來,傳入的loop函數(shù)(dispatchOnce)最終會作為線程的loop來執(zhí)行惠险,而wake函數(shù)(mLooper->wake)也會在InputThread析構(gòu)時調(diào)用苗傅。
InputDispatcher分發(fā)事件
通過前面的介紹,我們了解到在InputDispatcher啟動時創(chuàng)建了線程班巩,并且將dispatchOnce作為線程的執(zhí)行函數(shù)傳入到InputThread中渣慕。所以,當(dāng)InputDispatcher線程被喚醒后就會執(zhí)行dispatchOnce方法來分發(fā)事件抱慌。
我們繼續(xù)逊桦,在dispatchOnce方法中,首先會判斷是否有command需要處理(如:configChanged抑进,focusChanged等)强经,如果有就會調(diào)用runCommandsLockedInterruptible方法執(zhí)行所有command,然后會再次觸發(fā)wake執(zhí)行事件的處理寺渗;如果沒有則直接調(diào)用dispatchOnceInnerLocked來處理輸入事件匿情;最后,looper會再次進(jìn)入睡眠等待下一次喚醒信殊。
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
std::scoped_lock _l(mLock);
mDispatcherIsAlive.notify_all();
// Run a dispatch loop if there are no pending commands.
// The dispatch loop might enqueue commands to run afterwards.
if (!haveCommandsLocked()) {
// 這里沒有command需要處理炬称,就開始分發(fā)事件
dispatchOnceInnerLocked(&nextWakeupTime);
}
// Run all pending commands if there are any.
// If any commands were run then force the next poll to wake up immediately.
// 處理command,并修改nextWakeupTime
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}
// If we are still waiting for ack on some events,
// we might have to wake up earlier to check if an app is anr'ing.
// 檢測是否事件分發(fā)出現(xiàn)anr
const nsecs_t nextAnrCheck = processAnrsLocked();
nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);
// We are about to enter an infinitely long sleep, because we have no commands or
// pending or queued events
if (nextWakeupTime == LONG_LONG_MAX) {
mDispatcherEnteredIdle.notify_all();
}
} // release lock
// Wait for callback or timeout or wake. (make sure we round up, not down)
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
// 處理完成后調(diào)用looper的pollOnce進(jìn)入睡眠狀態(tài)涡拘,等待下一次喚醒玲躯,
// 如果是處理了command,則這個timeoutMillis為0
// 所以會接著執(zhí)行一次loop
mLooper->pollOnce(timeoutMillis);
}
dispatchOnceInnerLocked方法會先判斷是否有待分發(fā)的事件鳄乏,沒有則從事件隊(duì)列中取出一個事件府蔗;然后根據(jù)事件不同的type調(diào)用不同的dispatch方法進(jìn)行事件分發(fā)。
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
// 省略若干行
// Ready to start a new event.
// If we don't already have a pending event, go grab one.
if (!mPendingEvent) {
// 如果沒有待分發(fā)的事件
if (mInboundQueue.empty()) {
// 省略若干行
// Nothing to do if there is no pending event.
// 事件隊(duì)列為空汞窗,并且沒有待分發(fā)的事件姓赤,直接返回
if (!mPendingEvent) {
return;
}
} else {
// Inbound queue has at least one entry.
// 從隊(duì)列中取出一個事件
mPendingEvent = mInboundQueue.front();
mInboundQueue.pop_front();
traceInboundQueueLengthLocked();
}
// 省略若干行
switch (mPendingEvent->type) {
// 省略若干行
// 根據(jù)事件的type分別進(jìn)行處理
case EventEntry::Type::KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
// 省略若干行
// 分發(fā)key事件
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
case EventEntry::Type::MOTION: {
// 省略若干行
// 分發(fā)motion事件
done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
}
}
這里以key事件為例繼續(xù)介紹,dispatchKeyLocked中首先通過findFocusedWindowTargetsLocked方法查找到焦點(diǎn)窗口仲吏,然后調(diào)用dispatchEventLocked朝焦點(diǎn)窗口上分發(fā)事件不铆。
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
// 省略若干行
// Identify targets.
std::vector<InputTarget> inputTargets;
// 查找focus window
int32_t injectionResult =
findFocusedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime);
// 省略若干行
// 將事件分發(fā)到對應(yīng)window上去
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
dispatchEventLocked方法中會遍歷所有查找到的focus窗口(inputTarget)蝌焚,然后通過inputChannel獲取到鏈接對象connection,最后通過prepareDispatchCycleLocked將事件分發(fā)出去誓斥。
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry,
const std::vector<InputTarget>& inputTargets) {
// 省略若干行
// 遍歷所有的inputTarget
for (const InputTarget& inputTarget : inputTargets) {
// 通過inputChannel獲取connection
sp<Connection> connection =
getConnectionLocked(inputTarget.inputChannel->getConnectionToken());
if (connection != nullptr) {
// 開始事件分發(fā)
prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
}
// 省略若干行
}
}
prepareDispatchCycleLocked方法中先判斷是否需要split motion事件并進(jìn)行處理只洒,最后調(diào)用enqueueDispatchEntriesLocked方法將待分發(fā)的事件添加到mOutboundQueue隊(duì)列中。
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection,
EventEntry* eventEntry,
const InputTarget& inputTarget) {
// 省略若干行
// Split a motion event if needed.
// 如果需要split motion事件則進(jìn)行處理
if (inputTarget.flags & InputTarget::FLAG_SPLIT) {
LOG_ALWAYS_FATAL_IF(eventEntry->type != EventEntry::Type::MOTION,
"Entry type %s should not have FLAG_SPLIT",
EventEntry::typeToString(eventEntry->type));
const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry);
if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) {
// 省略若干行
enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget);
splitMotionEntry->release();
return;
}
}
// Not splitting. Enqueue dispatch entries for the event as is.
// 將將要分發(fā)的事件入隊(duì)
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}
enqueueDispatchEntriesLocked方法中會分別處理不同的flag對應(yīng)的事件將其添加到outboundQueue中劳坑,最后通過調(diào)用startDispatchCycleLocked開始事件的分發(fā)毕谴。
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection,
EventEntry* eventEntry,
const InputTarget& inputTarget) {
// 省略若干行
bool wasEmpty = connection->outboundQueue.empty();
// 分別處理不同flag對應(yīng)的event,并將其添加到outboundQueue隊(duì)列中
// 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.empty()) {
// 如果有event被添加到隊(duì)列則開始處理
startDispatchCycleLocked(currentTime, connection);
}
}
startDispatchCycleLocked方法中通過遍歷outboundQueue隊(duì)列距芬,取出所有的event涝开,然后根據(jù)其type分別調(diào)用InputPublisher的publishXxxEvent將事件分發(fā)出去。
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
// 省略若干行
// 循環(huán)遍歷outboundQueue隊(duì)列
while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {
// 從outboundQueue隊(duì)列取出事件
DispatchEntry* dispatchEntry = connection->outboundQueue.front();
dispatchEntry->deliveryTime = currentTime;
const nsecs_t timeout =
getDispatchingTimeoutLocked(connection->inputChannel->getConnectionToken());
dispatchEntry->timeoutTime = currentTime + timeout;
// Publish the event.
status_t status;
EventEntry* eventEntry = dispatchEntry->eventEntry;
// 根據(jù)event的不同type分別進(jìn)行分發(fā)
switch (eventEntry->type) {
case EventEntry::Type::KEY: {
const KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
std::array<uint8_t, 32> hmac = getSignature(*keyEntry, *dispatchEntry);
// Publish the key event.
// 分發(fā)key事件
status =
connection->inputPublisher
.publishKeyEvent(dispatchEntry->seq, dispatchEntry->resolvedEventId,
keyEntry->deviceId, keyEntry->source,
keyEntry->displayId, std::move(hmac),
dispatchEntry->resolvedAction,
dispatchEntry->resolvedFlags, keyEntry->keyCode,
keyEntry->scanCode, keyEntry->metaState,
keyEntry->repeatCount, keyEntry->downTime,
keyEntry->eventTime);
break;
}
case EventEntry::Type::MOTION: {
MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
PointerCoords scaledCoords[MAX_POINTERS];
const PointerCoords* usingCoords = motionEntry->pointerCoords;
// 省略若干行
// 分發(fā)motion事件
// Publish the motion event.
status = connection->inputPublisher
.publishMotionEvent(dispatchEntry->seq,
dispatchEntry->resolvedEventId,
motionEntry->deviceId, motionEntry->source,
motionEntry->displayId, std::move(hmac),
dispatchEntry->resolvedAction,
motionEntry->actionButton,
dispatchEntry->resolvedFlags,
motionEntry->edgeFlags, motionEntry->metaState,
motionEntry->buttonState,
motionEntry->classification, xScale, yScale,
xOffset, yOffset, motionEntry->xPrecision,
motionEntry->yPrecision,
motionEntry->xCursorPosition,
motionEntry->yCursorPosition,
motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount,
motionEntry->pointerProperties, usingCoords);
reportTouchEventForStatistics(*motionEntry);
break;
}
// 省略若干行
}
}
這里以key事件為例繼續(xù)介紹,在publishKeyEvent方法中,首先會根據(jù)傳入的event詳細(xì)信息構(gòu)建出InputMessage矫户,然后再調(diào)用InputChannel的sendMessage方法將msg發(fā)送出去。
status_t InputPublisher::publishKeyEvent(uint32_t seq, int32_t eventId, int32_t deviceId,
int32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac, int32_t action,
int32_t flags, int32_t keyCode, int32_t scanCode,
int32_t metaState, int32_t repeatCount, nsecs_t downTime,
nsecs_t eventTime) {
// 省略若干行
// 根據(jù)event信息構(gòu)建InputMessage
InputMessage msg;
msg.header.type = InputMessage::Type::KEY;
msg.body.key.seq = seq;
msg.body.key.eventId = eventId;
msg.body.key.deviceId = deviceId;
msg.body.key.source = source;
msg.body.key.displayId = displayId;
msg.body.key.hmac = std::move(hmac);
msg.body.key.action = action;
msg.body.key.flags = flags;
msg.body.key.keyCode = keyCode;
msg.body.key.scanCode = scanCode;
msg.body.key.metaState = metaState;
msg.body.key.repeatCount = repeatCount;
msg.body.key.downTime = downTime;
msg.body.key.eventTime = eventTime;
// 通過InputChannel的sendMessage方法將event發(fā)送出去
return mChannel->sendMessage(&msg);
}
sendMessage主要就是先copy一份事件msg银舱,然后調(diào)用send將msg循環(huán)寫入socket,從而實(shí)現(xiàn)輸入事件的分發(fā)跛梗。
status_t InputChannel::sendMessage(const InputMessage* msg) {
const size_t msgLength = msg->size();
InputMessage cleanMsg;
// copy一份msg
msg->getSanitizedCopy(&cleanMsg);
ssize_t nWrite;
do {
// 通過socket循環(huán)寫入msg
nWrite = ::send(mFd.get(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
// 省略若干行
return OK;
}
InputReader(InputDispatcher事件的來源)
InputDispatcher中的事件是從InputReader中來的寻馏,InputReader從EventHub中獲取到輸入事件后,會通過調(diào)用InputDispatcher的notifyXxx方法來將事件傳遞到InuptDispatcher中核偿。
InputReader啟動
在IMS的start方法中會調(diào)用InputReader的start方法來啟動InputReader诚欠,我們繼續(xù)看InputReader的start方法。在start方法中宪祥,會創(chuàng)建出InputThread線程聂薪,這里注意家乘,創(chuàng)建線程時傳入了兩個函數(shù)指針(laumda表達(dá)式):loopOnce和mEventHub->wake蝗羊。通過上面對InputThread的介紹,我們知道最終仁锯,loopOnce會作為線程的循環(huán)方法進(jìn)行調(diào)用耀找,而mEventHub->wake最終也會在線程析構(gòu)時觸發(fā)。
status_t InputReader::start() {
if (mThread) {
return ALREADY_EXISTS;
}
// 直接構(gòu)造出Thread业崖,傳入兩個回調(diào)函數(shù)
mThread = std::make_unique<InputThread>(
"InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });
return OK;
}
InputReader處理事件
InputReader在其線程的threadLoop中會調(diào)用loopOnce從EventHub中獲取輸入事件野芒,如果獲取到事件,則繼續(xù)調(diào)用processEventsLocked進(jìn)行處理双炕。接著會調(diào)用到InputDevice -> InputMapper -> InputDispatcher(InputListenerInterface)狞悲,在InputDispatcher中觸發(fā)notifyXxx方法,從而將事件分發(fā)出去妇斤。
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
std::vector<InputDeviceInfo> inputDevices;
// 省略若干行
// 從EventHub中獲取事件
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
// 獲取到輸入事件則調(diào)用processEventsLocked進(jìn)行處理
if (count) {
processEventsLocked(mEventBuffer, count);
}
// 省略若干行
}
processEventsLocked方法中會根據(jù)事件的type摇锋,分別處理device的變更事件以及輸入事件丹拯。輸入事件則繼續(xù)調(diào)用processEventsForDeviceLocked來處理,device改變則同步改變mDevices荸恕。
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) {
// 省略若干行
// 這里事件類型如果不是device change事件則繼續(xù)處理
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
// device change事件
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
// device接入乖酬,將device添加到全局map中(mDevices)
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED: // device斷開
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN: // device scan
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
ALOG_ASSERT(false); // can't happen
break;
}
}
count -= batchSize;
rawEvent += batchSize;
}
}
processEventsForDeviceLocked中從device的map中根據(jù)eventHubId查找device,如果找到則調(diào)用對應(yīng)device的process方法繼續(xù)處理融求。
void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents,
size_t count) {
// 通過eventHubId從map中查找InputDevice
auto deviceIt = mDevices.find(eventHubId);
if (deviceIt == mDevices.end()) {
// 沒有對應(yīng)的device則直接返回
ALOGW("Discarding event for unknown eventHubId %d.", eventHubId);
return;
}
std::shared_ptr<InputDevice>& device = deviceIt->second;
// device被忽略則返回
if (device->isIgnored()) {
// ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
}
// 調(diào)用InputDevice的process繼續(xù)處理事件
device->process(rawEvents, count);
}
InputDevice的process中會遍歷所有的event咬像,并且根據(jù)event中的deviceId從mDevices中找到對應(yīng)的device,然后遍歷其所有的InputMapper生宛,并調(diào)用mapper的process進(jìn)行事件處理县昂。
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
// Process all of the events in order for each mapper.
// We cannot simply ask each mapper to process them in bulk because mappers may
// have side-effects that must be interleaved. For example, joystick movement events and
// gamepad button presses are handled by different mappers but they should be dispatched
// in the order received.
for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
// 省略若干行
// 從devices中找到對應(yīng)的device,然后遍歷其所有inputMapper茅糜,并調(diào)用其process方法進(jìn)行處理
for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) {
mapper.process(rawEvent);
});
--count;
}
}
inline void for_each_mapper_in_subdevice(int32_t eventHubDevice,
std::function<void(InputMapper&)> f) {
auto deviceIt = mDevices.find(eventHubDevice);
// 查找對應(yīng)的device
if (deviceIt != mDevices.end()) {
auto& devicePair = deviceIt->second;
auto& mappers = devicePair.second;
// 遍歷該device的所有InputMapper七芭,并調(diào)用函數(shù)指針f
for (auto& mapperPtr : mappers) {
f(*mapperPtr);
}
}
}
InputMapper在InputReader中處理device接入事件觸發(fā)時會調(diào)用addDeviceLocked方法,然后會調(diào)用到createDeviceLocked方法來創(chuàng)建出對應(yīng)的InputDevice蔑赘,創(chuàng)建出device后狸驳,便調(diào)用它的addEventHubDevice來創(chuàng)建出相應(yīng)的InputMapper并添加到全局map中。
void InputReader::addDeviceLocked(nsecs_t when, int32_t eventHubId) {
// 根據(jù)eventHubId查找device
if (mDevices.find(eventHubId) != mDevices.end()) {
ALOGW("Ignoring spurious device added event for eventHubId %d.", eventHubId);
return;
}
InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId);
// 創(chuàng)建device
std::shared_ptr<InputDevice> device = createDeviceLocked(eventHubId, identifier);
// 省略若干行
}
std::shared_ptr<InputDevice> InputReader::createDeviceLocked(
int32_t eventHubId, const InputDeviceIdentifier& identifier) {
// 省略若干行
std::shared_ptr<InputDevice> device;
if (deviceIt != mDevices.end()) {
// 如果device已經(jīng)存在則直接返回
device = deviceIt->second;
} else {
// 否則創(chuàng)建出對應(yīng)的InputDevice
int32_t deviceId = (eventHubId < END_RESERVED_ID) ? eventHubId : nextInputDeviceIdLocked();
device = std::make_shared<InputDevice>(&mContext, deviceId, bumpGenerationLocked(),
identifier);
}
// 調(diào)用addEventHubDevice缩赛,構(gòu)建出相應(yīng)的mapper
device->addEventHubDevice(eventHubId);
return device;
}
通過addEventHubDevice方法耙箍,可以看出針對不同的device類型,會構(gòu)建出不同的mapper酥馍,最后將mapper數(shù)組添加到了mDevices的全局map中辩昆。后面我們以KeyboardInputMapper為例介紹key事件的傳遞過程。
void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) {
if (mDevices.find(eventHubId) != mDevices.end()) {
return;
}
std::unique_ptr<InputDeviceContext> contextPtr(new InputDeviceContext(*this, eventHubId));
uint32_t classes = contextPtr->getDeviceClasses();
std::vector<std::unique_ptr<InputMapper>> mappers;
// Check if we should skip population
if (!populateMappers) {
mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
return;
}
// Switch-like devices.
if (classes & INPUT_DEVICE_CLASS_SWITCH) {
mappers.push_back(std::make_unique<SwitchInputMapper>(*contextPtr));
}
// Scroll wheel-like devices.
if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) {
mappers.push_back(std::make_unique<RotaryEncoderInputMapper>(*contextPtr));
}
// Vibrator-like devices.
if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
mappers.push_back(std::make_unique<VibratorInputMapper>(*contextPtr));
}
// Keyboard-like devices.
uint32_t keyboardSource = 0;
int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
keyboardSource |= AINPUT_SOURCE_KEYBOARD;
}
if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
}
if (classes & INPUT_DEVICE_CLASS_DPAD) {
keyboardSource |= AINPUT_SOURCE_DPAD;
}
if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
keyboardSource |= AINPUT_SOURCE_GAMEPAD;
}
if (keyboardSource != 0) {
mappers.push_back(
std::make_unique<KeyboardInputMapper>(*contextPtr, keyboardSource, keyboardType));
}
// Cursor-like devices.
if (classes & INPUT_DEVICE_CLASS_CURSOR) {
mappers.push_back(std::make_unique<CursorInputMapper>(*contextPtr));
}
// Touchscreens and touchpad devices.
if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
mappers.push_back(std::make_unique<MultiTouchInputMapper>(*contextPtr));
} else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
mappers.push_back(std::make_unique<SingleTouchInputMapper>(*contextPtr));
}
// Joystick-like devices.
if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
mappers.push_back(std::make_unique<JoystickInputMapper>(*contextPtr));
}
// External stylus-like devices.
if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
mappers.push_back(std::make_unique<ExternalStylusInputMapper>(*contextPtr));
}
// insert the context into the devices set
mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
}
回到InputDevice的process方法中旨袒,循環(huán)遍歷了所有的mapper并調(diào)用其process方法汁针,這里以KeyboardInputMapper來介紹key事件的處理過程。
void KeyboardInputMapper::process(const RawEvent* rawEvent) {
switch (rawEvent->type) {
// 如果是key事件
case EV_KEY: {
int32_t scanCode = rawEvent->code;
int32_t usageCode = mCurrentHidUsage;
mCurrentHidUsage = 0;
// 如果code為keyboard或者游戲面板對應(yīng)的key
if (isKeyboardOrGamepadKey(scanCode)) {
processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);
}
break;
}
// 省略若干行
}
}
processKey方法中砚尽,會根據(jù)event是否為down以及event的其他屬性構(gòu)建出NotifyKeyArgs施无,然后通過getListener方法獲取到InputListener,并通過其notifyKey方法將事件傳遞到InputDispatcher中必孤。
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode) {
int32_t keyCode;
int32_t keyMetaState;
uint32_t policyFlags;
// 省略若干行
// 根據(jù)event內(nèi)容構(gòu)建相應(yīng)的args
NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, getDisplayId(),
policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
// 獲取InputListener猾骡,并調(diào)用其notifyKey方法傳遞key事件
getListener()->notifyKey(&args);
}
notifyKey方法中首先會構(gòu)建出KeyEvent事件對象,并通過IMS傳遞到Java層的interceptKeyBeforeQueueing方法敷搪;然后根據(jù)args構(gòu)建KeyEnvtry兴想,并將其添加到mInboundQueue隊(duì)列中;最后調(diào)用wake方法喚醒looper赡勘。
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
// 省略若干行
// 根據(jù)args構(gòu)建KeyEvent
KeyEvent event;
event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC,
args->action, flags, keyCode, args->scanCode, metaState, repeatCount,
args->downTime, args->eventTime);
android::base::Timer t;
// 調(diào)用IMS的interceptKeyBeforeQueueing
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
// 省略若干行
// 構(gòu)建KeyEntry
KeyEntry* newEntry =
new KeyEntry(args->id, args->eventTime, args->deviceId, args->source,
args->displayId, policyFlags, args->action, flags, keyCode,
args->scanCode, metaState, repeatCount, args->downTime);
// 將KeyEntry添加到mInboundQueue里面
needWake = enqueueInboundEventLocked(newEntry);
// 省略若干行
// 如果需要wake則喚醒looper
if (needWake) {
mLooper->wake();
}
}
enqueueInboundEventLocked方法中會將EventEntry添加到mInboundQueue隊(duì)列中嫂便,然后如果需要wake就喚醒looper,然后就會觸發(fā)threadLoop闸与,從而調(diào)用dispatchOnce方法回到InputDispatcher中分發(fā)事件毙替。
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.empty();
// 將EventEntry添加到mInboundQueue隊(duì)列中
mInboundQueue.push_back(entry);
traceInboundQueueLengthLocked();
// 省略若干行
return needWake;
}
EventHub
通過前面InputReader的介紹曼振,我們發(fā)現(xiàn)輸入事件的源頭是通過調(diào)用EventHub的getEvents方法獲取的。那么蔚龙,EventHub是如何創(chuàng)建以及進(jìn)行事件的獲取的呢冰评?
EventHub的創(chuàng)建
我們回到InputReader的構(gòu)造方法,發(fā)現(xiàn)在InputReader構(gòu)造方法的初始化列表中木羹,會賦值全局變量mEventHub甲雅。
InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener)
: mContext(this),
// 初始化mEventHub
mEventHub(eventHub),
mPolicy(policy),
mGlobalMetaState(0),
mGeneration(1),
mNextInputDeviceId(END_RESERVED_ID),
mDisableVirtualKeysTimeout(LLONG_MIN),
mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
mQueuedListener = new QueuedInputListener(listener);
{ // acquire lock
AutoMutex _l(mLock);
refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
} // release lock
}
在初始化列表中對全局變量mEventHub進(jìn)行了初始化,通過前面介紹我們知道坑填,InputReader是在InputManager中構(gòu)建出來的抛人,那么我們繼續(xù)看。
InputManager::InputManager(
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = createInputDispatcher(dispatcherPolicy);
mClassifier = new InputClassifier(mDispatcher);
// 通過createInputReader創(chuàng)建出InputReader
mReader = createInputReader(readerPolicy, mClassifier);
}
sp<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) {
// 這里直接通過std::make_unique構(gòu)建出EventHub實(shí)例
return new InputReader(std::make_unique<EventHub>(), policy, listener);
}
在InputManager中通過createInputReader構(gòu)建出InputReader實(shí)例脐瑰,而在createInputReader方法中妖枚,會首先通過std::make_unique構(gòu)建出EventHub實(shí)例,繼續(xù)看EventHub的構(gòu)造函數(shù)苍在。
EventHub::EventHub(void)
: mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD),
mNextDeviceId(1),
mControllerNumbers(),
mOpeningDevices(nullptr),
mClosingDevices(nullptr),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false),
mNeedToScanDevices(true),
mPendingEventCount(0),
mPendingEventIndex(0),
mPendingINotify(false) {
ensureProcessCanBlockSuspend();
// 創(chuàng)建出epoll
mEpollFd = epoll_create1(EPOLL_CLOEXEC);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
// 創(chuàng)建inotify
mINotifyFd = inotify_init();
// 通過inotify來監(jiān)聽DEVICE_PATH路徑(/dev/input)下的文件改變(增加或者刪除)
mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
// 省略若干行
struct epoll_event eventItem = {};
eventItem.events = EPOLLIN | EPOLLWAKEUP;
eventItem.data.fd = mINotifyFd;
// 將mINotifyFd添加到epoll中
int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);
// 創(chuàng)建管道
int wakeFds[2];
result = pipe(wakeFds);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
// 設(shè)置管道讀取端非阻塞屬性
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
errno);
// 設(shè)置管道寫入端非阻塞屬性
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
errno);
eventItem.data.fd = mWakeReadPipeFd;
// 將讀取端管道描述符添加到epoll
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
}
在EventHub的構(gòu)造方法中绝页,我們可以看到:首先會創(chuàng)建出epoll,然后創(chuàng)建出inotify來監(jiān)聽/dev/input路徑下文件的增刪寂恬,并將inotify添加到epoll中進(jìn)行監(jiān)聽续誉,還會創(chuàng)建出一個管道,并將管道讀取端也添加到epoll中初肉。這樣當(dāng)有新的輸入設(shè)備接入或者刪除事酷鸦,就會觸發(fā)喚醒epoll進(jìn)行處理。
EventHub如何獲取輸入事件
在上面介紹的InputReader中牙咏,我們了解到loopOnce方法中通過調(diào)用EventHub的getEvents來獲取輸入事件臼隔。那么,我們繼續(xù)看getEvents方法妄壶,此方法比較長摔握,我們先看下大概的框架。
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
for (;;) {
// Reopen input devices if needed.
if (mNeedToReopenDevices) {
// 如果存在需要reopen的設(shè)備盯拱,則先關(guān)閉所有device
// 然后設(shè)置需要scan設(shè)備的標(biāo)識
}
// Report any devices that had last been added/removed.
while (mClosingDevices) {
// 如果存在需要關(guān)閉的設(shè)備盒发,則遍歷所有需要關(guān)閉的設(shè)備鏈表例嘱,
// 刪除對應(yīng)的device狡逢,并構(gòu)建event
}
// 需要掃描device,則調(diào)用scanDevicesLocked方法掃描
// 最后更新device列表
if (mNeedToScanDevices) {
}
//存在需要open的device拼卵,則更新mOpeningDevices鏈表
// 并構(gòu)建event
while (mOpeningDevices != nullptr) {
}
// 需要scanFinish事件奢浑,則構(gòu)建對應(yīng)event
if (mNeedToSendFinishedDeviceScan) {
}
// Grab the next input event.
// 遍歷需要處理的事件列表
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
if (eventItem.data.fd == mINotifyFd) {
// 如果是inotify事件,則修改對應(yīng)標(biāo)識腋腮,后面會掃描處理對于的變更
}
if (eventItem.data.fd == mWakeReadPipeFd) {
// 管道事件雀彼,則設(shè)置wake為true壤蚜,跳出循環(huán)繼續(xù)執(zhí)行
}
// This must be an input event
if (eventItem.events & EPOLLIN) {
// 真正的輸入事件
}
}
// 開始wait時釋放鎖
mLock.unlock(); // release lock before poll
// epoll等待喚醒
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
// 喚醒開始執(zhí)行時則加鎖
mLock.lock(); // reacquire lock after poll
}
// All done, return the number of events we read.
return event - buffer;
}
通過以上getEvents方法的大致流程,能夠看到首先會查看是否有需要reopen的device并進(jìn)行處理徊哑,接著處理需要close的device袜刷,然后是判斷是否需要掃描設(shè)備并進(jìn)行device掃描;接著處理新接入的設(shè)備莺丑,然后開始遍歷待處理的事件著蟹,并分別處理inotify、管道以及真正的輸入事件梢莽;過程中如果有event被處理則就會break掉for循環(huán)繼續(xù)進(jìn)行下一次處理萧豆,如果所有事件都已處理完就會走到下面的epoll_wait進(jìn)入wait狀態(tài)等待喚醒。
EventHub處理reopen設(shè)備
// Reopen input devices if needed.
if (mNeedToReopenDevices) {
// 設(shè)置mNeedToReopenDevices為false昏名,避免下次循環(huán)繼續(xù)處理
mNeedToReopenDevices = false;
ALOGI("Reopening all input devices due to a configuration change.");
// 關(guān)閉所有device
closeAllDevicesLocked();
// 標(biāo)識需要掃描device涮雷,后面循環(huán)會進(jìn)行掃描設(shè)備
mNeedToScanDevices = true;
// 跳出for循環(huán),繼續(xù)后續(xù)處理
break; // return to the caller before we actually rescan
}
處理reopen設(shè)備轻局,首先是重置reopen標(biāo)識洪鸭,然后調(diào)用closeAllDevicesLocked來關(guān)閉所有的device,接著標(biāo)識設(shè)備需要掃描仑扑,最后break退出此次循環(huán)卿嘲,繼續(xù)下一次循環(huán)處理。繼續(xù)看closeAllDevicesLocked方法:
void EventHub::closeAllDevicesLocked() {
mUnattachedVideoDevices.clear();
while (mDevices.size() > 0) {
// 循環(huán)遍歷所有device夫壁,并調(diào)用closeDeviceLocked來進(jìn)行關(guān)閉
closeDeviceLocked(mDevices.valueAt(mDevices.size() - 1));
}
}
void EventHub::closeDeviceLocked(Device* device) {
// 省略若干行
// 從epoll移除此device的監(jiān)聽
unregisterDeviceFromEpollLocked(device);
// 省略若干行
// 從device列表中移除此設(shè)備
mDevices.removeItem(device->id);
// 關(guān)閉device
device->close();
// Unlink for opening devices list if it is present.
Device* pred = nullptr;
bool found = false;
// 從已經(jīng)打開的device列表中查找對應(yīng)的device
for (Device* entry = mOpeningDevices; entry != nullptr;) {
if (entry == device) {
found = true;
break;
}
pred = entry;
entry = entry->next;
}
// 如果找到拾枣,則從打開的device列表中將其移除
if (found) {
// Unlink the device from the opening devices list then delete it.
// We don't need to tell the client that the device was closed because
// it does not even know it was opened in the first place.
ALOGI("Device %s was immediately closed after opening.", device->path.c_str());
if (pred) {
pred->next = device->next;
} else {
mOpeningDevices = device->next;
}
// 刪除對應(yīng)device
delete device;
} else {
// Link into closing devices list.
// The device will be deleted later after we have informed the client.
// 打開的device列表中沒找到,則將device添加到待移除的設(shè)備列表中
device->next = mClosingDevices;
mClosingDevices = device;
}
}
EventHub處理close設(shè)備
關(guān)閉device時首先從epoll中刪除對應(yīng)的監(jiān)聽并從device列表中將其移除盒让,然后在已經(jīng)打開的device列表中查找梅肤,如果找到則將其從open的device列表中移除,否則就將其添加到close的device列表中去邑茄,后面會處理close列表姨蝴。這里我們繼續(xù)看下epoll移除device的unregisterDeviceFromEpollLocked方法:
status_t EventHub::unregisterDeviceFromEpollLocked(Device* device) {
if (device->hasValidFd()) {
// 如果設(shè)備存在有效的fd,則調(diào)用unregisterFdFromEpoll將其從epoll中移除
status_t result = unregisterFdFromEpoll(device->fd);
}
return OK;
}
status_t EventHub::unregisterFdFromEpoll(int fd) {
// 調(diào)用epoll_ctl并傳遞EPOLL_CTL_DEL的flag將fd從epoll中移除
if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, nullptr)) {
ALOGW("Could not remove fd from epoll instance: %s", strerror(errno));
return -errno;
}
return OK;
}
接著我們繼續(xù)看getEvents中對帶關(guān)閉設(shè)備的處理過程:
// Report any devices that had last been added/removed.
// 遍歷所有需要關(guān)閉的device鏈表
while (mClosingDevices) {
Device* device = mClosingDevices;
ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str());
// 移動表頭到到下一個位置
mClosingDevices = device->next;
// 構(gòu)建設(shè)備移除的event
event->when = now;
event->deviceId = (device->id == mBuiltInKeyboardId)
? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID
: device->id;
event->type = DEVICE_REMOVED;
event += 1;
// 刪除對于device
delete device;
// 標(biāo)識需要構(gòu)建掃描完成的條件
mNeedToSendFinishedDeviceScan = true;
}
處理關(guān)閉的device肺缕,首先是遍歷整個需要關(guān)閉的device鏈表左医,并依次對每一個device,構(gòu)造設(shè)備移除的event同木,然后刪除對應(yīng)的device浮梢,最后標(biāo)識需要構(gòu)建掃描完成的事件條件,待后面添加掃描完成的event彤路。
EventHub掃描設(shè)備
前面如果有處理reopen設(shè)備秕硝,則會關(guān)閉所有設(shè)備,并設(shè)置需要掃描設(shè)備的標(biāo)識洲尊,然后這里會調(diào)用scanDevicesLocked方法來掃描device远豺。
if (mNeedToScanDevices) {
// 重置需要掃描的標(biāo)識奈偏,避免下一次繼續(xù)掃描設(shè)備
mNeedToScanDevices = false;
// 開始掃描設(shè)備
scanDevicesLocked();
// 標(biāo)識后面需要有掃描完成的event
mNeedToSendFinishedDeviceScan = true;
}
掃描設(shè)備會調(diào)用scanDevicesLocked方法進(jìn)行掃描處理,我們繼續(xù)看:
void EventHub::scanDevicesLocked() {
// 繼續(xù)調(diào)用scanDirLocked來掃描設(shè)備躯护,這里傳入的路徑為/dev/input
status_t result = scanDirLocked(DEVICE_PATH);
if (result < 0) {
ALOGE("scan dir failed for %s", DEVICE_PATH);
}
// 省略若干行
// 如果存在虛擬的鍵盤惊来,則在這里創(chuàng)建虛擬鍵盤
if (mDevices.indexOfKey(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) < 0) {
createVirtualKeyboardLocked();
}
}
首先調(diào)用scanDirLocked掃描/dev/input目錄來索引可用的device,然后判斷如果存在虛擬的鍵盤棺滞,則調(diào)用createVirtualKeyboardLocked方法來創(chuàng)建虛擬鍵盤設(shè)備唁盏。
status_t EventHub::scanDirLocked(const char* dirname) {
char devname[PATH_MAX];
char* filename;
DIR* dir;
struct dirent* de;
// 打開/dev/input目錄
dir = opendir(dirname);
if (dir == nullptr) return -1;
strcpy(devname, dirname);
filename = devname + strlen(devname);
*filename++ = '/';
// 遍歷/dev/input目錄
while ((de = readdir(dir))) {
if (de->d_name[0] == '.' &&
(de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0')))
continue;
strcpy(filename, de->d_name);
// 如果文件名有效,則打開對于device
openDeviceLocked(devname);
}
// 關(guān)閉目錄
closedir(dir);
return 0;
}
掃描device主要是掃描/dev/input目錄检眯,遍歷每一個設(shè)備文件并調(diào)用openDeviceLocked方法來打開對應(yīng)的device厘擂,最后關(guān)閉目錄。
status_t EventHub::openDeviceLocked(const char* devicePath) {
char buffer[80];
ALOGV("Opening device: %s", devicePath);
// 打開device文件
int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK);
// 省略若干行
// 然后依次獲取設(shè)備的名稱锰瘸、驅(qū)動版本刽严、設(shè)備的廠商等信息、物理路徑避凝、唯一的id等信息
// 接著判斷是鍵盤或者游戲面板舞萄、鼠標(biāo)等設(shè)備類型進(jìn)行特殊處理
// 最后將設(shè)備添加到epoll中進(jìn)行監(jiān)聽
if (registerDeviceForEpollLocked(device) != OK) {
// 添加失敗則刪除設(shè)備并退出
delete device;
return -1;
}
// 省略若干行
// 將設(shè)備添加到device列表
addDeviceLocked(device);
return OK;
}
openDeviceLocked方法中,首先通過open方法打開對應(yīng)的設(shè)備文件管削,然后會獲取設(shè)備的各種信息并進(jìn)行相應(yīng)的處理倒脓,接著通過registerDeviceForEpollLocked方法將device添加到epoll中去,最后再通過addDeviceLocked方法將device添加到設(shè)備列表當(dāng)中去含思。
status_t EventHub::registerDeviceForEpollLocked(Device* device) {
// 省略若干行
// 調(diào)用registerFdForEpoll將設(shè)備描述符添加到epoll中去
status_t result = registerFdForEpoll(device->fd);
// 省略若干行
return result;
}
status_t EventHub::registerFdForEpoll(int fd) {
// TODO(b/121395353) - consider adding EPOLLRDHUP
struct epoll_event eventItem = {};
// 設(shè)置event類型為EPOLLIN 和 EPOLLWAKEUP
eventItem.events = EPOLLIN | EPOLLWAKEUP;
eventItem.data.fd = fd;
// 通過epoll_ctl調(diào)用并傳入EPOLL_CTL_ADD的flag添加對應(yīng)fd到epoll中
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
ALOGE("Could not add fd to epoll instance: %s", strerror(errno));
return -errno;
}
return OK;
}
void EventHub::addDeviceLocked(Device* device) {
// 將設(shè)備添加到device列表中
mDevices.add(device->id, device);
// 將device添加到open的設(shè)備鏈表中
device->next = mOpeningDevices;
mOpeningDevices = device;
}
我們能夠看到在registerFdForEpoll方法中崎弃,設(shè)備的fd被添加為EPOLLIN和EPOLLWAKEUP類型的,所以這兩種類型的事件到來時就可以喚醒epoll工作含潘,然后在addDeviceLocked方法中會將設(shè)備添加到device列表和open的device鏈表中去饲做。
EventHub處理open設(shè)備
在getEvents方法中,會遍歷整個open的設(shè)備鏈表遏弱,迭代每個設(shè)備盆均,然后構(gòu)建設(shè)備添加的event,最后標(biāo)識掃描完成的變量漱逸;如果在處理過程中泪姨,buffer已經(jīng)滿了,則會break掉饰抒,未處理的設(shè)備會在下一次迭代時繼續(xù)處理肮砾。
// 迭代每一個open的device
while (mOpeningDevices != nullptr) {
Device* device = mOpeningDevices;
ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str());
// 修改頭指針
mOpeningDevices = device->next;
// 構(gòu)建DEVICE_ADDED的event
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
event->type = DEVICE_ADDED;
event += 1;
// 設(shè)置scan完成標(biāo)識
mNeedToSendFinishedDeviceScan = true;
// buffer滿了,則跳出
if (--capacity == 0) {
break;
}
}
EventHub處理event
// 迭代處理所有event
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
if (eventItem.data.fd == mINotifyFd) {
// event為device變更循集,則標(biāo)識mPendingINotify唇敞,后面會進(jìn)行處理
if (eventItem.events & EPOLLIN) {
mPendingINotify = true;
} else {
ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
}
continue;
}
// event是wake管道消息
if (eventItem.data.fd == mWakeReadPipeFd) {
if (eventItem.events & EPOLLIN) {
ALOGV("awoken after wake()");
// 標(biāo)識被喚醒蔗草,后面epoll就不會進(jìn)入wait狀態(tài)
awoken = true;
char buffer[16];
ssize_t nRead;
do {// 從管道中讀取出消息內(nèi)容
nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
} while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
} else {
ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
eventItem.events);
}
continue;
}
// 通過event中的設(shè)備描述符獲取對應(yīng)device
Device* device = getDeviceByFdLocked(eventItem.data.fd);
// 省略若干行
// This must be an input event
if (eventItem.events & EPOLLIN) {
// event是input事件
// 從device中讀取出事件內(nèi)容
int32_t readSize =
read(device->fd, readBuffer, sizeof(struct input_event) * capacity);
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
// Device was removed before INotify noticed.
ALOGW("could not get event, removed? (fd: %d size: %" PRId32
" bufferSize: %zu capacity: %zu errno: %d)\n",
device->fd, readSize, bufferSize, capacity, errno);
// 出錯咒彤,則關(guān)閉對應(yīng)device疆柔,并標(biāo)識設(shè)備發(fā)生變更
deviceChanged = true;
closeDeviceLocked(device);
}
// 省略若干行
else {
// 獲取deviceId
int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
// 遍歷讀取到的所有event,并構(gòu)建出RawEvent
size_t count = size_t(readSize) / sizeof(struct input_event);
for (size_t i = 0; i < count; i++) {
struct input_event& iev = readBuffer[i];
event->when = processEventTimestamp(iev);
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;
capacity -= 1;
}
// 如果buffer滿了镶柱,則break掉
if (capacity == 0) {
// The result buffer is full. Reset the pending event index
// so we will try to read the device again on the next iteration.
mPendingEventIndex -= 1;
break;
}
}
}
}
這里處理event時旷档,首先處理設(shè)備的變更事件,然后會處理wake管道事件歇拆,最后才會處理真正的input事件鞋屈;處理input事件時會遍歷每一個獲取到的event,并構(gòu)建出對應(yīng)的RawEvent故觅。
EventHub處理inotify事件
// readNotify() will modify the list of devices so this must be done after
// processing all other events to ensure that we read all remaining events
// before closing the devices.
if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
// 標(biāo)識已經(jīng)處理過
mPendingINotify = false;
// 處理inotify事件
readNotifyLocked();
deviceChanged = true;
}
status_t EventHub::readNotifyLocked() {
// 省略若干行
// 從mINotifyFd讀取事件內(nèi)容
res = read(mINotifyFd, event_buf, sizeof(event_buf));
// 省略若干行
// 遍歷每一個inotify_event
while (res >= (int)sizeof(*event)) {
event = (struct inotify_event*)(event_buf + event_pos);
if (event->len) {
if (event->wd == mInputWd) {
// 是input類型的變更
// 獲取設(shè)備對應(yīng)的文件路徑
std::string filename = StringPrintf("%s/%s", DEVICE_PATH, event->name);
if (event->mask & IN_CREATE) {
// 是設(shè)備連入事件厂庇,則調(diào)用openDeviceLocked來添加設(shè)備
// 上面已經(jīng)介紹過,這里就不展開了
openDeviceLocked(filename.c_str());
} else {
// 否則是設(shè)備斷開事件输吏,則調(diào)用closeDeviceByPathLocked關(guān)閉設(shè)備
ALOGI("Removing device '%s' due to inotify event\n", filename.c_str());
closeDeviceByPathLocked(filename.c_str());
}
}
// 省略若干行
}
event_size = sizeof(*event) + event->len;
res -= event_size;
event_pos += event_size;
}
return 0;
}
這里首先會從mINotifyFd讀取對應(yīng)的inotify事件权旷,然后遍歷每一個event,判斷是設(shè)備接入還是斷開并分別進(jìn)行設(shè)備添加和移除的處理拄氯。
void EventHub::closeDeviceByPathLocked(const char* devicePath) {
// 從device列表中根據(jù)設(shè)備路徑查找device
Device* device = getDeviceByPathLocked(devicePath);
if (device) {
// 找到則調(diào)用closeDeviceLocked來關(guān)閉device
// 上面reopen時已經(jīng)介紹過,這里不再展開
closeDeviceLocked(device);
return;
}
ALOGV("Remove device: %s not found, device may already have been removed.", devicePath);
}
EventHub::Device* EventHub::getDeviceByPathLocked(const char* devicePath) const {
// 遍歷整個device列表
for (size_t i = 0; i < mDevices.size(); i++) {
Device* device = mDevices.valueAt(i);
// 根據(jù)設(shè)備路徑配備device
if (device->path == devicePath) {
return device;
}
}
return nullptr;
}
這里關(guān)閉設(shè)備它浅,首先是通過設(shè)備的路徑從device列表中查找對應(yīng)的device译柏,如果找到了,則調(diào)用closeDeviceLocked去處理設(shè)備的關(guān)閉姐霍。
小結(jié)
通過以上介紹香追,我們可以了解到EventHub的創(chuàng)建過程以及其采用epoll加inotify的方式來實(shí)現(xiàn)input設(shè)備以及input事件的監(jiān)聽轧拄;另外,在getEvents方法中,包含了整個設(shè)備的添加腻暮、刪除以及input事件的處理,而這些事件的處理正是基于EventHub創(chuàng)建時采用的epoll加inotify機(jī)制實(shí)現(xiàn)的盛龄。