Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ce2205fc authored by Patrick Williams's avatar Patrick Williams Committed by Android (Google) Code Review
Browse files

Merge "SF: throttle WindowInfosListener calls" into udc-dev

parents cd5edad6 1caf3b7d
Loading
Loading
Loading
Loading
+1 −10
Original line number Diff line number Diff line
@@ -2442,16 +2442,7 @@ WindowInfo Layer::fillInputInfo(const InputDisplayArgs& displayArgs) {
        info.inputConfig |= WindowInfo::InputConfig::NOT_TOUCHABLE;
    }

    // For compatibility reasons we let layers which can receive input
    // receive input before they have actually submitted a buffer. Because
    // of this we use canReceiveInput instead of isVisible to check the
    // policy-visibility, ignoring the buffer state. However for layers with
    // hasInputInfo()==false we can use the real visibility state.
    // We are just using these layers for occlusion detection in
    // InputDispatcher, and obviously if they aren't visible they can't occlude
    // anything.
    const bool visible = hasInputInfo() ? canReceiveInput() : isVisible();
    info.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !visible);
    info.setInputConfig(WindowInfo::InputConfig::NOT_VISIBLE, !isVisibleForInput());

    info.alpha = getAlpha();
    fillTouchOcclusionMode(info);
+15 −0
Original line number Diff line number Diff line
@@ -371,6 +371,21 @@ public:
     */
    bool canReceiveInput() const;

    /*
     * Whether or not the layer should be considered visible for input calculations.
     */
    virtual bool isVisibleForInput() const {
        // For compatibility reasons we let layers which can receive input
        // receive input before they have actually submitted a buffer. Because
        // of this we use canReceiveInput instead of isVisible to check the
        // policy-visibility, ignoring the buffer state. However for layers with
        // hasInputInfo()==false we can use the real visibility state.
        // We are just using these layers for occlusion detection in
        // InputDispatcher, and obviously if they aren't visible they can't occlude
        // anything.
        return hasInputInfo() ? canReceiveInput() : isVisible();
    }

    /*
     * isProtected - true if the layer may contain protected contents in the
     * GRALLOC_USAGE_PROTECTED sense.
+19 −3
Original line number Diff line number Diff line
@@ -3715,17 +3715,33 @@ void SurfaceFlinger::updateInputFlinger() {
        return;
    }

    std::unordered_set<Layer*> visibleLayers;
    mDrawingState.traverse([&visibleLayers](Layer* layer) {
        if (layer->isVisibleForInput()) {
            visibleLayers.insert(layer);
        }
    });
    bool visibleLayersChanged = false;
    if (visibleLayers != mVisibleLayers) {
        visibleLayersChanged = true;
        mVisibleLayers = std::move(visibleLayers);
    }

    BackgroundExecutor::getInstance().sendCallbacks({[updateWindowInfo,
                                                      windowInfos = std::move(windowInfos),
                                                      displayInfos = std::move(displayInfos),
                                                      inputWindowCommands =
                                                              std::move(mInputWindowCommands),
                                                      inputFlinger = mInputFlinger, this]() {
                                                      inputFlinger = mInputFlinger, this,
                                                      visibleLayersChanged]() {
        ATRACE_NAME("BackgroundExecutor::updateInputFlinger");
        if (updateWindowInfo) {
            mWindowInfosListenerInvoker
                    ->windowInfosChanged(windowInfos, displayInfos,
                                         inputWindowCommands.windowInfosReportedListeners);
                    ->windowInfosChanged(std::move(windowInfos), std::move(displayInfos),
                                         std::move(
                                                 inputWindowCommands.windowInfosReportedListeners),
                                         /* forceImmediateCall= */ visibleLayersChanged ||
                                                 !inputWindowCommands.focusRequests.empty());
        } else {
            // If there are listeners but no changes to input windows, call the listeners
            // immediately.
+5 −0
Original line number Diff line number Diff line
@@ -1424,6 +1424,11 @@ private:
    TransactionHandler mTransactionHandler;
    display::DisplayMap<ui::LayerStack, frontend::DisplayInfo> mFrontEndDisplayInfos;
    bool mFrontEndDisplayInfosChanged = false;

    // Layers visible during the last commit. This set should only be used for testing set equality
    // and membership. The pointers should not be dereferenced as it's possible the set contains
    // pointers to freed layers.
    std::unordered_set<Layer*> mVisibleLayers;
};

