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

Commit f6c9c5bd authored by Wonsik Kim's avatar Wonsik Kim
Browse files

MediaCodec: ensure reply does not get lost

The following operations store mReplyID to wait for a codec event
before replying:

- init, configure, start, flush, stop:
  These operations causes state transitions.
  Defer if mReplyID is set.
  When handling operation complete event, check current state and
  don't reply if the state is not an expected value.

- signalEOS, createInputSurface, setInputSurface:
  These operations do not cause state transitions.
  Defer if mReplyID is set.
  When handling operation complete event, check current state and
  don't reply if the state is not an expected value.

- release:
  Release is special, as we want to release even if we are in the middle
  of handling other operations.
  Reply to current operation to unblock app and start releasing.
  Release complete event is always handled.

Bug: 154678891
Test: atest CtsMediaTestCases -- --module-arg CtsMediaTestCases:size:small
Change-Id: I08286bffb13150813a1d237e49ab1bbf8f544f32
parent 9900ec1c
Loading
Loading
Loading
Loading
+157 −47
Original line number Original line Diff line number Diff line
@@ -1008,6 +1008,12 @@ status_t MediaCodec::PostAndAwaitResponse(
    return err;
    return err;
}
}


void MediaCodec::PostReplyWithError(const sp<AMessage> &msg, int32_t err) {
    sp<AReplyToken> replyID;
    CHECK(msg->senderAwaitsResponse(&replyID));
    PostReplyWithError(replyID, err);
}

void MediaCodec::PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err) {
void MediaCodec::PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err) {
    int32_t finalErr = err;
    int32_t finalErr = err;
    if (mReleasedByResourceManager) {
    if (mReleasedByResourceManager) {
@@ -1511,7 +1517,6 @@ status_t MediaCodec::reset() {
    mStickyError = OK;
    mStickyError = OK;


    // reset state not reset by setState(UNINITIALIZED)
    // reset state not reset by setState(UNINITIALIZED)
    mReplyID = 0;
    mDequeueInputReplyID = 0;
    mDequeueInputReplyID = 0;
    mDequeueOutputReplyID = 0;
    mDequeueOutputReplyID = 0;
    mDequeueInputTimeoutGeneration = 0;
    mDequeueInputTimeoutGeneration = 0;
@@ -2159,7 +2164,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                                if (mState == RELEASING) {
                                if (mState == RELEASING) {
                                    mComponentName.clear();
                                    mComponentName.clear();
                                }
                                }
                                (new AMessage)->postReply(mReplyID);
                                postPendingRepliesAndDeferredMessages();
                                sendErrorResponse = false;
                                sendErrorResponse = false;
                            }
                            }
                            break;
                            break;
@@ -2185,7 +2190,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                        case FLUSHED:
                        case FLUSHED:
                        case STARTED:
                        case STARTED:
                        {
                        {
                            sendErrorResponse = false;
                            sendErrorResponse = (mReplyID != nullptr);


                            setStickyError(err);
                            setStickyError(err);
                            postActivityNotificationIfPossible();
                            postActivityNotificationIfPossible();
@@ -2215,7 +2220,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {


                        default:
                        default:
                        {
                        {
                            sendErrorResponse = false;
                            sendErrorResponse = (mReplyID != nullptr);


                            setStickyError(err);
                            setStickyError(err);
                            postActivityNotificationIfPossible();
                            postActivityNotificationIfPossible();
@@ -2242,7 +2247,15 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                    }
                    }


                    if (sendErrorResponse) {
                    if (sendErrorResponse) {
                        PostReplyWithError(mReplyID, err);
                        // TRICKY: replicate PostReplyWithError logic for
                        //         err code override
                        int32_t finalErr = err;
                        if (mReleasedByResourceManager) {
                            // override the err code if MediaCodec has been
                            // released by ResourceManager.
                            finalErr = DEAD_OBJECT;
                        }
                        postPendingRepliesAndDeferredMessages(finalErr);
                    }
                    }
                    break;
                    break;
                }
                }
@@ -2290,7 +2303,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                                MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
                                MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
                    }
                    }


                    (new AMessage)->postReply(mReplyID);
                    postPendingRepliesAndDeferredMessages();
                    break;
                    break;
                }
                }


