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

Commit 9dc348d7 authored by Jeff Brown's avatar Jeff Brown Committed by Android (Google) Code Review
Browse files

Merge "Fix spurious ANRs in native activities."

parents f2fbd2ed 2b6c32ca
Loading
Loading
Loading
Loading
+32 −56
Original line number Diff line number Diff line
@@ -162,12 +162,12 @@ int32_t AInputQueue::hasEvents() {
int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
    *outEvent = NULL;

    bool finishNow = false;

    char byteread;
    ssize_t nRead = read(mDispatchKeyRead, &byteread, 1);

    Mutex::Autolock _l(mLock);

    if (nRead == 1) {
        mLock.lock();
        if (mDispatchingKeys.size() > 0) {
            KeyEvent* kevent = mDispatchingKeys[0];
            *outEvent = kevent;
@@ -178,6 +178,8 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
            inflight.finishSeq = 0;
            mInFlightEvents.push(inflight);
        }

        bool finishNow = false;
        if (mFinishPreDispatches.size() > 0) {
            finish_pre_dispatch finish(mFinishPreDispatches[0]);
            mFinishPreDispatches.removeAt(0);
@@ -193,7 +195,6 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
                ALOGW("getEvent couldn't find inflight for seq %d", finish.seq);
            }
        }
        mLock.unlock();

        if (finishNow) {
            finishEvent(*outEvent, true, false);
@@ -206,7 +207,8 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) {

    uint32_t consumerSeq;
    InputEvent* myEvent = NULL;
    status_t res = mConsumer.consume(this, true /*consumeBatches*/, &consumerSeq, &myEvent);
    status_t res = mConsumer.consume(&mPooledInputEventFactory, true /*consumeBatches*/,
            &consumerSeq, &myEvent);
    if (res != android::OK) {
        if (res != android::WOULD_BLOCK) {
            ALOGW("channel '%s' ~ Failed to consume input event.  status=%d",
@@ -215,6 +217,10 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
        return -1;
    }

    if (mConsumer.hasDeferredEvent()) {
        wakeupDispatchLocked();
    }

    in_flight_event inflight;
    inflight.event = myEvent;
    inflight.seq = -1;
@@ -255,7 +261,8 @@ void AInputQueue::finishEvent(AInputEvent* event, bool handled, bool didDefaultH
        return;
    }

    mLock.lock();
    Mutex::Autolock _l(mLock);

    const size_t N = mInFlightEvents.size();
    for (size_t i=0; i<N; i++) {
        const in_flight_event& inflight(mInFlightEvents[i]);
@@ -267,111 +274,82 @@ void AInputQueue::finishEvent(AInputEvent* event, bool handled, bool didDefaultH
                            mConsumer.getChannel()->getName().string(), res);
                }
            }
            if (static_cast<InputEvent*>(event)->getType() == AINPUT_EVENT_TYPE_KEY) {
                mAvailKeyEvents.push(static_cast<KeyEvent*>(event));
            } else {
                mAvailMotionEvents.push(static_cast<MotionEvent*>(event));
            }
            mPooledInputEventFactory.recycle(static_cast<InputEvent*>(event));
            mInFlightEvents.removeAt(i);
            mLock.unlock();
            return;
        }
    }
    mLock.unlock();

    ALOGW("finishEvent called for unknown event: %p", event);
}

void AInputQueue::dispatchEvent(android::KeyEvent* event) {
    mLock.lock();
    Mutex::Autolock _l(mLock);

    LOG_TRACE("dispatchEvent: dispatching=%d write=%d\n", mDispatchingKeys.size(),
            mDispatchKeyWrite);
    mDispatchingKeys.add(event);
    wakeupDispatch();
    mLock.unlock();
    wakeupDispatchLocked();
}

void AInputQueue::finishPreDispatch(int seq, bool handled) {
    mLock.lock();
    Mutex::Autolock _l(mLock);

    LOG_TRACE("finishPreDispatch: seq=%d handled=%d\n", seq, handled ? 1 : 0);
    finish_pre_dispatch finish;
    finish.seq = seq;
    finish.handled = handled;
    mFinishPreDispatches.add(finish);
    wakeupDispatch();
    mLock.unlock();
    wakeupDispatchLocked();
}

