Android事件分發(fā)的事件由來原理分析
Andriod事件分發(fā)的事件從何而來
上一篇最后留下了一個疑問,WMS的事件是哪里來的?
注冊事件回調是通過mWindowSession.addToDisplayAsUser來實現(xiàn)的,這是一個Binder調用實際調用的是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.調用的就是WMS的addWindow,addWindow方法很長,其中與事件相關的就兩行
//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復制給參數(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);
}
}
調用WMS中的成員mInputManager
調用了WMS中的成員mInputManager來注冊了InputChannel,mInputManager是一個InputManagerService。
這下就對了,事件從InputManagerService中來很合理。
public InputChannel createInputChannel(String name) {
return mNative.createInputChannel(name);
}
調用的mNative的方法
這個對象是在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);
}
調用了mInputManager的getDispatcher函數(shù)看名字就知道應該有個變量mDispatcher,查看mInputManager是怎么創(chuàng)建的可以發(fā)現(xiàn)是在NativeInputManager創(chuàng)建的時候初始化的
InputManager* im = new InputManager(this, this);
mInputManager = im;
看看InputManager怎么初始化
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最終調用到了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;
//調用創(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;
}
createInputChannel干了3件事
- 首先使用openInputChannelPair創(chuàng)建了2個InputChannel,一個clientChannel和一個serverChannel
- 將serverChannel封裝成connection,并放入成員變量mConnectionsByToken中管理,這樣在事件到來的時候就可以使用connection向客戶端發(fā)送事件了
- 利用Looper持續(xù)監(jiān)聽serverChannel,事件處理的回調消息會就到InputDispatcher::handleReceiveCallback回調,最后把clientChannel返回給客戶端,也就是最初在WMS中得到的InputChannel。
首先看下openInputChannelPair
//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;
}
//設置了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。
回到createInputChannel中
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,有事件時回調給InputDispatcher::handleReceiveCallback方法的最后把創(chuàng)建的clientChannel返回給了客戶端,就是開頭的WMS中。這樣在WMS就也能通過clientChannel來獲取事件了。
以上就是Android事件分發(fā)的事件由來原理分析的詳細內容,更多關于Android事件分發(fā)事件由來的資料請關注腳本之家其它相關文章!
相關文章
Android使用GestureOverlayView控件實現(xiàn)手勢識別
這篇文章主要為大家詳細介紹了Android使用GestureOverlayView控件實現(xiàn)手勢識別,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-04-04
Android Gradle Build Error:Some file crunching failed, see l
這篇文章主要介紹了Android Gradle Build Error:Some file crunching failed, see logs for details的快速解決方法的相關資料,需要的朋友可以參考下2016-10-10
詳解Android Studio安裝ButterKnife插件(手動安裝)
這篇文章主要介紹了詳解AndroidStudio安裝ButterKnife插件(手動安裝),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08
Android自定義View實現(xiàn)音頻播放圓形進度條
這篇文章主要為大家詳細介紹了Android自定義View實現(xiàn)音頻播放圓形進度條,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-06-06
android項目從Eclipse遷移到Android studio中常見問題解決方法
android項目從Eclipse遷移到Android studio中經常會遇到一些問題,本文提供了Android studio使用中常見問題解決方法2018-03-03

