Android Input系统之 InputMonitor 更新流程

分析源码为 android 12

一、InputMonitor层面分析

在 WMS 添加,更新和删除Window 的时候都会调用 InputMonitor 的 updateInputWindowsLw 更新 window 信息。如下是删除window 时候的调用函数:

WMS.java

void removeWindowToken(IBinder binder, boolean removeWindows, boolean animateExit,
            int displayId) {
        synchronized (mGlobalLock) {
            final DisplayContent dc = mRoot.getDisplayContent(displayId);

            if (dc == null) {
                ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
                        + " for non-exiting displayId=%d", binder, displayId);
                return;
            }
            final WindowToken token = dc.removeWindowToken(binder, animateExit);
            if (token == null) {
                ProtoLog.w(WM_ERROR,
                        "removeWindowToken: Attempted to remove non-existing token: %s",
                        binder);
                return;
            }

            if (removeWindows) {
                token.removeAllWindowsIfPossible();
            }
            // 调用 updateInputWindowsLw
            dc.getInputMonitor().updateInputWindowsLw(true /* force */);
        }
    }

updateInputWindowsLw 属于经常被外部调用的方法,它会最后触发到UpdateInputWindows 的 run 方法执行。

private class UpdateInputWindows implements Runnable {
        @Override
        public void run() {
            synchronized (mService.mGlobalLock) {
                mUpdateInputWindowsPending = false;
                mUpdateInputWindowsNeeded = false;

                if (mDisplayRemoved) {
                    return;
                }

                // Populate the input window list with information about all of the windows that
                // could potentially receive input.
                // As an optimization, we could try to prune the list of windows but this turns
                // out to be difficult because only the native code knows for sure which window
                // currently has touch focus.

                // If there's a drag in flight, provide a pseudo-window to catch drag input
                final boolean inDrag = mService.mDragDropController.dragDropActiveLocked();

                // Add all windows on the default display.
                mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);
            }
        }
    }

最后会调用到mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);这个关键方法:

private final class UpdateInputForAllWindowsConsumer implements Consumer<WindowState> {
        InputConsumerImpl mPipInputConsumer;
        InputConsumerImpl mWallpaperInputConsumer;
        InputConsumerImpl mRecentsAnimationInputConsumer;

        private boolean mAddPipInputConsumerHandle;
        private boolean mAddWallpaperInputConsumerHandle;
        private boolean mAddRecentsAnimationInputConsumerHandle;

        boolean mInDrag;

        private void updateInputWindows(boolean inDrag) {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");

            ......
            mDisplayContent.forAllWindows(this, true /* traverseTopToBottom */);
            updateInputFocusRequest(mRecentsAnimationInputConsumer);

            ......
            }

            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }

......
}

这里有调用了 mDisplayContent.forAllWindows方法来遍历每一个windowstate 执行自己的 accept 方法:

public void accept(WindowState w) {
            ......
// 这里会对每个WindowState转换成inputWindowHandle信息,
// 不过要求得有surface才可以,意味处于NO_SURFACE是不会进入
            if (w.mWinAnimator.hasSurface()) {
                populateInputWindowHandle(inputWindowHandle, w);
                setInputWindowInfoIfNeeded(mInputTransaction,
                        w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
            }
        }

把 WindowState 转换成 inputWindowHandle 后接下来会把这个inputWindowHandle 信息设置给 mSurfaceControl

static void setInputWindowInfoIfNeeded(SurfaceControl.Transaction t, SurfaceControl sc,
            InputWindowHandleWrapper inputWindowHandle) {
        if (DEBUG_INPUT) {
            Slog.d(TAG_WM, "Update InputWindowHandle: " + inputWindowHandle);
        }
        if (inputWindowHandle.isChanged()) {
            inputWindowHandle.applyChangesToSurface(t, sc);
        }
    }

接下来来到 SurfaceControl.java 的

public Transaction setInputWindowInfo(SurfaceControl sc, InputWindowHandle handle) {
            checkPreconditions(sc);
            nativeSetInputWindowInfo(mNativeObject, sc.mNativeObject, handle);
            return this;
        }

这里一看就是调用是 nativeSetInputWindowInfo 方法

static void nativeSetInputWindowInfo(JNIEnv* env, jclass clazz, jlong transactionObj,
        jlong nativeObject, jobject inputWindow) {
    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);

    sp<NativeInputWindowHandle> handle = android_view_InputWindowHandle_getHandle(
            env, inputWindow);
    handle->updateInfo();

    auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
    transaction->setInputWindowInfo(ctrl, *handle->getInfo());
}


