Loading media/libstagefright/MediaCodec.cpp +4 −3 Original line number Diff line number Diff line Loading @@ -3061,10 +3061,8 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case STOPPING: { if (mFlags & kFlagSawMediaServerDie) { bool postPendingReplies = true; if (mState == RELEASING && !mReplyID) { ALOGD("Releasing asynchronously, so nothing to reply here."); postPendingReplies = false; } // MediaServer died, there definitely won't // be a shutdown complete notification after Loading @@ -3077,8 +3075,11 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { if (mState == RELEASING) { mComponentName.clear(); } if (postPendingReplies) { if (mReplyID) { postPendingRepliesAndDeferredMessages(origin + ":dead"); } else { ALOGD("no pending replies: %s:dead following %s", origin.c_str(), mLastReplyOrigin.c_str()); } sendErrorResponse = false; } else if (!mReplyID) { Loading media/libstagefright/tests/mediacodec/MediaCodecTest.cpp +48 −0 Original line number Diff line number Diff line Loading @@ -393,3 +393,51 @@ TEST(MediaCodecTest, DeadWhileAsyncReleasing) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); looper->stop(); } TEST(MediaCodecTest, DeadWhileStoppingError) { // Test scenario: // // 1) Client thread calls stop(); MediaCodec looper thread calls // initiateShutdown(); shutdown is being handled at the component thread. // 2) An error occurs while handling initiateShutdown(). // 3) MediaCodec looper thread handles the error. // 4) Codec service dies after the error is handled // 5) MediaCodec looper thread handles the death. static const AString kCodecName{"test.codec"}; static const AString kCodecOwner{"nobody"}; static const AString kMediaType{"video/x-test"}; sp<MockCodec> mockCodec; std::function<sp<CodecBase>(const AString &name, const char *owner)> getCodecBase = [&mockCodec](const AString &, const char *) { mockCodec = new MockCodec([](const std::shared_ptr<MockBufferChannel> &) { // No mock setup, as we don't expect any buffer operations // in this scenario. }); ON_CALL(*mockCodec, initiateAllocateComponent(_)) .WillByDefault([mockCodec](const sp<AMessage> &) { mockCodec->callback()->onComponentAllocated(kCodecName.c_str()); }); ON_CALL(*mockCodec, initiateShutdown(_)) .WillByDefault([mockCodec](bool) { // 2) mockCodec->callback()->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); // 4) mockCodec->callback()->onError(DEAD_OBJECT, ACTION_CODE_FATAL); // Codec service has died, no callback. }); return mockCodec; }; sp<ALooper> looper{new ALooper}; sp<MediaCodec> codec = SetupMediaCodec( kCodecOwner, kCodecName, kMediaType, looper, getCodecBase); ASSERT_NE(nullptr, codec) << "Codec must not be null"; ASSERT_NE(nullptr, mockCodec) << "MockCodec must not be null"; codec->stop(); // sleep here so that the looper thread can handle the error std::this_thread::sleep_for(std::chrono::milliseconds(100)); looper->stop(); } Loading
media/libstagefright/MediaCodec.cpp +4 −3 Original line number Diff line number Diff line Loading @@ -3061,10 +3061,8 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { case STOPPING: { if (mFlags & kFlagSawMediaServerDie) { bool postPendingReplies = true; if (mState == RELEASING && !mReplyID) { ALOGD("Releasing asynchronously, so nothing to reply here."); postPendingReplies = false; } // MediaServer died, there definitely won't // be a shutdown complete notification after Loading @@ -3077,8 +3075,11 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { if (mState == RELEASING) { mComponentName.clear(); } if (postPendingReplies) { if (mReplyID) { postPendingRepliesAndDeferredMessages(origin + ":dead"); } else { ALOGD("no pending replies: %s:dead following %s", origin.c_str(), mLastReplyOrigin.c_str()); } sendErrorResponse = false; } else if (!mReplyID) { Loading
media/libstagefright/tests/mediacodec/MediaCodecTest.cpp +48 −0 Original line number Diff line number Diff line Loading @@ -393,3 +393,51 @@ TEST(MediaCodecTest, DeadWhileAsyncReleasing) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); looper->stop(); } TEST(MediaCodecTest, DeadWhileStoppingError) { // Test scenario: // // 1) Client thread calls stop(); MediaCodec looper thread calls // initiateShutdown(); shutdown is being handled at the component thread. // 2) An error occurs while handling initiateShutdown(). // 3) MediaCodec looper thread handles the error. // 4) Codec service dies after the error is handled // 5) MediaCodec looper thread handles the death. static const AString kCodecName{"test.codec"}; static const AString kCodecOwner{"nobody"}; static const AString kMediaType{"video/x-test"}; sp<MockCodec> mockCodec; std::function<sp<CodecBase>(const AString &name, const char *owner)> getCodecBase = [&mockCodec](const AString &, const char *) { mockCodec = new MockCodec([](const std::shared_ptr<MockBufferChannel> &) { // No mock setup, as we don't expect any buffer operations // in this scenario. }); ON_CALL(*mockCodec, initiateAllocateComponent(_)) .WillByDefault([mockCodec](const sp<AMessage> &) { mockCodec->callback()->onComponentAllocated(kCodecName.c_str()); }); ON_CALL(*mockCodec, initiateShutdown(_)) .WillByDefault([mockCodec](bool) { // 2) mockCodec->callback()->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); // 4) mockCodec->callback()->onError(DEAD_OBJECT, ACTION_CODE_FATAL); // Codec service has died, no callback. }); return mockCodec; }; sp<ALooper> looper{new ALooper}; sp<MediaCodec> codec = SetupMediaCodec( kCodecOwner, kCodecName, kMediaType, looper, getCodecBase); ASSERT_NE(nullptr, codec) << "Codec must not be null"; ASSERT_NE(nullptr, mockCodec) << "MockCodec must not be null"; codec->stop(); // sleep here so that the looper thread can handle the error std::this_thread::sleep_for(std::chrono::milliseconds(100)); looper->stop(); }