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

Commit b818fa6e authored by Tianyu Jiang's avatar Tianyu Jiang Committed by Android (Google) Code Review
Browse files

Merge "Support GraphicBuffer::flatten and GraphicBuffer::unflatten with BufferHub"

parents a1ce0076 7791e64f
Loading
Loading
Loading
Loading
+104 −12
Original line number Diff line number Diff line
@@ -371,14 +371,29 @@ status_t GraphicBuffer::isSupported(uint32_t inWidth, uint32_t inHeight, PixelFo
}

size_t GraphicBuffer::getFlattenedSize() const {
#ifndef LIBUI_IN_VNDK
    if (mBufferHubBuffer != nullptr) {
        return 48;
    }
#endif
    return static_cast<size_t>(13 + (handle ? mTransportNumInts : 0)) * sizeof(int);
}

size_t GraphicBuffer::getFdCount() const {
#ifndef LIBUI_IN_VNDK
    if (mBufferHubBuffer != nullptr) {
        return 0;
    }
#endif
    return static_cast<size_t>(handle ? mTransportNumFds : 0);
}

status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const {
#ifndef LIBUI_IN_VNDK
    if (mBufferHubBuffer != nullptr) {
        return flattenBufferHubBuffer(buffer, size, fds, count);
    }
#endif
    size_t sizeNeeded = GraphicBuffer::getFlattenedSize();
    if (size < sizeNeeded) return NO_MEMORY;

@@ -414,17 +429,11 @@ status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t&
        fds += mTransportNumFds;
        count -= static_cast<size_t>(mTransportNumFds);
    }

    return NO_ERROR;
}

