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

Commit 4ec8d832 authored by Wonsik Kim's avatar Wonsik Kim
Browse files

stagefright: prevent component to be stuck on error

Bug: 36818684
Bug: 34983882
Test: Run the command below on Nexus Player overnight:
while true ; do adb shell am instrument -e class 'android.platform.tv.tests.aupt.YouTubeTests'  -w 'android.platform.tv.tests.aupt/android.support.test.aupt.AuptTestRunner' ; done
Test: adb shell am instrument -e size small -w 'android.media.cts/android.support.test.runner.AndroidJUnitRunner'
Change-Id: I9663c3d62d97c3f5db0af6c30f39bb59cbc7e3e7
parent 7d25f0f5
Loading
Loading
Loading
Loading
+71 −12
Original line number Diff line number Diff line
@@ -251,6 +251,7 @@ protected:

    virtual PortMode getPortMode(OMX_U32 portIndex);

    virtual void stateExited();
    virtual bool onMessageReceived(const sp<AMessage> &msg);

    virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
@@ -553,6 +554,7 @@ ACodec::ACodec()
      mTunneled(false),
      mDescribeColorAspectsIndex((OMX_INDEXTYPE)0),
      mDescribeHDRStaticInfoIndex((OMX_INDEXTYPE)0),
      mStateGeneration(0),
      mVendorExtensionsStatus(kExtensionsUnchecked) {
    mUninitializedState = new UninitializedState(this);
    mLoadedState = new LoadedState(this);
@@ -5322,6 +5324,10 @@ ACodec::BaseState::PortMode ACodec::BaseState::getPortMode(
    return KEEP_BUFFERS;
}

void ACodec::BaseState::stateExited() {
    ++mCodec->mStateGeneration;
}

bool ACodec::BaseState::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case kWhatInputBufferFilled:
@@ -5398,6 +5404,12 @@ bool ACodec::BaseState::onMessageReceived(const sp<AMessage> &msg) {
            break;
        }

        case ACodec::kWhatForceStateTransition:
        {
            ALOGV("Already transitioned --- ignore");
            break;
        }

        default:
            return false;
    }
@@ -6988,7 +7000,6 @@ void ACodec::ExecutingState::resume() {

void ACodec::ExecutingState::stateEntered() {
    ALOGV("[%s] Now Executing", mCodec->mComponentName.c_str());

    mCodec->mRenderTracker.clear(systemTime(CLOCK_MONOTONIC));
    mCodec->processDeferredMessages();
}
@@ -7614,6 +7625,30 @@ void ACodec::onSignalEndOfInputStream() {
    mCallback->onSignaledInputEOS(err);
}

void ACodec::forceStateTransition(int generation) {
    if (generation != mStateGeneration) {
        ALOGV("Ignoring stale force state transition message: #%d (now #%d)",
                generation, mStateGeneration);
        return;
    }
    ALOGE("State machine stuck");
    // Error must have already been signalled to the client.

    // Deferred messages will be handled at LoadedState at the end of the
    // transition.
    mShutdownInProgress = true;
    // No shutdown complete callback at the end of the transition.
    mExplicitShutdown = false;
    mKeepComponentAllocated = true;

    status_t err = mOMXNode->sendCommand(OMX_CommandStateSet, OMX_StateIdle);
    if (err != OK) {
        // TODO: do some recovery here.
    } else {
        changeState(mExecutingToIdleState);
    }
}

bool ACodec::ExecutingState::onOMXFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano) {
    mCodec->onFrameRendered(mediaTimeUs, systemNano);
    return true;
@@ -7680,7 +7715,14 @@ bool ACodec::OutputPortSettingsChangedState::onMessageReceived(

    switch (msg->what()) {
        case kWhatFlush:
        case kWhatShutdown:
        case kWhatShutdown: {
            if (mCodec->mFatalError) {
                sp<AMessage> msg = new AMessage(ACodec::kWhatForceStateTransition, mCodec);
                msg->setInt32("generation", mCodec->mStateGeneration);
                msg->post(3000000);
            }
            // fall-through
        }
        case kWhatResume:
        case kWhatSetParameters:
        {
@@ -7693,6 +7735,16 @@ bool ACodec::OutputPortSettingsChangedState::onMessageReceived(
            break;
        }

        case kWhatForceStateTransition:
        {
            int32_t generation = 0;
            CHECK(msg->findInt32("generation", &generation));
            mCodec->forceStateTransition(generation);

            handled = true;
            break;
        }

        default:
            handled = BaseState::onMessageReceived(msg);
            break;
@@ -7752,15 +7804,7 @@ bool ACodec::OutputPortSettingsChangedState::onOMXEvent(

                if (err != OK) {
                    mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));

                    // This is technically not correct, but appears to be
                    // the only way to free the component instance.
                    // Controlled transitioning from excecuting->idle
                    // and idle->loaded seem impossible probably because
                    // the output port never finishes re-enabling.
                    mCodec->mShutdownInProgress = true;
                    mCodec->mKeepComponentAllocated = false;
                    mCodec->changeState(mCodec->mLoadedState);
                    ALOGE("Error occurred while disabling the output port");
                }

                return true;
@@ -7785,7 +7829,7 @@ bool ACodec::OutputPortSettingsChangedState::onOMXEvent(
        }

        default:
            return false;
            return BaseState::onOMXEvent(event, data1, data2);
    }
}

@@ -7987,6 +8031,11 @@ bool ACodec::FlushingState::onMessageReceived(const sp<AMessage> &msg) {
        case kWhatShutdown:
        {
            mCodec->deferMessage(msg);
            if (mCodec->mFatalError) {
                sp<AMessage> msg = new AMessage(ACodec::kWhatForceStateTransition, mCodec);
                msg->setInt32("generation", mCodec->mStateGeneration);
                msg->post(3000000);
            }
            break;
        }

@@ -7997,6 +8046,16 @@ bool ACodec::FlushingState::onMessageReceived(const sp<AMessage> &msg) {
            break;
        }

        case kWhatForceStateTransition:
        {
            int32_t generation = 0;
            CHECK(msg->findInt32("generation", &generation));
            mCodec->forceStateTransition(generation);

            handled = true;
            break;
        }

        default:
            handled = BaseState::onMessageReceived(msg);
            break;
+6 −0
Original line number Diff line number Diff line
@@ -150,6 +150,7 @@ private:
        kWhatSubmitOutputMetadataBufferIfEOS = 'subm',
        kWhatOMXDied                 = 'OMXd',
        kWhatReleaseCodecInstance    = 'relC',
        kWhatForceStateTransition    = 'fstt',
    };

    enum {
@@ -305,6 +306,8 @@ private:

    std::shared_ptr<ACodecBufferChannel> mBufferChannel;

    int32_t mStateGeneration;

    enum {
        kExtensionsUnchecked,
        kExtensionsNone,
@@ -569,6 +572,9 @@ private:
    // Send EOS on input stream.
    void onSignalEndOfInputStream();

    // Force EXEC->IDLE->LOADED shutdown sequence if not stale.
    void forceStateTransition(int generation);

    DISALLOW_EVIL_CONSTRUCTORS(ACodec);
};