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

Commit 803535b9 authored by Robert Carr's avatar Robert Carr
Browse files

InputDispatcher: Track InputChannels by IBinder token.

In the context of passing input through SurfaceFlinger we need
to change the way InputWindowHandles are passed back to the WindowManager.
In the past the InputDispatcher and the WindowManager have been in the same process.
This is taken advantange of by having the InputDispatcher pass back the same object
to the WindowManager (say in interceptKeyBeforeQueueing) which was passed in from
the WindowManager originally (in setInputWindows) this means if the WindowManager
needs to assosciate a WindowState with a given InputWindowHandle it could just
piggy back some information on a subclass of the object and cast it when receiving back
from the Input subsystem. Since the objects will be parcelled across IPC boundaries now
and the WM will not be the caller of setInputWindows, this mechanism won't work. Instead we
ask the WindowManager to provide an IBinder token at registration time, which we can parcel
through the process as a UUID. We provide this token back to Policy callbacks to enable
the WindowManager to look up it's local state.

Bug: 80101428
Bug: 113136004
Bug: 111440400
Test: Manual
Change-Id: Ia828eb61082240f38d82f89e04956da108f636de
parent 2c358bf8
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@

#include <string>

#include <binder/IBinder.h>
#include <input/Input.h>
#include <utils/Errors.h>
#include <utils/Timers.h>
@@ -190,11 +191,16 @@ public:
    status_t write(Parcel& out) const;
    status_t read(const Parcel& from);

    sp<IBinder> getToken() const;
    void setToken(const sp<IBinder>& token);

private:
    void setFd(int fd);

    std::string mName;
    int mFd = -1;

    sp<IBinder> mToken = nullptr;
};

