Hdr format settings [Backend]

Added new API to SurfaceControl to override the HDR formats supported by
device in SurfaceFlinger. This API is used in the CTS Tests to verify
HDR capabilities and enabling/disabling of HDR formats.

Bug: 172905874
Test: atest CtsDisplayTestCases
Change-Id: Icb13cdd638d315c0e23ece8aa61242470404a428
Merged-In: Icb13cdd638d315c0e23ece8aa61242470404a428
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index ceab6ec..97f8f47 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -477,6 +477,26 @@
         return reply.readInt32();
     }
 
+    virtual status_t overrideHdrTypes(const sp<IBinder>& display,
+                                      const std::vector<ui::Hdr>& hdrTypes) {
+        Parcel data, reply;
+        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
+        SAFE_PARCEL(data.writeStrongBinder, display);
+
+        std::vector<int32_t> hdrTypesVector;
+        for (ui::Hdr i : hdrTypes) {
+            hdrTypesVector.push_back(static_cast<int32_t>(i));
+        }
+        SAFE_PARCEL(data.writeInt32Vector, hdrTypesVector);
+
+        status_t result = remote()->transact(BnSurfaceComposer::OVERRIDE_HDR_TYPES, data, &reply);
+        if (result != NO_ERROR) {
+            ALOGE("overrideHdrTypes failed to transact: %d", result);
+            return result;
+        }
+        return result;
+    }
+
     status_t enableVSyncInjections(bool enable) override {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -1963,6 +1983,20 @@
             SAFE_PARCEL(reply->writeInt32, extraBuffers);
             return NO_ERROR;
         }
+        case OVERRIDE_HDR_TYPES: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<IBinder> display = nullptr;
+            SAFE_PARCEL(data.readStrongBinder, &display);
+
+            std::vector<int32_t> hdrTypes;
+            SAFE_PARCEL(data.readInt32Vector, &hdrTypes);
+
+            std::vector<ui::Hdr> hdrTypesVector;
+            for (int i : hdrTypes) {
+                hdrTypesVector.push_back(static_cast<ui::Hdr>(i));
+            }
+            return overrideHdrTypes(display, hdrTypesVector);
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index d7b2c2e..0b01084 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1985,6 +1985,11 @@
     return ComposerService::getComposerService()->getAnimationFrameStats(outStats);
 }
 
+status_t SurfaceComposerClient::overrideHdrTypes(const sp<IBinder>& display,
+                                                 const std::vector<ui::Hdr>& hdrTypes) {
+    return ComposerService::getComposerService()->overrideHdrTypes(display, hdrTypes);
+}
+
 status_t SurfaceComposerClient::getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
                                                                       ui::PixelFormat* outFormat,
                                                                       ui::Dataspace* outDataspace,
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 35990d1..9f9ca74 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -267,6 +267,13 @@
      */
     virtual status_t getAnimationFrameStats(FrameStats* outStats) const = 0;
 
+    /* Overrides the supported HDR modes for the given display device.
+     *
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     */
+    virtual status_t overrideHdrTypes(const sp<IBinder>& display,
+                                      const std::vector<ui::Hdr>& hdrTypes) = 0;
+
     virtual status_t enableVSyncInjections(bool enable) = 0;
 
     virtual status_t injectVSync(nsecs_t when) = 0;
@@ -570,6 +577,7 @@
         GET_DYNAMIC_DISPLAY_INFO,
         ADD_FPS_LISTENER,
         REMOVE_FPS_LISTENER,
+        OVERRIDE_HDR_TYPES,
         // Always append new enum to the end.
     };
 
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index a643e9e..c38375c 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -572,6 +572,9 @@
     static status_t clearAnimationFrameStats();
     static status_t getAnimationFrameStats(FrameStats* outStats);
 
+    static status_t overrideHdrTypes(const sp<IBinder>& display,
+                                     const std::vector<ui::Hdr>& hdrTypes);
+
     static void setDisplayProjection(const sp<IBinder>& token, ui::Rotation orientation,
                                      const Rect& layerStackRect, const Rect& displayRect);
 
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 8d7f8c9..5ac3f19 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -772,6 +772,10 @@
     status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
         return NO_ERROR;
     }
+    status_t overrideHdrTypes(const sp<IBinder>& /*display*/,
+                              const std::vector<ui::Hdr>& /*hdrTypes*/) override {
+        return NO_ERROR;
+    }
     status_t enableVSyncInjections(bool /*enable*/) override {
         return NO_ERROR;
     }
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index f4a2a3f..b7b2cc6 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -354,8 +354,20 @@
     return mCompositionDisplay->getDisplayColorProfile()->getSupportedPerFrameMetadata();
 }
 
