Camera: Collect capture latency histograms

Add capture latency histograms to existing westworld metrics data.

Test: Camera CTS, and observe statsd output
Bug: 154159000
Change-Id: Id0ac5c29f29bdab5ac21f16fe33430f7a7456553
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 92c8e30..e80404b 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2161,6 +2161,14 @@
                 streamStats[i].mRequestCount = stats->second.mRequestedFrameCount;
                 streamStats[i].mErrorCount = stats->second.mDroppedFrameCount;
                 streamStats[i].mStartLatencyMs = stats->second.mStartLatencyMs;
+                streamStats[i].mHistogramType =
+                        hardware::CameraStreamStats::HISTOGRAM_TYPE_CAPTURE_LATENCY;
+                streamStats[i].mHistogramBins.assign(
+                        stats->second.mCaptureLatencyBins.begin(),
+                        stats->second.mCaptureLatencyBins.end());
+                streamStats[i].mHistogramCounts.assign(
+                        stats->second.mCaptureLatencyHistogram.begin(),
+                        stats->second.mCaptureLatencyHistogram.end());
             }
         }
         listener->notifyIdle(requestCount, resultErrorCount, deviceError, streamStats);
diff --git a/services/camera/libcameraservice/utils/SessionStatsBuilder.cpp b/services/camera/libcameraservice/utils/SessionStatsBuilder.cpp
index 83965c4..7a7707c 100644
--- a/services/camera/libcameraservice/utils/SessionStatsBuilder.cpp
+++ b/services/camera/libcameraservice/utils/SessionStatsBuilder.cpp
@@ -18,12 +18,21 @@
 #define ATRACE_TAG ATRACE_TAG_CAMERA
 //#define LOG_NDEBUG 0
 
+#include <numeric>
+
+#include <inttypes.h>
 #include <utils/Log.h>
 
 #include "SessionStatsBuilder.h"
 
 namespace android {
 
+// Bins for capture latency: [0, 100], [100, 200], [200, 300], ...
+// [1300, 2100], [2100, inf].
+// Capture latency is in the unit of millisecond.
+const std::array<int32_t, StreamStats::LATENCY_BIN_COUNT-1> StreamStats::mCaptureLatencyBins {
+        { 100, 200, 300, 400, 500, 700, 900, 1300, 2100 } };
+
 status_t SessionStatsBuilder::addStream(int id) {
     std::lock_guard<std::mutex> l(mLock);
     StreamStats stats;
@@ -52,10 +61,14 @@
     mCounterStopped = false;
     mDeviceError = false;
     for (auto& streamStats : mStatsMap) {
-        streamStats.second.mRequestedFrameCount = 0;
-        streamStats.second.mDroppedFrameCount = 0;
-        streamStats.second.mCounterStopped = false;
-        streamStats.second.mStartLatencyMs = 0;
+        StreamStats& streamStat = streamStats.second;
+        streamStat.mRequestedFrameCount = 0;
+        streamStat.mDroppedFrameCount = 0;
+        streamStat.mCounterStopped = false;
+        streamStat.mStartLatencyMs = 0;
+
+        std::fill(streamStat.mCaptureLatencyHistogram.begin(),
+                streamStat.mCaptureLatencyHistogram.end(), 0);
     }
 }
 
@@ -66,23 +79,28 @@
 
 void SessionStatsBuilder::stopCounter(int id) {
     std::lock_guard<std::mutex> l(mLock);
-    mStatsMap[id].mCounterStopped = true;
+    StreamStats& streamStat = mStatsMap[id];
+    streamStat.mCounterStopped = true;
 }
 
 void SessionStatsBuilder::incCounter(int id, bool dropped, int32_t captureLatencyMs) {
     std::lock_guard<std::mutex> l(mLock);
+
     auto it = mStatsMap.find(id);
-    if (it != mStatsMap.end()) {
-         if (!it->second.mCounterStopped) {
-             it->second.mRequestedFrameCount++;
-             if (dropped) {
-                 it->second.mDroppedFrameCount++;
-             } else if (it->second.mRequestedFrameCount == 1) {
-                 // The capture latency for the first request.
-                 it->second.mStartLatencyMs = captureLatencyMs;
-             }
-         }
+    if (it == mStatsMap.end()) return;
+
+    StreamStats& streamStat = it->second;
+    if (streamStat.mCounterStopped) return;
+
+    streamStat.mRequestedFrameCount++;
+    if (dropped) {
+        streamStat.mDroppedFrameCount++;
+    } else if (streamStat.mRequestedFrameCount - streamStat.mDroppedFrameCount == 1) {
+        // The capture latency for the first request.
+        streamStat.mStartLatencyMs = captureLatencyMs;
     }
+
+    streamStat.updateLatencyHistogram(captureLatencyMs);
 }
 
 void SessionStatsBuilder::stopCounter() {
@@ -95,10 +113,10 @@
 
 void SessionStatsBuilder::incResultCounter(bool dropped) {
     std::lock_guard<std::mutex> l(mLock);
-    if (!mCounterStopped) {
-        mRequestCount ++;
-        if (dropped) mErrorResultCount++;
-    }
+    if (mCounterStopped) return;
+
+    mRequestCount++;
+    if (dropped) mErrorResultCount++;
 }
 
 void SessionStatsBuilder::onDeviceError() {
@@ -106,4 +124,18 @@
     mDeviceError = true;
 }
 
+void StreamStats::updateLatencyHistogram(int32_t latencyMs) {
+    size_t i;
+    for (i = 0; i < mCaptureLatencyBins.size(); i++) {
+        if (latencyMs < mCaptureLatencyBins[i]) {
+            mCaptureLatencyHistogram[i] ++;
+            break;
+        }
+    }
+
+    if (i == mCaptureLatencyBins.size()) {
+        mCaptureLatencyHistogram[i]++;
+    }
+}
+
 }; // namespace android
diff --git a/services/camera/libcameraservice/utils/SessionStatsBuilder.h b/services/camera/libcameraservice/utils/SessionStatsBuilder.h
index 7943637..c23abb6 100644
--- a/services/camera/libcameraservice/utils/SessionStatsBuilder.h
+++ b/services/camera/libcameraservice/utils/SessionStatsBuilder.h
@@ -19,22 +19,38 @@
 
 #include <utils/Errors.h>
 
-#include <mutex>
+#include <array>
 #include <map>
+#include <mutex>
 
 namespace android {
 
 // Helper class to build stream stats
 struct StreamStats {
+    // Fields for buffer drop
     int64_t mRequestedFrameCount;
     int64_t mDroppedFrameCount;
     bool mCounterStopped;
+
+    // Fields for stream startup latency
     int32_t mStartLatencyMs;
 
+    // Fields for capture latency measurement
+    const static int LATENCY_BIN_COUNT = 10;
+    // Boundary values separating between adjacent bins, excluding 0 and
+    // infinity.
+    const static std::array<int32_t, LATENCY_BIN_COUNT-1> mCaptureLatencyBins;
+    // Counter values for all histogram bins. One more entry than mCaptureLatencyBins.
+    std::array<int64_t, LATENCY_BIN_COUNT> mCaptureLatencyHistogram;
+
     StreamStats() : mRequestedFrameCount(0),
                      mDroppedFrameCount(0),
                      mCounterStopped(false),
-                     mStartLatencyMs(0) {}
+                     mStartLatencyMs(0),
+                     mCaptureLatencyHistogram{}
+                  {}
+
+    void updateLatencyHistogram(int32_t latencyMs);
 };
 
 // Helper class to build session stats