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

Commit 0390077c authored by chaviw's avatar chaviw
Browse files

Run screen capture requests asynchronously

After posting the screenshot request to the main thread, don't wait for
the results and instead just return immediately. The results from the
screenshot will be sent through the requested ScreenCaptureListener

In the current change, SurfaceComposerClient still waits for the
result before returning so the JNI callers still get the screenshot
synchronously. The call will become asynchronous in native in a later
change.

Test: SurfaceFlinger_test
Test: adb shell screencap
Test: power + volume down screenshot
Test: Recents screenshots
Change-Id: I5e352d6920b9298a0a376354f977f2ef7456841b
parent a52ade19
Loading
Loading
Loading
Loading
+19 −2
Original line number Diff line number Diff line
@@ -446,9 +446,26 @@ void RegionSamplingThread::captureSample() {
                                   PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
    }

    ScreenCaptureResults captureResults;
    class SyncScreenCaptureListener : public BnScreenCaptureListener {
    public:
        status_t onScreenCaptureComplete(const ScreenCaptureResults& captureResults) override {
            resultsPromise.set_value(captureResults);
            return NO_ERROR;
        }

        ScreenCaptureResults waitForResults() {
            std::future<ScreenCaptureResults> resultsFuture = resultsPromise.get_future();
            return resultsFuture.get();
        }

    private:
        std::promise<ScreenCaptureResults> resultsPromise;
    };

    const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
    mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
                                 true /* regionSampling */, captureResults);
                                 true /* regionSampling */, captureListener);
    ScreenCaptureResults captureResults = captureListener->waitForResults();

    std::vector<Descriptor> activeDescriptors;
    for (const auto& descriptor : descriptors) {
+48 −57
Original line number Diff line number Diff line
@@ -5530,12 +5530,9 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
    auto traverseLayers = [this, args, layerStack](const LayerVector::Visitor& visitor) {
        traverseLayersInLayerStack(layerStack, args.uid, visitor);
    };
    ScreenCaptureResults captureResults;
    status_t status = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
                                          args.pixelFormat, captureResults);
    captureResults.result = status;
    captureListener->onScreenCaptureComplete(captureResults);
    return status;

    return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
                               args.pixelFormat, captureListener);
}

status_t SurfaceFlinger::setSchedFifo(bool enabled) {
@@ -5608,12 +5605,8 @@ status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack,
        traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor);
    };

    ScreenCaptureResults captureResults;
    status_t status = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
                                          ui::PixelFormat::RGBA_8888, captureResults);
    captureResults.result = status;
    captureListener->onScreenCaptureComplete(captureResults);
    return status;
    return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
                               ui::PixelFormat::RGBA_8888, captureListener);
}

status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
@@ -5704,7 +5697,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
                                                 captureSecureLayers);
    });

    auto traverseLayers = [parent, args, &excludeLayers](const LayerVector::Visitor& visitor) {
    auto traverseLayers = [parent, args, excludeLayers](const LayerVector::Visitor& visitor) {
        parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
            if (!layer->isVisible()) {
                return;
@@ -5726,18 +5719,14 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
        });
    };

    ScreenCaptureResults captureResults;
    status_t status = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
                                          args.pixelFormat, captureResults);
    captureResults.result = status;
    captureListener->onScreenCaptureComplete(captureResults);
    return status;
    return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
                               args.pixelFormat, captureListener);
}

status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
                                             TraverseLayersFunction traverseLayers,
                                             ui::Size bufferSize, ui::PixelFormat reqPixelFormat,
                                             ScreenCaptureResults& captureResults) {
                                             const sp<IScreenCaptureListener>& captureListener) {
    ATRACE_CALL();

    // TODO(b/116112787) Make buffer usage a parameter.
@@ -5747,54 +5736,56 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
            getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(),
                                             static_cast<android_pixel_format>(reqPixelFormat),
                                             1 /* layerCount */, usage, "screenshot");

    return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
                               false /* regionSampling */, captureResults);
                               false /* regionSampling */, captureListener);
}

status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
                                             TraverseLayersFunction traverseLayers,
                                             const sp<GraphicBuffer>& buffer, bool regionSampling,
                                             ScreenCaptureResults& captureResults) {
                                             sp<GraphicBuffer>& buffer, bool regionSampling,
                                             const sp<IScreenCaptureListener>& captureListener) {
    ATRACE_CALL();

    if (captureListener == nullptr) {
        ALOGE("capture screen must provide a capture listener callback");
        return BAD_VALUE;
    }

    const int uid = IPCThreadState::self()->getCallingUid();
    const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;

    status_t result;
    int syncFd;

    do {
        std::tie(result, syncFd) =
                schedule([&]() -> std::pair<status_t, int> {
    static_cast<void>(schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable {
        if (mRefreshPending) {
            ALOGW("Skipping screenshot for now");
                        return {EAGAIN, -1};
            captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, regionSampling,
                                captureListener);
            return;
        }
        ScreenCaptureResults captureResults;
        std::unique_ptr<RenderArea> renderArea = renderAreaFuture.get();
        if (!renderArea) {
            ALOGW("Skipping screen capture because of invalid render area.");
                        return {NO_MEMORY, -1};
            captureResults.result = NO_MEMORY;
            captureListener->onScreenCaptureComplete(captureResults);
            return;
        }

        status_t result = NO_ERROR;
                    int fd = -1;

                    Mutex::Autolock lock(mStateLock);
        int syncFd = -1;
        renderArea->render([&] {
                        result = renderScreenImplLocked(*renderArea, traverseLayers, buffer.get(),
                                                        forSystem, &fd, regionSampling,
                                                        captureResults);
            result = renderScreenImplLocked(*renderArea, traverseLayers, buffer, forSystem, &syncFd,
                                            regionSampling, captureResults);
        });

                    return {result, fd};
                }).get();
    } while (result == EAGAIN);

        if (result == NO_ERROR) {
            sync_wait(syncFd, -1);
            close(syncFd);
        }
        captureResults.result = result;
        captureListener->onScreenCaptureComplete(captureResults);
    }));

    return result;
    return NO_ERROR;
}

status_t SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
+7 −7
Original line number Diff line number Diff line
@@ -781,14 +781,14 @@ private:
    // Boot animation, on/off animations and screen capture
    void startBootAnim();

    status_t renderScreenImplLocked(const RenderArea& renderArea,
                                    TraverseLayersFunction traverseLayers,
                                    const sp<GraphicBuffer>& buffer, bool forSystem, int* outSyncFd,
                                    bool regionSampling, ScreenCaptureResults& captureResults);
    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, ScreenCaptureResults& captureResults);
    status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, const sp<GraphicBuffer>&,
                                 bool regionSampling, ScreenCaptureResults& captureResults);
                                 ui::PixelFormat, const sp<IScreenCaptureListener>&);
    status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, sp<GraphicBuffer>&,
                                 bool regionSampling, const sp<IScreenCaptureListener>&);

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