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;
 };
 
 /**