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

Commit 1042a228 authored by Dan Stoza's avatar Dan Stoza Committed by android-build-merger
Browse files

Merge changes I23e6f088,I800208e8,I55123a7a into oc-dr1-dev

am: 607b5d1b

Change-Id: I51b25a25bae1517f64edf9ce072244addd1b3544
parents 6645d887 607b5d1b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -104,7 +104,7 @@ LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
    libhidltransport \
    libhwbinder

LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code -std=c++1z

include $(BUILD_SHARED_LIBRARY)

+244 −296
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <dlfcn.h>
#include <inttypes.h>
#include <stdatomic.h>
#include <optional>

#include <EGL/egl.h>

@@ -1053,6 +1054,7 @@ void SurfaceFlinger::signalLayerUpdate() {
}

void SurfaceFlinger::signalRefresh() {
    mRefreshPending = true;
    mEventQueue.refresh();
}

@@ -1398,6 +1400,8 @@ bool SurfaceFlinger::handleMessageInvalidate() {
void SurfaceFlinger::handleMessageRefresh() {
    ATRACE_CALL();

    mRefreshPending = false;

    nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);

    preComposition(refreshStartTime);
@@ -4043,128 +4047,88 @@ void SurfaceFlinger::repaintEverything() {
    signalTransaction();
}

// ---------------------------------------------------------------------------
// Capture screen into an IGraphiBufferProducer
// ---------------------------------------------------------------------------
// Checks that the requested width and height are valid and updates them to the display dimensions
// if they are set to 0
static status_t updateDimensionsLocked(const sp<const DisplayDevice>& displayDevice,
                                       Transform::orientation_flags rotation,
                                       uint32_t* requestedWidth, uint32_t* requestedHeight) {
    // get screen geometry
    uint32_t displayWidth = displayDevice->getWidth();
    uint32_t displayHeight = displayDevice->getHeight();

/* The code below is here to handle b/8734824
 *
 * We create a IGraphicBufferProducer wrapper that forwards all calls
 * from the surfaceflinger thread to the calling binder thread, where they
 * are executed. This allows the calling thread in the calling process to be
 * reused and not depend on having "enough" binder threads to handle the
 * requests.
 */
class GraphicProducerWrapper : public BBinder, public MessageHandler {
    /* Parts of GraphicProducerWrapper are run on two different threads,
     * communicating by sending messages via Looper but also by shared member
     * data. Coherence maintenance is subtle and in places implicit (ugh).
     *
     * Don't rely on Looper's sendMessage/handleMessage providing
     * release/acquire semantics for any data not actually in the Message.
     * Data going from surfaceflinger to binder threads needs to be
     * synchronized explicitly.
     *
     * Barrier open/wait do provide release/acquire semantics. This provides
     * implicit synchronization for data coming back from binder to
     * surfaceflinger threads.
     */
    if (rotation & Transform::ROT_90) {
        std::swap(displayWidth, displayHeight);
    }

    sp<IGraphicBufferProducer> impl;
    sp<Looper> looper;
    status_t result;
    bool exitPending;
    bool exitRequested;
    Barrier barrier;
    uint32_t code;
    Parcel const* data;
    Parcel* reply;

    enum {
        MSG_API_CALL,
        MSG_EXIT
    };
    if ((*requestedWidth > displayWidth) || (*requestedHeight > displayHeight)) {
        ALOGE("size mismatch (%d, %d) > (%d, %d)",
                *requestedWidth, *requestedHeight, displayWidth, displayHeight);
        return BAD_VALUE;
    }

    /*
     * Called on surfaceflinger thread. This is called by our "fake"
     * BpGraphicBufferProducer. We package the data and reply Parcel and
     * forward them to the binder thread.
     */
    virtual status_t transact(uint32_t code,
            const Parcel& data, Parcel* reply, uint32_t /* flags */) {
        this->code = code;
        this->data = &data;
        this->reply = reply;
        if (exitPending) {
            // if we've exited, we run the message synchronously right here.
            // note (JH): as far as I can tell from looking at the code, this
            // never actually happens. if it does, i'm not sure if it happens
            // on the surfaceflinger or binder thread.
            handleMessage(Message(MSG_API_CALL));
        } else {
            barrier.close();
            // Prevent stores to this->{code, data, reply} from being
            // reordered later than the construction of Message.
            atomic_thread_fence(memory_order_release);
            looper->sendMessage(this, Message(MSG_API_CALL));
            barrier.wait();
    if (*requestedWidth == 0) {
        *requestedWidth = displayWidth;
    }
        return result;
    if (*requestedHeight == 0) {
        *requestedHeight = displayHeight;
    }

    /*
     * here we run on the binder thread. All we've got to do is
     * call the real BpGraphicBufferProducer.
     */
    virtual void handleMessage(const Message& message) {
        int what = message.what;
        // Prevent reads below from happening before the read from Message
        atomic_thread_fence(memory_order_acquire);
        if (what == MSG_API_CALL) {
            result = IInterface::asBinder(impl)->transact(code, data[0], reply);
            barrier.open();
        } else if (what == MSG_EXIT) {
            exitRequested = true;
        }
    return NO_ERROR;
}

// A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope
class WindowDisconnector {
public:
    explicit GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl)
    :   impl(impl),
        looper(new Looper(true)),
        result(NO_ERROR),
        exitPending(false),
        exitRequested(false),
        code(0),
        data(NULL),
        reply(NULL)
    {}

    // Binder thread
    status_t waitForResponse() {
        do {
            looper->pollOnce(-1);
        } while (!exitRequested);
        return result;
    WindowDisconnector(ANativeWindow* window, int api) : mWindow(window), mApi(api) {}
    ~WindowDisconnector() {
        native_window_api_disconnect(mWindow, mApi);
    }

    // Client thread
    void exit(status_t result) {
        this->result = result;
        exitPending = true;
        // Ensure this->result is visible to the binder thread before it
        // handles the message.
        atomic_thread_fence(memory_order_release);
        looper->sendMessage(this, Message(MSG_EXIT));
    }
private:
    ANativeWindow* mWindow;
    const int mApi;
};

static status_t getWindowBuffer(ANativeWindow* window, uint32_t requestedWidth,
                                uint32_t requestedHeight, bool hasWideColorDisplay,
                                bool renderEngineUsesWideColor, ANativeWindowBuffer** outBuffer) {
    const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
            GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;

    int err = 0;
    err = native_window_set_buffers_dimensions(window, requestedWidth, requestedHeight);
    err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
    err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
    err |= native_window_set_usage(window, usage);

    if (hasWideColorDisplay) {
        err |= native_window_set_buffers_data_space(window,
                                                    renderEngineUsesWideColor
                                                            ? HAL_DATASPACE_DISPLAY_P3
                                                            : HAL_DATASPACE_V0_SRGB);
    }

    if (err != NO_ERROR) {
        return BAD_VALUE;
    }

    /* TODO: Once we have the sync framework everywhere this can use
     * server-side waits on the fence that dequeueBuffer returns.
     */
    err = native_window_dequeue_buffer_and_wait(window, outBuffer);
    if (err != NO_ERROR) {
        return err;
    }

    return NO_ERROR;
}

status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
        const sp<IGraphicBufferProducer>& producer,
        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
        int32_t minLayerZ, int32_t maxLayerZ,
        bool useIdentityTransform, ISurfaceComposer::Rotation rotation) {
    ATRACE_CALL();

    if (CC_UNLIKELY(display == 0))
        return BAD_VALUE;
@@ -4198,65 +4162,95 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
            break;
    }

    class MessageCaptureScreen : public MessageBase {
        SurfaceFlinger* flinger;
        sp<IBinder> display;
        sp<IGraphicBufferProducer> producer;
        Rect sourceCrop;
        uint32_t reqWidth, reqHeight;
        uint32_t minLayerZ,maxLayerZ;
        bool useIdentityTransform;
        Transform::orientation_flags rotation;
        status_t result;
        bool isLocalScreenshot;
    public:
        MessageCaptureScreen(SurfaceFlinger* flinger,
                const sp<IBinder>& display,
                const sp<IGraphicBufferProducer>& producer,
                Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
                int32_t minLayerZ, int32_t maxLayerZ,
                bool useIdentityTransform,
                Transform::orientation_flags rotation,
                bool isLocalScreenshot)
            : flinger(flinger), display(display), producer(producer),
              sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight),
              minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
              useIdentityTransform(useIdentityTransform),
              rotation(rotation), result(PERMISSION_DENIED),
              isLocalScreenshot(isLocalScreenshot)
        {
    { // Autolock scope
        Mutex::Autolock lock(mStateLock);
        sp<const DisplayDevice> displayDevice(getDisplayDeviceLocked(display));
        updateDimensionsLocked(displayDevice, rotationFlags, &reqWidth, &reqHeight);
    }
        status_t getResult() const {

    // create a surface (because we're a producer, and we need to
    // dequeue/queue a buffer)
    sp<Surface> surface = new Surface(producer, false);

    // Put the screenshot Surface into async mode so that
    // Layer::headFenceHasSignaled will always return true and we'll latch the
    // first buffer regardless of whether or not its acquire fence has
    // signaled. This is needed to avoid a race condition in the rotation
    // animation. See b/30209608
    surface->setAsyncMode(true);

    ANativeWindow* window = surface.get();

    status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
    if (result != NO_ERROR) {
        return result;
    }
        virtual bool handler() {
            Mutex::Autolock _l(flinger->mStateLock);
            sp<const DisplayDevice> hw(flinger->getDisplayDeviceLocked(display));
            result = flinger->captureScreenImplLocked(hw, producer,
                    sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
                    useIdentityTransform, rotation, isLocalScreenshot);
            static_cast<GraphicProducerWrapper*>(IInterface::asBinder(producer).get())->exit(result);
            return true;
    WindowDisconnector disconnector(window, NATIVE_WINDOW_API_EGL);

    ANativeWindowBuffer* buffer = nullptr;
    result = getWindowBuffer(window, reqWidth, reqHeight, hasWideColorDisplay,
                                      getRenderEngine().usesWideColor(), &buffer);
    if (result != NO_ERROR) {
        return result;
    }
    };

    // this creates a "fake" BBinder which will serve as a "fake" remote
    // binder to receive the marshaled calls and forward them to the
    // real remote (a BpGraphicBufferProducer)
    sp<GraphicProducerWrapper> wrapper = new GraphicProducerWrapper(producer);
    // This mutex protects syncFd and captureResult for communication of the return values from the
    // main thread back to this Binder thread
    std::mutex captureMutex;
    std::condition_variable captureCondition;
    std::unique_lock<std::mutex> captureLock(captureMutex);
    int syncFd = -1;
    std::optional<status_t> captureResult;

    sp<LambdaMessage> message = new LambdaMessage([&]() {
        // If there is a refresh pending, bug out early and tell the binder thread to try again
        // after the refresh.
        if (mRefreshPending) {
            ATRACE_NAME("Skipping screenshot for now");
            std::unique_lock<std::mutex> captureLock(captureMutex);
            captureResult = std::make_optional<status_t>(EAGAIN);
            captureCondition.notify_one();
            return;
        }

    // the asInterface() call below creates our "fake" BpGraphicBufferProducer
    // which does the marshaling work forwards to our "fake remote" above.
    sp<MessageBase> msg = new MessageCaptureScreen(this,
            display, IGraphicBufferProducer::asInterface( wrapper ),
            sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
            useIdentityTransform, rotationFlags, isLocalScreenshot);
        status_t result = NO_ERROR;
        int fd = -1;
        {
            Mutex::Autolock _l(mStateLock);
            sp<const DisplayDevice> device(getDisplayDeviceLocked(display));
            result = captureScreenImplLocked(device, buffer, sourceCrop, reqWidth, reqHeight,
                                             minLayerZ, maxLayerZ, useIdentityTransform,
                                             rotationFlags, isLocalScreenshot, &fd);
        }

    status_t res = postMessageAsync(msg);
    if (res == NO_ERROR) {
        res = wrapper->waitForResponse();
        {
            std::unique_lock<std::mutex> captureLock(captureMutex);
            syncFd = fd;
            captureResult = std::make_optional<status_t>(result);
            captureCondition.notify_one();
        }
    return res;
    });

    result = postMessageAsync(message);
    if (result == NO_ERROR) {
        captureCondition.wait(captureLock, [&]() { return captureResult; });
        while (*captureResult == EAGAIN) {
            captureResult.reset();
            result = postMessageAsync(message);
            if (result != NO_ERROR) {
                return result;
            }
            captureCondition.wait(captureLock, [&]() { return captureResult; });
        }
        result = *captureResult;
    }

    if (result == NO_ERROR) {
        // queueBuffer takes ownership of syncFd
        result = window->queueBuffer(window, buffer, syncFd);
    }

    return result;
}


@@ -4335,33 +4329,34 @@ void SurfaceFlinger::renderScreenImplLocked(
    hw->setViewportAndProjection();
}

// A simple RAII class that holds an EGLImage and destroys it either:
//   a) When the destroy() method is called
//   b) When the object goes out of scope
class ImageHolder {
public:
    ImageHolder(EGLDisplay display, EGLImageKHR image) : mDisplay(display), mImage(image) {}
    ~ImageHolder() { destroy(); }

status_t SurfaceFlinger::captureScreenImplLocked(
        const sp<const DisplayDevice>& hw,
        const sp<IGraphicBufferProducer>& producer,
        Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
        int32_t minLayerZ, int32_t maxLayerZ,
        bool useIdentityTransform, Transform::orientation_flags rotation,
        bool isLocalScreenshot)
{
    ATRACE_CALL();

    // get screen geometry
    uint32_t hw_w = hw->getWidth();
    uint32_t hw_h = hw->getHeight();

    if (rotation & Transform::ROT_90) {
        std::swap(hw_w, hw_h);
    void destroy() {
        if (mImage != EGL_NO_IMAGE_KHR) {
            eglDestroyImageKHR(mDisplay, mImage);
            mImage = EGL_NO_IMAGE_KHR;
        }

    if ((reqWidth > hw_w) || (reqHeight > hw_h)) {
        ALOGE("size mismatch (%d, %d) > (%d, %d)",
                reqWidth, reqHeight, hw_w, hw_h);
        return BAD_VALUE;
    }

    reqWidth  = (!reqWidth)  ? hw_w : reqWidth;
    reqHeight = (!reqHeight) ? hw_h : reqHeight;
private:
    const EGLDisplay mDisplay;
    EGLImageKHR mImage;
};

status_t SurfaceFlinger::captureScreenImplLocked(const sp<const DisplayDevice>& hw,
                                                 ANativeWindowBuffer* buffer, Rect sourceCrop,
                                                 uint32_t reqWidth, uint32_t reqHeight,
                                                 int32_t minLayerZ, int32_t maxLayerZ,
                                                 bool useIdentityTransform,
                                                 Transform::orientation_flags rotation,
                                                 bool isLocalScreenshot, int* outSyncFd) {
    ATRACE_CALL();

    bool secureLayerIsVisible = false;
    for (const auto& layer : mDrawingState.layersSortedByZ) {
@@ -4381,47 +4376,26 @@ status_t SurfaceFlinger::captureScreenImplLocked(
        return PERMISSION_DENIED;
    }

    // create a surface (because we're a producer, and we need to
    // dequeue/queue a buffer)
    sp<Surface> sur = new Surface(producer, false);

    // Put the screenshot Surface into async mode so that
    // Layer::headFenceHasSignaled will always return true and we'll latch the
    // first buffer regardless of whether or not its acquire fence has
    // signaled. This is needed to avoid a race condition in the rotation
    // animation. See b/30209608
    sur->setAsyncMode(true);

    ANativeWindow* window = sur.get();

    status_t result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
    if (result == NO_ERROR) {
        uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
                        GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;

        int err = 0;
        err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight);
        err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
        err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
        err |= native_window_set_usage(window, usage);

        if (err == NO_ERROR) {
            ANativeWindowBuffer* buffer;
            /* TODO: Once we have the sync framework everywhere this can use
             * server-side waits on the fence that dequeueBuffer returns.
             */
            result = native_window_dequeue_buffer_and_wait(window,  &buffer);
            if (result == NO_ERROR) {
    int syncFd = -1;
    // create an EGLImage from the buffer so we can later
    // turn it into a texture
    EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
            EGL_NATIVE_BUFFER_ANDROID, buffer, NULL);
                if (image != EGL_NO_IMAGE_KHR) {
    if (image == EGL_NO_IMAGE_KHR) {
        return BAD_VALUE;
    }

    // This will automatically destroy the image if we return before calling its destroy method
    ImageHolder imageHolder(mEGLDisplay, image);

    // this binds the given EGLImage as a framebuffer for the
    // duration of this scope.
    RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image);
                    if (imageBond.getStatus() == NO_ERROR) {
    if (imageBond.getStatus() != NO_ERROR) {
        ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
        return INVALID_OPERATION;
    }

    // this will in fact render into our dequeued buffer
    // via an FBO, which means we didn't have to create
    // an EGLSurface and therefore we're not
@@ -4430,25 +4404,16 @@ status_t SurfaceFlinger::captureScreenImplLocked(
        hw, sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, true,
        useIdentityTransform, rotation);

#ifdef USE_HWC2
                        if (hasWideColorDisplay) {
                            native_window_set_buffers_data_space(window,
                                getRenderEngine().usesWideColor() ?
                                    HAL_DATASPACE_DISPLAY_P3 : HAL_DATASPACE_V0_SRGB);
                        }
#endif

    // Attempt to create a sync khr object that can produce a sync point. If that
    // isn't available, create a non-dupable sync object in the fallback path and
    // wait on it directly.
                        EGLSyncKHR sync;
    EGLSyncKHR sync = EGL_NO_SYNC_KHR;
    if (!DEBUG_SCREENSHOTS) {
       sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
       // native fence fd will not be populated until flush() is done.
       getRenderEngine().flush();
                        } else {
                            sync = EGL_NO_SYNC_KHR;
    }

    if (sync != EGL_NO_SYNC_KHR) {
        // get the sync fd
        syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
@@ -4475,6 +4440,8 @@ status_t SurfaceFlinger::captureScreenImplLocked(
            ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
        }
    }
    *outSyncFd = syncFd;

    if (DEBUG_SCREENSHOTS) {
        uint32_t* pixels = new uint32_t[reqWidth*reqHeight];
        getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
@@ -4483,29 +4450,10 @@ status_t SurfaceFlinger::captureScreenImplLocked(
        delete [] pixels;
    }

                    } else {
                        ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
                        result = INVALID_OPERATION;
                        window->cancelBuffer(window, buffer, syncFd);
                        buffer = NULL;
                    }
    // destroy our image
                    eglDestroyImageKHR(mEGLDisplay, image);
                } else {
                    result = BAD_VALUE;
                }
                if (buffer) {
                    // queueBuffer takes ownership of syncFd
                    result = window->queueBuffer(window, buffer, syncFd);
                }
            }
        } else {
            result = BAD_VALUE;
        }
        native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
    }
    imageHolder.destroy();

    return result;
    return NO_ERROR;
}

void SurfaceFlinger::checkScreenshot(size_t w, size_t s, size_t h, void const* vaddr,
+11 −0
Original line number Diff line number Diff line
@@ -417,6 +417,14 @@ private:
            int32_t minLayerZ, int32_t maxLayerZ,
            bool yswap, bool useIdentityTransform, Transform::orientation_flags rotation);

#ifdef USE_HWC2
    status_t captureScreenImplLocked(const sp<const DisplayDevice>& device,
                                     ANativeWindowBuffer* buffer, Rect sourceCrop,
                                     uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ,
                                     int32_t maxLayerZ, bool useIdentityTransform,
                                     Transform::orientation_flags rotation, bool isLocalScreenshot,
                                     int* outSyncFd);
#else
    status_t captureScreenImplLocked(
            const sp<const DisplayDevice>& hw,
            const sp<IGraphicBufferProducer>& producer,
@@ -424,6 +432,7 @@ private:
            int32_t minLayerZ, int32_t maxLayerZ,
            bool useIdentityTransform, Transform::orientation_flags rotation,
            bool isLocalScreenshot);
#endif

    sp<StartBootAnimThread> mStartBootAnimThread = nullptr;

@@ -695,6 +704,8 @@ private:
    };
    std::queue<CompositePresentTime> mCompositePresentTimes;

    std::atomic<bool> mRefreshPending{false};

    /* ------------------------------------------------------------------------
     * Feature prototyping
     */