Add metrics logging logic

...for bad packet lengths and duplicate seqnos.

Bug: 244578445, 245275823
Test: Built and ran emulator
Change-Id: I65cc5b4347e6d85417b8d643f4a4a93b628ae401
diff --git a/stream-servers/FrameBuffer.h b/stream-servers/FrameBuffer.h
index 022ea13..0fa3863 100644
--- a/stream-servers/FrameBuffer.h
+++ b/stream-servers/FrameBuffer.h
@@ -630,6 +630,9 @@
     std::unique_ptr<BorrowedImageInfo> borrowColorBufferForDisplay(uint32_t colorBufferHandle);
 
     HealthMonitor<>& getHealthMonitor();
+    emugl::MetricsLogger& getMetricsLogger() {
+        return *m_logger;
+    }
 
    private:
     FrameBuffer(int p_width, int p_height, bool useSubWindow);
diff --git a/stream-servers/RenderThread.cpp b/stream-servers/RenderThread.cpp
index 664c8c6..5425ed9 100644
--- a/stream-servers/RenderThread.cpp
+++ b/stream-servers/RenderThread.cpp
@@ -348,6 +348,7 @@
     }
 
     GfxApiLogger gfxLogger;
+    auto& metricsLogger = FrameBuffer::getFB()->getMetricsLogger();
 
     uint32_t* seqnoPtr = nullptr;
 
@@ -454,6 +455,7 @@
                     .processName = processName,
                     .gfxApiLogger = &gfxLogger,
                     .healthMonitor = &FrameBuffer::getFB()->getHealthMonitor(),
+                    .metricsLogger = &metricsLogger,
                 };
                 last = tInfo.m_vkInfo->m_vkDec.decode(readBuf.buf(), readBuf.validData(), ioStream,
                                                       seqnoPtr, context);
diff --git a/stream-servers/vulkan/VkDecoder.cpp b/stream-servers/vulkan/VkDecoder.cpp
index 743bef3..ba5b424 100644
--- a/stream-servers/vulkan/VkDecoder.cpp
+++ b/stream-servers/vulkan/VkDecoder.cpp
@@ -30,6 +30,7 @@
 #include "VkDecoder.h"
 
 #include <functional>
+#include <optional>
 #include <unordered_map>
 
 #include "VkDecoderGlobalState.h"
@@ -37,6 +38,7 @@
 #include "VulkanDispatch.h"
 #include "VulkanStream.h"
 #include "base/BumpPool.h"
+#include "base/Metrics.h"
 #include "base/System.h"
 #include "base/Tracing.h"
 #include "common/goldfish_vk_marshaling.h"
@@ -48,6 +50,10 @@
 #include "host-common/logging.h"
 #include "stream-servers/IOStream.h"
 
+#define MAX_PACKET_LENGTH (400 * 1024 * 1024)  // 400MB
+
+using android::base::MetricEventBadPacketLength;
+using android::base::MetricEventDuplicateSequenceNum;
 using emugl::vkDispatch;
 
 using namespace goldfish_vk;
@@ -62,7 +68,8 @@
           m_boxedHandleCreateMapping(m_state),
           m_boxedHandleDestroyMapping(m_state),
           m_boxedHandleUnwrapAndDeleteMapping(m_state),
-          m_boxedHandleUnwrapAndDeletePreserveBoxedMapping(m_state) {}
+          m_boxedHandleUnwrapAndDeletePreserveBoxedMapping(m_state),
+          m_prevSeqno(std::nullopt) {}
     VulkanStream* stream() { return &m_vkStream; }
     VulkanMemReadingStream* readStream() { return &m_vkMemReadingStream; }
 
@@ -84,6 +91,7 @@
     BoxedHandleUnwrapAndDeleteMapping m_boxedHandleUnwrapAndDeleteMapping;
     android::base::BumpPool m_pool;
     BoxedHandleUnwrapAndDeletePreserveBoxedMapping m_boxedHandleUnwrapAndDeletePreserveBoxedMapping;
+    std::optional<uint32_t> m_prevSeqno;
 };
 
 VkDecoder::VkDecoder() : mImpl(new VkDecoder::Impl()) {}
@@ -106,6 +114,7 @@
     const char* processName = context.processName;
     auto& gfx_logger = *context.gfxApiLogger;
     auto& healthMonitor = *context.healthMonitor;
+    auto& metricsLogger = *context.metricsLogger;
     if (len < 8) return 0;
     bool queueSubmitWithCommandsEnabled =
         feature_is_enabled(kFeature_VulkanQueueSubmitWithCommands);