KeyEvent* AInputQueue::consumeUnhandledEvent() {
    KeyEvent* event = NULL;
    Mutex::Autolock _l(mLock);

    mLock.lock();
    KeyEvent* event = NULL;
    if (mUnhandledKeys.size() > 0) {
        event = mUnhandledKeys[0];
        mUnhandledKeys.removeAt(0);
    }
    mLock.unlock();

    LOG_TRACE("consumeUnhandledEvent: KeyEvent=%p", event);

    return event;
}

KeyEvent* AInputQueue::consumePreDispatchingEvent(int* outSeq) {
    KeyEvent* event = NULL;
    Mutex::Autolock _l(mLock);

    mLock.lock();
    KeyEvent* event = NULL;
    if (mPreDispatchingKeys.size() > 0) {
        const in_flight_event& inflight(mPreDispatchingKeys[0]);
        event = static_cast<KeyEvent*>(inflight.event);
        *outSeq = inflight.seq;
        mPreDispatchingKeys.removeAt(0);
    }
    mLock.unlock();

    LOG_TRACE("consumePreDispatchingEvent: KeyEvent=%p", event);

    return event;
}

KeyEvent* AInputQueue::createKeyEvent() {
    mLock.lock();
    KeyEvent* event;
    if (mAvailKeyEvents.size() <= 0) {
        event = new KeyEvent();
    } else {
        event = mAvailKeyEvents.top();
        mAvailKeyEvents.pop();
    }
    mLock.unlock();
    return event;
}
    Mutex::Autolock _l(mLock);

MotionEvent* AInputQueue::createMotionEvent() {
    mLock.lock();
    MotionEvent* event;
    if (mAvailMotionEvents.size() <= 0) {
        event = new MotionEvent();
    } else {
        event = mAvailMotionEvents.top();
        mAvailMotionEvents.pop();
    }
    mLock.unlock();
    return event;
    return mPooledInputEventFactory.createKeyEvent();
}

void AInputQueue::doUnhandledKey(KeyEvent* keyEvent) {
    mLock.lock();
    Mutex::Autolock _l(mLock);

    LOG_TRACE("Unhandled key: pending=%d write=%d\n", mUnhandledKeys.size(), mWorkWrite);
    if (mUnhandledKeys.size() <= 0 && mWorkWrite >= 0) {
        write_work(mWorkWrite, CMD_DEF_KEY);
    }
    mUnhandledKeys.add(keyEvent);
    mLock.unlock();
}

bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) {
    mLock.lock();
    Mutex::Autolock _l(mLock);

    LOG_TRACE("preDispatch key: pending=%d write=%d\n", mPreDispatchingKeys.size(), mWorkWrite);
    const size_t N = mInFlightEvents.size();
    for (size_t i=0; i<N; i++) {
@@ -380,7 +358,6 @@ bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) {
            if (inflight.seq >= 0) {
                // This event has already been pre-dispatched!
                LOG_TRACE("Event already pre-dispatched!");
                mLock.unlock();
                return false;
            }
            mSeq++;
@@ -391,7 +368,6 @@ bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) {
                write_work(mWorkWrite, CMD_DEF_KEY);
            }
            mPreDispatchingKeys.add(inflight);
            mLock.unlock();
            return true;
        }
    }
@@ -400,7 +376,7 @@ bool AInputQueue::preDispatchKey(KeyEvent* keyEvent) {
    return false;
}

