您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“Android事件分發(fā)中事件是怎么來的”,內(nèi)容詳細,步驟清晰,細節(jié)處理妥當(dāng),希望這篇“Android事件分發(fā)中事件是怎么來的”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識吧。
注冊事件回調(diào)是通過mWindowSession.addToDisplayAsUser來實現(xiàn)的,這是一個Binder調(diào)用實際調(diào)用的是frameworks/base/services/core/java/com/android/server/wm/Session.java這個類。
//frameworks/base/services/core/java/com/android/server/wm/Session.java @Override public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls, Rect outAttachedFrame, float[] outSizeCompatScale) { return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId, requestedVisibilities, outInputChannel, outInsetsState, outActiveControls, outAttachedFrame, outSizeCompatScale); }
這里的mService就是WMS.調(diào)用的就是WMS的addWindow,addWindow方法很長,其中與事件相關(guān)的就兩行
//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java ...... final WindowState win = new WindowState(this, session, client, token, parentWindow,appOp[0], attrs, viewVisibility, session.mUid, userId,session.mCanAddInternalSystemWindow); win.openInputChannel(outInputChannel);
//frameworks/base/services/core/java/com/android/server/wm/WindowState.java void openInputChannel(InputChannel outInputChannel) { if (mInputChannel != null) { throw new IllegalStateException("Window already has an input channel."); } String name = getName(); mInputChannel = mWmService.mInputManager.createInputChannel(name); mInputChannelToken = mInputChannel.getToken(); mInputWindowHandle.setToken(mInputChannelToken); mWmService.mInputToWindowMap.put(mInputChannelToken, this); if (outInputChannel != null) { //將native創(chuàng)建的InputChannel復(fù)制給參數(shù)outInputChannel mInputChannel.copyTo(outInputChannel); } else { // If the window died visible, we setup a fake input channel, so that taps // can still detected by input monitor channel, and we can relaunch the app. // Create fake event receiver that simply reports all events as handled. mDeadWindowEventReceiver = new DeadWindowEventReceiver(mInputChannel); } }
調(diào)用了WMS中的成員mInputManager來注冊了InputChannel,mInputManager是一個InputManagerService。
這下就對了,事件從InputManagerService中來很合理。
public InputChannel createInputChannel(String name) { return mNative.createInputChannel(name); }
這個對象是在InputManagerService創(chuàng)建的時候初始化的
public InputManagerService(Context context) { this(new Injector(context, DisplayThread.get().getLooper())); } @VisibleForTesting InputManagerService(Injector injector) { // The static association map is accessed by both java and native code, so it must be // initialized before initializing the native service. mStaticAssociations = loadStaticInputPortAssociations(); mContext = injector.getContext(); mHandler = new InputManagerHandler(injector.getLooper()); mNative = injector.getNativeService(this); .... } //frameworks/base/services/core/java/com/android/server/input/NativeInputManagerService.java NativeInputManagerService getNativeService(InputManagerService service) { return new NativeInputManagerService.NativeImpl(service, mContext, mLooper.getQueue()); }
最終返回的是一個NativeImpl實例。字面意思就知道了,這是一個Native方法的實現(xiàn),createInputChannel來到了native層。
//frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp base::Result<std::unique_ptr<InputChannel>> NativeInputManager::createInputChannel( const std::string& name) { ATRACE_CALL(); return mInputManager->getDispatcher().createInputChannel(name); }
調(diào)用了mInputManager的getDispatcher函數(shù)看名字就知道應(yīng)該有個變量mDispatcher,查看mInputManager是怎么創(chuàng)建的可以發(fā)現(xiàn)是在NativeInputManager創(chuàng)建的時候初始化的
InputManager* im = new InputManager(this, this); mInputManager = im;
InputManager::InputManager( const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { mDispatcher = createInputDispatcher(dispatcherPolicy); mClassifier = std::make_unique<InputClassifier>(*mDispatcher); mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mClassifier); mReader = createInputReader(readerPolicy, *mBlocker); }
這里就出現(xiàn)了重要的兩個類InputDispatcher和InputReader,createInputChanne方法l最終調(diào)用到了InputDispatcher中的createInputChannel。
//frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::string& name) { if (DEBUG_CHANNEL_CREATION) { ALOGD("channel '%s' ~ createInputChannel", name.c_str()); } std::unique_ptr<InputChannel> serverChannel; std::unique_ptr<InputChannel> clientChannel; //調(diào)用創(chuàng)建了一個serverChannel和一個clientChannel status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel); if (result) { return base::Error(result) << "Failed to open input channel pair with name " << name; } { // acquire lock std::scoped_lock _l(mLock); const sp<IBinder>& token = serverChannel->getConnectionToken(); int fd = serverChannel->getFd(); sp<Connection> connection = new Connection(std::move(serverChannel), false /*monitor*/, mIdGenerator); if (mConnectionsByToken.find(token) != mConnectionsByToken.end()) { ALOGE("Created a new connection, but the token %p is already known", token.get()); } mConnectionsByToken.emplace(token, connection); std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback, this, std::placeholders::_1, token); mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr); } // release lock // Wake the looper because some connections have changed. mLooper->wake(); return clientChannel; }
首先使用openInputChannelPair創(chuàng)建了2個InputChannel,一個clientChannel和一個serverChannel
將serverChannel封裝成connection,并放入成員變量mConnectionsByToken中管理,這樣在事件到來的時候就可以使用connection向客戶端發(fā)送事件了
利用Looper持續(xù)監(jiān)聽serverChannel,事件處理的回調(diào)消息會就到InputDispatcher::handleReceiveCallback回調(diào),最后把clientChannel返回給客戶端,也就是最初在WMS中得到的InputChannel。
//frameworks/native/libs/input/InputTransport.cpp status_t InputChannel::openInputChannelPair(const std::string& name, std::unique_ptr<InputChannel>& outServerChannel, std::unique_ptr<InputChannel>& outClientChannel) { int sockets[2]; //真正創(chuàng)建了socket if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) { status_t result = -errno; ALOGE("channel '%s' ~ Could not create socket pair. errno=%s(%d)", name.c_str(), strerror(errno), errno); outServerChannel.reset(); outClientChannel.reset(); return result; } //設(shè)置了socket傳輸?shù)拇笮?2k 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]); outServerChannel = InputChannel::create(serverChannelName, std::move(serverFd), token); std::string clientChannelName = name + " (client)"; android::base::unique_fd clientFd(sockets[1]); outClientChannel = InputChannel::create(clientChannelName, std::move(clientFd), token); return OK; }
熟悉Linux的話就知道socketpair創(chuàng)建了一對雙向的socket,往socket[0]中寫能從socket[1]讀,反向也是一樣,分別創(chuàng)建了outServerChannel和outClientChannel,兩個InputChannel有著同一個BBinder作為token。
const sp<IBinder>& token = serverChannel->getConnectionToken(); int fd = serverChannel->getFd();//拿到socket fd sp<Connection> connection = new Connection(std::move(serverChannel), false /*monitor*/, mIdGenerator); if (mConnectionsByToken.find(token) != mConnectionsByToken.end()) { ALOGE("Created a new connection, but the token %p is already known", token.get()); } mConnectionsByToken.emplace(token, connection); std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback, this, std::placeholders::_1, token); mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr);
這里將創(chuàng)建的serverChannel封裝成了connection,同時用token作為key,存到了mConnectionsByToken中,這樣就可以利用token來快速找到serverChannel封裝的connection。最后監(jiān)聽serverChannel的fd,有事件時回調(diào)給InputDispatcher::handleReceiveCallback方法的最后把創(chuàng)建的clientChannel返回給了客戶端,就是開頭的WMS中。這樣在WMS就也能通過clientChannel來獲取事件了。
讀到這里,這篇“Android事件分發(fā)中事件是怎么來的”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領(lǐng)會,如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。