@@ -2329,7 +2342,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                        mFlags |= kFlagUsesSoftwareRenderer;
                        mFlags |= kFlagUsesSoftwareRenderer;
                    }
                    }
                    setState(CONFIGURED);
                    setState(CONFIGURED);
                    (new AMessage)->postReply(mReplyID);
                    postPendingRepliesAndDeferredMessages();


                    // augment our media metrics info, now that we know more things
                    // augment our media metrics info, now that we know more things
                    // such as what the codec extracted from any CSD passed in.
                    // such as what the codec extracted from any CSD passed in.
@@ -2374,6 +2387,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {


                case kWhatInputSurfaceCreated:
                case kWhatInputSurfaceCreated:
                {
                {
                    if (mState != CONFIGURED) {
                        // state transitioned unexpectedly; we should have replied already.
                        ALOGD("received kWhatInputSurfaceCreated message in state %s",
                                stateString(mState).c_str());
                        break;
                    }
                    // response to initiateCreateInputSurface()
                    // response to initiateCreateInputSurface()
                    status_t err = NO_ERROR;
                    status_t err = NO_ERROR;
                    sp<AMessage> response = new AMessage;
                    sp<AMessage> response = new AMessage;
@@ -2392,12 +2411,18 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                    } else {
                    } else {
                        response->setInt32("err", err);
                        response->setInt32("err", err);
                    }
                    }
                    response->postReply(mReplyID);
                    postPendingRepliesAndDeferredMessages(response);
                    break;
                    break;
                }
                }


                case kWhatInputSurfaceAccepted:
                case kWhatInputSurfaceAccepted:
                {
                {
                    if (mState != CONFIGURED) {
                        // state transitioned unexpectedly; we should have replied already.
                        ALOGD("received kWhatInputSurfaceAccepted message in state %s",
                                stateString(mState).c_str());
                        break;
                    }
                    // response to initiateSetInputSurface()
                    // response to initiateSetInputSurface()
                    status_t err = NO_ERROR;
                    status_t err = NO_ERROR;
                    sp<AMessage> response = new AMessage();
                    sp<AMessage> response = new AMessage();
@@ -2408,19 +2433,25 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                    } else {
                    } else {
                        response->setInt32("err", err);
                        response->setInt32("err", err);
                    }
                    }
                    response->postReply(mReplyID);
                    postPendingRepliesAndDeferredMessages(response);
                    break;
                    break;
                }
                }


                case kWhatSignaledInputEOS:
                case kWhatSignaledInputEOS:
                {
                {
                    if (!isExecuting()) {
                        // state transitioned unexpectedly; we should have replied already.
                        ALOGD("received kWhatSignaledInputEOS message in state %s",
                                stateString(mState).c_str());
                        break;
                    }
                    // response to signalEndOfInputStream()
                    // response to signalEndOfInputStream()
                    sp<AMessage> response = new AMessage;
                    sp<AMessage> response = new AMessage;
                    status_t err;
                    status_t err;
                    if (msg->findInt32("err", &err)) {
                    if (msg->findInt32("err", &err)) {
                        response->setInt32("err", err);
                        response->setInt32("err", err);
                    }
                    }
                    response->postReply(mReplyID);
                    postPendingRepliesAndDeferredMessages(response);
                    break;
                    break;
                }
                }


@@ -2439,7 +2470,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                                MediaResource::GraphicMemoryResource(getGraphicBufferSize()));
                                MediaResource::GraphicMemoryResource(getGraphicBufferSize()));
                    }
                    }
                    setState(STARTED);
                    setState(STARTED);
                    (new AMessage)->postReply(mReplyID);
                    postPendingRepliesAndDeferredMessages();
                    break;
                    break;
                }
                }


@@ -2669,7 +2700,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                        break;
                        break;
                    }
                    }
                    setState(INITIALIZED);
                    setState(INITIALIZED);
                    (new AMessage)->postReply(mReplyID);
                    postPendingRepliesAndDeferredMessages();
                    break;
                    break;
                }
                }


@@ -2693,7 +2724,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                    mReleaseSurface.reset();
                    mReleaseSurface.reset();


                    if (mReplyID != nullptr) {
                    if (mReplyID != nullptr) {
                        (new AMessage)->postReply(mReplyID);
                        postPendingRepliesAndDeferredMessages();
                    }
                    }
                    if (mAsyncReleaseCompleteNotification != nullptr) {
                    if (mAsyncReleaseCompleteNotification != nullptr) {
                        flushMediametrics();
                        flushMediametrics();
@@ -2718,7 +2749,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                        mCodec->signalResume();
                        mCodec->signalResume();
                    }
                    }


                    (new AMessage)->postReply(mReplyID);
                    postPendingRepliesAndDeferredMessages();
                    break;
                    break;
                }
                }


