Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit db0232d8 authored by Peiyong Lin's avatar Peiyong Lin Committed by Android (Google) Code Review
Browse files

Merge "[SurfaceFlinger] Add support to capture protected contents."

parents 396fed9b 05cc0118
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -586,6 +586,7 @@ status_t CaptureArgs::write(Parcel& output) const {
    SAFE_PARCEL(output.writeBool, captureSecureLayers);
    SAFE_PARCEL(output.writeInt32, uid);
    SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(dataspace));
    SAFE_PARCEL(output.writeBool, allowProtected);
    return NO_ERROR;
}

@@ -599,6 +600,7 @@ status_t CaptureArgs::read(const Parcel& input) {
    SAFE_PARCEL(input.readInt32, &uid);
    SAFE_PARCEL(input.readInt32, &value);
    dataspace = static_cast<ui::Dataspace>(value);
    SAFE_PARCEL(input.readBool, &allowProtected);
    return NO_ERROR;
}

+9 −1
Original line number Diff line number Diff line
@@ -318,6 +318,14 @@ struct CaptureArgs {
    // NOTE: In normal cases, we want the screen to be captured in display's colorspace.
    ui::Dataspace dataspace = ui::Dataspace::UNKNOWN;

    // The receiver of the capture can handle protected buffer. A protected buffer has
    // GRALLOC_USAGE_PROTECTED usage bit and must not be accessed unprotected behaviour.
    // Any read/write access from unprotected context will result in undefined behaviour.
    // Protected contents are typically DRM contents. This has no direct implication to the
    // secure property of the surface, which is specified by the application explicitly to avoid
    // the contents being accessed/captured by screenshot or unsecure display.
    bool allowProtected = false;

    virtual status_t write(Parcel& output) const;
    virtual status_t read(const Parcel& input);
};
@@ -345,7 +353,7 @@ struct ScreenCaptureResults {
    sp<GraphicBuffer> buffer;
    bool capturedSecureLayers{false};
    ui::Dataspace capturedDataspace{ui::Dataspace::V0_SRGB};
    status_t result = NO_ERROR;
    status_t result = OK;

    status_t write(Parcel& output) const;
    status_t read(const Parcel& input);
+3 −2
Original line number Diff line number Diff line
@@ -465,7 +465,7 @@ public:
    virtual bool canReceiveInput() const;

    /*
     * isProtected - true if the layer may contain protected content in the
     * isProtected - true if the layer may contain protected contents in the
     * GRALLOC_USAGE_PROTECTED sense.
     */
    virtual bool isProtected() const { return false; }
@@ -677,7 +677,8 @@ public:

    /*
     * isSecure - true if this surface is secure, that is if it prevents
     * screenshots or VNC servers.
     * screenshots or VNC servers. A surface can be set to be secure by the
     * application, being secure doesn't mean the surface has DRM contents.
     */
    bool isSecure() const;

+67 −49
Original line number Diff line number Diff line
@@ -5381,6 +5381,45 @@ static status_t validateScreenshotPermissions(const CaptureArgs& captureArgs) {
    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();
@@ -5429,46 +5468,7 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
    };

    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,
@@ -5503,7 +5503,8 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack,
    };

    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,
@@ -5624,18 +5625,32 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
    };

    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),
@@ -5646,7 +5661,7 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,

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();

@@ -5704,6 +5719,8 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
                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.
@@ -5748,14 +5765,13 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
    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,
@@ -5793,7 +5809,7 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
    // 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);

@@ -5805,6 +5821,8 @@ status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
            layer->onLayerDisplayed(releaseFence);
        }
    }
    // Always switch back to unprotected context.
    getRenderEngine().useProtectedContext(false);

    return NO_ERROR;
}
+5 −4
Original line number Diff line number Diff line
@@ -797,13 +797,14 @@ private:
    // Boot animation, on/off animations and screen capture
    void startBootAnim();

    status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction,
                                    const sp<GraphicBuffer>&, bool forSystem, int* outSyncFd,
                                    bool regionSampling, ScreenCaptureResults&);
    status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize,
                                 ui::PixelFormat, const sp<IScreenCaptureListener>&);
                                 ui::PixelFormat, const bool allowProtected,
                                 const sp<IScreenCaptureListener>&);
    status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, sp<GraphicBuffer>&,
                                 bool regionSampling, const sp<IScreenCaptureListener>&);
    status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction,
                                    const sp<GraphicBuffer>&, bool forSystem, int* outSyncFd,
                                    bool regionSampling, ScreenCaptureResults&);

    sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock);
    sp<DisplayDevice> getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock);