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

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

Merge "Fix possible race conditions during channel unregistration." into gingerbread

parents 72722ec4 0cacb87f
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -554,6 +554,8 @@ private:
    // All registered connections mapped by receive pipe file descriptor.
    // All registered connections mapped by receive pipe file descriptor.
    KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
    KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;


    ssize_t getConnectionIndex(const sp<InputChannel>& inputChannel);

    // Active connections are connections that have a non-empty outbound queue.
    // Active connections are connections that have a non-empty outbound queue.
    // We don't use a ref-counted pointer here because we explicitly abort connections
    // We don't use a ref-counted pointer here because we explicitly abort connections
    // during unregistration which causes the connection's outbound queue to be cleared
    // during unregistration which causes the connection's outbound queue to be cleared
+20 −12
Original line number Original line Diff line number Diff line
@@ -433,8 +433,7 @@ void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTi
    for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
    for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
        const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i);
        const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i);


        ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(
        ssize_t connectionIndex = getConnectionIndex(inputTarget.inputChannel);
                inputTarget.inputChannel->getReceivePipeFd());
        if (connectionIndex >= 0) {
        if (connectionIndex >= 0) {
            sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
            sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
            prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget,
            prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget,
@@ -1367,12 +1366,10 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan
    LOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().string());
    LOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().string());
#endif
#endif


    int receiveFd;
    { // acquire lock
    { // acquire lock
        AutoMutex _l(mLock);
        AutoMutex _l(mLock);


        receiveFd = inputChannel->getReceivePipeFd();
        if (getConnectionIndex(inputChannel) >= 0) {
        if (mConnectionsByReceiveFd.indexOfKey(receiveFd) >= 0) {
            LOGW("Attempted to register already registered input channel '%s'",
            LOGW("Attempted to register already registered input channel '%s'",
                    inputChannel->getName().string());
                    inputChannel->getName().string());
            return BAD_VALUE;
            return BAD_VALUE;
@@ -1386,12 +1383,13 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan
            return status;
            return status;
        }
        }


        int32_t receiveFd = inputChannel->getReceivePipeFd();
        mConnectionsByReceiveFd.add(receiveFd, connection);
        mConnectionsByReceiveFd.add(receiveFd, connection);


        mPollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);

        runCommandsLockedInterruptible();
        runCommandsLockedInterruptible();
    } // release lock
    } // release lock

    mPollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
    return OK;
    return OK;
}
}


@@ -1400,12 +1398,10 @@ status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputCh
    LOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().string());
    LOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().string());
#endif
#endif


    int32_t receiveFd;
    { // acquire lock
    { // acquire lock
        AutoMutex _l(mLock);
        AutoMutex _l(mLock);


        receiveFd = inputChannel->getReceivePipeFd();
        ssize_t connectionIndex = getConnectionIndex(inputChannel);
        ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(receiveFd);
        if (connectionIndex < 0) {
        if (connectionIndex < 0) {
            LOGW("Attempted to unregister already unregistered input channel '%s'",
            LOGW("Attempted to unregister already unregistered input channel '%s'",
                    inputChannel->getName().string());
                    inputChannel->getName().string());
@@ -1417,20 +1413,32 @@ status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputCh


        connection->status = Connection::STATUS_ZOMBIE;
        connection->status = Connection::STATUS_ZOMBIE;


        mPollLoop->removeCallback(inputChannel->getReceivePipeFd());

        nsecs_t currentTime = now();
        nsecs_t currentTime = now();
        abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
        abortDispatchCycleLocked(currentTime, connection, true /*broken*/);


        runCommandsLockedInterruptible();
        runCommandsLockedInterruptible();
    } // release lock
    } // release lock


    mPollLoop->removeCallback(receiveFd);

    // Wake the poll loop because removing the connection may have changed the current
    // Wake the poll loop because removing the connection may have changed the current
    // synchronization state.
    // synchronization state.
    mPollLoop->wake();
    mPollLoop->wake();
    return OK;
    return OK;
}
}


ssize_t InputDispatcher::getConnectionIndex(const sp<InputChannel>& inputChannel) {
    ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(inputChannel->getReceivePipeFd());
    if (connectionIndex >= 0) {
        sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
        if (connection->inputChannel.get() == inputChannel.get()) {
            return connectionIndex;
        }
    }

    return -1;
}

void InputDispatcher::activateConnectionLocked(Connection* connection) {
void InputDispatcher::activateConnectionLocked(Connection* connection) {
    for (size_t i = 0; i < mActiveConnections.size(); i++) {
    for (size_t i = 0; i < mActiveConnections.size(); i++) {
        if (mActiveConnections.itemAt(i) == connection) {
        if (mActiveConnections.itemAt(i) == connection) {