class SurfaceComposerAIDL : public gui::BnSurfaceComposer {
+86 −40
Original line number Diff line number Diff line
@@ -25,20 +25,17 @@ using gui::DisplayInfo;
using gui::IWindowInfosListener;
using gui::WindowInfo;

struct WindowInfosListenerInvoker::WindowInfosReportedListener : gui::BnWindowInfosReportedListener,
                                                                 DeathRecipient {
    explicit WindowInfosReportedListener(
            size_t callbackCount,
            const std::unordered_set<sp<gui::IWindowInfosReportedListener>,
                                     SpHash<gui::IWindowInfosReportedListener>>&
                    windowInfosReportedListeners)
          : mCallbacksPending(callbackCount),
            mWindowInfosReportedListeners(windowInfosReportedListeners) {}
using WindowInfosListenerVector = ftl::SmallVector<const sp<IWindowInfosListener>, 3>;

struct WindowInfosReportedListenerInvoker : gui::BnWindowInfosReportedListener,
                                            IBinder::DeathRecipient {
    WindowInfosReportedListenerInvoker(WindowInfosListenerVector windowInfosListeners,
                                       WindowInfosReportedListenerSet windowInfosReportedListeners)
          : mCallbacksPending(windowInfosListeners.size()),
            mWindowInfosListeners(std::move(windowInfosListeners)),
            mWindowInfosReportedListeners(std::move(windowInfosReportedListeners)) {}

    binder::Status onWindowInfosReported() override {
        // TODO(b/222421815) There could potentially be callbacks that we don't need to wait for
        // before calling the WindowInfosReportedListeners coming from InputWindowCommands. Filter
        // the list of callbacks down to those from system server.
        if (--mCallbacksPending == 0) {
            for (const auto& listener : mWindowInfosReportedListeners) {
                sp<IBinder> asBinder = IInterface::asBinder(listener);
@@ -46,6 +43,12 @@ struct WindowInfosListenerInvoker::WindowInfosReportedListener : gui::BnWindowIn
                    listener->onWindowInfosReported();
                }
            }

            auto wpThis = wp<WindowInfosReportedListenerInvoker>::fromExisting(this);
            for (const auto& listener : mWindowInfosListeners) {
                sp<IBinder> binder = IInterface::asBinder(listener);
                binder->unlinkToDeath(wpThis);
            }
        }
        return binder::Status::ok();
    }
@@ -54,9 +57,9 @@ struct WindowInfosListenerInvoker::WindowInfosReportedListener : gui::BnWindowIn

private:
    std::atomic<size_t> mCallbacksPending;
    std::unordered_set<sp<gui::IWindowInfosReportedListener>,
                       SpHash<gui::IWindowInfosReportedListener>>
            mWindowInfosReportedListeners;
    static constexpr size_t kStaticCapacity = 3;
    const WindowInfosListenerVector mWindowInfosListeners;
    WindowInfosReportedListenerSet mWindowInfosReportedListeners;
};

void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener) {
@@ -82,11 +85,13 @@ void WindowInfosListenerInvoker::binderDied(const wp<IBinder>& who) {
}

void WindowInfosListenerInvoker::windowInfosChanged(
        const std::vector<WindowInfo>& windowInfos, const std::vector<DisplayInfo>& displayInfos,
        const std::unordered_set<sp<gui::IWindowInfosReportedListener>,
                                 SpHash<gui::IWindowInfosReportedListener>>&
                windowInfosReportedListeners) {
    ftl::SmallVector<const sp<IWindowInfosListener>, kStaticCapacity> windowInfosListeners;
        std::vector<WindowInfo> windowInfos, std::vector<DisplayInfo> displayInfos,
        WindowInfosReportedListenerSet reportedListeners, bool forceImmediateCall) {
    reportedListeners.insert(sp<WindowInfosListenerInvoker>::fromExisting(this));
    auto callListeners = [this, windowInfos = std::move(windowInfos),
                          displayInfos = std::move(displayInfos)](
                                 WindowInfosReportedListenerSet reportedListeners) mutable {
        WindowInfosListenerVector windowInfosListeners;
        {
            std::scoped_lock lock(mListenersMutex);
            for (const auto& [_, listener] : mWindowInfosListeners) {
@@ -94,26 +99,67 @@ void WindowInfosListenerInvoker::windowInfosChanged(
            }
        }

    auto windowInfosReportedListener = windowInfosReportedListeners.empty()
            ? nullptr
            : sp<WindowInfosReportedListener>::make(windowInfosListeners.size(),
                                                    windowInfosReportedListeners);
        auto reportedInvoker =
                sp<WindowInfosReportedListenerInvoker>::make(windowInfosListeners,
                                                             std::move(reportedListeners));

        for (const auto& listener : windowInfosListeners) {
            sp<IBinder> asBinder = IInterface::asBinder(listener);

            // linkToDeath is used here to ensure that the windowInfosReportedListeners
            // are called even if one of the windowInfosListeners dies before
            // calling onWindowInfosReported.
        if (windowInfosReportedListener) {
            asBinder->linkToDeath(windowInfosReportedListener);
            asBinder->linkToDeath(reportedInvoker);

            auto status =
                    listener->onWindowInfosChanged(windowInfos, displayInfos, reportedInvoker);
            if (!status.isOk()) {
                reportedInvoker->onWindowInfosReported();
            }
        }
    };

    {
        std::scoped_lock lock(mMessagesMutex);
        // If there are unacked messages and this isn't a forced call, then return immediately.
        // If a forced window infos change doesn't happen first, the update will be sent after
        // the WindowInfosReportedListeners are called. If a forced window infos change happens or
        // if there are subsequent delayed messages before this update is sent, then this message
        // will be dropped and the listeners will only be called with the latest info. This is done
        // to reduce the amount of binder memory used.
        if (mActiveMessageCount > 0 && !forceImmediateCall) {
            mWindowInfosChangedDelayed = std::move(callListeners);
            mReportedListenersDelayed.merge(reportedListeners);
            return;
        }

        auto status = listener->onWindowInfosChanged(windowInfos, displayInfos,
                                                     windowInfosReportedListener);
        if (windowInfosReportedListener && !status.isOk()) {
            windowInfosReportedListener->onWindowInfosReported();
        mWindowInfosChangedDelayed = nullptr;
        reportedListeners.merge(mReportedListenersDelayed);
        mActiveMessageCount++;
    }
    callListeners(std::move(reportedListeners));
}

binder::Status WindowInfosListenerInvoker::onWindowInfosReported() {
    std::function<void(WindowInfosReportedListenerSet)> callListeners;
    WindowInfosReportedListenerSet reportedListeners;

    {
        std::scoped_lock lock{mMessagesMutex};
        mActiveMessageCount--;
        if (!mWindowInfosChangedDelayed || mActiveMessageCount > 0) {
            return binder::Status::ok();
        }

        mActiveMessageCount++;
        callListeners = std::move(mWindowInfosChangedDelayed);
        mWindowInfosChangedDelayed = nullptr;
        reportedListeners = std::move(mReportedListenersDelayed);
        mReportedListenersDelayed.clear();
    }

    callListeners(std::move(reportedListeners));
    return binder::Status::ok();
}

} // namespace android
Loading