Merge "Implement Display Layer Stats V0.1"
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 7aa660e..5428e2e 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"
@@ -1929,6 +1930,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 6b3c5a4..b9e5d3f 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);
@@ -4028,15 +4029,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 {