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

Commit 9302c879 authored by Jeff Brown's avatar Jeff Brown
Browse files

Refactor input dispatcher use of window/app handles.

This change moves the cached window and application input state
into the handle objects themselves.  It simplifies the dispatcher
somewhat because it no longer needs to fix up references to
transient InputWindow objects each time the window list is updated.

This change will also make it easier to optimize setInputWindows
to avoid doing a lot of redundant data copying.  In principle, only
the modified fields need to be updated.  However, for now we
continue to update all fields in unison as before.

It turns out that the input dispatcher was inappropriately retaining
pointers to InputWindow objects within the mWindows InputWindow
vector.  This vector is copy-on-write so it is possible and the
item pointers to change if an editing operation is performed on
the vector when it does not exclusively own the underlying
SharedBuffer.  This bug was uncovered by a previous change that
replaced calls to clear() and appendVector() with a simple use
of operator= which caused the buffer to be shared.  Consequently
after editItemAt was called (which it shouldn't have, actually)
the buffer was copied and the cached InputWindow pointers became
invalid.  Oops.  This change fixes the problem.

Change-Id: I0a259339a6015fcf9113dc4081a6875e047fd425
parent 14fcf900
Loading
Loading
Loading
Loading
+18 −12
Original line number Diff line number Diff line
@@ -26,26 +26,32 @@
namespace android {

/*
 * A handle to an application that can receive input.
 * Used by the native input dispatcher to indirectly refer to the window manager objects
 * Describes the properties of an application that can receive input.
 *
 * Used by the native input dispatcher as a handle for the window manager objects
 * that describe an application.
 */
class InputApplicationHandle : public RefBase {
public:
    String8 name;
    nsecs_t dispatchingTimeout;

    /**
     * Requests that the state of this object be updated to reflect
     * the most current available information about the application.
     *
     * This method should only be called from within the input dispatcher's
     * critical section.
     *
     * Returns true on success, or false if the handle is no longer valid.
     */
    virtual bool update() = 0;

protected:
    InputApplicationHandle() { }
    virtual ~InputApplicationHandle() { }
};


/*
 * An input application describes properties of an application that can receive input.
 */
struct InputApplication {
    sp<InputApplicationHandle> inputApplicationHandle;
    String8 name;
    nsecs_t dispatchingTimeout;
};

} // namespace android

#endif // _UI_INPUT_APPLICATION_H
+267 −271

File changed.

Preview size limit exceeded, changes collapsed.

+30 −27
Original line number Diff line number Diff line
@@ -321,13 +321,14 @@ public:
     *
     * This method may be called on any thread (usually by the input manager).
     */
    virtual void setInputWindows(const Vector<InputWindow>& inputWindows) = 0;
    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) = 0;

    /* Sets the focused application.
     *
     * This method may be called on any thread (usually by the input manager).
     */
    virtual void setFocusedApplication(const InputApplication* inputApplication) = 0;
    virtual void setFocusedApplication(
            const sp<InputApplicationHandle>& inputApplicationHandle) = 0;

    /* Sets the input dispatching mode.
     *
@@ -406,8 +407,8 @@ public:
            int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
            uint32_t policyFlags);

    virtual void setInputWindows(const Vector<InputWindow>& inputWindows);
    virtual void setFocusedApplication(const InputApplication* inputApplication);
    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles);
    virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle);
    virtual void setInputDispatchMode(bool enabled, bool frozen);
    virtual void setInputFilterEnabled(bool enabled);

@@ -578,7 +579,6 @@ private:
        sp<Connection> connection;
        nsecs_t eventTime;
        KeyEntry* keyEntry;
        sp<InputChannel> inputChannel;
        sp<InputApplicationHandle> inputApplicationHandle;
        sp<InputWindowHandle> inputWindowHandle;
        int32_t userActivityEventType;
@@ -894,7 +894,7 @@ private:
    // to transfer focus to a new application.
    EventEntry* mNextUnblockedEvent;

    const InputWindow* findTouchedWindowAtLocked(int32_t x, int32_t y);
    sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t x, int32_t y);

    // All registered connections mapped by receive pipe file descriptor.
    KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
@@ -953,19 +953,19 @@ private:
    bool mDispatchFrozen;
    bool mInputFilterEnabled;

    Vector<InputWindow> mWindows;
    Vector<sp<InputWindowHandle> > mWindowHandles;

    const InputWindow* getWindowLocked(const sp<InputChannel>& inputChannel);
    sp<InputWindowHandle> getWindowHandleLocked(const sp<InputChannel>& inputChannel) const;
    bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;

    // Focus tracking for keys, trackball, etc.
    const InputWindow* mFocusedWindow;
    sp<InputWindowHandle> mFocusedWindowHandle;

    // Focus tracking for touch.
    struct TouchedWindow {
        const InputWindow* window;
        sp<InputWindowHandle> windowHandle;
        int32_t targetFlags;
        BitSet32 pointerIds;        // zero unless target flag FLAG_SPLIT is set
        sp<InputChannel> channel;
    };
    struct TouchState {
        bool down;
@@ -978,9 +978,10 @@ private:
        ~TouchState();
        void reset();
        void copyFrom(const TouchState& other);
        void addOrUpdateWindow(const InputWindow* window,int32_t targetFlags, BitSet32 pointerIds);
        void addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
                int32_t targetFlags, BitSet32 pointerIds);
        void filterNonAsIsTouchWindows();
        const InputWindow* getFirstForegroundWindow() const;
        sp<InputWindowHandle> getFirstForegroundWindowHandle() const;
        bool isSlippery() const;
    };

@@ -988,9 +989,7 @@ private:
    TouchState mTempTouchState;

    // Focused application.
    InputApplication* mFocusedApplication;
    InputApplication mFocusedApplicationStorage; // preallocated storage for mFocusedApplication
    void releaseFocusedApplicationLocked();
    sp<InputApplicationHandle> mFocusedApplicationHandle;

    // Dispatch inbound events.
    bool dispatchConfigurationChangedLocked(
@@ -1021,16 +1020,17 @@ private:
    nsecs_t mInputTargetWaitStartTime;
    nsecs_t mInputTargetWaitTimeoutTime;
    bool mInputTargetWaitTimeoutExpired;
    sp<InputApplicationHandle> mInputTargetWaitApplication;
    sp<InputApplicationHandle> mInputTargetWaitApplicationHandle;

    // Contains the last window which received a hover event.
    const InputWindow* mLastHoverWindow;
    sp<InputWindowHandle> mLastHoverWindowHandle;

    // Finding targets for input events.
    void resetTargetsLocked();
    void commitTargetsLocked();
    int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry,
            const InputApplication* application, const InputWindow* window,
            const sp<InputApplicationHandle>& applicationHandle,
            const sp<InputWindowHandle>& windowHandle,
            nsecs_t* nextWakeupTime);
    void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout,
            const sp<InputChannel>& inputChannel);
@@ -1043,15 +1043,17 @@ private:
            nsecs_t* nextWakeupTime, bool* outConflictingPointerActions,
            const MotionSample** outSplitBatchAfterSample);

    void addWindowTargetLocked(const InputWindow* window, int32_t targetFlags,
            BitSet32 pointerIds);
    void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
            int32_t targetFlags, BitSet32 pointerIds);
    void addMonitoringTargetsLocked();
    void pokeUserActivityLocked(const EventEntry* eventEntry);
    bool checkInjectionPermission(const InputWindow* window, const InjectionState* injectionState);
    bool isWindowObscuredAtPointLocked(const InputWindow* window, int32_t x, int32_t y) const;
    bool isWindowFinishedWithPreviousInputLocked(const InputWindow* window);
    String8 getApplicationWindowLabelLocked(const InputApplication* application,
            const InputWindow* window);
    bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
            const InjectionState* injectionState);
    bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
            int32_t x, int32_t y) const;
    bool isWindowFinishedWithPreviousInputLocked(const sp<InputWindowHandle>& windowHandle);
    String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle,
            const sp<InputWindowHandle>& windowHandle);

    // Manage the dispatch cycle for a single connection.
    // These methods are deliberately not Interruptible because doing all of the work
@@ -1100,7 +1102,8 @@ private:
    void onDispatchCycleBrokenLocked(
            nsecs_t currentTime, const sp<Connection>& connection);
    void onANRLocked(
            nsecs_t currentTime, const InputApplication* application, const InputWindow* window,
            nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
            const sp<InputWindowHandle>& windowHandle,
            nsecs_t eventTime, nsecs_t waitStartTime);

    // Outbound policy interactions.
+6 −6
Original line number Diff line number Diff line
@@ -22,25 +22,25 @@

namespace android {

// --- InputWindow ---
// --- InputWindowHandle ---

bool InputWindow::touchableRegionContainsPoint(int32_t x, int32_t y) const {
bool InputWindowHandle::touchableRegionContainsPoint(int32_t x, int32_t y) const {
    return touchableRegion.contains(x, y);
}

bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const {
bool InputWindowHandle::frameContainsPoint(int32_t x, int32_t y) const {
    return x >= frameLeft && x <= frameRight
            && y >= frameTop && y <= frameBottom;
}

bool InputWindow::isTrustedOverlay() const {
bool InputWindowHandle::isTrustedOverlay() const {
    return layoutParamsType == TYPE_INPUT_METHOD
            || layoutParamsType == TYPE_INPUT_METHOD_DIALOG
            || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY;
}

bool InputWindow::supportsSplitTouch() const {
    return layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH;
bool InputWindowHandle::supportsSplitTouch() const {
    return layoutParamsFlags & FLAG_SPLIT_TOUCH;
}

} // namespace android
+18 −17
Original line number Diff line number Diff line
@@ -31,29 +31,14 @@ namespace android {

/*
 * A handle to a window that can receive input.
 *
 * Used by the native input dispatcher to indirectly refer to the window manager objects
 * that describe a window.
 */
class InputWindowHandle : public RefBase {
protected:
    InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
            mInputApplicationHandle(inputApplicationHandle) { }
    virtual ~InputWindowHandle() { }

public:
    inline sp<InputApplicationHandle> getInputApplicationHandle() {
        return mInputApplicationHandle;
    }
    const sp<InputApplicationHandle> inputApplicationHandle;

private:
    sp<InputApplicationHandle> mInputApplicationHandle;
};


/*
 * An input window describes the bounds of a window that can receive input.
 */
struct InputWindow {
    // Window flags from WindowManager.LayoutParams
    enum {
        FLAG_ALLOW_LOCK_WHILE_SCREEN_ON     = 0x00000001,
@@ -164,6 +149,22 @@ struct InputWindow {
    bool isTrustedOverlay() const;

    bool supportsSplitTouch() const;

    /**
     * Requests that the state of this object be updated to reflect
     * the most current available information about the application.
     *
     * This method should only be called from within the input dispatcher's
     * critical section.
     *
     * Returns true on success, or false if the handle is no longer valid.
     */
    virtual bool update() = 0;

protected:
    InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
            inputApplicationHandle(inputApplicationHandle) { }
    virtual ~InputWindowHandle() { }
};

} // namespace android
Loading