blob: 11d122b525898e339a66a153ff01920fe46d91dc [file] [log] [blame]
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string>
#include <vector>
#include <gtest/gtest.h>
#include <gui/BufferReleaseChannel.h>
using namespace std::string_literals;
using android::gui::BufferReleaseChannel;
namespace android {
namespace {
// Helper function to check if two file descriptors point to the same file.
bool is_same_file(int fd1, int fd2) {
struct stat stat1;
if (fstat(fd1, &stat1) != 0) {
return false;
}
struct stat stat2;
if (fstat(fd2, &stat2) != 0) {
return false;
}
return (stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino);
}
} // namespace
TEST(BufferReleaseChannelTest, MessageFlattenable) {
ReleaseCallbackId releaseCallbackId{1, 2};
sp<Fence> releaseFence = sp<Fence>::make(memfd_create("fake-fence-fd", 0));
uint32_t maxAcquiredBufferCount = 5;
std::vector<uint8_t> dataBuffer;
std::vector<int> fdBuffer;
// Verify that we can flatten a message
{
BufferReleaseChannel::Message message{releaseCallbackId, releaseFence,
maxAcquiredBufferCount};
dataBuffer.resize(message.getFlattenedSize());
void* dataPtr = dataBuffer.data();
size_t dataSize = dataBuffer.size();
fdBuffer.resize(message.getFdCount());
int* fdPtr = fdBuffer.data();
size_t fdSize = fdBuffer.size();
ASSERT_EQ(OK, message.flatten(dataPtr, dataSize, fdPtr, fdSize));
// Fence's unique_fd uses fdsan to check ownership of the file descriptor. Normally the file
// descriptor is passed through the Unix socket and duplicated (and sent to another process)
// so there's no problem with duplicate file descriptor ownership. For this unit test, we
// need to set up a duplicate file descriptor to avoid crashing due to duplicate ownership.
ASSERT_EQ(releaseFence->get(), fdBuffer[0]);
fdBuffer[0] = message.releaseFence->dup();
}
// Verify that we can unflatten a message
{
BufferReleaseChannel::Message message;
const void* dataPtr = dataBuffer.data();
size_t dataSize = dataBuffer.size();
const int* fdPtr = fdBuffer.data();
size_t fdSize = fdBuffer.size();
ASSERT_EQ(OK, message.unflatten(dataPtr, dataSize, fdPtr, fdSize));
ASSERT_EQ(releaseCallbackId, message.releaseCallbackId);
ASSERT_TRUE(is_same_file(releaseFence->get(), message.releaseFence->get()));
ASSERT_EQ(maxAcquiredBufferCount, message.maxAcquiredBufferCount);
}
}
// Verify that the BufferReleaseChannel consume returns WOULD_BLOCK when there's no message
// available.
TEST(BufferReleaseChannelTest, ConsumerEndpointIsNonBlocking) {
std::unique_ptr<BufferReleaseChannel::ConsumerEndpoint> consumer;
std::shared_ptr<BufferReleaseChannel::ProducerEndpoint> producer;
ASSERT_EQ(OK, BufferReleaseChannel::open("test-channel"s, consumer, producer));
ReleaseCallbackId releaseCallbackId;
sp<Fence> releaseFence;
uint32_t maxAcquiredBufferCount;
ASSERT_EQ(WOULD_BLOCK,
consumer->readReleaseFence(releaseCallbackId, releaseFence, maxAcquiredBufferCount));
}
// Verify that we can write a message to the BufferReleaseChannel producer and read that message
// using the BufferReleaseChannel consumer.
TEST(BufferReleaseChannelTest, ProduceAndConsume) {
std::unique_ptr<BufferReleaseChannel::ConsumerEndpoint> consumer;
std::shared_ptr<BufferReleaseChannel::ProducerEndpoint> producer;
ASSERT_EQ(OK, BufferReleaseChannel::open("test-channel"s, consumer, producer));
sp<Fence> fence = sp<Fence>::make(memfd_create("fake-fence-fd", 0));
for (uint64_t i = 0; i < 64; i++) {
ReleaseCallbackId producerId{i, i + 1};
uint32_t maxAcquiredBufferCount = i + 2;
ASSERT_EQ(OK, producer->writeReleaseFence(producerId, fence, maxAcquiredBufferCount));
}
for (uint64_t i = 0; i < 64; i++) {
ReleaseCallbackId expectedId{i, i + 1};
uint32_t expectedMaxAcquiredBufferCount = i + 2;
ReleaseCallbackId consumerId;
sp<Fence> consumerFence;
uint32_t maxAcquiredBufferCount;
ASSERT_EQ(OK,
consumer->readReleaseFence(consumerId, consumerFence, maxAcquiredBufferCount));
ASSERT_EQ(expectedId, consumerId);
ASSERT_TRUE(is_same_file(fence->get(), consumerFence->get()));
ASSERT_EQ(expectedMaxAcquiredBufferCount, maxAcquiredBufferCount);
}
}
} // namespace android