void AInputQueue::wakeupDispatch() {
void AInputQueue::wakeupDispatchLocked() {
restart:
    char dummy = 0;
    int res = write(mDispatchKeyWrite, &dummy, sizeof(dummy));
+4 −9
Original line number Diff line number Diff line
@@ -65,7 +65,7 @@ extern void android_NativeActivity_hideSoftInput(
 *      b. Java sends event through default key handler.
 *      c. event is finished.
 */
struct AInputQueue : public android::InputEventFactoryInterface {
struct AInputQueue {
public:
    /* Creates a consumer associated with an input channel. */
    explicit AInputQueue(const android::sp<android::InputChannel>& channel, int workWrite);
@@ -96,16 +96,16 @@ public:
    android::KeyEvent* consumeUnhandledEvent();
    android::KeyEvent* consumePreDispatchingEvent(int* outSeq);

    virtual android::KeyEvent* createKeyEvent();
    virtual android::MotionEvent* createMotionEvent();
    android::KeyEvent* createKeyEvent();

    int mWorkWrite;

private:
    void doUnhandledKey(android::KeyEvent* keyEvent);
    bool preDispatchKey(android::KeyEvent* keyEvent);
    void wakeupDispatch();
    void wakeupDispatchLocked();

    android::PooledInputEventFactory mPooledInputEventFactory;
    android::InputConsumer mConsumer;
    android::sp<android::Looper> mLooper;

@@ -127,11 +127,6 @@ private:

    int mSeq;

    // Cache of previously allocated key events.
    android::Vector<android::KeyEvent*> mAvailKeyEvents;
    // Cache of previously allocated motion events.
    android::Vector<android::MotionEvent*> mAvailMotionEvents;

    // All input events that are actively being processed.
    android::Vector<in_flight_event> mInFlightEvents;

+20 −0
Original line number Diff line number Diff line
@@ -615,6 +615,26 @@ private:
    MotionEvent mMotionEvent;
};

/*
 * An input event factory implementation that maintains a pool of input events.
 */
class PooledInputEventFactory : public InputEventFactoryInterface {
public:
    PooledInputEventFactory(size_t maxPoolSize = 20);
    virtual ~PooledInputEventFactory();

    virtual KeyEvent* createKeyEvent();
    virtual MotionEvent* createMotionEvent();

    void recycle(InputEvent* event);

private:
    const size_t mMaxPoolSize;

    Vector<KeyEvent*> mKeyEventPool;
    Vector<MotionEvent*> mMotionEventPool;
};

/*
 * Calculates the velocity of pointer movements over time.
 */
+23 −1
Original line number Diff line number Diff line
@@ -292,7 +292,29 @@ public:
     */
    status_t sendFinishedSignal(uint32_t seq, bool handled);

    /* Returns true if there is a pending batch. */
    /* Returns true if there is a deferred event waiting.
     *
     * Should be called after calling consume() to determine whether the consumer
     * has a deferred event to be processed.  Deferred events are somewhat special in
     * that they have already been removed from the input channel.  If the input channel
     * becomes empty, the client may need to do extra work to ensure that it processes
     * the deferred event despite the fact that the inptu channel's file descriptor
     * is not readable.
     *
     * One option is simply to call consume() in a loop until it returns WOULD_BLOCK.
     * This guarantees that all deferred events will be processed.
     *
     * Alternately, the caller can call hasDeferredEvent() to determine whether there is
     * a deferred event waiting and then ensure that its event loop wakes up at least
     * one more time to consume the deferred event.
     */
    bool hasDeferredEvent() const;

    /* Returns true if there is a pending batch.
     *
     * Should be called after calling consume() with consumeBatches == false to determine
     * whether consume() should be called again later on with consumeBatches == true.
     */
    bool hasPendingBatch() const;

private:
+52 −0
Original line number Diff line number Diff line
@@ -683,6 +683,58 @@ bool MotionEvent::isTouchEvent(int32_t source, int32_t action) {
}


// --- PooledInputEventFactory ---

PooledInputEventFactory::PooledInputEventFactory(size_t maxPoolSize) :
        mMaxPoolSize(maxPoolSize) {
}

PooledInputEventFactory::~PooledInputEventFactory() {
    for (size_t i = 0; i < mKeyEventPool.size(); i++) {
        delete mKeyEventPool.itemAt(i);
    }
    for (size_t i = 0; i < mMotionEventPool.size(); i++) {
        delete mMotionEventPool.itemAt(i);
    }
}

KeyEvent* PooledInputEventFactory::createKeyEvent() {
    if (!mKeyEventPool.isEmpty()) {
        KeyEvent* event = mKeyEventPool.top();
        mKeyEventPool.pop();
        return event;
    }
    return new KeyEvent();
}

MotionEvent* PooledInputEventFactory::createMotionEvent() {
    if (!mMotionEventPool.isEmpty()) {
        MotionEvent* event = mMotionEventPool.top();
        mMotionEventPool.pop();
        return event;
    }
    return new MotionEvent();
}

void PooledInputEventFactory::recycle(InputEvent* event) {
    switch (event->getType()) {
    case AINPUT_EVENT_TYPE_KEY:
        if (mKeyEventPool.size() < mMaxPoolSize) {
            mKeyEventPool.push(static_cast<KeyEvent*>(event));
            return;
        }
        break;
    case AINPUT_EVENT_TYPE_MOTION:
        if (mMotionEventPool.size() < mMaxPoolSize) {
            mMotionEventPool.push(static_cast<MotionEvent*>(event));
            return;
        }
        break;
    }
    delete event;
}


// --- VelocityTracker ---

const uint32_t VelocityTracker::DEFAULT_DEGREE;
Loading