Loading libs/vr/libbufferhub/Android.bp +8 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ sourceFiles = [ "buffer_hub_base.cpp", "buffer_hub_client.cpp", "buffer_hub_metadata.cpp", "buffer_hub_rpc.cpp", "consumer_buffer.cpp", "detached_buffer.cpp", Loading Loading @@ -69,3 +70,10 @@ cc_test { name: "buffer_hub-test", } cc_test { srcs: ["buffer_hub_metadata-test.cpp"], static_libs: ["libbufferhub"], shared_libs: sharedLibraries, header_libs: headerLibraries, name: "buffer_hub_metadata-test", } libs/vr/libbufferhub/buffer_hub_metadata-test.cpp 0 → 100644 +105 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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 <gtest/gtest.h> #include <private/dvr/buffer_hub_metadata.h> using android::dvr::BufferHubDefs::IsBufferGained; namespace android { namespace dvr { constexpr size_t kEmptyUserMetadataSize = 0; class BufferHubMetadataTest : public ::testing::Test {}; TEST_F(BufferHubMetadataTest, Create_UserMetdataSizeTooBig) { BufferHubMetadata m1 = BufferHubMetadata::Create(std::numeric_limits<uint32_t>::max()); EXPECT_FALSE(m1.IsValid()); } TEST_F(BufferHubMetadataTest, Create_Success) { BufferHubMetadata m1 = BufferHubMetadata::Create(kEmptyUserMetadataSize); EXPECT_TRUE(m1.IsValid()); EXPECT_NE(m1.metadata_header(), nullptr); } TEST_F(BufferHubMetadataTest, Import_Success) { BufferHubMetadata m1 = BufferHubMetadata::Create(kEmptyUserMetadataSize); EXPECT_TRUE(m1.IsValid()); EXPECT_NE(m1.metadata_header(), nullptr); pdx::LocalHandle h2 = m1.ashmem_handle().Duplicate(); EXPECT_TRUE(h2.IsValid()); BufferHubMetadata m2 = BufferHubMetadata::Import(std::move(h2)); EXPECT_FALSE(h2.IsValid()); EXPECT_TRUE(m1.IsValid()); BufferHubDefs::MetadataHeader* mh1 = m1.metadata_header(); EXPECT_NE(mh1, nullptr); // TODO(b/111976433): Update this test once BufferHub state machine gets // updated. In the old model, buffer starts in the gained state (i.e. // valued 0). In the new model, buffer states in the released state. EXPECT_TRUE(IsBufferGained(mh1->fence_state.load())); EXPECT_TRUE(m2.IsValid()); BufferHubDefs::MetadataHeader* mh2 = m2.metadata_header(); EXPECT_NE(mh2, nullptr); // TODO(b/111976433): Update this test once BufferHub state machine gets // updated. In the old model, buffer starts in the gained state (i.e. // valued 0). In the new model, buffer states in the released state. EXPECT_TRUE(IsBufferGained(mh2->fence_state.load())); } TEST_F(BufferHubMetadataTest, MoveMetadataInvalidatesOldOne) { BufferHubMetadata m1 = BufferHubMetadata::Create(sizeof(int)); EXPECT_TRUE(m1.IsValid()); EXPECT_NE(m1.metadata_header(), nullptr); EXPECT_TRUE(m1.ashmem_handle().IsValid()); EXPECT_EQ(m1.user_metadata_size(), sizeof(int)); BufferHubMetadata m2 = std::move(m1); // After the move, the metadata header (a raw pointer) should be reset in the // older buffer. EXPECT_EQ(m1.metadata_header(), nullptr); EXPECT_NE(m2.metadata_header(), nullptr); EXPECT_FALSE(m1.ashmem_handle().IsValid()); EXPECT_TRUE(m2.ashmem_handle().IsValid()); EXPECT_EQ(m1.user_metadata_size(), 0U); EXPECT_EQ(m2.user_metadata_size(), sizeof(int)); BufferHubMetadata m3{std::move(m2)}; // After the move, the metadata header (a raw pointer) should be reset in the // older buffer. EXPECT_EQ(m2.metadata_header(), nullptr); EXPECT_NE(m3.metadata_header(), nullptr); EXPECT_FALSE(m2.ashmem_handle().IsValid()); EXPECT_TRUE(m3.ashmem_handle().IsValid()); EXPECT_EQ(m2.user_metadata_size(), 0U); EXPECT_EQ(m3.user_metadata_size(), sizeof(int)); } } // namespace dvr } // namespace android libs/vr/libbufferhub/buffer_hub_metadata.cpp 0 → 100644 +108 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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 <errno.h> #include <sys/mman.h> #include <cutils/ashmem.h> #include <log/log.h> #include <private/dvr/buffer_hub_metadata.h> namespace android { namespace dvr { namespace { static const int kAshmemProt = PROT_READ | PROT_WRITE; } // namespace using BufferHubDefs::kMetadataHeaderSize; using BufferHubDefs::MetadataHeader; /* static */ BufferHubMetadata BufferHubMetadata::Create(size_t user_metadata_size) { // The size the of metadata buffer is used as the "width" parameter during // allocation. Thus it cannot overflow uint32_t. if (user_metadata_size >= (std::numeric_limits<uint32_t>::max() - kMetadataHeaderSize)) { ALOGE("BufferHubMetadata::Create: metadata size too big: %zu.", user_metadata_size); return {}; } const size_t metadata_size = user_metadata_size + kMetadataHeaderSize; int fd = ashmem_create_region(/*name=*/"BufferHubMetadata", metadata_size); if (fd < 0) { ALOGE("BufferHubMetadata::Create: failed to create ashmem region."); return {}; } // Hand over the ownership of the fd to a pdx::LocalHandle immediately after // the successful return of ashmem_create_region. The ashmem_handle is going // to own the fd and to prevent fd leaks during error handling. pdx::LocalHandle ashmem_handle{fd}; if (ashmem_set_prot_region(ashmem_handle.Get(), kAshmemProt) != 0) { ALOGE("BufferHubMetadata::Create: failed to set protect region."); return {}; } return BufferHubMetadata::Import(std::move(ashmem_handle)); } /* static */ BufferHubMetadata BufferHubMetadata::Import(pdx::LocalHandle ashmem_handle) { if (!ashmem_valid(ashmem_handle.Get())) { ALOGE("BufferHubMetadata::Import: invalid ashmem fd."); return {}; } size_t metadata_size = ashmem_get_size_region(ashmem_handle.Get()); size_t user_metadata_size = metadata_size - kMetadataHeaderSize; auto metadata_header = static_cast<MetadataHeader*>( mmap(nullptr, metadata_size, kAshmemProt, MAP_SHARED, ashmem_handle.Get(), /*offset=*/0)); if (metadata_header == nullptr) { ALOGE("BufferHubMetadata::Import: failed to map region."); return {}; } return BufferHubMetadata(user_metadata_size, std::move(ashmem_handle), metadata_header); } BufferHubMetadata::BufferHubMetadata(size_t user_metadata_size, pdx::LocalHandle ashmem_handle, MetadataHeader* metadata_header) : user_metadata_size_(user_metadata_size), ashmem_handle_(std::move(ashmem_handle)), metadata_header_(metadata_header) {} BufferHubMetadata::~BufferHubMetadata() { if (metadata_header_ != nullptr) { int ret = munmap(metadata_header_, metadata_size()); ALOGE_IF(ret != 0, "BufferHubMetadata::~BufferHubMetadata: failed to unmap ashmem, " "error=%d.", errno); metadata_header_ = nullptr; } } } // namespace dvr } // namespace android libs/vr/libbufferhub/include/private/dvr/buffer_hub_metadata.h 0 → 100644 +93 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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. */ #ifndef ANDROID_DVR_BUFFER_HUB_METADATA_H_ #define ANDROID_DVR_BUFFER_HUB_METADATA_H_ #include <pdx/file_handle.h> #include <private/dvr/buffer_hub_defs.h> namespace android { namespace dvr { class BufferHubMetadata { public: // Creates a new BufferHubMetadata backed by an ashmem region. // // @param user_metadata_size Size in bytes of the user defined metadata. The // entire metadata shared memory region to be allocated is the size of // canonical BufferHubDefs::MetadataHeader plus user_metadata_size. static BufferHubMetadata Create(size_t user_metadata_size); // Imports an existing BufferHubMetadata from an ashmem FD. // // TODO(b/112338294): Refactor BufferHub to use Binder as its internal IPC // backend instead of UDS. // // @param ashmem_handle Ashmem file handle representing an ashmem region. static BufferHubMetadata Import(pdx::LocalHandle ashmem_handle); BufferHubMetadata() = default; BufferHubMetadata(BufferHubMetadata&& other) { *this = std::move(other); } ~BufferHubMetadata(); BufferHubMetadata& operator=(BufferHubMetadata&& other) { if (this != &other) { user_metadata_size_ = other.user_metadata_size_; other.user_metadata_size_ = 0; ashmem_handle_ = std::move(other.ashmem_handle_); // The old raw metadata_header_ pointer must be cleared, otherwise the // destructor will automatically mummap() the shared memory. metadata_header_ = other.metadata_header_; other.metadata_header_ = nullptr; } return *this; } // Returns true if the metadata is valid, i.e. the metadata has a valid ashmem // fd and the ashmem has been mapped into virtual address space. bool IsValid() const { return ashmem_handle_.IsValid() && metadata_header_ != nullptr; } size_t user_metadata_size() const { return user_metadata_size_; } size_t metadata_size() const { return user_metadata_size_ + BufferHubDefs::kMetadataHeaderSize; } const pdx::LocalHandle& ashmem_handle() const { return ashmem_handle_; } BufferHubDefs::MetadataHeader* metadata_header() { return metadata_header_; } private: BufferHubMetadata(size_t user_metadata_size, pdx::LocalHandle ashmem_handle, BufferHubDefs::MetadataHeader* metadata_header); BufferHubMetadata(const BufferHubMetadata&) = delete; void operator=(const BufferHubMetadata&) = delete; size_t user_metadata_size_ = 0; pdx::LocalHandle ashmem_handle_; BufferHubDefs::MetadataHeader* metadata_header_ = nullptr; }; } // namespace dvr } // namespace android #endif // ANDROID_DVR_BUFFER_HUB_METADATA_H_ Loading
libs/vr/libbufferhub/Android.bp +8 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ sourceFiles = [ "buffer_hub_base.cpp", "buffer_hub_client.cpp", "buffer_hub_metadata.cpp", "buffer_hub_rpc.cpp", "consumer_buffer.cpp", "detached_buffer.cpp", Loading Loading @@ -69,3 +70,10 @@ cc_test { name: "buffer_hub-test", } cc_test { srcs: ["buffer_hub_metadata-test.cpp"], static_libs: ["libbufferhub"], shared_libs: sharedLibraries, header_libs: headerLibraries, name: "buffer_hub_metadata-test", }
libs/vr/libbufferhub/buffer_hub_metadata-test.cpp 0 → 100644 +105 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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 <gtest/gtest.h> #include <private/dvr/buffer_hub_metadata.h> using android::dvr::BufferHubDefs::IsBufferGained; namespace android { namespace dvr { constexpr size_t kEmptyUserMetadataSize = 0; class BufferHubMetadataTest : public ::testing::Test {}; TEST_F(BufferHubMetadataTest, Create_UserMetdataSizeTooBig) { BufferHubMetadata m1 = BufferHubMetadata::Create(std::numeric_limits<uint32_t>::max()); EXPECT_FALSE(m1.IsValid()); } TEST_F(BufferHubMetadataTest, Create_Success) { BufferHubMetadata m1 = BufferHubMetadata::Create(kEmptyUserMetadataSize); EXPECT_TRUE(m1.IsValid()); EXPECT_NE(m1.metadata_header(), nullptr); } TEST_F(BufferHubMetadataTest, Import_Success) { BufferHubMetadata m1 = BufferHubMetadata::Create(kEmptyUserMetadataSize); EXPECT_TRUE(m1.IsValid()); EXPECT_NE(m1.metadata_header(), nullptr); pdx::LocalHandle h2 = m1.ashmem_handle().Duplicate(); EXPECT_TRUE(h2.IsValid()); BufferHubMetadata m2 = BufferHubMetadata::Import(std::move(h2)); EXPECT_FALSE(h2.IsValid()); EXPECT_TRUE(m1.IsValid()); BufferHubDefs::MetadataHeader* mh1 = m1.metadata_header(); EXPECT_NE(mh1, nullptr); // TODO(b/111976433): Update this test once BufferHub state machine gets // updated. In the old model, buffer starts in the gained state (i.e. // valued 0). In the new model, buffer states in the released state. EXPECT_TRUE(IsBufferGained(mh1->fence_state.load())); EXPECT_TRUE(m2.IsValid()); BufferHubDefs::MetadataHeader* mh2 = m2.metadata_header(); EXPECT_NE(mh2, nullptr); // TODO(b/111976433): Update this test once BufferHub state machine gets // updated. In the old model, buffer starts in the gained state (i.e. // valued 0). In the new model, buffer states in the released state. EXPECT_TRUE(IsBufferGained(mh2->fence_state.load())); } TEST_F(BufferHubMetadataTest, MoveMetadataInvalidatesOldOne) { BufferHubMetadata m1 = BufferHubMetadata::Create(sizeof(int)); EXPECT_TRUE(m1.IsValid()); EXPECT_NE(m1.metadata_header(), nullptr); EXPECT_TRUE(m1.ashmem_handle().IsValid()); EXPECT_EQ(m1.user_metadata_size(), sizeof(int)); BufferHubMetadata m2 = std::move(m1); // After the move, the metadata header (a raw pointer) should be reset in the // older buffer. EXPECT_EQ(m1.metadata_header(), nullptr); EXPECT_NE(m2.metadata_header(), nullptr); EXPECT_FALSE(m1.ashmem_handle().IsValid()); EXPECT_TRUE(m2.ashmem_handle().IsValid()); EXPECT_EQ(m1.user_metadata_size(), 0U); EXPECT_EQ(m2.user_metadata_size(), sizeof(int)); BufferHubMetadata m3{std::move(m2)}; // After the move, the metadata header (a raw pointer) should be reset in the // older buffer. EXPECT_EQ(m2.metadata_header(), nullptr); EXPECT_NE(m3.metadata_header(), nullptr); EXPECT_FALSE(m2.ashmem_handle().IsValid()); EXPECT_TRUE(m3.ashmem_handle().IsValid()); EXPECT_EQ(m2.user_metadata_size(), 0U); EXPECT_EQ(m3.user_metadata_size(), sizeof(int)); } } // namespace dvr } // namespace android
libs/vr/libbufferhub/buffer_hub_metadata.cpp 0 → 100644 +108 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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 <errno.h> #include <sys/mman.h> #include <cutils/ashmem.h> #include <log/log.h> #include <private/dvr/buffer_hub_metadata.h> namespace android { namespace dvr { namespace { static const int kAshmemProt = PROT_READ | PROT_WRITE; } // namespace using BufferHubDefs::kMetadataHeaderSize; using BufferHubDefs::MetadataHeader; /* static */ BufferHubMetadata BufferHubMetadata::Create(size_t user_metadata_size) { // The size the of metadata buffer is used as the "width" parameter during // allocation. Thus it cannot overflow uint32_t. if (user_metadata_size >= (std::numeric_limits<uint32_t>::max() - kMetadataHeaderSize)) { ALOGE("BufferHubMetadata::Create: metadata size too big: %zu.", user_metadata_size); return {}; } const size_t metadata_size = user_metadata_size + kMetadataHeaderSize; int fd = ashmem_create_region(/*name=*/"BufferHubMetadata", metadata_size); if (fd < 0) { ALOGE("BufferHubMetadata::Create: failed to create ashmem region."); return {}; } // Hand over the ownership of the fd to a pdx::LocalHandle immediately after // the successful return of ashmem_create_region. The ashmem_handle is going // to own the fd and to prevent fd leaks during error handling. pdx::LocalHandle ashmem_handle{fd}; if (ashmem_set_prot_region(ashmem_handle.Get(), kAshmemProt) != 0) { ALOGE("BufferHubMetadata::Create: failed to set protect region."); return {}; } return BufferHubMetadata::Import(std::move(ashmem_handle)); } /* static */ BufferHubMetadata BufferHubMetadata::Import(pdx::LocalHandle ashmem_handle) { if (!ashmem_valid(ashmem_handle.Get())) { ALOGE("BufferHubMetadata::Import: invalid ashmem fd."); return {}; } size_t metadata_size = ashmem_get_size_region(ashmem_handle.Get()); size_t user_metadata_size = metadata_size - kMetadataHeaderSize; auto metadata_header = static_cast<MetadataHeader*>( mmap(nullptr, metadata_size, kAshmemProt, MAP_SHARED, ashmem_handle.Get(), /*offset=*/0)); if (metadata_header == nullptr) { ALOGE("BufferHubMetadata::Import: failed to map region."); return {}; } return BufferHubMetadata(user_metadata_size, std::move(ashmem_handle), metadata_header); } BufferHubMetadata::BufferHubMetadata(size_t user_metadata_size, pdx::LocalHandle ashmem_handle, MetadataHeader* metadata_header) : user_metadata_size_(user_metadata_size), ashmem_handle_(std::move(ashmem_handle)), metadata_header_(metadata_header) {} BufferHubMetadata::~BufferHubMetadata() { if (metadata_header_ != nullptr) { int ret = munmap(metadata_header_, metadata_size()); ALOGE_IF(ret != 0, "BufferHubMetadata::~BufferHubMetadata: failed to unmap ashmem, " "error=%d.", errno); metadata_header_ = nullptr; } } } // namespace dvr } // namespace android
libs/vr/libbufferhub/include/private/dvr/buffer_hub_metadata.h 0 → 100644 +93 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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. */ #ifndef ANDROID_DVR_BUFFER_HUB_METADATA_H_ #define ANDROID_DVR_BUFFER_HUB_METADATA_H_ #include <pdx/file_handle.h> #include <private/dvr/buffer_hub_defs.h> namespace android { namespace dvr { class BufferHubMetadata { public: // Creates a new BufferHubMetadata backed by an ashmem region. // // @param user_metadata_size Size in bytes of the user defined metadata. The // entire metadata shared memory region to be allocated is the size of // canonical BufferHubDefs::MetadataHeader plus user_metadata_size. static BufferHubMetadata Create(size_t user_metadata_size); // Imports an existing BufferHubMetadata from an ashmem FD. // // TODO(b/112338294): Refactor BufferHub to use Binder as its internal IPC // backend instead of UDS. // // @param ashmem_handle Ashmem file handle representing an ashmem region. static BufferHubMetadata Import(pdx::LocalHandle ashmem_handle); BufferHubMetadata() = default; BufferHubMetadata(BufferHubMetadata&& other) { *this = std::move(other); } ~BufferHubMetadata(); BufferHubMetadata& operator=(BufferHubMetadata&& other) { if (this != &other) { user_metadata_size_ = other.user_metadata_size_; other.user_metadata_size_ = 0; ashmem_handle_ = std::move(other.ashmem_handle_); // The old raw metadata_header_ pointer must be cleared, otherwise the // destructor will automatically mummap() the shared memory. metadata_header_ = other.metadata_header_; other.metadata_header_ = nullptr; } return *this; } // Returns true if the metadata is valid, i.e. the metadata has a valid ashmem // fd and the ashmem has been mapped into virtual address space. bool IsValid() const { return ashmem_handle_.IsValid() && metadata_header_ != nullptr; } size_t user_metadata_size() const { return user_metadata_size_; } size_t metadata_size() const { return user_metadata_size_ + BufferHubDefs::kMetadataHeaderSize; } const pdx::LocalHandle& ashmem_handle() const { return ashmem_handle_; } BufferHubDefs::MetadataHeader* metadata_header() { return metadata_header_; } private: BufferHubMetadata(size_t user_metadata_size, pdx::LocalHandle ashmem_handle, BufferHubDefs::MetadataHeader* metadata_header); BufferHubMetadata(const BufferHubMetadata&) = delete; void operator=(const BufferHubMetadata&) = delete; size_t user_metadata_size_ = 0; pdx::LocalHandle ashmem_handle_; BufferHubDefs::MetadataHeader* metadata_header_ = nullptr; }; } // namespace dvr } // namespace android #endif // ANDROID_DVR_BUFFER_HUB_METADATA_H_