sp<NativeInputWindowHandle> android_view_InputWindowHandle_getHandle(
        JNIEnv* env, jobject inputWindowHandleObj) {
    if (!inputWindowHandleObj) {
        return NULL;
    }

    AutoMutex _l(gHandleMutex);

    jlong ptr = env->GetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr);
    NativeInputWindowHandle* handle;
    if (ptr) {//这个java端的ptr变量,主要功能就是为了保存对应native层面指针地址
        handle = reinterpret_cast<NativeInputWindowHandle*>(ptr);
    } else {
        jweak objWeak = env->NewWeakGlobalRef(inputWindowHandleObj);
        handle = new NativeInputWindowHandle(objWeak);
    //java层面对象作为了参数,方便后面调用java对象相关属性
        handle->incStrong((void*)android_view_InputWindowHandle_getHandle);
        env->SetLongField(inputWindowHandleObj, gInputWindowHandleClassInfo.ptr,
                reinterpret_cast<jlong>(handle));
    }
    return handle;
}

重点看看 handle->updateInfo(),这个只截取部分:


bool NativeInputWindowHandle::updateInfo() {
    JNIEnv* env = AndroidRuntime::getJNIEnv();
    jobject obj = env->NewLocalRef(mObjWeak);
    if (!obj) {
        releaseChannel();
        return false;
    }

    mInfo.touchableRegion.clear();

    jobject tokenObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.token);
    if (tokenObj) {
        mInfo.token = ibinderForJavaObject(env, tokenObj);
        env->DeleteLocalRef(tokenObj);
    } else {
        mInfo.token.clear();
    }

    mInfo.name = getStringField(env, obj, gInputWindowHandleClassInfo.name, "<null>");

    mInfo.dispatchingTimeout = std::chrono::milliseconds(
            env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutMillis));
            //这里可以看出主要就是对java的数据拷贝到这个mInfo
    mInfo.frameLeft = env->GetIntField(obj,
            gInputWindowHandleClassInfo.frameLeft);
    env->DeleteLocalRef(obj);
    return true;
}


接下来看看 transaction->setInputWindowInfo(ctrl, *handle->getInfo()); 这里较为简单,知识把对应的WindowInfo数据传递给对应的layer_state_t,其实对应就是Layer

SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo(
        const sp<SurfaceControl>& sc, const WindowInfo& info) {
    layer_state_t* s = getLayerState(sc);
    if (!s) {
        mStatus = BAD_INDEX;
        return *this;
    }
    s->windowInfoHandle = new WindowInfoHandle(info);
    s->what |= layer_state_t::eInputInfoChanged;
    return *this;
}

那么到此总结一下:
1、InputMonitior遍历每个WindowState相关数据,当然得有surface的,毕竟和surfaceflinger打交道
2、然后把数据java 的InputWindow数据转化native的InputWindow数据,通过一步步传递到transition中,即保存到了layer_state_t中
调用transition的apply方法:

status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay) {
   //省略遍历目前mComposerStates对象,这里面包好目前的所有inputwindow
    for (auto const& kv : mComposerStates){
        composerStates.add(kv.second);
    }
//跨进程调用setTransactionState把composerStates作为参数
    sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken,
                            mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,
                            {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
                            hasListenerCallbacks, listenerCallbacks, mId);
    //省略
    mStatus = NO_ERROR;
    return NO_ERROR;
}

二、到达SurfaceFlinger层面分析

跨进程调用到了SurfaceFlinger中了:

