Implement Display Layer Stats V0.1

Try to collect data for analyzing how many display controller layers we
need and what we use them for. This change will collect additional data
from per frame point of view.

Test: adb shell dumpsys SurfaceFlinger --enable-layer-stats
Test: adb shell dumpsys SurfaceFlinger --disable-layer-stats
Test: adb shell dumpsys SurfaceFlinger --clear-layer-stats
Test: adb shell dumpsys SurfaceFlinger --dump-layer-stats
Bug: b/75953772
Change-Id: Ib48777df7e1fed637be7eb1aefbdf1808d1daccd
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
index d7e191d..d5654cc 100644
--- a/libs/ui/DebugUtils.cpp
+++ b/libs/ui/DebugUtils.cpp
@@ -234,6 +234,33 @@
     return android::base::StringPrintf("Unknown color mode %d", colorMode);
 }
 
+std::string decodeColorTransform(android_color_transform colorTransform) {
+    switch (colorTransform) {
+        case HAL_COLOR_TRANSFORM_IDENTITY:
+            return std::string("Identity");
+
+        case HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX:
+            return std::string("Arbitrary matrix");
+
+        case HAL_COLOR_TRANSFORM_VALUE_INVERSE:
+            return std::string("Inverse value");
+
+        case HAL_COLOR_TRANSFORM_GRAYSCALE:
+            return std::string("Grayscale");
+
+        case HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA:
+            return std::string("Correct protanopia");
+
+        case HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA:
+            return std::string("Correct deuteranopia");
+
+        case HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA:
+            return std::string("Correct tritanopia");
+    }
+
+    return android::base::StringPrintf("Unknown color transform %d", colorTransform);
+}
+
 // Converts a PixelFormat to a human-readable string.  Max 11 chars.
 // (Could use a table of prefab String8 objects.)
 std::string decodePixelFormat(android::PixelFormat format) {
diff --git a/libs/ui/include/ui/DebugUtils.h b/libs/ui/include/ui/DebugUtils.h
index 3370107..7690093 100644
--- a/libs/ui/include/ui/DebugUtils.h
+++ b/libs/ui/include/ui/DebugUtils.h
@@ -30,5 +30,6 @@
 std::string decodeRange(android_dataspace dataspace);
 std::string dataspaceDetails(android_dataspace dataspace);
 std::string decodeColorMode(android::ColorMode colormode);
+std::string decodeColorTransform(android_color_transform colorTransform);
 std::string decodePixelFormat(android::PixelFormat format);
 std::string to_string(const android::Rect& rect);
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index fe0b30b..e4161bb 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -98,6 +98,7 @@
       mPowerMode(initialPowerMode),
       mActiveConfig(0),
       mActiveColorMode(ColorMode::NATIVE),
+      mColorTransform(HAL_COLOR_TRANSFORM_IDENTITY),
       mDisplayHasWideColor(supportWideColor),
       mDisplayHasHdr(supportHdr)
 {
@@ -268,6 +269,16 @@
     return mActiveColorMode;
 }
 
+void DisplayDevice::setColorTransform(const mat4& transform) {
+    const bool isIdentity = (transform == mat4());
+    mColorTransform =
+            isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
+}
+
+android_color_transform_t DisplayDevice::getColorTransform() const {
+    return mColorTransform;
+}
+
 void DisplayDevice::setCompositionDataSpace(android_dataspace dataspace) {
     ANativeWindow* const window = mNativeWindow.get();
     native_window_set_buffers_data_space(window, dataspace);
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index fbb0d46..c1ef2e8 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -21,6 +21,8 @@
 
 #include <stdlib.h>
 
+#include <math/mat4.h>
+
 #include <ui/Region.h>
 
 #include <binder/IBinder.h>
@@ -163,6 +165,8 @@
 
     ColorMode getActiveColorMode() const;
     void setActiveColorMode(ColorMode mode);
+    android_color_transform_t getColorTransform() const;
+    void setColorTransform(const mat4& transform);
     void setCompositionDataSpace(android_dataspace dataspace);
 
     /* ------------------------------------------------------------------------
@@ -237,6 +241,8 @@
     int mActiveConfig;
     // current active color mode
     ColorMode mActiveColorMode;
+    // Current color transform
+    android_color_transform_t mColorTransform;
 
     // Need to know if display is wide-color capable or not.
     // Initialized by SurfaceFlinger when the DisplayDevice is created.
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 3dc8cae..43bef60 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -42,6 +42,7 @@
 #include <gui/LayerDebugInfo.h>
 #include <gui/Surface.h>
 
+#include "BufferLayer.h"
 #include "Colorizer.h"
 #include "DisplayDevice.h"
 #include "Layer.h"
@@ -1935,6 +1936,16 @@
 
     const int32_t transform = static_cast<int32_t>(hwcInfo.transform);
     layerInfo->set_hwc_transform(transform);
+
+    const int32_t compositionType = static_cast<int32_t>(hwcInfo.compositionType);
+    layerInfo->set_hwc_composition_type(compositionType);
+
+    if (std::strcmp(getTypeId(), "BufferLayer") == 0 &&
+        static_cast<BufferLayer*>(this)->isProtected()) {
+        layerInfo->set_is_protected(true);
+    } else {
+        layerInfo->set_is_protected(false);
+    }
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/LayerStats.cpp b/services/surfaceflinger/LayerStats.cpp
index ad1043f..38ea6ed 100644
--- a/services/surfaceflinger/LayerStats.cpp
+++ b/services/surfaceflinger/LayerStats.cpp
@@ -19,6 +19,7 @@
 
 #include "LayerStats.h"
 #include "DisplayHardware/HWComposer.h"
+#include "ui/DebugUtils.h"
 
 #include <android-base/stringprintf.h>
 #include <log/log.h>
@@ -31,7 +32,7 @@
     ATRACE_CALL();
     std::lock_guard<std::mutex> lock(mMutex);
     if (mEnabled) return;
-    mLayerStatsMap.clear();
+    mLayerShapeStatsMap.clear();
     mEnabled = true;
     ALOGD("Logging enabled");
 }
@@ -47,7 +48,7 @@
 void LayerStats::clear() {
     ATRACE_CALL();
     std::lock_guard<std::mutex> lock(mMutex);
-    mLayerStatsMap.clear();
+    mLayerShapeStatsMap.clear();
     ALOGD("Cleared current layer stats");
 }
 
@@ -57,42 +58,69 @@
 
 void LayerStats::traverseLayerTreeStatsLocked(
         std::vector<std::unique_ptr<LayerProtoParser::Layer>> layerTree,
-        const LayerProtoParser::LayerGlobal* layerGlobal) {
+        const LayerProtoParser::LayerGlobal* layerGlobal, std::vector<std::string>& layerShapeVec) {
     for (std::unique_ptr<LayerProtoParser::Layer>& layer : layerTree) {
         if (!layer) continue;
-        traverseLayerTreeStatsLocked(std::move(layer->children), layerGlobal);
-        std::string key =
-                base::StringPrintf("%s,%s,%s,%s,%s,%s,%s,%s,%s",
-                                   destinationLocation(layer->hwcFrame.left,
-                                                       layerGlobal->resolution[0], true),
-                                   destinationLocation(layer->hwcFrame.top,
-                                                       layerGlobal->resolution[1], false),
-                                   destinationSize(layer->hwcFrame.right - layer->hwcFrame.left,
-                                                   layerGlobal->resolution[0], true),
-                                   destinationSize(layer->hwcFrame.bottom - layer->hwcFrame.top,
-                                                   layerGlobal->resolution[1], false),
-                                   layer->type.c_str(), scaleRatioWH(layer.get()).c_str(),
-                                   layerTransform(layer->hwcTransform), layer->pixelFormat.c_str(),
-                                   layer->dataspace.c_str());
-        mLayerStatsMap[key]++;
+        traverseLayerTreeStatsLocked(std::move(layer->children), layerGlobal, layerShapeVec);
+        std::string key = "";
+        base::StringAppendF(&key, ",%s", layer->type.c_str());
+        base::StringAppendF(&key, ",%s", layerCompositionType(layer->hwcCompositionType));
+        base::StringAppendF(&key, ",%d", layer->isProtected);
+        base::StringAppendF(&key, ",%s", layerTransform(layer->hwcTransform));
+        base::StringAppendF(&key, ",%s", layerPixelFormat(layer->activeBuffer.format));
+        base::StringAppendF(&key, ",%s", layer->dataspace.c_str());
+        base::StringAppendF(&key, ",%s",
+                            destinationLocation(layer->hwcFrame.left, layerGlobal->resolution[0],
+                                                true));
+        base::StringAppendF(&key, ",%s",
+                            destinationLocation(layer->hwcFrame.top, layerGlobal->resolution[1],
+                                                false));
+        base::StringAppendF(&key, ",%s",
+                            destinationSize(layer->hwcFrame.right - layer->hwcFrame.left,
+                                            layerGlobal->resolution[0], true));
+        base::StringAppendF(&key, ",%s",
+                            destinationSize(layer->hwcFrame.bottom - layer->hwcFrame.top,
+                                            layerGlobal->resolution[1], false));
+        base::StringAppendF(&key, ",%s", scaleRatioWH(layer.get()).c_str());
+        base::StringAppendF(&key, ",%s", alpha(static_cast<float>(layer->color.a)));
+
+        layerShapeVec.push_back(key);
+        ALOGV("%s", key.c_str());
     }
 }
 
 void LayerStats::logLayerStats(const LayersProto& layersProto) {
     ATRACE_CALL();
+    ALOGV("Logging");
     auto layerGlobal = LayerProtoParser::generateLayerGlobalInfo(layersProto);
     auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+    std::vector<std::string> layerShapeVec;
+
     std::lock_guard<std::mutex> lock(mMutex);
-    traverseLayerTreeStatsLocked(std::move(layerTree), &layerGlobal);
+    traverseLayerTreeStatsLocked(std::move(layerTree), &layerGlobal, layerShapeVec);
+
+    std::string layerShapeKey =
+            base::StringPrintf("%d,%s,%s,%s", static_cast<int32_t>(layerShapeVec.size()),
+                               layerGlobal.colorMode.c_str(), layerGlobal.colorTransform.c_str(),
+                               layerTransform(layerGlobal.globalTransform));
+    ALOGV("%s", layerShapeKey.c_str());
+
+    std::sort(layerShapeVec.begin(), layerShapeVec.end(), std::greater<std::string>());
+    for (auto const& s : layerShapeVec) {
+        layerShapeKey += s;
+    }
+
+    mLayerShapeStatsMap[layerShapeKey]++;
 }
 
 void LayerStats::dump(String8& result) {
     ATRACE_CALL();
     ALOGD("Dumping");
-    result.append("Count,DstPosX,DstPosY,DstWidth,DstHeight,LayerType,WScale,HScale,");
-    result.append("Transform,PixelFormat,Dataspace\n");
     std::lock_guard<std::mutex> lock(mMutex);
-    for (auto& u : mLayerStatsMap) {
+    result.append("Frequency,LayerCount,ColorMode,ColorTransform,Orientation\n");
+    result.append("LayerType,CompositionType,IsProtected,Transform,PixelFormat,Dataspace,");
+    result.append("DstX,DstY,DstWidth,DstHeight,WScale,HScale,Alpha\n");
+    for (auto& u : mLayerShapeStatsMap) {
         result.appendFormat("%u,%s\n", u.second, u.first.c_str());
     }
 }
@@ -129,6 +157,14 @@
     return getTransformName(static_cast<hwc_transform_t>(transform));
 }
 
+const char* LayerStats::layerCompositionType(int32_t compositionType) {
+    return getCompositionName(static_cast<hwc2_composition_t>(compositionType));
+}
+
+const char* LayerStats::layerPixelFormat(int32_t pixelFormat) {
+    return decodePixelFormat(pixelFormat).c_str();
+}
+
 std::string LayerStats::scaleRatioWH(const LayerProtoParser::Layer* layer) {
     if (!layer->type.compare("ColorLayer")) return "N/A,N/A";
     std::string ret = "";
@@ -166,6 +202,21 @@
     return ">=16";
 }
 
+const char* LayerStats::alpha(float a) {
+    if (a == 1.0f) return "1.0";
+    if (a > 0.9f) return "0.99";
+    if (a > 0.8f) return "0.9";
+    if (a > 0.7f) return "0.8";
+    if (a > 0.6f) return "0.7";
+    if (a > 0.5f) return "0.6";
+    if (a > 0.4f) return "0.5";
+    if (a > 0.3f) return "0.4";
+    if (a > 0.2f) return "0.3";
+    if (a > 0.1f) return "0.2";
+    if (a > 0.0f) return "0.1";
+    return "0.0";
+}
+
 bool LayerStats::isRotated(int32_t transform) {
     return transform & HWC_TRANSFORM_ROT_90;
 }
diff --git a/services/surfaceflinger/LayerStats.h b/services/surfaceflinger/LayerStats.h
index 9522725..7871fc6 100644
--- a/services/surfaceflinger/LayerStats.h
+++ b/services/surfaceflinger/LayerStats.h
@@ -38,18 +38,25 @@
 private:
     // Traverse layer tree to get all visible layers' stats
     void traverseLayerTreeStatsLocked(
-        std::vector<std::unique_ptr<LayerProtoParser::Layer>> layerTree,
-        const LayerProtoParser::LayerGlobal* layerGlobal);
+            std::vector<std::unique_ptr<LayerProtoParser::Layer>> layerTree,
+            const LayerProtoParser::LayerGlobal* layerGlobal,
+            std::vector<std::string>& layerShapeVec);
     // Convert layer's top-left position into 8x8 percentage of the display
     static const char* destinationLocation(int32_t location, int32_t range, bool isHorizontal);
     // Convert layer's size into 8x8 percentage of the display
     static const char* destinationSize(int32_t size, int32_t range, bool isWidth);
     // Return the name of the transform
     static const char* layerTransform(int32_t transform);
+    // Return the name of the composition type
+    static const char* layerCompositionType(int32_t compositionType);
+    // Return the name of the pixel format
+    static const char* layerPixelFormat(int32_t pixelFormat);
     // Calculate scale ratios of layer's width/height with rotation information
     static std::string scaleRatioWH(const LayerProtoParser::Layer* layer);
     // Calculate scale ratio from source to destination and convert to string
     static const char* scaleRatio(int32_t destinationScale, int32_t sourceScale);
+    // Bucket the alpha into designed buckets
+    static const char* alpha(float a);
     // Return whether the original buffer is rotated in final composition
     static bool isRotated(int32_t transform);
     // Return whether the original buffer is V-flipped in final composition
@@ -60,10 +67,10 @@
     bool mEnabled = false;
     // Protect mLayersStatsMap
     std::mutex mMutex;
-    // Hashmap for tracking the layer stats
-    // KEY is a concatenation of a particular set of layer properties
-    // VALUE is the number of times this particular get scanned out
-    std::unordered_map<std::string, uint32_t> mLayerStatsMap;
+    // Hashmap for tracking the frame(layer shape) stats
+    // KEY is a concatenation of all layers' properties within a frame
+    // VALUE is the number of times this particular set has been scanned out
+    std::unordered_map<std::string, uint32_t> mLayerShapeStatsMap;
 };
 
 }  // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b7931bc..e104727 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1959,6 +1959,7 @@
             continue;
         }
         if (colorMatrix != mPreviousColorMatrix) {
+            displayDevice->setColorTransform(colorMatrix);
             status_t result = getBE().mHwc->setColorTransform(hwcId, colorMatrix);
             ALOGE_IF(result != NO_ERROR, "Failed to set color transform on "
                     "display %zd: %d", displayId, result);
@@ -4027,15 +4028,19 @@
 
 LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(int32_t hwcId) const {
     LayersProto layersProto;
-
     const sp<DisplayDevice>& displayDevice(mDisplays[hwcId]);
+
     SizeProto* resolution = layersProto.mutable_resolution();
     resolution->set_w(displayDevice->getWidth());
     resolution->set_h(displayDevice->getHeight());
 
+    layersProto.set_color_mode(decodeColorMode(displayDevice->getActiveColorMode()));
+    layersProto.set_color_transform(decodeColorTransform(displayDevice->getColorTransform()));
+    layersProto.set_global_transform(
+            static_cast<int32_t>(displayDevice->getOrientationTransform()));
+
     mDrawingState.traverseInZOrder([&](Layer* layer) {
-        if (!layer->visibleRegion.isEmpty() &&
-            layer->getBE().mHwcLayers.count(hwcId)) {
+        if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(hwcId)) {
             LayerProto* layerProto = layersProto.add_layers();
             layer->writeToProto(layerProto, hwcId);
         }
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index b10e07b..452592e 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -44,7 +44,12 @@
 
 const LayerProtoParser::LayerGlobal LayerProtoParser::generateLayerGlobalInfo(
         const LayersProto& layersProto) {
-    return {{layersProto.resolution().w(), layersProto.resolution().h()}};
+    LayerGlobal layerGlobal;
+    layerGlobal.resolution = {layersProto.resolution().w(), layersProto.resolution().h()};
+    layerGlobal.colorMode = layersProto.color_mode();
+    layerGlobal.colorTransform = layersProto.color_transform();
+    layerGlobal.globalTransform = layersProto.global_transform();
+    return layerGlobal;
 }
 
 std::vector<std::unique_ptr<LayerProtoParser::Layer>> LayerProtoParser::generateLayerTree(
@@ -116,6 +121,8 @@
     layer->hwcTransform = layerProto.hwc_transform();
     layer->windowType = layerProto.window_type();
     layer->appId = layerProto.app_id();
+    layer->hwcCompositionType = layerProto.hwc_composition_type();
+    layer->isProtected = layerProto.is_protected();
 
     return layer;
 }
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index fd893da..74a6f28 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -112,6 +112,8 @@
         int32_t hwcTransform;
         int32_t windowType;
         int32_t appId;
+        int32_t hwcCompositionType;
+        bool isProtected;
 
         std::string to_string() const;
     };
@@ -119,6 +121,9 @@
     class LayerGlobal {
     public:
         int2 resolution;
+        std::string colorMode;
+        std::string colorTransform;
+        int32_t globalTransform;
     };
 
     static const LayerGlobal generateLayerGlobalInfo(const LayersProto& layersProto);
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 6675aae..77c6675 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -8,6 +8,9 @@
 message LayersProto {
   repeated LayerProto layers = 1;
   optional SizeProto resolution = 2;
+  optional string color_mode = 3;
+  optional string color_transform = 4;
+  optional int32 global_transform = 5;
 }
 
 // Information about each layer.
@@ -73,6 +76,10 @@
   optional int32 hwc_transform = 32;
   optional int32 window_type = 33;
   optional int32 app_id = 34;
+  // The layer's composition type
+  optional int32 hwc_composition_type = 35;
+  // If it's a buffer layer, indicate if the content is protected
+  optional bool is_protected = 36;
 }
 
 message PositionProto {