[SurfaceFlinger] add getDisplayedContentSample i/f

Add interface to ISurfaceComposer that can query the
graphics.composer for statistics on the displayed pixel content.

Bug: 116028618
Test: Boot
Test: ran test client, see data collected
Change-Id: Ide9b81b80c3399e7d648c7b611514e0d699120de
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 7d26151..f1fefcc 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -651,6 +651,49 @@
                                    &reply);
         return result;
     }
+
+    virtual status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
+                                               uint64_t timestamp,
+                                               DisplayedFrameStats* outStats) const {
+        if (!outStats) return BAD_VALUE;
+
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeStrongBinder(display);
+        data.writeUint64(maxFrames);
+        data.writeUint64(timestamp);
+
+        status_t result =
+                remote()->transact(BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLE, data, &reply);
+
+        if (result != NO_ERROR) {
+            return result;
+        }
+
+        result = reply.readUint64(&outStats->numFrames);
+        if (result != NO_ERROR) {
+            return result;
+        }
+
+        result = reply.readInt64Vector(
+                reinterpret_cast<std::vector<int64_t>*>(&outStats->component_0_sample));
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt64Vector(
+                reinterpret_cast<std::vector<int64_t>*>(&outStats->component_1_sample));
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt64Vector(
+                reinterpret_cast<std::vector<int64_t>*>(&outStats->component_2_sample));
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt64Vector(
+                reinterpret_cast<std::vector<int64_t>*>(&outStats->component_3_sample));
+        return result;
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -1055,6 +1098,40 @@
             return setDisplayContentSamplingEnabled(display, enable,
                                                     static_cast<uint8_t>(componentMask), maxFrames);
         }
+        case GET_DISPLAYED_CONTENT_SAMPLE: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+
+            sp<IBinder> display = data.readStrongBinder();
+            uint64_t maxFrames = 0;
+            uint64_t timestamp = 0;
+
+            status_t result = data.readUint64(&maxFrames);
+            if (result != NO_ERROR) {
+                ALOGE("getDisplayedContentSample failure in reading max frames: %d", result);
+                return result;
+            }
+
+            result = data.readUint64(&timestamp);
+            if (result != NO_ERROR) {
+                ALOGE("getDisplayedContentSample failure in reading timestamp: %d", result);
+                return result;
+            }
+
+            DisplayedFrameStats stats;
+            result = getDisplayedContentSample(display, maxFrames, timestamp, &stats);
+            if (result == NO_ERROR) {
+                reply->writeUint64(stats.numFrames);
+                reply->writeInt64Vector(
+                        *reinterpret_cast<std::vector<int64_t>*>(&stats.component_0_sample));
+                reply->writeInt64Vector(
+                        *reinterpret_cast<std::vector<int64_t>*>(&stats.component_1_sample));
+                reply->writeInt64Vector(
+                        *reinterpret_cast<std::vector<int64_t>*>(&stats.component_2_sample));
+                reply->writeInt64Vector(
+                        *reinterpret_cast<std::vector<int64_t>*>(&stats.component_3_sample));
+            }
+            return result;
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 405d228..070b253 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1106,6 +1106,12 @@
                                                                                    maxFrames);
 }
 
+status_t SurfaceComposerClient::getDisplayedContentSample(const sp<IBinder>& display,
+                                                          uint64_t maxFrames, uint64_t timestamp,
+                                                          DisplayedFrameStats* outStats) {
+    return ComposerService::getComposerService()->getDisplayedContentSample(display, maxFrames,
+                                                                            timestamp, outStats);
+}
 // ----------------------------------------------------------------------------
 
 status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 41369c8..3052c0b 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -27,10 +27,11 @@
 
 #include <binder/IInterface.h>
 
+#include <ui/DisplayedFrameStats.h>
 #include <ui/FrameStats.h>
-#include <ui/PixelFormat.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/GraphicTypes.h>
+#include <ui/PixelFormat.h>
 
 #include <vector>
 
@@ -308,6 +309,14 @@
     virtual status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
                                                       uint8_t componentMask,
                                                       uint64_t maxFrames) const = 0;
+
+    /* Returns statistics on the color profile of the last frame displayed for a given display
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
+                                               uint64_t timestamp,
+                                               DisplayedFrameStats* outStats) const = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -349,6 +358,7 @@
         GET_COLOR_MANAGEMENT,
         GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES,
         SET_DISPLAY_CONTENT_SAMPLING_ENABLED,
+        GET_DISPLAYED_CONTENT_SAMPLE,
     };
 
     virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index ba943a0..2b107aa 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -30,6 +30,7 @@
 #include <utils/SortedVector.h>
 #include <utils/threads.h>
 
+#include <ui/DisplayedFrameStats.h>
 #include <ui/FrameStats.h>
 #include <ui/GraphicTypes.h>
 #include <ui/PixelFormat.h>
@@ -389,6 +390,9 @@
     static status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
                                                      uint8_t componentMask, uint64_t maxFrames);
 
+    static status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
+                                              uint64_t timestamp, DisplayedFrameStats* outStats);
+
 private:
     virtual void onFirstRef();
 
diff --git a/libs/gui/tests/DisplayedContentSampling_test.cpp b/libs/gui/tests/DisplayedContentSampling_test.cpp
index f9d5dd6..5443812 100644
--- a/libs/gui/tests/DisplayedContentSampling_test.cpp
+++ b/libs/gui/tests/DisplayedContentSampling_test.cpp
@@ -104,4 +104,19 @@
                                                                0);
     EXPECT_EQ(OK, status);
 }
+
+TEST_F(DisplayedContentSamplingTest, SampleCollectionCoherentWithSupportMask) {
+    if (shouldSkipTest()) return;
+
+    DisplayedFrameStats stats;
+    status_t status = mComposerClient->getDisplayedContentSample(mDisplayToken, 0, 0, &stats);
+    EXPECT_EQ(OK, status);
+    if (stats.numFrames <= 0) return;
+
+    if (componentMask & (0x1 << 0)) EXPECT_NE(0, stats.component_0_sample.size());
+    if (componentMask & (0x1 << 1)) EXPECT_NE(0, stats.component_1_sample.size());
+    if (componentMask & (0x1 << 2)) EXPECT_NE(0, stats.component_2_sample.size());
+    if (componentMask & (0x1 << 3)) EXPECT_NE(0, stats.component_3_sample.size());
+}
+
 } // namespace android
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index cb1756f..d37b810 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -652,6 +652,11 @@
                                               uint64_t /*maxFrames*/) const override {
         return NO_ERROR;
     }
+    status_t getDisplayedContentSample(const sp<IBinder>& /*display*/, uint64_t /*maxFrames*/,
+                                       uint64_t /*timestamp*/,
+                                       DisplayedFrameStats* /*outStats*/) const override {
+        return NO_ERROR;
+    }
 
     virtual status_t getColorManagement(bool* /*outGetColorManagement*/) const { return NO_ERROR; }