diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2024-08-28 21:03:47 -0700 |
---|---|---|
committer | Linux Build Service Account <lnxbuild@localhost> | 2024-08-28 21:03:47 -0700 |
commit | 53696dbbf6b8cc56413489900868826df767463c (patch) | |
tree | 98b3e7392f61feaa7fe380ebf2d0ced9d27d33e1 | |
parent | ba0f55423259510b82104aa80dcea2b6d035f340 (diff) | |
parent | 9fe6899662ba6534e488333c5b16f6c52f24af8c (diff) |
Merge 9fe6899662ba6534e488333c5b16f6c52f24af8c on remote branch
Change-Id: I5e8b7d75de67d15aecd61feeacb08c7f4fc6e879
-rw-r--r-- | media/codec2/core/include/C2Buffer.h | 3 | ||||
-rw-r--r-- | media/codec2/tests/Android.bp | 6 | ||||
-rw-r--r-- | media/codec2/tests/vndk/C2FenceTest.cpp | 455 | ||||
-rw-r--r-- | media/codec2/vndk/C2Fence.cpp | 420 | ||||
-rw-r--r-- | media/codec2/vndk/include/C2FenceFactory.h | 104 | ||||
-rw-r--r-- | services/audiopolicy/enginedefault/src/Engine.cpp | 7 |
6 files changed, 954 insertions, 41 deletions
diff --git a/media/codec2/core/include/C2Buffer.h b/media/codec2/core/include/C2Buffer.h index 98f1165d46..5f6e541f65 100644 --- a/media/codec2/core/include/C2Buffer.h +++ b/media/codec2/core/include/C2Buffer.h @@ -101,6 +101,8 @@ public: /** * Returns a file descriptor that can be used to wait for this fence in a select system call. + * \note If there are multiple file descriptors in fence then a file descriptor for merged fence + * would be returned * \note The returned file descriptor, if valid, must be closed by the caller. * * This can be used in e.g. poll() system calls. This file becomes readable (POLLIN) when the @@ -137,6 +139,7 @@ private: std::shared_ptr<Impl> mImpl; C2Fence(std::shared_ptr<Impl> impl); friend struct _C2FenceFactory; + friend std::vector<int> ExtractFdsFromCodec2SyncFence(const C2Fence& fence); }; /** diff --git a/media/codec2/tests/Android.bp b/media/codec2/tests/Android.bp index 2217235dd9..53d88ae7ca 100644 --- a/media/codec2/tests/Android.bp +++ b/media/codec2/tests/Android.bp @@ -44,6 +44,11 @@ cc_test { "C2SampleComponent_test.cpp", "C2UtilTest.cpp", "vndk/C2BufferTest.cpp", + "vndk/C2FenceTest.cpp", + ], + + static_libs: [ + "libgmock", ], shared_libs: [ @@ -51,6 +56,7 @@ cc_test { "libcodec2_vndk", "libcutils", "liblog", + "libui", "libutils", ], diff --git a/media/codec2/tests/vndk/C2FenceTest.cpp b/media/codec2/tests/vndk/C2FenceTest.cpp new file mode 100644 index 0000000000..9292381d70 --- /dev/null +++ b/media/codec2/tests/vndk/C2FenceTest.cpp @@ -0,0 +1,455 @@ +/* + * Copyright 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 <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <C2Buffer.h> +#include <C2FenceFactory.h> + +#include <unistd.h> + +#include <android-base/unique_fd.h> +#include <linux/kcmp.h> /* Definition of KCMP_* constants */ +#include <sys/mman.h> +#include <sys/syscall.h> /* Definition of SYS_* constants */ +#include <ui/Fence.h> + +namespace android { + +static int fd_kcmp(int fd1, int fd2) { + static pid_t pid = getpid(); + + return syscall(SYS_kcmp, pid, pid, KCMP_FILE, fd1, fd2); +} + +// matcher to check if value (arg) and fd refers to the same file +MATCHER_P(RefersToTheSameFile, fd, "") { + return fd_kcmp(fd, arg) == 0; +} + +// matcher to check if value (arg) is a dup of an fd +MATCHER_P(IsDupOf, fd, "") { + return (ExplainMatchResult(::testing::Ne(-1), arg, result_listener) && + ExplainMatchResult(::testing::Ne(fd), arg, result_listener) && + ExplainMatchResult(RefersToTheSameFile(fd), arg, result_listener)); +} + +class C2FenceTest : public ::testing::Test { +public: + C2FenceTest() = default; + + ~C2FenceTest() = default; + + +protected: + enum : int32_t { + SYNC_FENCE_DEPRECATED_MAGIC = 3, + SYNC_FENCE_UNORDERED_MAGIC = '\302fsu', + SYNC_FENCE_MAGIC = '\302fso', + }; + + // Validate a null fence + void validateNullFence(const C2Fence &fence); + + // Validate a single fd sync fence + void validateSingleFdFence(const C2Fence &fence, int fd); + + // Validate a two fd unordered sync fence + void validateTwoFdUnorderedFence(const C2Fence &fence, int fd1, int fd2, int mergeFd); + + // Validate a three fd sync fence + void validateThreeFdFence(const C2Fence &fence, int fd1, int fd2, int fd3); +}; + +TEST_F(C2FenceTest, IsDupOf_sanity) { + int fd1 = memfd_create("test1", 0 /* flags */); + int fd2 = memfd_create("test2", 0 /* flags */); + int fd3 = memfd_create("test3", 0 /* flags */); + + EXPECT_THAT(fd1, ::testing::Not(IsDupOf(fd2))); + EXPECT_THAT(-1, ::testing::Not(IsDupOf(fd2))); + EXPECT_THAT(-1, ::testing::Not(IsDupOf(-1))); + EXPECT_THAT(fd3, ::testing::Not(IsDupOf(fd3))); + + int fd4 = dup(fd3); + EXPECT_THAT(fd4, IsDupOf(fd3)); + EXPECT_THAT(fd3, IsDupOf(fd4)); + + close(fd1); + close(fd2); + close(fd3); + close(fd4); +} + +TEST_F(C2FenceTest, NullFence) { + validateNullFence(C2Fence()); +} + +void C2FenceTest::validateNullFence(const C2Fence &fence) { + // Verify that the fence is valid. + EXPECT_TRUE(fence.valid()); + EXPECT_TRUE(fence.ready()); + base::unique_fd fenceFd{fence.fd()}; + EXPECT_EQ(fenceFd.get(), -1); + EXPECT_FALSE(fence.isHW()); // perhaps this should be false for a null fence + + // A null fence has no fds + std::vector<int> fds = ExtractFdsFromCodec2SyncFence(fence); + EXPECT_THAT(fds, ::testing::IsEmpty()); + for (int fd : fds) { + close(fd); + } + + // A null fence has no native handle + native_handle_t *handle = _C2FenceFactory::CreateNativeHandle(fence); + EXPECT_THAT(handle, ::testing::IsNull()); + if (handle) { + native_handle_close(handle); + native_handle_delete(handle); + } +} + +TEST_F(C2FenceTest, SyncFence_with_negative_fd) { + // Create a SyncFence with a negative fd. + C2Fence fence = _C2FenceFactory::CreateSyncFence(-1, false /* validate */); + + validateNullFence(fence); +} + +TEST_F(C2FenceTest, SyncFence_with_valid_fd) { + // Create a SyncFence with a valid fd. We cannot create an actual sync fd, + // so we cannot test wait(), but we can verify the ABI APIs + + int fd = memfd_create("test", 0 /* flags */); + + C2Fence fence = _C2FenceFactory::CreateSyncFence(fd, false /* validate */); + validateSingleFdFence(fence, fd); +} + +void C2FenceTest::validateSingleFdFence(const C2Fence &fence, int fd) { + // EXPECT_TRUE(fence.valid()); // need a valid sync fd to test this + // EXPECT_TRUE(fence.ready()); + // Verify that the fence says it is a HW sync fence. + EXPECT_TRUE(fence.isHW()); // FIXME this may be an implementation detail + + // Verify that the fd returned is a duped version of the initial fd + base::unique_fd fenceFd{fence.fd()}; + EXPECT_THAT(fenceFd.get(), IsDupOf(fd)); + + // Verify that fds returns a duped version of the initial fd + std::vector<int> fds = ExtractFdsFromCodec2SyncFence(fence); + EXPECT_THAT(fds, ::testing::SizeIs(1)); + EXPECT_THAT(fds, ::testing::ElementsAre(IsDupOf(fd))); + for (int fd_i : fds) { + close(fd_i); + } + + native_handle_t *handle = _C2FenceFactory::CreateNativeHandle(fence); + EXPECT_THAT(handle, ::testing::NotNull()); + if (handle) { + EXPECT_EQ(handle->numFds, 1); + EXPECT_EQ(handle->numInts, 1); + EXPECT_THAT(handle->data[0], IsDupOf(fd)); + EXPECT_EQ(handle->data[1], SYNC_FENCE_MAGIC); + + native_handle_close(handle); + native_handle_delete(handle); + } +} + +TEST_F(C2FenceTest, UnorderedMultiSyncFence_with_one_valid_test_fd) { + // Create a multi SyncFence with a single valid fd. This should create + // a single fd sync fence. We can only validate this through its public + // methods: fd/fds and verify the native handle ABI. + + int fd = memfd_create("test", 0 /* flags */); + + c2_status_t status = C2_BAD_VALUE; + C2Fence fence = _C2FenceFactory::CreateUnorderedMultiSyncFence( + { -1, fd, -1 }, &status); + // if we only have one valid fd, we are not merging fences, so the test fd is not validated + EXPECT_EQ(status, C2_OK); + + validateSingleFdFence(fence, fd); +} + +TEST_F(C2FenceTest, UnorderedMultiSyncFence_with_one_valid_test_fd_null_status) { + // Create a multi SyncFence with a single valid fd. This should create + // a single fd sync fence. We can only validate this through its public + // methods: fd/fds and verify the native handle ABI. + + int fd = memfd_create("test", 0 /* flags */); + + C2Fence fence = _C2FenceFactory::CreateUnorderedMultiSyncFence( + { -1, fd, -1 }); + + validateSingleFdFence(fence, fd); +} + +TEST_F(C2FenceTest, UnorderedMultiSyncFence_with_merge_failure) { + // Create a multi SyncFence with a multiple non-sync fence fds. This should + // result in a fence created, but also an error. + + int fd1 = memfd_create("test1", 0 /* flags */); + int fd2 = memfd_create("test2", 0 /* flags */); + int fd3 = memfd_create("test3", 0 /* flags */); + + c2_status_t status = C2_BAD_VALUE; + C2Fence fence = _C2FenceFactory::CreateUnorderedMultiSyncFence( + { fd1, fd2, fd3 }, &status); + EXPECT_EQ(status, C2_CORRUPTED); + + validateThreeFdFence(fence, fd1, fd2, fd3); +} + +TEST_F(C2FenceTest, UnorderedMultiSyncFence_with_merge_failure_null_status) { + // Create a multi SyncFence with a multiple non-sync fence fds. This should + // result in a fence created, but also an error. + + int fd1 = memfd_create("test1", 0 /* flags */); + int fd2 = memfd_create("test2", 0 /* flags */); + int fd3 = memfd_create("test3", 0 /* flags */); + + C2Fence fence = _C2FenceFactory::CreateUnorderedMultiSyncFence( + { fd1, fd2, fd3 }); + + validateThreeFdFence(fence, fd1, fd2, fd3); +} + +TEST_F(C2FenceTest, UnorderedMultiSyncFence_with_multiple_fds) { + // We cannot create a true unordered multi sync fence as we can only + // create test fds and those cannot be merged. As such, we cannot + // test the factory method CreateUnorderedMultiSyncFence. We can however + // create a test fence from a constructed native handle. + + // Technically, we need 3 fds as if we end up with only 2, we wouldn't + // actually need a 2nd (final fence fd) since it is equivalent to the + // first. In fact we will generate (and always generated) a single fd + // fence in that case. + int fd1 = memfd_create("test1", 0 /* flags */); + int fd2 = memfd_create("test2", 0 /* flags */); + int mergeFd = memfd_create("test3", 0 /* flags */); + + native_handle_t *handle = native_handle_create(3 /* numfds */, 1 /* numints */); + handle->data[0] = fd1; + handle->data[1] = fd2; + handle->data[2] = mergeFd; + handle->data[3] = SYNC_FENCE_UNORDERED_MAGIC; + C2Fence fence = _C2FenceFactory::CreateFromNativeHandle(handle, true /* takeOwnership */); + native_handle_delete(handle); + + validateTwoFdUnorderedFence(fence, fd1, fd2, mergeFd); +} + +void C2FenceTest::validateTwoFdUnorderedFence( + const C2Fence &fence, int fd1, int fd2, int mergeFd) { + // EXPECT_TRUE(fence.valid()); // need a valid sync fd to test this + // EXPECT_TRUE(fence.ready()); + // Verify that the fence says it is a HW sync fence. + EXPECT_TRUE(fence.isHW()); // FIXME this may be an implementation detail + + // Verify that the fd returned is a duped version of the merge fd + base::unique_fd fenceFd{fence.fd()}; + EXPECT_THAT(fenceFd.get(), IsDupOf(mergeFd)); + + // Verify that fds returns a duped versions of the initial fds (but not the merge fd) + std::vector<int> fds = ExtractFdsFromCodec2SyncFence(fence); + EXPECT_THAT(fds, ::testing::SizeIs(2)); + EXPECT_THAT(fds, ::testing::ElementsAre(IsDupOf(fd1), IsDupOf(fd2))); + for (int fd_i : fds) { + close(fd_i); + } + + native_handle_t *handle = _C2FenceFactory::CreateNativeHandle(fence); + EXPECT_THAT(handle, ::testing::NotNull()); + if (handle) { + EXPECT_EQ(handle->numFds, 3); + EXPECT_EQ(handle->numInts, 1); + EXPECT_THAT(handle->data[0], IsDupOf(fd1)); + EXPECT_THAT(handle->data[1], IsDupOf(fd2)); + EXPECT_THAT(handle->data[2], IsDupOf(mergeFd)); + EXPECT_EQ(handle->data[3], SYNC_FENCE_UNORDERED_MAGIC); + + native_handle_close(handle); + native_handle_delete(handle); + } +} + +TEST_F(C2FenceTest, MultiSyncFence_with_one_valid_test_fd) { + // Create a multi SyncFence with a single valid fd. This should create + // a single fd sync fence. We can only validate this through its public + // methods: fd/fds and verify the native handle ABI. + + int fd = memfd_create("test", 0 /* flags */); + + c2_status_t status = C2_BAD_VALUE; + C2Fence fence = _C2FenceFactory::CreateMultiSyncFence( + { -1, fd, -1 }, &status); + // if we only have one valid fd, we are not merging fences, so the test fds are not validated + EXPECT_EQ(status, C2_OK); + + validateSingleFdFence(fence, fd); +} + +TEST_F(C2FenceTest, MultiSyncFence_with_one_valid_test_fd_null_status) { + // Create a multi SyncFence with a single valid fd. This should create + // a single fd sync fence. We can only validate this through its public + // methods: fd/fds and verify the native handle ABI. + + int fd = memfd_create("test", 0 /* flags */); + + C2Fence fence = _C2FenceFactory::CreateMultiSyncFence( + { -1, fd, -1 }); + + validateSingleFdFence(fence, fd); +} + +TEST_F(C2FenceTest, MultiSyncFence_with_multiple_fds) { + int fd1 = memfd_create("test1", 0 /* flags */); + int fd2 = memfd_create("test2", 0 /* flags */); + int fd3 = memfd_create("test3", 0 /* flags */); + + c2_status_t status = C2_BAD_VALUE; + C2Fence fence = _C2FenceFactory::CreateMultiSyncFence( + { fd1, fd2, fd3 }, &status); + // test fds are not validated + EXPECT_EQ(status, C2_OK); + + validateThreeFdFence(fence, fd1, fd2, fd3); +} + +void C2FenceTest::validateThreeFdFence(const C2Fence &fence, int fd1, int fd2, int fd3) { + // EXPECT_TRUE(fence.valid()); // need a valid sync fd to test this + // EXPECT_TRUE(fence.ready()); + // Verify that the fence says it is a HW sync fence. + EXPECT_TRUE(fence.isHW()); // FIXME this may be an implementation detail + + // Verify that the fd returned is a duped version of the final fd + base::unique_fd fenceFd{fence.fd()}; + EXPECT_THAT(fenceFd.get(), IsDupOf(fd3)); + + // Verify that fds returns a duped versions of all 3 initial fds + std::vector<int> fds = ExtractFdsFromCodec2SyncFence(fence); + EXPECT_THAT(fds, ::testing::SizeIs(3)); + EXPECT_THAT(fds, ::testing::ElementsAre(IsDupOf(fd1), IsDupOf(fd2), IsDupOf(fd3))); + for (int fd_i : fds) { + close(fd_i); + } + + native_handle_t *handle = _C2FenceFactory::CreateNativeHandle(fence); + EXPECT_THAT(handle, ::testing::NotNull()); + if (handle) { + EXPECT_EQ(handle->numFds, 3); + EXPECT_EQ(handle->numInts, 1); + EXPECT_THAT(handle->data[0], IsDupOf(fd1)); + EXPECT_THAT(handle->data[1], IsDupOf(fd2)); + EXPECT_THAT(handle->data[2], IsDupOf(fd3)); + EXPECT_EQ(handle->data[3], SYNC_FENCE_MAGIC); + + native_handle_close(handle); + native_handle_delete(handle); + } +} + +TEST_F(C2FenceTest, BackwardCompat_UDC_sync_fence) { + // Create a single SyncFence from a UDC native handle + + int fd = memfd_create("test", 0 /* flags */); + + native_handle_t *handle = native_handle_create(1 /* numfds */, 1 /* numints */); + handle->data[0] = fd; + handle->data[1] = SYNC_FENCE_DEPRECATED_MAGIC; + C2Fence fence = _C2FenceFactory::CreateFromNativeHandle(handle, true /* takeOwnership */); + native_handle_delete(handle); + + validateSingleFdFence(fence, fd); +} + +TEST_F(C2FenceTest, BackwardCompat_24Q1_single_fd_fence) { + // Create a single SyncFence from a 24Q1 native handle + // This had the same (albeit separately duped) fd twice, and used the legacy + // magic number. + + int fd = memfd_create("test", 0 /* flags */); + + native_handle_t *handle = native_handle_create(2 /* numfds */, 1 /* numints */); + handle->data[0] = fd; + handle->data[1] = dup(fd); + handle->data[2] = SYNC_FENCE_DEPRECATED_MAGIC; + C2Fence fence = _C2FenceFactory::CreateFromNativeHandle(handle, true /* takeOwnership */); + native_handle_delete(handle); + + validateSingleFdFence(fence, fd); +} + +TEST_F(C2FenceTest, BackwardCompat_24Q3_single_fd_fence) { + // Create a single SyncFence from the defined native handle + + int fd = memfd_create("test", 0 /* flags */); + + native_handle_t *handle = native_handle_create(1 /* numfds */, 1 /* numints */); + handle->data[0] = fd; + handle->data[1] = SYNC_FENCE_MAGIC; + C2Fence fence = _C2FenceFactory::CreateFromNativeHandle(handle, true /* takeOwnership */); + native_handle_delete(handle); + + validateSingleFdFence(fence, fd); +} + +TEST_F(C2FenceTest, BackwardCompat_24Q1_multi_fd_fence) { + // Create a single SyncFence from a 24Q1 era native handle with + // the legacy magic number. + + int fd1 = memfd_create("test1", 0 /* flags */); + int fd2 = memfd_create("test2", 0 /* flags */); + int mergeFd = memfd_create("test3", 0 /* flags */); + + native_handle_t *handle = native_handle_create(3 /* numfds */, 1 /* numints */); + handle->data[0] = fd1; + handle->data[1] = fd2; + handle->data[2] = mergeFd; + handle->data[3] = SYNC_FENCE_DEPRECATED_MAGIC; + C2Fence fence = _C2FenceFactory::CreateFromNativeHandle(handle, true /* takeOwnership */); + native_handle_delete(handle); + + validateTwoFdUnorderedFence(fence, fd1, fd2, mergeFd); +} + +// No need to create BackwardCompat_24Q3_unordered_multi_fd_fence because +// we are creating that fence already from the 24Q3 native handle layout +// in the UnorderedMultiSyncFence_with_multiple_fds test. + +TEST_F(C2FenceTest, BackwardCompat_24Q3_multi_fd_fence) { + // Create a single SyncFence from a 24Q1 era native handle with + // the legacy magic number. + + int fd1 = memfd_create("test1", 0 /* flags */); + int fd2 = memfd_create("test2", 0 /* flags */); + int fd3 = memfd_create("test3", 0 /* flags */); + + native_handle_t *handle = native_handle_create(3 /* numfds */, 1 /* numints */); + handle->data[0] = fd1; + handle->data[1] = fd2; + handle->data[2] = fd3; + handle->data[3] = SYNC_FENCE_MAGIC; + C2Fence fence = _C2FenceFactory::CreateFromNativeHandle(handle, true /* takeOwnership */); + native_handle_delete(handle); + + validateThreeFdFence(fence, fd1, fd2, fd3); +} + +} // namespace android diff --git a/media/codec2/vndk/C2Fence.cpp b/media/codec2/vndk/C2Fence.cpp index 2b0f24f6bf..8f16c67b1c 100644 --- a/media/codec2/vndk/C2Fence.cpp +++ b/media/codec2/vndk/C2Fence.cpp @@ -23,16 +23,27 @@ #include <C2FenceFactory.h> #include <C2SurfaceSyncObj.h> -#define MAX_FENCE_FDS 1 +// support up to 32 sync fds (and an optional merged fd), and 1 int +#define MAX_FENCE_FDS 33 +#define MAX_FENCE_INTS 1 class C2Fence::Impl { public: - enum type_t : uint32_t { - ANDROID_FENCE, - INVALID_FENCE, - NULL_FENCE, - SURFACE_FENCE, - SYNC_FENCE, + // These enums are not part of the ABI, so can be changed. + enum type_t : int32_t { + ANDROID_FENCE = -2, + INVALID_FENCE = -1, + NULL_FENCE = 0, + SURFACE_FENCE = 2, + + SYNC_FENCE = 3, + }; + + // magic numbers for native handles + enum : int32_t { + SYNC_FENCE_DEPRECATED_MAGIC = 3, + SYNC_FENCE_UNORDERED_MAGIC = '\302fsu', + SYNC_FENCE_MAGIC = '\302fso', }; virtual c2_status_t wait(c2_nsecs_t timeoutNs) = 0; @@ -49,7 +60,8 @@ public: /** * Create a native handle for the fence so it can be marshalled. - * The native handle must store fence type in the first integer. + * All native handles must store fence type in the last integer. + * The created native handle (if not null) must be closed by the caller. * * \return a valid native handle if the fence can be marshalled, otherwise return null. */ @@ -59,11 +71,29 @@ public: Impl() = default; + /** + * Get the type of the fence from the native handle. + * + * \param nh the native handle to get the type from. + * \return the type of the fence, or INVALID_FENCE if the native handle is + * invalid or malformed. + */ static type_t GetTypeFromNativeHandle(const native_handle_t* nh) { - if (nh && nh->numFds >= 0 && nh->numFds <= MAX_FENCE_FDS && nh->numInts > 0) { - return static_cast<type_t>(nh->data[nh->numFds]); + if (!nh || nh->numFds < 0 || nh->numFds > MAX_FENCE_FDS + || nh->numInts < 1 || nh->numInts > MAX_FENCE_INTS) { + return INVALID_FENCE; + } + + // the magic number for Codec 2.0 native handles is the last integer + switch (nh->data[nh->numFds + nh->numInts - 1]) { + case SYNC_FENCE_MAGIC: + case SYNC_FENCE_UNORDERED_MAGIC: + case SYNC_FENCE_DEPRECATED_MAGIC: + return SYNC_FENCE; + + default: + return INVALID_FENCE; } - return INVALID_FENCE; } }; @@ -216,6 +246,53 @@ C2Fence _C2FenceFactory::CreateSurfaceFence( using namespace android; +/** + * Implementation for a sync fence. + * + * A sync fence is fundamentally a fence that is created from an android sync + * fd (which represents a HW fence). + * + * The native handle layout for a single sync fence is: + * fd[0] - sync fd + * int[0] - magic (SYNC_FENCE_MAGIC (=`\302fso')) + * + * Note: Between Android T and 24Q3, the magic number was erroneously + * SYNC_FENCE (=3). + * + * Multi(ple) Sync Fences + * + * Since Android 24Q3, this implementation also supports a sequence of + * sync fences. When this is the case, there is an expectation that the last + * sync fence being ready will guarantee that all other sync fences are + * also ready. (This guarantees backward compatibility to a single fd sync fence, + * and mFence will be that final fence.) + * + * It is furthermore recommended that the fences be in order - either by + * expected signaling time, or by the order in which they need to be ready. The + * specific ordering is not specified or enforced, but it could be an + * implementation requirement of the specific use case in the future. + * + * This implementation also supports an unordered set of sync fences. In this + * case, it will merge all the fences into a single merged fence, which will + * be the backward compatible singular fence (stored in mFence). + * + * The native handle layout for an unordered multi-fence sync fence (from Android + * 24Q3) is: + * + * fd[0] - sync fd 1 + * ... + * fd[n-1] - sync fd N + * fd[n] - merged fence fd + * int[0] - magic (SYNC_FENCE_UNORDERED_MAGIC (='\302fsu')) + * + * The native handle layout for an ordered multi-fence sync fence (from Android + * 24Q3) is: + * + * fd[0] - sync fd 1 + * ... + * fd[n-1] - sync fd N + * int[0] - magic (SYNC_FENCE_MAGIC (='\302fso')) + */ class _C2FenceFactory::SyncFenceImpl : public C2Fence::Impl { public: virtual c2_status_t wait(c2_nsecs_t timeoutNs) { @@ -223,7 +300,6 @@ public: if (timeoutMs > INT_MAX) { timeoutMs = INT_MAX; } - switch (mFence->wait((int)timeoutMs)) { case NO_ERROR: return C2_OK; @@ -235,7 +311,7 @@ public: } virtual bool valid() const { - return mFence->getStatus() != Fence::Status::Invalid; + return (mFence && (mFence->getStatus() != Fence::Status::Invalid)); } virtual bool ready() const { @@ -246,6 +322,22 @@ public: return mFence->dup(); } + /** + * Returns a duped list of fds used when creating this fence. It will + * not return the internally created merged fence fd. + */ + std::vector<int> fds() const { + std::vector<int> retFds; + for (int index = 0; index < mListFences.size(); index++) { + retFds.push_back(mListFences[index]->dup()); + } + // ensure that at least one fd is returned + if (mListFences.empty()) { + retFds.push_back(mFence->dup()); + } + return retFds; + } + virtual bool isHW() const { return true; } @@ -255,61 +347,319 @@ public: } virtual native_handle_t *createNativeHandle() const { - native_handle_t* nh = native_handle_create(1, 1); + std::vector<int> nativeFds = fds(); + int32_t magic = SYNC_FENCE_MAGIC; + + // Also parcel the singular fence if it is not already part of the list. + // If this was a single-fd fence, mListFences will be empty, but fds() + // already returned that a list with that single fd. + if (!mListFences.empty() && mListFences.back() != mFence) { + nativeFds.push_back(fd()); + if (!mListFences.empty()) { + magic = SYNC_FENCE_UNORDERED_MAGIC; + } + } + + native_handle_t* nh = native_handle_create(nativeFds.size(), 1); if (!nh) { ALOGE("Failed to allocate native handle for sync fence"); + for (int fd : nativeFds) { + close(fd); + } return nullptr; } - nh->data[0] = fd(); - nh->data[1] = type(); + + for (int i = 0; i < nativeFds.size(); i++) { + nh->data[i] = nativeFds[i]; + } + nh->data[nativeFds.size()] = magic; return nh; } virtual ~SyncFenceImpl() {}; + /** + * Constructs a SyncFenceImpl from a single sync fd. No error checking is + * performed on the fd here as we cannot make this a null fence. + * + * \param fenceFd the fence fd to create the SyncFenceImpl from. + */ SyncFenceImpl(int fenceFd) : - mFence(sp<Fence>::make(fenceFd)) {} + mFence(sp<Fence>::make(fenceFd)) { + } + + SyncFenceImpl(const sp<Fence> &fence) : + mFence(fence) { + } - static std::shared_ptr<SyncFenceImpl> CreateFromNativeHandle(const native_handle_t* nh) { - if (!nh || nh->numFds != 1 || nh->numInts != 1) { - ALOGE("Invalid handle for sync fence"); + /** + * Constructs a SyncFenceImpl from a list of sync fds. + * + * \param fenceFds the list of fence fds to create the SyncFenceImpl from. + * \param finalFence the singular fence for this multi-fd fence. This can + * be either the last fence in fences or a sepearate (merged) fence. + */ + SyncFenceImpl(const std::vector<sp<Fence>>& fences, const sp<Fence> &finalFence) : + mListFences(fences), + mFence(finalFence) { + } + + /** + * Creates a SyncFenceImpl from a native handle. + * + * \param nh the native handle to create the SyncFenceImpl from. + * \param takeOwnership if true, the SyncFenceImpl will take ownership of the + * file descriptors in the native handle. Otherwise, + * the SyncFenceImpl will dup the file descriptors. + * + * \return a shared_ptr to the SyncFenceImpl, or nullptr if the native + * handle is invalid or malformed. + */ + static std::shared_ptr<SyncFenceImpl> CreateFromNativeHandle( + const native_handle_t* nh, bool takeOwnership) { + // we should only call this method if _C2FenceFactory::GetTypeFromNativeHandle + // returned SYNC_FENCE, but do these checks anyways to avoid overflows + // in case that does not happen. + if (!nh) { + ALOGE("Invalid handle for a sync fence (nullptr)"); + return nullptr; + } else if (nh->numFds < 1 || nh->numInts < 1 + || nh->numFds > MAX_FENCE_FDS || nh->numInts > MAX_FENCE_INTS) { + ALOGE("Invalid handle for a sync fence (%d fds, %d ints)", nh->numFds, nh->numInts); return nullptr; } - int fd = dup(nh->data[0]); - std::shared_ptr<SyncFenceImpl> p = std::make_shared<SyncFenceImpl>(fd); - if (!p) { - ALOGE("Failed to allocate sync fence impl"); - close(fd); + std::vector<sp<Fence>> fences; + for (int i = 0; i < nh->numFds; i++) { + int fd = nh->data[i]; + if (!takeOwnership && fd >= 0) { + fd = dup(fd); + } + if (fd >= 0) { + sp<Fence> fence = sp<Fence>::make(fd); + if (fence) { + fences.push_back(fence); + } else { + ALOGW("Failed to create fence from fd %d", fd); + } + } + } + + std::shared_ptr<SyncFenceImpl> p; + if (fences.size() == 0) { + ALOGE("No valid fences found in handle for a sync fence"); + return nullptr; + } else if (fences.size() == 1) { + p = std::make_shared<SyncFenceImpl>(fences[0]); + } else { + int32_t magic = nh->data[nh->numFds + nh->numInts - 1]; + if (magic != SYNC_FENCE_MAGIC) { + // The last fence is the merged fence. Separate it. + sp<Fence> finalFence = fences.back(); + fences.pop_back(); + + // Special case: if we end up with only a single element list + // with another merged fence, that merged fence must be the + // same fence. This happened in an early version of multi fd + // support for single-fd sync fences. + if (fences.size() == 1) { + // For single-fd fence the sp-s must be equal + finalFence = fences.back(); + } + p = std::make_shared<SyncFenceImpl>(fences, finalFence); + } else { + // Use the last fence as the standalone fence. + p = std::make_shared<SyncFenceImpl>(fences, fences.back()); + } } + + ALOGE_IF(!p, "Failed to allocate sync fence impl"); return p; } private: - const sp<Fence> mFence; + /** + * The list of fences in case of a multi-fence sync fence. Otherwise, this + * list is empty. + */ + std::vector<sp<Fence>> mListFences; + + /** + * The singular fence for this sync fence. For multi-fence sync fences, + * this could be a merged fence, or simply the final fence. + */ + sp<Fence> mFence; }; -C2Fence _C2FenceFactory::CreateSyncFence(int fenceFd) { +std::vector<int> ExtractFdsFromCodec2SyncFence(const C2Fence& fence) { + std::vector<int> retFds; + if ((fence.mImpl) && (fence.mImpl->type() == C2Fence::Impl::SYNC_FENCE)) { + retFds = static_cast<_C2FenceFactory::SyncFenceImpl *>(fence.mImpl.get())->fds(); + } + return retFds; +} + +C2Fence _C2FenceFactory::CreateSyncFence(int fenceFd, bool validate) { std::shared_ptr<C2Fence::Impl> p; if (fenceFd >= 0) { p = std::make_shared<_C2FenceFactory::SyncFenceImpl>(fenceFd); if (!p) { ALOGE("Failed to allocate sync fence impl"); close(fenceFd); - } - if (!p->valid()) { + } else if (validate && (!p->valid() || p->ready())) { + // don't create a fence object if the sync fd already signaled or is invalid p.reset(); } } else { - ALOGE("Create sync fence from invalid fd"); + ALOGV("Won't create sync fence from invalid fd"); } return C2Fence(p); } +C2Fence _C2FenceFactory::CreateSyncFence(int fenceFd) { + return CreateSyncFence(fenceFd, true); +} + +C2Fence _C2FenceFactory::CreateUnorderedMultiSyncFence( + const std::vector<int>& fenceFds, c2_status_t *status) { + if (status) { + *status = C2_OK; + } + + sp<Fence> finalFence; + std::vector<sp<Fence>> fences; + + bool mergeFailed = false; + for (int fenceFd : fenceFds) { + if (fenceFd < 0) { + // ignore invalid fences + continue; + } + sp<Fence> fence = sp<Fence>::make(fenceFd); + + // If we could not create an sp, further sp-s will also fail. + if (fence == nullptr) { + if (status) { + *status = C2_NO_MEMORY; + } + break; + } + fences.push_back(fence); + + if (finalFence == nullptr) { + finalFence = fence; + } else { + sp<Fence> mergedFence = Fence::merge("syncFence", finalFence, fence); + if (mergedFence == nullptr || mergedFence == Fence::NO_FENCE) { + ALOGE_IF(!mergeFailed, "Could not merge fences for sync fence."); + mergeFailed = true; + if (status) { + *status = (mergedFence == nullptr) ? C2_NO_MEMORY : C2_CORRUPTED; + } + + if (mergedFence == nullptr) { + break; + } + // If we cannot merge one of the fences, the best course of action + // is to keep going, as the alternative would be to clear all fences + // (making this a null fence) but that will always be ready. + } else { + finalFence = mergedFence; + } + } + } + + // we may have ended up with a single or no fence due to merging failures or + // invalid fds. + if (fences.size() == 0) { + // we have no fds, we have a null fence. + return C2Fence(); + } + + std::shared_ptr<C2Fence::Impl> p; + + if (fences.size() == 1) { + // We have a single sync fd. We don't need the merged fence, which is + // already simply that sole fence. + p = std::make_shared<_C2FenceFactory::SyncFenceImpl>(finalFence); + } else { + // if we couldn't merge any fences just use the last one + if (finalFence == fences[0]) { + finalFence = fences.back(); + } + + p = std::make_shared<_C2FenceFactory::SyncFenceImpl>(fences, finalFence); + } + + if (!p) { + ALOGE("Failed to allocate sync fence impl closing FDs"); + // all fds were moved into Fence objects which will close them. + if (status) { + *status = C2_NO_MEMORY; + } + return C2Fence(); + } + + return C2Fence(p); +} + +C2Fence _C2FenceFactory::CreateMultiSyncFence( + const std::vector<int>& fenceFds, c2_status_t *status) { + if (status) { + *status = C2_OK; + } + + std::vector<sp<Fence>> fences; + + for (int fenceFd : fenceFds) { + if (fenceFd < 0) { + // ignore invalid fences + continue; + } + sp<Fence> fence = sp<Fence>::make(fenceFd); + + // If we could not create an sp, keep going with the existing fences. + if (fence == nullptr) { + if (status) { + *status = C2_NO_MEMORY; + } + break; + } + fences.push_back(fence); + } + + // we may have ended up with a single or no fence due to invalid fds. + if (fences.size() == 0) { + // we have no fds, we have a null fence. + return C2Fence(); + } + + std::shared_ptr<C2Fence::Impl> p; + + if (fences.size() == 1) { + // We have a single sync fd, this is a simple sync fence. + p = std::make_shared<_C2FenceFactory::SyncFenceImpl>(fences[0]); + } else { + p = std::make_shared<_C2FenceFactory::SyncFenceImpl>(fences, fences.back()); + } + + if (!p) { + ALOGE("Failed to allocate sync fence impl closing FDs"); + // all fds were moved into Fence objects which will close them. + if (status) { + *status = C2_NO_MEMORY; + } + return C2Fence(); + } + + return C2Fence(p); +} + native_handle_t* _C2FenceFactory::CreateNativeHandle(const C2Fence& fence) { return fence.mImpl? fence.mImpl->createNativeHandle() : nullptr; } -C2Fence _C2FenceFactory::CreateFromNativeHandle(const native_handle_t* handle) { +C2Fence _C2FenceFactory::CreateFromNativeHandle( + const native_handle_t* handle, bool takeOwnership) { if (!handle) { return C2Fence(); } @@ -317,10 +667,14 @@ C2Fence _C2FenceFactory::CreateFromNativeHandle(const native_handle_t* handle) { std::shared_ptr<C2Fence::Impl> p; switch (type) { case C2Fence::Impl::SYNC_FENCE: - p = SyncFenceImpl::CreateFromNativeHandle(handle); + p = SyncFenceImpl::CreateFromNativeHandle(handle, takeOwnership); break; default: - ALOGD("Unsupported fence type %d", type); + ALOGV("Unsupported fence type %d", type); + // Still close the handle here if taking ownership. + if (takeOwnership) { + (void) native_handle_close(handle); + } // return a null-fence in this case break; } diff --git a/media/codec2/vndk/include/C2FenceFactory.h b/media/codec2/vndk/include/C2FenceFactory.h index 4944115c35..1664624ff8 100644 --- a/media/codec2/vndk/include/C2FenceFactory.h +++ b/media/codec2/vndk/include/C2FenceFactory.h @@ -20,6 +20,22 @@ #include <C2Buffer.h> +/* + * Extract a list of sync fence fds from a potentially multi-sync C2Fence. + * This will return dupped file descriptors of the fences used to creating the + * sync fence. Specifically, for an unordered mult-sync fence, the merged + * singular fence will not be returned even though it is created aspart of + * constructing the C2Fence object. On the other hand, for a single fd sync + * fence, the returned list will contain the sole file descriptor. + * + * \param fence C2Fence object from which associated + * file descriptors need to be extracted + * \return a vector of sync fence fds. This will be a vector of size 0 if C2Fence + * is not a sync fence. The caller is responsible for closing the + * fds in the returned vector. + */ +std::vector<int> ExtractFdsFromCodec2SyncFence(const C2Fence& fence); + class C2SurfaceSyncMemory; /** @@ -41,13 +57,82 @@ struct _C2FenceFactory { uint32_t waitId); /* - * Create C2Fence from a fence file fd. + * Create C2Fence from a sync fence fd. * - * \param fenceFd Fence file descriptor. + * \param fenceFd Sync fence file descriptor. * It will be owned and closed by the returned fence object. + * \param validate If true, the fence fd will be validated to ensure + * it is a valid pending sync fence fd. */ + + static C2Fence CreateSyncFence(int fenceFd, bool validate /*= true*/); + + //Overloading CreateSyncFence for backward compatibility + static C2Fence CreateSyncFence(int fenceFd); + /* + * Create C2Fence from list of sync fence fds, while also merging them to + * create a singular fence, which can be used as a backward compatible sync + * fence. + * + * \param fenceFds Vector of sync fence file descriptors. + * All file descriptors will be owned (and closed) by + * the returned fence object. + */ + [[deprecated("Use CreateUnorderedMultiSyncFence instead.")]] + static C2Fence CreateMultipleFdSyncFence(const std::vector<int>& fenceFds) { + return CreateUnorderedMultiSyncFence(fenceFds); + } + + /* + * Create C2Fence from a list of unordered sync fence fds, while also merging + * them to create a singular fence, which can be used as a backward compatible + * sync fence. + * + * \param fenceFds Vector of sync fence file descriptors. + * All file descriptors will be owned (and closed) by + * the returned fence object. + * \param status Optional pointer to a status field. If not null, it will be + * updated with the status of the operation. Possible values + * are: + * - C2_OK: The operation succeeded. + * - C2_NO_MEMORY: The operation failed because of lack of + * memory. + * - C2_CORRUPTED: The operation failed because the sync + * fence fds could bot be merged. + * \return A C2Fence object representing the sync fence fds, or + * an empty C2Fence if the no C2Fence could be created. + * It is possible for the operation to fail but still return + * a possibly viable C2Fence object, e.g. if the merge + * operation failed only partially. Similarly, it is possible + * for the operation to succeed but still return an empty + * C2Fence object, e.g. if all fence fds were invalid. + */ + static C2Fence CreateUnorderedMultiSyncFence( + const std::vector<int>& fenceFds, c2_status_t *status = nullptr /* nullable */); + + /* + * Create C2Fence from a list of sync fence fds. Waiting for the last fence + * must guarantee that all other fences are also signaled. + * + * \param fenceFds Vector of sync fence file descriptors. + * All file descriptors will be owned (and closed) by + * the returned fence object. + * \param status Optional pointer to a status field. If not null, it will be + * updated with the status of the operation. Possible values + * are: + * - C2_OK: The operation succeeded. + * - C2_NO_MEMORY: The operation failed because of lack of + * memory. + * \return A C2Fence object representing the sync fence fds, or + * an empty C2Fence if the operation failed. It is possible + * for the operation to succeed but still return an empty + * C2Fence object, e.g. if all fence fds were invalid. + */ + static C2Fence CreateMultiSyncFence( + const std::vector<int>& fenceFds, c2_status_t *status = nullptr /* nullable */); + /** * Create a native handle from fence for marshalling * @@ -57,13 +142,18 @@ struct _C2FenceFactory { /* * Create C2Fence from a native handle. - + * * \param handle A native handle representing a fence - * The fd in the native handle will be duplicated, so the caller will - * still own the handle and have to close it. + * \param takeOwnership If true, the native handle and the file descriptors + * within will be owned by the returned fence object. + * If false (default), the caller will still own the + * handle and its file descriptors and will have to + * close it. + * In either case the caller is responsible for + * deleting the native handle. */ - static C2Fence CreateFromNativeHandle(const native_handle_t* handle); + static C2Fence CreateFromNativeHandle( + const native_handle_t* handle, bool takeOwnership = false); }; - #endif // STAGEFRIGHT_CODEC2_FENCE_FACTORY_H_ diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp index 4a8d381b8c..c5316600b0 100644 --- a/services/audiopolicy/enginedefault/src/Engine.cpp +++ b/services/audiopolicy/enginedefault/src/Engine.cpp @@ -278,7 +278,12 @@ DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy, switch (strategy) { case STRATEGY_TRANSMITTED_THROUGH_SPEAKER: - devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER); + if (property_get_bool("vendor.audio.enable.wfdfilteredaudio", false)) { + devices = availableOutputDevices.getFirstDevicesFromTypes({AUDIO_DEVICE_OUT_IP, + AUDIO_DEVICE_OUT_SPEAKER}); + } else { + devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER); + } break; case STRATEGY_PHONE: { |