[TimeStats] Track per-frame CPU time.

This measures from the beginning of the invalidate message, until
CompositionEngine::present finishes.

Bug: 144037240
Test: dumpsys SurfaceFlinger --timestats -dump
Change-Id: I1c686db9fa1746518c48810bf385041806ce06d2
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 611afce..626efb8 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -20,14 +20,13 @@
 #include "TimeStats.h"
 
 #include <android-base/stringprintf.h>
-
 #include <log/log.h>
-
 #include <utils/String8.h>
 #include <utils/Timers.h>
 #include <utils/Trace.h>
 
 #include <algorithm>
+#include <chrono>
 
 namespace android {
 
@@ -113,6 +112,23 @@
     mTimeStats.clientCompositionFrames++;
 }
 
+static int32_t msBetween(nsecs_t start, nsecs_t end) {
+    int64_t delta = std::chrono::duration_cast<std::chrono::milliseconds>(
+                            std::chrono::nanoseconds(end - start))
+                            .count();
+    delta = std::clamp(delta, int64_t(INT32_MIN), int64_t(INT32_MAX));
+    return static_cast<int32_t>(delta);
+}
+
+void TimeStats::recordFrameDuration(nsecs_t startTime, nsecs_t endTime) {
+    if (!mEnabled.load()) return;
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (mPowerTime.powerMode == HWC_POWER_MODE_NORMAL) {
+        mTimeStats.frameDuration.insert(msBetween(startTime, endTime));
+    }
+}
+
 bool TimeStats::recordReadyLocked(int32_t layerId, TimeRecord* timeRecord) {
     if (!timeRecord->ready) {
         ALOGV("[%d]-[%" PRIu64 "]-presentFence is still not received", layerId,
@@ -149,12 +165,6 @@
     return true;
 }
 
-static int32_t msBetween(nsecs_t start, nsecs_t end) {
-    int64_t delta = (end - start) / 1000000;
-    delta = std::clamp(delta, int64_t(INT32_MIN), int64_t(INT32_MAX));
-    return static_cast<int32_t>(delta);
-}
-
 void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId) {
     ATRACE_CALL();