-const HdrCapabilities& DisplayDevice::getHdrCapabilities() const {
-    return mCompositionDisplay->getDisplayColorProfile()->getHdrCapabilities();
+void DisplayDevice::overrideHdrTypes(const std::vector<ui::Hdr>& hdrTypes) {
+    mOverrideHdrTypes = hdrTypes;
+}
+
+HdrCapabilities DisplayDevice::getHdrCapabilities() const {
+    const HdrCapabilities& capabilities =
+            mCompositionDisplay->getDisplayColorProfile()->getHdrCapabilities();
+    std::vector<ui::Hdr> hdrTypes = capabilities.getSupportedHdrTypes();
+    if (!mOverrideHdrTypes.empty()) {
+        hdrTypes = mOverrideHdrTypes;
+    }
+    return HdrCapabilities(hdrTypes, capabilities.getDesiredMaxLuminance(),
+                           capabilities.getDesiredMaxAverageLuminance(),
+                           capabilities.getDesiredMinLuminance());
 }
 
 std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1);
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 7156613..68846d3 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -126,13 +126,15 @@
     bool hasHLGSupport() const;
     bool hasDolbyVisionSupport() const;
 
+    void overrideHdrTypes(const std::vector<ui::Hdr>& hdrTypes);
+
     // The returned HdrCapabilities is the combination of HDR capabilities from
     // hardware composer and RenderEngine. When the DisplayDevice supports wide
     // color gamut, RenderEngine is able to simulate HDR support in Display P3
     // color space for both PQ and HLG HDR contents. The minimum and maximum
     // luminance will be set to sDefaultMinLumiance and sDefaultMaxLumiance
     // respectively if hardware composer doesn't return meaningful values.
-    const HdrCapabilities& getHdrCapabilities() const;
+    HdrCapabilities getHdrCapabilities() const;
 
     // Return true if intent is supported by the display.
     bool hasRenderIntent(ui::RenderIntent intent) const;
@@ -217,6 +219,8 @@
     const bool mIsPrimary;
 
     std::optional<DeviceProductInfo> mDeviceProductInfo;
+
+    std::vector<ui::Hdr> mOverrideHdrTypes;
 };
 
 struct DisplayDeviceState {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 31097aa..f9636ca 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1287,6 +1287,21 @@
     return NO_ERROR;
 }
 
+status_t SurfaceFlinger::overrideHdrTypes(const sp<IBinder>& displayToken,
+                                          const std::vector<ui::Hdr>& hdrTypes) {
+    Mutex::Autolock lock(mStateLock);
+
+    auto display = getDisplayDeviceLocked(displayToken);
+    if (!display) {
+        ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
+        return NAME_NOT_FOUND;
+    }
+
+    display->overrideHdrTypes(hdrTypes);
+    dispatchDisplayHotplugEvent(display->getPhysicalId(), true /* connected */);
+    return NO_ERROR;
+}
+
 status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp<IBinder>& displayToken,
                                                                ui::PixelFormat* outFormat,
                                                                ui::Dataspace* outDataspace,
@@ -5013,6 +5028,7 @@
         case DESTROY_DISPLAY:
         case ENABLE_VSYNC_INJECTIONS:
         case GET_ANIMATION_FRAME_STATS:
+        case OVERRIDE_HDR_TYPES:
         case GET_HDR_CAPABILITIES:
         case SET_DESIRED_DISPLAY_MODE_SPECS:
         case GET_DESIRED_DISPLAY_MODE_SPECS:
@@ -5029,9 +5045,11 @@
         case NOTIFY_POWER_BOOST:
         case SET_GLOBAL_SHADOW_SETTINGS:
         case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
-            // ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN is used by CTS tests, which acquire the
-            // necessary permission dynamically. Don't use the permission cache for this check.
-            bool usePermissionCache = code != ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN;
+            // ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN and OVERRIDE_HDR_TYPES are used by CTS tests,
+            // which acquire the necessary permission dynamically. Don't use the permission cache
+            // for this check.
+            bool usePermissionCache =
+                    code != ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN && code != OVERRIDE_HDR_TYPES;
             if (!callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) {
                 IPCThreadState* ipc = IPCThreadState::self();
                 ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d",
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8d2f66d..e4ff6c9 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -642,6 +642,8 @@
     void setPowerMode(const sp<IBinder>& displayToken, int mode) override;
     status_t clearAnimationFrameStats() override;
     status_t getAnimationFrameStats(FrameStats* outStats) const override;
+    status_t overrideHdrTypes(const sp<IBinder>& displayToken,
+                              const std::vector<ui::Hdr>& hdrTypes) override;
     status_t enableVSyncInjections(bool enable) override;
     status_t injectVSync(nsecs_t when) override;
     status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) override;