总述
对于IMS来说,其主要就这几个内容
- 一个socketpair:进行跨进程通讯
- 两个线程:InputReader、InputDispatcher
- 三个队列:IQ,OQ,WQ
- 一个主要方法:findTouchedWindowTargetsLocked()用于查找对应窗口
1.一个socketpair:从InputChannel研究socketpair中两个fd的传递
在ViewRootImpl中的setView方法中有个inputChannel的变量,这个是事件传递的主要类,我们分析下其进程间通讯问题; frameworks/base/core/java/android/view/ViewRootImpl.java
inputChannel = new InputChannel();
res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId,
mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,
mTempControls);
这里inputchannel通过Session的跨进程通讯 ,将inputChannel传递到WMS中,也就是systemserver进程
// 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) {
return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId,
requestedVisibilities, outInputChannel, outInsetsState, outActiveControls);
}
这里跨进程通讯有一个点需要关注下;Session的aidl文件看下
//frameworks/base/core/java/android/view/IWindowSession.aidl
interface IWindowSession {
int addToDisplay(IWindow window, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, in InsetsVisibilities requestedVisibilities,
out InputChannel outInputChannel, out InsetsState insetsState,
out InsetsSourceControl[] activeControls);
int addToDisplayAsUser(IWindow window, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, in int userId,
in InsetsVisibilities requestedVisibilities, out InputChannel outInputChannel,
out InsetsState insetsState, out InsetsSourceControl[] activeControls);
}
InputChannel前面都有个out字段,这个是aidl文件的一个关键字,这个关键字的意思就是该数据只能通过服务端传到客户端;
一般而言就是客户端定义一个空数据,然后由服务端填充后,返回给客户端;也就是说outInputChannel这个字段是由systemserver中填充了该数据,app端来接收该数据
//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
int displayId, int requestUserId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
final boolean openInputChannels = (outInputChannel != null && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) {
//调用windowstate的openInputChannel
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();
//这里调用了IMP的createInputChannel,并返回了一个mInputChannel
mInputChannel = mWmService.mInputManager.createInputChannel(name);
mInputChannelToken = mInputChannel.getToken();
mInputWindowHandle.setToken(mInputChannelToken);
mWmService.mInputToWindowMap.put(mInputChannelToken, this);
if (outInputChannel != null) {
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);
}
}
//frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public InputChannel createInputChannel(String name) {
return mNative.createInputChannel(name);
}
//frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
base::Result<std::unique_ptr<InputChannel>> NativeInputManager::createInputChannel(
const std::string& name) {
return mInputManager->getDispatcher().createInputChannel(name);
}
上面是调用到了native层中的NativeInputManager::createInputChannel;紧接着就调用到了InputDispatcher中的createInputChannel; 注意这里是在systemserver进程,只是在native层中,只有一次的跨进程通讯,就是通过Session,从app进程到了systemserver进程
我们接着看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;
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);
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;
}
//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];
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;
}
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;
}
`
在InputTransport.cpp中是关键的逻辑,这里面有个socketpair;
socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)创建了一个数组大小为2 的fd数组;
并将两个fd【serverFd、clientFd】分别创建了两个InputChannel【outServerChannel、outClientChannel】 这样在InputDispatcher.cpp的createInputChannel中就获取到了两个InputChannel 【outServerChannel、outClientChannel】
`
1:对于服务端的Fd int fd = serverChannel->getFd();服务端的fd通过 mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr); 跨线程传递给了InputDispatcher线程,并唤醒InputDispatcher线程
2:客户端的fd则直接通过clientChannel传递给WindowState中openInputChannel方法中的字段mInputChannel;然后mInputChannel.copyto(outInputChannel); 将数据填充;这样app端就接受到该数据,app就可以接收systemserver中InputDispatcher线程传递过来的事件信息;进而达到事件传递的目的
2. 两个线程:InputReader、InputDispatcher
3. 三个队列:IQ,OQ,WQ
4. 一个主要方法:findTouchedWindowTargetsLocked()用于查找对应窗口
- 在findTouchedWindowTargetsLocked方法中主要是通过MotionEntry& entry获取的触摸位置x,y,找到对应的窗口
- 这个方法newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState, isStylus, isDown /addOutsideTargets/);
std::vector<sp<WindowInfoHandle>> InputDispatcher::findTouchedSpyWindowsAtLocked(
int32_t displayId, int32_t x, int32_t y, bool isStylus) const {
// Traverse windows from front to back and gather the touched spy windows.
std::vector<sp<WindowInfoHandle>> spyWindows;
const auto& windowHandles = getWindowHandlesLocked(displayId);
for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
const WindowInfo& info = *windowHandle->getInfo();
if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus)) {
continue;
}
if (!info.isSpy()) {
// The first touched non-spy window was found, so return the spy windows touched so far.
return spyWindows;
}
spyWindows.push_back(windowHandle);
}
return spyWindows;
}
const std::vector<sp<WindowInfoHandle>>& InputDispatcher::getWindowHandlesLocked(
int32_t displayId) const {
static const std::vector<sp<WindowInfoHandle>> EMPTY_WINDOW_HANDLES;
auto it = mWindowHandlesByDisplay.find(displayId);
return it != mWindowHandlesByDisplay.end() ? it->second : EMPTY_WINDOW_HANDLES;
}
可以看出窗口是从mWindowHandlesByDisplay获取来的,mWindowHandlesByDisplay又是由谁添加进来的窗口数据呢,先说答案,是从surfaceflinger中传递过来的;
//frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime)
FTL_FAKE_GUARD(kMainThreadContext) {
...
updateInputFlinger();
...
}
void SurfaceFlinger::updateInputFlinger() {
std::vector<WindowInfo> windowInfos;
std::vector<DisplayInfo> displayInfos;
bool updateWindowInfo = false;
if (mVisibleRegionsDirty || mInputInfoChanged) {
mInputInfoChanged = false;
updateWindowInfo = true;
//先构建windowInfos
buildWindowInfos(windowInfos, displayInfos);
}
if (updateWindowInfo) {
//在调用windowInfosChanged,这里是有跨进程通讯的
mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
inputWindowCommands.syncInputWindows);
}
}
//frameworks/native/services/surfaceflinger/WindowInfosListenerInvoker.cpp
void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos,
const std::vector<DisplayInfo>& displayInfos,
bool shouldSync) {
ftl::SmallVector<const sp<IWindowInfosListener>, kStaticCapacity> windowInfosListeners;
{
std::scoped_lock lock(mListenersMutex);
for (const auto& [_, listener] : mWindowInfosListeners) {
windowInfosListeners.push_back(listener);
}
}
mCallbacksPending = windowInfosListeners.size();
//调用回InputDispatcher的onWindowInfosChanged回调:
//详细解释:由于listener是客户端(systemserver的InputDispatcher),surfaceflinger是服务端;通过客户端向服务端注册回调接口,实现将服务端的数据传递到客户端
for (const auto& listener : windowInfosListeners) {
listener->onWindowInfosChanged(windowInfos, displayInfos,shouldSync ? mWindowInfosReportedListener : nullptr);
}
}
//frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy,
std::chrono::nanoseconds staleEventTimeout)
...
mLatencyTracker(&mLatencyAggregator) {
//注册监听事件
mWindowInfoListener = new DispatcherWindowListener(*this);
SurfaceComposerClient::getDefault()->addWindowInfosListener(mWindowInfoListener);
}
void InputDispatcher::DispatcherWindowListener::onWindowInfosChanged(
const std::vector<gui::WindowInfo>& windowInfos,
const std::vector<DisplayInfo>& displayInfos) {
mDispatcher.onWindowInfosChanged(windowInfos, displayInfos);
}
//frameworks/native/libs/gui/SurfaceComposerClient.cpp
status_t SurfaceComposerClient::addWindowInfosListener(
const sp<WindowInfosListener>& windowInfosListener,
std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>>* outInitialInfo) {
//跨进程到surfaceflinger中注册监听事件
return WindowInfosListenerReporter::getInstance()->addWindowInfosListener(windowInfosListener, ComposerService::getComposerService(),outInitialInfo);
}
- 在InputDispatcher中注册了一个WindowInfosListener事件
- WindowInfosListenerReporter会通过跨进程通讯(Binder)传递到surfaceflinger端
- 在surfaceflinger的commit中,将调用updateInputFlinger刷新窗口层级
- 接着调用WindowInfosListenerReporter的onWindowInfosChanged将窗口层级传递出去
- 传递到InputDispatcher中DispatcherWindowListener的onWindowInfosChanged方法中;
提问:在WindowInfosListenerInvoker中调用了onWindowInfosChanged是怎么将数据从服务端【surfaceflinger】传送到InputDispatcher的呢
详细解释:由于listener是客户端(systemserver的InputDispatcher),surfaceflinger是服务端;通过客户端向服务端注册回调接口,实现将服务端的数据传递到客户端
上述就已经将窗口信息传递到InputDispatcher线程中了
void InputDispatcher::onWindowInfosChanged(const std::vector<WindowInfo>& windowInfos,
const std::vector<DisplayInfo>& displayInfos) {
for (const auto& [displayId, handles] : handlesPerDisplay) {
setInputWindowsLocked(handles, displayId);
}
// Wake up poll loop since it may need to make new input dispatching choices.
mLooper->wake();
}
void InputDispatcher::setInputWindowsLocked(
const std::vector<sp<WindowInfoHandle>>& windowInfoHandles, int32_t displayId) {
updateWindowHandlesForDisplayLocked(windowInfoHandles, displayId);
}
void InputDispatcher::updateWindowHandlesForDisplayLocked(
const std::vector<sp<WindowInfoHandle>>& windowInfoHandles, int32_t displayId) {
//更新窗口信息
mWindowHandlesByDisplay[displayId] = newHandles;
}
这里将窗口信息更新到mWindowHandlesByDisplay中,在getWindowHandlesLocked中就可以获取窗口信息,并根据x,y获取当前的focus窗口