diff options
| author | 2018-12-05 13:34:48 -0800 | |
|---|---|---|
| committer | 2019-01-11 18:28:53 +0000 | |
| commit | 021776e289849daf3b3c327d5b0a57ee55873225 (patch) | |
| tree | a8c639255ff3eb554e55354f7cda6094164aafbd | |
| parent | 6b4b1e5b1f7ad32dcadc49a2455370003b20897a (diff) | |
Refactor BufferHubBuffer to use hwbinder
Entirely move BufferHubBuffer off pdx dependency and using hwbinder
backend and rewrite test cases to fit in current behavior.
Remove duplicated test cases in buffer_hub-test. Commented out
BufferHubBuffer related parts and remove related include and using
statement.
Add hidl interface dependency to libs/gui build file to avoid compile
errors.
Test: BufferHub_test, GraphicBuffer_test, buffer_hub-test
Bug: 116681016
Change-Id: I9d8f734f681e04d3d50b7a02c27b17df8c66cbad
| -rw-r--r-- | libs/gui/Android.bp | 2 | ||||
| -rw-r--r-- | libs/ui/Android.bp | 6 | ||||
| -rw-r--r-- | libs/ui/BufferHubBuffer.cpp | 316 | ||||
| -rw-r--r-- | libs/ui/include/ui/BufferHubBuffer.h | 108 | ||||
| -rw-r--r-- | libs/ui/tests/Android.bp | 8 | ||||
| -rw-r--r-- | libs/ui/tests/BufferHubBuffer_test.cpp | 172 | ||||
| -rw-r--r-- | libs/ui/tests/GraphicBuffer_test.cpp | 2 | ||||
| -rw-r--r-- | libs/vr/libbufferhub/buffer_hub-test.cpp | 93 |
8 files changed, 342 insertions, 365 deletions
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index d1c732bc1f..3521e89ae6 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -121,6 +121,7 @@ cc_library_shared { ], shared_libs: [ + "android.frameworks.bufferhub@1.0", "android.hardware.graphics.common@1.1", "libbase", "libsync", @@ -153,6 +154,7 @@ cc_library_shared { "BufferHubProducer.cpp", ], exclude_shared_libs: [ + "android.frameworks.bufferhub@1.0", "libbufferhub", "libbufferhubqueue", "libpdx_default_transport", diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 956465c52a..d089bf6bc3 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -77,6 +77,7 @@ cc_library_shared { ], shared_libs: [ + "android.frameworks.bufferhub@1.0", "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.common@1.2", "android.hardware.graphics.mapper@2.0", @@ -93,7 +94,6 @@ cc_library_shared { "libutils", "libutilscallstack", "liblog", - "libpdx_default_transport", // TODO(b/112338294): Remove this once BufferHub moved to use Binder. ], export_shared_lib_headers: [ @@ -121,6 +121,7 @@ cc_library_shared { "libnativewindow_headers", ], exclude_shared_libs: [ + "android.frameworks.bufferhub@1.0", "libpdx_default_transport", ], }, @@ -148,9 +149,6 @@ cc_library_shared { "libhardware_headers", "libui_headers", ], - - // TODO(b/117568153): Temporarily opt out using libcrt. - no_libcrt: true, } cc_library_headers { diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp index 11849608ba..c70f18823c 100644 --- a/libs/ui/BufferHubBuffer.cpp +++ b/libs/ui/BufferHubBuffer.cpp @@ -14,150 +14,190 @@ * limitations under the License. */ -// We would eliminate the clang warnings introduced by libdpx. -// TODO(b/112338294): Remove those once BufferHub moved to use Binder -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#pragma clang diagnostic ignored "-Wdouble-promotion" -#pragma clang diagnostic ignored "-Wgnu-case-range" -#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" -#pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override" -#pragma clang diagnostic ignored "-Wnested-anon-types" -#pragma clang diagnostic ignored "-Wpacked" -#pragma clang diagnostic ignored "-Wshadow" -#pragma clang diagnostic ignored "-Wsign-conversion" -#pragma clang diagnostic ignored "-Wswitch-enum" -#pragma clang diagnostic ignored "-Wundefined-func-template" -#pragma clang diagnostic ignored "-Wunused-template" -#pragma clang diagnostic ignored "-Wweak-vtables" -#include <pdx/default_transport/client_channel.h> -#include <pdx/default_transport/client_channel_factory.h> -#include <pdx/file_handle.h> -#include <private/dvr/bufferhub_rpc.h> -#pragma clang diagnostic pop - #include <poll.h> #include <android-base/unique_fd.h> +#include <android/frameworks/bufferhub/1.0/IBufferHub.h> +#include <log/log.h> #include <ui/BufferHubBuffer.h> #include <ui/BufferHubDefs.h> - -using android::base::unique_fd; -using android::dvr::BufferTraits; -using android::dvr::DetachedBufferRPC; -using android::dvr::NativeHandleWrapper; - -// TODO(b/112338294): Remove PDX dependencies from libui. -using android::pdx::LocalChannelHandle; -using android::pdx::LocalHandle; -using android::pdx::Status; -using android::pdx::default_transport::ClientChannel; -using android::pdx::default_transport::ClientChannelFactory; +#include <utils/Trace.h> + +using ::android::base::unique_fd; +using ::android::BufferHubDefs::AnyClientAcquired; +using ::android::BufferHubDefs::AnyClientGained; +using ::android::BufferHubDefs::IsClientAcquired; +using ::android::BufferHubDefs::IsClientGained; +using ::android::BufferHubDefs::IsClientPosted; +using ::android::BufferHubDefs::IsClientReleased; +using ::android::frameworks::bufferhub::V1_0::BufferHubStatus; +using ::android::frameworks::bufferhub::V1_0::BufferTraits; +using ::android::frameworks::bufferhub::V1_0::IBufferClient; +using ::android::frameworks::bufferhub::V1_0::IBufferHub; +using ::android::hardware::hidl_handle; +using ::android::hardware::graphics::common::V1_2::HardwareBufferDescription; namespace android { -namespace { - -// TODO(b/112338294): Remove this string literal after refactoring BufferHub -// to use Binder. -static constexpr char kBufferHubClientPath[] = "system/buffer_hub/client"; - -using BufferHubDefs::AnyClientAcquired; -using BufferHubDefs::AnyClientGained; -using BufferHubDefs::IsClientAcquired; -using BufferHubDefs::IsClientGained; -using BufferHubDefs::IsClientPosted; -using BufferHubDefs::IsClientReleased; -using BufferHubDefs::kHighBitsMask; +std::unique_ptr<BufferHubBuffer> BufferHubBuffer::Create(uint32_t width, uint32_t height, + uint32_t layerCount, uint32_t format, + uint64_t usage, size_t userMetadataSize) { + auto buffer = std::unique_ptr<BufferHubBuffer>( + new BufferHubBuffer(width, height, layerCount, format, usage, userMetadataSize)); + return buffer->IsValid() ? std::move(buffer) : nullptr; +} -} // namespace +std::unique_ptr<BufferHubBuffer> BufferHubBuffer::Import(const native_handle_t* token) { + if (token == nullptr) { + ALOGE("%s: token cannot be nullptr!", __FUNCTION__); + return nullptr; + } -BufferHubClient::BufferHubClient() : Client(ClientChannelFactory::Create(kBufferHubClientPath)) {} + auto buffer = std::unique_ptr<BufferHubBuffer>(new BufferHubBuffer(token)); + return buffer->IsValid() ? std::move(buffer) : nullptr; +} -BufferHubClient::BufferHubClient(LocalChannelHandle mChannelHandle) - : Client(ClientChannel::Create(std::move(mChannelHandle))) {} +BufferHubBuffer::BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount, + uint32_t format, uint64_t usage, size_t userMetadataSize) { + ATRACE_CALL(); + ALOGD("%s: width=%u height=%u layerCount=%u, format=%u " + "usage=%" PRIx64 " mUserMetadataSize=%zu", + __FUNCTION__, width, height, layerCount, format, usage, userMetadataSize); + + sp<IBufferHub> bufferhub = IBufferHub::getService(); + if (bufferhub.get() == nullptr) { + ALOGE("%s: BufferHub service not found!", __FUNCTION__); + return; + } -BufferHubClient::~BufferHubClient() {} + AHardwareBuffer_Desc aDesc = {width, height, layerCount, format, + usage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL}; + HardwareBufferDescription desc; + memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription)); + + BufferHubStatus ret; + sp<IBufferClient> client; + BufferTraits bufferTraits; + IBufferHub::allocateBuffer_cb alloc_cb = [&](const auto& status, const auto& outClient, + const auto& traits) { + ret = status; + client = std::move(outClient); + bufferTraits = std::move(traits); + }; + + if (!bufferhub->allocateBuffer(desc, static_cast<uint32_t>(userMetadataSize), alloc_cb) + .isOk()) { + ALOGE("%s: allocateBuffer transaction failed!", __FUNCTION__); + return; + } else if (ret != BufferHubStatus::NO_ERROR) { + ALOGE("%s: allocateBuffer failed with error %u.", __FUNCTION__, ret); + return; + } else if (client == nullptr) { + ALOGE("%s: allocateBuffer got null BufferClient.", __FUNCTION__); + return; + } -bool BufferHubClient::IsValid() const { - return IsConnected() && GetChannelHandle().valid(); + const int importRet = initWithBufferTraits(bufferTraits); + if (importRet < 0) { + ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-importRet)); + client->close(); + } + mBufferClient = std::move(client); } -LocalChannelHandle BufferHubClient::TakeChannelHandle() { - if (IsConnected()) { - return std::move(GetChannelHandle()); - } else { - return {}; +BufferHubBuffer::BufferHubBuffer(const native_handle_t* token) { + sp<IBufferHub> bufferhub = IBufferHub::getService(); + if (bufferhub.get() == nullptr) { + ALOGE("%s: BufferHub service not found!", __FUNCTION__); + return; } -} -BufferHubBuffer::BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount, - uint32_t format, uint64_t usage, size_t mUserMetadataSize) { - ATRACE_CALL(); - ALOGD("%s: width=%u height=%u layerCount=%u, format=%u usage=%" PRIx64 " mUserMetadataSize=%zu", - __FUNCTION__, width, height, layerCount, format, usage, mUserMetadataSize); - - auto status = - mClient.InvokeRemoteMethod<DetachedBufferRPC::Create>(width, height, layerCount, format, - usage, mUserMetadataSize); - if (!status) { - ALOGE("%s: Failed to create detached buffer: %s", __FUNCTION__, - status.GetErrorMessage().c_str()); - mClient.Close(-status.error()); + BufferHubStatus ret; + sp<IBufferClient> client; + BufferTraits bufferTraits; + IBufferHub::importBuffer_cb import_cb = [&](const auto& status, const auto& outClient, + const auto& traits) { + ret = status; + client = std::move(outClient); + bufferTraits = std::move(traits); + }; + + // hidl_handle(native_handle_t*) simply creates a raw pointer reference withouth ownership + // transfer. + if (!bufferhub->importBuffer(hidl_handle(token), import_cb).isOk()) { + ALOGE("%s: importBuffer transaction failed!", __FUNCTION__); + return; + } else if (ret != BufferHubStatus::NO_ERROR) { + ALOGE("%s: importBuffer failed with error %u.", __FUNCTION__, ret); + return; + } else if (client == nullptr) { + ALOGE("%s: importBuffer got null BufferClient.", __FUNCTION__); + return; } - const int ret = ImportGraphicBuffer(); - if (ret < 0) { - ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-ret)); - mClient.Close(ret); + const int importRet = initWithBufferTraits(bufferTraits); + if (importRet < 0) { + ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-importRet)); + client->close(); } + mBufferClient = std::move(client); } -BufferHubBuffer::BufferHubBuffer(LocalChannelHandle mChannelHandle) - : mClient(std::move(mChannelHandle)) { - const int ret = ImportGraphicBuffer(); - if (ret < 0) { - ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-ret)); - mClient.Close(ret); +BufferHubBuffer::~BufferHubBuffer() { + // Close buffer client to avoid possible race condition: user could first duplicate and hold + // token with the original buffer gone, and then try to import the token. The close function + // will explicitly invalidate the token to avoid this. + if (mBufferClient != nullptr) { + if (!mBufferClient->close().isOk()) { + ALOGE("%s: close BufferClient transaction failed!", __FUNCTION__); + } } } -int BufferHubBuffer::ImportGraphicBuffer() { +int BufferHubBuffer::initWithBufferTraits(const BufferTraits& bufferTraits) { ATRACE_CALL(); - auto status = mClient.InvokeRemoteMethod<DetachedBufferRPC::Import>(); - if (!status) { - ALOGE("%s: Failed to import GraphicBuffer: %s", __FUNCTION__, - status.GetErrorMessage().c_str()); - return -status.error(); + if (bufferTraits.bufferInfo.getNativeHandle() == nullptr) { + ALOGE("%s: missing buffer info handle.", __FUNCTION__); + return -EINVAL; + } + + if (bufferTraits.bufferHandle.getNativeHandle() == nullptr) { + ALOGE("%s: missing gralloc handle.", __FUNCTION__); + return -EINVAL; } - BufferTraits<LocalHandle> bufferTraits = status.take(); - if (bufferTraits.id() < 0) { - ALOGE("%s: Received an invalid id!", __FUNCTION__); - return -EIO; + int bufferId = bufferTraits.bufferInfo->data[1]; + if (bufferId < 0) { + ALOGE("%s: Received an invalid (negative) id!", __FUNCTION__); + return -EINVAL; } - // Stash the buffer id to replace the value in mId. - const int bufferId = bufferTraits.id(); + uint32_t clientBitMask; + memcpy(&clientBitMask, &bufferTraits.bufferInfo->data[2], sizeof(clientBitMask)); + if (clientBitMask == 0U) { + ALOGE("%s: Received a invalid client state mask!", __FUNCTION__); + return -EINVAL; + } - // Import the metadata. - LocalHandle metadataHandle = bufferTraits.take_metadata_handle(); - unique_fd metadataFd(metadataHandle.Release()); - mMetadata = BufferHubMetadata::Import(std::move(metadataFd)); + // Import the metadata. Dup since hidl_handle owns the fd + unique_fd ashmemFd(dup(bufferTraits.bufferInfo->data[0])); + mMetadata = BufferHubMetadata::Import(std::move(ashmemFd)); if (!mMetadata.IsValid()) { ALOGE("%s: invalid metadata.", __FUNCTION__); - return -ENOMEM; + return -EINVAL; } - if (mMetadata.metadata_size() != bufferTraits.metadata_size()) { - ALOGE("%s: metadata buffer too small: %zu, expected: %" PRIu64 ".", __FUNCTION__, - mMetadata.metadata_size(), bufferTraits.metadata_size()); - return -ENOMEM; + uint32_t userMetadataSize; + memcpy(&userMetadataSize, &bufferTraits.bufferInfo->data[3], sizeof(userMetadataSize)); + if (mMetadata.user_metadata_size() != userMetadataSize) { + ALOGE("%s: user metadata size not match: expected %u, actual %zu.", __FUNCTION__, + userMetadataSize, mMetadata.user_metadata_size()); + return -EINVAL; } - size_t metadataSize = static_cast<size_t>(bufferTraits.metadata_size()); + size_t metadataSize = static_cast<size_t>(mMetadata.metadata_size()); if (metadataSize < BufferHubDefs::kMetadataHeaderSize) { ALOGE("%s: metadata too small: %zu", __FUNCTION__, metadataSize); return -EINVAL; @@ -178,24 +218,14 @@ int BufferHubBuffer::ImportGraphicBuffer() { // Import the buffer: We only need to hold on the native_handle_t here so that // GraphicBuffer instance can be created in future. - mBufferHandle = bufferTraits.take_buffer_handle(); - - // Populate buffer desc based on buffer traits. - mBufferDesc.width = bufferTraits.width(); - mBufferDesc.height = bufferTraits.height(); - mBufferDesc.layers = bufferTraits.layer_count(); - mBufferDesc.format = bufferTraits.format(); - mBufferDesc.usage = bufferTraits.usage(); - mBufferDesc.stride = bufferTraits.stride(); - mBufferDesc.rfu0 = 0U; - mBufferDesc.rfu1 = 0U; - - // If all imports succeed, replace the previous buffer and id. + mBufferHandle = std::move(bufferTraits.bufferHandle); + memcpy(&mBufferDesc, &bufferTraits.bufferDesc, sizeof(AHardwareBuffer_Desc)); + mId = bufferId; - mClientStateMask = bufferTraits.client_state_mask(); + mClientStateMask = clientBitMask; // TODO(b/112012161) Set up shared fences. - ALOGD("%s: id=%d, buffer_state=%" PRIx32 ".", __FUNCTION__, id(), + ALOGD("%s: id=%d, buffer_state=%" PRIx32 ".", __FUNCTION__, mId, buffer_state_->load(std::memory_order_acquire)); return 0; } @@ -225,7 +255,7 @@ int BufferHubBuffer::Gain() { int BufferHubBuffer::Post() { uint32_t current_buffer_state = buffer_state_->load(std::memory_order_acquire); - uint32_t updated_buffer_state = (~mClientStateMask) & kHighBitsMask; + uint32_t updated_buffer_state = (~mClientStateMask) & BufferHubDefs::kHighBitsMask; do { if (!IsClientGained(current_buffer_state, mClientStateMask)) { ALOGE("%s: Cannot post a buffer that is not gained by this client. buffer_id=%d " @@ -283,24 +313,42 @@ int BufferHubBuffer::Release() { return 0; } -int BufferHubBuffer::Poll(int timeoutMs) { - ATRACE_CALL(); - - pollfd p = {mClient.event_fd(), POLLIN, 0}; - return poll(&p, 1, timeoutMs); +bool BufferHubBuffer::IsValid() const { + // TODO(b/68770788): check eventFd once implemented + return mBufferHandle.getNativeHandle() != nullptr && mId >= 0 && mClientStateMask != 0U && + mMetadata.IsValid() && mBufferClient != nullptr; } -Status<LocalChannelHandle> BufferHubBuffer::Duplicate() { - ATRACE_CALL(); - ALOGD("%s: id=%d.", __FUNCTION__, mId); +// TODO(b/68770788): implement Poll() once we have event fd +int BufferHubBuffer::Poll(int /* timeoutMs */) { + return -ENOSYS; +} - auto statusOrHandle = mClient.InvokeRemoteMethod<DetachedBufferRPC::Duplicate>(); +native_handle_t* BufferHubBuffer::Duplicate() { + if (mBufferClient == nullptr) { + ALOGE("%s: missing BufferClient!", __FUNCTION__); + return nullptr; + } - if (!statusOrHandle.ok()) { - ALOGE("%s: Failed to duplicate buffer (id=%d): %s.", __FUNCTION__, mId, - statusOrHandle.GetErrorMessage().c_str()); + hidl_handle token; + BufferHubStatus ret; + IBufferClient::duplicate_cb dup_cb = [&](const auto& outToken, const auto& status) { + token = std::move(outToken); + ret = status; + }; + + if (!mBufferClient->duplicate(dup_cb).isOk()) { + ALOGE("%s: duplicate transaction failed!", __FUNCTION__); + return nullptr; + } else if (ret != BufferHubStatus::NO_ERROR) { + ALOGE("%s: duplicate failed with error %u.", __FUNCTION__, ret); + return nullptr; + } else if (token.getNativeHandle() == nullptr) { + ALOGE("%s: duplicate got null token.", __FUNCTION__); + return nullptr; } - return statusOrHandle; + + return native_handle_clone(token.getNativeHandle()); } } // namespace android diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h index 90dd391d8d..44dfa95e67 100644 --- a/libs/ui/include/ui/BufferHubBuffer.h +++ b/libs/ui/include/ui/BufferHubBuffer.h @@ -17,73 +17,43 @@ #ifndef ANDROID_BUFFER_HUB_BUFFER_H_ #define ANDROID_BUFFER_HUB_BUFFER_H_ -// We would eliminate the clang warnings introduced by libdpx. -// TODO(b/112338294): Remove those once BufferHub moved to use Binder -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#pragma clang diagnostic ignored "-Wdouble-promotion" -#pragma clang diagnostic ignored "-Wgnu-case-range" -#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" -#pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override" -#pragma clang diagnostic ignored "-Wnested-anon-types" -#pragma clang diagnostic ignored "-Wpacked" -#pragma clang diagnostic ignored "-Wshadow" -#pragma clang diagnostic ignored "-Wsign-conversion" -#pragma clang diagnostic ignored "-Wswitch-enum" -#pragma clang diagnostic ignored "-Wundefined-func-template" -#pragma clang diagnostic ignored "-Wunused-template" -#pragma clang diagnostic ignored "-Wweak-vtables" -#include <pdx/client.h> -#include <private/dvr/native_handle_wrapper.h> -#pragma clang diagnostic pop - +#include <android/frameworks/bufferhub/1.0/IBufferClient.h> #include <android/hardware_buffer.h> +#include <cutils/native_handle.h> #include <ui/BufferHubDefs.h> #include <ui/BufferHubMetadata.h> namespace android { -class BufferHubClient : public pdx::Client { -public: - BufferHubClient(); - virtual ~BufferHubClient(); - explicit BufferHubClient(pdx::LocalChannelHandle mChannelHandle); - - bool IsValid() const; - pdx::LocalChannelHandle TakeChannelHandle(); - - using pdx::Client::Close; - using pdx::Client::event_fd; - using pdx::Client::GetChannel; - using pdx::Client::InvokeRemoteMethod; -}; - class BufferHubBuffer { public: - // Allocates a standalone BufferHubBuffer not associated with any producer consumer set. + // Allocates a standalone BufferHubBuffer. static std::unique_ptr<BufferHubBuffer> Create(uint32_t width, uint32_t height, uint32_t layerCount, uint32_t format, - uint64_t usage, size_t userMetadataSize) { - return std::unique_ptr<BufferHubBuffer>( - new BufferHubBuffer(width, height, layerCount, format, usage, userMetadataSize)); - } + uint64_t usage, size_t userMetadataSize); - // Imports the given channel handle to a BufferHubBuffer, taking ownership. - static std::unique_ptr<BufferHubBuffer> Import(pdx::LocalChannelHandle mChannelHandle) { - return std::unique_ptr<BufferHubBuffer>(new BufferHubBuffer(std::move(mChannelHandle))); - } + // Imports the given token to a BufferHubBuffer. Not taking ownership of the token. Caller + // should close and destroy the token after calling this function regardless of output. + // TODO(b/122543147): use a movable wrapper for token + static std::unique_ptr<BufferHubBuffer> Import(const native_handle_t* token); BufferHubBuffer(const BufferHubBuffer&) = delete; void operator=(const BufferHubBuffer&) = delete; + virtual ~BufferHubBuffer(); + // Gets ID of the buffer client. All BufferHubBuffer clients derived from the same buffer in - // bufferhubd share the same buffer id. + // BufferHub share the same buffer id. int id() const { return mId; } - // Returns the buffer description, which is guaranteed to be faithful values from bufferhubd. + // Returns the buffer description, which is guaranteed to be faithful values from BufferHub. const AHardwareBuffer_Desc& desc() const { return mBufferDesc; } - const native_handle_t* DuplicateHandle() { return mBufferHandle.DuplicateHandle(); } + // Duplicate the underlying Gralloc buffer handle. Caller is responsible to free the handle + // after use. + native_handle_t* DuplicateHandle() { + return native_handle_clone(mBufferHandle.getNativeHandle()); + } // Returns the current value of MetadataHeader::buffer_state. uint32_t buffer_state() { @@ -96,12 +66,12 @@ public: size_t user_metadata_size() const { return mMetadata.user_metadata_size(); } - // Returns true if the buffer holds an open PDX channels towards bufferhubd. - bool IsConnected() const { return mClient.IsValid(); } + // Returns true if the BufferClient is still alive. + bool IsConnected() const { return mBufferClient->ping().isOk(); } - // Returns true if the buffer holds an valid native buffer handle that's availble for the client - // to read from and/or write into. - bool IsValid() const { return mBufferHandle.IsValid(); } + // Returns true if the buffer is valid: non-null buffer handle, valid id, valid client bit mask, + // valid metadata and valid buffer client + bool IsValid() const; // Gains the buffer for exclusive write permission. Read permission is implied once a buffer is // gained. @@ -124,33 +94,27 @@ public: // current cycle of the usage of the buffer. int Release(); - // Returns the event mask for all the events that are pending on this buffer (see sys/poll.h for - // all possible bits). - pdx::Status<int> GetEventMask(int events) { - if (auto* channel = mClient.GetChannel()) { - return channel->GetEventMask(events); - } else { - return pdx::ErrorStatus(EINVAL); - } - } - // Polls the fd for |timeoutMs| milliseconds (-1 for infinity). int Poll(int timeoutMs); - // Creates a BufferHubBuffer client from an existing one. The new client will - // share the same underlying gralloc buffer and ashmem region for metadata. - pdx::Status<pdx::LocalChannelHandle> Duplicate(); + // Creates a token that stands for this BufferHubBuffer client and could be used for Import to + // create another BufferHubBuffer. The new BufferHubBuffer will share the same underlying + // gralloc buffer and ashmem region for metadata. Note that the caller owns the token and + // should free it after use. + // Returns a valid token on success, nullptr on failure. + // TODO(b/122543147): use a movable wrapper for token + native_handle_t* Duplicate(); private: BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint32_t format, uint64_t usage, size_t userMetadataSize); - BufferHubBuffer(pdx::LocalChannelHandle mChannelHandle); + BufferHubBuffer(const native_handle_t* token); - int ImportGraphicBuffer(); + int initWithBufferTraits(const frameworks::bufferhub::V1_0::BufferTraits& bufferTraits); // Global id for the buffer that is consistent across processes. - int mId = -1; + int mId = 0; // Client state mask of this BufferHubBuffer object. It is unique amoung all // clients/users of the buffer. @@ -159,8 +123,8 @@ private: // Stores ground truth of the buffer. AHardwareBuffer_Desc mBufferDesc; - // Wrapps the gralloc buffer handle of this buffer. - dvr::NativeHandleWrapper<pdx::LocalHandle> mBufferHandle; + // Wraps the gralloc buffer handle of this buffer. + hardware::hidl_handle mBufferHandle; // An ashmem-based metadata object. The same shared memory are mapped to the // bufferhubd daemon and all buffer clients. @@ -170,8 +134,8 @@ private: std::atomic<uint32_t>* fence_state_ = nullptr; std::atomic<uint32_t>* active_clients_bit_mask_ = nullptr; - // PDX backend. - BufferHubClient mClient; + // HwBinder backend + sp<frameworks::bufferhub::V1_0::IBufferClient> mBufferClient; }; } // namespace android diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp index a670b3ce63..665469e015 100644 --- a/libs/ui/tests/Android.bp +++ b/libs/ui/tests/Android.bp @@ -31,12 +31,14 @@ cc_test { cc_test { name: "GraphicBuffer_test", header_libs: [ - "libbufferhub_headers", "libdvr_headers", "libnativewindow_headers", ], shared_libs: [ - "libpdx_default_transport", + "android.frameworks.bufferhub@1.0", + "libcutils", + "libhidlbase", + "libhwbinder", "libui", "libutils", ], @@ -47,7 +49,6 @@ cc_test { cc_test { name: "BufferHub_test", header_libs: [ - "libbufferhub_headers", "libdvr_headers", "libnativewindow_headers", ], @@ -60,7 +61,6 @@ cc_test { "libhidlbase", "libhwbinder", "liblog", - "libpdx_default_transport", "libui", "libutils" ], diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp index 69b9590d40..cd744cd106 100644 --- a/libs/ui/tests/BufferHubBuffer_test.cpp +++ b/libs/ui/tests/BufferHubBuffer_test.cpp @@ -16,10 +16,9 @@ #define LOG_TAG "BufferHubBufferTest" -#include <android/frameworks/bufferhub/1.0/IBufferClient.h> -#include <android/frameworks/bufferhub/1.0/IBufferHub.h> #include <android/hardware_buffer.h> #include <cutils/native_handle.h> +#include <gmock/gmock.h> #include <gtest/gtest.h> #include <hidl/ServiceManagement.h> #include <hwbinder/IPCThreadState.h> @@ -29,36 +28,38 @@ namespace android { namespace { +using ::android::BufferHubDefs::AnyClientAcquired; +using ::android::BufferHubDefs::AnyClientGained; +using ::android::BufferHubDefs::AnyClientPosted; +using ::android::BufferHubDefs::IsBufferReleased; +using ::android::BufferHubDefs::IsClientAcquired; +using ::android::BufferHubDefs::IsClientGained; +using ::android::BufferHubDefs::IsClientPosted; +using ::android::BufferHubDefs::IsClientReleased; +using ::android::BufferHubDefs::kMetadataHeaderSize; +using ::testing::IsNull; +using ::testing::NotNull; + const int kWidth = 640; const int kHeight = 480; const int kLayerCount = 1; const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888; const int kUsage = 0; -const size_t kUserMetadataSize = 0; - -using BufferHubDefs::AnyClientAcquired; -using BufferHubDefs::AnyClientGained; -using BufferHubDefs::AnyClientPosted; -using BufferHubDefs::IsBufferReleased; -using BufferHubDefs::IsClientAcquired; -using BufferHubDefs::IsClientGained; -using BufferHubDefs::IsClientPosted; -using BufferHubDefs::IsClientReleased; -using BufferHubDefs::kFirstClientBitMask; -using BufferHubDefs::kMetadataHeaderSize; -using frameworks::bufferhub::V1_0::BufferHubStatus; -using frameworks::bufferhub::V1_0::IBufferClient; -using frameworks::bufferhub::V1_0::IBufferHub; -using hardware::hidl_handle; -using hardware::graphics::common::V1_2::HardwareBufferDescription; -using hidl::base::V1_0::IBase; -using pdx::LocalChannelHandle; +const AHardwareBuffer_Desc kDesc = {kWidth, kHeight, kLayerCount, kFormat, + kUsage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL}; +const size_t kUserMetadataSize = 1; class BufferHubBufferTest : public ::testing::Test { protected: void SetUp() override { android::hardware::ProcessState::self()->startThreadPool(); } }; +bool cmpAHardwareBufferDesc(const AHardwareBuffer_Desc& desc, const AHardwareBuffer_Desc& other) { + // Not comparing stride because it's unknown before allocation + return desc.format == other.format && desc.height == other.height && + desc.layers == other.layers && desc.usage == other.usage && desc.width == other.width; +} + class BufferHubBufferStateTransitionTest : public BufferHubBufferTest { protected: void SetUp() override { @@ -78,91 +79,126 @@ private: void BufferHubBufferStateTransitionTest::CreateTwoClientsOfABuffer() { b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize); + ASSERT_THAT(b1, NotNull()); b1ClientMask = b1->client_state_mask(); ASSERT_NE(b1ClientMask, 0U); - auto statusOrHandle = b1->Duplicate(); - ASSERT_TRUE(statusOrHandle); - LocalChannelHandle h2 = statusOrHandle.take(); - b2 = BufferHubBuffer::Import(std::move(h2)); + + native_handle_t* token = b1->Duplicate(); + ASSERT_THAT(token, NotNull()); + + // TODO(b/122543147): use a movalbe wrapper for token + b2 = BufferHubBuffer::Import(token); + native_handle_close(token); + native_handle_delete(token); + ASSERT_THAT(b2, NotNull()); + b2ClientMask = b2->client_state_mask(); ASSERT_NE(b2ClientMask, 0U); ASSERT_NE(b2ClientMask, b1ClientMask); } -TEST_F(BufferHubBufferTest, CreateBufferHubBufferFails) { +TEST_F(BufferHubBufferTest, CreateBufferFails) { // Buffer Creation will fail: BLOB format requires height to be 1. auto b1 = BufferHubBuffer::Create(kWidth, /*height=*/2, kLayerCount, /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage, kUserMetadataSize); - EXPECT_FALSE(b1->IsConnected()); - EXPECT_FALSE(b1->IsValid()); + EXPECT_THAT(b1, IsNull()); // Buffer Creation will fail: user metadata size too large. auto b2 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage, /*userMetadataSize=*/std::numeric_limits<size_t>::max()); - EXPECT_FALSE(b2->IsConnected()); - EXPECT_FALSE(b2->IsValid()); + EXPECT_THAT(b2, IsNull()); // Buffer Creation will fail: user metadata size too large. const size_t userMetadataSize = std::numeric_limits<size_t>::max() - kMetadataHeaderSize; auto b3 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage, userMetadataSize); - EXPECT_FALSE(b3->IsConnected()); - EXPECT_FALSE(b3->IsValid()); + EXPECT_THAT(b3, IsNull()); } -TEST_F(BufferHubBufferTest, CreateBufferHubBuffer) { +TEST_F(BufferHubBufferTest, CreateBuffer) { auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize); + ASSERT_THAT(b1, NotNull()); EXPECT_TRUE(b1->IsConnected()); EXPECT_TRUE(b1->IsValid()); - EXPECT_NE(b1->id(), 0); + EXPECT_TRUE(cmpAHardwareBufferDesc(b1->desc(), kDesc)); + EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize); } -TEST_F(BufferHubBufferTest, DuplicateBufferHubBuffer) { +TEST_F(BufferHubBufferTest, DuplicateAndImportBuffer) { auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize); - int id1 = b1->id(); - uint32_t bufferStateMask1 = b1->client_state_mask(); - EXPECT_NE(bufferStateMask1, 0U); + ASSERT_THAT(b1, NotNull()); EXPECT_TRUE(b1->IsValid()); - EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize); - auto statusOrHandle = b1->Duplicate(); - EXPECT_TRUE(statusOrHandle); + native_handle_t* token = b1->Duplicate(); + EXPECT_TRUE(token); // The detached buffer should still be valid. EXPECT_TRUE(b1->IsConnected()); EXPECT_TRUE(b1->IsValid()); - // Gets the channel handle for the duplicated buffer. - LocalChannelHandle h2 = statusOrHandle.take(); - EXPECT_TRUE(h2.valid()); + std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token); + native_handle_close(token); + native_handle_delete(token); - std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(h2)); - EXPECT_FALSE(h2.valid()); - ASSERT_TRUE(b2 != nullptr); + ASSERT_THAT(b2, NotNull()); EXPECT_TRUE(b2->IsValid()); - EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize); - int id2 = b2->id(); - uint32_t bufferStateMask2 = b2->client_state_mask(); - EXPECT_NE(bufferStateMask2, 0U); + EXPECT_TRUE(cmpAHardwareBufferDesc(b1->desc(), b2->desc())); + EXPECT_EQ(b1->user_metadata_size(), b2->user_metadata_size()); // These two buffer instances are based on the same physical buffer under the // hood, so they should share the same id. - EXPECT_EQ(id1, id2); + EXPECT_EQ(b1->id(), b2->id()); // We use client_state_mask() to tell those two instances apart. - EXPECT_NE(bufferStateMask1, bufferStateMask2); + EXPECT_NE(b1->client_state_mask(), b2->client_state_mask()); // Both buffer instances should be in released state currently. EXPECT_TRUE(IsBufferReleased(b1->buffer_state())); EXPECT_TRUE(IsBufferReleased(b2->buffer_state())); +} + +TEST_F(BufferHubBufferTest, ImportFreedBuffer) { + auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage, + kUserMetadataSize); + ASSERT_THAT(b1, NotNull()); + EXPECT_TRUE(b1->IsValid()); + + native_handle_t* token = b1->Duplicate(); + EXPECT_TRUE(token); - // TODO(b/112338294): rewrite test after migration - return; + // Explicitly destroy b1. Backend buffer should be freed and token becomes invalid + b1.reset(); + + // TODO(b/122543147): use a movalbe wrapper for token + std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token); + native_handle_close(token); + native_handle_delete(token); + + // Import should fail with INVALID_TOKEN + EXPECT_THAT(b2, IsNull()); +} + +// nullptr must not crash the service +TEST_F(BufferHubBufferTest, ImportNullToken) { + auto b1 = BufferHubBuffer::Import(nullptr); + EXPECT_THAT(b1, IsNull()); +} + +// TODO(b/118180214): remove the comment after ag/5856474 landed +// This test has a very little chance to fail (number of existing tokens / 2 ^ 32) +TEST_F(BufferHubBufferTest, ImportInvalidToken) { + native_handle_t* token = native_handle_create(/*numFds=*/0, /*numInts=*/1); + token->data[0] = 0; + + auto b1 = BufferHubBuffer::Import(token); + native_handle_delete(token); + + EXPECT_THAT(b1, IsNull()); } TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromReleasedState) { @@ -357,13 +393,20 @@ TEST_F(BufferHubBufferTest, createNewConsumerAfterGain) { std::unique_ptr<BufferHubBuffer> b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize); + ASSERT_THAT(b1, NotNull()); ASSERT_EQ(b1->Gain(), 0); // Create a consumer of the buffer and test if the consumer can acquire the // buffer if producer posts. - auto statusOrHandle = b1->Duplicate(); - ASSERT_TRUE(statusOrHandle); - std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(statusOrHandle.take())); + // TODO(b/122543147): use a movalbe wrapper for token + native_handle_t* token = b1->Duplicate(); + ASSERT_TRUE(token); + + std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token); + native_handle_close(token); + native_handle_delete(token); + + ASSERT_THAT(b2, NotNull()); ASSERT_NE(b1->client_state_mask(), b2->client_state_mask()); ASSERT_EQ(b1->Post(), 0); @@ -380,13 +423,20 @@ TEST_F(BufferHubBufferTest, createNewConsumerAfterPost) { // Create a consumer of the buffer and test if the consumer can acquire the // buffer if producer posts. - auto statusOrHandle = b1->Duplicate(); - ASSERT_TRUE(statusOrHandle); - std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(statusOrHandle.take())); + // TODO(b/122543147): use a movalbe wrapper for token + native_handle_t* token = b1->Duplicate(); + ASSERT_TRUE(token); + + std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token); + native_handle_close(token); + native_handle_delete(token); + + ASSERT_THAT(b2, NotNull()); ASSERT_NE(b1->client_state_mask(), b2->client_state_mask()); EXPECT_EQ(b2->Acquire(), 0); } } // namespace + } // namespace android diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp index 81ab3acfe4..5b46454c60 100644 --- a/libs/ui/tests/GraphicBuffer_test.cpp +++ b/libs/ui/tests/GraphicBuffer_test.cpp @@ -39,7 +39,7 @@ TEST_F(GraphicBufferTest, CreateFromBufferHubBuffer) { std::unique_ptr<BufferHubBuffer> b1 = BufferHubBuffer::Create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat, kTestUsage, /*userMetadataSize=*/0); - EXPECT_NE(b1, nullptr); + ASSERT_NE(b1, nullptr); EXPECT_TRUE(b1->IsValid()); sp<GraphicBuffer> gb(new GraphicBuffer(std::move(b1))); diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp index 487a604890..ed5a992f3c 100644 --- a/libs/vr/libbufferhub/buffer_hub-test.cpp +++ b/libs/vr/libbufferhub/buffer_hub-test.cpp @@ -5,7 +5,6 @@ #include <private/dvr/producer_buffer.h> #include <sys/epoll.h> #include <sys/eventfd.h> -#include <ui/BufferHubBuffer.h> #include <ui/BufferHubDefs.h> #include <mutex> @@ -20,9 +19,6 @@ return result; \ })() -using android::BufferHubBuffer; -using android::GraphicBuffer; -using android::sp; using android::BufferHubDefs::AnyClientAcquired; using android::BufferHubDefs::AnyClientGained; using android::BufferHubDefs::AnyClientPosted; @@ -31,19 +27,15 @@ using android::BufferHubDefs::IsClientAcquired; using android::BufferHubDefs::IsClientPosted; using android::BufferHubDefs::IsClientReleased; using android::BufferHubDefs::kFirstClientBitMask; -using android::BufferHubDefs::kMetadataHeaderSize; using android::dvr::ConsumerBuffer; using android::dvr::ProducerBuffer; -using android::pdx::LocalChannelHandle; using android::pdx::LocalHandle; using android::pdx::Status; const int kWidth = 640; const int kHeight = 480; -const int kLayerCount = 1; const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888; const int kUsage = 0; -const size_t kUserMetadataSize = 0; // Maximum number of consumers for the buffer that only has one producer in the // test. const size_t kMaxConsumerCount = @@ -808,7 +800,7 @@ TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) { // TODO(b/112338294) rewrite test after migration return; - std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create( + /* std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create( kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); std::unique_ptr<ConsumerBuffer> c = ConsumerBuffer::Import(p->CreateConsumer()); @@ -876,49 +868,14 @@ TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) { EXPECT_TRUE(d->IsConnected()); EXPECT_TRUE(d->IsValid()); - EXPECT_EQ(d->id(), p_id); -} - -TEST_F(LibBufferHubTest, TestCreateBufferHubBufferFails) { - // Buffer Creation will fail: BLOB format requires height to be 1. - auto b1 = BufferHubBuffer::Create(kWidth, /*height=2*/ 2, kLayerCount, - /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage, - kUserMetadataSize); - - EXPECT_FALSE(b1->IsConnected()); - EXPECT_FALSE(b1->IsValid()); - - // Buffer Creation will fail: user metadata size too large. - auto b2 = BufferHubBuffer::Create( - kWidth, kHeight, kLayerCount, kFormat, kUsage, - /*user_metadata_size=*/std::numeric_limits<size_t>::max()); - - EXPECT_FALSE(b2->IsConnected()); - EXPECT_FALSE(b2->IsValid()); - - // Buffer Creation will fail: user metadata size too large. - auto b3 = BufferHubBuffer::Create( - kWidth, kHeight, kLayerCount, kFormat, kUsage, - /*user_metadata_size=*/std::numeric_limits<size_t>::max() - - kMetadataHeaderSize); - - EXPECT_FALSE(b3->IsConnected()); - EXPECT_FALSE(b3->IsValid()); -} - -TEST_F(LibBufferHubTest, TestCreateBufferHubBuffer) { - auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, - kUsage, kUserMetadataSize); - EXPECT_TRUE(b1->IsConnected()); - EXPECT_TRUE(b1->IsValid()); - EXPECT_NE(b1->id(), 0); + EXPECT_EQ(d->id(), p_id); */ } TEST_F(LibBufferHubTest, TestDetach) { // TODO(b/112338294) rewrite test after migration return; - std::unique_ptr<ProducerBuffer> p1 = ProducerBuffer::Create( + /* std::unique_ptr<ProducerBuffer> p1 = ProducerBuffer::Create( kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t)); ASSERT_TRUE(p1.get() != nullptr); int p1_id = p1->id(); @@ -936,47 +893,5 @@ TEST_F(LibBufferHubTest, TestDetach) { EXPECT_FALSE(h1.valid()); EXPECT_TRUE(b1->IsValid()); int b1_id = b1->id(); - EXPECT_EQ(b1_id, p1_id); -} - -TEST_F(LibBufferHubTest, TestDuplicateBufferHubBuffer) { - auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, - kUsage, kUserMetadataSize); - int b1_id = b1->id(); - EXPECT_TRUE(b1->IsValid()); - EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize); - EXPECT_NE(b1->client_state_mask(), 0U); - - auto status_or_handle = b1->Duplicate(); - EXPECT_TRUE(status_or_handle); - - // The detached buffer should still be valid. - EXPECT_TRUE(b1->IsConnected()); - EXPECT_TRUE(b1->IsValid()); - - // Gets the channel handle for the duplicated buffer. - LocalChannelHandle h2 = status_or_handle.take(); - EXPECT_TRUE(h2.valid()); - - std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(h2)); - EXPECT_FALSE(h2.valid()); - ASSERT_TRUE(b2 != nullptr); - EXPECT_TRUE(b2->IsValid()); - EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize); - EXPECT_NE(b2->client_state_mask(), 0U); - - int b2_id = b2->id(); - - // These two buffer instances are based on the same physical buffer under the - // hood, so they should share the same id. - EXPECT_EQ(b1_id, b2_id); - // We use client_state_mask() to tell those two instances apart. - EXPECT_NE(b1->client_state_mask(), b2->client_state_mask()); - - // Both buffer instances should be in gained state. - EXPECT_TRUE(IsBufferReleased(b1->buffer_state())); - EXPECT_TRUE(IsBufferReleased(b2->buffer_state())); - - // TODO(b/112338294) rewrite test after migration - return; + EXPECT_EQ(b1_id, p1_id); */ } |