/*
+16 −0
Original line number Diff line number Diff line
@@ -244,6 +244,10 @@ sp<InputChannel> InputChannel::dup() const {
status_t InputChannel::write(Parcel& out) const {
    status_t s = out.writeString8(String8(getName().c_str()));

    if (s != OK) {
        return s;
    }
    s = out.writeStrongBinder(mToken);
    if (s != OK) {
        return s;
    }
@@ -255,6 +259,7 @@ status_t InputChannel::write(Parcel& out) const {

status_t InputChannel::read(const Parcel& from) {
    mName = from.readString8();
    mToken = from.readStrongBinder();

    int rawFd = from.readFileDescriptor();
    setFd(::dup(rawFd));
@@ -266,6 +271,17 @@ status_t InputChannel::read(const Parcel& from) {
    return OK;
}

sp<IBinder> InputChannel::getToken() const {
    return mToken;
}

void InputChannel::setToken(const sp<IBinder>& token) {
    if (mToken != nullptr) {
        ALOGE("Assigning InputChannel (%s) a second handle?", mName.c_str());
    }
    mToken = token;
}

// --- InputPublisher ---

InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
+38 −29
Original line number Diff line number Diff line
@@ -818,7 +818,7 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
            sp<InputWindowHandle> focusedWindowHandle =
                    getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry));
            if (focusedWindowHandle != nullptr) {
                commandEntry->inputWindowHandle = focusedWindowHandle;
                commandEntry->inputChannel = focusedWindowHandle->getInputChannel();
            }
            commandEntry->keyEntry = entry;
            entry->refCount += 1;
@@ -1064,6 +1064,13 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,
    }
}

void InputDispatcher::removeWindowByTokenLocked(const sp<IBinder>& token) {
    for (size_t d = 0; d < mTouchStatesByDisplay.size(); d++) {
        TouchState& state = mTouchStatesByDisplay.editValueAt(d);
        state.removeWindowByToken(token);
    }
}

void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout,
        const sp<InputChannel>& inputChannel) {
    if (newTimeout > 0) {
@@ -1078,17 +1085,10 @@ void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout
            ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
            if (connectionIndex >= 0) {
                sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
                sp<InputWindowHandle> windowHandle = connection->inputWindowHandle;
                sp<IBinder> token = connection->inputChannel->getToken();

                if (windowHandle != nullptr) {
                    const InputWindowInfo* info = windowHandle->getInfo();
                    if (info) {
                        ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(info->displayId);
                        if (stateIndex >= 0) {
                            mTouchStatesByDisplay.editValueAt(stateIndex).removeWindow(
                                    windowHandle);
                        }
                    }
                if (token != nullptr) {
                    removeWindowByTokenLocked(token);
                }

                if (connection->status == Connection::STATUS_NORMAL) {
@@ -3640,8 +3640,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
            mConfig.keyRepeatTimeout * 0.000001f);
}

status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, int32_t displayId) {
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, int32_t displayId) {
#if DEBUG_REGISTRATION
    ALOGD("channel '%s' ~ registerInputChannel - displayId=%" PRId32,
            inputChannel->getName().c_str(), displayId);
@@ -3658,9 +3657,9 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan

        // If InputWindowHandle is null and displayId is not ADISPLAY_ID_NONE,
        // treat inputChannel as monitor channel for displayId.
        bool monitor = inputWindowHandle == nullptr && displayId != ADISPLAY_ID_NONE;
        bool monitor = inputChannel->getToken() == nullptr && displayId != ADISPLAY_ID_NONE;

        sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
        sp<Connection> connection = new Connection(inputChannel, monitor);

        int fd = inputChannel->getFd();
        mConnectionsByFd.add(fd, connection);
@@ -3809,7 +3808,7 @@ void InputDispatcher::onANRLocked(
    CommandEntry* commandEntry = postCommandLocked(
            & InputDispatcher::doNotifyANRLockedInterruptible);
    commandEntry->inputApplicationHandle = applicationHandle;
    commandEntry->inputWindowHandle = windowHandle;
    commandEntry->inputChannel = windowHandle != nullptr ? windowHandle->getInputChannel() : nullptr;
    commandEntry->reason = reason;
}

@@ -3829,7 +3828,7 @@ void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible(
    if (connection->status != Connection::STATUS_ZOMBIE) {
        mLock.unlock();

        mPolicy->notifyInputChannelBroken(connection->inputWindowHandle);
        mPolicy->notifyInputChannelBroken(connection->inputChannel->getToken());

        mLock.lock();
    }
@@ -3840,14 +3839,14 @@ void InputDispatcher::doNotifyANRLockedInterruptible(
    mLock.unlock();

    nsecs_t newTimeout = mPolicy->notifyANR(
            commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle,
            commandEntry->inputApplicationHandle,
            commandEntry->inputChannel ? commandEntry->inputChannel->getToken() : nullptr,
            commandEntry->reason);

    mLock.lock();

    resumeAfterTargetsNotReadyTimeoutLocked(newTimeout,
            commandEntry->inputWindowHandle != nullptr
                    ? commandEntry->inputWindowHandle->getInputChannel() : nullptr);
            commandEntry->inputChannel);
}

void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
@@ -3860,7 +3859,9 @@ void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
    mLock.unlock();

    android::base::Timer t;
    nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,
    sp<IBinder> token = commandEntry->inputChannel != nullptr ?
        commandEntry->inputChannel->getToken() : nullptr;
    nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(token,
            &event, entry->policyFlags);
    if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
        ALOGW("Excessive delay in interceptKeyBeforeDispatching; took %s ms",
@@ -3961,7 +3962,7 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con

                mLock.unlock();

                mPolicy->dispatchUnhandledKey(connection->inputWindowHandle,
                mPolicy->dispatchUnhandledKey(connection->inputChannel->getToken(),
                        &event, keyEntry->policyFlags, &event);

                mLock.lock();
@@ -4006,7 +4007,7 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con

            mLock.unlock();

            bool fallback = mPolicy->dispatchUnhandledKey(connection->inputWindowHandle,
            bool fallback = mPolicy->dispatchUnhandledKey(connection->inputChannel->getToken(),
                    &event, keyEntry->policyFlags, &event);

            mLock.lock();
@@ -4722,9 +4723,8 @@ bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& mement

// --- InputDispatcher::Connection ---

InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel,
        const sp<InputWindowHandle>& inputWindowHandle, bool monitor) :
        status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel, bool monitor) :
        status(STATUS_NORMAL), inputChannel(inputChannel),
        monitor(monitor),
        inputPublisher(inputChannel), inputPublisherBlocked(false) {
}
@@ -4733,8 +4733,8 @@ InputDispatcher::Connection::~Connection() {
}

const std::string InputDispatcher::Connection::getWindowName() const {
    if (inputWindowHandle != nullptr) {
        return inputWindowHandle->getName();
    if (inputChannel != nullptr) {
        return inputChannel->getName();
    }
    if (monitor) {
        return "monitor";
@@ -4841,6 +4841,15 @@ void InputDispatcher::TouchState::removeWindow(const sp<InputWindowHandle>& wind
    }
}

void InputDispatcher::TouchState::removeWindowByToken(const sp<IBinder>& token) {
    for (size_t i = 0; i < windows.size(); i++) {
        if (windows.itemAt(i).windowHandle->getInputChannel()->getToken() == token) {
            windows.removeAt(i);
            return;
        }
    }
}

void InputDispatcher::TouchState::filterNonAsIsTouchWindows() {
    for (size_t i = 0 ; i < windows.size(); ) {
        TouchedWindow& window = windows.editItemAt(i);
+13 −11
Original line number Diff line number Diff line
@@ -208,11 +208,11 @@ public:
    /* Notifies the system that an application is not responding.
     * Returns a new timeout to continue waiting, or 0 to abort dispatch. */
    virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
            const sp<InputWindowHandle>& inputWindowHandle,
            const sp<IBinder>& token,
            const std::string& reason) = 0;

    /* Notifies the system that an input channel is unrecoverably broken. */
    virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) = 0;
    virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;

    /* Gets the input dispatcher configuration. */
    virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
