IMS相关

36 阅读6分钟

总述

对于IMS来说,其主要就这几个内容

  1. 一个socketpair:进行跨进程通讯
  2. 两个线程:InputReader、InputDispatcher
  3. 三个队列:IQ,OQ,WQ
  4. 一个主要方法: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窗口