CCodec: detect and report error when work processing is stuck
Bug: 110799227
Test: atest CtsSecurityTestCases:StagefrightTest
Test: atest CtsMediaTestCases:EncodeDecodeTest \
CtsMediaTestCases:EncodeVirtualDisplayTest \
CtsMediaTestCases:EncodeVirtualDisplayWithCompositionTest \
CtsMediaTestCases:MediaCasTest \
CtsMediaTestCases:MediaCodecListTest \
CtsMediaTestCases:MediaCodecTest \
CtsMediaTestCases:MediaMetadataRetrieverTest \
CtsMediaTestCases:MediaPlayerDrmTest \
CtsMediaTestCases:MediaPlayerSurfaceTest \
CtsMediaTestCases:MediaRecorderTest \
CtsMediaTestCases:MediaScannerTest \
CtsMediaTestCases:ResourceManagerTest
Change-Id: Id3c20b6ff35b5d38e9dd30f41a678023fc418ed2
diff --git a/media/sfplugin/CCodec.cpp b/media/sfplugin/CCodec.cpp
index 4dac6e7..43247d6 100644
--- a/media/sfplugin/CCodec.cpp
+++ b/media/sfplugin/CCodec.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
#define LOG_TAG "CCodec"
#include <utils/Log.h>
@@ -490,6 +490,10 @@
{RenderedFrameInfo(mediaTimeUs, renderTimeNs)});
}
+ void onWorkQueued() override {
+ mCodec->onWorkQueued();
+ }
+
private:
CCodec *mCodec;
};
@@ -497,7 +501,8 @@
// CCodec
CCodec::CCodec()
- : mChannel(new CCodecBufferChannel(std::make_shared<CCodecCallbackImpl>(this))) {
+ : mChannel(new CCodecBufferChannel(std::make_shared<CCodecCallbackImpl>(this))),
+ mQueuedWorkCount(0) {
CCodecWatchdog::getInstance()->registerCodec(this);
}
@@ -543,7 +548,7 @@
mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
return;
}
- ALOGV("allocate(%s)", codecInfo->getCodecName());
+ ALOGD("allocate(%s)", codecInfo->getCodecName());
mClientListener.reset(new ClientListener(this));
AString componentName = codecInfo->getCodecName();
@@ -1201,6 +1206,7 @@
}
mChannel->flush(flushedWork);
+ subQueuedWorkCount(flushedWork.size());
{
Mutexed<State>::Locked state(mState);
@@ -1347,6 +1353,7 @@
case kWhatStart: {
// C2Component::start() should return within 500ms.
setDeadline(now + 550ms, "start");
+ mQueuedWorkCount = 0;
start();
break;
}
@@ -1354,6 +1361,10 @@
// C2Component::stop() should return within 500ms.
setDeadline(now + 550ms, "stop");
stop();
+
+ mQueuedWorkCount = 0;
+ Mutexed<NamedTimePoint>::Locked deadline(mQueueDeadline);
+ deadline->set(TimePoint::max(), "none");
break;
}
case kWhatFlush: {
@@ -1398,6 +1409,7 @@
}
}
+ subQueuedWorkCount(1);
// handle configuration changes in work done
Mutexed<Config>::Locked config(mConfig);
bool changed = false;
@@ -1479,11 +1491,19 @@
std::string name;
{
Mutexed<NamedTimePoint>::Locked deadline(mDeadline);
- if (deadline->get() >= std::chrono::steady_clock::now()) {
- // We're not stuck.
- return;
+ if (deadline->get() < std::chrono::steady_clock::now()) {
+ name = deadline->getName();
}
- name = deadline->getName();
+ }
+ {
+ Mutexed<NamedTimePoint>::Locked deadline(mQueueDeadline);
+ if (deadline->get() < std::chrono::steady_clock::now()) {
+ name = deadline->getName();
+ }
+ }
+ if (name.empty()) {
+ // We're not stuck.
+ return;
}
ALOGW("previous call to %s exceeded timeout", name.c_str());
@@ -1491,6 +1511,24 @@
mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
}
+void CCodec::onWorkQueued() {
+ ALOGV("queued work count +1 from %d", mQueuedWorkCount.load());
+ ++mQueuedWorkCount;
+ Mutexed<NamedTimePoint>::Locked deadline(mQueueDeadline);
+ deadline->set(std::chrono::steady_clock::now() + 3s, "queue");
+}
+
+void CCodec::subQueuedWorkCount(uint32_t count) {
+ ALOGV("queued work count -%u from %d", count, mQueuedWorkCount.load());
+ if ((mQueuedWorkCount -= count) > 0) {
+ Mutexed<NamedTimePoint>::Locked deadline(mQueueDeadline);
+ deadline->set(std::chrono::steady_clock::now() + 3s, "queue");
+ } else {
+ Mutexed<NamedTimePoint>::Locked deadline(mQueueDeadline);
+ deadline->set(TimePoint::max(), "none");
+ }
+}
+
} // namespace android
extern "C" android::CodecBase *CreateCodec() {
diff --git a/media/sfplugin/CCodec.h b/media/sfplugin/CCodec.h
index 2dfa6e4..9a11cd4 100644
--- a/media/sfplugin/CCodec.h
+++ b/media/sfplugin/CCodec.h
@@ -95,6 +95,9 @@
void setDeadline(const TimePoint &deadline, const char *name);
+ void onWorkQueued();
+ void subQueuedWorkCount(uint32_t count);
+
enum {
kWhatAllocate,
kWhatConfigure,
@@ -158,6 +161,8 @@
struct ClientListener;
Mutexed<NamedTimePoint> mDeadline;
+ std::atomic_int32_t mQueuedWorkCount;
+ Mutexed<NamedTimePoint> mQueueDeadline;
typedef CCodecConfig Config;
Mutexed<Config> mConfig;
Mutexed<std::list<std::unique_ptr<C2Work>>> mWorkDoneQueue;
diff --git a/media/sfplugin/CCodecBufferChannel.cpp b/media/sfplugin/CCodecBufferChannel.cpp
index 052ea8c..d83390c 100644
--- a/media/sfplugin/CCodecBufferChannel.cpp
+++ b/media/sfplugin/CCodecBufferChannel.cpp
@@ -1316,6 +1316,7 @@
c2_status_t err = mComponent->queue(&items);
if (err == C2_OK && eos && buffer->size() > 0u) {
+ mCCodecCallback->onWorkQueued();
work.reset(new C2Work);
work->input.ordinal.timestamp = timeUs;
work->input.ordinal.frameIndex = mFrameIndex++;
@@ -1326,6 +1327,9 @@
items.push_back(std::move(work));
err = mComponent->queue(&items);
}
+ if (err == C2_OK) {
+ mCCodecCallback->onWorkQueued();
+ }
feedInputBufferIfAvailableInternal();
return err;
diff --git a/media/sfplugin/CCodecBufferChannel.h b/media/sfplugin/CCodecBufferChannel.h
index 033d364..f47e566 100644
--- a/media/sfplugin/CCodecBufferChannel.h
+++ b/media/sfplugin/CCodecBufferChannel.h
@@ -42,6 +42,7 @@
virtual ~CCodecCallback() = default;
virtual void onError(status_t err, enum ActionCode actionCode) = 0;
virtual void onOutputFramesRendered(int64_t mediaTimeUs, nsecs_t renderTimeNs) = 0;
+ virtual void onWorkQueued() = 0;
};
/**