@@ -117,6 +126,13 @@
     while (end - ptr >= 8) {
         uint32_t opcode = *(uint32_t*)ptr;
         uint32_t packetLen = *(uint32_t*)(ptr + 4);
+
+        // packetLen should be at least 8 (op code and packet length) and should not be excessively large
+        if (packetLen < 8 || packetLen > MAX_PACKET_LENGTH) {
+            WARN("Bad packet length %d detected, decode may fail", packetLen);
+            metricsLogger.logMetricEvent(MetricEventBadPacketLength{.len = packetLen});
+        }
+
         if (end - ptr < packetLen) return ptr - (unsigned char*)buf;
         gfx_logger.record(ptr, std::min(size_t(packetLen + 8), size_t(end - ptr)));
         stream()->setStream(ioStream);
@@ -134,6 +150,13 @@
             uint32_t seqno;
             memcpy(&seqno, *readStreamPtrPtr, sizeof(uint32_t));
             *readStreamPtrPtr += sizeof(uint32_t);
+            if (m_prevSeqno && seqno == m_prevSeqno.value()) {
+                WARN(
+                    "Seqno %d is the same as previously processed on thread %d. It might be a "
+                    "duplicate command.",
+                    seqno, getCurrentThreadId());
+                metricsLogger.logMetricEvent(MetricEventDuplicateSequenceNum{.opcode = opcode});
+            }
             if (seqnoPtr && !m_forSnapshotLoad) {
                 {
                     auto watchdog =
@@ -162,6 +185,7 @@
                         __asm__ __volatile__("pause;");
 #endif
                     }
+                    m_prevSeqno = seqno;
                 }
             }
         }
@@ -32196,7 +32220,7 @@
                 if (queueSubmitWithCommandsEnabled)
                     __atomic_fetch_add(seqnoPtr, 1, __ATOMIC_SEQ_CST);
                 m_state->on_vkQueueFlushCommandsGOOGLE(&m_pool, queue, commandBuffer, dataSize,
-                                                       pData, gfx_logger);
+                                                       pData, context);
                 vkStream->unsetHandleMapping();
                 vkReadStream->setReadPos((uintptr_t)(*readStreamPtrPtr) -
                                          (uintptr_t)snapshotTraceBegin);
diff --git a/stream-servers/vulkan/VkDecoderContext.h b/stream-servers/vulkan/VkDecoderContext.h
index a80d6a4..7b3f1f2 100644
--- a/stream-servers/vulkan/VkDecoderContext.h
+++ b/stream-servers/vulkan/VkDecoderContext.h
@@ -15,11 +15,15 @@
 
 #pragma once
 
+#include <memory>
+
 #include "base/GfxApiLogger.h"
 #include "base/HealthMonitor.h"
+#include "base/Metrics.h"
 
 struct VkDecoderContext {
     const char* processName = nullptr;
     emugl::GfxApiLogger* gfxApiLogger = nullptr;
     emugl::HealthMonitor<>* healthMonitor = nullptr;
+    emugl::MetricsLogger* metricsLogger = nullptr;
 };
\ No newline at end of file
diff --git a/stream-servers/vulkan/VkDecoderGlobalState.cpp b/stream-servers/vulkan/VkDecoderGlobalState.cpp
index de9b2cc..5b05d76 100644
--- a/stream-servers/vulkan/VkDecoderGlobalState.cpp
+++ b/stream-servers/vulkan/VkDecoderGlobalState.cpp
@@ -27,6 +27,7 @@
 #include "VkAndroidNativeBuffer.h"
 #include "VkCommonOperations.h"
 #include "VkDecoderSnapshot.h"
+#include "VkDecoderContext.h"
 #include "VkFormatUtils.h"
 #include "VulkanDispatch.h"
 #include "VulkanStream.h"
@@ -70,6 +71,8 @@
 using android::base::ConditionVariable;
 using android::base::Lock;
 using android::base::ManagedDescriptor;
+using android::base::MetricEventBadPacketLength;
+using android::base::MetricEventDuplicateSequenceNum;
 using android::base::DescriptorType;
 using android::base::Optional;
 using android::base::StaticLock;
