SF - plumbing game mode for metrics (part 2)

Update TimeStats to take in the game mode from layer for all the frames.

Bug: 186025682
Test: statsd_testdrive 10063
Test: atest libsurfaceflinger_unittest
Change-Id: If95a8c91940228a8925ae9e4e21656d1b492a2ba
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index d6a0787..f1b153f 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -58,6 +58,21 @@
     return histogramProto;
 }
 
+SurfaceflingerStatsLayerInfo_GameMode gameModeToProto(int32_t gameMode) {
+    switch (gameMode) {
+        case TimeStatsHelper::GameModeUnsupported:
+            return SurfaceflingerStatsLayerInfo::GAME_MODE_UNSUPPORTED;
+        case TimeStatsHelper::GameModeStandard:
+            return SurfaceflingerStatsLayerInfo::GAME_MODE_STANDARD;
+        case TimeStatsHelper::GameModePerformance:
+            return SurfaceflingerStatsLayerInfo::GAME_MODE_PERFORMANCE;
+        case TimeStatsHelper::GameModeBattery:
+            return SurfaceflingerStatsLayerInfo::GAME_MODE_BATTERY;
+        default:
+            return SurfaceflingerStatsLayerInfo::GAME_MODE_UNSPECIFIED;
+    }
+}
+
 SurfaceflingerStatsLayerInfo_SetFrameRateVote frameRateVoteToProto(
         const TimeStats::SetFrameRateVote& setFrameRateVote) {
     using FrameRateCompatibilityEnum =
@@ -206,6 +221,7 @@
         *atom->mutable_app_deadline_misses() =
                 histogramToProto(layer->deltas["appDeadlineDeltas"].hist,
                                  mMaxPulledHistogramBuckets);
+        atom->set_game_mode(gameModeToProto(layer->gameMode));
     }
 
     // Always clear data.
@@ -437,7 +453,8 @@
 
 void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate,
                                                    std::optional<Fps> renderRate,
-                                                   SetFrameRateVote frameRateVote) {
+                                                   SetFrameRateVote frameRateVote,
+                                                   int32_t gameMode) {
     ATRACE_CALL();
     ALOGV("[%d]-flushAvailableRecordsToStatsLocked", layerId);
 
@@ -464,12 +481,13 @@
 
             TimeStatsHelper::TimelineStats& displayStats = mTimeStats.stats[timelineKey];
 
-            TimeStatsHelper::LayerStatsKey layerKey = {uid, layerName};
+            TimeStatsHelper::LayerStatsKey layerKey = {uid, layerName, gameMode};
             if (!displayStats.stats.count(layerKey)) {
                 displayStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket;
                 displayStats.stats[layerKey].renderRateBucket = renderRateBucket;
                 displayStats.stats[layerKey].uid = uid;
                 displayStats.stats[layerKey].layerName = layerName;
+                displayStats.stats[layerKey].gameMode = gameMode;
             }
             if (frameRateVote.frameRate > 0.0f) {
                 displayStats.stats[layerKey].setFrameRateVote = frameRateVote;
@@ -535,10 +553,11 @@
             layerName.compare(0, kMinLenLayerName, kPopupWindowPrefix) != 0;
 }
 
-bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName) {
+bool TimeStats::canAddNewAggregatedStats(uid_t uid, const std::string& layerName,
+                                         int32_t gameMode) {
     uint32_t layerRecords = 0;
     for (const auto& record : mTimeStats.stats) {
-        if (record.second.stats.count({uid, layerName}) > 0) {
+        if (record.second.stats.count({uid, layerName, gameMode}) > 0) {
             return true;
         }
 
@@ -549,7 +568,7 @@
 }
 
 void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
-                            uid_t uid, nsecs_t postTime) {
+                            uid_t uid, nsecs_t postTime, int32_t gameMode) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
@@ -557,13 +576,14 @@
           postTime);
 
     std::lock_guard<std::mutex> lock(mMutex);
-    if (!canAddNewAggregatedStats(uid, layerName)) {
+    if (!canAddNewAggregatedStats(uid, layerName, gameMode)) {
         return;
     }
     if (!mTimeStatsTracker.count(layerId) && mTimeStatsTracker.size() < MAX_NUM_LAYER_RECORDS &&
         layerNameIsValid(layerName)) {
         mTimeStatsTracker[layerId].uid = uid;
         mTimeStatsTracker[layerId].layerName = layerName;
+        mTimeStatsTracker[layerId].gameMode = gameMode;
     }
     if (!mTimeStatsTracker.count(layerId)) return;
     LayerRecord& layerRecord = mTimeStatsTracker[layerId];
@@ -698,7 +718,7 @@
 
 void TimeStats::setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime,
                                Fps displayRefreshRate, std::optional<Fps> renderRate,
-                               SetFrameRateVote frameRateVote) {
+                               SetFrameRateVote frameRateVote, int32_t gameMode) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
@@ -717,13 +737,14 @@
         layerRecord.waitData++;
     }
 
