[SurfaceFlinger] Add support to capture protected contents.

Previously capture screen always use an unprotected buffer, which forces
layers with protected contents to be black. This patch enables to
capture with a protected buffer when there's no unprotected access to
the contents.

Bug: b/146180867
Test: N/A
Change-Id: I03a2c4f8d093f390abf7afb90aa3f7ea82f27ce4
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 575da26..e457659 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -5383,6 +5383,45 @@
     return PERMISSION_DENIED;
 }
 
+status_t SurfaceFlinger::setSchedFifo(bool enabled) {
+    static constexpr int kFifoPriority = 2;
+    static constexpr int kOtherPriority = 0;
+
+    struct sched_param param = {0};
+    int sched_policy;
+    if (enabled) {
+        sched_policy = SCHED_FIFO;
+        param.sched_priority = kFifoPriority;
+    } else {
+        sched_policy = SCHED_OTHER;
+        param.sched_priority = kOtherPriority;
+    }
+
+    if (sched_setscheduler(0, sched_policy, &param) != 0) {
+        return -errno;
+    }
+    return NO_ERROR;
+}
+
+sp<DisplayDevice> SurfaceFlinger::getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) {
+    if (const sp<IBinder> displayToken =
+                getPhysicalDisplayTokenLocked(PhysicalDisplayId{displayOrLayerStack})) {
+        return getDisplayDeviceLocked(displayToken);
+    }
+    // Couldn't find display by displayId. Try to get display by layerStack since virtual displays
+    // may not have a displayId.
+    return getDisplayByLayerStack(displayOrLayerStack);
+}
+
+sp<DisplayDevice> SurfaceFlinger::getDisplayByLayerStack(uint64_t layerStack) {
+    for (const auto& [token, display] : mDisplays) {
+        if (display->getLayerStack() == layerStack) {
+            return display;
+        }
+    }
+    return nullptr;
+}
+
 status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
                                         const sp<IScreenCaptureListener>& captureListener) {
     ATRACE_CALL();
@@ -5431,46 +5470,7 @@
     };
 
     return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
-                               args.pixelFormat, captureListener);
-}
-
-status_t SurfaceFlinger::setSchedFifo(bool enabled) {
-    static constexpr int kFifoPriority = 2;
-    static constexpr int kOtherPriority = 0;
-
-    struct sched_param param = {0};
-    int sched_policy;
-    if (enabled) {
-        sched_policy = SCHED_FIFO;
-        param.sched_priority = kFifoPriority;
-    } else {
-        sched_policy = SCHED_OTHER;
-        param.sched_priority = kOtherPriority;
-    }
-
-    if (sched_setscheduler(0, sched_policy, &param) != 0) {
-        return -errno;
-    }
-    return NO_ERROR;
-}
-
-sp<DisplayDevice> SurfaceFlinger::getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) {
-    if (const sp<IBinder> displayToken =
-                getPhysicalDisplayTokenLocked(PhysicalDisplayId{displayOrLayerStack})) {
-        return getDisplayDeviceLocked(displayToken);
-    }
-    // Couldn't find display by displayId. Try to get display by layerStack since virtual displays
-    // may not have a displayId.
-    return getDisplayByLayerStack(displayOrLayerStack);
-}
-
-sp<DisplayDevice> SurfaceFlinger::getDisplayByLayerStack(uint64_t layerStack) {
-    for (const auto& [token, display] : mDisplays) {
-        if (display->getLayerStack() == layerStack) {
-            return display;
-        }
-    }
-    return nullptr;
+                               args.pixelFormat, args.allowProtected, captureListener);
 }
 
 status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack,
@@ -5505,7 +5505,8 @@
     };
 
     return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
-                               ui::PixelFormat::RGBA_8888, captureListener);
+                               ui::PixelFormat::RGBA_8888, false /* allowProtected */,
+                               captureListener);
 }
 
 status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
@@ -5626,18 +5627,32 @@
     };
 
     return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
-                               args.pixelFormat, captureListener);
+                               args.pixelFormat, args.allowProtected, captureListener);
 }
 
 status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
                                              TraverseLayersFunction traverseLayers,
                                              ui::Size bufferSize, ui::PixelFormat reqPixelFormat,
+                                             const bool allowProtected,
                                              const sp<IScreenCaptureListener>& captureListener) {
     ATRACE_CALL();
 
-    // TODO(b/116112787) Make buffer usage a parameter.
-    const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
-            GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+    // Loop over all visible layers to see whether there's any protected layer. A protected layer is
+    // typically a layer with DRM contents, or have the GRALLOC_USAGE_PROTECTED set on the buffer.
+    // A protected layer has no implication on whether it's secure, which is explicitly set by
+    // application to avoid being screenshot or drawn via unsecure display.
+    const bool supportsProtected = getRenderEngine().supportsProtectedContent();
+    bool hasProtectedLayer = false;
+    if (allowProtected && supportsProtected) {
+        traverseLayers([&](Layer* layer) {
+            hasProtectedLayer = hasProtectedLayer || (layer->isVisible() && layer->isProtected());
+        });
+    }
+
+    const uint32_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE |
+            (hasProtectedLayer && allowProtected && supportsProtected
+                     ? GRALLOC_USAGE_PROTECTED
+                     : GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
     sp<GraphicBuffer> buffer =
             getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(),
                                              static_cast<android_pixel_format>(reqPixelFormat),
@@ -5648,7 +5663,7 @@
 
 status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
                                              TraverseLayersFunction traverseLayers,
-                                             sp<GraphicBuffer>& buffer, bool regionSampling,
+                                             sp<GraphicBuffer>& buffer, const bool regionSampling,
                                              const sp<IScreenCaptureListener>& captureListener) {
     ATRACE_CALL();
 
@@ -5706,6 +5721,8 @@
                 captureResults.capturedSecureLayers || (layer->isVisible() && layer->isSecure());
     });
 
+    const bool useProtected = buffer->getUsage() & GRALLOC_USAGE_PROTECTED;
+
     // We allow the system server to take screenshots of secure layers for
     // use in situations like the Screen-rotation animation and place
     // the impetus on WindowManager to not persist them.
@@ -5750,14 +5767,13 @@
     std::vector<Layer*> renderedLayers;
     Region clearRegion = Region::INVALID_REGION;
     traverseLayers([&](Layer* layer) {
-        const bool supportProtectedContent = false;
         Region clip(renderArea.getBounds());
         compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
                 clip,
                 layer->needsFilteringForScreenshots(display.get(), transform) ||
                         renderArea.needsFiltering(),
                 renderArea.isSecure(),
-                supportProtectedContent,
+                useProtected,
                 clearRegion,
                 layerStackSpaceRect,
                 clientCompositionDisplay.outputDataspace,
@@ -5795,7 +5811,7 @@
     // there is no need for synchronization with the GPU.
     base::unique_fd bufferFence;
     base::unique_fd drawFence;
-    getRenderEngine().useProtectedContext(false);
+    getRenderEngine().useProtectedContext(useProtected);
     getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer,
                                  /*useFramebufferCache=*/false, std::move(bufferFence), &drawFence);
 
@@ -5807,6 +5823,8 @@
             layer->onLayerDisplayed(releaseFence);
         }
     }
+    // Always switch back to unprotected context.
+    getRenderEngine().useProtectedContext(false);
 
     return NO_ERROR;
 }