@@ -4678,13 +4681,13 @@
 
     void on_vkQueueFlushCommandsGOOGLE(android::base::BumpPool* pool, VkQueue queue,
                                        VkCommandBuffer boxed_commandBuffer, VkDeviceSize dataSize,
-                                       const void* pData, GfxApiLogger& gfxLogger) {
+                                       const void* pData, const VkDecoderContext& context) {
         (void)queue;
 
         VkCommandBuffer commandBuffer = unbox_VkCommandBuffer(boxed_commandBuffer);
         VulkanDispatch* vk = dispatch_VkCommandBuffer(boxed_commandBuffer);
         VulkanMemReadingStream* readStream = readstream_VkCommandBuffer(boxed_commandBuffer);
-        subDecode(readStream, vk, boxed_commandBuffer, commandBuffer, dataSize, pData, gfxLogger);
+        subDecode(readStream, vk, boxed_commandBuffer, commandBuffer, dataSize, pData, context);
     }
 
     VkDescriptorSet getOrAllocateDescriptorSetFromPoolAndId(VulkanDispatch* vk, VkDevice device,
@@ -8030,8 +8033,8 @@
                                                          VkQueue queue,
                                                          VkCommandBuffer commandBuffer,
                                                          VkDeviceSize dataSize, const void* pData,
-                                                         GfxApiLogger& gfxLogger) {
-    mImpl->on_vkQueueFlushCommandsGOOGLE(pool, queue, commandBuffer, dataSize, pData, gfxLogger);
+                                                         const VkDecoderContext& context) {
+    mImpl->on_vkQueueFlushCommandsGOOGLE(pool, queue, commandBuffer, dataSize, pData, context);
 }
 
 void VkDecoderGlobalState::on_vkQueueCommitDescriptorSetUpdatesGOOGLE(
diff --git a/stream-servers/vulkan/VkDecoderGlobalState.h b/stream-servers/vulkan/VkDecoderGlobalState.h
index 257adc2..c854763 100644
--- a/stream-servers/vulkan/VkDecoderGlobalState.h
+++ b/stream-servers/vulkan/VkDecoderGlobalState.h
@@ -20,6 +20,7 @@
 #include <utility>
 #include <vector>
 
+#include "VkDecoderContext.h"
 #include "VkQsriTimeline.h"
 #include "VulkanDispatch.h"
 #include "VulkanHandleMapping.h"
@@ -582,7 +583,7 @@
     // VK_GOOGLE_gfxstream
     void on_vkQueueFlushCommandsGOOGLE(android::base::BumpPool* pool, VkQueue queue,
                                        VkCommandBuffer commandBuffer, VkDeviceSize dataSize,
-                                       const void* pData, emugl::GfxApiLogger& gfxLogger);
+                                       const void* pData, const VkDecoderContext& context);
     void on_vkQueueCommitDescriptorSetUpdatesGOOGLE(
         android::base::BumpPool* pool, VkQueue queue, uint32_t descriptorPoolCount,
         const VkDescriptorPool* pDescriptorPools, uint32_t descriptorSetCount,
diff --git a/stream-servers/vulkan/VkSubDecoder.cpp b/stream-servers/vulkan/VkSubDecoder.cpp
index 1c472c3..45ac925 100644
--- a/stream-servers/vulkan/VkSubDecoder.cpp
+++ b/stream-servers/vulkan/VkSubDecoder.cpp
@@ -27,9 +27,12 @@
 // python3 $VULKAN_REGISTRY_SCRIPTS_DIR/genvk.py -registry $VULKAN_REGISTRY_XML_DIR/vk.xml cereal -o $CEREAL_OUTPUT_DIR
 //
 #define MAX_STACK_ITEMS 16
+#define MAX_PACKET_LENGTH (400 * 1024 * 1024)  // 400MB
 size_t subDecode(VulkanMemReadingStream* readStream, VulkanDispatch* vk, void* boxed_dispatchHandle,
                  void* dispatchHandle, VkDeviceSize dataSize, const void* pData,
-                 GfxApiLogger& gfx_logger) {
+                 const VkDecoderContext& context) {
+    auto& gfx_logger = *context.gfxApiLogger;
+    auto& metricsLogger = *context.metricsLogger;
     uint32_t count = 0;
     unsigned char* buf = (unsigned char*)pData;
     android::base::BumpPool* pool = readStream->pool();
@@ -39,6 +42,13 @@
     while (end - ptr >= 8) {
         uint32_t opcode = *(uint32_t*)ptr;
         uint32_t packetLen = *(uint32_t*)(ptr + 4);
+
+        // packetLen should be at least 8 (op code and packet length) and should not be excessively large
+        if (packetLen < 8 || packetLen > MAX_PACKET_LENGTH) {
+            WARN("Bad packet length %d detected, subdecode may fail", packetLen);
+            metricsLogger.logMetricEvent(MetricEventBadPacketLength{.len = packetLen});
+        }
+
         if (end - ptr < packetLen) return ptr - (unsigned char*)buf;
         gfx_logger.record(ptr, std::min(size_t(packetLen + 8), size_t(end - ptr)));
         readStream->setBuf((uint8_t*)(ptr + 8));