-    flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote);
+    flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote,
+                                       gameMode);
 }
 
 void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber,
                                 const std::shared_ptr<FenceTime>& presentFence,
                                 Fps displayRefreshRate, std::optional<Fps> renderRate,
-                                SetFrameRateVote frameRateVote) {
+                                SetFrameRateVote frameRateVote, int32_t gameMode) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
@@ -743,7 +764,8 @@
         layerRecord.waitData++;
     }
 
-    flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote);
+    flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate, frameRateVote,
+                                       gameMode);
 }
 
 static const constexpr int32_t kValidJankyReason = JankType::DisplayHAL |
@@ -801,6 +823,7 @@
     // the first jank record is not dropped.
 
     static const std::string kDefaultLayerName = "none";
+    static constexpr int32_t kDefaultGameMode = TimeStatsHelper::GameModeUnsupported;
 
     const int32_t refreshRateBucket =
             clampToNearestBucket(info.refreshRate, REFRESH_RATE_BUCKET_WIDTH);
@@ -817,13 +840,14 @@
 
     updateJankPayload<TimeStatsHelper::TimelineStats>(timelineStats, info.reasons);
 
-    TimeStatsHelper::LayerStatsKey layerKey = {info.uid, info.layerName};
+    TimeStatsHelper::LayerStatsKey layerKey = {info.uid, info.layerName, info.gameMode};
     if (!timelineStats.stats.count(layerKey)) {
-        layerKey = {info.uid, kDefaultLayerName};
+        layerKey = {info.uid, kDefaultLayerName, kDefaultGameMode};
         timelineStats.stats[layerKey].displayRefreshRateBucket = refreshRateBucket;
         timelineStats.stats[layerKey].renderRateBucket = renderRateBucket;
         timelineStats.stats[layerKey].uid = info.uid;
-        timelineStats.stats[layerKey].layerName = kDefaultLayerName;
+        timelineStats.stats[layerKey].layerName = kDefaultGameMode;
+        timelineStats.stats[layerKey].gameMode = info.gameMode;
     }
 
     TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timelineStats.stats[layerKey];
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 5b0f5bd..dd48950 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -87,7 +87,7 @@
                                             const std::shared_ptr<FenceTime>& readyFence) = 0;
 
     virtual void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
-                             uid_t uid, nsecs_t postTime) = 0;
+                             uid_t uid, nsecs_t postTime, int32_t gameMode) = 0;
     virtual void setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) = 0;
     // Reasons why latching a particular buffer may be skipped
     enum class LatchSkipReason {
@@ -109,11 +109,11 @@
     // rendering path, as they flush prior fences if those fences have fired.
     virtual void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime,
                                 Fps displayRefreshRate, std::optional<Fps> renderRate,
-                                SetFrameRateVote frameRateVote) = 0;
+                                SetFrameRateVote frameRateVote, int32_t gameMode) = 0;
     virtual void setPresentFence(int32_t layerId, uint64_t frameNumber,
                                  const std::shared_ptr<FenceTime>& presentFence,
                                  Fps displayRefreshRate, std::optional<Fps> renderRate,
-                                 SetFrameRateVote frameRateVote) = 0;
+                                 SetFrameRateVote frameRateVote, int32_t gameMode) = 0;
 
     // Increments janky frames, blamed to the provided {refreshRate, renderRate, uid, layerName}
     // key, with JankMetadata as supplementary reasons for the jank. Because FrameTimeline is the
@@ -131,6 +131,7 @@
         std::optional<Fps> renderRate;
         uid_t uid = 0;
         std::string layerName;
