summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2024-08-28 21:03:47 -0700
committerLinux Build Service Account <lnxbuild@localhost>2024-08-28 21:03:47 -0700
commit53696dbbf6b8cc56413489900868826df767463c (patch)
tree98b3e7392f61feaa7fe380ebf2d0ced9d27d33e1
parentba0f55423259510b82104aa80dcea2b6d035f340 (diff)
parent9fe6899662ba6534e488333c5b16f6c52f24af8c (diff)
Merge 9fe6899662ba6534e488333c5b16f6c52f24af8c on remote branch
Change-Id: I5e8b7d75de67d15aecd61feeacb08c7f4fc6e879
-rw-r--r--media/codec2/core/include/C2Buffer.h3
-rw-r--r--media/codec2/tests/Android.bp6
-rw-r--r--media/codec2/tests/vndk/C2FenceTest.cpp455
-rw-r--r--media/codec2/vndk/C2Fence.cpp420
-rw-r--r--media/codec2/vndk/include/C2FenceFactory.h104
-rw-r--r--services/audiopolicy/enginedefault/src/Engine.cpp7
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: {