status_t SurfaceFlinger::setTransactionState(
        const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& states,
        const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
        const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
        bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
        const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) {
   
    TransactionState state{frameTimelineInfo,  states,
                           displays,           flags,
                           applyToken,         inputWindowCommands,
                           desiredPresentTime, isAutoTimestamp,
                           uncacheBuffer,      postTime,
                           permissions,        hasListenerCallbacks,
                           listenerCallbacks,  originPid,
                           originUid,          transactionId};

    //把TransactionState放入队列,且会启动对应的scheduleCommit
    queueTransaction(state);

    // Check the pending state to make sure the transaction is synchronous.
    if (state.transactionCommittedSignal) {
        waitForSynchronousTransaction(*state.transactionCommittedSignal);
    }

    return NO_ERROR;
}

然后执行SurfaceFlinger对应的commit会调用applyTransactionState再通过
setClientStateLocked把传递过来的layer_state_t进行获取更新到SurfaceFlinger的Layer
依次往下调用updateInputFlinger,会调用buildWindowInfos把当前所有的layer中获取数据转化到WindowInfo

uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTimelineInfo,
                                              ComposerState& composerState,
                                              int64_t desiredPresentTime, bool isAutoTimestamp,
                                              int64_t postTime, uint32_t permissions) {
//省略
 if (what & layer_state_t::eInputInfoChanged) {
        layer->setInputInfo(*s.windowInfoHandle->getInfo());
        flags |= eTraversalNeeded;
    }
//省略
}

这样就更新到了Layer中 接下来再调用updateInputFlinger

void SurfaceFlinger::updateInputFlinger() {
    //省略
    if (mVisibleRegionsDirty || mInputInfoChanged) {
        mInputInfoChanged = false;
        updateWindowInfo = true;
        //把WindowInfos搞出
        buildWindowInfos(windowInfos, displayInfos);
    }
    BackgroundExecutor::getInstance().sendCallbacks({[updateWindowInfo,
                                                      windowInfos = std::move(windowInfos),
                                                      displayInfos = std::move(displayInfos),
                                                      inputWindowCommands =
                                                              std::move(mInputWindowCommands),
                                                      inputFlinger = mInputFlinger, this]() {
        if (updateWindowInfo) {
          
            //这里会触发通知
           mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
                                                            inputWindowCommands.syncInputWindows);
        } else if (inputWindowCommands.syncInputWindows) {
            // If the caller requested to sync input windows, but there are no
            // changes to input windows, notify immediately.
            windowInfosReported();
        }
        
        for (const auto& focusRequest : inputWindowCommands.focusRequests) {
            inputFlinger->setFocusedWindow(focusRequest);
        }
    }});

    mInputWindowCommands.clear();
}

这里看看buildWindowInfos

void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos,
                                      std::vector<DisplayInfo>& outDisplayInfos) {
 //省略
    mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
        if (!layer->needsInputInfo()) return;

        // Do not create WindowInfos for windows on displays that cannot receive input.
        if (const auto opt = displayInputInfos.get(layer->getLayerStack())) {
            const auto& info = opt->get();
            outWindowInfos.push_back(layer->fillInputInfo(info.transform, info.isSecure));//根据layer填满outWindowInfos信息
        }
    });

    sNumWindowInfos = outWindowInfos.size();

    outDisplayInfos.reserve(displayInputInfos.size());
    for (const auto& [_, info] : displayInputInfos) {
        outDisplayInfos.push_back(info.info);
    }
}

再接下来看看WindowInfo怎么传递通知出去给InputDispatch

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();

    for (const auto& listener : windowInfosListeners) {
    //这里listener其实就是InputDispather
        listener->onWindowInfosChanged(windowInfos, displayInfos,
                                       shouldSync ? mWindowInfosReportedListener : nullptr);
    }
}

而后调用到InputDispatcher中

void InputDispatcher::DispatcherWindowListener::onWindowInfosChanged(
        const std::vector<gui::WindowInfo>& windowInfos,
        const std::vector<DisplayInfo>& displayInfos) {
    mDispatcher.onWindowInfosChanged(windowInfos, displayInfos);
}

完毕。

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值