@@ -2730,14 +2761,18 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {


        case kWhatInit:
        case kWhatInit:
        {
        {
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            if (mState != UNINITIALIZED) {
            if (mState != UNINITIALIZED) {
                PostReplyWithError(replyID, INVALID_OPERATION);
                PostReplyWithError(msg, INVALID_OPERATION);
                break;
                break;
            }
            }


            if (mReplyID) {
                mDeferredMessages.push_back(msg);
                break;
            }
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            mReplyID = replyID;
            mReplyID = replyID;
            setState(INITIALIZING);
            setState(INITIALIZING);


@@ -2799,13 +2834,17 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {


        case kWhatConfigure:
        case kWhatConfigure:
        {
        {
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            if (mState != INITIALIZED) {
            if (mState != INITIALIZED) {
                PostReplyWithError(replyID, INVALID_OPERATION);
                PostReplyWithError(msg, INVALID_OPERATION);
                break;
            }

            if (mReplyID) {
                mDeferredMessages.push_back(msg);
                break;
                break;
            }
            }
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));


            sp<RefBase> obj;
            sp<RefBase> obj;
            CHECK(msg->findObject("surface", &obj));
            CHECK(msg->findObject("surface", &obj));
@@ -2944,14 +2983,18 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
        case kWhatCreateInputSurface:
        case kWhatCreateInputSurface:
        case kWhatSetInputSurface:
        case kWhatSetInputSurface:
        {
        {
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            // Must be configured, but can't have been started yet.
            // Must be configured, but can't have been started yet.
            if (mState != CONFIGURED) {
            if (mState != CONFIGURED) {
                PostReplyWithError(replyID, INVALID_OPERATION);
                PostReplyWithError(msg, INVALID_OPERATION);
                break;
            }

            if (mReplyID) {
                mDeferredMessages.push_back(msg);
                break;
                break;
            }
            }
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));


            mReplyID = replyID;
            mReplyID = replyID;
            if (msg->what() == kWhatCreateInputSurface) {
            if (msg->what() == kWhatCreateInputSurface) {
@@ -2967,9 +3010,6 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
        }
        }
        case kWhatStart:
        case kWhatStart:
        {
        {
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            if (mState == FLUSHED) {
            if (mState == FLUSHED) {
                setState(STARTED);
                setState(STARTED);
                if (mHavePendingInputBuffers) {
                if (mHavePendingInputBuffers) {
@@ -2977,12 +3017,19 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                    mHavePendingInputBuffers = false;
                    mHavePendingInputBuffers = false;
                }
                }
                mCodec->signalResume();
                mCodec->signalResume();
                PostReplyWithError(replyID, OK);
                PostReplyWithError(msg, OK);
                break;
                break;
            } else if (mState != CONFIGURED) {
            } else if (mState != CONFIGURED) {
                PostReplyWithError(replyID, INVALID_OPERATION);
                PostReplyWithError(msg, INVALID_OPERATION);
                break;
            }

            if (mReplyID) {
                mDeferredMessages.push_back(msg);
                break;
                break;
            }
            }
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));


            mReplyID = replyID;
            mReplyID = replyID;
            setState(STARTING);
            setState(STARTING);
@@ -2991,15 +3038,42 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
            break;
            break;
        }
        }


        case kWhatStop:
        case kWhatStop: {
            if (mReplyID) {
                mDeferredMessages.push_back(msg);
                break;
            }
            [[fallthrough]];
        }
        case kWhatRelease:
        case kWhatRelease:
        {
        {
            State targetState =
            State targetState =
                (msg->what() == kWhatStop) ? INITIALIZED : UNINITIALIZED;
                (msg->what() == kWhatStop) ? INITIALIZED : UNINITIALIZED;


            if ((mState == RELEASING && targetState == UNINITIALIZED)
                    || (mState == STOPPING && targetState == INITIALIZED)) {
                mDeferredMessages.push_back(msg);
                break;
            }

            sp<AReplyToken> replyID;
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));
            CHECK(msg->senderAwaitsResponse(&replyID));


            sp<AMessage> asyncNotify;
            (void)msg->findMessage("async", &asyncNotify);
            // post asyncNotify if going out of scope.
            struct AsyncNotifyPost {
                AsyncNotifyPost(const sp<AMessage> &asyncNotify) : mAsyncNotify(asyncNotify) {}
                ~AsyncNotifyPost() {
                    if (mAsyncNotify) {
                        mAsyncNotify->post();
                    }
                }
                void clear() { mAsyncNotify.clear(); }
            private:
                sp<AMessage> mAsyncNotify;
            } asyncNotifyPost{asyncNotify};

            // already stopped/released
            // already stopped/released
            if (mState == UNINITIALIZED && mReleasedByResourceManager) {
            if (mState == UNINITIALIZED && mReleasedByResourceManager) {
                sp<AMessage> response = new AMessage;
                sp<AMessage> response = new AMessage;
@@ -3063,12 +3137,14 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
            // after this, and we'll no longer be able to reply.
            // after this, and we'll no longer be able to reply.
            if (mState == FLUSHING || mState == STOPPING
            if (mState == FLUSHING || mState == STOPPING
                    || mState == CONFIGURING || mState == STARTING) {
                    || mState == CONFIGURING || mState == STARTING) {
                (new AMessage)->postReply(mReplyID);
                // mReply is always set if in these states.
                postPendingRepliesAndDeferredMessages();
            }
            }


            if (mFlags & kFlagSawMediaServerDie) {
            if (mFlags & kFlagSawMediaServerDie) {
                // It's dead, Jim. Don't expect initiateShutdown to yield
                // It's dead, Jim. Don't expect initiateShutdown to yield
                // any useful results now...
                // any useful results now...
                // Any pending reply would have been handled at kWhatError.
                setState(UNINITIALIZED);
                setState(UNINITIALIZED);
                if (targetState == UNINITIALIZED) {
                if (targetState == UNINITIALIZED) {
                    mComponentName.clear();
                    mComponentName.clear();
@@ -3082,12 +3158,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
            // reply now with an error to unblock the client, client can
            // reply now with an error to unblock the client, client can
            // release after the failure (instead of ANR).
            // release after the failure (instead of ANR).
            if (msg->what() == kWhatStop && (mFlags & kFlagStickyError)) {
            if (msg->what() == kWhatStop && (mFlags & kFlagStickyError)) {
                // Any pending reply would have been handled at kWhatError.
                PostReplyWithError(replyID, getStickyError());
                PostReplyWithError(replyID, getStickyError());
                break;
                break;
            }
            }


            sp<AMessage> asyncNotify;
            if (asyncNotify != nullptr) {
            if (msg->findMessage("async", &asyncNotify) && asyncNotify != nullptr) {
                if (mSurface != NULL) {
                if (mSurface != NULL) {
                    if (!mReleaseSurface) {
                    if (!mReleaseSurface) {
                        mReleaseSurface.reset(new ReleaseSurface);
                        mReleaseSurface.reset(new ReleaseSurface);
@@ -3107,6 +3183,12 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
                }
                }
            }
            }


            if (mReplyID) {
                // State transition replies are handled above, so this reply
                // would not be related to state transition. As we are
                // shutting down the component, just fail the operation.
                postPendingRepliesAndDeferredMessages(UNKNOWN_ERROR);
            }
            mReplyID = replyID;
            mReplyID = replyID;
            setState(msg->what() == kWhatStop ? STOPPING : RELEASING);
            setState(msg->what() == kWhatStop ? STOPPING : RELEASING);


@@ -3121,8 +3203,8 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {


            if (asyncNotify != nullptr) {
            if (asyncNotify != nullptr) {
                mResourceManagerProxy->markClientForPendingRemoval();
                mResourceManagerProxy->markClientForPendingRemoval();
                (new AMessage)->postReply(mReplyID);
                postPendingRepliesAndDeferredMessages();
                mReplyID = 0;
                asyncNotifyPost.clear();
                mAsyncReleaseCompleteNotification = asyncNotify;
                mAsyncReleaseCompleteNotification = asyncNotify;
            }
            }


@@ -3293,17 +3375,21 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {


        case kWhatSignalEndOfInputStream:
        case kWhatSignalEndOfInputStream:
        {
        {
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            if (!isExecuting() || !mHaveInputSurface) {
            if (!isExecuting() || !mHaveInputSurface) {
                PostReplyWithError(replyID, INVALID_OPERATION);
                PostReplyWithError(msg, INVALID_OPERATION);
                break;
                break;
            } else if (mFlags & kFlagStickyError) {
            } else if (mFlags & kFlagStickyError) {
                PostReplyWithError(replyID, getStickyError());
                PostReplyWithError(msg, getStickyError());
                break;
                break;
            }
            }


            if (mReplyID) {
                mDeferredMessages.push_back(msg);
                break;
            }
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            mReplyID = replyID;
            mReplyID = replyID;
            mCodec->signalEndOfInputStream();
            mCodec->signalEndOfInputStream();
            break;
            break;
@@ -3345,16 +3431,20 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {


        case kWhatFlush:
        case kWhatFlush:
        {
        {
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));

            if (!isExecuting()) {
            if (!isExecuting()) {
                PostReplyWithError(replyID, INVALID_OPERATION);
                PostReplyWithError(msg, INVALID_OPERATION);
                break;
                break;
            } else if (mFlags & kFlagStickyError) {
            } else if (mFlags & kFlagStickyError) {
                PostReplyWithError(replyID, getStickyError());
                PostReplyWithError(msg, getStickyError());
                break;
            }

            if (mReplyID) {
                mDeferredMessages.push_back(msg);
                break;
                break;
            }
            }
            sp<AReplyToken> replyID;
            CHECK(msg->senderAwaitsResponse(&replyID));


            mReplyID = replyID;
            mReplyID = replyID;
            // TODO: skip flushing if already FLUSHED
            // TODO: skip flushing if already FLUSHED
@@ -4188,6 +4278,26 @@ status_t MediaCodec::amendOutputFormatWithCodecSpecificData(
    return OK;
    return OK;
}
}


void MediaCodec::postPendingRepliesAndDeferredMessages(status_t err /* = OK */) {
    sp<AMessage> response{new AMessage};
    if (err != OK) {
        response->setInt32("err", err);
    }
    postPendingRepliesAndDeferredMessages(response);
}

void MediaCodec::postPendingRepliesAndDeferredMessages(const sp<AMessage> &response) {
    CHECK(mReplyID);
    response->postReply(mReplyID);
    mReplyID.clear();
    ALOGV_IF(!mDeferredMessages.empty(),
            "posting %zu deferred messages", mDeferredMessages.size());
    for (sp<AMessage> msg : mDeferredMessages) {
        msg->post();
    }
    mDeferredMessages.clear();
}

std::string MediaCodec::stateString(State state) {
std::string MediaCodec::stateString(State state) {
    const char *rval = NULL;
    const char *rval = NULL;
    char rawbuffer[16]; // room for "%d"
    char rawbuffer[16]; // room for "%d"
+5 −0
Original line number Original line Diff line number Diff line
@@ -366,6 +366,7 @@ private:
    AString mOwnerName;
    AString mOwnerName;
    sp<MediaCodecInfo> mCodecInfo;
    sp<MediaCodecInfo> mCodecInfo;
    sp<AReplyToken> mReplyID;
    sp<AReplyToken> mReplyID;
    std::vector<sp<AMessage>> mDeferredMessages;
    uint32_t mFlags;
    uint32_t mFlags;
    status_t mStickyError;
    status_t mStickyError;
    sp<Surface> mSurface;
    sp<Surface> mSurface;
@@ -435,6 +436,7 @@ private:
    static status_t PostAndAwaitResponse(
    static status_t PostAndAwaitResponse(
            const sp<AMessage> &msg, sp<AMessage> *response);
            const sp<AMessage> &msg, sp<AMessage> *response);


    void PostReplyWithError(const sp<AMessage> &msg, int32_t err);
    void PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err);
    void PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err);


    status_t init(const AString &name);
    status_t init(const AString &name);
@@ -484,6 +486,9 @@ private:
    bool hasPendingBuffer(int portIndex);
    bool hasPendingBuffer(int portIndex);
    bool hasPendingBuffer();
    bool hasPendingBuffer();


    void postPendingRepliesAndDeferredMessages(status_t err = OK);
    void postPendingRepliesAndDeferredMessages(const sp<AMessage> &response);

    /* called to get the last codec error when the sticky flag is set.
    /* called to get the last codec error when the sticky flag is set.
     * if no such codec error is found, returns UNKNOWN_ERROR.
     * if no such codec error is found, returns UNKNOWN_ERROR.
     */
     */