+        int32_t gameMode = 0;
         int32_t reasons = 0;
         nsecs_t displayDeadlineDelta = 0;
         nsecs_t displayPresentJitter = 0;
@@ -141,8 +142,8 @@
                     ((renderRate == std::nullopt && o.renderRate == std::nullopt) ||
                      (renderRate != std::nullopt && o.renderRate != std::nullopt &&
                       Fps::EqualsInBuckets{}(*renderRate, *o.renderRate))) &&
-                    uid == o.uid && layerName == o.layerName && reasons == o.reasons &&
-                    displayDeadlineDelta == o.displayDeadlineDelta &&
+                    uid == o.uid && layerName == o.layerName && gameMode == o.gameMode &&
+                    reasons == o.reasons && displayDeadlineDelta == o.displayDeadlineDelta &&
                     displayPresentJitter == o.displayPresentJitter &&
                     appDeadlineDelta == o.appDeadlineDelta;
         }
@@ -199,6 +200,7 @@
     struct LayerRecord {
         uid_t uid;
         std::string layerName;
+        int32_t gameMode = 0;
         // This is the index in timeRecords, at which the timestamps for that
         // specific frame are still not fully received. This is not waiting for
         // fences to signal, but rather waiting to receive those fences/timestamps.
@@ -251,7 +253,7 @@
                                     const std::shared_ptr<FenceTime>& readyFence) override;
 
     void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName, uid_t uid,
-                     nsecs_t postTime) override;
+                     nsecs_t postTime, int32_t gameMode) override;
     void setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) override;
     void incrementLatchSkipped(int32_t layerId, LatchSkipReason reason) override;
     void incrementBadDesiredPresent(int32_t layerId) override;
@@ -261,10 +263,11 @@
                          const std::shared_ptr<FenceTime>& acquireFence) override;
     void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime,
                         Fps displayRefreshRate, std::optional<Fps> renderRate,
-                        SetFrameRateVote frameRateVote) override;
+                        SetFrameRateVote frameRateVote, int32_t gameMode) override;
     void setPresentFence(int32_t layerId, uint64_t frameNumber,
                          const std::shared_ptr<FenceTime>& presentFence, Fps displayRefreshRate,
-                         std::optional<Fps> renderRate, SetFrameRateVote frameRateVote) override;
+                         std::optional<Fps> renderRate, SetFrameRateVote frameRateVote,
+                         int32_t gameMode) override;
 
     void incrementJankyFrames(const JankyFramesInfo& info) override;
     // Clean up the layer record
@@ -286,10 +289,10 @@
     bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord);
     void flushAvailableRecordsToStatsLocked(int32_t layerId, Fps displayRefreshRate,
                                             std::optional<Fps> renderRate,
-                                            SetFrameRateVote frameRateVote);
+                                            SetFrameRateVote frameRateVote, int32_t gameMode);
     void flushPowerTimeLocked();
     void flushAvailableGlobalRecordsToStatsLocked();
-    bool canAddNewAggregatedStats(uid_t uid, const std::string& layerName);
+    bool canAddNewAggregatedStats(uid_t uid, const std::string& layerName, int32_t gameMode);
 
     void enable();
     void disable();
diff --git a/services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto b/services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto
index 133a541..e45757d 100644
--- a/services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto
+++ b/services/surfaceflinger/TimeStats/timestatsatomsproto/timestats_atoms.proto
@@ -166,6 +166,23 @@
     // This is intended to be used as a dimension in collecting per-render rate
     // jank statistics.
     optional int32 render_rate_bucket = 23;
+
+    enum GameMode {
+         GAME_MODE_UNSPECIFIED = 0;
+         GAME_MODE_UNSUPPORTED = 1;
+         GAME_MODE_STANDARD = 2;
+         GAME_MODE_PERFORMANCE = 3;
+         GAME_MODE_BATTERY = 4;
+    }
+
+    // Game mode that the layer was running at. Used to track user engagement
+    // in different modes. The modes are defined in GameManager.java
+    // Game modes are used only for integrating with GameManager. All non-game
+    // layers will have this field set to UNSUPPORTED.
+    // Introduced in Android 12
+    // This is intended to be used as a dimension in collecting per-game mode
+    // fps and frame related metrics.
+    optional GameMode game_mode = 26;
     // The layer for this set of metrics
     // In many scenarios the package name is included in the layer name, e.g.,
     // layers created by Window Manager. But this is not a guarantee - in the