status_t GraphicBuffer::unflatten(
        void const*& buffer, size_t& size, int const*& fds, size_t& count) {
    if (size < 12 * sizeof(int)) {
        android_errorWriteLog(0x534e4554, "114223584");
        return NO_MEMORY;
    }

status_t GraphicBuffer::unflatten(void const*& buffer, size_t& size, int const*& fds,
                                  size_t& count) {
    int const* buf = static_cast<int const*>(buffer);

    // NOTE: it turns out that some media code generates a flattened GraphicBuffer manually!!!!!
@@ -436,10 +445,21 @@ status_t GraphicBuffer::unflatten(
    } else if (buf[0] == 'GBFR') {
        // old version, when usage bits were 32-bits
        flattenWordCount = 12;
    } else if (buf[0] == 'BHBB') { // BufferHub backed buffer.
#ifndef LIBUI_IN_VNDK
        return unflattenBufferHubBuffer(buffer, size, fds, count);
#else
        return BAD_TYPE;
#endif
    } else {
        return BAD_TYPE;
    }

    if (size < 12 * sizeof(int)) {
        android_errorWriteLog(0x534e4554, "114223584");
        return NO_MEMORY;
    }

    const size_t numFds  = static_cast<size_t>(buf[10]);
    const size_t numInts = static_cast<size_t>(buf[11]);

@@ -480,8 +500,8 @@ status_t GraphicBuffer::unflatten(
        } else {
            usage = uint64_t(usage_deprecated);
        }
        native_handle* h = native_handle_create(
                static_cast<int>(numFds), static_cast<int>(numInts));
        native_handle* h =
                native_handle_create(static_cast<int>(numFds), static_cast<int>(numInts));
        if (!h) {
            width = height = stride = format = usage_deprecated = 0;
            layerCount = 0;
@@ -530,11 +550,83 @@ status_t GraphicBuffer::unflatten(
    size -= sizeNeeded;
    fds += numFds;
    count -= numFds;

    return NO_ERROR;
}

#ifndef LIBUI_IN_VNDK
status_t GraphicBuffer::flattenBufferHubBuffer(void*& buffer, size_t& size, int*& fds,
                                               size_t& count) const {
    sp<NativeHandle> tokenHandle = mBufferHubBuffer->duplicate();
    if (tokenHandle == nullptr || tokenHandle->handle() == nullptr ||
        tokenHandle->handle()->numFds != 0) {
        return BAD_VALUE;
    }

    // Size needed for one label, one number of ints inside the token, one generation number and
    // the token itself.
    int numIntsInToken = tokenHandle->handle()->numInts;
    const size_t sizeNeeded = static_cast<size_t>(3 + numIntsInToken) * sizeof(int);
    if (size < sizeNeeded) {
        ALOGE("%s: needed size %d, given size %d. Not enough memory.", __FUNCTION__,
              static_cast<int>(sizeNeeded), static_cast<int>(size));
        return NO_MEMORY;
    }
    size -= sizeNeeded;

    int* buf = static_cast<int*>(buffer);
    buf[0] = 'BHBB';
    buf[1] = numIntsInToken;
    memcpy(buf + 2, tokenHandle->handle()->data, static_cast<size_t>(numIntsInToken) * sizeof(int));
    buf[2 + numIntsInToken] = static_cast<int32_t>(mGenerationNumber);

    // Do not pass fds if it is BufferHubBuffer backed GraphicBuffer. Not modifying fds or count.
    fds += 0;
    count -= 0;
    return NO_ERROR;
}

status_t GraphicBuffer::unflattenBufferHubBuffer(void const*& buffer, size_t& size, int const*& fds,
                                                 size_t& count) {
    const int* buf = static_cast<const int*>(buffer);
    int numIntsInToken = buf[1];
    // Size needed for one label, one number of ints inside the token, one generation number and
    // the token itself.
    const size_t sizeNeeded = static_cast<size_t>(3 + numIntsInToken) * sizeof(int);
    if (size < sizeNeeded) {
        ALOGE("%s: needed size %d, given size %d. Not enough memory.", __FUNCTION__,
              static_cast<int>(sizeNeeded), static_cast<int>(size));
        return NO_MEMORY;
    }
    size -= sizeNeeded;
    native_handle_t* importToken = native_handle_create(/*numFds=*/0, /*numInts=*/numIntsInToken);
    memcpy(importToken->data, buf + 2, static_cast<size_t>(buf[1]) * sizeof(int));
    sp<NativeHandle> importTokenHandle = NativeHandle::create(importToken, /*ownHandle=*/true);
    std::unique_ptr<BufferHubBuffer> bufferHubBuffer = BufferHubBuffer::import(importTokenHandle);
    if (bufferHubBuffer == nullptr || bufferHubBuffer.get() == nullptr) {
        return BAD_VALUE;
    }
    // Reconstruct this GraphicBuffer object using the new BufferHubBuffer object.
    if (handle) {
        free_handle();
    }
    mId = 0;
    mGenerationNumber = static_cast<uint32_t>(buf[2 + numIntsInToken]);
    mInitCheck =
            initWithHandle(bufferHubBuffer->duplicateHandle(), /*method=*/TAKE_UNREGISTERED_HANDLE,
                           bufferHubBuffer->desc().width, bufferHubBuffer->desc().height,
                           static_cast<PixelFormat>(bufferHubBuffer->desc().format),
                           bufferHubBuffer->desc().layers, bufferHubBuffer->desc().usage,
                           bufferHubBuffer->desc().stride);
    mBufferId = bufferHubBuffer->id();
    mBufferHubBuffer.reset(std::move(bufferHubBuffer.get()));

    // BufferHubBuffer backed GraphicBuffer does not have flattened handle. Not modifying fds or
    // count.
    fds += 0;
    count -= 0;
    return NO_ERROR;
}

bool GraphicBuffer::isBufferHubBuffer() const {
    return mBufferHubBuffer != nullptr;
}
+12 −0
Original line number Diff line number Diff line
@@ -281,6 +281,18 @@ private:
    uint32_t mGenerationNumber;

#ifndef LIBUI_IN_VNDK
    // Flatten this GraphicBuffer object if backed by BufferHubBuffer.
    status_t flattenBufferHubBuffer(void*& buffer, size_t& size, int*& fds, size_t& count) const;

    // Unflatten into BufferHubBuffer backed GraphicBuffer.
    // Unflatten will fail if the original GraphicBuffer object is destructed. For instance, a
    // GraphicBuffer backed by BufferHubBuffer_1 flatten in process/thread A, transport the token
    // to process/thread B through a socket, BufferHubBuffer_1 dies and bufferhub invalidated the
    // token. Race condition occurs between the invalidation of the token in bufferhub process and
    // process/thread B trying to unflatten and import the buffer with that token.
    status_t unflattenBufferHubBuffer(void const*& buffer, size_t& size, int const*& fds,
                                      size_t& count);

    // Stores a BufferHubBuffer that handles buffer signaling, identification.
    std::unique_ptr<BufferHubBuffer> mBufferHubBuffer;
#endif // LIBUI_IN_VNDK
+45 −0
Original line number Diff line number Diff line
@@ -74,4 +74,49 @@ TEST_F(GraphicBufferTest, BufferIdMatchesBufferHubBufferId) {
    EXPECT_EQ(gb->getBufferId(), b1_id);
}

TEST_F(GraphicBufferTest, flattenAndUnflatten) {
    std::unique_ptr<BufferHubBuffer> b1 =
            BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat,
                                    kTestUsage, /*userMetadataSize=*/0);
    ASSERT_NE(b1, nullptr);
    sp<GraphicBuffer> gb1(new GraphicBuffer(std::move(b1)));
    gb1->setGenerationNumber(42);

    size_t flattenedSize = gb1->getFlattenedSize();
    EXPECT_EQ(flattenedSize, 48);
    size_t fdCount = gb1->getFdCount();
    EXPECT_EQ(fdCount, 0);

    int data[flattenedSize];
    int fds[0];

    // Make copies of needed items since flatten modifies them.
    size_t flattenedSizeCopy = flattenedSize;
    size_t fdCountCopy = fdCount;
    void* dataStart = data;
    int* fdsStart = fds;
    status_t err = gb1->flatten(dataStart, flattenedSizeCopy, fdsStart, fdCountCopy);
    ASSERT_EQ(err, NO_ERROR);
    EXPECT_EQ(flattenedSizeCopy, 0);
    EXPECT_EQ(fdCountCopy, 0);

    size_t unflattenSize = flattenedSize;
    size_t unflattenFdCount = fdCount;
    const void* unflattenData = static_cast<const void*>(dataStart);
    const int* unflattenFdData = static_cast<const int*>(fdsStart);

    GraphicBuffer* gb2 = new GraphicBuffer();
    err = gb2->unflatten(unflattenData, unflattenSize, unflattenFdData, unflattenFdCount);
    ASSERT_EQ(err, NO_ERROR);
    EXPECT_TRUE(gb2->isBufferHubBuffer());

    EXPECT_EQ(gb2->getWidth(), kTestWidth);
    EXPECT_EQ(gb2->getHeight(), kTestHeight);
    EXPECT_EQ(static_cast<uint32_t>(gb2->getPixelFormat()), kTestFormat);
    EXPECT_EQ(gb2->getUsage(), kTestUsage);
    EXPECT_EQ(gb2->getLayerCount(), kTestLayerCount);
    EXPECT_EQ(gb1->getBufferId(), gb2->getBufferId());
    EXPECT_EQ(gb2->getGenerationNumber(), 42);
}

} // namespace android