@@ -243,12 +243,12 @@ public:
    virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0;

    /* Allows the policy a chance to intercept a key before dispatching. */
    virtual nsecs_t interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle,
    virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token,
            const KeyEvent* keyEvent, uint32_t policyFlags) = 0;

    /* Allows the policy a chance to perform default processing for an unhandled key.
     * Returns an alternate keycode to redispatch as a fallback, or 0 to give up. */
    virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle,
    virtual bool dispatchUnhandledKey(const sp<IBinder>& token,
            const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) = 0;

    /* Notifies the policy about switch events.
@@ -352,8 +352,8 @@ public:
     *
     * This method may be called on any thread (usually by the input manager).
     */
    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
            const sp<InputWindowHandle>& inputWindowHandle, int32_t displayId) = 0;
    virtual status_t registerInputChannel(
            const sp<InputChannel>& inputChannel, int32_t displayId) = 0;

    /* Unregister input channels that will no longer receive input events.
     *
@@ -413,7 +413,7 @@ public:
            const sp<InputChannel>& toChannel);

    virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
            const sp<InputWindowHandle>& inputWindowHandle, int32_t displayId);
            int32_t displayId);
    virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);

private:
@@ -617,11 +617,11 @@ private:
        nsecs_t eventTime;
        KeyEntry* keyEntry;
        sp<InputApplicationHandle> inputApplicationHandle;
        sp<InputWindowHandle> inputWindowHandle;
        std::string reason;
        int32_t userActivityEventType;
        uint32_t seq;
        bool handled;
        sp<InputChannel> inputChannel;
    };

    // Generic queue implementation.
@@ -834,7 +834,6 @@ private:

        Status status;
        sp<InputChannel> inputChannel; // never null
        sp<InputWindowHandle> inputWindowHandle; // may be null
        bool monitor;
        InputPublisher inputPublisher;
        InputState inputState;
@@ -850,8 +849,7 @@ private:
        // yet received a "finished" response from the application.
        Queue<DispatchEntry> waitQueue;

        explicit Connection(const sp<InputChannel>& inputChannel,
                const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
        explicit Connection(const sp<InputChannel>& inputChannel, bool monitor);

        inline const std::string getInputChannelName() const { return inputChannel->getName(); }

@@ -1007,6 +1005,7 @@ private:
        void addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
                int32_t targetFlags, BitSet32 pointerIds);
        void removeWindow(const sp<InputWindowHandle>& windowHandle);
        void removeWindowByToken(const sp<IBinder>& token);
        void filterNonAsIsTouchWindows();
        sp<InputWindowHandle> getFirstForegroundWindowHandle() const;
        bool isSlippery() const;
@@ -1062,6 +1061,9 @@ private:
            const sp<InputApplicationHandle>& applicationHandle,
            const sp<InputWindowHandle>& windowHandle,
            nsecs_t* nextWakeupTime, const char* reason);

    void removeWindowByTokenLocked(const sp<IBinder>& token);

    void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout,
            const sp<InputChannel>& inputChannel);
    nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime);
+1 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ cc_test {
    ],
    shared_libs: [
        "libbase",
        "libbinder",
        "libcutils",
        "liblog",
        "libutils",
Loading