@@ -271,7 +288,7 @@
     // Introduced in Android 12.
     optional FrameTimingHistogram app_deadline_misses = 25;
 
-    // Next ID: 26
+    // Next ID: 27
 }
 
 /**
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index a7e7db2..ffb2f09 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -122,6 +122,20 @@
     return result;
 }
 
+std::string TimeStatsHelper::TimeStatsLayer::toString(int32_t gameMode) const {
+    switch (gameMode) {
+        case TimeStatsHelper::GameModeUnsupported:
+            return "GameModeUnsupported";
+        case TimeStatsHelper::GameModeStandard:
+            return "GameModeStandard";
+        case TimeStatsHelper::GameModePerformance:
+            return "GameModePerformance";
+        case TimeStatsHelper::GameModeBattery:
+            return "GameModeBattery";
+        default:
+            return "GameModeUnspecified";
+    }
+}
 std::string TimeStatsHelper::TimeStatsLayer::toString() const {
     std::string result = "\n";
     StringAppendF(&result, "displayRefreshRate = %d fps\n", displayRefreshRateBucket);
@@ -129,6 +143,7 @@
     StringAppendF(&result, "uid = %d\n", uid);
     StringAppendF(&result, "layerName = %s\n", layerName.c_str());
     StringAppendF(&result, "packageName = %s\n", packageName.c_str());
+    StringAppendF(&result, "gameMode = %s\n", toString(gameMode).c_str());
     StringAppendF(&result, "totalFrames = %d\n", totalFrames);
     StringAppendF(&result, "droppedFrames = %d\n", droppedFrames);
     StringAppendF(&result, "lateAcquireFrames = %d\n", lateAcquireFrames);
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 2b37ffe..2afff8d 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -77,6 +77,18 @@
         std::string toString() const;
     };
 
+    /**
+     * GameMode of the layer. GameModes are set by SysUI through WMShell.
+     * Actual game mode definitions are managed by GameManager.java
+     * The values defined here should always be in sync with the ones in GameManager.
+     */
+    enum GameMode {
+        GameModeUnsupported = 0,
+        GameModeStandard = 1,
+        GameModePerformance = 2,
+        GameModeBattery = 3,
+    };
+
     class TimeStatsLayer {
     public:
         uid_t uid;
@@ -84,6 +96,7 @@
         std::string packageName;
         int32_t displayRefreshRateBucket = 0;
         int32_t renderRateBucket = 0;
+        int32_t gameMode = 0;
         int32_t totalFrames = 0;
         int32_t droppedFrames = 0;
         int32_t lateAcquireFrames = 0;
@@ -93,6 +106,7 @@
         std::unordered_map<std::string, Histogram> deltas;
 
         std::string toString() const;
+        std::string toString(int32_t gameMode) const;
         SFTimeStatsLayerProto toProto() const;
     };
 
@@ -123,24 +137,19 @@
     struct LayerStatsKey {
         uid_t uid = 0;
         std::string layerName;
+        int32_t gameMode = 0;
 
         struct Hasher {
             size_t operator()(const LayerStatsKey& key) const {
-                size_t result = std::hash<uid_t>{}(key.uid);
-                return HashCombine(result, std::hash<std::string>{}(key.layerName));
+                size_t uidHash = std::hash<uid_t>{}(key.uid);
+                size_t layerNameHash = std::hash<std::string>{}(key.layerName);
+                size_t gameModeHash = std::hash<int32_t>{}(key.gameMode);
+                return HashCombine(uidHash, HashCombine(layerNameHash, gameModeHash));
             }
         };
 
         bool operator==(const LayerStatsKey& o) const {
-            return uid == o.uid && layerName == o.layerName;
-        }
-    };
-
-    struct LayerStatsHasher {
-        size_t operator()(const std::pair<uid_t, std::string>& p) const {
-            // Normally this isn't a very good hash function due to symmetry reasons,
-            // but these are distinct types so this should be good enough
-            return std::hash<uid_t>{}(p.first) ^ std::hash<std::string>{}(p.second);
+            return uid == o.uid && layerName == o.layerName && gameMode == o.gameMode;
         }
     };