Snap for 4448085 from f2b791587c15ec5028d0b266d415c631a4078916 to oc-m3-release
Change-Id: Id0e8bb274f32339b9889c9b0de619e011711c5c7
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
index abf7b06..b3cbdef 100644
--- a/cmds/atrace/Android.bp
+++ b/cmds/atrace/Android.bp
@@ -11,6 +11,7 @@
"libhidltransport",
"liblog",
"libutils",
+ "libcutils",
"libz",
"libbase",
],
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 3c4a933..f29da17 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1796,8 +1796,14 @@
}
const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
+
+ // Note that we cannot validate the package path here because the file might not exist
+ // and we cannot call realpath to resolve system symlinks. Since /data/user/0 symlinks to
+ // /data/data/ a lot of validations will fail if we attempt to check the package path.
+ // It is still ok to be more relaxed because any file removal is done after forking and
+ // dropping capabilities.
if (!validate_secondary_dex_path(pkgname.c_str(), dex_path.c_str(), volume_uuid_cstr,
- uid, storage_flag)) {
+ uid, storage_flag, /*validate_package_path*/ false)) {
LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
return false;
}
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index d277bd3..dd32ac6 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -801,7 +801,7 @@
}
bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
- const char* volume_uuid, int uid, int storage_flag) {
+ const char* volume_uuid, int uid, int storage_flag, bool validate_package_path) {
CHECK(storage_flag == FLAG_STORAGE_CE || storage_flag == FLAG_STORAGE_DE);
// Empty paths are not allowed.
@@ -815,15 +815,18 @@
// The path should be at most PKG_PATH_MAX long.
if (dex_path.size() > PKG_PATH_MAX) { return false; }
- // The dex_path should be under the app data directory.
- std::string app_private_dir = storage_flag == FLAG_STORAGE_CE
- ? create_data_user_ce_package_path(
- volume_uuid, multiuser_get_user_id(uid), pkgname.c_str())
- : create_data_user_de_package_path(
- volume_uuid, multiuser_get_user_id(uid), pkgname.c_str());
+ if (validate_package_path) {
+ // If we are asked to validate the package path check that
+ // the dex_path is under the app data directory.
+ std::string app_private_dir = storage_flag == FLAG_STORAGE_CE
+ ? create_data_user_ce_package_path(
+ volume_uuid, multiuser_get_user_id(uid), pkgname.c_str())
+ : create_data_user_de_package_path(
+ volume_uuid, multiuser_get_user_id(uid), pkgname.c_str());
- if (strncmp(dex_path.c_str(), app_private_dir.c_str(), app_private_dir.size()) != 0) {
- return false;
+ if (strncmp(dex_path.c_str(), app_private_dir.c_str(), app_private_dir.size()) != 0) {
+ return false;
+ }
}
// If we got here we have a valid path.
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index da3a293..e938042 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -125,7 +125,7 @@
int validate_system_app_path(const char* path);
bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
- const char* volume_uuid, int uid, int storage_flag);
+ const char* volume_uuid, int uid, int storage_flag, bool validate_package_path = true);
int get_path_from_env(dir_rec_t* rec, const char* var);
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index 0d5d206..ec7be53 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -45,7 +45,7 @@
<feature name="android.software.backup" />
<feature name="android.software.home_screen" />
<feature name="android.software.input_methods" />
- <feature name="android.software.picture_in_picture" />
+ <feature name="android.software.picture_in_picture" notLowRam="true" />
<feature name="android.software.activities_on_secondary_displays" />
<feature name="android.software.print" />
<feature name="android.software.companion_device_setup" />
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index 6b7254c..3264666 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -38,4 +38,20 @@
* strings.
*/
@utf8InCpp String[] getNamesForUids(in int[] uids);
+
+ /**
+ * Returns the name of the installer (a package) which installed the named
+ * package. Preloaded packages return the string "preload". Sideloaded packages
+ * return an empty string. Unknown or unknowable are returned as empty strings.
+ */
+
+ @utf8InCpp String getInstallerForPackage(in String packageName);
+
+ /**
+ * Returns the version code of the named package.
+ * Unknown or unknowable versions are returned as 0.
+ */
+
+ int getVersionCodeForPackage(in String packageName);
+
}
diff --git a/libs/hwc2on1adapter/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
index 8c6ef69..77f06bb 100644
--- a/libs/hwc2on1adapter/HWC2On1Adapter.cpp
+++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -426,7 +426,13 @@
std::unique_lock<std::recursive_timed_mutex> lock(mStateMutex);
- mCallbacks[descriptor] = {callbackData, pointer};
+ if (pointer != nullptr) {
+ mCallbacks[descriptor] = {callbackData, pointer};
+ } else {
+ ALOGI("unregisterCallback(%s)", to_string(descriptor).c_str());
+ mCallbacks.erase(descriptor);
+ return Error::None;
+ }
bool hasPendingInvalidate = false;
std::vector<hwc2_display_t> displayIds;
@@ -2005,10 +2011,21 @@
return Error::None;
}
+static bool compareRects(const hwc_rect_t& rect1, const hwc_rect_t& rect2) {
+ return rect1.left == rect2.left &&
+ rect1.right == rect2.right &&
+ rect1.top == rect2.top &&
+ rect1.bottom == rect2.bottom;
+}
+
Error HWC2On1Adapter::Layer::setVisibleRegion(hwc_region_t visible) {
- mVisibleRegion.resize(visible.numRects);
- std::copy_n(visible.rects, visible.numRects, mVisibleRegion.begin());
- mDisplay.markGeometryChanged();
+ if ((getNumVisibleRegions() != visible.numRects) ||
+ !std::equal(mVisibleRegion.begin(), mVisibleRegion.end(), visible.rects,
+ compareRects)) {
+ mVisibleRegion.resize(visible.numRects);
+ std::copy_n(visible.rects, visible.numRects, mVisibleRegion.begin());
+ mDisplay.markGeometryChanged();
+ }
return Error::None;
}
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index da0ea24..f327200 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -37,7 +37,8 @@
"libnativewindow"
]
-HeaderLibraries = [
+headerLibraries = [
+ "libdvr_headers",
"libnativebase_headers",
]
@@ -45,12 +46,13 @@
srcs: sourceFiles,
cflags: [
"-DLOG_TAG=\"libbufferhub\"",
- "-DTRACE=0"
+ "-DTRACE=0",
+ "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
],
export_include_dirs: localIncludeFiles,
static_libs: staticLibraries,
shared_libs: sharedLibraries,
- header_libs: HeaderLibraries,
+ header_libs: headerLibraries,
name: "libbufferhub",
export_header_lib_headers: [
"libnativebase_headers",
@@ -62,6 +64,7 @@
srcs: ["bufferhub_tests.cpp"],
static_libs: ["libbufferhub"] + staticLibraries,
shared_libs: sharedLibraries,
+ header_libs: headerLibraries,
name: "bufferhub_tests",
}
diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp
index b9a53b0..97341b1 100644
--- a/libs/vr/libbufferhub/buffer_hub_client.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_client.cpp
@@ -2,7 +2,7 @@
#include <log/log.h>
#include <poll.h>
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <sys/epoll.h>
#include <utils/Trace.h>
#include <mutex>
@@ -12,9 +12,8 @@
#include "include/private/dvr/bufferhub_rpc.h"
-using android::pdx::LocalHandle;
using android::pdx::LocalChannelHandle;
-using android::pdx::rpc::WrapBuffer;
+using android::pdx::LocalHandle;
using android::pdx::Status;
namespace android {
@@ -29,7 +28,11 @@
endpoint_path)},
id_(-1) {}
-BufferHubBuffer::~BufferHubBuffer() {}
+BufferHubBuffer::~BufferHubBuffer() {
+ if (metadata_header_ != nullptr) {
+ metadata_buffer_.Unlock();
+ }
+}
Status<LocalChannelHandle> BufferHubBuffer::CreateConsumer() {
Status<LocalChannelHandle> status =
@@ -43,7 +46,7 @@
int BufferHubBuffer::ImportBuffer() {
ATRACE_NAME("BufferHubBuffer::ImportBuffer");
- Status<NativeBufferHandle<LocalHandle>> status =
+ Status<BufferDescription<LocalHandle>> status =
InvokeRemoteMethod<BufferHubRPC::GetBuffer>();
if (!status) {
ALOGE("BufferHubBuffer::ImportBuffer: Failed to get buffer: %s",
@@ -54,24 +57,135 @@
return -EIO;
}
- auto buffer_handle = status.take();
+ auto buffer_desc = status.take();
// Stash the buffer id to replace the value in id_.
- const int new_id = buffer_handle.id();
+ const int new_id = buffer_desc.id();
// Import the buffer.
IonBuffer ion_buffer;
- ALOGD_IF(
- TRACE, "BufferHubBuffer::ImportBuffer: id=%d FdCount=%zu IntCount=%zu",
- buffer_handle.id(), buffer_handle.FdCount(), buffer_handle.IntCount());
+ ALOGD_IF(TRACE, "BufferHubBuffer::ImportBuffer: id=%d.", buffer_desc.id());
- const int ret = buffer_handle.Import(&ion_buffer);
- if (ret < 0)
+ if (const int ret = buffer_desc.ImportBuffer(&ion_buffer))
return ret;
- // If the import succeeds, replace the previous buffer and id.
+ // Import the metadata.
+ IonBuffer metadata_buffer;
+ if (const int ret = buffer_desc.ImportMetadata(&metadata_buffer)) {
+ ALOGE("Failed to import metadata buffer, error=%d", ret);
+ return ret;
+ }
+ size_t metadata_buf_size = metadata_buffer.width();
+ if (metadata_buf_size < BufferHubDefs::kMetadataHeaderSize) {
+ ALOGE("BufferHubBuffer::ImportBuffer: metadata buffer too small: %zu",
+ metadata_buf_size);
+ return -ENOMEM;
+ }
+
+ // If all imports succee, replace the previous buffer and id.
buffer_ = std::move(ion_buffer);
+ metadata_buffer_ = std::move(metadata_buffer);
+ metadata_buf_size_ = metadata_buf_size;
+ user_metadata_size_ = metadata_buf_size_ - BufferHubDefs::kMetadataHeaderSize;
+
+ void* metadata_ptr = nullptr;
+ if (const int ret =
+ metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
+ /*y=*/0, metadata_buf_size_,
+ /*height=*/1, &metadata_ptr)) {
+ ALOGE("BufferHubBuffer::ImportBuffer: Failed to lock metadata.");
+ return ret;
+ }
+
+ // Set up shared fences.
+ shared_acquire_fence_ = buffer_desc.take_acquire_fence();
+ shared_release_fence_ = buffer_desc.take_release_fence();
+ if (!shared_acquire_fence_ || !shared_release_fence_) {
+ ALOGE("BufferHubBuffer::ImportBuffer: Failed to import shared fences.");
+ return -EIO;
+ }
+
+ metadata_header_ =
+ reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
+ if (user_metadata_size_) {
+ user_metadata_ptr_ =
+ reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(metadata_ptr) +
+ BufferHubDefs::kMetadataHeaderSize);
+ } else {
+ user_metadata_ptr_ = nullptr;
+ }
+
id_ = new_id;
+ buffer_state_bit_ = buffer_desc.buffer_state_bit();
+
+ // Note that here the buffer state is mapped from shared memory as an atomic
+ // object. The std::atomic's constructor will not be called so that the
+ // original value stored in the memory region will be preserved.
+ buffer_state_ = &metadata_header_->buffer_state;
+ ALOGD_IF(TRACE,
+ "BufferHubBuffer::ImportBuffer: id=%d, buffer_state=%" PRIx64 ".",
+ id(), buffer_state_->load());
+ fence_state_ = &metadata_header_->fence_state;
+ ALOGD_IF(TRACE,
+ "BufferHubBuffer::ImportBuffer: id=%d, fence_state=%" PRIx64 ".",
+ id(), fence_state_->load());
+
+ return 0;
+}
+
+inline int BufferHubBuffer::CheckMetadata(size_t user_metadata_size) const {
+ if (user_metadata_size && !user_metadata_ptr_) {
+ ALOGE("BufferHubBuffer::CheckMetadata: doesn't support custom metadata.");
+ return -EINVAL;
+ }
+ if (user_metadata_size > user_metadata_size_) {
+ ALOGE("BufferHubBuffer::CheckMetadata: too big: %zu, maximum: %zu.",
+ user_metadata_size, user_metadata_size_);
+ return -E2BIG;
+ }
+ return 0;
+}
+
+int BufferHubBuffer::UpdateSharedFence(const LocalHandle& new_fence,
+ const LocalHandle& shared_fence) {
+ if (pending_fence_fd_.Get() != new_fence.Get()) {
+ // First, replace the old fd if there was already one. Skipping if the new
+ // one is the same as the old.
+ if (pending_fence_fd_.IsValid()) {
+ const int ret = epoll_ctl(shared_fence.Get(), EPOLL_CTL_DEL,
+ pending_fence_fd_.Get(), nullptr);
+ ALOGW_IF(ret,
+ "BufferHubBuffer::UpdateSharedFence: failed to remove old fence "
+ "fd from epoll set, error: %s.",
+ strerror(errno));
+ }
+
+ if (new_fence.IsValid()) {
+ // If ready fence is valid, we put that into the epoll set.
+ epoll_event event;
+ event.events = EPOLLIN;
+ event.data.u64 = buffer_state_bit();
+ pending_fence_fd_ = new_fence.Duplicate();
+ if (epoll_ctl(shared_fence.Get(), EPOLL_CTL_ADD, pending_fence_fd_.Get(),
+ &event) < 0) {
+ const int error = errno;
+ ALOGE(
+ "BufferHubBuffer::UpdateSharedFence: failed to add new fence fd "
+ "into epoll set, error: %s.",
+ strerror(error));
+ return -error;
+ }
+ // Set bit in fence state to indicate that there is a fence from this
+ // producer or consumer.
+ fence_state_->fetch_or(buffer_state_bit());
+ } else {
+ // Unset bit in fence state to indicate that there is no fence, so that
+ // when consumer to acquire or producer to acquire, it knows no need to
+ // check fence for this buffer.
+ fence_state_->fetch_and(~buffer_state_bit());
+ }
+ }
+
return 0;
}
@@ -131,31 +245,144 @@
: LocalChannelHandle{nullptr, -status.error()});
}
+int BufferConsumer::LocalAcquire(DvrNativeBufferMetadata* out_meta,
+ LocalHandle* out_fence) {
+ if (!out_meta)
+ return -EINVAL;
+
+ // Only check producer bit and this consumer buffer's particular consumer bit.
+ // The buffer is can be acquired iff: 1) producer bit is set; 2) consumer bit
+ // is not set.
+ uint64_t buffer_state = buffer_state_->load();
+ if (!BufferHubDefs::IsBufferPosted(buffer_state, buffer_state_bit())) {
+ ALOGE("BufferConsumer::LocalAcquire: not posted, id=%d state=%" PRIx64
+ " buffer_state_bit=%" PRIx64 ".",
+ id(), buffer_state, buffer_state_bit());
+ return -EBUSY;
+ }
+
+ // Copy the canonical metadata.
+ void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata);
+ memcpy(out_meta, metadata_ptr, sizeof(DvrNativeBufferMetadata));
+ // Fill in the user_metadata_ptr in address space of the local process.
+ if (out_meta->user_metadata_size) {
+ out_meta->user_metadata_ptr =
+ reinterpret_cast<uint64_t>(user_metadata_ptr_);
+ } else {
+ out_meta->user_metadata_ptr = 0;
+ }
+
+ uint64_t fence_state = fence_state_->load();
+ // If there is an acquire fence from producer, we need to return it.
+ if (fence_state & BufferHubDefs::kProducerStateBit) {
+ *out_fence = shared_acquire_fence_.Duplicate();
+ }
+
+ // Set the consumer bit unique to this consumer.
+ BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL, buffer_state_bit());
+ return 0;
+}
+
int BufferConsumer::Acquire(LocalHandle* ready_fence) {
return Acquire(ready_fence, nullptr, 0);
}
int BufferConsumer::Acquire(LocalHandle* ready_fence, void* meta,
- size_t meta_size_bytes) {
+ size_t user_metadata_size) {
ATRACE_NAME("BufferConsumer::Acquire");
- LocalFence fence;
- auto return_value =
- std::make_pair(std::ref(fence), WrapBuffer(meta, meta_size_bytes));
- auto status = InvokeRemoteMethodInPlace<BufferHubRPC::ConsumerAcquire>(
- &return_value, meta_size_bytes);
- if (status && ready_fence)
- *ready_fence = fence.take();
- return status ? 0 : -status.error();
+
+ if (const int error = CheckMetadata(user_metadata_size))
+ return error;
+
+ DvrNativeBufferMetadata canonical_meta;
+ if (const int error = LocalAcquire(&canonical_meta, ready_fence))
+ return error;
+
+ if (meta && user_metadata_size) {
+ void* metadata_src =
+ reinterpret_cast<void*>(canonical_meta.user_metadata_ptr);
+ if (metadata_src) {
+ memcpy(meta, metadata_src, user_metadata_size);
+ } else {
+ ALOGW("BufferConsumer::Acquire: no user-defined metadata.");
+ }
+ }
+
+ auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerAcquire>();
+ if (!status)
+ return -status.error();
+ return 0;
+}
+
+int BufferConsumer::AcquireAsync(DvrNativeBufferMetadata* out_meta,
+ LocalHandle* out_fence) {
+ ATRACE_NAME("BufferConsumer::AcquireAsync");
+
+ if (const int error = LocalAcquire(out_meta, out_fence))
+ return error;
+
+ auto status = SendImpulse(BufferHubRPC::ConsumerAcquire::Opcode);
+ if (!status)
+ return -status.error();
+ return 0;
+}
+
+int BufferConsumer::LocalRelease(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& release_fence) {
+ if (const int error = CheckMetadata(meta->user_metadata_size))
+ return error;
+
+ // Check invalid state transition.
+ uint64_t buffer_state = buffer_state_->load();
+ if (!BufferHubDefs::IsBufferAcquired(buffer_state)) {
+ ALOGE("BufferConsumer::LocalRelease: not acquired id=%d state=%" PRIx64 ".",
+ id(), buffer_state);
+ return -EBUSY;
+ }
+
+ // On release, only the user requested metadata is copied back into the shared
+ // memory for metadata. Since there are multiple consumers, it doesn't make
+ // sense to send the canonical metadata back to the producer. However, one of
+ // the consumer can still choose to write up to user_metadata_size bytes of
+ // data into user_metadata_ptr.
+ if (meta->user_metadata_ptr && meta->user_metadata_size) {
+ void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr);
+ memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size);
+ }
+
+ // Send out the release fence through the shared epoll fd. Note that during
+ // releasing the producer is not expected to be polling on the fence.
+ if (const int error = UpdateSharedFence(release_fence, shared_release_fence_))
+ return error;
+
+ // For release operation, the client don't need to change the state as it's
+ // bufferhubd's job to flip the produer bit once all consumers are released.
+ return 0;
}
int BufferConsumer::Release(const LocalHandle& release_fence) {
ATRACE_NAME("BufferConsumer::Release");
+
+ DvrNativeBufferMetadata meta;
+ if (const int error = LocalRelease(&meta, release_fence))
+ return error;
+
return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ConsumerRelease>(
BorrowedFence(release_fence.Borrow())));
}
int BufferConsumer::ReleaseAsync() {
+ DvrNativeBufferMetadata meta;
+ return ReleaseAsync(&meta, LocalHandle());
+}
+
+int BufferConsumer::ReleaseAsync(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& release_fence) {
ATRACE_NAME("BufferConsumer::ReleaseAsync");
+
+ if (const int error = LocalRelease(meta, release_fence))
+ return error;
+
return ReturnStatusOrError(
SendImpulse(BufferHubRPC::ConsumerRelease::Opcode));
}
@@ -168,24 +395,25 @@
}
BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format,
- uint32_t usage, size_t metadata_size)
- : BufferProducer(width, height, format, usage, usage, metadata_size) {}
+ uint32_t usage, size_t user_metadata_size)
+ : BufferProducer(width, height, format, usage, usage, user_metadata_size) {}
BufferProducer::BufferProducer(uint32_t width, uint32_t height, uint32_t format,
uint64_t producer_usage, uint64_t consumer_usage,
- size_t metadata_size)
+ size_t user_metadata_size)
: BASE(BufferHubRPC::kClientPath) {
ATRACE_NAME("BufferProducer::BufferProducer");
ALOGD_IF(TRACE,
"BufferProducer::BufferProducer: fd=%d width=%u height=%u format=%u "
"producer_usage=%" PRIx64 " consumer_usage=%" PRIx64
- " metadata_size=%zu",
+ " user_metadata_size=%zu",
event_fd(), width, height, format, producer_usage, consumer_usage,
- metadata_size);
+ user_metadata_size);
// (b/37881101) Deprecate producer/consumer usage
auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
- width, height, format, (producer_usage | consumer_usage), metadata_size);
+ width, height, format, (producer_usage | consumer_usage),
+ user_metadata_size);
if (!status) {
ALOGE(
"BufferProducer::BufferProducer: Failed to create producer buffer: %s",
@@ -206,27 +434,28 @@
BufferProducer::BufferProducer(const std::string& name, int user_id,
int group_id, uint32_t width, uint32_t height,
uint32_t format, uint32_t usage,
- size_t meta_size_bytes)
+ size_t user_metadata_size)
: BufferProducer(name, user_id, group_id, width, height, format, usage,
- usage, meta_size_bytes) {}
+ usage, user_metadata_size) {}
BufferProducer::BufferProducer(const std::string& name, int user_id,
int group_id, uint32_t width, uint32_t height,
uint32_t format, uint64_t producer_usage,
- uint64_t consumer_usage, size_t meta_size_bytes)
+ uint64_t consumer_usage,
+ size_t user_metadata_size)
: BASE(BufferHubRPC::kClientPath) {
ATRACE_NAME("BufferProducer::BufferProducer");
ALOGD_IF(TRACE,
"BufferProducer::BufferProducer: fd=%d name=%s user_id=%d "
"group_id=%d width=%u height=%u format=%u producer_usage=%" PRIx64
- " consumer_usage=%" PRIx64 " meta_size_bytes=%zu",
+ " consumer_usage=%" PRIx64 " user_metadata_size=%zu",
event_fd(), name.c_str(), user_id, group_id, width, height, format,
- producer_usage, consumer_usage, meta_size_bytes);
+ producer_usage, consumer_usage, user_metadata_size);
// (b/37881101) Deprecate producer/consumer usage
auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>(
name, user_id, group_id, width, height, format,
- (producer_usage | consumer_usage), meta_size_bytes);
+ (producer_usage | consumer_usage), user_metadata_size);
if (!status) {
ALOGE(
"BufferProducer::BufferProducer: Failed to create/get persistent "
@@ -260,12 +489,12 @@
const int width = static_cast<int>(size);
const int height = 1;
const int format = HAL_PIXEL_FORMAT_BLOB;
- const size_t meta_size_bytes = 0;
+ const size_t user_metadata_size = 0;
// (b/37881101) Deprecate producer/consumer usage
auto status = InvokeRemoteMethod<BufferHubRPC::CreateBuffer>(
width, height, format, (producer_usage | consumer_usage),
- meta_size_bytes);
+ user_metadata_size);
if (!status) {
ALOGE("BufferProducer::BufferProducer: Failed to create blob: %s",
status.GetErrorMessage().c_str());
@@ -299,12 +528,12 @@
const int width = static_cast<int>(size);
const int height = 1;
const int format = HAL_PIXEL_FORMAT_BLOB;
- const size_t meta_size_bytes = 0;
+ const size_t user_metadata_size = 0;
// (b/37881101) Deprecate producer/consumer usage
auto status = InvokeRemoteMethod<BufferHubRPC::CreatePersistentBuffer>(
name, user_id, group_id, width, height, format,
- (producer_usage | consumer_usage), meta_size_bytes);
+ (producer_usage | consumer_usage), user_metadata_size);
if (!status) {
ALOGE(
"BufferProducer::BufferProducer: Failed to create persistent "
@@ -360,28 +589,141 @@
}
}
+int BufferProducer::LocalPost(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& ready_fence) {
+ if (const int error = CheckMetadata(meta->user_metadata_size))
+ return error;
+
+ // Check invalid state transition.
+ uint64_t buffer_state = buffer_state_->load();
+ if (!BufferHubDefs::IsBufferGained(buffer_state)) {
+ ALOGE("BufferProducer::LocalPost: not gained, id=%d state=%" PRIx64 ".",
+ id(), buffer_state);
+ return -EBUSY;
+ }
+
+ // Copy the canonical metadata.
+ void* metadata_ptr = reinterpret_cast<void*>(&metadata_header_->metadata);
+ memcpy(metadata_ptr, meta, sizeof(DvrNativeBufferMetadata));
+ // Copy extra user requested metadata.
+ if (meta->user_metadata_ptr && meta->user_metadata_size) {
+ void* metadata_src = reinterpret_cast<void*>(meta->user_metadata_ptr);
+ memcpy(user_metadata_ptr_, metadata_src, meta->user_metadata_size);
+ }
+
+ // Send out the acquire fence through the shared epoll fd. Note that during
+ // posting no consumer is not expected to be polling on the fence.
+ if (const int error = UpdateSharedFence(ready_fence, shared_acquire_fence_))
+ return error;
+
+ // Set the producer bit atomically to transit into posted state.
+ BufferHubDefs::ModifyBufferState(buffer_state_, 0ULL,
+ BufferHubDefs::kProducerStateBit);
+ return 0;
+}
+
int BufferProducer::Post(const LocalHandle& ready_fence, const void* meta,
- size_t meta_size_bytes) {
+ size_t user_metadata_size) {
ATRACE_NAME("BufferProducer::Post");
+
+ // Populate cononical metadata for posting.
+ DvrNativeBufferMetadata canonical_meta;
+ canonical_meta.user_metadata_ptr = reinterpret_cast<uint64_t>(meta);
+ canonical_meta.user_metadata_size = user_metadata_size;
+
+ if (const int error = LocalPost(&canonical_meta, ready_fence))
+ return error;
+
return ReturnStatusOrError(InvokeRemoteMethod<BufferHubRPC::ProducerPost>(
- BorrowedFence(ready_fence.Borrow()), WrapBuffer(meta, meta_size_bytes)));
+ BorrowedFence(ready_fence.Borrow())));
+}
+
+int BufferProducer::PostAsync(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& ready_fence) {
+ ATRACE_NAME("BufferProducer::PostAsync");
+
+ if (const int error = LocalPost(meta, ready_fence))
+ return error;
+
+ return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerPost::Opcode));
+}
+
+int BufferProducer::LocalGain(DvrNativeBufferMetadata* out_meta,
+ LocalHandle* out_fence) {
+ uint64_t buffer_state = buffer_state_->load();
+ ALOGD_IF(TRACE, "BufferProducer::LocalGain: buffer=%d, state=%" PRIx64 ".",
+ id(), buffer_state);
+
+ if (!out_meta)
+ return -EINVAL;
+
+ if (!BufferHubDefs::IsBufferReleased(buffer_state)) {
+ if (BufferHubDefs::IsBufferGained(buffer_state)) {
+ // We don't want to log error when gaining a newly allocated
+ // buffer.
+ ALOGI("BufferProducer::LocalGain: already gained id=%d.", id());
+ return -EALREADY;
+ }
+ ALOGE("BufferProducer::LocalGain: not released id=%d state=%" PRIx64 ".",
+ id(), buffer_state);
+ return -EBUSY;
+ }
+
+ // Canonical metadata is undefined on Gain. Except for user_metadata and
+ // release_fence_mask. Fill in the user_metadata_ptr in address space of the
+ // local process.
+ if (metadata_header_->metadata.user_metadata_size && user_metadata_ptr_) {
+ out_meta->user_metadata_size =
+ metadata_header_->metadata.user_metadata_size;
+ out_meta->user_metadata_ptr =
+ reinterpret_cast<uint64_t>(user_metadata_ptr_);
+ } else {
+ out_meta->user_metadata_size = 0;
+ out_meta->user_metadata_ptr = 0;
+ }
+
+ uint64_t fence_state = fence_state_->load();
+ // If there is an release fence from consumer, we need to return it.
+ if (fence_state & BufferHubDefs::kConsumerStateMask) {
+ *out_fence = shared_release_fence_.Duplicate();
+ out_meta->release_fence_mask =
+ fence_state & BufferHubDefs::kConsumerStateMask;
+ }
+
+ // Clear out all bits and the buffer is now back to gained state.
+ buffer_state_->store(0ULL);
+ return 0;
}
int BufferProducer::Gain(LocalHandle* release_fence) {
ATRACE_NAME("BufferProducer::Gain");
+
+ DvrNativeBufferMetadata meta;
+ if (const int error = LocalGain(&meta, release_fence))
+ return error;
+
auto status = InvokeRemoteMethod<BufferHubRPC::ProducerGain>();
if (!status)
return -status.error();
- if (release_fence)
- *release_fence = status.take().take();
return 0;
}
-int BufferProducer::GainAsync() {
+int BufferProducer::GainAsync(DvrNativeBufferMetadata* out_meta,
+ LocalHandle* release_fence) {
ATRACE_NAME("BufferProducer::GainAsync");
+
+ if (const int error = LocalGain(out_meta, release_fence))
+ return error;
+
return ReturnStatusOrError(SendImpulse(BufferHubRPC::ProducerGain::Opcode));
}
+int BufferProducer::GainAsync() {
+ DvrNativeBufferMetadata meta;
+ LocalHandle fence;
+ return GainAsync(&meta, &fence);
+}
+
std::unique_ptr<BufferProducer> BufferProducer::Import(
LocalChannelHandle channel) {
ALOGD_IF(TRACE, "BufferProducer::Import: channel=%d", channel.value());
diff --git a/libs/vr/libbufferhub/bufferhub_tests.cpp b/libs/vr/libbufferhub/bufferhub_tests.cpp
index 1daa5d6..c4b9a8c 100644
--- a/libs/vr/libbufferhub/bufferhub_tests.cpp
+++ b/libs/vr/libbufferhub/bufferhub_tests.cpp
@@ -1,5 +1,9 @@
#include <gtest/gtest.h>
+#include <poll.h>
#include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/bufferhub_rpc.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
#include <mutex>
#include <thread>
@@ -13,8 +17,10 @@
return result; \
})()
-using android::dvr::BufferProducer;
using android::dvr::BufferConsumer;
+using android::dvr::BufferHubDefs::kConsumerStateMask;
+using android::dvr::BufferHubDefs::kProducerStateBit;
+using android::dvr::BufferProducer;
using android::pdx::LocalHandle;
const int kWidth = 640;
@@ -37,29 +43,149 @@
BufferConsumer::Import(c->CreateConsumer());
ASSERT_TRUE(c2.get() != nullptr);
+ // Producer state mask is unique, i.e. 1.
+ EXPECT_EQ(p->buffer_state_bit(), kProducerStateBit);
+ // Consumer state mask cannot have producer bit on.
+ EXPECT_EQ(c->buffer_state_bit() & kProducerStateBit, 0);
+ // Consumer state mask must be a single, i.e. power of 2.
+ EXPECT_NE(c->buffer_state_bit(), 0);
+ EXPECT_EQ(c->buffer_state_bit() & (c->buffer_state_bit() - 1), 0);
+ // Consumer state mask cannot have producer bit on.
+ EXPECT_EQ(c2->buffer_state_bit() & kProducerStateBit, 0);
+ // Consumer state mask must be a single, i.e. power of 2.
+ EXPECT_NE(c2->buffer_state_bit(), 0);
+ EXPECT_EQ(c2->buffer_state_bit() & (c2->buffer_state_bit() - 1), 0);
+ // Each consumer should have unique bit.
+ EXPECT_EQ(c->buffer_state_bit() & c2->buffer_state_bit(), 0);
+
+ // Initial state: producer not available, consumers not available.
+ EXPECT_EQ(0, RETRY_EINTR(p->Poll(100)));
+ EXPECT_EQ(0, RETRY_EINTR(c->Poll(100)));
+ EXPECT_EQ(0, RETRY_EINTR(c2->Poll(100)));
+
EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
- // Both consumers should be triggered.
- EXPECT_GE(0, RETRY_EINTR(p->Poll(0)));
- EXPECT_LT(0, RETRY_EINTR(c->Poll(10)));
- EXPECT_LT(0, RETRY_EINTR(c2->Poll(10)));
+
+ // New state: producer not available, consumers available.
+ EXPECT_EQ(0, RETRY_EINTR(p->Poll(100)));
+ EXPECT_EQ(1, RETRY_EINTR(c->Poll(100)));
+ EXPECT_EQ(1, RETRY_EINTR(c2->Poll(100)));
uint64_t context;
LocalHandle fence;
- EXPECT_LE(0, c->Acquire(&fence, &context));
+ EXPECT_EQ(0, c->Acquire(&fence, &context));
EXPECT_EQ(kContext, context);
- EXPECT_GE(0, RETRY_EINTR(c->Poll(0)));
+ EXPECT_EQ(0, RETRY_EINTR(c->Poll(100)));
+ EXPECT_EQ(1, RETRY_EINTR(c2->Poll(100)));
- EXPECT_LE(0, c2->Acquire(&fence, &context));
+ EXPECT_EQ(0, c2->Acquire(&fence, &context));
EXPECT_EQ(kContext, context);
- EXPECT_GE(0, RETRY_EINTR(c2->Poll(0)));
+ EXPECT_EQ(0, RETRY_EINTR(c2->Poll(100)));
+ EXPECT_EQ(0, RETRY_EINTR(c->Poll(100)));
EXPECT_EQ(0, c->Release(LocalHandle()));
- EXPECT_GE(0, RETRY_EINTR(p->Poll(0)));
+ EXPECT_EQ(0, RETRY_EINTR(p->Poll(100)));
EXPECT_EQ(0, c2->Discard());
- EXPECT_LE(0, RETRY_EINTR(p->Poll(0)));
+ EXPECT_EQ(1, RETRY_EINTR(p->Poll(100)));
EXPECT_EQ(0, p->Gain(&fence));
- EXPECT_GE(0, RETRY_EINTR(p->Poll(0)));
+ EXPECT_EQ(0, RETRY_EINTR(p->Poll(100)));
+ EXPECT_EQ(0, RETRY_EINTR(c->Poll(100)));
+ EXPECT_EQ(0, RETRY_EINTR(c2->Poll(100)));
+}
+
+TEST_F(LibBufferHubTest, TestEpoll) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c.get() != nullptr);
+
+ LocalHandle epoll_fd{epoll_create1(EPOLL_CLOEXEC)};
+ ASSERT_TRUE(epoll_fd.IsValid());
+
+ epoll_event event;
+ std::array<epoll_event, 64> events;
+
+ auto event_sources = p->GetEventSources();
+ ASSERT_LT(event_sources.size(), events.size());
+
+ for (const auto& event_source : event_sources) {
+ event = {.events = event_source.event_mask | EPOLLET,
+ .data = {.fd = p->event_fd()}};
+ ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd,
+ &event));
+ }
+
+ event_sources = c->GetEventSources();
+ ASSERT_LT(event_sources.size(), events.size());
+
+ for (const auto& event_source : event_sources) {
+ event = {.events = event_source.event_mask | EPOLLET,
+ .data = {.fd = c->event_fd()}};
+ ASSERT_EQ(0, epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_source.event_fd,
+ &event));
+ }
+
+ // No events should be signaled initially.
+ ASSERT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 0));
+
+ // Post the producer and check for consumer signal.
+ EXPECT_EQ(0, p->Post({}, kContext));
+ ASSERT_EQ(1, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100));
+ ASSERT_TRUE(events[0].events & EPOLLIN);
+ ASSERT_EQ(c->event_fd(), events[0].data.fd);
+
+ // Save the event bits to translate later.
+ event = events[0];
+
+ // Check for events again. Edge-triggered mode should prevent any.
+ EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100));
+ EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100));
+ EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100));
+ EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100));
+
+ // Translate the events.
+ auto event_status = c->GetEventMask(event.events);
+ ASSERT_TRUE(event_status);
+ ASSERT_TRUE(event_status.get() & EPOLLIN);
+
+ // Check for events again. Edge-triggered mode should prevent any.
+ EXPECT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 100));
+}
+
+TEST_F(LibBufferHubTest, TestStateMask) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+
+ // It's ok to create up to 63 consumer buffers.
+ uint64_t buffer_state_bits = p->buffer_state_bit();
+ std::array<std::unique_ptr<BufferConsumer>, 63> cs;
+ for (size_t i = 0; i < 63; i++) {
+ cs[i] = BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(cs[i].get() != nullptr);
+ // Expect all buffers have unique state mask.
+ EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0);
+ buffer_state_bits |= cs[i]->buffer_state_bit();
+ }
+ EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask);
+
+ // The 64th creation will fail with out-of-memory error.
+ auto state = p->CreateConsumer();
+ EXPECT_EQ(state.error(), E2BIG);
+
+ // Release any consumer should allow us to re-create.
+ for (size_t i = 0; i < 63; i++) {
+ buffer_state_bits &= ~cs[i]->buffer_state_bit();
+ cs[i] = nullptr;
+ cs[i] = BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(cs[i].get() != nullptr);
+ // The released state mask will be reused.
+ EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0);
+ buffer_state_bits |= cs[i]->buffer_state_bit();
+ EXPECT_EQ(buffer_state_bits, kProducerStateBit | kConsumerStateMask);
+ }
}
TEST_F(LibBufferHubTest, TestStateTransitions) {
@@ -98,6 +224,7 @@
// Release in acquired state should succeed.
EXPECT_EQ(0, c->Release(LocalHandle()));
+ EXPECT_LT(0, RETRY_EINTR(p->Poll(10)));
// Release, acquire, and post in released state should fail.
EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
@@ -144,6 +271,11 @@
int64_t field1;
int64_t field2;
};
+ struct OverSizedMetadata {
+ int64_t field1;
+ int64_t field2;
+ int64_t field3;
+ };
std::unique_ptr<BufferProducer> p = BufferProducer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
ASSERT_TRUE(p.get() != nullptr);
@@ -151,9 +283,16 @@
BufferConsumer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
- int64_t sequence = 3;
- EXPECT_NE(0, p->Post(LocalHandle(), sequence));
+ // It is illegal to post metadata larger than originally requested during
+ // buffer allocation.
+ OverSizedMetadata evil_meta = {};
+ EXPECT_NE(0, p->Post(LocalHandle(), evil_meta));
EXPECT_GE(0, RETRY_EINTR(c->Poll(10)));
+
+ // It is ok to post metadata smaller than originally requested during
+ // buffer allocation.
+ int64_t sequence = 42;
+ EXPECT_EQ(0, p->Post(LocalHandle(), sequence));
}
TEST_F(LibBufferHubTest, TestAcquireWithWrongMetaSize) {
@@ -161,6 +300,11 @@
int64_t field1;
int64_t field2;
};
+ struct OverSizedMetadata {
+ int64_t field1;
+ int64_t field2;
+ int64_t field3;
+ };
std::unique_ptr<BufferProducer> p = BufferProducer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
ASSERT_TRUE(p.get() != nullptr);
@@ -173,7 +317,16 @@
LocalHandle fence;
int64_t sequence;
- EXPECT_NE(0, c->Acquire(&fence, &sequence));
+ OverSizedMetadata e;
+
+ // It is illegal to acquire metadata larger than originally requested during
+ // buffer allocation.
+ EXPECT_NE(0, c->Acquire(&fence, &e));
+
+ // It is ok to acquire metadata smaller than originally requested during
+ // buffer allocation.
+ EXPECT_EQ(0, c->Acquire(&fence, &sequence));
+ EXPECT_EQ(m.field1, sequence);
}
TEST_F(LibBufferHubTest, TestAcquireWithNoMeta) {
@@ -266,12 +419,140 @@
LocalHandle fence;
auto c = BufferConsumer::Import(p->CreateConsumer());
ASSERT_NE(nullptr, c);
- EXPECT_NE(-EPIPE, c->Acquire(&fence));
+ EXPECT_EQ(0, p->Post<void>(LocalHandle()));
+ EXPECT_EQ(0, c->Acquire(&fence));
+ EXPECT_EQ(0, c->Release(LocalHandle()));
+ EXPECT_LT(0, RETRY_EINTR(p->Poll(10)));
// Test that removing persistence and closing the producer orphans the
// consumer.
+ EXPECT_EQ(0, p->Gain(&fence));
+ EXPECT_EQ(0, p->Post<void>(LocalHandle()));
EXPECT_EQ(0, p->RemovePersistence());
p = nullptr;
+ // Orphaned consumer can acquire the posted buffer one more time in
+ // asynchronous manner. But synchronous call will fail.
+ DvrNativeBufferMetadata meta;
+ EXPECT_EQ(0, c->AcquireAsync(&meta, &fence));
EXPECT_EQ(-EPIPE, c->Release(LocalHandle()));
}
+
+namespace {
+
+int PollFd(int fd, int timeout_ms) {
+ pollfd p = {fd, POLLIN, 0};
+ return poll(&p, 1, timeout_ms);
+}
+
+} // namespace
+
+TEST_F(LibBufferHubTest, TestAcquireFence) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, /*metadata_size=*/0);
+ ASSERT_TRUE(p.get() != nullptr);
+ std::unique_ptr<BufferConsumer> c =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c.get() != nullptr);
+
+ DvrNativeBufferMetadata meta;
+ LocalHandle f1(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
+
+ // Post with unsignaled fence.
+ EXPECT_EQ(0, p->PostAsync(&meta, f1));
+
+ // Should acquire a valid fence.
+ LocalHandle f2;
+ EXPECT_LT(0, RETRY_EINTR(c->Poll(10)));
+ EXPECT_EQ(0, c->AcquireAsync(&meta, &f2));
+ EXPECT_TRUE(f2.IsValid());
+ // The original fence and acquired fence should have different fd number.
+ EXPECT_NE(f1.Get(), f2.Get());
+ EXPECT_GE(0, PollFd(f2.Get(), 0));
+
+ // Signal the original fence will trigger the new fence.
+ eventfd_write(f1.Get(), 1);
+ // Now the original FD has been signaled.
+ EXPECT_LT(0, PollFd(f2.Get(), 10));
+
+ // Release the consumer with an invalid fence.
+ EXPECT_EQ(0, c->ReleaseAsync(&meta, LocalHandle()));
+
+ // Should gain an invalid fence.
+ LocalHandle f3;
+ EXPECT_LT(0, RETRY_EINTR(p->Poll(10)));
+ EXPECT_EQ(0, p->GainAsync(&meta, &f3));
+ EXPECT_FALSE(f3.IsValid());
+
+ // Post with a signaled fence.
+ EXPECT_EQ(0, p->PostAsync(&meta, f1));
+
+ // Should acquire a valid fence and it's already signalled.
+ LocalHandle f4;
+ EXPECT_LT(0, RETRY_EINTR(c->Poll(10)));
+ EXPECT_EQ(0, c->AcquireAsync(&meta, &f4));
+ EXPECT_TRUE(f4.IsValid());
+ EXPECT_LT(0, PollFd(f4.Get(), 10));
+
+ // Release with an unsignalled fence and signal it immediately after release
+ // without producer gainning.
+ LocalHandle f5(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
+ EXPECT_EQ(0, c->ReleaseAsync(&meta, f5));
+ eventfd_write(f5.Get(), 1);
+
+ // Should gain a valid fence, which is already signaled.
+ LocalHandle f6;
+ EXPECT_LT(0, RETRY_EINTR(p->Poll(10)));
+ EXPECT_EQ(0, p->GainAsync(&meta, &f6));
+ EXPECT_TRUE(f6.IsValid());
+ EXPECT_LT(0, PollFd(f6.Get(), 10));
+}
+
+TEST_F(LibBufferHubTest, TestOrphanedAcquire) {
+ std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
+ ASSERT_TRUE(p.get() != nullptr);
+ std::unique_ptr<BufferConsumer> c1 =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c1.get() != nullptr);
+ const uint64_t consumer_state_bit1 = c1->buffer_state_bit();
+
+ DvrNativeBufferMetadata meta;
+ EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle()));
+
+ LocalHandle fence;
+ EXPECT_LT(0, RETRY_EINTR(c1->Poll(10)));
+ EXPECT_LE(0, c1->AcquireAsync(&meta, &fence));
+ // Destroy the consumer now will make it orphaned and the buffer is still
+ // acquired.
+ c1 = nullptr;
+ EXPECT_GE(0, RETRY_EINTR(p->Poll(10)));
+
+ std::unique_ptr<BufferConsumer> c2 =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c2.get() != nullptr);
+ const uint64_t consumer_state_bit2 = c2->buffer_state_bit();
+ EXPECT_NE(consumer_state_bit1, consumer_state_bit2);
+
+ // The new consumer is available for acquire.
+ EXPECT_LT(0, RETRY_EINTR(c2->Poll(10)));
+ EXPECT_LE(0, c2->AcquireAsync(&meta, &fence));
+ // Releasing the consumer makes the buffer gainable.
+ EXPECT_EQ(0, c2->ReleaseAsync(&meta, LocalHandle()));
+
+ // The buffer is now available for the producer to gain.
+ EXPECT_LT(0, RETRY_EINTR(p->Poll(10)));
+
+ // But if another consumer is created in released state.
+ std::unique_ptr<BufferConsumer> c3 =
+ BufferConsumer::Import(p->CreateConsumer());
+ ASSERT_TRUE(c3.get() != nullptr);
+ const uint64_t consumer_state_bit3 = c3->buffer_state_bit();
+ EXPECT_NE(consumer_state_bit2, consumer_state_bit3);
+ // The consumer buffer is not acquirable.
+ EXPECT_GE(0, RETRY_EINTR(c3->Poll(10)));
+ EXPECT_EQ(-EBUSY, c3->AcquireAsync(&meta, &fence));
+
+ // Producer should be able to gain no matter what.
+ EXPECT_EQ(0, p->GainAsync(&meta, &fence));
+}
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
index be20e72..1186f93 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
@@ -11,6 +11,8 @@
#include <private/dvr/ion_buffer.h>
+#include "bufferhub_rpc.h"
+
namespace android {
namespace dvr {
@@ -75,6 +77,14 @@
}
}
+ std::vector<pdx::ClientChannel::EventSource> GetEventSources() const {
+ if (auto* client_channel = GetChannel()) {
+ return client_channel->GetEventSources();
+ } else {
+ return {};
+ }
+ }
+
native_handle_t* native_handle() const {
return const_cast<native_handle_t*>(buffer_.handle());
}
@@ -84,6 +94,10 @@
int id() const { return id_; }
+ // A state mask which is unique to a buffer hub client among all its siblings
+ // sharing the same concrete graphic buffer.
+ uint64_t buffer_state_bit() const { return buffer_state_bit_; }
+
// The following methods return settings of the first buffer. Currently,
// it is only possible to create multi-buffer BufferHubBuffers with the same
// settings.
@@ -98,6 +112,9 @@
uint64_t producer_usage() const { return buffer_.usage(); }
uint64_t consumer_usage() const { return buffer_.usage(); }
+ uint64_t GetQueueIndex() const { return metadata_header_->queue_index; }
+ void SetQueueIndex(uint64_t index) { metadata_header_->queue_index = index; }
+
protected:
explicit BufferHubBuffer(LocalChannelHandle channel);
explicit BufferHubBuffer(const std::string& endpoint_path);
@@ -106,6 +123,31 @@
// Initialization helper.
int ImportBuffer();
+ // Check invalid metadata operation. Returns 0 if requested metadata is valid.
+ int CheckMetadata(size_t user_metadata_size) const;
+
+ // Send out the new fence by updating the shared fence (shared_release_fence
+ // for producer and shared_acquire_fence for consumer). Note that during this
+ // should only be used in LocalPost() or LocalRelease, and the shared fence
+ // shouldn't be poll'ed by the other end.
+ int UpdateSharedFence(const LocalHandle& new_fence,
+ const LocalHandle& shared_fence);
+
+ // IonBuffer that is shared between bufferhubd, producer, and consumers.
+ size_t metadata_buf_size_{0};
+ size_t user_metadata_size_{0};
+ BufferHubDefs::MetadataHeader* metadata_header_{nullptr};
+ void* user_metadata_ptr_{nullptr};
+ std::atomic<uint64_t>* buffer_state_{nullptr};
+ std::atomic<uint64_t>* fence_state_{nullptr};
+
+ LocalHandle shared_acquire_fence_;
+ LocalHandle shared_release_fence_;
+
+ // A local fence fd that holds the ownership of the fence fd on Post (for
+ // producer) and Release (for consumer).
+ LocalHandle pending_fence_fd_;
+
private:
BufferHubBuffer(const BufferHubBuffer&) = delete;
void operator=(const BufferHubBuffer&) = delete;
@@ -114,8 +156,9 @@
// for logging and debugging purposes only and should not be used for lookup
// or any other functional purpose as a security precaution.
int id_;
-
+ uint64_t buffer_state_bit_{0ULL};
IonBuffer buffer_;
+ IonBuffer metadata_buffer_;
};
// This represents a writable buffer. Calling Post notifies all clients and
@@ -136,12 +179,17 @@
static std::unique_ptr<BufferProducer> Import(
Status<LocalChannelHandle> status);
+ // Asynchronously posts a buffer. The fence and metadata are passed to
+ // consumer via shared fd and shared memory.
+ int PostAsync(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& ready_fence);
+
// Post this buffer, passing |ready_fence| to the consumers. The bytes in
// |meta| are passed unaltered to the consumers. The producer must not modify
// the buffer until it is re-gained.
// This returns zero or a negative unix error code.
int Post(const LocalHandle& ready_fence, const void* meta,
- size_t meta_size_bytes);
+ size_t user_metadata_size);
template <typename Meta,
typename = typename std::enable_if<std::is_void<Meta>::value>::type>
@@ -160,16 +208,15 @@
// is in the released state.
// This returns zero or a negative unix error code.
int Gain(LocalHandle* release_fence);
+ int GainAsync();
// Asynchronously marks a released buffer as gained. This method is similar to
// the synchronous version above, except that it does not wait for BufferHub
- // to acknowledge success or failure, nor does it transfer a release fence to
- // the client. This version may be used in situations where a release fence is
- // not needed. Because of the asynchronous nature of the underlying message,
- // no error is returned if this method is called when the buffer is in an
- // incorrect state. Returns zero if sending the message succeeded, or a
- // negative errno code otherwise.
- int GainAsync();
+ // to acknowledge success or failure. Because of the asynchronous nature of
+ // the underlying message, no error is returned if this method is called when
+ // the buffer is in an incorrect state. Returns zero if sending the message
+ // succeeded, or a negative errno code if local error check fails.
+ int GainAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
// Attaches the producer to |name| so that it becomes a persistent buffer that
// may be retrieved by name at a later time. This may be used in cases where a
@@ -216,7 +263,7 @@
BufferProducer(const std::string& name, int user_id, int group_id,
uint32_t width, uint32_t height, uint32_t format,
uint64_t producer_usage, uint64_t consumer_usage,
- size_t meta_size_bytes);
+ size_t user_metadata_size);
// Constructs a blob (flat) buffer with the given usage flags.
BufferProducer(uint32_t usage, size_t size);
@@ -234,6 +281,11 @@
// Imports the given file handle to a producer channel, taking ownership.
explicit BufferProducer(LocalChannelHandle channel);
+
+ // Local state transition helpers.
+ int LocalGain(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+ int LocalPost(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& ready_fence);
};
// This is a connection to a producer buffer, which can be located in another
@@ -263,7 +315,7 @@
// are available. This call will only succeed if the buffer is in the posted
// state.
// Returns zero on success, or a negative errno code otherwise.
- int Acquire(LocalHandle* ready_fence, void* meta, size_t meta_size_bytes);
+ int Acquire(LocalHandle* ready_fence, void* meta, size_t user_metadata_size);
// Attempt to retrieve a post event from buffer hub. If successful,
// |ready_fence| is set to a fence to wait on until the buffer is ready. This
@@ -274,20 +326,22 @@
return Acquire(ready_fence, meta, sizeof(*meta));
}
+ // Asynchronously acquires a bufer.
+ int AcquireAsync(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+
// This should be called after a successful Acquire call. If the fence is
// valid the fence determines the buffer usage, otherwise the buffer is
// released immediately.
// This returns zero or a negative unix error code.
int Release(const LocalHandle& release_fence);
+ int ReleaseAsync();
// Asynchronously releases a buffer. Similar to the synchronous version above,
- // except that it does not wait for BufferHub to reply with success or error,
- // nor does it transfer a release fence. This version may be used in
- // situations where a release fence is not needed. Because of the asynchronous
- // nature of the underlying message, no error is returned if this method is
- // called when the buffer is in an incorrect state. Returns zero if sending
- // the message succeeded, or a negative errno code otherwise.
- int ReleaseAsync();
+ // except that it does not wait for BufferHub to reply with success or error.
+ // The fence and metadata are passed to consumer via shared fd and shared
+ // memory.
+ int ReleaseAsync(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& release_fence);
// May be called after or instead of Acquire to indicate that the consumer
// does not need to access the buffer this cycle. This returns zero or a
@@ -305,6 +359,11 @@
friend BASE;
explicit BufferConsumer(LocalChannelHandle channel);
+
+ // Local state transition helpers.
+ int LocalAcquire(DvrNativeBufferMetadata* out_meta, LocalHandle* out_fence);
+ int LocalRelease(const DvrNativeBufferMetadata* meta,
+ const LocalHandle& release_fence);
};
} // namespace dvr
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index ca0e0e0..f9fd42d 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -5,6 +5,7 @@
#include <gui/BufferQueueDefs.h>
#include <sys/types.h>
+#include <dvr/dvr_api.h>
#include <pdx/channel_handle.h>
#include <pdx/file_handle.h>
#include <pdx/rpc/remote_method.h>
@@ -14,6 +15,71 @@
namespace android {
namespace dvr {
+namespace BufferHubDefs {
+
+static constexpr uint32_t kMetadataFormat = HAL_PIXEL_FORMAT_BLOB;
+static constexpr uint32_t kMetadataUsage =
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+
+// Single producuer multiple (up to 63) consumers ownership signal.
+// 64-bit atomic unsigned int.
+//
+// MSB LSB
+// | |
+// v v
+// [P|C62|...|C1|C0]
+// Gain'ed state: [0|..|0|0] -> Exclusively Writable.
+// Post'ed state: [1|..|0|0]
+// Acquired'ed state: [1|..|X|X] -> At least one bit is set in lower 63 bits
+// Released'ed state: [0|..|X|X] -> At least one bit is set in lower 63 bits
+static constexpr uint64_t kProducerStateBit = 1ULL << 63;
+static constexpr uint64_t kConsumerStateMask = (1ULL << 63) - 1;
+
+static inline void ModifyBufferState(std::atomic<uint64_t>* buffer_state,
+ uint64_t clear_mask, uint64_t set_mask) {
+ uint64_t old_state;
+ uint64_t new_state;
+ do {
+ old_state = buffer_state->load();
+ new_state = (old_state & ~clear_mask) | set_mask;
+ } while (!buffer_state->compare_exchange_weak(old_state, new_state));
+}
+
+static inline bool IsBufferGained(uint64_t state) { return state == 0; }
+
+static inline bool IsBufferPosted(uint64_t state,
+ uint64_t consumer_bit = kConsumerStateMask) {
+ return (state & kProducerStateBit) && !(state & consumer_bit);
+}
+
+static inline bool IsBufferAcquired(uint64_t state) {
+ return (state & kProducerStateBit) && (state & kConsumerStateMask);
+}
+
+static inline bool IsBufferReleased(uint64_t state) {
+ return !(state & kProducerStateBit) && (state & kConsumerStateMask);
+}
+
+struct __attribute__((packed, aligned(8))) MetadataHeader {
+ // Internal data format, which can be updated as long as the size, padding and
+ // field alignment of the struct is consistent within the same ABI. As this
+ // part is subject for future updates, it's not stable cross Android version,
+ // so don't have it visible from outside of the Android platform (include Apps
+ // and vendor HAL).
+ std::atomic<uint64_t> buffer_state;
+ std::atomic<uint64_t> fence_state;
+ uint64_t queue_index;
+
+ // Public data format, which should be updated with caution. See more details
+ // in dvr_api.h
+ DvrNativeBufferMetadata metadata;
+};
+
+static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
+static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
+
+} // namespace BufferHubDefs
+
template <typename FileHandleType>
class NativeBufferHandle {
public:
@@ -93,6 +159,57 @@
void operator=(const NativeBufferHandle&) = delete;
};
+template <typename FileHandleType>
+class BufferDescription {
+ public:
+ BufferDescription() = default;
+ BufferDescription(const IonBuffer& buffer, const IonBuffer& metadata, int id,
+ uint64_t buffer_state_bit,
+ const FileHandleType& acquire_fence_fd,
+ const FileHandleType& release_fence_fd)
+ : id_(id),
+ buffer_state_bit_(buffer_state_bit),
+ buffer_(buffer, id),
+ metadata_(metadata, id),
+ acquire_fence_fd_(acquire_fence_fd.Borrow()),
+ release_fence_fd_(release_fence_fd.Borrow()) {}
+
+ BufferDescription(BufferDescription&& other) = default;
+ BufferDescription& operator=(BufferDescription&& other) = default;
+
+ // ID of the buffer client. All BufferHubBuffer clients derived from the same
+ // buffer in bufferhubd share the same buffer id.
+ int id() const { return id_; }
+ // State mask of the buffer client. Each BufferHubBuffer client backed by the
+ // same buffer channel has uniqued state bit among its siblings. For a
+ // producer buffer the bit must be kProducerStateBit; for a consumer the bit
+ // must be one of the kConsumerStateMask.
+ uint64_t buffer_state_bit() const { return buffer_state_bit_; }
+ FileHandleType take_acquire_fence() { return std::move(acquire_fence_fd_); }
+ FileHandleType take_release_fence() { return std::move(release_fence_fd_); }
+
+ int ImportBuffer(IonBuffer* buffer) { return buffer_.Import(buffer); }
+ int ImportMetadata(IonBuffer* metadata) { return metadata_.Import(metadata); }
+
+ private:
+ int id_{-1};
+ uint64_t buffer_state_bit_{0};
+ // Two IonBuffers: one for the graphic buffer and one for metadata.
+ NativeBufferHandle<FileHandleType> buffer_;
+ NativeBufferHandle<FileHandleType> metadata_;
+
+ // Pamameters for shared fences.
+ FileHandleType acquire_fence_fd_;
+ FileHandleType release_fence_fd_;
+
+ PDX_SERIALIZABLE_MEMBERS(BufferDescription<FileHandleType>, id_,
+ buffer_state_bit_, buffer_, metadata_,
+ acquire_fence_fd_, release_fence_fd_);
+
+ BufferDescription(const BufferDescription&) = delete;
+ void operator=(const BufferDescription&) = delete;
+};
+
using BorrowedNativeBufferHandle = NativeBufferHandle<pdx::BorrowedHandle>;
using LocalNativeBufferHandle = NativeBufferHandle<pdx::LocalHandle>;
@@ -149,11 +266,11 @@
// Size of the meta data associated with all the buffers allocated from the
// queue.
- size_t meta_size_bytes;
+ size_t user_metadata_size;
private:
PDX_SERIALIZABLE_MEMBERS(ProducerQueueConfig, is_async, default_width,
- default_height, default_format, meta_size_bytes);
+ default_height, default_format, user_metadata_size);
};
class ProducerQueueConfigBuilder {
@@ -161,7 +278,7 @@
// Build a ProducerQueueConfig object.
ProducerQueueConfig Build() {
return {is_async_, default_width_, default_height_, default_format_,
- meta_size_bytes_};
+ user_metadata_size_};
}
ProducerQueueConfigBuilder& SetIsAsync(bool is_async) {
@@ -186,12 +303,12 @@
template <typename Meta>
ProducerQueueConfigBuilder& SetMetadata() {
- meta_size_bytes_ = sizeof(Meta);
+ user_metadata_size_ = sizeof(Meta);
return *this;
}
- ProducerQueueConfigBuilder& SetMetadataSize(size_t meta_size_bytes) {
- meta_size_bytes_ = meta_size_bytes;
+ ProducerQueueConfigBuilder& SetMetadataSize(size_t user_metadata_size) {
+ user_metadata_size_ = user_metadata_size;
return *this;
}
@@ -200,7 +317,7 @@
uint32_t default_width_{1};
uint32_t default_height_{1};
uint32_t default_format_{1}; // PIXEL_FORMAT_RGBA_8888
- size_t meta_size_bytes_{0};
+ size_t user_metadata_size_{0};
};
// Explicit specializations of ProducerQueueConfigBuilder::Build for void
@@ -208,7 +325,7 @@
template <>
inline ProducerQueueConfigBuilder&
ProducerQueueConfigBuilder::SetMetadata<void>() {
- meta_size_bytes_ = 0;
+ user_metadata_size_ = 0;
return *this;
}
@@ -269,7 +386,6 @@
};
// Aliases.
- using MetaData = pdx::rpc::BufferWrapper<std::uint8_t*>;
using LocalChannelHandle = pdx::LocalChannelHandle;
using LocalHandle = pdx::LocalHandle;
using Void = pdx::rpc::Void;
@@ -277,25 +393,24 @@
// Methods.
PDX_REMOTE_METHOD(CreateBuffer, kOpCreateBuffer,
void(uint32_t width, uint32_t height, uint32_t format,
- uint64_t usage, size_t meta_size_bytes));
+ uint64_t usage, size_t user_metadata_size));
PDX_REMOTE_METHOD(CreatePersistentBuffer, kOpCreatePersistentBuffer,
void(const std::string& name, int user_id, int group_id,
uint32_t width, uint32_t height, uint32_t format,
- uint64_t usage, size_t meta_size_bytes));
+ uint64_t usage, size_t user_metadata_size));
PDX_REMOTE_METHOD(GetPersistentBuffer, kOpGetPersistentBuffer,
void(const std::string& name));
PDX_REMOTE_METHOD(GetBuffer, kOpGetBuffer,
- NativeBufferHandle<LocalHandle>(Void));
+ BufferDescription<LocalHandle>(Void));
PDX_REMOTE_METHOD(NewConsumer, kOpNewConsumer, LocalChannelHandle(Void));
PDX_REMOTE_METHOD(ProducerMakePersistent, kOpProducerMakePersistent,
void(const std::string& name, int user_id, int group_id));
PDX_REMOTE_METHOD(ProducerRemovePersistence, kOpProducerRemovePersistence,
void(Void));
PDX_REMOTE_METHOD(ProducerPost, kOpProducerPost,
- void(LocalFence acquire_fence, MetaData));
+ void(LocalFence acquire_fence));
PDX_REMOTE_METHOD(ProducerGain, kOpProducerGain, LocalFence(Void));
- PDX_REMOTE_METHOD(ConsumerAcquire, kOpConsumerAcquire,
- std::pair<LocalFence, MetaData>(std::size_t metadata_size));
+ PDX_REMOTE_METHOD(ConsumerAcquire, kOpConsumerAcquire, LocalFence(Void));
PDX_REMOTE_METHOD(ConsumerRelease, kOpConsumerRelease,
void(LocalFence release_fence));
PDX_REMOTE_METHOD(ConsumerSetIgnore, kOpConsumerSetIgnore, void(bool ignore));
@@ -305,7 +420,7 @@
QueueInfo(const ProducerQueueConfig& producer_config,
const UsagePolicy& usage_policy));
PDX_REMOTE_METHOD(CreateConsumerQueue, kOpCreateConsumerQueue,
- LocalChannelHandle(Void));
+ LocalChannelHandle(bool silent_queue));
PDX_REMOTE_METHOD(GetQueueInfo, kOpGetQueueInfo, QueueInfo(Void));
PDX_REMOTE_METHOD(ProducerQueueAllocateBuffers,
kOpProducerQueueAllocateBuffers,
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 0b3b2f0..93ccd0f 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -48,6 +48,7 @@
cflags: [
"-DLOG_TAG=\"libbufferhubqueue\"",
"-DTRACE=0",
+ "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
],
srcs: sourceFiles,
export_include_dirs: includeFiles,
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index f9f87ff..8bea0cd 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -10,6 +10,7 @@
#include <pdx/default_transport/client_channel.h>
#include <pdx/default_transport/client_channel_factory.h>
#include <pdx/file_handle.h>
+#include <pdx/trace.h>
#define RETRY_EINTR(fnc_call) \
([&]() -> decltype(fnc_call) { \
@@ -44,17 +45,6 @@
}
}
-// Polls a buffer for the given events, taking care to do the proper
-// translation.
-Status<int> PollEvents(const std::shared_ptr<BufferHubBuffer>& buffer,
- short events) {
- auto poll_status = PollEvents(buffer->event_fd(), events);
- if (!poll_status)
- return poll_status;
-
- return buffer->GetEventMask(poll_status.get());
-}
-
std::pair<int32_t, int32_t> Unstuff(uint64_t value) {
return {static_cast<int32_t>(value >> 32),
static_cast<int32_t>(value & ((1ull << 32) - 1))};
@@ -115,27 +105,27 @@
default_width_ = queue_info.producer_config.default_width;
default_height_ = queue_info.producer_config.default_height;
default_format_ = queue_info.producer_config.default_format;
- meta_size_ = queue_info.producer_config.meta_size_bytes;
+ user_metadata_size_ = queue_info.producer_config.user_metadata_size;
id_ = queue_info.id;
}
std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateConsumerQueue() {
- if (auto status = CreateConsumerQueueHandle())
+ if (auto status = CreateConsumerQueueHandle(/*silent*/ false))
return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take()));
else
return nullptr;
}
std::unique_ptr<ConsumerQueue> BufferHubQueue::CreateSilentConsumerQueue() {
- if (auto status = CreateConsumerQueueHandle())
- return std::unique_ptr<ConsumerQueue>(
- new ConsumerQueue(status.take(), true));
+ if (auto status = CreateConsumerQueueHandle(/*silent*/ true))
+ return std::unique_ptr<ConsumerQueue>(new ConsumerQueue(status.take()));
else
return nullptr;
}
-Status<LocalChannelHandle> BufferHubQueue::CreateConsumerQueueHandle() {
- auto status = InvokeRemoteMethod<BufferHubRPC::CreateConsumerQueue>();
+Status<LocalChannelHandle> BufferHubQueue::CreateConsumerQueueHandle(
+ bool silent) {
+ auto status = InvokeRemoteMethod<BufferHubRPC::CreateConsumerQueue>(silent);
if (!status) {
ALOGE(
"BufferHubQueue::CreateConsumerQueue: Failed to create consumer queue: "
@@ -148,6 +138,7 @@
}
bool BufferHubQueue::WaitForBuffers(int timeout) {
+ ATRACE_NAME("BufferHubQueue::WaitForBuffers");
std::array<epoll_event, kMaxEvents> events;
// Loop at least once to check for hangups.
@@ -178,13 +169,18 @@
const int num_events = ret;
// A BufferQueue's epoll fd tracks N+1 events, where there are N events,
- // one for each buffer, in the queue and one extra event for the queue
+ // one for each buffer in the queue, and one extra event for the queue
// client itself.
for (int i = 0; i < num_events; i++) {
int32_t event_fd;
int32_t index;
std::tie(event_fd, index) = Unstuff(events[i].data.u64);
+ PDX_TRACE_FORMAT(
+ "epoll_event|queue_id=%d;num_events=%d;event_index=%d;event_fd=%d;"
+ "slot=%d|",
+ id(), num_events, i, event_fd, index);
+
ALOGD_IF(TRACE,
"BufferHubQueue::WaitForBuffers: event %d: event_fd=%d index=%d",
i, event_fd, index);
@@ -208,6 +204,7 @@
Status<void> BufferHubQueue::HandleBufferEvent(size_t slot, int event_fd,
int poll_events) {
+ ATRACE_NAME("BufferHubQueue::HandleBufferEvent");
if (!buffers_[slot]) {
ALOGW("BufferHubQueue::HandleBufferEvent: Invalid buffer slot: %zu", slot);
return ErrorStatus(ENOENT);
@@ -221,58 +218,19 @@
}
const int events = status.get();
+ PDX_TRACE_FORMAT(
+ "buffer|queue_id=%d;buffer_id=%d;slot=%zu;event_fd=%d;poll_events=%x;"
+ "events=%d|",
+ id(), buffers_[slot]->id(), slot, event_fd, poll_events, events);
+
if (events & EPOLLIN) {
- auto entry_status = OnBufferReady(buffers_[slot], slot);
- if (entry_status.ok() || entry_status.error() == EALREADY) {
- // Only enqueue the buffer if it moves to or is already in the state
- // requested in OnBufferReady().
- return Enqueue(entry_status.take());
- } else if (entry_status.error() == EBUSY) {
- // If the buffer is busy this means that the buffer moved from released to
- // posted when a new consumer was created before the ProducerQueue had a
- // chance to regain it. This is a valid transition that we have to handle
- // because edge triggered poll events latch the ready state even if it is
- // later de-asserted -- don't enqueue or print an error log in this case.
- } else {
- ALOGE(
- "BufferHubQueue::HandleBufferEvent: Failed to set buffer ready, "
- "queue_id=%d buffer_id=%d: %s",
- id(), buffers_[slot]->id(), entry_status.GetErrorMessage().c_str());
- }
+ return Enqueue({buffers_[slot], slot, buffers_[slot]->GetQueueIndex()});
} else if (events & EPOLLHUP) {
- // Check to see if the current buffer in the slot hung up. This is a bit of
- // paranoia to deal with the epoll set getting out of sync with the buffer
- // slots.
- auto poll_status = PollEvents(buffers_[slot], POLLIN);
- if (!poll_status && poll_status.error() != ETIMEDOUT) {
- ALOGE("BufferHubQueue::HandleBufferEvent: Failed to poll buffer: %s",
- poll_status.GetErrorMessage().c_str());
- return poll_status.error_status();
- }
-
- const bool hangup_pending = status.ok() && (poll_status.get() & EPOLLHUP);
-
ALOGW(
"BufferHubQueue::HandleBufferEvent: Received EPOLLHUP event: slot=%zu "
- "event_fd=%d buffer_id=%d hangup_pending=%d poll_status=%x",
- slot, buffers_[slot]->event_fd(), buffers_[slot]->id(), hangup_pending,
- poll_status.get());
-
- if (hangup_pending) {
- return RemoveBuffer(slot);
- } else {
- // Clean up the bookkeeping for the event fd. This is a bit of paranoia to
- // deal with the epoll set getting out of sync with the buffer slots.
- // Hitting this path should be very unusual.
- const int ret = epoll_fd_.Control(EPOLL_CTL_DEL, event_fd, nullptr);
- if (ret < 0) {
- ALOGE(
- "BufferHubQueue::HandleBufferEvent: Failed to remove fd=%d from "
- "epoll set: %s",
- event_fd, strerror(-ret));
- return ErrorStatus(-ret);
- }
- }
+ "event_fd=%d buffer_id=%d",
+ slot, buffers_[slot]->event_fd(), buffers_[slot]->id());
+ return RemoveBuffer(slot);
} else {
ALOGW(
"BufferHubQueue::HandleBufferEvent: Unknown event, slot=%zu, epoll "
@@ -284,6 +242,7 @@
}
Status<void> BufferHubQueue::HandleQueueEvent(int poll_event) {
+ ATRACE_NAME("BufferHubQueue::HandleQueueEvent");
auto status = GetEventMask(poll_event);
if (!status) {
ALOGW("BufferHubQueue::HandleQueueEvent: Failed to get event mask: %s",
@@ -330,13 +289,16 @@
return remove_status.error_status();
}
- epoll_event event = {.events = EPOLLIN | EPOLLET,
- .data = {.u64 = Stuff(buffer->event_fd(), slot)}};
- const int ret = epoll_fd_.Control(EPOLL_CTL_ADD, buffer->event_fd(), &event);
- if (ret < 0) {
- ALOGE("BufferHubQueue::AddBuffer: Failed to add buffer to epoll set: %s",
- strerror(-ret));
- return ErrorStatus(-ret);
+ for (const auto& event_source : buffer->GetEventSources()) {
+ epoll_event event = {.events = event_source.event_mask | EPOLLET,
+ .data = {.u64 = Stuff(buffer->event_fd(), slot)}};
+ const int ret =
+ epoll_fd_.Control(EPOLL_CTL_ADD, event_source.event_fd, &event);
+ if (ret < 0) {
+ ALOGE("BufferHubQueue::AddBuffer: Failed to add buffer to epoll set: %s",
+ strerror(-ret));
+ return ErrorStatus(-ret);
+ }
}
buffers_[slot] = buffer;
@@ -348,15 +310,16 @@
ALOGD_IF(TRACE, "BufferHubQueue::RemoveBuffer: slot=%zu", slot);
if (buffers_[slot]) {
- const int ret =
- epoll_fd_.Control(EPOLL_CTL_DEL, buffers_[slot]->event_fd(), nullptr);
- if (ret < 0) {
- ALOGE(
- "BufferHubQueue::RemoveBuffer: Failed to remove buffer from epoll "
- "set: "
- "%s",
- strerror(-ret));
- return ErrorStatus(-ret);
+ for (const auto& event_source : buffers_[slot]->GetEventSources()) {
+ const int ret =
+ epoll_fd_.Control(EPOLL_CTL_DEL, event_source.event_fd, nullptr);
+ if (ret < 0) {
+ ALOGE(
+ "BufferHubQueue::RemoveBuffer: Failed to remove buffer from epoll "
+ "set: %s",
+ strerror(-ret));
+ return ErrorStatus(-ret);
+ }
}
// Trigger OnBufferRemoved callback if registered.
@@ -372,7 +335,7 @@
Status<void> BufferHubQueue::Enqueue(Entry entry) {
if (!is_full()) {
- available_buffers_.Append(std::move(entry));
+ available_buffers_.push(std::move(entry));
// Trigger OnBufferAvailable callback if registered.
if (on_buffer_available_)
@@ -385,25 +348,26 @@
}
}
-Status<std::shared_ptr<BufferHubBuffer>> BufferHubQueue::Dequeue(
- int timeout, size_t* slot, void* meta, LocalHandle* fence) {
+Status<std::shared_ptr<BufferHubBuffer>> BufferHubQueue::Dequeue(int timeout,
+ size_t* slot) {
ALOGD_IF(TRACE, "BufferHubQueue::Dequeue: count=%zu, timeout=%d", count(),
timeout);
- if (!WaitForBuffers(timeout))
- return ErrorStatus(ETIMEDOUT);
+ PDX_TRACE_FORMAT("BufferHubQueue::Dequeue|count=%zu|", count());
- auto& entry = available_buffers_.Front();
+ if (count() == 0) {
+ if (!WaitForBuffers(timeout))
+ return ErrorStatus(ETIMEDOUT);
+ }
+
+ auto& entry = available_buffers_.top();
+ PDX_TRACE_FORMAT("buffer|buffer_id=%d;slot=%zu|", entry.buffer->id(),
+ entry.slot);
std::shared_ptr<BufferHubBuffer> buffer = std::move(entry.buffer);
*slot = entry.slot;
- *fence = std::move(entry.fence);
- if (meta && entry.metadata) {
- std::copy(entry.metadata.get(), entry.metadata.get() + meta_size_,
- reinterpret_cast<uint8_t*>(meta));
- }
- available_buffers_.PopFront();
+ available_buffers_.pop();
return {std::move(buffer)};
}
@@ -419,7 +383,8 @@
pdx::Status<void> BufferHubQueue::FreeAllBuffers() {
// Clear all available buffers.
- available_buffers_.Clear();
+ while (!available_buffers_.empty())
+ available_buffers_.pop();
pdx::Status<void> last_error; // No error.
// Clear all buffers this producer queue is tracking.
@@ -429,7 +394,7 @@
if (!status) {
ALOGE(
"ProducerQueue::FreeAllBuffers: Failed to remove buffer at "
- "slot=%d.",
+ "slot=%zu.",
slot);
last_error = status.error_status();
}
@@ -548,7 +513,7 @@
if (!status)
return status;
- return Enqueue(buffer, slot);
+ return BufferHubQueue::Enqueue({buffer, slot, 0ULL});
}
Status<void> ProducerQueue::RemoveBuffer(size_t slot) {
@@ -565,40 +530,33 @@
Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue(
int timeout, size_t* slot, LocalHandle* release_fence) {
- if (slot == nullptr || release_fence == nullptr) {
- ALOGE("ProducerQueue::Dequeue: Invalid parameter: slot=%p release_fence=%p",
- slot, release_fence);
+ DvrNativeBufferMetadata canonical_meta;
+ return Dequeue(timeout, slot, &canonical_meta, release_fence);
+}
+
+pdx::Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue(
+ int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
+ pdx::LocalHandle* release_fence) {
+ ATRACE_NAME("ProducerQueue::Dequeue");
+ if (slot == nullptr || out_meta == nullptr || release_fence == nullptr) {
+ ALOGE("ProducerQueue::Dequeue: Invalid parameter.");
return ErrorStatus(EINVAL);
}
- auto buffer_status =
- BufferHubQueue::Dequeue(timeout, slot, nullptr, release_fence);
- if (!buffer_status)
- return buffer_status.error_status();
+ auto status = BufferHubQueue::Dequeue(timeout, slot);
+ if (!status)
+ return status.error_status();
- return {std::static_pointer_cast<BufferProducer>(buffer_status.take())};
-}
-
-Status<BufferHubQueue::Entry> ProducerQueue::OnBufferReady(
- const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) {
- ALOGD_IF(TRACE,
- "ProducerQueue::OnBufferReady: queue_id=%d buffer_id=%d slot=%zu",
- id(), buffer->id(), slot);
-
- // Avoid taking a transient reference, buffer is valid for the duration of
- // this method call.
- auto* producer_buffer = static_cast<BufferProducer*>(buffer.get());
- LocalHandle release_fence;
-
- const int ret = producer_buffer->Gain(&release_fence);
- if (ret < 0)
+ auto buffer = std::static_pointer_cast<BufferProducer>(status.take());
+ const int ret = buffer->GainAsync(out_meta, release_fence);
+ if (ret < 0 && ret != -EALREADY)
return ErrorStatus(-ret);
- else
- return {{buffer, nullptr, std::move(release_fence), slot}};
+
+ return {std::move(buffer)};
}
-ConsumerQueue::ConsumerQueue(LocalChannelHandle handle, bool ignore_on_import)
- : BufferHubQueue(std::move(handle)), ignore_on_import_(ignore_on_import) {
+ConsumerQueue::ConsumerQueue(LocalChannelHandle handle)
+ : BufferHubQueue(std::move(handle)) {
auto status = ImportQueue();
if (!status) {
ALOGE("ConsumerQueue::ConsumerQueue: Failed to import queue: %s",
@@ -619,9 +577,17 @@
Status<size_t> ConsumerQueue::ImportBuffers() {
auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerQueueImportBuffers>();
if (!status) {
- ALOGE("ConsumerQueue::ImportBuffers: Failed to import consumer buffer: %s",
+ if (status.error() == EBADR) {
+ ALOGI(
+ "ConsumerQueue::ImportBuffers: Queue is silent, no buffers "
+ "imported.");
+ return {0};
+ } else {
+ ALOGE(
+ "ConsumerQueue::ImportBuffers: Failed to import consumer buffer: %s",
status.GetErrorMessage().c_str());
- return status.error_status();
+ return status.error_status();
+ }
}
int ret;
@@ -642,22 +608,6 @@
continue;
}
- // Setup ignore state before adding buffer to the queue.
- if (ignore_on_import_) {
- ALOGD_IF(TRACE,
- "ConsumerQueue::ImportBuffers: Setting buffer to ignored state: "
- "buffer_id=%d",
- buffer_consumer->id());
- ret = buffer_consumer->SetIgnore(true);
- if (ret < 0) {
- ALOGE(
- "ConsumerQueue::ImportBuffers: Failed to set ignored state on "
- "imported buffer buffer_id=%d: %s",
- buffer_consumer->id(), strerror(-ret));
- last_error = ErrorStatus(-ret);
- }
- }
-
auto add_status =
AddBuffer(std::move(buffer_consumer), buffer_handle_slot.second);
if (!add_status) {
@@ -685,7 +635,7 @@
// Check to see if the buffer is already signaled. This is necessary to catch
// cases where buffers are already available; epoll edge triggered mode does
- // not fire until and edge transition when adding new buffers to the epoll
+ // not fire until an edge transition when adding new buffers to the epoll
// set. Note that we only poll the fd events because HandleBufferEvent() takes
// care of checking the translated buffer events.
auto poll_status = PollEvents(buffer->event_fd(), POLLIN);
@@ -703,51 +653,53 @@
}
Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue(
- int timeout, size_t* slot, void* meta, size_t meta_size,
+ int timeout, size_t* slot, void* meta, size_t user_metadata_size,
LocalHandle* acquire_fence) {
- if (meta_size != meta_size_) {
+ if (user_metadata_size != user_metadata_size_) {
ALOGE(
"ConsumerQueue::Dequeue: Metadata size (%zu) for the dequeuing buffer "
"does not match metadata size (%zu) for the queue.",
- meta_size, meta_size_);
+ user_metadata_size, user_metadata_size_);
return ErrorStatus(EINVAL);
}
- if (slot == nullptr || acquire_fence == nullptr) {
- ALOGE(
- "ConsumerQueue::Dequeue: Invalid parameter: slot=%p meta=%p "
- "acquire_fence=%p",
- slot, meta, acquire_fence);
- return ErrorStatus(EINVAL);
+ DvrNativeBufferMetadata canonical_meta;
+ auto status = Dequeue(timeout, slot, &canonical_meta, acquire_fence);
+ if (!status)
+ return status.error_status();
+
+ if (meta && user_metadata_size) {
+ void* metadata_src =
+ reinterpret_cast<void*>(canonical_meta.user_metadata_ptr);
+ if (metadata_src) {
+ memcpy(meta, metadata_src, user_metadata_size);
+ } else {
+ ALOGW("ConsumerQueue::Dequeue: no user-defined metadata.");
+ }
}
- auto buffer_status =
- BufferHubQueue::Dequeue(timeout, slot, meta, acquire_fence);
- if (!buffer_status)
- return buffer_status.error_status();
-
- return {std::static_pointer_cast<BufferConsumer>(buffer_status.take())};
+ return status;
}
-Status<BufferHubQueue::Entry> ConsumerQueue::OnBufferReady(
- const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) {
- ALOGD_IF(TRACE,
- "ConsumerQueue::OnBufferReady: queue_id=%d buffer_id=%d slot=%zu",
- id(), buffer->id(), slot);
+Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue(
+ int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
+ pdx::LocalHandle* acquire_fence) {
+ ATRACE_NAME("ConsumerQueue::Dequeue");
+ if (slot == nullptr || out_meta == nullptr || acquire_fence == nullptr) {
+ ALOGE("ConsumerQueue::Dequeue: Invalid parameter.");
+ return ErrorStatus(EINVAL);
+ }
- // Avoid taking a transient reference, buffer is valid for the duration of
- // this method call.
- auto* consumer_buffer = static_cast<BufferConsumer*>(buffer.get());
- std::unique_ptr<uint8_t[]> metadata(meta_size_ ? new uint8_t[meta_size_]
- : nullptr);
- LocalHandle acquire_fence;
+ auto status = BufferHubQueue::Dequeue(timeout, slot);
+ if (!status)
+ return status.error_status();
- const int ret =
- consumer_buffer->Acquire(&acquire_fence, metadata.get(), meta_size_);
+ auto buffer = std::static_pointer_cast<BufferConsumer>(status.take());
+ const int ret = buffer->AcquireAsync(out_meta, acquire_fence);
if (ret < 0)
return ErrorStatus(-ret);
- else
- return {{buffer, std::move(metadata), std::move(acquire_fence), slot}};
+
+ return {std::move(buffer)};
}
Status<void> ConsumerQueue::OnBufferAllocated() {
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
index 53eed89..221bc4f 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp
@@ -328,7 +328,7 @@
LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1);
- DvrNativeBufferMetadata meta_data = {};
+ DvrNativeBufferMetadata meta_data;
meta_data.timestamp = timestamp;
meta_data.is_auto_timestamp = static_cast<int32_t>(is_auto_timestamp);
meta_data.dataspace = static_cast<int32_t>(dataspace);
@@ -339,7 +339,7 @@
meta_data.scaling_mode = static_cast<int32_t>(scaling_mode);
meta_data.transform = static_cast<int32_t>(transform);
- buffer_producer->Post(fence_fd, &meta_data, sizeof(meta_data));
+ buffer_producer->PostAsync(&meta_data, fence_fd);
buffers_[slot].mBufferState.queue();
output->width = buffer_producer->width();
@@ -384,7 +384,7 @@
}
auto buffer_producer = buffers_[slot].mBufferProducer;
- queue_->Enqueue(buffer_producer, slot);
+ queue_->Enqueue(buffer_producer, slot, 0ULL);
buffers_[slot].mBufferState.cancel();
buffers_[slot].mFence = fence;
ALOGD_IF(TRACE, "cancelBuffer: slot %d", slot);
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index 3e93788..6962d6c 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -5,12 +5,13 @@
#include <pdx/client.h>
#include <pdx/status.h>
-#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/buffer_hub_client.h>
+#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/epoll_file_descriptor.h>
#include <private/dvr/ring_buffer.h>
#include <memory>
+#include <queue>
#include <vector>
namespace android {
@@ -50,22 +51,30 @@
uint32_t default_format() const { return default_format_; }
// Creates a new consumer in handle form for immediate transport over RPC.
- pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle();
+ pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle(
+ bool silent = false);
// Returns the number of buffers avaiable for dequeue.
- size_t count() const { return available_buffers_.GetSize(); }
+ size_t count() const { return available_buffers_.size(); }
// Returns the total number of buffers that the queue is tracking.
size_t capacity() const { return capacity_; }
// Returns the size of metadata structure associated with this queue.
- size_t metadata_size() const { return meta_size_; }
+ size_t metadata_size() const { return user_metadata_size_; }
// Returns whether the buffer queue is full.
- bool is_full() const { return available_buffers_.IsFull(); }
+ bool is_full() const {
+ return available_buffers_.size() >= kMaxQueueCapacity;
+ }
explicit operator bool() const { return epoll_fd_.IsValid(); }
+ int GetBufferId(size_t slot) const {
+ return (slot < buffers_.size() && buffers_[slot]) ? buffers_[slot]->id()
+ : -1;
+ }
+
std::shared_ptr<BufferHubBuffer> GetBuffer(size_t slot) const {
return buffers_[slot];
}
@@ -131,8 +140,8 @@
// block. Specifying a timeout of -1 causes Dequeue() to block indefinitely,
// while specifying a timeout equal to zero cause Dequeue() to return
// immediately, even if no buffers are available.
- pdx::Status<std::shared_ptr<BufferHubBuffer>> Dequeue(
- int timeout, size_t* slot, void* meta, pdx::LocalHandle* fence);
+ pdx::Status<std::shared_ptr<BufferHubBuffer>> Dequeue(int timeout,
+ size_t* slot);
// Waits for buffers to become available and adds them to the available queue.
bool WaitForBuffers(int timeout);
@@ -145,8 +154,9 @@
// per-buffer data.
struct Entry {
Entry() : slot(0) {}
- Entry(const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot)
- : buffer(buffer), slot(slot) {}
+ Entry(const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot,
+ uint64_t index)
+ : buffer(buffer), slot(slot), index(index) {}
Entry(const std::shared_ptr<BufferHubBuffer>& buffer,
std::unique_ptr<uint8_t[]> metadata, pdx::LocalHandle fence,
size_t slot)
@@ -161,20 +171,24 @@
std::unique_ptr<uint8_t[]> metadata;
pdx::LocalHandle fence;
size_t slot;
+ uint64_t index;
+ };
+
+ struct EntryComparator {
+ bool operator()(const Entry& lhs, const Entry& rhs) {
+ return lhs.index > rhs.index;
+ }
};
// Enqueues a buffer to the available list (Gained for producer or Acquireed
// for consumer).
pdx::Status<void> Enqueue(Entry entry);
- virtual pdx::Status<Entry> OnBufferReady(
- const std::shared_ptr<BufferHubBuffer>& buf, size_t slot) = 0;
-
// Called when a buffer is allocated remotely.
virtual pdx::Status<void> OnBufferAllocated() { return {}; }
// Size of the metadata that buffers in this queue cary.
- size_t meta_size_{0};
+ size_t user_metadata_size_{0};
private:
void Initialize();
@@ -218,10 +232,12 @@
// Tracks the buffers belonging to this queue. Buffers are stored according to
// "slot" in this vector. Each slot is a logical id of the buffer within this
// queue regardless of its queue position or presence in the ring buffer.
- std::vector<std::shared_ptr<BufferHubBuffer>> buffers_{kMaxQueueCapacity};
+ std::array<std::shared_ptr<BufferHubBuffer>, kMaxQueueCapacity> buffers_;
// Buffers and related data that are available for dequeue.
- RingBuffer<Entry> available_buffers_{kMaxQueueCapacity};
+ // RingBuffer<Entry> available_buffers_{kMaxQueueCapacity};
+ std::priority_queue<Entry, std::vector<Entry>, EntryComparator>
+ available_buffers_;
// Keeps track with how many buffers have been added into the queue.
size_t capacity_{0};
@@ -311,11 +327,14 @@
// to the consumer side.
pdx::Status<std::shared_ptr<BufferProducer>> Dequeue(
int timeout, size_t* slot, pdx::LocalHandle* release_fence);
+ pdx::Status<std::shared_ptr<BufferProducer>> Dequeue(
+ int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
+ pdx::LocalHandle* release_fence);
// Enqueues a producer buffer in the queue.
pdx::Status<void> Enqueue(const std::shared_ptr<BufferProducer>& buffer,
- size_t slot) {
- return BufferHubQueue::Enqueue({buffer, slot});
+ size_t slot, uint64_t index) {
+ return BufferHubQueue::Enqueue({buffer, slot, index});
}
private:
@@ -326,9 +345,6 @@
// arguments as the constructors.
explicit ProducerQueue(pdx::LocalChannelHandle handle);
ProducerQueue(const ProducerQueueConfig& config, const UsagePolicy& usage);
-
- pdx::Status<Entry> OnBufferReady(
- const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) override;
};
class ConsumerQueue : public BufferHubQueue {
@@ -347,10 +363,9 @@
// used to avoid participation in the buffer lifecycle by a consumer queue
// that is only used to spawn other consumer queues, such as in an
// intermediate service.
- static std::unique_ptr<ConsumerQueue> Import(pdx::LocalChannelHandle handle,
- bool ignore_on_import = false) {
+ static std::unique_ptr<ConsumerQueue> Import(pdx::LocalChannelHandle handle) {
return std::unique_ptr<ConsumerQueue>(
- new ConsumerQueue(std::move(handle), ignore_on_import));
+ new ConsumerQueue(std::move(handle)));
}
// Import newly created buffers from the service side.
@@ -374,13 +389,16 @@
}
pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue(
- int timeout, size_t* slot, void* meta, size_t meta_size,
+ int timeout, size_t* slot, void* meta, size_t user_metadata_size,
+ pdx::LocalHandle* acquire_fence);
+ pdx::Status<std::shared_ptr<BufferConsumer>> Dequeue(
+ int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
pdx::LocalHandle* acquire_fence);
private:
friend BufferHubQueue;
- ConsumerQueue(pdx::LocalChannelHandle handle, bool ignore_on_import = false);
+ ConsumerQueue(pdx::LocalChannelHandle handle);
// Add a consumer buffer to populate the queue. Once added, a consumer buffer
// is NOT available to use until the producer side |Post| it. |WaitForBuffers|
@@ -389,14 +407,7 @@
pdx::Status<void> AddBuffer(const std::shared_ptr<BufferConsumer>& buffer,
size_t slot);
- pdx::Status<Entry> OnBufferReady(
- const std::shared_ptr<BufferHubBuffer>& buffer, size_t slot) override;
-
pdx::Status<void> OnBufferAllocated() override;
-
- // Flag indicating that imported (consumer) buffers should be ignored when
- // imported to avoid participating in the buffer ownership flow.
- bool ignore_on_import_;
};
} // namespace dvr
diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp
index 865573c..8bd1ef1 100644
--- a/libs/vr/libbufferhubqueue/tests/Android.bp
+++ b/libs/vr/libbufferhubqueue/tests/Android.bp
@@ -1,4 +1,7 @@
+header_libraries = [
+ "libdvr_headers",
+]
shared_libraries = [
"libbase",
@@ -21,6 +24,7 @@
cc_test {
srcs: ["buffer_hub_queue-test.cpp"],
+ header_libs: header_libraries,
static_libs: static_libraries,
shared_libs: shared_libraries,
cflags: [
@@ -35,6 +39,7 @@
cc_test {
srcs: ["buffer_hub_queue_producer-test.cpp"],
+ header_libs: header_libraries,
static_libs: static_libraries,
shared_libs: shared_libraries,
cflags: [
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index 7581a06..8a72531 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -3,6 +3,8 @@
#include <private/dvr/buffer_hub_queue_client.h>
#include <gtest/gtest.h>
+#include <poll.h>
+#include <sys/eventfd.h>
#include <vector>
@@ -46,9 +48,9 @@
void AllocateBuffer(size_t* slot_out = nullptr) {
// Create producer buffer.
- auto status = producer_queue_->AllocateBuffer(
- kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage);
+ auto status = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
+ kBufferLayerCount,
+ kBufferFormat, kBufferUsage);
ASSERT_TRUE(status.ok());
size_t slot = status.take();
@@ -56,6 +58,23 @@
*slot_out = slot;
}
+ bool WaitAndHandleOnce(BufferHubQueue* queue, int timeout_ms) {
+ pollfd pfd{queue->queue_fd(), POLLIN, 0};
+ int ret;
+ do {
+ ret = poll(&pfd, 1, timeout_ms);
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret < 0) {
+ ALOGW("Failed to poll queue %d's event fd, error: %s.", queue->id(),
+ strerror(errno));
+ return false;
+ } else if (ret == 0) {
+ return false;
+ }
+ return queue->HandleQueueEvents();
+ }
+
protected:
ProducerQueueConfigBuilder config_builder_;
std::unique_ptr<ProducerQueue> producer_queue_;
@@ -75,7 +94,7 @@
for (size_t i = 0; i < nb_dequeue_times; i++) {
size_t slot;
LocalHandle fence;
- auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
+ auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(p1_status.ok());
auto p1 = p1_status.take();
ASSERT_NE(nullptr, p1);
@@ -113,31 +132,26 @@
// Dequeue returns timeout since no buffer is ready to consumer, but
// this implicitly triggers buffer import and bump up |capacity|.
LocalHandle fence;
- auto status = consumer_queue_->Dequeue(0, &slot, &seq, &fence);
+ auto status = consumer_queue_->Dequeue(100, &slot, &seq, &fence);
ASSERT_FALSE(status.ok());
ASSERT_EQ(ETIMEDOUT, status.error());
ASSERT_EQ(consumer_queue_->capacity(), i + 1);
}
- // Use /dev/zero as a stand-in for a fence. As long as BufferHub does not need
- // to merge fences, which only happens when multiple consumers release the
- // same buffer with release fences, the file object should simply pass
- // through.
- LocalHandle post_fence("/dev/zero", O_RDONLY);
- struct stat post_fence_stat;
- ASSERT_EQ(0, fstat(post_fence.Get(), &post_fence_stat));
+ // Use eventfd as a stand-in for a fence.
+ LocalHandle post_fence(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
for (size_t i = 0; i < kBufferCount; i++) {
LocalHandle fence;
// First time there is no buffer available to dequeue.
- auto consumer_status = consumer_queue_->Dequeue(0, &slot, &seq, &fence);
+ auto consumer_status = consumer_queue_->Dequeue(100, &slot, &seq, &fence);
ASSERT_FALSE(consumer_status.ok());
ASSERT_EQ(ETIMEDOUT, consumer_status.error());
// Make sure Producer buffer is POSTED so that it's ready to Accquire
// in the consumer's Dequeue() function.
- auto producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+ auto producer_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(producer_status.ok());
auto producer = producer_status.take();
ASSERT_NE(nullptr, producer);
@@ -147,20 +161,10 @@
// Second time the just the POSTED buffer should be dequeued.
uint64_t seq_out = 0;
- consumer_status = consumer_queue_->Dequeue(0, &slot, &seq_out, &fence);
+ consumer_status = consumer_queue_->Dequeue(100, &slot, &seq_out, &fence);
ASSERT_TRUE(consumer_status.ok());
EXPECT_TRUE(fence.IsValid());
- struct stat acquire_fence_stat;
- ASSERT_EQ(0, fstat(fence.Get(), &acquire_fence_stat));
-
- // The file descriptors should refer to the same file object. Testing the
- // device id and inode is a proxy for testing that the fds refer to the same
- // file object.
- EXPECT_NE(post_fence.Get(), fence.Get());
- EXPECT_EQ(post_fence_stat.st_dev, acquire_fence_stat.st_dev);
- EXPECT_EQ(post_fence_stat.st_ino, acquire_fence_stat.st_ino);
-
auto consumer = consumer_status.take();
ASSERT_NE(nullptr, consumer);
ASSERT_EQ(seq_in, seq_out);
@@ -196,12 +200,11 @@
for (size_t i = 0; i < kBufferCount; i++) {
Entry* entry = &buffers[i];
- auto producer_status =
- producer_queue_->Dequeue(0, &entry->slot, &entry->fence);
+ auto producer_status = producer_queue_->Dequeue(
+ /*timeout_ms=*/100, &entry->slot, &entry->fence);
ASSERT_TRUE(producer_status.ok());
entry->buffer = producer_status.take();
ASSERT_NE(nullptr, entry->buffer);
- EXPECT_EQ(i, entry->slot);
}
// Remove a buffer and make sure both queues reflect the change.
@@ -218,8 +221,8 @@
buffers[0].buffer = nullptr;
// Now the consumer queue should know it's gone.
- EXPECT_FALSE(consumer_queue_->HandleQueueEvents());
- EXPECT_EQ(kBufferCount - 1, consumer_queue_->capacity());
+ EXPECT_FALSE(WaitAndHandleOnce(consumer_queue_.get(), /*timeout_ms=*/100));
+ ASSERT_EQ(kBufferCount - 1, consumer_queue_->capacity());
// Allocate a new buffer. This should take the first empty slot.
size_t slot;
@@ -286,17 +289,20 @@
auto silent_queue = producer_queue_->CreateSilentConsumerQueue();
ASSERT_NE(nullptr, silent_queue);
- // Check that buffers are correctly imported on construction.
- EXPECT_EQ(kBufferCount, silent_queue->capacity());
+ // Check that silent queue doesn't import buffers on creation.
+ EXPECT_EQ(0, silent_queue->capacity());
// Dequeue and post a buffer.
size_t slot;
LocalHandle fence;
- auto producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+ auto producer_status =
+ producer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence);
ASSERT_TRUE(producer_status.ok());
auto producer_buffer = producer_status.take();
ASSERT_NE(nullptr, producer_buffer);
ASSERT_EQ(0, producer_buffer->Post<void>({}));
+ // After post, check the number of remaining available buffers.
+ EXPECT_EQ(kBufferCount - 1, producer_queue_->count());
// Currently we expect no buffer to be available prior to calling
// WaitForBuffers/HandleQueueEvents.
@@ -314,23 +320,30 @@
EXPECT_EQ(1u, consumer_queue_->count());
// Reclaim released/ignored buffers.
- producer_queue_->HandleQueueEvents();
+ ASSERT_EQ(kBufferCount - 1, producer_queue_->count());
+
+ usleep(10000);
+ WaitAndHandleOnce(producer_queue_.get(), /*timeout_ms=*/100);
ASSERT_EQ(kBufferCount - 1, producer_queue_->count());
// Post another buffer.
- producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+ producer_status = producer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence);
ASSERT_TRUE(producer_status.ok());
producer_buffer = producer_status.take();
ASSERT_NE(nullptr, producer_buffer);
ASSERT_EQ(0, producer_buffer->Post<void>({}));
// Verify that the consumer queue receives it.
- EXPECT_EQ(1u, consumer_queue_->count());
- EXPECT_TRUE(consumer_queue_->HandleQueueEvents());
- EXPECT_EQ(2u, consumer_queue_->count());
+ size_t consumer_queue_count = consumer_queue_->count();
+ WaitAndHandleOnce(consumer_queue_.get(), /*timeout_ms=*/100);
+ EXPECT_LT(consumer_queue_count, consumer_queue_->count());
+
+ // Save the current consumer queue buffer count to compare after the dequeue.
+ consumer_queue_count = consumer_queue_->count();
// Dequeue and acquire/release (discard) buffers on the consumer end.
- auto consumer_status = consumer_queue_->Dequeue(0, &slot, &fence);
+ auto consumer_status =
+ consumer_queue_->Dequeue(/*timeout_ms=*/100, &slot, &fence);
ASSERT_TRUE(consumer_status.ok());
auto consumer_buffer = consumer_status.take();
ASSERT_NE(nullptr, consumer_buffer);
@@ -338,7 +351,7 @@
// Buffer should be returned to the producer queue without being handled by
// the silent consumer queue.
- EXPECT_EQ(1u, consumer_queue_->count());
+ EXPECT_GT(consumer_queue_count, consumer_queue_->count());
EXPECT_EQ(kBufferCount - 2, producer_queue_->count());
EXPECT_TRUE(producer_queue_->HandleQueueEvents());
EXPECT_EQ(kBufferCount - 1, producer_queue_->count());
@@ -362,13 +375,13 @@
for (auto mi : ms) {
size_t slot;
LocalHandle fence;
- auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
+ auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(p1_status.ok());
auto p1 = p1_status.take();
ASSERT_NE(nullptr, p1);
ASSERT_EQ(p1->Post(LocalHandle(-1), &mi, sizeof(mi)), 0);
TestMetadata mo;
- auto c1_status = consumer_queue_->Dequeue(0, &slot, &mo, &fence);
+ auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence);
ASSERT_TRUE(c1_status.ok());
auto c1 = c1_status.take();
ASSERT_EQ(mi.a, mo.a);
@@ -387,7 +400,7 @@
int64_t mi = 3;
size_t slot;
LocalHandle fence;
- auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
+ auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(p1_status.ok());
auto p1 = p1_status.take();
ASSERT_NE(nullptr, p1);
@@ -395,7 +408,7 @@
int32_t mo;
// Acquire a buffer with mismatched metadata is not OK.
- auto c1_status = consumer_queue_->Dequeue(0, &slot, &mo, &fence);
+ auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence);
ASSERT_FALSE(c1_status.ok());
}
@@ -406,14 +419,14 @@
size_t slot;
LocalHandle fence;
- auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
+ auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(p1_status.ok());
auto p1 = p1_status.take();
ASSERT_NE(nullptr, p1);
int64_t mo;
- producer_queue_->Enqueue(p1, slot);
- auto c1_status = consumer_queue_->Dequeue(0, &slot, &mo, &fence);
+ producer_queue_->Enqueue(p1, slot, 0ULL);
+ auto c1_status = consumer_queue_->Dequeue(100, &slot, &mo, &fence);
ASSERT_FALSE(c1_status.ok());
}
@@ -424,14 +437,14 @@
size_t s1;
AllocateBuffer();
LocalHandle fence;
- auto p1_status = producer_queue_->Dequeue(0, &s1, &fence);
+ auto p1_status = producer_queue_->Dequeue(100, &s1, &fence);
ASSERT_TRUE(p1_status.ok());
auto p1 = p1_status.take();
ASSERT_NE(nullptr, p1);
// producer queue is exhausted
size_t s2;
- auto p2_status = producer_queue_->Dequeue(0, &s2, &fence);
+ auto p2_status = producer_queue_->Dequeue(100, &s2, &fence);
ASSERT_FALSE(p2_status.ok());
ASSERT_EQ(ETIMEDOUT, p2_status.error());
@@ -441,7 +454,7 @@
ASSERT_EQ(producer_queue_->capacity(), 2U);
// now we can dequeue again
- p2_status = producer_queue_->Dequeue(0, &s2, &fence);
+ p2_status = producer_queue_->Dequeue(100, &s2, &fence);
ASSERT_TRUE(p2_status.ok());
auto p2 = p2_status.take();
ASSERT_NE(nullptr, p2);
@@ -456,7 +469,7 @@
int64_t seq = 1;
ASSERT_EQ(p1->Post(LocalHandle(), seq), 0);
size_t cs1, cs2;
- auto c1_status = consumer_queue_->Dequeue(0, &cs1, &seq, &fence);
+ auto c1_status = consumer_queue_->Dequeue(100, &cs1, &seq, &fence);
ASSERT_TRUE(c1_status.ok());
auto c1 = c1_status.take();
ASSERT_NE(nullptr, c1);
@@ -465,7 +478,7 @@
ASSERT_EQ(cs1, s1);
ASSERT_EQ(p2->Post(LocalHandle(), seq), 0);
- auto c2_status = consumer_queue_->Dequeue(0, &cs2, &seq, &fence);
+ auto c2_status = consumer_queue_->Dequeue(100, &cs2, &seq, &fence);
ASSERT_TRUE(c2_status.ok());
auto c2 = c2_status.take();
ASSERT_NE(nullptr, c2);
@@ -485,7 +498,7 @@
LocalHandle fence;
size_t slot;
- auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
+ auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(p1_status.ok());
auto p1 = p1_status.take();
ASSERT_EQ(p1->usage() & set_mask, set_mask);
@@ -504,7 +517,7 @@
LocalHandle fence;
size_t slot;
- auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
+ auto p1_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(p1_status.ok());
auto p1 = p1_status.take();
ASSERT_EQ(0u, p1->usage() & clear_mask);
@@ -543,9 +556,9 @@
ASSERT_TRUE(status.ok());
// While allocation without those bits should fail.
- status = producer_queue_->AllocateBuffer(
- kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage & ~deny_clear_mask);
+ status = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
+ kBufferLayerCount, kBufferFormat,
+ kBufferUsage & ~deny_clear_mask);
ASSERT_FALSE(status.ok());
ASSERT_EQ(EINVAL, status.error());
}
@@ -603,7 +616,7 @@
// Free all buffers when one buffer is dequeued.
CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
- producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+ producer_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(producer_status.ok());
status = producer_queue_->FreeAllBuffers();
EXPECT_TRUE(status.ok());
@@ -611,7 +624,7 @@
// Free all buffers when all buffers are dequeued.
CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
for (size_t i = 0; i < kBufferCount; i++) {
- producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+ producer_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(producer_status.ok());
}
status = producer_queue_->FreeAllBuffers();
@@ -619,7 +632,7 @@
// Free all buffers when one buffer is posted.
CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
- producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+ producer_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(producer_status.ok());
producer_buffer = producer_status.take();
ASSERT_NE(nullptr, producer_buffer);
@@ -630,7 +643,7 @@
// Free all buffers when all buffers are posted.
CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
for (size_t i = 0; i < kBufferCount; i++) {
- producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+ producer_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(producer_status.ok());
producer_buffer = producer_status.take();
ASSERT_NE(nullptr, producer_buffer);
@@ -642,12 +655,12 @@
// Free all buffers when all buffers are acquired.
CHECK_NO_BUFFER_THEN_ALLOCATE(kBufferCount);
for (size_t i = 0; i < kBufferCount; i++) {
- producer_status = producer_queue_->Dequeue(0, &slot, &fence);
+ producer_status = producer_queue_->Dequeue(100, &slot, &fence);
ASSERT_TRUE(producer_status.ok());
producer_buffer = producer_status.take();
ASSERT_NE(nullptr, producer_buffer);
ASSERT_EQ(0, producer_buffer->Post(fence, &seq, sizeof(seq)));
- consumer_status = consumer_queue_->Dequeue(0, &slot, &seq, &fence);
+ consumer_status = consumer_queue_->Dequeue(100, &slot, &seq, &fence);
ASSERT_TRUE(consumer_status.ok());
}
diff --git a/libs/vr/libdvr/dvr_buffer.cpp b/libs/vr/libdvr/dvr_buffer.cpp
index 4d9b215..1a99234 100644
--- a/libs/vr/libdvr/dvr_buffer.cpp
+++ b/libs/vr/libdvr/dvr_buffer.cpp
@@ -44,7 +44,13 @@
}
void dvrWriteBufferDestroy(DvrWriteBuffer* write_buffer) {
- delete write_buffer;
+ if (write_buffer != nullptr) {
+ ALOGW_IF(
+ write_buffer->slot != -1,
+ "dvrWriteBufferDestroy: Destroying a buffer associated with a valid "
+ "buffer queue slot. This may indicate possible leaks.");
+ delete write_buffer;
+ }
}
int dvrWriteBufferIsValid(DvrWriteBuffer* write_buffer) {
@@ -107,7 +113,15 @@
*read_buffer = new DvrReadBuffer;
}
-void dvrReadBufferDestroy(DvrReadBuffer* read_buffer) { delete read_buffer; }
+void dvrReadBufferDestroy(DvrReadBuffer* read_buffer) {
+ if (read_buffer != nullptr) {
+ ALOGW_IF(
+ read_buffer->slot != -1,
+ "dvrReadBufferDestroy: Destroying a buffer associated with a valid "
+ "buffer queue slot. This may indicate possible leaks.");
+ delete read_buffer;
+ }
+}
int dvrReadBufferIsValid(DvrReadBuffer* read_buffer) {
return read_buffer && read_buffer->read_buffer;
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index 4adb5d2..09a49dd 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -27,15 +27,6 @@
format_(producer_queue->default_format()) {}
int DvrWriteBufferQueue::GetNativeWindow(ANativeWindow** out_window) {
- if (producer_queue_->metadata_size() != sizeof(DvrNativeBufferMetadata)) {
- ALOGE(
- "DvrWriteBufferQueue::GetNativeWindow: The size of buffer metadata "
- "(%zu) of the write queue does not match of size of "
- "DvrNativeBufferMetadata (%zu).",
- producer_queue_->metadata_size(), sizeof(DvrNativeBufferMetadata));
- return -EINVAL;
- }
-
if (native_window_ == nullptr) {
// Lazy creation of |native_window|, as not everyone is using
// DvrWriteBufferQueue as an external surface.
@@ -64,9 +55,26 @@
int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer,
int* out_fence_fd) {
+ DvrNativeBufferMetadata meta;
+ DvrWriteBuffer* buffer = nullptr;
+ int fence_fd = -1;
+ if (const int ret = GainBuffer(timeout, &buffer, &meta, &fence_fd))
+ return ret;
+ if (!buffer)
+ return -ENOMEM;
+
+ write_buffers_[buffer->slot].reset(buffer);
+ write_buffer->write_buffer = std::move(buffer->write_buffer);
+ *out_fence_fd = fence_fd;
+ return 0;
+}
+
+int DvrWriteBufferQueue::GainBuffer(int timeout,
+ DvrWriteBuffer** out_write_buffer,
+ DvrNativeBufferMetadata* out_meta,
+ int* out_fence_fd) {
size_t slot;
- pdx::LocalHandle fence;
- std::shared_ptr<BufferProducer> buffer_producer;
+ pdx::LocalHandle release_fence;
// Need to retry N+1 times, where N is total number of buffers in the queue.
// As in the worst case, we will dequeue all N buffers and reallocate them, on
@@ -75,15 +83,29 @@
size_t retry = 0;
for (; retry < max_retries; retry++) {
- auto buffer_status = producer_queue_->Dequeue(timeout, &slot, &fence);
+ auto buffer_status =
+ producer_queue_->Dequeue(timeout, &slot, out_meta, &release_fence);
if (!buffer_status) {
ALOGE_IF(buffer_status.error() != ETIMEDOUT,
- "DvrWriteBufferQueue::Dequeue: Failed to dequeue buffer: %s",
+ "DvrWriteBufferQueue::GainBuffer: Failed to dequeue buffer: %s",
buffer_status.GetErrorMessage().c_str());
return -buffer_status.error();
}
- buffer_producer = buffer_status.take();
+ if (write_buffers_[slot] == nullptr) {
+ // Lazy initialization of a write_buffers_ slot. Note that a slot will
+ // only be dynamically allocated once during the entire cycle life of a
+ // queue.
+ write_buffers_[slot] = std::make_unique<DvrWriteBuffer>();
+ write_buffers_[slot]->slot = slot;
+ }
+
+ LOG_ALWAYS_FATAL_IF(
+ write_buffers_[slot]->write_buffer,
+ "DvrWriteBufferQueue::GainBuffer: Buffer slot is not empty: %zu", slot);
+ write_buffers_[slot]->write_buffer = std::move(buffer_status.take());
+
+ const auto& buffer_producer = write_buffers_[slot]->write_buffer;
if (!buffer_producer)
return -ENOMEM;
@@ -122,6 +144,9 @@
remove_status.GetErrorMessage().c_str());
return -remove_status.error();
}
+ // Make sure that the previously allocated buffer is dereferenced from
+ // write_buffers_ array.
+ write_buffers_[slot]->write_buffer = nullptr;
auto allocate_status = producer_queue_->AllocateBuffer(
width_, height_, old_layer_count, format_, old_usage);
@@ -139,8 +164,52 @@
return -ENOMEM;
}
- write_buffer->write_buffer = std::move(buffer_producer);
- *out_fence_fd = fence.Release();
+ *out_write_buffer = write_buffers_[slot].release();
+ *out_fence_fd = release_fence.Release();
+
+ return 0;
+}
+
+int DvrWriteBufferQueue::PostBuffer(DvrWriteBuffer* write_buffer,
+ const DvrNativeBufferMetadata* meta,
+ int ready_fence_fd) {
+ LOG_FATAL_IF(
+ (write_buffers->slot < 0 || write_buffers->slot >= write_buffers_.size()),
+ "DvrWriteBufferQueue::ReleaseBuffer: Invalid slot: %zu", slot);
+
+ // Some basic sanity checks before we put the buffer back into a slot.
+ size_t slot = static_cast<size_t>(write_buffer->slot);
+ if (write_buffers_[slot] != nullptr) {
+ ALOGE("DvrWriteBufferQueue::PostBuffer: Slot is not empty: %zu", slot);
+ return -EINVAL;
+ }
+ if (write_buffer->write_buffer == nullptr) {
+ ALOGE("DvrWriteBufferQueue::PostBuffer: Invalid write buffer.");
+ return -EINVAL;
+ }
+ if (write_buffer->write_buffer->id() != producer_queue_->GetBufferId(slot)) {
+ ALOGE(
+ "DvrWriteBufferQueue::PostBuffer: Buffer to be posted does not "
+ "belong to this buffer queue. Posting buffer: id=%d, buffer in "
+ "queue: id=%d",
+ write_buffer->write_buffer->id(), producer_queue_->GetBufferId(slot));
+ return -EINVAL;
+ }
+
+ write_buffer->write_buffer->SetQueueIndex(next_post_index_++);
+ pdx::LocalHandle fence(ready_fence_fd);
+ const int ret = write_buffer->write_buffer->PostAsync(meta, fence);
+ if (ret < 0) {
+ ALOGE("DvrWriteBufferQueue::PostBuffer: Failed to post buffer, ret=%d",
+ ret);
+ return ret;
+ }
+
+ // Put the DvrWriteBuffer pointer back into its slot for reuse.
+ write_buffers_[slot].reset(write_buffer);
+ // It's import to reset the write buffer client now. It should stay invalid
+ // until next GainBuffer on the same slot.
+ write_buffers_[slot]->write_buffer = nullptr;
return 0;
}
@@ -239,6 +308,27 @@
return write_queue->Dequeue(timeout, write_buffer, out_fence_fd);
}
+int dvrWriteBufferQueueGainBuffer(DvrWriteBufferQueue* write_queue, int timeout,
+ DvrWriteBuffer** out_write_buffer,
+ DvrNativeBufferMetadata* out_meta,
+ int* out_fence_fd) {
+ if (!write_queue || !out_write_buffer || !out_meta || !out_fence_fd)
+ return -EINVAL;
+
+ return write_queue->GainBuffer(timeout, out_write_buffer, out_meta,
+ out_fence_fd);
+}
+
+int dvrWriteBufferQueuePostBuffer(DvrWriteBufferQueue* write_queue,
+ DvrWriteBuffer* write_buffer,
+ const DvrNativeBufferMetadata* meta,
+ int ready_fence_fd) {
+ if (!write_queue || !write_buffer || !write_buffer->write_buffer || !meta)
+ return -EINVAL;
+
+ return write_queue->PostBuffer(write_buffer, meta, ready_fence_fd);
+}
+
int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue,
uint32_t width, uint32_t height) {
if (!write_queue)
@@ -291,6 +381,82 @@
read_buffer->read_buffer = buffer_status.take();
*out_fence_fd = acquire_fence.Release();
+
+ return 0;
+}
+
+int DvrReadBufferQueue::AcquireBuffer(int timeout,
+ DvrReadBuffer** out_read_buffer,
+ DvrNativeBufferMetadata* out_meta,
+ int* out_fence_fd) {
+ size_t slot;
+ pdx::LocalHandle acquire_fence;
+ auto buffer_status =
+ consumer_queue_->Dequeue(timeout, &slot, out_meta, &acquire_fence);
+ if (!buffer_status) {
+ ALOGE_IF(buffer_status.error() != ETIMEDOUT,
+ "DvrReadBufferQueue::AcquireBuffer: Failed to dequeue buffer: %s",
+ buffer_status.GetErrorMessage().c_str());
+ return -buffer_status.error();
+ }
+
+ if (read_buffers_[slot] == nullptr) {
+ // Lazy initialization of a read_buffers_ slot. Note that a slot will only
+ // be dynamically allocated once during the entire cycle life of a queue.
+ read_buffers_[slot] = std::make_unique<DvrReadBuffer>();
+ read_buffers_[slot]->slot = slot;
+ }
+
+ LOG_FATAL_IF(
+ read_buffers_[slot]->read_buffer,
+ "DvrReadBufferQueue::AcquireBuffer: Buffer slot is not empty: %zu", slot);
+ read_buffers_[slot]->read_buffer = std::move(buffer_status.take());
+
+ *out_read_buffer = read_buffers_[slot].release();
+ *out_fence_fd = acquire_fence.Release();
+
+ return 0;
+}
+
+int DvrReadBufferQueue::ReleaseBuffer(DvrReadBuffer* read_buffer,
+ const DvrNativeBufferMetadata* meta,
+ int release_fence_fd) {
+ LOG_FATAL_IF(
+ (read_buffers->slot < 0 || read_buffers->slot >= read_buffers_size()),
+ "DvrReadBufferQueue::ReleaseBuffer: Invalid slot: %zu", slot);
+
+ // Some basic sanity checks before we put the buffer back into a slot.
+ size_t slot = static_cast<size_t>(read_buffer->slot);
+ if (read_buffers_[slot] != nullptr) {
+ ALOGE("DvrReadBufferQueue::ReleaseBuffer: Slot is not empty: %zu", slot);
+ return -EINVAL;
+ }
+ if (read_buffer->read_buffer == nullptr) {
+ ALOGE("DvrReadBufferQueue::ReleaseBuffer: Invalid read buffer.");
+ return -EINVAL;
+ }
+ if (read_buffer->read_buffer->id() != consumer_queue_->GetBufferId(slot)) {
+ ALOGE(
+ "DvrReadBufferQueue::ReleaseBuffer: Buffer to be released does not "
+ "belong to this buffer queue. Releasing buffer: id=%d, buffer in "
+ "queue: id=%d",
+ read_buffer->read_buffer->id(), consumer_queue_->GetBufferId(slot));
+ return -EINVAL;
+ }
+
+ pdx::LocalHandle fence(release_fence_fd);
+ int ret = read_buffer->read_buffer->ReleaseAsync(meta, fence);
+ if (ret < 0) {
+ ALOGE("DvrReadBufferQueue::ReleaseBuffer: Failed to release buffer, ret=%d",
+ ret);
+ return ret;
+ }
+
+ // Put the DvrReadBuffer pointer back into its slot for reuse.
+ read_buffers_[slot].reset(read_buffer);
+ // It's import to reset the read buffer client now. It should stay invalid
+ // until next AcquireBuffer on the same slot.
+ read_buffers_[slot]->read_buffer = nullptr;
return 0;
}
@@ -311,9 +477,11 @@
} else {
consumer_queue_->SetBufferRemovedCallback(
[callback, context](const std::shared_ptr<BufferHubBuffer>& buffer) {
- DvrReadBuffer read_buffer{
- std::static_pointer_cast<BufferConsumer>(buffer)};
- callback(&read_buffer, context);
+ // When buffer is removed from the queue, the slot is already invalid.
+ auto read_buffer = std::make_unique<DvrReadBuffer>();
+ read_buffer->read_buffer =
+ std::static_pointer_cast<BufferConsumer>(buffer);
+ callback(read_buffer.release(), context);
});
}
}
@@ -370,6 +538,27 @@
meta_size_bytes);
}
+int dvrReadBufferQueueAcquireBuffer(DvrReadBufferQueue* read_queue, int timeout,
+ DvrReadBuffer** out_read_buffer,
+ DvrNativeBufferMetadata* out_meta,
+ int* out_fence_fd) {
+ if (!read_queue || !out_read_buffer || !out_meta || !out_fence_fd)
+ return -EINVAL;
+
+ return read_queue->AcquireBuffer(timeout, out_read_buffer, out_meta,
+ out_fence_fd);
+}
+
+int dvrReadBufferQueueReleaseBuffer(DvrReadBufferQueue* read_queue,
+ DvrReadBuffer* read_buffer,
+ const DvrNativeBufferMetadata* meta,
+ int release_fence_fd) {
+ if (!read_queue || !read_buffer || !read_buffer->read_buffer || !meta)
+ return -EINVAL;
+
+ return read_queue->ReleaseBuffer(read_buffer, meta, release_fence_fd);
+}
+
int dvrReadBufferQueueSetBufferAvailableCallback(
DvrReadBufferQueue* read_queue,
DvrReadBufferQueueBufferAvailableCallback callback, void* context) {
diff --git a/libs/vr/libdvr/dvr_buffer_queue_internal.h b/libs/vr/libdvr/dvr_buffer_queue_internal.h
index 795d6cd..e53a686 100644
--- a/libs/vr/libdvr/dvr_buffer_queue_internal.h
+++ b/libs/vr/libdvr/dvr_buffer_queue_internal.h
@@ -5,10 +5,14 @@
#include <private/dvr/buffer_hub_queue_client.h>
#include <sys/cdefs.h>
+#include <array>
#include <memory>
+#include "dvr_internal.h"
+
struct ANativeWindow;
+typedef struct DvrNativeBufferMetadata DvrNativeBufferMetadata;
typedef struct DvrReadBuffer DvrReadBuffer;
typedef struct DvrReadBufferQueue DvrReadBufferQueue;
typedef struct DvrWriteBuffer DvrWriteBuffer;
@@ -17,6 +21,7 @@
void* context);
struct DvrWriteBufferQueue {
+ using BufferHubQueue = android::dvr::BufferHubQueue;
using ProducerQueue = android::dvr::ProducerQueue;
// Create a concrete object for DvrWriteBufferQueue.
@@ -38,18 +43,27 @@
int GetNativeWindow(ANativeWindow** out_window);
int CreateReadQueue(DvrReadBufferQueue** out_read_queue);
int Dequeue(int timeout, DvrWriteBuffer* write_buffer, int* out_fence_fd);
+ int GainBuffer(int timeout, DvrWriteBuffer** out_write_buffer,
+ DvrNativeBufferMetadata* out_meta, int* out_fence_fd);
+ int PostBuffer(DvrWriteBuffer* write_buffer,
+ const DvrNativeBufferMetadata* meta, int ready_fence_fd);
int ResizeBuffer(uint32_t width, uint32_t height);
private:
std::shared_ptr<ProducerQueue> producer_queue_;
+ std::array<std::unique_ptr<DvrWriteBuffer>, BufferHubQueue::kMaxQueueCapacity>
+ write_buffers_;
+ int64_t next_post_index_ = 0;
uint32_t width_;
uint32_t height_;
uint32_t format_;
+
android::sp<android::Surface> native_window_;
};
struct DvrReadBufferQueue {
+ using BufferHubQueue = android::dvr::BufferHubQueue;
using ConsumerQueue = android::dvr::ConsumerQueue;
explicit DvrReadBufferQueue(
@@ -61,7 +75,11 @@
int CreateReadQueue(DvrReadBufferQueue** out_read_queue);
int Dequeue(int timeout, DvrReadBuffer* read_buffer, int* out_fence_fd,
- void* out_meta, size_t meta_size_bytes);
+ void* out_meta, size_t user_metadata_size);
+ int AcquireBuffer(int timeout, DvrReadBuffer** out_read_buffer,
+ DvrNativeBufferMetadata* out_meta, int* out_fence_fd);
+ int ReleaseBuffer(DvrReadBuffer* read_buffer,
+ const DvrNativeBufferMetadata* meta, int release_fence_fd);
void SetBufferAvailableCallback(
DvrReadBufferQueueBufferAvailableCallback callback, void* context);
void SetBufferRemovedCallback(
@@ -70,6 +88,8 @@
private:
std::shared_ptr<ConsumerQueue> consumer_queue_;
+ std::array<std::unique_ptr<DvrReadBuffer>, BufferHubQueue::kMaxQueueCapacity>
+ read_buffers_;
};
#endif // ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
diff --git a/libs/vr/libdvr/dvr_internal.h b/libs/vr/libdvr/dvr_internal.h
index 28b6c28..de8bb96 100644
--- a/libs/vr/libdvr/dvr_internal.h
+++ b/libs/vr/libdvr/dvr_internal.h
@@ -34,10 +34,20 @@
extern "C" {
struct DvrWriteBuffer {
+ // The slot nubmer of the buffer, a valid slot number must be in the range of
+ // [0, android::BufferQueueDefs::NUM_BUFFER_SLOTS). This is only valid for
+ // DvrWriteBuffer acquired from a DvrWriteBufferQueue.
+ int32_t slot = -1;
+
std::shared_ptr<android::dvr::BufferProducer> write_buffer;
};
struct DvrReadBuffer {
+ // The slot nubmer of the buffer, a valid slot number must be in the range of
+ // [0, android::BufferQueueDefs::NUM_BUFFER_SLOTS). This is only valid for
+ // DvrReadBuffer acquired from a DvrReadBufferQueue.
+ int32_t slot = -1;
+
std::shared_ptr<android::dvr::BufferConsumer> read_buffer;
};
diff --git a/libs/vr/libdvr/dvr_pose.cpp b/libs/vr/libdvr/dvr_pose.cpp
index 2ac3c0c..c379ef5 100644
--- a/libs/vr/libdvr/dvr_pose.cpp
+++ b/libs/vr/libdvr/dvr_pose.cpp
@@ -9,8 +9,7 @@
using android::dvr::ConsumerQueue;
-int dvrPoseClientGetDataReader(DvrPoseClient* client,
- DvrPoseRawDataType data_type,
+int dvrPoseClientGetDataReader(DvrPoseClient* client, uint64_t data_type,
DvrReadBufferQueue** queue_out) {
if (!client || !queue_out)
return -EINVAL;
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index 8d4995a..499b7c1 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -15,6 +15,12 @@
extern "C" {
#endif
+#ifdef __GNUC__
+#define ALIGNED_DVR_STRUCT(x) __attribute__((packed, aligned(x)))
+#else
+#define ALIGNED_DVR_STRUCT(x)
+#endif
+
typedef struct ANativeWindow ANativeWindow;
typedef struct DvrPoseAsync DvrPoseAsync;
@@ -34,6 +40,7 @@
typedef struct DvrReadBufferQueue DvrReadBufferQueue;
typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
+typedef struct DvrNativeBufferMetadata DvrNativeBufferMetadata;
typedef struct DvrSurface DvrSurface;
typedef uint64_t DvrSurfaceAttributeType;
@@ -180,6 +187,13 @@
int timeout,
DvrWriteBuffer* out_buffer,
int* out_fence_fd);
+typedef int (*DvrWriteBufferQueueGainBufferPtr)(
+ DvrWriteBufferQueue* write_queue, int timeout,
+ DvrWriteBuffer** out_write_buffer, DvrNativeBufferMetadata* out_meta,
+ int* out_fence_fd);
+typedef int (*DvrWriteBufferQueuePostBufferPtr)(
+ DvrWriteBufferQueue* write_queue, DvrWriteBuffer* write_buffer,
+ const DvrNativeBufferMetadata* meta, int ready_fence_fd);
typedef int (*DvrWriteBufferQueueResizeBufferPtr)(
DvrWriteBufferQueue* write_queue, uint32_t width, uint32_t height);
typedef void (*DvrReadBufferQueueDestroyPtr)(DvrReadBufferQueue* read_queue);
@@ -194,6 +208,13 @@
DvrReadBuffer* out_buffer,
int* out_fence_fd, void* out_meta,
size_t meta_size_bytes);
+typedef int (*DvrReadBufferQueueAcquireBufferPtr)(
+ DvrReadBufferQueue* read_queue, int timeout,
+ DvrReadBuffer** out_read_buffer, DvrNativeBufferMetadata* out_meta,
+ int* out_fence_fd);
+typedef int (*DvrReadBufferQueueReleaseBufferPtr)(
+ DvrReadBufferQueue* read_queue, DvrReadBuffer* read_buffer,
+ const DvrNativeBufferMetadata* meta, int release_fence_fd);
typedef void (*DvrReadBufferQueueBufferAvailableCallback)(void* context);
typedef int (*DvrReadBufferQueueSetBufferAvailableCallbackPtr)(
DvrReadBufferQueue* read_queue,
@@ -250,11 +271,11 @@
typedef int (*DvrPoseClientDataCapturePtr)(DvrPoseClient* client,
const DvrPoseDataCaptureRequest* request);
typedef int (*DvrPoseClientDataReaderDestroyPtr)(DvrPoseClient* client,
- DvrPoseRawDataType data_type);
+ uint64_t data_type);
// dvr_pose.h
typedef int (*DvrPoseClientGetDataReaderPtr)(DvrPoseClient* client,
- DvrPoseRawDataType data_type,
+ uint64_t data_type,
DvrReadBufferQueue** read_queue);
// services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
@@ -352,7 +373,24 @@
// existing data members. If new fields need to be added, please take extra care
// to make sure that new data field is padded properly the size of the struct
// stays same.
-struct DvrNativeBufferMetadata {
+struct ALIGNED_DVR_STRUCT(8) DvrNativeBufferMetadata {
+#ifdef __cplusplus
+ DvrNativeBufferMetadata()
+ : timestamp(0),
+ is_auto_timestamp(0),
+ dataspace(0),
+ crop_left(0),
+ crop_top(0),
+ crop_right(0),
+ crop_bottom(0),
+ scaling_mode(0),
+ transform(0),
+ index(0),
+ user_metadata_size(0),
+ user_metadata_ptr(0),
+ release_fence_mask(0),
+ reserved{0} {}
+#endif
// Timestamp of the frame.
int64_t timestamp;
@@ -376,10 +414,32 @@
// android/native_window.h
int32_t transform;
- // Reserved bytes for so that the struct is forward compatible.
- int32_t reserved[16];
+ // The index of the frame.
+ int64_t index;
+
+ // Size of additional metadata requested by user.
+ uint64_t user_metadata_size;
+
+ // Raw memory address of the additional user defined metadata. Only valid when
+ // user_metadata_size is non-zero.
+ uint64_t user_metadata_ptr;
+
+ // Only applicable for metadata retrieved from GainAsync. This indicates which
+ // consumer has pending fence that producer should epoll on.
+ uint64_t release_fence_mask;
+
+ // Reserved bytes for so that the struct is forward compatible and padding to
+ // 104 bytes so the size is a multiple of 8.
+ int32_t reserved[8];
};
+#ifdef __cplusplus
+// Warning: DvrNativeBufferMetadata is part of the DVR API and changing its size
+// will cause compatiblity issues between different DVR API releases.
+static_assert(sizeof(DvrNativeBufferMetadata) == 104,
+ "Unexpected size for DvrNativeBufferMetadata");
+#endif
+
struct DvrApi_v1 {
// Defines an API entry for V1 (no version suffix).
#define DVR_V1_API_ENTRY(name) Dvr##name##Ptr name
diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
index 9036773..cce8c7e 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api_entries.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
@@ -167,6 +167,12 @@
// Gets an ANativeWindow from DvrWriteBufferQueue.
DVR_V1_API_ENTRY(WriteBufferQueueGetANativeWindow);
+// Dvr{Read,Write}BufferQueue API for asynchronous IPC.
+DVR_V1_API_ENTRY(WriteBufferQueueGainBuffer);
+DVR_V1_API_ENTRY(WriteBufferQueuePostBuffer);
+DVR_V1_API_ENTRY(ReadBufferQueueAcquireBuffer);
+DVR_V1_API_ENTRY(ReadBufferQueueReleaseBuffer);
+
// Pose client
DVR_V1_API_ENTRY(PoseClientGetDataReader);
DVR_V1_API_ENTRY(PoseClientDataCapture);
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
index 8b9e048..bf695c7 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
@@ -89,21 +89,44 @@
int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
DvrReadBufferQueue** out_read_queue);
-// Dequeue a buffer to write into.
+// @deprecated Please use dvrWriteBufferQueueGainBuffer instead.
+int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
+ DvrWriteBuffer* out_buffer, int* out_fence_fd);
+
+// Gains a buffer to write into.
//
-// @param write_queue The DvrWriteBufferQueue of interest.
+// @param write_queue The DvrWriteBufferQueue to gain buffer from.
// @param timeout Specifies the number of milliseconds that the method will
// block. Specifying a timeout of -1 causes it to block indefinitely,
// while specifying a timeout equal to zero cause it to return immediately,
// even if no buffers are available.
// @param out_buffer A targeting DvrWriteBuffer object to hold the output of the
-// dequeue operation. Must be created by |dvrWriteBufferCreateEmpty|.
+// dequeue operation.
+// @param out_meta A DvrNativeBufferMetadata object populated by the
+// corresponding dvrReadBufferQueueReleaseBuffer API.
// @param out_fence_fd A sync fence fd defined in NDK's sync.h API, which
// signals the release of underlying buffer. The producer should wait until
// this fence clears before writing data into it.
// @return Zero on success, or negative error code.
-int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
- DvrWriteBuffer* out_buffer, int* out_fence_fd);
+int dvrWriteBufferQueueGainBuffer(DvrWriteBufferQueue* write_queue, int timeout,
+ DvrWriteBuffer** out_write_buffer,
+ DvrNativeBufferMetadata* out_meta,
+ int* out_fence_fd);
+
+// Posts a buffer and signals its readiness to be read from.
+//
+// @param write_queue The DvrWriteBufferQueue to post buffer into.
+// @param write_buffer The buffer to be posted.
+// @param meta The buffer metadata describing the buffer.
+// @param ready_fence_fd A sync fence fd defined in NDK's sync.h API, which
+// signals the readdiness of underlying buffer. When a valid fence gets
+// passed in, the consumer will wait the fence to be ready before it starts
+// to ready from the buffer.
+// @return Zero on success, or negative error code.
+int dvrWriteBufferQueuePostBuffer(DvrWriteBufferQueue* write_queue,
+ DvrWriteBuffer* write_buffer,
+ const DvrNativeBufferMetadata* meta,
+ int ready_fence_fd);
// Overrides buffer dimension with new width and height.
//
@@ -153,28 +176,45 @@
int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
DvrReadBufferQueue** out_read_queue);
-// Dequeue a buffer to read from.
+// @deprecated Please use dvrReadBufferQueueAcquireBuffer instead.
+int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
+ DvrReadBuffer* out_buffer, int* out_fence_fd,
+ void* out_meta, size_t meta_size_bytes);
+
+// Dequeues a buffer to read from.
//
-// @param read_queue The DvrReadBufferQueue of interest.
+// @param read_queue The DvrReadBufferQueue to acquire buffer from.
// @param timeout Specifies the number of milliseconds that the method will
// block. Specifying a timeout of -1 causes it to block indefinitely,
// while specifying a timeout equal to zero cause it to return immediately,
// even if no buffers are available.
// @param out_buffer A targeting DvrReadBuffer object to hold the output of the
// dequeue operation. Must be created by |dvrReadBufferCreateEmpty|.
+// @param out_meta A DvrNativeBufferMetadata object populated by the
+// corresponding dvrWriteBufferQueuePostBuffer API.
// @param out_fence_fd A sync fence fd defined in NDK's sync.h API, which
// signals the release of underlying buffer. The consumer should wait until
// this fence clears before reading data from it.
-// @param out_meta The memory area where a metadata object will be filled.
-// Can be nullptr iff |meta_size_bytes| is zero (i.e., there is no
-// metadata).
-// @param meta_size_bytes Size of the metadata object caller expects. If it
-// doesn't match the size of actually metadata transported by the buffer
-// queue, the method returns -EINVAL.
// @return Zero on success, or negative error code.
-int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
- DvrReadBuffer* out_buffer, int* out_fence_fd,
- void* out_meta, size_t meta_size_bytes);
+int dvrReadBufferQueueAcquireBuffer(DvrReadBufferQueue* read_queue, int timeout,
+ DvrReadBuffer** out_read_buffer,
+ DvrNativeBufferMetadata* out_meta,
+ int* out_fence_fd);
+
+// Releases a buffer and signals its readiness to be written into.
+//
+// @param read_queue The DvrReadBufferQueue to release buffer into.
+// @param read_buffer The buffer to be released.
+// @param meta The buffer metadata describing the buffer.
+// @param release_fence_fd A sync fence fd defined in NDK's sync.h API, which
+// signals the readdiness of underlying buffer. When a valid fence gets
+// passed in, the producer will wait the fence to be ready before it starts
+// to write into the buffer again.
+// @return Zero on success, or negative error code.
+int dvrReadBufferQueueReleaseBuffer(DvrReadBufferQueue* read_queue,
+ DvrReadBuffer* read_buffer,
+ const DvrNativeBufferMetadata* meta,
+ int release_fence_fd);
// Callback function which will be called when a buffer is avaiable.
//
diff --git a/libs/vr/libdvr/include/dvr/dvr_pose.h b/libs/vr/libdvr/include/dvr/dvr_pose.h
index 85631f7..8752751 100644
--- a/libs/vr/libdvr/include/dvr/dvr_pose.h
+++ b/libs/vr/libdvr/include/dvr/dvr_pose.h
@@ -99,20 +99,20 @@
} DvrPose;
// Represents a data type that can be streamed from pose service.
-typedef enum DvrPoseRawDataType {
- DVR_POSE_RAW_DATA_STEREO_IMAGE,
- DVR_POSE_RAW_DATA_POINT_CLOUD,
- DVR_POSE_RAW_DATA_FEATURES,
+enum {
+ DVR_POSE_RAW_DATA_STEREO_IMAGE = (1ULL << 0),
+ DVR_POSE_RAW_DATA_POINT_CLOUD = (1ULL << 1),
+ DVR_POSE_RAW_DATA_FEATURES = (1ULL << 2),
// Always last.
- DVR_POSE_RAW_DATA_COUNT,
-} DvrPoseRawDataType;
+ DVR_POSE_RAW_DATA_COUNT = (1ULL << 3),
+};
// A request to retrieve data from the pose service. Expects that a buffer
// queue has been initialized through dvrPoseClientGetDataReader().
typedef struct DvrPoseDataCaptureRequest {
- // The type of data to capture. Refer to enum DvrPoseRawDataType for types.
- DvrPoseRawDataType data_type;
+ // The type of data to capture. Refer to enum DVR_POSE_RAW_DATA_* for types.
+ uint64_t data_type;
// The sample interval. This can be used to skip samples. For example, a
// value of 5 will capture every fifth frame and discard the 4 frames in
// between. Set to 1 to capture all frames.
@@ -144,8 +144,7 @@
// be found in the metadata struct DvrNativeBufferMetadata, where width is
// |crop_right| and height is |crop_bottom|/2. Each image is contiguous in
// memory with stride equal to width.
-int dvrPoseClientGetDataReader(DvrPoseClient* client,
- DvrPoseRawDataType data_type,
+int dvrPoseClientGetDataReader(DvrPoseClient* client, uint64_t data_type,
DvrReadBufferQueue** queue_out);
// TODO(b/65067592): Move pose api's from pose_client.h to here.
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index ab2ee75..887766a 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -42,11 +42,13 @@
"dvr_named_buffer-test.cpp",
],
+ header_libs: ["libdvr_headers"],
static_libs: static_libraries,
shared_libs: shared_libraries,
cflags: [
"-DLOG_TAG=\"dvr_api-test\"",
"-DTRACE=0",
+ "-Wno-missing-field-initializers",
"-O0",
"-g",
],
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index 0b30c38..62cd8d4 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -27,8 +27,6 @@
static constexpr uint64_t kBufferUsage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
static constexpr size_t kQueueCapacity = 3;
-typedef uint64_t TestMeta;
-
class DvrBufferQueueTest : public ::testing::Test {
public:
static void BufferAvailableCallback(void* context) {
@@ -65,20 +63,20 @@
int buffer_removed_count_{0};
};
-TEST_F(DvrBufferQueueTest, TestWrite_QueueCreateDestroy) {
+TEST_F(DvrBufferQueueTest, WriteQueueCreateDestroy) {
int ret = dvrWriteBufferQueueCreate(
kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- /*capacity=*/0, sizeof(TestMeta), &write_queue_);
+ /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
ASSERT_EQ(0, ret);
dvrWriteBufferQueueDestroy(write_queue_);
write_queue_ = nullptr;
}
-TEST_F(DvrBufferQueueTest, TestWrite_QueueGetCapacity) {
+TEST_F(DvrBufferQueueTest, WriteQueueGetCapacity) {
int ret = dvrWriteBufferQueueCreate(
kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- kQueueCapacity, sizeof(TestMeta), &write_queue_);
+ kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
ASSERT_EQ(0, ret);
size_t capacity = dvrWriteBufferQueueGetCapacity(write_queue_);
@@ -87,10 +85,10 @@
ASSERT_EQ(kQueueCapacity, capacity);
}
-TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromWriteQueue) {
+TEST_F(DvrBufferQueueTest, CreateReadQueueFromWriteQueue) {
int ret = dvrWriteBufferQueueCreate(
kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- /*capacity=*/0, sizeof(TestMeta), &write_queue_);
+ /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
ASSERT_EQ(0, ret);
DvrReadBufferQueue* read_queue = nullptr;
@@ -102,10 +100,10 @@
dvrReadBufferQueueDestroy(read_queue);
}
-TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromReadQueue) {
+TEST_F(DvrBufferQueueTest, CreateReadQueueFromReadQueue) {
int ret = dvrWriteBufferQueueCreate(
kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- /*capacity=*/0, sizeof(TestMeta), &write_queue_);
+ /*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
ASSERT_EQ(0, ret);
DvrReadBufferQueue* read_queue1 = nullptr;
@@ -124,102 +122,86 @@
dvrReadBufferQueueDestroy(read_queue2);
}
-TEST_F(DvrBufferQueueTest, CreateEmptyBuffer) {
+TEST_F(DvrBufferQueueTest, GainBuffer) {
int ret = dvrWriteBufferQueueCreate(
kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- kQueueCapacity, sizeof(TestMeta), &write_queue_);
- ASSERT_EQ(0, ret);
+ kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
+ ASSERT_EQ(ret, 0);
- DvrReadBuffer* read_buffer = nullptr;
- DvrWriteBuffer* write_buffer = nullptr;
+ DvrWriteBuffer* wb = nullptr;
+ EXPECT_FALSE(dvrWriteBufferIsValid(wb));
- EXPECT_FALSE(dvrReadBufferIsValid(read_buffer));
- EXPECT_FALSE(dvrWriteBufferIsValid(write_buffer));
-
- dvrReadBufferCreateEmpty(&read_buffer);
- ASSERT_NE(nullptr, read_buffer);
-
- dvrWriteBufferCreateEmpty(&write_buffer);
- ASSERT_NE(nullptr, write_buffer);
-
- EXPECT_FALSE(dvrReadBufferIsValid(read_buffer));
- EXPECT_FALSE(dvrWriteBufferIsValid(write_buffer));
-
- DvrReadBufferQueue* read_queue = nullptr;
-
- ASSERT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
-
- const int kTimeoutMs = 0;
+ DvrNativeBufferMetadata meta;
int fence_fd = -1;
- ASSERT_EQ(0, dvrWriteBufferQueueDequeue(write_queue_, kTimeoutMs,
- write_buffer, &fence_fd));
- EXPECT_EQ(-1, fence_fd);
- EXPECT_TRUE(dvrWriteBufferIsValid(write_buffer));
-
- ASSERT_EQ(0, dvrWriteBufferClear(write_buffer));
- EXPECT_FALSE(dvrWriteBufferIsValid(write_buffer));
+ ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta,
+ &fence_fd);
+ ASSERT_EQ(ret, 0);
+ EXPECT_EQ(fence_fd, -1);
+ EXPECT_NE(wb, nullptr);
+ EXPECT_TRUE(dvrWriteBufferIsValid(wb));
}
-TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) {
+TEST_F(DvrBufferQueueTest, AcquirePostGainRelease) {
int ret = dvrWriteBufferQueueCreate(
kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- kQueueCapacity, sizeof(TestMeta), &write_queue_);
- ASSERT_EQ(0, ret);
+ kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
+ ASSERT_EQ(ret, 0);
- static constexpr int kTimeout = 0;
DvrReadBufferQueue* read_queue = nullptr;
DvrReadBuffer* rb = nullptr;
DvrWriteBuffer* wb = nullptr;
+ DvrNativeBufferMetadata meta1;
+ DvrNativeBufferMetadata meta2;
int fence_fd = -1;
ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
- ASSERT_EQ(0, ret);
- ASSERT_NE(nullptr, read_queue);
+ ASSERT_EQ(ret, 0);
+ ASSERT_NE(read_queue, nullptr);
dvrReadBufferQueueSetBufferAvailableCallback(read_queue,
&BufferAvailableCallback, this);
- dvrWriteBufferCreateEmpty(&wb);
- ASSERT_NE(nullptr, wb);
-
- dvrReadBufferCreateEmpty(&rb);
- ASSERT_NE(nullptr, rb);
-
// Gain buffer for writing.
- ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb, &fence_fd);
- ASSERT_EQ(0, ret);
+ ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb, &meta1,
+ &fence_fd);
+ ASSERT_EQ(ret, 0);
+ ASSERT_NE(wb, nullptr);
ASSERT_TRUE(dvrWriteBufferIsValid(wb));
ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, gain buffer %p, fence_fd=%d",
wb, fence_fd);
android::base::unique_fd release_fence(fence_fd);
// Post buffer to the read_queue.
- TestMeta seq = 42U;
- ret = dvrWriteBufferPost(wb, /* fence */ -1, &seq, sizeof(seq));
- ASSERT_EQ(0, ret);
- dvrWriteBufferDestroy(wb);
+ meta1.timestamp = 42;
+ ret = dvrWriteBufferQueuePostBuffer(write_queue_, wb, &meta1, /*fence=*/-1);
+ ASSERT_EQ(ret, 0);
+ ASSERT_FALSE(dvrWriteBufferIsValid(wb));
wb = nullptr;
// Acquire buffer for reading.
- TestMeta acquired_seq = 0U;
- ret = dvrReadBufferQueueDequeue(read_queue, kTimeout, rb, &fence_fd,
- &acquired_seq, sizeof(acquired_seq));
- ASSERT_EQ(0, ret);
+ ret = dvrReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10, &rb, &meta2,
+ &fence_fd);
+ ASSERT_EQ(ret, 0);
+ ASSERT_NE(rb, nullptr);
// Dequeue is successfully, BufferAvailableCallback should be fired once.
- ASSERT_EQ(1, buffer_available_count_);
+ ASSERT_EQ(buffer_available_count_, 1);
ASSERT_TRUE(dvrReadBufferIsValid(rb));
- ASSERT_EQ(seq, acquired_seq);
+
+ // Metadata should be passed along from producer to consumer properly.
+ ASSERT_EQ(meta1.timestamp, meta2.timestamp);
+
ALOGD_IF(TRACE,
"TestDequeuePostDequeueRelease, acquire buffer %p, fence_fd=%d", rb,
fence_fd);
android::base::unique_fd acquire_fence(fence_fd);
// Release buffer to the write_queue.
- ret = dvrReadBufferRelease(rb, -1);
- ASSERT_EQ(0, ret);
- dvrReadBufferDestroy(rb);
+ ret = dvrReadBufferQueueReleaseBuffer(read_queue, rb, &meta2,
+ /*release_fence_fd=*/-1);
+ ASSERT_EQ(ret, 0);
+ ASSERT_FALSE(dvrReadBufferIsValid(rb));
rb = nullptr;
// TODO(b/34387835) Currently buffer allocation has to happen after all queues
@@ -232,37 +214,18 @@
dvrReadBufferQueueDestroy(read_queue);
}
-TEST_F(DvrBufferQueueTest, TestGetANativeWindow) {
+TEST_F(DvrBufferQueueTest, GetANativeWindow) {
int ret = dvrWriteBufferQueueCreate(
kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- /*capacity=*/0, sizeof(TestMeta), &write_queue_);
- ASSERT_EQ(0, ret);
-
- ANativeWindow* window = nullptr;
-
- // The |write_queue_| doesn't have proper metadata (must be
- // DvrNativeBufferMetadata) configured during creation.
- ret = dvrWriteBufferQueueGetANativeWindow(write_queue_, &window);
- ASSERT_EQ(-EINVAL, ret);
- ASSERT_EQ(nullptr, window);
- dvrWriteBufferQueueDestroy(write_queue_);
- write_queue_ = nullptr;
-
- // A write queue with DvrNativeBufferMetadata should work fine.
- ASSERT_EQ(nullptr, write_queue_);
-
- ret = dvrWriteBufferQueueCreate(
- kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
/*capacity=*/0, sizeof(DvrNativeBufferMetadata), &write_queue_);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, write_queue_);
+ ANativeWindow* window = nullptr;
ret = dvrWriteBufferQueueGetANativeWindow(write_queue_, &window);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, window);
- // TODO(b/64723700): Remove dependencies of Android platform bits so that we
- // can run dvr_buffer_queue-test in DTS.
uint32_t width = ANativeWindow_getWidth(window);
uint32_t height = ANativeWindow_getHeight(window);
uint32_t format = ANativeWindow_getFormat(window);
@@ -274,15 +237,15 @@
// Create buffer queue of three buffers and dequeue three buffers out of it.
// Before each dequeue operation, we resize the buffer queue and expect the
// queue always return buffer with desired dimension.
-TEST_F(DvrBufferQueueTest, TestResizeBuffer) {
+TEST_F(DvrBufferQueueTest, ResizeBuffer) {
int ret = dvrWriteBufferQueueCreate(
kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- kQueueCapacity, sizeof(TestMeta), &write_queue_);
+ kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
ASSERT_EQ(0, ret);
- static constexpr int kTimeout = 0;
int fence_fd = -1;
+ DvrNativeBufferMetadata meta;
DvrReadBufferQueue* read_queue = nullptr;
DvrWriteBuffer* wb1 = nullptr;
DvrWriteBuffer* wb2 = nullptr;
@@ -300,13 +263,6 @@
dvrReadBufferQueueSetBufferRemovedCallback(read_queue, &BufferRemovedCallback,
this);
- dvrWriteBufferCreateEmpty(&wb1);
- ASSERT_NE(nullptr, wb1);
- dvrWriteBufferCreateEmpty(&wb2);
- ASSERT_NE(nullptr, wb2);
- dvrWriteBufferCreateEmpty(&wb3);
- ASSERT_NE(nullptr, wb3);
-
// Handle all pending events on the read queue.
ret = dvrReadBufferQueueHandleEvents(read_queue);
ASSERT_EQ(0, ret);
@@ -321,7 +277,8 @@
ASSERT_EQ(0, ret);
// Gain first buffer for writing. All buffers will be resized.
- ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb1, &fence_fd);
+ ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb1, &meta,
+ &fence_fd);
ASSERT_EQ(0, ret);
ASSERT_TRUE(dvrWriteBufferIsValid(wb1));
ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p", wb1);
@@ -347,7 +304,8 @@
ASSERT_EQ(0, ret);
// The next buffer we dequeued should have new width.
- ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb2, &fence_fd);
+ ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb2, &meta,
+ &fence_fd);
ASSERT_EQ(0, ret);
ASSERT_TRUE(dvrWriteBufferIsValid(wb2));
ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb2,
@@ -373,7 +331,8 @@
ASSERT_EQ(0, ret);
// The next buffer we dequeued should have new width.
- ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb3, &fence_fd);
+ ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/0, &wb3, &meta,
+ &fence_fd);
ASSERT_EQ(0, ret);
ASSERT_TRUE(dvrWriteBufferIsValid(wb3));
ALOGD_IF(TRACE, "TestResizeBuffer, gain buffer %p, fence_fd=%d", wb3,
@@ -396,78 +355,10 @@
dvrReadBufferQueueDestroy(read_queue);
}
-TEST_F(DvrBufferQueueTest, DequeueEmptyMetadata) {
- // Overrides default queue parameters: Empty metadata.
+TEST_F(DvrBufferQueueTest, ReadQueueEventFd) {
int ret = dvrWriteBufferQueueCreate(
kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- /*capacity=*/1, /*metadata_size=*/0, &write_queue_);
- ASSERT_EQ(0, ret);
-
- DvrReadBuffer* rb = nullptr;
- DvrWriteBuffer* wb = nullptr;
- dvrReadBufferCreateEmpty(&rb);
- dvrWriteBufferCreateEmpty(&wb);
-
- DvrReadBufferQueue* read_queue = nullptr;
- EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
-
- const int kTimeoutMs = 0;
- int fence_fd = -1;
- EXPECT_EQ(0, dvrWriteBufferQueueDequeue(write_queue_, 0, wb, &fence_fd));
-
- EXPECT_EQ(0, dvrWriteBufferPost(wb, /*fence=*/-1, nullptr, 0));
- EXPECT_EQ(0, dvrWriteBufferClear(wb));
- dvrWriteBufferDestroy(wb);
- wb = nullptr;
-
- // When acquire buffer, it's legit to pass nullptr as out_meta iff metadata
- // size is Zero.
- EXPECT_EQ(0, dvrReadBufferQueueDequeue(read_queue, kTimeoutMs, rb, &fence_fd,
- nullptr, 0));
- EXPECT_TRUE(dvrReadBufferIsValid(rb));
-}
-
-TEST_F(DvrBufferQueueTest, DequeueMismatchMetadata) {
- int ret = dvrWriteBufferQueueCreate(
- kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- /*capacity=*/1, sizeof(TestMeta), &write_queue_);
- ASSERT_EQ(0, ret);
-
- DvrReadBuffer* rb = nullptr;
- DvrWriteBuffer* wb = nullptr;
- dvrReadBufferCreateEmpty(&rb);
- dvrWriteBufferCreateEmpty(&wb);
-
- DvrReadBufferQueue* read_queue = nullptr;
- EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
-
- const int kTimeoutMs = 0;
- int fence_fd = -1;
- EXPECT_EQ(0, dvrWriteBufferQueueDequeue(write_queue_, 0, wb, &fence_fd));
-
- TestMeta seq = 42U;
- EXPECT_EQ(0, dvrWriteBufferPost(wb, /*fence=*/-1, &seq, sizeof(seq)));
- EXPECT_EQ(0, dvrWriteBufferClear(wb));
- dvrWriteBufferDestroy(wb);
- wb = nullptr;
-
- // Dequeue with wrong metadata will cause EINVAL.
- int8_t wrong_metadata;
- EXPECT_EQ(-EINVAL,
- dvrReadBufferQueueDequeue(read_queue, kTimeoutMs, rb, &fence_fd,
- &wrong_metadata, sizeof(wrong_metadata)));
- EXPECT_FALSE(dvrReadBufferIsValid(rb));
-
- // Dequeue with empty metadata will cause EINVAL.
- EXPECT_EQ(-EINVAL, dvrReadBufferQueueDequeue(read_queue, kTimeoutMs, rb,
- &fence_fd, nullptr, 0));
- EXPECT_FALSE(dvrReadBufferIsValid(rb));
-}
-
-TEST_F(DvrBufferQueueTest, TestReadQueueEventFd) {
- int ret = dvrWriteBufferQueueCreate(
- kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- kQueueCapacity, sizeof(TestMeta), &write_queue_);
+ kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
ASSERT_EQ(0, ret);
DvrReadBufferQueue* read_queue = nullptr;
@@ -483,10 +374,10 @@
// Verifies a Dvr{Read,Write}BufferQueue contains the same set of
// Dvr{Read,Write}Buffer(s) during their lifecycles. And for the same buffer_id,
// the corresponding AHardwareBuffer handle stays the same.
-TEST_F(DvrBufferQueueTest, TestStableBufferIdAndHardwareBuffer) {
+TEST_F(DvrBufferQueueTest, StableBufferIdAndHardwareBuffer) {
int ret = dvrWriteBufferQueueCreate(
kBufferWidth, kBufferHeight, kBufferFormat, kLayerCount, kBufferUsage,
- kQueueCapacity, sizeof(TestMeta), &write_queue_);
+ kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_);
ASSERT_EQ(0, ret);
int fence_fd = -1;
@@ -497,25 +388,21 @@
std::array<DvrReadBuffer*, kQueueCapacity> rbs;
// Write buffers.
std::array<DvrWriteBuffer*, kQueueCapacity> wbs;
+ // Buffer metadata.
+ std::array<DvrNativeBufferMetadata, kQueueCapacity> metas;
// Hardware buffers for Read buffers.
std::unordered_map<int, AHardwareBuffer*> rhbs;
// Hardware buffers for Write buffers.
std::unordered_map<int, AHardwareBuffer*> whbs;
- for (size_t i = 0; i < kQueueCapacity; i++) {
- dvrReadBufferCreateEmpty(&rbs[i]);
- dvrWriteBufferCreateEmpty(&wbs[i]);
- }
-
constexpr int kNumTests = 100;
- constexpr int kTimeout = 0;
- TestMeta seq = 0U;
// This test runs the following operations many many times. Thus we prefer to
// use ASSERT_XXX rather than EXPECT_XXX to avoid spamming the output.
std::function<void(size_t i)> Gain = [&](size_t i) {
- ASSERT_EQ(0, dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wbs[i],
- &fence_fd));
+ int ret = dvrWriteBufferQueueGainBuffer(write_queue_, /*timeout=*/10,
+ &wbs[i], &metas[i], &fence_fd);
+ ASSERT_EQ(ret, 0);
ASSERT_LT(fence_fd, 0); // expect invalid fence.
ASSERT_TRUE(dvrWriteBufferIsValid(wbs[i]));
int buffer_id = dvrWriteBufferGetId(wbs[i]);
@@ -540,15 +427,16 @@
std::function<void(size_t i)> Post = [&](size_t i) {
ASSERT_TRUE(dvrWriteBufferIsValid(wbs[i]));
- seq++;
- ASSERT_EQ(0, dvrWriteBufferPost(wbs[i], /*fence=*/-1, &seq, sizeof(seq)));
+ metas[i].timestamp++;
+ int ret = dvrWriteBufferQueuePostBuffer(write_queue_, wbs[i], &metas[i],
+ /*fence=*/-1);
+ ASSERT_EQ(ret, 0);
};
std::function<void(size_t i)> Acquire = [&](size_t i) {
- TestMeta out_seq = 0U;
- ASSERT_EQ(0,
- dvrReadBufferQueueDequeue(read_queue, kTimeout, rbs[i], &fence_fd,
- &out_seq, sizeof(out_seq)));
+ int ret = dvrReadBufferQueueAcquireBuffer(read_queue, /*timeout=*/10,
+ &rbs[i], &metas[i], &fence_fd);
+ ASSERT_EQ(ret, 0);
ASSERT_LT(fence_fd, 0); // expect invalid fence.
ASSERT_TRUE(dvrReadBufferIsValid(rbs[i]));
@@ -574,8 +462,9 @@
std::function<void(size_t i)> Release = [&](size_t i) {
ASSERT_TRUE(dvrReadBufferIsValid(rbs[i]));
- seq++;
- ASSERT_EQ(0, dvrReadBufferRelease(rbs[i], /*fence=*/-1));
+ int ret = dvrReadBufferQueueReleaseBuffer(read_queue, rbs[i], &metas[i],
+ /*release_fence_fd=*/-1);
+ ASSERT_EQ(ret, 0);
};
// Scenario one:
@@ -630,12 +519,6 @@
ASSERT_NO_FATAL_FAILURE(Release(kQueueCapacity - 1 - i));
}
}
-
- // Clean up all read buffers and write buffers.
- for (size_t i = 0; i < kQueueCapacity; i++) {
- dvrReadBufferDestroy(rbs[i]);
- dvrWriteBufferDestroy(wbs[i]);
- }
}
} // namespace
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp
index 8fce140..10c0b31 100644
--- a/libs/vr/libpdx/Android.bp
+++ b/libs/vr/libpdx/Android.bp
@@ -36,6 +36,7 @@
"variant_tests.cpp",
],
static_libs: [
+ "libcutils",
"libgmock",
"libpdx",
"liblog",
diff --git a/libs/vr/libpdx/private/pdx/client_channel.h b/libs/vr/libpdx/private/pdx/client_channel.h
index dbfd626..10a49bb 100644
--- a/libs/vr/libpdx/private/pdx/client_channel.h
+++ b/libs/vr/libpdx/private/pdx/client_channel.h
@@ -1,6 +1,8 @@
#ifndef ANDROID_PDX_CLIENT_CHANNEL_H_
#define ANDROID_PDX_CLIENT_CHANNEL_H_
+#include <vector>
+
#include <pdx/channel_handle.h>
#include <pdx/file_handle.h>
#include <pdx/status.h>
@@ -20,6 +22,15 @@
virtual int event_fd() const = 0;
virtual Status<int> GetEventMask(int events) = 0;
+ struct EventSource {
+ int event_fd;
+ int event_mask;
+ };
+
+ // Returns a set of event-generating fds with and event mask for each. These
+ // fds are owned by the ClientChannel and must never be closed by the caller.
+ virtual std::vector<EventSource> GetEventSources() const = 0;
+
virtual LocalChannelHandle& GetChannelHandle() = 0;
virtual void* AllocateTransactionState() = 0;
virtual void FreeTransactionState(void* state) = 0;
diff --git a/libs/vr/libpdx/private/pdx/mock_client_channel.h b/libs/vr/libpdx/private/pdx/mock_client_channel.h
index 561c939..49e0682 100644
--- a/libs/vr/libpdx/private/pdx/mock_client_channel.h
+++ b/libs/vr/libpdx/private/pdx/mock_client_channel.h
@@ -11,6 +11,7 @@
public:
MOCK_CONST_METHOD0(GetIpcTag, uint32_t());
MOCK_CONST_METHOD0(event_fd, int());
+ MOCK_CONST_METHOD0(GetEventSources, std::vector<EventSource>());
MOCK_METHOD1(GetEventMask, Status<int>(int));
MOCK_METHOD0(GetChannelHandle, LocalChannelHandle&());
MOCK_METHOD0(AllocateTransactionState, void*());
diff --git a/libs/vr/libpdx/private/pdx/trace.h b/libs/vr/libpdx/private/pdx/trace.h
index ebe8491..c687fd6 100644
--- a/libs/vr/libpdx/private/pdx/trace.h
+++ b/libs/vr/libpdx/private/pdx/trace.h
@@ -1,35 +1,82 @@
#ifndef ANDROID_PDX_TRACE_H_
#define ANDROID_PDX_TRACE_H_
-// Tracing utilities for libpdx. Tracing in the service framework is enabled
-// under these conditions:
-// 1. ATRACE_TAG is defined, AND
-// 2. ATRACE_TAG does not equal ATRACE_TAG_NEVER, AND
-// 3. PDX_TRACE_ENABLED is defined, AND
-// 4. PDX_TRACE_ENABLED is equal to logical true.
-//
-// If any of these conditions are not met tracing is completely removed from the
-// library and headers.
+#include <array>
-// If ATRACE_TAG is not defined, default to never.
-#ifndef ATRACE_TAG
-#define ATRACE_TAG ATRACE_TAG_NEVER
-#endif
-
-// Include tracing functions after the trace tag is defined.
#include <utils/Trace.h>
-// If PDX_TRACE_ENABLED is not defined, default to off.
-#ifndef PDX_TRACE_ENABLED
-#define PDX_TRACE_ENABLED 0
+// Enables internal tracing in libpdx. This is disabled by default to avoid
+// spamming the trace buffers during normal trace activities. libpdx must be
+// built with this set to true to enable internal tracing.
+#ifndef PDX_LIB_TRACE_ENABLED
+#define PDX_LIB_TRACE_ENABLED false
#endif
-#if (ATRACE_TAG) != (ATRACE_TAG_NEVER) && (PDX_TRACE_ENABLED)
-#define PDX_TRACE_NAME ATRACE_NAME
-#else
-#define PDX_TRACE_NAME(name) \
- do { \
- } while (0)
-#endif
+namespace android {
+namespace pdx {
+
+// Utility to generate scoped tracers with arguments.
+class ScopedTraceArgs {
+ public:
+ template <typename... Args>
+ ScopedTraceArgs(uint64_t tag, const char* format, Args&&... args)
+ : tag_{tag} {
+ if (atrace_is_tag_enabled(tag_)) {
+ std::array<char, 1024> buffer;
+ snprintf(buffer.data(), buffer.size(), format,
+ std::forward<Args>(args)...);
+ atrace_begin(tag_, buffer.data());
+ }
+ }
+
+ ~ScopedTraceArgs() { atrace_end(tag_); }
+
+ private:
+ uint64_t tag_;
+
+ ScopedTraceArgs(const ScopedTraceArgs&) = delete;
+ void operator=(const ScopedTraceArgs&) = delete;
+};
+
+// Utility to generate scoped tracers.
+class ScopedTrace {
+ public:
+ template <typename... Args>
+ ScopedTrace(uint64_t tag, bool enabled, const char* name)
+ : tag_{tag}, enabled_{enabled} {
+ if (enabled_)
+ atrace_begin(tag_, name);
+ }
+
+ ~ScopedTrace() {
+ if (enabled_)
+ atrace_end(tag_);
+ }
+
+ private:
+ uint64_t tag_;
+ bool enabled_;
+
+ ScopedTrace(const ScopedTrace&) = delete;
+ void operator=(const ScopedTrace&) = delete;
+};
+
+} // namespace pdx
+} // namespace android
+
+// Macro to define a scoped tracer with arguments. Uses PASTE(x, y) macro
+// defined in utils/Trace.h.
+#define PDX_TRACE_FORMAT(format, ...) \
+ ::android::pdx::ScopedTraceArgs PASTE(__tracer, __LINE__) { \
+ ATRACE_TAG, format, ##__VA_ARGS__ \
+ }
+
+// TODO(eieio): Rename this to PDX_LIB_TRACE_NAME() for internal use by libpdx
+// and rename internal uses inside the library. This version is only enabled
+// when PDX_LIB_TRACE_ENABLED is true.
+#define PDX_TRACE_NAME(name) \
+ ::android::pdx::ScopedTrace PASTE(__tracer, __LINE__) { \
+ ATRACE_TAG, PDX_LIB_TRACE_ENABLED, name \
+ }
#endif // ANDROID_PDX_TRACE_H_
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index 0f6511b..f891c59 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -42,6 +42,7 @@
"pdx_tool.cpp",
],
shared_libs: [
+ "libcutils",
"liblog",
],
static_libs: [
diff --git a/libs/vr/libpdx_uds/channel_event_set.cpp b/libs/vr/libpdx_uds/channel_event_set.cpp
index ebe7cea..c68968e 100644
--- a/libs/vr/libpdx_uds/channel_event_set.cpp
+++ b/libs/vr/libpdx_uds/channel_event_set.cpp
@@ -1,6 +1,10 @@
#include "private/uds/channel_event_set.h"
+#include <errno.h>
#include <log/log.h>
+#include <poll.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
#include <uds/ipc_helper.h>
@@ -8,41 +12,34 @@
namespace pdx {
namespace uds {
-ChannelEventSet::ChannelEventSet() {
- const int flags = EFD_CLOEXEC | EFD_NONBLOCK;
- LocalHandle epoll_fd, event_fd;
+namespace {
- if (!SetupHandle(epoll_create1(EPOLL_CLOEXEC), &epoll_fd, "epoll") ||
- !SetupHandle(eventfd(0, flags), &event_fd, "event")) {
- return;
- }
-
- epoll_event event;
- event.events = 0;
- event.data.u32 = 0;
- if (epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, event_fd.Get(), &event) < 0) {
- const int error = errno;
- ALOGE("ChannelEventSet::ChannelEventSet: Failed to add event_fd: %s",
- strerror(error));
- return;
- }
-
- epoll_fd_ = std::move(epoll_fd);
- event_fd_ = std::move(event_fd);
-}
-
-Status<void> ChannelEventSet::AddDataFd(const LocalHandle& data_fd) {
- epoll_event event;
- event.events = EPOLLHUP | EPOLLRDHUP;
- event.data.u32 = event.events;
- if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_ADD, data_fd.Get(), &event) < 0) {
- const int error = errno;
- ALOGE("ChannelEventSet::ChannelEventSet: Failed to add event_fd: %s",
+template <typename FileHandleType>
+Status<void> SetupHandle(int fd, FileHandleType* handle,
+ const char* error_name) {
+ const int error = errno;
+ handle->Reset(fd);
+ if (!*handle) {
+ ALOGE("SetupHandle: Failed to setup %s handle: %s", error_name,
strerror(error));
return ErrorStatus{error};
- } else {
- return {};
}
+ return {};
+}
+
+} // anonymous namespace
+
+ChannelEventSet::ChannelEventSet() {
+ const int flags = EFD_CLOEXEC | EFD_NONBLOCK;
+ LocalHandle pollin_event_fd, pollhup_event_fd;
+
+ if (!SetupHandle(eventfd(0, flags), &pollin_event_fd, "pollin_event") ||
+ !SetupHandle(eventfd(0, flags), &pollhup_event_fd, "pollhup_event")) {
+ return;
+ }
+
+ pollin_event_fd_ = std::move(pollin_event_fd);
+ pollhup_event_fd_ = std::move(pollhup_event_fd);
}
int ChannelEventSet::ModifyEvents(int clear_mask, int set_mask) {
@@ -51,66 +48,101 @@
const int old_bits = event_bits_;
const int new_bits = (event_bits_ & ~clear_mask) | set_mask;
event_bits_ = new_bits;
+ eventfd_t value;
- // If anything changed clear the event and update the event mask.
- if (old_bits != new_bits) {
- eventfd_t value;
- eventfd_read(event_fd_.Get(), &value);
+ // Calculate which bits changed and how. Bits that haven't changed since last
+ // modification will not change the state of an eventfd.
+ const int set_bits = new_bits & ~old_bits;
+ const int clear_bits = ~new_bits & old_bits;
- epoll_event event;
- event.events = POLLIN;
- event.data.u32 = event_bits_;
- if (epoll_ctl(epoll_fd_.Get(), EPOLL_CTL_MOD, event_fd_.Get(), &event) <
- 0) {
- const int error = errno;
- ALOGE("ChannelEventSet::AddEventHandle: Failed to update event: %s",
- strerror(error));
- return -error;
- }
- }
+ if (set_bits & EPOLLIN)
+ eventfd_write(pollin_event_fd_.Get(), 1);
+ else if (clear_bits & EPOLLIN)
+ eventfd_read(pollin_event_fd_.Get(), &value);
- // If there are any bits set, re-trigger the eventfd.
- if (new_bits)
- eventfd_write(event_fd_.Get(), 1);
+ if (set_bits & EPOLLHUP)
+ eventfd_write(pollhup_event_fd_.Get(), 1);
+ else if (clear_bits & EPOLLHUP)
+ eventfd_read(pollhup_event_fd_.Get(), &value);
return 0;
}
-Status<void> ChannelEventSet::SetupHandle(int fd, LocalHandle* handle,
- const char* error_name) {
- const int error = errno;
- handle->Reset(fd);
- if (!*handle) {
- ALOGE("ChannelEventSet::SetupHandle: Failed to setup %s handle: %s",
- error_name, strerror(error));
+ChannelEventReceiver::ChannelEventReceiver(LocalHandle data_fd,
+ LocalHandle pollin_event_fd,
+ LocalHandle pollhup_event_fd) {
+ LocalHandle epoll_fd;
+ if (!SetupHandle(epoll_create1(EPOLL_CLOEXEC), &epoll_fd, "epoll")) {
+ return;
+ }
+
+ epoll_event event;
+ event.events = EPOLLHUP | EPOLLRDHUP;
+ event.data.u32 = 0;
+ if (epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, data_fd.Get(), &event) < 0) {
+ const int error = errno;
+ ALOGE("ChannelEventSet::ChannelEventSet: Failed to add data_fd: %s",
+ strerror(error));
+ return;
+ }
+
+ event.events = EPOLLIN;
+ event.data.u32 = 0;
+ if (epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, pollin_event_fd.Get(), &event) <
+ 0) {
+ const int error = errno;
+ ALOGE("ChannelEventSet::ChannelEventSet: Failed to add pollin_event_fd: %s",
+ strerror(error));
+ return;
+ }
+
+ event.events = EPOLLIN;
+ event.data.u32 = 0;
+ if (epoll_ctl(epoll_fd.Get(), EPOLL_CTL_ADD, pollhup_event_fd.Get(), &event) <
+ 0) {
+ const int error = errno;
+ ALOGE(
+ "ChannelEventSet::ChannelEventSet: Failed to add pollhup_event_fd: %s",
+ strerror(error));
+ return;
+ }
+
+ pollin_event_fd_ = std::move(pollin_event_fd);
+ pollhup_event_fd_ = std::move(pollhup_event_fd);
+ data_fd_ = std::move(data_fd);
+ epoll_fd_ = std::move(epoll_fd);
+}
+
+Status<int> ChannelEventReceiver::PollPendingEvents(int timeout_ms) const {
+ std::array<pollfd, 3> pfds = {{{pollin_event_fd_.Get(), POLLIN, 0},
+ {pollhup_event_fd_.Get(), POLLIN, 0},
+ {data_fd_.Get(), POLLHUP | POLLRDHUP, 0}}};
+ if (RETRY_EINTR(poll(pfds.data(), pfds.size(), timeout_ms)) < 0) {
+ const int error = errno;
+ ALOGE(
+ "ChannelEventReceiver::PollPendingEvents: Failed to poll for events: "
+ "%s",
+ strerror(error));
return ErrorStatus{error};
}
- return {};
+
+ const int event_mask =
+ ((pfds[0].revents & POLLIN) ? EPOLLIN : 0) |
+ ((pfds[1].revents & POLLIN) ? EPOLLHUP : 0) |
+ ((pfds[2].revents & (POLLHUP | POLLRDHUP)) ? EPOLLHUP : 0);
+ return {event_mask};
}
Status<int> ChannelEventReceiver::GetPendingEvents() const {
constexpr long kTimeoutMs = 0;
- epoll_event event;
- const int count =
- RETRY_EINTR(epoll_wait(epoll_fd_.Get(), &event, 1, kTimeoutMs));
+ return PollPendingEvents(kTimeoutMs);
+}
- Status<int> status;
- if (count < 0) {
- status.SetError(errno);
- ALOGE("ChannelEventReceiver::GetPendingEvents: Failed to get events: %s",
- status.GetErrorMessage().c_str());
- return status;
- } else if (count == 0) {
- status.SetError(ETIMEDOUT);
- return status;
- }
-
- const int mask_out = event.data.u32;
- ALOGD_IF(TRACE, "ChannelEventReceiver::GetPendingEvents: mask_out=%x",
- mask_out);
-
- status.SetValue(mask_out);
- return status;
+std::vector<ClientChannel::EventSource> ChannelEventReceiver::GetEventSources()
+ const {
+ return {{data_fd_.Get(), EPOLLHUP | EPOLLRDHUP},
+ {pollin_event_fd_.Get(), EPOLLIN},
+ {pollhup_event_fd_.Get(), POLLIN}};
}
} // namespace uds
diff --git a/libs/vr/libpdx_uds/channel_manager.cpp b/libs/vr/libpdx_uds/channel_manager.cpp
index afc0a4f..43ebe05 100644
--- a/libs/vr/libpdx_uds/channel_manager.cpp
+++ b/libs/vr/libpdx_uds/channel_manager.cpp
@@ -22,18 +22,26 @@
}
LocalChannelHandle ChannelManager::CreateHandle(LocalHandle data_fd,
- LocalHandle event_fd) {
- if (data_fd && event_fd) {
+ LocalHandle pollin_event_fd,
+ LocalHandle pollhup_event_fd) {
+ if (data_fd && pollin_event_fd && pollhup_event_fd) {
std::lock_guard<std::mutex> autolock(mutex_);
- int32_t handle = data_fd.Get();
- channels_.emplace(handle,
- ChannelData{std::move(data_fd), std::move(event_fd)});
+ const int32_t handle = data_fd.Get();
+ channels_.emplace(
+ handle,
+ ChannelEventReceiver{std::move(data_fd), std::move(pollin_event_fd),
+ std::move(pollhup_event_fd)});
return LocalChannelHandle(this, handle);
+ } else {
+ ALOGE(
+ "ChannelManager::CreateHandle: Invalid arguments: data_fd=%d "
+ "pollin_event_fd=%d pollhup_event_fd=%d",
+ data_fd.Get(), pollin_event_fd.Get(), pollhup_event_fd.Get());
+ return LocalChannelHandle(nullptr, -1);
}
- return LocalChannelHandle(nullptr, -1);
}
-ChannelManager::ChannelData* ChannelManager::GetChannelData(int32_t handle) {
+ChannelEventReceiver* ChannelManager::GetChannelData(int32_t handle) {
std::lock_guard<std::mutex> autolock(mutex_);
auto channel = channels_.find(handle);
return channel != channels_.end() ? &channel->second : nullptr;
diff --git a/libs/vr/libpdx_uds/client_channel.cpp b/libs/vr/libpdx_uds/client_channel.cpp
index 9d91617..2e9c1de 100644
--- a/libs/vr/libpdx_uds/client_channel.cpp
+++ b/libs/vr/libpdx_uds/client_channel.cpp
@@ -33,7 +33,9 @@
} else if (static_cast<size_t>(index) < response.channels.size()) {
auto& channel_info = response.channels[index];
*handle = ChannelManager::Get().CreateHandle(
- std::move(channel_info.data_fd), std::move(channel_info.event_fd));
+ std::move(channel_info.data_fd),
+ std::move(channel_info.pollin_event_fd),
+ std::move(channel_info.pollhup_event_fd));
} else {
return false;
}
@@ -53,9 +55,9 @@
if (auto* channel_data =
ChannelManager::Get().GetChannelData(handle.value())) {
- ChannelInfo<BorrowedHandle> channel_info;
- channel_info.data_fd.Reset(handle.value());
- channel_info.event_fd = channel_data->event_receiver.event_fd();
+ ChannelInfo<BorrowedHandle> channel_info{
+ channel_data->data_fd(), channel_data->pollin_event_fd(),
+ channel_data->pollhup_event_fd()};
request.channels.push_back(std::move(channel_info));
return request.channels.size() - 1;
} else {
@@ -90,10 +92,12 @@
size_t send_len = CountVectorSize(send_vector, send_count);
InitRequest(&transaction_state->request, opcode, send_len, max_recv_len,
false);
- auto status = SendData(socket_fd, transaction_state->request);
- if (status && send_len > 0)
- status = SendDataVector(socket_fd, send_vector, send_count);
- return status;
+ if (send_len == 0) {
+ send_vector = nullptr;
+ send_count = 0;
+ }
+ return SendData(socket_fd, transaction_state->request, send_vector,
+ send_count);
}
Status<void> ReceiveResponse(const BorrowedHandle& socket_fd,
diff --git a/libs/vr/libpdx_uds/client_channel_factory.cpp b/libs/vr/libpdx_uds/client_channel_factory.cpp
index 433f459..09dc7be 100644
--- a/libs/vr/libpdx_uds/client_channel_factory.cpp
+++ b/libs/vr/libpdx_uds/client_channel_factory.cpp
@@ -139,20 +139,33 @@
RequestHeader<BorrowedHandle> request;
InitRequest(&request, opcodes::CHANNEL_OPEN, 0, 0, false);
+
status = SendData(socket_.Borrow(), request);
if (!status)
return status.error_status();
+
ResponseHeader<LocalHandle> response;
status = ReceiveData(socket_.Borrow(), &response);
if (!status)
return status.error_status();
- int ref = response.ret_code;
- if (ref < 0 || static_cast<size_t>(ref) > response.file_descriptors.size())
+ else if (response.ret_code < 0 || response.channels.size() != 1)
return ErrorStatus(EIO);
- LocalHandle event_fd = std::move(response.file_descriptors[ref]);
+ LocalHandle pollin_event_fd = std::move(response.channels[0].pollin_event_fd);
+ LocalHandle pollhup_event_fd =
+ std::move(response.channels[0].pollhup_event_fd);
+
+ if (!pollin_event_fd || !pollhup_event_fd) {
+ ALOGE(
+ "ClientChannelFactory::Connect: Required fd was not returned from the "
+ "service: pollin_event_fd=%d pollhup_event_fd=%d",
+ pollin_event_fd.Get(), pollhup_event_fd.Get());
+ return ErrorStatus(EIO);
+ }
+
return ClientChannel::Create(ChannelManager::Get().CreateHandle(
- std::move(socket_), std::move(event_fd)));
+ std::move(socket_), std::move(pollin_event_fd),
+ std::move(pollhup_event_fd)));
}
} // namespace uds
diff --git a/libs/vr/libpdx_uds/ipc_helper.cpp b/libs/vr/libpdx_uds/ipc_helper.cpp
index d75ce86..f85b3bb 100644
--- a/libs/vr/libpdx_uds/ipc_helper.cpp
+++ b/libs/vr/libpdx_uds/ipc_helper.cpp
@@ -20,6 +20,9 @@
namespace {
+constexpr size_t kMaxFdCount =
+ 256; // Total of 1KiB of data to transfer these FDs.
+
// Default implementations of Send/Receive interfaces to use standard socket
// send/sendmsg/recv/recvmsg functions.
class SocketSender : public SendInterface {
@@ -175,20 +178,31 @@
}
Status<void> SendPayload::Send(const BorrowedHandle& socket_fd,
- const ucred* cred) {
+ const ucred* cred, const iovec* data_vec,
+ size_t vec_count) {
+ if (file_handles_.size() > kMaxFdCount) {
+ ALOGE(
+ "SendPayload::Send: Trying to send too many file descriptors (%zu), "
+ "max allowed = %zu",
+ file_handles_.size(), kMaxFdCount);
+ return ErrorStatus{EINVAL};
+ }
+
SendInterface* sender = sender_ ? sender_ : &g_socket_sender;
MessagePreamble preamble;
preamble.magic = kMagicPreamble;
preamble.data_size = buffer_.size();
preamble.fd_count = file_handles_.size();
- Status<void> ret = SendAll(sender, socket_fd, &preamble, sizeof(preamble));
- if (!ret)
- return ret;
msghdr msg = {};
- iovec recv_vect = {buffer_.data(), buffer_.size()};
- msg.msg_iov = &recv_vect;
- msg.msg_iovlen = 1;
+ msg.msg_iovlen = 2 + vec_count;
+ msg.msg_iov = static_cast<iovec*>(alloca(sizeof(iovec) * msg.msg_iovlen));
+ msg.msg_iov[0].iov_base = &preamble;
+ msg.msg_iov[0].iov_len = sizeof(preamble);
+ msg.msg_iov[1].iov_base = buffer_.data();
+ msg.msg_iov[1].iov_len = buffer_.size();
+ for (size_t i = 0; i < vec_count; i++)
+ msg.msg_iov[i + 2] = data_vec[i];
if (cred || !file_handles_.empty()) {
const size_t fd_bytes = file_handles_.size() * sizeof(int);
@@ -270,7 +284,15 @@
ucred* cred) {
RecvInterface* receiver = receiver_ ? receiver_ : &g_socket_receiver;
MessagePreamble preamble;
- Status<void> ret = RecvAll(receiver, socket_fd, &preamble, sizeof(preamble));
+ msghdr msg = {};
+ iovec recv_vect = {&preamble, sizeof(preamble)};
+ msg.msg_iov = &recv_vect;
+ msg.msg_iovlen = 1;
+ const size_t receive_fd_bytes = kMaxFdCount * sizeof(int);
+ msg.msg_controllen = CMSG_SPACE(sizeof(ucred)) + CMSG_SPACE(receive_fd_bytes);
+ msg.msg_control = alloca(msg.msg_controllen);
+
+ Status<void> ret = RecvMsgAll(receiver, socket_fd, &msg);
if (!ret)
return ret;
@@ -284,23 +306,6 @@
file_handles_.clear();
read_pos_ = 0;
- msghdr msg = {};
- iovec recv_vect = {buffer_.data(), buffer_.size()};
- msg.msg_iov = &recv_vect;
- msg.msg_iovlen = 1;
-
- if (cred || preamble.fd_count) {
- const size_t receive_fd_bytes = preamble.fd_count * sizeof(int);
- msg.msg_controllen =
- (cred ? CMSG_SPACE(sizeof(ucred)) : 0) +
- (receive_fd_bytes == 0 ? 0 : CMSG_SPACE(receive_fd_bytes));
- msg.msg_control = alloca(msg.msg_controllen);
- }
-
- ret = RecvMsgAll(receiver, socket_fd, &msg);
- if (!ret)
- return ret;
-
bool cred_available = false;
file_handles_.reserve(preamble.fd_count);
cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
@@ -320,6 +325,10 @@
cmsg = CMSG_NXTHDR(&msg, cmsg);
}
+ ret = RecvAll(receiver, socket_fd, buffer_.data(), buffer_.size());
+ if (!ret)
+ return ret;
+
if (cred && !cred_available) {
ALOGE("ReceivePayload::Receive: Failed to obtain message credentials");
ret.SetError(EIO);
diff --git a/libs/vr/libpdx_uds/private/uds/channel_event_set.h b/libs/vr/libpdx_uds/private/uds/channel_event_set.h
index 1f464d5..99e7502 100644
--- a/libs/vr/libpdx_uds/private/uds/channel_event_set.h
+++ b/libs/vr/libpdx_uds/private/uds/channel_event_set.h
@@ -1,11 +1,9 @@
#ifndef ANDROID_PDX_UDS_CHANNEL_EVENT_SET_H_
#define ANDROID_PDX_UDS_CHANNEL_EVENT_SET_H_
-#include <errno.h>
-#include <poll.h>
-#include <sys/epoll.h>
-#include <sys/eventfd.h>
+#include <vector>
+#include <pdx/client_channel.h>
#include <pdx/file_handle.h>
#include <pdx/status.h>
@@ -19,21 +17,20 @@
ChannelEventSet(ChannelEventSet&&) = default;
ChannelEventSet& operator=(ChannelEventSet&&) = default;
- BorrowedHandle event_fd() const { return epoll_fd_.Borrow(); }
+ BorrowedHandle pollin_event_fd() const { return pollin_event_fd_.Borrow(); }
+ BorrowedHandle pollhup_event_fd() const { return pollhup_event_fd_.Borrow(); }
- explicit operator bool() const { return !!epoll_fd_ && !!event_fd_; }
+ explicit operator bool() const {
+ return !!pollin_event_fd_ && !!pollhup_event_fd_;
+ }
- Status<void> AddDataFd(const LocalHandle& data_fd);
int ModifyEvents(int clear_mask, int set_mask);
private:
- LocalHandle epoll_fd_;
- LocalHandle event_fd_;
+ LocalHandle pollin_event_fd_;
+ LocalHandle pollhup_event_fd_;
uint32_t event_bits_ = 0;
- static Status<void> SetupHandle(int fd, LocalHandle* handle,
- const char* error_name);
-
ChannelEventSet(const ChannelEventSet&) = delete;
void operator=(const ChannelEventSet&) = delete;
};
@@ -41,14 +38,31 @@
class ChannelEventReceiver {
public:
ChannelEventReceiver() = default;
- ChannelEventReceiver(LocalHandle epoll_fd) : epoll_fd_{std::move(epoll_fd)} {}
+ ChannelEventReceiver(LocalHandle data_fd, LocalHandle pollin_event_fd,
+ LocalHandle pollhup_event_fd);
ChannelEventReceiver(ChannelEventReceiver&&) = default;
ChannelEventReceiver& operator=(ChannelEventReceiver&&) = default;
+ explicit operator bool() const {
+ return !!pollin_event_fd_ && !!pollhup_event_fd_ && !!data_fd_ &&
+ !!epoll_fd_;
+ }
+
BorrowedHandle event_fd() const { return epoll_fd_.Borrow(); }
+
+ BorrowedHandle pollin_event_fd() const { return pollin_event_fd_.Borrow(); }
+ BorrowedHandle pollhup_event_fd() const { return pollhup_event_fd_.Borrow(); }
+ BorrowedHandle data_fd() const { return data_fd_.Borrow(); }
+
Status<int> GetPendingEvents() const;
+ Status<int> PollPendingEvents(int timeout_ms) const;
+
+ std::vector<ClientChannel::EventSource> GetEventSources() const;
private:
+ LocalHandle data_fd_;
+ LocalHandle pollin_event_fd_;
+ LocalHandle pollhup_event_fd_;
LocalHandle epoll_fd_;
ChannelEventReceiver(const ChannelEventReceiver&) = delete;
diff --git a/libs/vr/libpdx_uds/private/uds/channel_manager.h b/libs/vr/libpdx_uds/private/uds/channel_manager.h
index 2aca414..5f6a514 100644
--- a/libs/vr/libpdx_uds/private/uds/channel_manager.h
+++ b/libs/vr/libpdx_uds/private/uds/channel_manager.h
@@ -16,13 +16,11 @@
public:
static ChannelManager& Get();
- LocalChannelHandle CreateHandle(LocalHandle data_fd, LocalHandle event_fd);
- struct ChannelData {
- LocalHandle data_fd;
- ChannelEventReceiver event_receiver;
- };
+ LocalChannelHandle CreateHandle(LocalHandle data_fd,
+ LocalHandle pollin_event_fd,
+ LocalHandle pollhup_event_fd);
- ChannelData* GetChannelData(int32_t handle);
+ ChannelEventReceiver* GetChannelData(int32_t handle);
private:
ChannelManager() = default;
@@ -30,7 +28,7 @@
void CloseHandle(int32_t handle) override;
std::mutex mutex_;
- std::unordered_map<int32_t, ChannelData> channels_;
+ std::unordered_map<int32_t, ChannelEventReceiver> channels_;
};
} // namespace uds
diff --git a/libs/vr/libpdx_uds/private/uds/client_channel.h b/libs/vr/libpdx_uds/private/uds/client_channel.h
index 8f607f5..7a5ddf4 100644
--- a/libs/vr/libpdx_uds/private/uds/client_channel.h
+++ b/libs/vr/libpdx_uds/private/uds/client_channel.h
@@ -23,11 +23,19 @@
uint32_t GetIpcTag() const override { return Endpoint::kIpcTag; }
int event_fd() const override {
- return channel_data_ ? channel_data_->event_receiver.event_fd().Get() : -1;
+ return channel_data_ ? channel_data_->event_fd().Get() : -1;
}
+
+ std::vector<EventSource> GetEventSources() const override {
+ if (channel_data_)
+ return channel_data_->GetEventSources();
+ else
+ return {};
+ }
+
Status<int> GetEventMask(int /*events*/) override {
if (channel_data_)
- return channel_data_->event_receiver.GetPendingEvents();
+ return channel_data_->GetPendingEvents();
else
return ErrorStatus(EINVAL);
}
@@ -74,7 +82,7 @@
const iovec* receive_vector, size_t receive_count);
LocalChannelHandle channel_handle_;
- ChannelManager::ChannelData* channel_data_;
+ ChannelEventReceiver* channel_data_;
std::mutex socket_mutex_;
};
diff --git a/libs/vr/libpdx_uds/private/uds/ipc_helper.h b/libs/vr/libpdx_uds/private/uds/ipc_helper.h
index bde16d3..63b5b10 100644
--- a/libs/vr/libpdx_uds/private/uds/ipc_helper.h
+++ b/libs/vr/libpdx_uds/private/uds/ipc_helper.h
@@ -59,7 +59,8 @@
public:
SendPayload(SendInterface* sender = nullptr) : sender_{sender} {}
Status<void> Send(const BorrowedHandle& socket_fd);
- Status<void> Send(const BorrowedHandle& socket_fd, const ucred* cred);
+ Status<void> Send(const BorrowedHandle& socket_fd, const ucred* cred,
+ const iovec* data_vec = nullptr, size_t vec_count = 0);
// MessageWriter
void* GetNextWriteBufferSection(size_t size) override;
@@ -109,10 +110,12 @@
class ChannelInfo {
public:
FileHandleType data_fd;
- FileHandleType event_fd;
+ FileHandleType pollin_event_fd;
+ FileHandleType pollhup_event_fd;
private:
- PDX_SERIALIZABLE_MEMBERS(ChannelInfo, data_fd, event_fd);
+ PDX_SERIALIZABLE_MEMBERS(ChannelInfo, data_fd, pollin_event_fd,
+ pollhup_event_fd);
};
template <typename FileHandleType>
@@ -156,18 +159,22 @@
};
template <typename T>
-inline Status<void> SendData(const BorrowedHandle& socket_fd, const T& data) {
+inline Status<void> SendData(const BorrowedHandle& socket_fd, const T& data,
+ const iovec* data_vec = nullptr,
+ size_t vec_count = 0) {
SendPayload payload;
rpc::Serialize(data, &payload);
- return payload.Send(socket_fd);
+ return payload.Send(socket_fd, nullptr, data_vec, vec_count);
}
template <typename FileHandleType>
inline Status<void> SendData(const BorrowedHandle& socket_fd,
- const RequestHeader<FileHandleType>& request) {
+ const RequestHeader<FileHandleType>& request,
+ const iovec* data_vec = nullptr,
+ size_t vec_count = 0) {
SendPayload payload;
rpc::Serialize(request, &payload);
- return payload.Send(socket_fd, &request.cred);
+ return payload.Send(socket_fd, &request.cred, data_vec, vec_count);
}
Status<void> SendData(const BorrowedHandle& socket_fd, const void* data,
diff --git a/libs/vr/libpdx_uds/private/uds/service_endpoint.h b/libs/vr/libpdx_uds/private/uds/service_endpoint.h
index a163812..01ebf65 100644
--- a/libs/vr/libpdx_uds/private/uds/service_endpoint.h
+++ b/libs/vr/libpdx_uds/private/uds/service_endpoint.h
@@ -7,6 +7,7 @@
#include <mutex>
#include <string>
#include <unordered_map>
+#include <utility>
#include <vector>
#include <pdx/service.h>
@@ -139,7 +140,8 @@
Status<void> ReenableEpollEvent(const BorrowedHandle& channel_fd);
Channel* GetChannelState(int32_t channel_id);
BorrowedHandle GetChannelSocketFd(int32_t channel_id);
- BorrowedHandle GetChannelEventFd(int32_t channel_id);
+ Status<std::pair<BorrowedHandle, BorrowedHandle>> GetChannelEventFd(
+ int32_t channel_id);
int32_t GetChannelId(const BorrowedHandle& channel_fd);
Status<void> CreateChannelSocketPair(LocalHandle* local_socket,
LocalHandle* remote_socket);
diff --git a/libs/vr/libpdx_uds/service_endpoint.cpp b/libs/vr/libpdx_uds/service_endpoint.cpp
index 27a56f9..0ee77f4 100644
--- a/libs/vr/libpdx_uds/service_endpoint.cpp
+++ b/libs/vr/libpdx_uds/service_endpoint.cpp
@@ -49,7 +49,9 @@
} else if (static_cast<size_t>(index) < request.channels.size()) {
auto& channel_info = request.channels[index];
*handle = ChannelManager::Get().CreateHandle(
- std::move(channel_info.data_fd), std::move(channel_info.event_fd));
+ std::move(channel_info.data_fd),
+ std::move(channel_info.pollin_event_fd),
+ std::move(channel_info.pollhup_event_fd));
} else {
return false;
}
@@ -69,9 +71,9 @@
if (auto* channel_data =
ChannelManager::Get().GetChannelData(handle.value())) {
- ChannelInfo<BorrowedHandle> channel_info;
- channel_info.data_fd.Reset(handle.value());
- channel_info.event_fd = channel_data->event_receiver.event_fd();
+ ChannelInfo<BorrowedHandle> channel_info{
+ channel_data->data_fd(), channel_data->pollin_event_fd(),
+ channel_data->pollhup_event_fd()};
response.channels.push_back(std::move(channel_info));
return response.channels.size() - 1;
} else {
@@ -80,12 +82,13 @@
}
Status<ChannelReference> PushChannelHandle(BorrowedHandle data_fd,
- BorrowedHandle event_fd) {
- if (!data_fd || !event_fd)
+ BorrowedHandle pollin_event_fd,
+ BorrowedHandle pollhup_event_fd) {
+ if (!data_fd || !pollin_event_fd || !pollhup_event_fd)
return ErrorStatus{EINVAL};
- ChannelInfo<BorrowedHandle> channel_info;
- channel_info.data_fd = std::move(data_fd);
- channel_info.event_fd = std::move(event_fd);
+ ChannelInfo<BorrowedHandle> channel_info{std::move(data_fd),
+ std::move(pollin_event_fd),
+ std::move(pollhup_event_fd)};
response.channels.push_back(std::move(channel_info));
return response.channels.size() - 1;
}
@@ -287,7 +290,6 @@
return ErrorStatus(errno);
}
ChannelData channel_data;
- channel_data.event_set.AddDataFd(channel_fd);
channel_data.data_fd = std::move(channel_fd);
channel_data.channel_state = channel_state;
for (;;) {
@@ -431,18 +433,21 @@
return status.error_status();
std::lock_guard<std::mutex> autolock(channel_mutex_);
- auto channel_data = OnNewChannelLocked(std::move(local_socket), channel);
- if (!channel_data)
- return channel_data.error_status();
- *channel_id = channel_data.get().first;
+ auto channel_data_status =
+ OnNewChannelLocked(std::move(local_socket), channel);
+ if (!channel_data_status)
+ return channel_data_status.error_status();
+
+ ChannelData* channel_data;
+ std::tie(*channel_id, channel_data) = channel_data_status.take();
// Flags are ignored for now.
// TODO(xiaohuit): Implement those.
auto* state = static_cast<MessageState*>(message->GetState());
Status<ChannelReference> ref = state->PushChannelHandle(
- remote_socket.Borrow(),
- channel_data.get().second->event_set.event_fd().Borrow());
+ remote_socket.Borrow(), channel_data->event_set.pollin_event_fd(),
+ channel_data->event_set.pollhup_event_fd());
if (!ref)
return ref.error_status();
state->sockets_to_close.push_back(std::move(remote_socket));
@@ -472,13 +477,15 @@
return handle;
}
-BorrowedHandle Endpoint::GetChannelEventFd(int32_t channel_id) {
+Status<std::pair<BorrowedHandle, BorrowedHandle>> Endpoint::GetChannelEventFd(
+ int32_t channel_id) {
std::lock_guard<std::mutex> autolock(channel_mutex_);
- BorrowedHandle handle;
auto channel_data = channels_.find(channel_id);
- if (channel_data != channels_.end())
- handle = channel_data->second.event_set.event_fd().Borrow();
- return handle;
+ if (channel_data != channels_.end()) {
+ return {{channel_data->second.event_set.pollin_event_fd(),
+ channel_data->second.event_set.pollhup_event_fd()}};
+ }
+ return ErrorStatus(ENOENT);
}
int32_t Endpoint::GetChannelId(const BorrowedHandle& channel_fd) {
@@ -593,11 +600,6 @@
}
BorrowedHandle channel_fd{event.data.fd};
- if (event.events & (EPOLLRDHUP | EPOLLHUP)) {
- BuildCloseMessage(GetChannelId(channel_fd), message);
- return {};
- }
-
return ReceiveMessageForChannel(channel_fd, message);
}
@@ -616,12 +618,23 @@
if (return_code < 0) {
return CloseChannel(channel_id);
} else {
- // Reply with the event fd.
- auto push_status = state->PushFileHandle(GetChannelEventFd(channel_id));
- state->response_data.clear(); // Just in case...
- if (!push_status)
- return push_status.error_status();
- return_code = push_status.get();
+ // Open messages do not have a payload and may not transfer any channels
+ // or file descriptors on behalf of the service.
+ state->response_data.clear();
+ state->response.file_descriptors.clear();
+ state->response.channels.clear();
+
+ // Return the channel event-related fds in a single ChannelInfo entry
+ // with an empty data_fd member.
+ auto status = GetChannelEventFd(channel_id);
+ if (!status)
+ return status.error_status();
+
+ auto handles = status.take();
+ state->response.channels.push_back({BorrowedHandle(),
+ std::move(handles.first),
+ std::move(handles.second)});
+ return_code = 0;
}
break;
}
diff --git a/libs/vr/libpdx_uds/service_framework_tests.cpp b/libs/vr/libpdx_uds/service_framework_tests.cpp
index 5943b0a..2742716 100644
--- a/libs/vr/libpdx_uds/service_framework_tests.cpp
+++ b/libs/vr/libpdx_uds/service_framework_tests.cpp
@@ -1,5 +1,6 @@
#include <errno.h>
#include <fcntl.h>
+#include <poll.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <unistd.h>
@@ -506,6 +507,37 @@
EXPECT_EQ(-EINVAL, client->SendAsync(invalid_pointer, sizeof(int)));
}
+// Test impulses.
+TEST_F(ServiceFrameworkTest, ImpulseHangup) {
+ // Create a test service and add it to the dispatcher.
+ auto service = TestService::Create(kTestService1);
+ ASSERT_NE(nullptr, service);
+ ASSERT_EQ(0, dispatcher_->AddService(service));
+
+ auto client = TestClient::Create(kTestService1);
+ ASSERT_NE(nullptr, client);
+
+ const int kMaxIterations = 1000;
+ for (int i = 0; i < kMaxIterations; i++) {
+ auto impulse_client = TestClient::Create(kTestService1);
+ ASSERT_NE(nullptr, impulse_client);
+
+ const uint8_t a = (i >> 0) & 0xff;
+ const uint8_t b = (i >> 8) & 0xff;
+ const uint8_t c = (i >> 16) & 0xff;
+ const uint8_t d = (i >> 24) & 0xff;
+ ImpulsePayload expected_payload = {{a, b, c, d}};
+ EXPECT_EQ(0, impulse_client->SendAsync(expected_payload.data(), 4));
+
+ // Hangup the impulse test client, then send a sync message over client to
+ // make sure the hangup message is handled before checking the impulse
+ // payload.
+ impulse_client = nullptr;
+ client->GetThisChannelId();
+ EXPECT_EQ(expected_payload, service->GetImpulsePayload());
+ }
+}
+
// Test Message::PushChannel/Service::PushChannel API.
TEST_F(ServiceFrameworkTest, PushChannel) {
// Create a test service and add it to the dispatcher.
@@ -574,9 +606,7 @@
pid_t process_id2;
- std::thread thread([&]() {
- process_id2 = client->GetThisProcessId();
- });
+ std::thread thread([&]() { process_id2 = client->GetThisProcessId(); });
thread.join();
EXPECT_LT(2, process_id2);
@@ -614,15 +644,15 @@
auto client = TestClient::Create(kTestService1);
ASSERT_NE(nullptr, client);
- epoll_event event;
- int count = epoll_wait(client->event_fd(), &event, 1, 0);
+ pollfd pfd{client->event_fd(), POLLIN, 0};
+ int count = poll(&pfd, 1, 0);
ASSERT_EQ(0, count);
client->SendPollInEvent();
- count = epoll_wait(client->event_fd(), &event, 1, -1);
+ count = poll(&pfd, 1, 10000 /*10s*/);
ASSERT_EQ(1, count);
- ASSERT_TRUE((EPOLLIN & event.events) != 0);
+ ASSERT_TRUE((POLLIN & pfd.revents) != 0);
}
TEST_F(ServiceFrameworkTest, PollHup) {
@@ -635,15 +665,15 @@
auto client = TestClient::Create(kTestService1);
ASSERT_NE(nullptr, client);
- epoll_event event;
- int count = epoll_wait(client->event_fd(), &event, 1, 0);
+ pollfd pfd{client->event_fd(), POLLIN, 0};
+ int count = poll(&pfd, 1, 0);
ASSERT_EQ(0, count);
client->SendPollHupEvent();
- count = epoll_wait(client->event_fd(), &event, 1, -1);
+ count = poll(&pfd, 1, 10000 /*10s*/);
ASSERT_EQ(1, count);
- auto event_status = client->GetEventMask(event.events);
+ auto event_status = client->GetEventMask(pfd.revents);
ASSERT_TRUE(event_status.ok());
ASSERT_TRUE((EPOLLHUP & event_status.get()) != 0);
}
diff --git a/libs/vr/libvrflinger/acquired_buffer.cpp b/libs/vr/libvrflinger/acquired_buffer.cpp
index fda9585..9614c6d 100644
--- a/libs/vr/libvrflinger/acquired_buffer.cpp
+++ b/libs/vr/libvrflinger/acquired_buffer.cpp
@@ -9,8 +9,8 @@
namespace dvr {
AcquiredBuffer::AcquiredBuffer(const std::shared_ptr<BufferConsumer>& buffer,
- LocalHandle acquire_fence)
- : buffer_(buffer), acquire_fence_(std::move(acquire_fence)) {}
+ LocalHandle acquire_fence, std::size_t slot)
+ : buffer_(buffer), acquire_fence_(std::move(acquire_fence)), slot_(slot) {}
AcquiredBuffer::AcquiredBuffer(const std::shared_ptr<BufferConsumer>& buffer,
int* error) {
@@ -31,18 +31,20 @@
}
}
-AcquiredBuffer::AcquiredBuffer(AcquiredBuffer&& other)
- : buffer_(std::move(other.buffer_)),
- acquire_fence_(std::move(other.acquire_fence_)) {}
+AcquiredBuffer::AcquiredBuffer(AcquiredBuffer&& other) {
+ *this = std::move(other);
+}
AcquiredBuffer::~AcquiredBuffer() { Release(LocalHandle(kEmptyFence)); }
AcquiredBuffer& AcquiredBuffer::operator=(AcquiredBuffer&& other) {
if (this != &other) {
- Release(LocalHandle(kEmptyFence));
+ Release();
- buffer_ = std::move(other.buffer_);
- acquire_fence_ = std::move(other.acquire_fence_);
+ using std::swap;
+ swap(buffer_, other.buffer_);
+ swap(acquire_fence_, other.acquire_fence_);
+ swap(slot_, other.slot_);
}
return *this;
}
@@ -81,8 +83,6 @@
ALOGD_IF(TRACE, "AcquiredBuffer::Release: buffer_id=%d release_fence=%d",
buffer_ ? buffer_->id() : -1, release_fence.Get());
if (buffer_) {
- // Close the release fence since we can't transfer it with an async release.
- release_fence.Close();
const int ret = buffer_->ReleaseAsync();
if (ret < 0) {
ALOGE("AcquiredBuffer::Release: Failed to release buffer %d: %s",
@@ -92,9 +92,10 @@
}
buffer_ = nullptr;
- acquire_fence_.Close();
}
+ acquire_fence_.Close();
+ slot_ = 0;
return 0;
}
diff --git a/libs/vr/libvrflinger/acquired_buffer.h b/libs/vr/libvrflinger/acquired_buffer.h
index e0dc9f2..32e912a 100644
--- a/libs/vr/libvrflinger/acquired_buffer.h
+++ b/libs/vr/libvrflinger/acquired_buffer.h
@@ -21,7 +21,7 @@
// this constructor; the constructor does not attempt to ACQUIRE the buffer
// itself.
AcquiredBuffer(const std::shared_ptr<BufferConsumer>& buffer,
- pdx::LocalHandle acquire_fence);
+ pdx::LocalHandle acquire_fence, std::size_t slot = 0);
// Constructs an AcquiredBuffer from a BufferConsumer. The BufferConsumer MUST
// be in the POSTED state prior to calling this constructor, as this
@@ -64,13 +64,18 @@
// to the producer. On success, the BufferConsumer and acquire fence are set
// to empty state; if release fails, the BufferConsumer and acquire fence are
// left in place and a negative error code is returned.
- int Release(pdx::LocalHandle release_fence);
+ int Release(pdx::LocalHandle release_fence = {});
+
+ // Returns the slot in the queue this buffer belongs to. Buffers that are not
+ // part of a queue return 0.
+ std::size_t slot() const { return slot_; }
private:
std::shared_ptr<BufferConsumer> buffer_;
// Mutable so that the fence can be closed when it is determined to be
// signaled during IsAvailable().
mutable pdx::LocalHandle acquire_fence_;
+ std::size_t slot_{0};
AcquiredBuffer(const AcquiredBuffer&) = delete;
void operator=(const AcquiredBuffer&) = delete;
diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp
index 40396b9..ef8cca3 100644
--- a/libs/vr/libvrflinger/display_manager_service.cpp
+++ b/libs/vr/libvrflinger/display_manager_service.cpp
@@ -65,6 +65,7 @@
}
pdx::Status<void> DisplayManagerService::HandleMessage(pdx::Message& message) {
+ ATRACE_NAME("DisplayManagerService::HandleMessage");
auto channel = std::static_pointer_cast<DisplayManager>(message.GetChannel());
switch (message.GetOp()) {
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index af18e21..ac68a5e 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -124,6 +124,8 @@
// surface-specific messages to the per-instance handlers.
Status<void> DisplayService::HandleMessage(pdx::Message& message) {
ALOGD_IF(TRACE, "DisplayService::HandleMessage: opcode=%d", message.GetOp());
+ ATRACE_NAME("DisplayService::HandleMessage");
+
switch (message.GetOp()) {
case DisplayProtocol::GetMetrics::Opcode:
DispatchRemoteMethod<DisplayProtocol::GetMetrics>(
@@ -349,17 +351,9 @@
void DisplayService::UpdateActiveDisplaySurfaces() {
auto visible_surfaces = GetVisibleDisplaySurfaces();
-
- std::sort(visible_surfaces.begin(), visible_surfaces.end(),
- [](const std::shared_ptr<DisplaySurface>& a,
- const std::shared_ptr<DisplaySurface>& b) {
- return a->z_order() < b->z_order();
- });
-
ALOGD_IF(TRACE,
"DisplayService::UpdateActiveDisplaySurfaces: %zd visible surfaces",
visible_surfaces.size());
-
hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
}
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index 6853781..87c823e 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -213,8 +213,8 @@
ATRACE_NAME("ApplicationDisplaySurface::OnCreateQueue");
ALOGD_IF(TRACE,
"ApplicationDisplaySurface::OnCreateQueue: surface_id=%d, "
- "meta_size_bytes=%zu",
- surface_id(), config.meta_size_bytes);
+ "user_metadata_size=%zu",
+ surface_id(), config.user_metadata_size);
std::lock_guard<std::mutex> autolock(lock_);
auto producer = ProducerQueue::Create(config, UsagePolicy{});
@@ -280,10 +280,10 @@
Status<LocalChannelHandle> DirectDisplaySurface::OnCreateQueue(
Message& /*message*/, const ProducerQueueConfig& config) {
ATRACE_NAME("DirectDisplaySurface::OnCreateQueue");
- ALOGD_IF(
- TRACE,
- "DirectDisplaySurface::OnCreateQueue: surface_id=%d meta_size_bytes=%zu",
- surface_id(), config.meta_size_bytes);
+ ALOGD_IF(TRACE,
+ "DirectDisplaySurface::OnCreateQueue: surface_id=%d "
+ "user_metadata_size=%zu",
+ surface_id(), config.user_metadata_size);
std::lock_guard<std::mutex> autolock(lock_);
if (!direct_queue_) {
@@ -382,7 +382,7 @@
}
acquired_buffers_.Append(
- AcquiredBuffer(buffer_consumer, std::move(acquire_fence)));
+ AcquiredBuffer(buffer_consumer, std::move(acquire_fence), slot));
}
}
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index 3418d65..b3da120 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -5,12 +5,14 @@
#include <fcntl.h>
#include <log/log.h>
#include <poll.h>
+#include <stdint.h>
#include <sync/sync.h>
#include <sys/eventfd.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/system_properties.h>
#include <sys/timerfd.h>
+#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <utils/Trace.h>
@@ -30,7 +32,9 @@
using android::hardware::Return;
using android::hardware::Void;
+using android::pdx::ErrorStatus;
using android::pdx::LocalHandle;
+using android::pdx::Status;
using android::pdx::rpc::EmptyVariant;
using android::pdx::rpc::IfAnyOf;
@@ -44,9 +48,8 @@
const char kBacklightBrightnessSysFile[] =
"/sys/class/leds/lcd-backlight/brightness";
-const char kPrimaryDisplayWaitPPEventFile[] = "/sys/class/graphics/fb0/wait_pp";
-
const char kDvrPerformanceProperty[] = "sys.dvr.performance";
+const char kDvrStandaloneProperty[] = "ro.boot.vr";
const char kRightEyeOffsetProperty[] = "dvr.right_eye_offset_ns";
@@ -83,10 +86,30 @@
return true;
}
-} // anonymous namespace
+// Utility to generate scoped tracers with arguments.
+// TODO(eieio): Move/merge this into utils/Trace.h?
+class TraceArgs {
+ public:
+ template <typename... Args>
+ TraceArgs(const char* format, Args&&... args) {
+ std::array<char, 1024> buffer;
+ snprintf(buffer.data(), buffer.size(), format, std::forward<Args>(args)...);
+ atrace_begin(ATRACE_TAG, buffer.data());
+ }
-// HardwareComposer static data;
-constexpr size_t HardwareComposer::kMaxHardwareLayers;
+ ~TraceArgs() { atrace_end(ATRACE_TAG); }
+
+ private:
+ TraceArgs(const TraceArgs&) = delete;
+ void operator=(const TraceArgs&) = delete;
+};
+
+// Macro to define a scoped tracer with arguments. Uses PASTE(x, y) macro
+// defined in utils/Trace.h.
+#define TRACE_FORMAT(format, ...) \
+ TraceArgs PASTE(__tracer, __LINE__) { format, ##__VA_ARGS__ }
+
+} // anonymous namespace
HardwareComposer::HardwareComposer()
: initialized_(false), request_display_callback_(nullptr) {}
@@ -98,18 +121,20 @@
}
bool HardwareComposer::Initialize(
- Hwc2::Composer* hidl, RequestDisplayCallback request_display_callback) {
+ Hwc2::Composer* composer, RequestDisplayCallback request_display_callback) {
if (initialized_) {
ALOGE("HardwareComposer::Initialize: already initialized.");
return false;
}
+ is_standalone_device_ = property_get_bool(kDvrStandaloneProperty, false);
+
request_display_callback_ = request_display_callback;
HWC::Error error = HWC::Error::None;
Hwc2::Config config;
- error = hidl->getActiveConfig(HWC_DISPLAY_PRIMARY, &config);
+ error = composer->getActiveConfig(HWC_DISPLAY_PRIMARY, &config);
if (error != HWC::Error::None) {
ALOGE("HardwareComposer: Failed to get current display config : %d",
@@ -117,7 +142,7 @@
return false;
}
- error = GetDisplayMetrics(hidl, HWC_DISPLAY_PRIMARY, config,
+ error = GetDisplayMetrics(composer, HWC_DISPLAY_PRIMARY, config,
&native_display_metrics_);
if (error != HWC::Error::None) {
@@ -140,6 +165,9 @@
display_transform_ = HWC_TRANSFORM_NONE;
display_metrics_ = native_display_metrics_;
+ // Setup the display metrics used by all Layer instances.
+ Layer::SetDisplayMetrics(native_display_metrics_);
+
post_thread_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
LOG_ALWAYS_FATAL_IF(
!post_thread_event_fd_,
@@ -198,9 +226,17 @@
}
void HardwareComposer::OnPostThreadResumed() {
- hidl_.reset(new Hwc2::Composer(false));
- hidl_callback_ = new ComposerCallback;
- hidl_->registerCallback(hidl_callback_);
+ // Phones create a new composer client on resume and destroy it on pause.
+ // Standalones only create the composer client once and then use SetPowerMode
+ // to control the screen on pause/resume.
+ if (!is_standalone_device_ || !composer_) {
+ composer_.reset(new Hwc2::Composer(false));
+ composer_callback_ = new ComposerCallback;
+ composer_->registerCallback(composer_callback_);
+ Layer::SetComposer(composer_.get());
+ } else {
+ SetPowerMode(true);
+ }
EnableVsync(true);
@@ -217,19 +253,19 @@
void HardwareComposer::OnPostThreadPaused() {
retire_fence_fds_.clear();
- display_surfaces_.clear();
+ layers_.clear();
- for (size_t i = 0; i < kMaxHardwareLayers; ++i) {
- layers_[i].Reset();
- }
- active_layer_count_ = 0;
-
- if (hidl_) {
+ if (composer_) {
EnableVsync(false);
}
- hidl_callback_ = nullptr;
- hidl_.reset(nullptr);
+ if (!is_standalone_device_) {
+ composer_callback_ = nullptr;
+ composer_.reset(nullptr);
+ Layer::SetComposer(nullptr);
+ } else {
+ SetPowerMode(false);
+ }
// Trigger target-specific performance mode change.
property_set(kDvrPerformanceProperty, "idle");
@@ -239,29 +275,35 @@
uint32_t num_types;
uint32_t num_requests;
HWC::Error error =
- hidl_->validateDisplay(display, &num_types, &num_requests);
+ composer_->validateDisplay(display, &num_types, &num_requests);
if (error == HWC2_ERROR_HAS_CHANGES) {
// TODO(skiazyk): We might need to inspect the requested changes first, but
// so far it seems like we shouldn't ever hit a bad state.
// error = hwc2_funcs_.accept_display_changes_fn_(hardware_composer_device_,
// display);
- error = hidl_->acceptDisplayChanges(display);
+ error = composer_->acceptDisplayChanges(display);
}
return error;
}
HWC::Error HardwareComposer::EnableVsync(bool enabled) {
- return hidl_->setVsyncEnabled(
+ return composer_->setVsyncEnabled(
HWC_DISPLAY_PRIMARY,
(Hwc2::IComposerClient::Vsync)(enabled ? HWC2_VSYNC_ENABLE
: HWC2_VSYNC_DISABLE));
}
+HWC::Error HardwareComposer::SetPowerMode(bool active) {
+ HWC::PowerMode power_mode = active ? HWC::PowerMode::On : HWC::PowerMode::Off;
+ return composer_->setPowerMode(
+ HWC_DISPLAY_PRIMARY, power_mode.cast<Hwc2::IComposerClient::PowerMode>());
+}
+
HWC::Error HardwareComposer::Present(hwc2_display_t display) {
int32_t present_fence;
- HWC::Error error = hidl_->presentDisplay(display, &present_fence);
+ HWC::Error error = composer_->presentDisplay(display, &present_fence);
// According to the documentation, this fence is signaled at the time of
// vsync/DMA for physical displays.
@@ -275,21 +317,21 @@
return error;
}
-HWC::Error HardwareComposer::GetDisplayAttribute(Hwc2::Composer* hidl,
+HWC::Error HardwareComposer::GetDisplayAttribute(Hwc2::Composer* composer,
hwc2_display_t display,
hwc2_config_t config,
hwc2_attribute_t attribute,
int32_t* out_value) const {
- return hidl->getDisplayAttribute(
+ return composer->getDisplayAttribute(
display, config, (Hwc2::IComposerClient::Attribute)attribute, out_value);
}
HWC::Error HardwareComposer::GetDisplayMetrics(
- Hwc2::Composer* hidl, hwc2_display_t display, hwc2_config_t config,
+ Hwc2::Composer* composer, hwc2_display_t display, hwc2_config_t config,
HWCDisplayMetrics* out_metrics) const {
HWC::Error error;
- error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_WIDTH,
+ error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_WIDTH,
&out_metrics->width);
if (error != HWC::Error::None) {
ALOGE(
@@ -298,7 +340,7 @@
return error;
}
- error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_HEIGHT,
+ error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_HEIGHT,
&out_metrics->height);
if (error != HWC::Error::None) {
ALOGE(
@@ -307,7 +349,7 @@
return error;
}
- error = GetDisplayAttribute(hidl, display, config,
+ error = GetDisplayAttribute(composer, display, config,
HWC2_ATTRIBUTE_VSYNC_PERIOD,
&out_metrics->vsync_period_ns);
if (error != HWC::Error::None) {
@@ -317,7 +359,7 @@
return error;
}
- error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_DPI_X,
+ error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_DPI_X,
&out_metrics->dpi.x);
if (error != HWC::Error::None) {
ALOGE(
@@ -326,7 +368,7 @@
return error;
}
- error = GetDisplayAttribute(hidl, display, config, HWC2_ATTRIBUTE_DPI_Y,
+ error = GetDisplayAttribute(composer, display, config, HWC2_ATTRIBUTE_DPI_Y,
&out_metrics->dpi.y);
if (error != HWC::Error::None) {
ALOGE(
@@ -349,10 +391,10 @@
<< std::endl;
stream << "Post thread resumed: " << post_thread_resumed_ << std::endl;
- stream << "Active layers: " << active_layer_count_ << std::endl;
+ stream << "Active layers: " << layers_.size() << std::endl;
stream << std::endl;
- for (size_t i = 0; i < active_layer_count_; i++) {
+ for (size_t i = 0; i < layers_.size(); i++) {
stream << "Layer " << i << ":";
stream << " type=" << layers_[i].GetCompositionType().to_string();
stream << " surface_id=" << layers_[i].GetSurfaceId();
@@ -363,7 +405,7 @@
if (post_thread_resumed_) {
stream << "Hardware Composer Debug Info:" << std::endl;
- stream << hidl_->dumpDebugInfo();
+ stream << composer_->dumpDebugInfo();
}
return stream.str();
@@ -373,8 +415,8 @@
ATRACE_NAME("HardwareComposer::PostLayers");
// Setup the hardware composer layers with current buffers.
- for (size_t i = 0; i < active_layer_count_; i++) {
- layers_[i].Prepare();
+ for (auto& layer : layers_) {
+ layer.Prepare();
}
HWC::Error error = Validate(HWC_DISPLAY_PRIMARY);
@@ -396,20 +438,18 @@
retire_fence_fds_.erase(retire_fence_fds_.begin());
}
- const bool is_frame_pending = IsFramePendingInDriver();
const bool is_fence_pending = static_cast<int32_t>(retire_fence_fds_.size()) >
post_thread_config_.allowed_pending_fence_count;
- if (is_fence_pending || is_frame_pending) {
+ if (is_fence_pending) {
ATRACE_INT("frame_skip_count", ++frame_skip_count_);
- ALOGW_IF(is_frame_pending, "Warning: frame already queued, dropping frame");
ALOGW_IF(is_fence_pending,
"Warning: dropping a frame to catch up with HWC (pending = %zd)",
retire_fence_fds_.size());
- for (size_t i = 0; i < active_layer_count_; i++) {
- layers_[i].Drop();
+ for (auto& layer : layers_) {
+ layer.Drop();
}
return;
} else {
@@ -419,7 +459,7 @@
}
#if TRACE > 1
- for (size_t i = 0; i < active_layer_count_; i++) {
+ for (size_t i = 0; i < layers_.size(); i++) {
ALOGI("HardwareComposer::PostLayers: layer=%zu buffer_id=%d composition=%s",
i, layers_[i].GetBufferId(),
layers_[i].GetCompositionType().to_string().c_str());
@@ -435,18 +475,18 @@
std::vector<Hwc2::Layer> out_layers;
std::vector<int> out_fences;
- error = hidl_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers,
- &out_fences);
+ error = composer_->getReleaseFences(HWC_DISPLAY_PRIMARY, &out_layers,
+ &out_fences);
ALOGE_IF(error != HWC::Error::None,
"HardwareComposer::PostLayers: Failed to get release fences: %s",
error.to_string().c_str());
- // Perform post-frame bookkeeping. Unused layers are a no-op.
+ // Perform post-frame bookkeeping.
uint32_t num_elements = out_layers.size();
for (size_t i = 0; i < num_elements; ++i) {
- for (size_t j = 0; j < active_layer_count_; ++j) {
- if (layers_[j].GetLayerHandle() == out_layers[i]) {
- layers_[j].Finish(out_fences[i]);
+ for (auto& layer : layers_) {
+ if (layer.GetLayerHandle() == out_layers[i]) {
+ layer.Finish(out_fences[i]);
}
}
}
@@ -462,7 +502,7 @@
pending_surfaces_ = std::move(surfaces);
}
- if (request_display_callback_)
+ if (request_display_callback_ && (!is_standalone_device_ || !composer_))
request_display_callback_(!display_idle);
// Set idle state based on whether there are any surfaces to handle.
@@ -565,67 +605,35 @@
} else if (pfd[0].revents != 0) {
return 0;
} else if (pfd[1].revents != 0) {
- ALOGI("VrHwcPost thread interrupted");
+ ALOGI("VrHwcPost thread interrupted: revents=%x", pfd[1].revents);
return kPostThreadInterrupted;
} else {
return 0;
}
}
-// Reads the value of the display driver wait_pingpong state. Returns 0 or 1
-// (the value of the state) on success or a negative error otherwise.
-// TODO(eieio): This is pretty driver specific, this should be moved to a
-// separate class eventually.
-int HardwareComposer::ReadWaitPPState() {
- // Gracefully handle when the kernel does not support this feature.
- if (!primary_display_wait_pp_fd_)
- return 0;
-
- const int wait_pp_fd = primary_display_wait_pp_fd_.Get();
- int ret, error;
-
- ret = lseek(wait_pp_fd, 0, SEEK_SET);
- if (ret < 0) {
- error = errno;
- ALOGE("HardwareComposer::ReadWaitPPState: Failed to seek wait_pp fd: %s",
- strerror(error));
- return -error;
- }
-
- char data = -1;
- ret = read(wait_pp_fd, &data, sizeof(data));
- if (ret < 0) {
- error = errno;
- ALOGE("HardwareComposer::ReadWaitPPState: Failed to read wait_pp state: %s",
- strerror(error));
- return -error;
- }
-
- switch (data) {
- case '0':
- return 0;
- case '1':
- return 1;
- default:
- ALOGE(
- "HardwareComposer::ReadWaitPPState: Unexpected value for wait_pp: %d",
- data);
- return -EINVAL;
- }
+Status<int64_t> HardwareComposer::GetVSyncTime() {
+ auto status = composer_callback_->GetVsyncTime(HWC_DISPLAY_PRIMARY);
+ ALOGE_IF(!status,
+ "HardwareComposer::GetVSyncTime: Failed to get vsync timestamp: %s",
+ status.GetErrorMessage().c_str());
+ return status;
}
// Waits for the next vsync and returns the timestamp of the vsync event. If
// vsync already passed since the last call, returns the latest vsync timestamp
// instead of blocking.
-int HardwareComposer::WaitForVSync(int64_t* timestamp) {
- int error = PostThreadPollInterruptible(
- hidl_callback_->GetVsyncEventFd(), POLLIN, /*timeout_ms*/ 1000);
- if (error == kPostThreadInterrupted || error < 0) {
+Status<int64_t> HardwareComposer::WaitForVSync() {
+ const int64_t predicted_vsync_time =
+ last_vsync_timestamp_ +
+ display_metrics_.vsync_period_ns * vsync_prediction_interval_;
+ const int error = SleepUntil(predicted_vsync_time);
+ if (error < 0) {
+ ALOGE("HardwareComposer::WaifForVSync:: Failed to sleep: %s",
+ strerror(-error));
return error;
- } else {
- *timestamp = hidl_callback_->GetVsyncTime();
- return 0;
}
+ return {predicted_vsync_time};
}
int HardwareComposer::SleepUntil(int64_t wakeup_timestamp) {
@@ -643,8 +651,8 @@
return -error;
}
- return PostThreadPollInterruptible(
- vsync_sleep_timer_fd_, POLLIN, /*timeout_ms*/ -1);
+ return PostThreadPollInterruptible(vsync_sleep_timer_fd_, POLLIN,
+ /*timeout_ms*/ -1);
}
void HardwareComposer::PostThread() {
@@ -667,15 +675,6 @@
strerror(errno));
#endif // ENABLE_BACKLIGHT_BRIGHTNESS
- // Open the wait pingpong status node for the primary display.
- // TODO(eieio): Move this into a platform-specific class.
- primary_display_wait_pp_fd_ =
- LocalHandle(kPrimaryDisplayWaitPPEventFile, O_RDONLY);
- ALOGW_IF(
- !primary_display_wait_pp_fd_,
- "HardwareComposer: Failed to open wait_pp node for primary display: %s",
- strerror(errno));
-
// Create a timerfd based on CLOCK_MONOTINIC.
vsync_sleep_timer_fd_.Reset(timerfd_create(CLOCK_MONOTONIC, 0));
LOG_ALWAYS_FATAL_IF(
@@ -740,26 +739,41 @@
thread_policy_setup =
SetThreadPolicy("graphics:high", "/system/performance");
}
+
+ // Initialize the last vsync timestamp with the current time. The
+ // predictor below uses this time + the vsync interval in absolute time
+ // units for the initial delay. Once the driver starts reporting vsync the
+ // predictor will sync up with the real vsync.
+ last_vsync_timestamp_ = GetSystemClockNs();
}
int64_t vsync_timestamp = 0;
{
- std::array<char, 128> buf;
- snprintf(buf.data(), buf.size(), "wait_vsync|vsync=%d|",
- vsync_count_ + 1);
- ATRACE_NAME(buf.data());
+ TRACE_FORMAT("wait_vsync|vsync=%u;last_timestamp=%" PRId64
+ ";prediction_interval=%d|",
+ vsync_count_ + 1, last_vsync_timestamp_,
+ vsync_prediction_interval_);
- const int error = WaitForVSync(&vsync_timestamp);
+ auto status = WaitForVSync();
ALOGE_IF(
- error < 0,
+ !status,
"HardwareComposer::PostThread: Failed to wait for vsync event: %s",
- strerror(-error));
- // Don't bother processing this frame if a pause was requested
- if (error == kPostThreadInterrupted)
+ status.GetErrorMessage().c_str());
+
+ // If there was an error either sleeping was interrupted due to pausing or
+ // there was an error getting the latest timestamp.
+ if (!status)
continue;
+
+ // Predicted vsync timestamp for this interval. This is stable because we
+ // use absolute time for the wakeup timer.
+ vsync_timestamp = status.get();
}
- ++vsync_count_;
+ // Advance the vsync counter only if the system is keeping up with hardware
+ // vsync to give clients an indication of the delays.
+ if (vsync_prediction_interval_ == 1)
+ ++vsync_count_;
const bool layer_config_changed = UpdateLayerConfig();
@@ -809,6 +823,38 @@
}
}
+ {
+ auto status = GetVSyncTime();
+ if (!status) {
+ ALOGE("HardwareComposer::PostThread: Failed to get VSYNC time: %s",
+ status.GetErrorMessage().c_str());
+ }
+
+ // If we failed to read vsync there might be a problem with the driver.
+ // Since there's nothing we can do just behave as though we didn't get an
+ // updated vsync time and let the prediction continue.
+ const int64_t current_vsync_timestamp =
+ status ? status.get() : last_vsync_timestamp_;
+
+ const bool vsync_delayed =
+ last_vsync_timestamp_ == current_vsync_timestamp;
+ ATRACE_INT("vsync_delayed", vsync_delayed);
+
+ // If vsync was delayed advance the prediction interval and allow the
+ // fence logic in PostLayers() to skip the frame.
+ if (vsync_delayed) {
+ ALOGW(
+ "HardwareComposer::PostThread: VSYNC timestamp did not advance "
+ "since last frame: timestamp=%" PRId64 " prediction_interval=%d",
+ current_vsync_timestamp, vsync_prediction_interval_);
+ vsync_prediction_interval_++;
+ } else {
+ // We have an updated vsync timestamp, reset the prediction interval.
+ last_vsync_timestamp_ = current_vsync_timestamp;
+ vsync_prediction_interval_ = 1;
+ }
+ }
+
PostLayers();
}
}
@@ -827,38 +873,60 @@
ATRACE_NAME("UpdateLayerConfig_HwLayers");
- display_surfaces_.clear();
+ // Sort the new direct surface list by z-order to determine the relative order
+ // of the surfaces. This relative order is used for the HWC z-order value to
+ // insulate VrFlinger and HWC z-order semantics from each other.
+ std::sort(surfaces.begin(), surfaces.end(), [](const auto& a, const auto& b) {
+ return a->z_order() < b->z_order();
+ });
- Layer* target_layer;
- size_t layer_index;
- for (layer_index = 0;
- layer_index < std::min(surfaces.size(), kMaxHardwareLayers);
- layer_index++) {
+ // Prepare a new layer stack, pulling in layers from the previous
+ // layer stack that are still active and updating their attributes.
+ std::vector<Layer> layers;
+ size_t layer_index = 0;
+ for (const auto& surface : surfaces) {
// The bottom layer is opaque, other layers blend.
HWC::BlendMode blending =
layer_index == 0 ? HWC::BlendMode::None : HWC::BlendMode::Coverage;
- layers_[layer_index].Setup(surfaces[layer_index], native_display_metrics_,
- hidl_.get(), blending,
- display_transform_, HWC::Composition::Device,
- layer_index);
- display_surfaces_.push_back(surfaces[layer_index]);
+
+ // Try to find a layer for this surface in the set of active layers.
+ auto search =
+ std::lower_bound(layers_.begin(), layers_.end(), surface->surface_id());
+ const bool found = search != layers_.end() &&
+ search->GetSurfaceId() == surface->surface_id();
+ if (found) {
+ // Update the attributes of the layer that may have changed.
+ search->SetBlending(blending);
+ search->SetZOrder(layer_index); // Relative z-order.
+
+ // Move the existing layer to the new layer set and remove the empty layer
+ // object from the current set.
+ layers.push_back(std::move(*search));
+ layers_.erase(search);
+ } else {
+ // Insert a layer for the new surface.
+ layers.emplace_back(surface, blending, display_transform_,
+ HWC::Composition::Device, layer_index);
+ }
+
+ ALOGI_IF(
+ TRACE,
+ "HardwareComposer::UpdateLayerConfig: layer_index=%zu surface_id=%d",
+ layer_index, layers[layer_index].GetSurfaceId());
+
+ layer_index++;
}
- // Clear unused layers.
- for (size_t i = layer_index; i < kMaxHardwareLayers; i++)
- layers_[i].Reset();
+ // Sort the new layer stack by ascending surface id.
+ std::sort(layers.begin(), layers.end());
- active_layer_count_ = layer_index;
+ // Replace the previous layer set with the new layer set. The destructor of
+ // the previous set will clean up the remaining Layers that are not moved to
+ // the new layer set.
+ layers_ = std::move(layers);
+
ALOGD_IF(TRACE, "HardwareComposer::UpdateLayerConfig: %zd active layers",
- active_layer_count_);
-
- // Any surfaces left over could not be assigned a hardware layer and will
- // not be displayed.
- ALOGW_IF(surfaces.size() != display_surfaces_.size(),
- "HardwareComposer::UpdateLayerConfig: More surfaces than layers: "
- "pending_surfaces=%zu display_surfaces=%zu",
- surfaces.size(), display_surfaces_.size());
-
+ layers_.size());
return true;
}
@@ -874,17 +942,28 @@
}
}
-HardwareComposer::ComposerCallback::ComposerCallback() {
- vsync_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
- LOG_ALWAYS_FATAL_IF(
- !vsync_event_fd_,
- "Failed to create vsync event fd : %s",
- strerror(errno));
-}
-
Return<void> HardwareComposer::ComposerCallback::onHotplug(
- Hwc2::Display /*display*/,
- IComposerCallback::Connection /*conn*/) {
+ Hwc2::Display display, IComposerCallback::Connection /*conn*/) {
+ // See if the driver supports the vsync_event node in sysfs.
+ if (display < HWC_NUM_PHYSICAL_DISPLAY_TYPES &&
+ !displays_[display].driver_vsync_event_fd) {
+ std::array<char, 1024> buffer;
+ snprintf(buffer.data(), buffer.size(),
+ "/sys/class/graphics/fb%" PRIu64 "/vsync_event", display);
+ if (LocalHandle handle{buffer.data(), O_RDONLY}) {
+ ALOGI(
+ "HardwareComposer::ComposerCallback::onHotplug: Driver supports "
+ "vsync_event node for display %" PRIu64,
+ display);
+ displays_[display].driver_vsync_event_fd = std::move(handle);
+ } else {
+ ALOGI(
+ "HardwareComposer::ComposerCallback::onHotplug: Driver does not "
+ "support vsync_event node for display %" PRIu64,
+ display);
+ }
+ }
+
return Void();
}
@@ -893,40 +972,94 @@
return hardware::Void();
}
-Return<void> HardwareComposer::ComposerCallback::onVsync(
- Hwc2::Display display, int64_t timestamp) {
- if (display == HWC_DISPLAY_PRIMARY) {
- std::lock_guard<std::mutex> lock(vsync_mutex_);
- vsync_time_ = timestamp;
- int error = eventfd_write(vsync_event_fd_.Get(), 1);
- LOG_ALWAYS_FATAL_IF(error != 0, "Failed writing to vsync event fd");
+Return<void> HardwareComposer::ComposerCallback::onVsync(Hwc2::Display display,
+ int64_t timestamp) {
+ TRACE_FORMAT("vsync_callback|display=%" PRIu64 ";timestamp=%" PRId64 "|",
+ display, timestamp);
+ if (display < HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
+ displays_[display].callback_vsync_timestamp = timestamp;
+ } else {
+ ALOGW(
+ "HardwareComposer::ComposerCallback::onVsync: Received vsync on "
+ "non-physical display: display=%" PRId64,
+ display);
}
return Void();
}
-const pdx::LocalHandle&
-HardwareComposer::ComposerCallback::GetVsyncEventFd() const {
- return vsync_event_fd_;
+Status<int64_t> HardwareComposer::ComposerCallback::GetVsyncTime(
+ Hwc2::Display display) {
+ if (display >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
+ ALOGE(
+ "HardwareComposer::ComposerCallback::GetVsyncTime: Invalid physical "
+ "display requested: display=%" PRIu64,
+ display);
+ return ErrorStatus(EINVAL);
+ }
+
+ // See if the driver supports direct vsync events.
+ LocalHandle& event_fd = displays_[display].driver_vsync_event_fd;
+ if (!event_fd) {
+ // Fall back to returning the last timestamp returned by the vsync
+ // callback.
+ std::lock_guard<std::mutex> autolock(vsync_mutex_);
+ return displays_[display].callback_vsync_timestamp;
+ }
+
+ // When the driver supports the vsync_event sysfs node we can use it to
+ // determine the latest vsync timestamp, even if the HWC callback has been
+ // delayed.
+
+ // The driver returns data in the form "VSYNC=<timestamp ns>".
+ std::array<char, 32> data;
+ data.fill('\0');
+
+ // Seek back to the beginning of the event file.
+ int ret = lseek(event_fd.Get(), 0, SEEK_SET);
+ if (ret < 0) {
+ const int error = errno;
+ ALOGE(
+ "HardwareComposer::ComposerCallback::GetVsyncTime: Failed to seek "
+ "vsync event fd: %s",
+ strerror(error));
+ return ErrorStatus(error);
+ }
+
+ // Read the vsync event timestamp.
+ ret = read(event_fd.Get(), data.data(), data.size());
+ if (ret < 0) {
+ const int error = errno;
+ ALOGE_IF(error != EAGAIN,
+ "HardwareComposer::ComposerCallback::GetVsyncTime: Error "
+ "while reading timestamp: %s",
+ strerror(error));
+ return ErrorStatus(error);
+ }
+
+ int64_t timestamp;
+ ret = sscanf(data.data(), "VSYNC=%" PRIu64,
+ reinterpret_cast<uint64_t*>(×tamp));
+ if (ret < 0) {
+ const int error = errno;
+ ALOGE(
+ "HardwareComposer::ComposerCallback::GetVsyncTime: Error while "
+ "parsing timestamp: %s",
+ strerror(error));
+ return ErrorStatus(error);
+ }
+
+ return {timestamp};
}
-int64_t HardwareComposer::ComposerCallback::GetVsyncTime() {
- std::lock_guard<std::mutex> lock(vsync_mutex_);
- eventfd_t event;
- eventfd_read(vsync_event_fd_.Get(), &event);
- LOG_ALWAYS_FATAL_IF(vsync_time_ < 0,
- "Attempt to read vsync time before vsync event");
- int64_t return_val = vsync_time_;
- vsync_time_ = -1;
- return return_val;
-}
+Hwc2::Composer* Layer::composer_{nullptr};
+HWCDisplayMetrics Layer::display_metrics_{0, 0, {0, 0}, 0};
void Layer::Reset() {
- if (hidl_ != nullptr && hardware_composer_layer_) {
- hidl_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_);
+ if (hardware_composer_layer_) {
+ composer_->destroyLayer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_);
hardware_composer_layer_ = 0;
}
- hidl_ = nullptr;
z_order_ = 0;
blending_ = HWC::BlendMode::None;
transform_ = HWC::Transform::None;
@@ -935,38 +1068,54 @@
source_ = EmptyVariant{};
acquire_fence_.Close();
surface_rect_functions_applied_ = false;
+ pending_visibility_settings_ = true;
+ cached_buffer_map_.clear();
}
-void Layer::Setup(const std::shared_ptr<DirectDisplaySurface>& surface,
- const HWCDisplayMetrics& display_metrics,
- Hwc2::Composer* hidl, HWC::BlendMode blending,
- HWC::Transform transform, HWC::Composition composition_type,
- size_t z_order) {
- Reset();
- hidl_ = hidl;
- z_order_ = z_order;
- blending_ = blending;
- transform_ = transform;
- composition_type_ = HWC::Composition::Invalid;
- target_composition_type_ = composition_type;
- source_ = SourceSurface{surface};
- CommonLayerSetup(display_metrics);
+Layer::Layer(const std::shared_ptr<DirectDisplaySurface>& surface,
+ HWC::BlendMode blending, HWC::Transform transform,
+ HWC::Composition composition_type, size_t z_order)
+ : z_order_{z_order},
+ blending_{blending},
+ transform_{transform},
+ target_composition_type_{composition_type},
+ source_{SourceSurface{surface}} {
+ CommonLayerSetup();
}
-void Layer::Setup(const std::shared_ptr<IonBuffer>& buffer,
- const HWCDisplayMetrics& display_metrics,
- Hwc2::Composer* hidl, HWC::BlendMode blending,
- HWC::Transform transform, HWC::Composition composition_type,
- size_t z_order) {
- Reset();
- hidl_ = hidl;
- z_order_ = z_order;
- blending_ = blending;
- transform_ = transform;
- composition_type_ = HWC::Composition::Invalid;
- target_composition_type_ = composition_type;
- source_ = SourceBuffer{buffer};
- CommonLayerSetup(display_metrics);
+Layer::Layer(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
+ HWC::Transform transform, HWC::Composition composition_type,
+ size_t z_order)
+ : z_order_{z_order},
+ blending_{blending},
+ transform_{transform},
+ target_composition_type_{composition_type},
+ source_{SourceBuffer{buffer}} {
+ CommonLayerSetup();
+}
+
+Layer::~Layer() { Reset(); }
+
+Layer::Layer(Layer&& other) { *this = std::move(other); }
+
+Layer& Layer::operator=(Layer&& other) {
+ if (this != &other) {
+ Reset();
+ using std::swap;
+ swap(hardware_composer_layer_, other.hardware_composer_layer_);
+ swap(z_order_, other.z_order_);
+ swap(blending_, other.blending_);
+ swap(transform_, other.transform_);
+ swap(composition_type_, other.composition_type_);
+ swap(target_composition_type_, other.target_composition_type_);
+ swap(source_, other.source_);
+ swap(acquire_fence_, other.acquire_fence_);
+ swap(surface_rect_functions_applied_,
+ other.surface_rect_functions_applied_);
+ swap(pending_visibility_settings_, other.pending_visibility_settings_);
+ swap(cached_buffer_map_, other.cached_buffer_map_);
+ }
+ return *this;
}
void Layer::UpdateBuffer(const std::shared_ptr<IonBuffer>& buffer) {
@@ -974,8 +1123,19 @@
std::get<SourceBuffer>(source_) = {buffer};
}
-void Layer::SetBlending(HWC::BlendMode blending) { blending_ = blending; }
-void Layer::SetZOrder(size_t z_order) { z_order_ = z_order; }
+void Layer::SetBlending(HWC::BlendMode blending) {
+ if (blending_ != blending) {
+ blending_ = blending;
+ pending_visibility_settings_ = true;
+ }
+}
+
+void Layer::SetZOrder(size_t z_order) {
+ if (z_order_ != z_order) {
+ z_order_ = z_order;
+ pending_visibility_settings_ = true;
+ }
+}
IonBuffer* Layer::GetBuffer() {
struct Visitor {
@@ -986,91 +1146,108 @@
return source_.Visit(Visitor{});
}
-void Layer::UpdateLayerSettings(const HWCDisplayMetrics& display_metrics) {
- if (!IsLayerSetup()) {
- ALOGE(
- "HardwareComposer::Layer::UpdateLayerSettings: Attempt to update "
- "unused Layer!");
- return;
- }
+void Layer::UpdateVisibilitySettings() {
+ if (pending_visibility_settings_) {
+ pending_visibility_settings_ = false;
+ HWC::Error error;
+ hwc2_display_t display = HWC_DISPLAY_PRIMARY;
+
+ error = composer_->setLayerBlendMode(
+ display, hardware_composer_layer_,
+ blending_.cast<Hwc2::IComposerClient::BlendMode>());
+ ALOGE_IF(error != HWC::Error::None,
+ "Layer::UpdateLayerSettings: Error setting layer blend mode: %s",
+ error.to_string().c_str());
+
+ error =
+ composer_->setLayerZOrder(display, hardware_composer_layer_, z_order_);
+ ALOGE_IF(error != HWC::Error::None,
+ "Layer::UpdateLayerSettings: Error setting z_ order: %s",
+ error.to_string().c_str());
+ }
+}
+
+void Layer::UpdateLayerSettings() {
HWC::Error error;
hwc2_display_t display = HWC_DISPLAY_PRIMARY;
- error = hidl_->setLayerCompositionType(
- display, hardware_composer_layer_,
- composition_type_.cast<Hwc2::IComposerClient::Composition>());
- ALOGE_IF(
- error != HWC::Error::None,
- "Layer::UpdateLayerSettings: Error setting layer composition type: %s",
- error.to_string().c_str());
-
- error = hidl_->setLayerBlendMode(
- display, hardware_composer_layer_,
- blending_.cast<Hwc2::IComposerClient::BlendMode>());
- ALOGE_IF(error != HWC::Error::None,
- "Layer::UpdateLayerSettings: Error setting layer blend mode: %s",
- error.to_string().c_str());
+ UpdateVisibilitySettings();
// TODO(eieio): Use surface attributes or some other mechanism to control
// the layer display frame.
- error = hidl_->setLayerDisplayFrame(
+ error = composer_->setLayerDisplayFrame(
display, hardware_composer_layer_,
- {0, 0, display_metrics.width, display_metrics.height});
+ {0, 0, display_metrics_.width, display_metrics_.height});
ALOGE_IF(error != HWC::Error::None,
"Layer::UpdateLayerSettings: Error setting layer display frame: %s",
error.to_string().c_str());
- error = hidl_->setLayerVisibleRegion(
+ error = composer_->setLayerVisibleRegion(
display, hardware_composer_layer_,
- {{0, 0, display_metrics.width, display_metrics.height}});
+ {{0, 0, display_metrics_.width, display_metrics_.height}});
ALOGE_IF(error != HWC::Error::None,
"Layer::UpdateLayerSettings: Error setting layer visible region: %s",
error.to_string().c_str());
- error = hidl_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f);
+ error =
+ composer_->setLayerPlaneAlpha(display, hardware_composer_layer_, 1.0f);
ALOGE_IF(error != HWC::Error::None,
"Layer::UpdateLayerSettings: Error setting layer plane alpha: %s",
error.to_string().c_str());
-
- error = hidl_->setLayerZOrder(display, hardware_composer_layer_, z_order_);
- ALOGE_IF(error != HWC::Error::None,
- "Layer::UpdateLayerSettings: Error setting z_ order: %s",
- error.to_string().c_str());
}
-void Layer::CommonLayerSetup(const HWCDisplayMetrics& display_metrics) {
+void Layer::CommonLayerSetup() {
HWC::Error error =
- hidl_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_);
- ALOGE_IF(
- error != HWC::Error::None,
- "Layer::CommonLayerSetup: Failed to create layer on primary display: %s",
- error.to_string().c_str());
- UpdateLayerSettings(display_metrics);
+ composer_->createLayer(HWC_DISPLAY_PRIMARY, &hardware_composer_layer_);
+ ALOGE_IF(error != HWC::Error::None,
+ "Layer::CommonLayerSetup: Failed to create layer on primary "
+ "display: %s",
+ error.to_string().c_str());
+ UpdateLayerSettings();
+}
+
+bool Layer::CheckAndUpdateCachedBuffer(std::size_t slot, int buffer_id) {
+ auto search = cached_buffer_map_.find(slot);
+ if (search != cached_buffer_map_.end() && search->second == buffer_id)
+ return true;
+
+ // Assign or update the buffer slot.
+ if (buffer_id >= 0)
+ cached_buffer_map_[slot] = buffer_id;
+ return false;
}
void Layer::Prepare() {
- int right, bottom;
+ int right, bottom, id;
sp<GraphicBuffer> handle;
+ std::size_t slot;
// Acquire the next buffer according to the type of source.
IfAnyOf<SourceSurface, SourceBuffer>::Call(&source_, [&](auto& source) {
- std::tie(right, bottom, handle, acquire_fence_) = source.Acquire();
+ std::tie(right, bottom, id, handle, acquire_fence_, slot) =
+ source.Acquire();
});
- // When a layer is first setup there may be some time before the first buffer
- // arrives. Setup the HWC layer as a solid color to stall for time until the
- // first buffer arrives. Once the first buffer arrives there will always be a
- // buffer for the frame even if it is old.
+ TRACE_FORMAT("Layer::Prepare|buffer_id=%d;slot=%zu|", id, slot);
+
+ // Update any visibility (blending, z-order) changes that occurred since
+ // last prepare.
+ UpdateVisibilitySettings();
+
+ // When a layer is first setup there may be some time before the first
+ // buffer arrives. Setup the HWC layer as a solid color to stall for time
+ // until the first buffer arrives. Once the first buffer arrives there will
+ // always be a buffer for the frame even if it is old.
if (!handle.get()) {
if (composition_type_ == HWC::Composition::Invalid) {
composition_type_ = HWC::Composition::SolidColor;
- hidl_->setLayerCompositionType(
+ composer_->setLayerCompositionType(
HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
composition_type_.cast<Hwc2::IComposerClient::Composition>());
Hwc2::IComposerClient::Color layer_color = {0, 0, 0, 0};
- hidl_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
- layer_color);
+ composer_->setLayerColor(HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
+ layer_color);
} else {
// The composition type is already set. Nothing else to do until a
// buffer arrives.
@@ -1078,15 +1255,20 @@
} else {
if (composition_type_ != target_composition_type_) {
composition_type_ = target_composition_type_;
- hidl_->setLayerCompositionType(
+ composer_->setLayerCompositionType(
HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
composition_type_.cast<Hwc2::IComposerClient::Composition>());
}
+ // See if the HWC cache already has this buffer.
+ const bool cached = CheckAndUpdateCachedBuffer(slot, id);
+ if (cached)
+ handle = nullptr;
+
HWC::Error error{HWC::Error::None};
- error = hidl_->setLayerBuffer(HWC_DISPLAY_PRIMARY,
- hardware_composer_layer_, 0, handle,
- acquire_fence_.Get());
+ error =
+ composer_->setLayerBuffer(HWC_DISPLAY_PRIMARY, hardware_composer_layer_,
+ slot, handle, acquire_fence_.Get());
ALOGE_IF(error != HWC::Error::None,
"Layer::Prepare: Error setting layer buffer: %s",
@@ -1095,9 +1277,9 @@
if (!surface_rect_functions_applied_) {
const float float_right = right;
const float float_bottom = bottom;
- error = hidl_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY,
- hardware_composer_layer_,
- {0, 0, float_right, float_bottom});
+ error = composer_->setLayerSourceCrop(HWC_DISPLAY_PRIMARY,
+ hardware_composer_layer_,
+ {0, 0, float_right, float_bottom});
ALOGE_IF(error != HWC::Error::None,
"Layer::Prepare: Error setting layer source crop: %s",
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index fc0efee..7010db9 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -52,10 +52,7 @@
// source supplying buffers for the layer's contents.
class Layer {
public:
- Layer() {}
-
- // Releases any shared pointers and fence handles held by this instance.
- void Reset();
+ Layer() = default;
// Sets up the layer to use a display surface as its content source. The Layer
// automatically handles ACQUIRE/RELEASE phases for the surface's buffer train
@@ -66,10 +63,9 @@
// |composition_type| receives either HWC_FRAMEBUFFER for most layers or
// HWC_FRAMEBUFFER_TARGET (unless you know what you are doing).
// |index| is the index of this surface in the DirectDisplaySurface array.
- void Setup(const std::shared_ptr<DirectDisplaySurface>& surface,
- const HWCDisplayMetrics& display_metrics, Hwc2::Composer* hidl,
- HWC::BlendMode blending, HWC::Transform transform,
- HWC::Composition composition_type, size_t z_roder);
+ Layer(const std::shared_ptr<DirectDisplaySurface>& surface,
+ HWC::BlendMode blending, HWC::Transform transform,
+ HWC::Composition composition_type, size_t z_roder);
// Sets up the layer to use a direct buffer as its content source. No special
// handling of the buffer is performed; responsibility for updating or
@@ -79,10 +75,17 @@
// |transform| receives HWC_TRANSFORM_* values.
// |composition_type| receives either HWC_FRAMEBUFFER for most layers or
// HWC_FRAMEBUFFER_TARGET (unless you know what you are doing).
- void Setup(const std::shared_ptr<IonBuffer>& buffer,
- const HWCDisplayMetrics& display_metrics, Hwc2::Composer* hidl,
- HWC::BlendMode blending, HWC::Transform transform,
- HWC::Composition composition_type, size_t z_order);
+ Layer(const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
+ HWC::Transform transform, HWC::Composition composition_type,
+ size_t z_order);
+
+ Layer(Layer&&);
+ Layer& operator=(Layer&&);
+
+ ~Layer();
+
+ // Releases any shared pointers and fence handles held by this instance.
+ void Reset();
// Layers that use a direct IonBuffer should call this each frame to update
// which buffer will be used for the next PostLayers.
@@ -117,9 +120,6 @@
HWC::Layer GetLayerHandle() const { return hardware_composer_layer_; }
bool IsLayerSetup() const { return !source_.empty(); }
- // Applies all of the settings to this layer using the hwc functions
- void UpdateLayerSettings(const HWCDisplayMetrics& display_metrics);
-
int GetSurfaceId() const {
int surface_id = -1;
pdx::rpc::IfAnyOf<SourceSurface>::Call(
@@ -138,10 +138,47 @@
return buffer_id;
}
- private:
- void CommonLayerSetup(const HWCDisplayMetrics& display_metrics);
+ // Compares Layers by surface id.
+ bool operator<(const Layer& other) const {
+ return GetSurfaceId() < other.GetSurfaceId();
+ }
+ bool operator<(int surface_id) const { return GetSurfaceId() < surface_id; }
- Hwc2::Composer* hidl_ = nullptr;
+ // Sets the composer instance used by all Layer instances.
+ static void SetComposer(Hwc2::Composer* composer) { composer_ = composer; }
+
+ // Sets the display metrics used by all Layer instances.
+ static void SetDisplayMetrics(HWCDisplayMetrics display_metrics) {
+ display_metrics_ = display_metrics;
+ }
+
+ private:
+ void CommonLayerSetup();
+
+ // Applies all of the settings to this layer using the hwc functions
+ void UpdateLayerSettings();
+
+ // Applies visibility settings that may have changed.
+ void UpdateVisibilitySettings();
+
+ // Checks whether the buffer, given by id, is associated with the given slot
+ // in the HWC buffer cache. If the slot is not associated with the given
+ // buffer the cache is updated to establish the association and the buffer
+ // should be sent to HWC using setLayerBuffer. Returns true if the association
+ // was already established, false if not. A buffer_id of -1 is never
+ // associated and always returns false.
+ bool CheckAndUpdateCachedBuffer(std::size_t slot, int buffer_id);
+
+ // Composer instance shared by all instances of Layer. This must be set
+ // whenever a new instance of the Composer is created. This may be set to
+ // nullptr as long as there are no instances of Layer that might need to use
+ // it.
+ static Hwc2::Composer* composer_;
+
+ // Display metrics shared by all instances of Layer. This must be set at least
+ // once during VrFlinger initialization and is expected to remain constant
+ // thereafter.
+ static HWCDisplayMetrics display_metrics_;
// The hardware composer layer and metrics to use during the prepare cycle.
hwc2_layer_t hardware_composer_layer_ = 0;
@@ -169,19 +206,21 @@
// the previous buffer is returned or an empty value if no buffer has ever
// been posted. When a new buffer is acquired the previous buffer's release
// fence is passed out automatically.
- std::tuple<int, int, sp<GraphicBuffer>, pdx::LocalHandle> Acquire() {
+ std::tuple<int, int, int, sp<GraphicBuffer>, pdx::LocalHandle, std::size_t>
+ Acquire() {
if (surface->IsBufferAvailable()) {
acquired_buffer.Release(std::move(release_fence));
acquired_buffer = surface->AcquireCurrentBuffer();
ATRACE_ASYNC_END("BufferPost", acquired_buffer.buffer()->id());
}
if (!acquired_buffer.IsEmpty()) {
- return std::make_tuple(acquired_buffer.buffer()->width(),
- acquired_buffer.buffer()->height(),
- acquired_buffer.buffer()->buffer()->buffer(),
- acquired_buffer.ClaimAcquireFence());
+ return std::make_tuple(
+ acquired_buffer.buffer()->width(),
+ acquired_buffer.buffer()->height(), acquired_buffer.buffer()->id(),
+ acquired_buffer.buffer()->buffer()->buffer(),
+ acquired_buffer.ClaimAcquireFence(), acquired_buffer.slot());
} else {
- return std::make_tuple(0, 0, nullptr, pdx::LocalHandle{});
+ return std::make_tuple(0, 0, -1, nullptr, pdx::LocalHandle{}, 0);
}
}
@@ -213,12 +252,13 @@
struct SourceBuffer {
std::shared_ptr<IonBuffer> buffer;
- std::tuple<int, int, sp<GraphicBuffer>, pdx::LocalHandle> Acquire() {
+ std::tuple<int, int, int, sp<GraphicBuffer>, pdx::LocalHandle, std::size_t>
+ Acquire() {
if (buffer)
- return std::make_tuple(buffer->width(), buffer->height(),
- buffer->buffer(), pdx::LocalHandle{});
+ return std::make_tuple(buffer->width(), buffer->height(), -1,
+ buffer->buffer(), pdx::LocalHandle{}, 0);
else
- return std::make_tuple(0, 0, nullptr, pdx::LocalHandle{});
+ return std::make_tuple(0, 0, -1, nullptr, pdx::LocalHandle{}, 0);
}
void Finish(pdx::LocalHandle /*fence*/) {}
@@ -235,6 +275,13 @@
pdx::LocalHandle acquire_fence_;
bool surface_rect_functions_applied_ = false;
+ bool pending_visibility_settings_ = true;
+
+ // Map of buffer slot assignments that have already been established with HWC:
+ // slot -> buffer_id. When this map contains a matching slot and buffer_id the
+ // buffer argument to setLayerBuffer may be nullptr to avoid the cost of
+ // importing a buffer HWC already knows about.
+ std::map<std::size_t, int> cached_buffer_map_;
Layer(const Layer&) = delete;
void operator=(const Layer&) = delete;
@@ -254,14 +301,10 @@
using VSyncCallback = std::function<void(int, int64_t, int64_t, uint32_t)>;
using RequestDisplayCallback = std::function<void(bool)>;
- // Since there is no universal way to query the number of hardware layers,
- // just set it to 4 for now.
- static constexpr size_t kMaxHardwareLayers = 4;
-
HardwareComposer();
~HardwareComposer();
- bool Initialize(Hwc2::Composer* hidl,
+ bool Initialize(Hwc2::Composer* composer,
RequestDisplayCallback request_display_callback);
bool IsInitialized() const { return initialized_; }
@@ -299,30 +342,36 @@
void OnDeletedGlobalBuffer(DvrGlobalBufferKey key);
private:
- HWC::Error GetDisplayAttribute(Hwc2::Composer* hidl, hwc2_display_t display,
- hwc2_config_t config,
+ HWC::Error GetDisplayAttribute(Hwc2::Composer* composer,
+ hwc2_display_t display, hwc2_config_t config,
hwc2_attribute_t attributes,
int32_t* out_value) const;
- HWC::Error GetDisplayMetrics(Hwc2::Composer* hidl, hwc2_display_t display,
+ HWC::Error GetDisplayMetrics(Hwc2::Composer* composer, hwc2_display_t display,
hwc2_config_t config,
HWCDisplayMetrics* out_metrics) const;
HWC::Error EnableVsync(bool enabled);
+ HWC::Error SetPowerMode(bool active);
class ComposerCallback : public Hwc2::IComposerCallback {
public:
- ComposerCallback();
+ ComposerCallback() = default;
hardware::Return<void> onHotplug(Hwc2::Display display,
Connection conn) override;
hardware::Return<void> onRefresh(Hwc2::Display display) override;
hardware::Return<void> onVsync(Hwc2::Display display,
int64_t timestamp) override;
- const pdx::LocalHandle& GetVsyncEventFd() const;
- int64_t GetVsyncTime();
+
+ pdx::Status<int64_t> GetVsyncTime(Hwc2::Display display);
+
private:
std::mutex vsync_mutex_;
- pdx::LocalHandle vsync_event_fd_;
- int64_t vsync_time_ = -1;
+
+ struct Display {
+ pdx::LocalHandle driver_vsync_event_fd;
+ int64_t callback_vsync_timestamp{0};
+ };
+ std::array<Display, HWC_NUM_PHYSICAL_DISPLAY_TYPES> displays_;
};
HWC::Error Validate(hwc2_display_t display);
@@ -356,18 +405,16 @@
// the case of a timeout. If we're interrupted, kPostThreadInterrupted will be
// returned.
int PostThreadPollInterruptible(const pdx::LocalHandle& event_fd,
- int requested_events,
- int timeout_ms);
+ int requested_events, int timeout_ms);
// WaitForVSync and SleepUntil are blocking calls made on the post thread that
// can be interrupted by a control thread. If interrupted, these calls return
// kPostThreadInterrupted.
int ReadWaitPPState();
- int WaitForVSync(int64_t* timestamp);
+ pdx::Status<int64_t> WaitForVSync();
+ pdx::Status<int64_t> GetVSyncTime();
int SleepUntil(int64_t wakeup_timestamp);
- bool IsFramePendingInDriver() { return ReadWaitPPState() == 1; }
-
// Reconfigures the layer stack if the display surfaces changed since the last
// frame. Called only from the post thread.
bool UpdateLayerConfig();
@@ -385,9 +432,10 @@
void UpdateConfigBuffer();
bool initialized_;
+ bool is_standalone_device_;
- std::unique_ptr<Hwc2::Composer> hidl_;
- sp<ComposerCallback> hidl_callback_;
+ std::unique_ptr<Hwc2::Composer> composer_;
+ sp<ComposerCallback> composer_callback_;
RequestDisplayCallback request_display_callback_;
// Display metrics of the physical display.
@@ -403,13 +451,9 @@
// thread and read by the post thread.
std::vector<std::shared_ptr<DirectDisplaySurface>> pending_surfaces_;
- // The surfaces displayed by the post thread. Used exclusively by the post
- // thread.
- std::vector<std::shared_ptr<DirectDisplaySurface>> display_surfaces_;
-
- // Layer array for handling buffer flow into hardware composer layers.
- std::array<Layer, kMaxHardwareLayers> layers_;
- size_t active_layer_count_ = 0;
+ // Layer set for handling buffer flow into hardware composer layers. This
+ // vector must be sorted by surface_id in ascending order.
+ std::vector<Layer> layers_;
// Handler to hook vsync events outside of this class.
VSyncCallback vsync_callback_;
@@ -419,8 +463,8 @@
std::thread post_thread_;
// Post thread state machine and synchronization primitives.
- PostThreadStateType post_thread_state_{
- PostThreadState::Idle | PostThreadState::Suspended};
+ PostThreadStateType post_thread_state_{PostThreadState::Idle |
+ PostThreadState::Suspended};
std::atomic<bool> post_thread_quiescent_{true};
bool post_thread_resumed_{false};
pdx::LocalHandle post_thread_event_fd_;
@@ -431,15 +475,15 @@
// Backlight LED brightness sysfs node.
pdx::LocalHandle backlight_brightness_fd_;
- // Primary display wait_pingpong state sysfs node.
- pdx::LocalHandle primary_display_wait_pp_fd_;
-
// VSync sleep timerfd.
pdx::LocalHandle vsync_sleep_timer_fd_;
// The timestamp of the last vsync.
int64_t last_vsync_timestamp_ = 0;
+ // The number of vsync intervals to predict since the last vsync.
+ int vsync_prediction_interval_ = 1;
+
// Vsync count since display on.
uint32_t vsync_count_ = 0;
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index fcf94f0..85dc586 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -64,9 +64,6 @@
ALOGI("Starting up VrFlinger...");
- setpriority(PRIO_PROCESS, 0, android::PRIORITY_URGENT_DISPLAY);
- set_sched_policy(0, SP_FOREGROUND);
-
// We need to be able to create endpoints with full perms.
umask(0000);
@@ -100,6 +97,9 @@
prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrDispatch"), 0, 0, 0);
ALOGI("Entering message loop.");
+ setpriority(PRIO_PROCESS, 0, android::PRIORITY_URGENT_DISPLAY);
+ set_sched_policy(0, SP_FOREGROUND);
+
int ret = dispatcher_->EnterDispatchLoop();
if (ret < 0) {
ALOGE("Dispatch loop exited because: %s\n", strerror(-ret));
diff --git a/libs/vr/libvrflinger/vsync_service.cpp b/libs/vr/libvrflinger/vsync_service.cpp
index 3098b43..fdeb899 100644
--- a/libs/vr/libvrflinger/vsync_service.cpp
+++ b/libs/vr/libvrflinger/vsync_service.cpp
@@ -110,6 +110,7 @@
}
pdx::Status<void> VSyncService::HandleMessage(pdx::Message& message) {
+ ATRACE_NAME("VSyncService::HandleMessage");
switch (message.GetOp()) {
case VSyncProtocol::Wait::Opcode:
AddWaiter(message);
diff --git a/libs/vr/libvrsensor/include/dvr/pose_client.h b/libs/vr/libvrsensor/include/dvr/pose_client.h
index d69d825..bb25f1d 100644
--- a/libs/vr/libvrsensor/include/dvr/pose_client.h
+++ b/libs/vr/libvrsensor/include/dvr/pose_client.h
@@ -167,8 +167,7 @@
const DvrPoseDataCaptureRequest* request);
// Destroys the write buffer queue for the given |data_type|.
-int dvrPoseClientDataReaderDestroy(DvrPoseClient* client,
- DvrPoseRawDataType data_type);
+int dvrPoseClientDataReaderDestroy(DvrPoseClient* client, uint64_t data_type);
#ifdef __cplusplus
} // extern "C"
diff --git a/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h b/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h
index 7198fe8..39592bb 100644
--- a/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h
+++ b/libs/vr/libvrsensor/include/private/dvr/pose_client_internal.h
@@ -10,8 +10,7 @@
namespace android {
namespace dvr {
-int dvrPoseClientGetDataReaderHandle(DvrPoseClient *client,
- DvrPoseRawDataType data_type,
+int dvrPoseClientGetDataReaderHandle(DvrPoseClient *client, uint64_t data_type,
ConsumerQueue **queue_out);
} // namespace dvr
diff --git a/libs/vr/libvrsensor/pose_client.cpp b/libs/vr/libvrsensor/pose_client.cpp
index 4e23e25..4acc085 100644
--- a/libs/vr/libvrsensor/pose_client.cpp
+++ b/libs/vr/libvrsensor/pose_client.cpp
@@ -141,7 +141,7 @@
return ReturnStatusOrError(status);
}
- int GetTangoReaderHandle(DvrPoseRawDataType data_type, ConsumerQueue** queue_out) {
+ int GetTangoReaderHandle(uint64_t data_type, ConsumerQueue** queue_out) {
// Get buffer.
Transaction trans{*this};
Status<LocalChannelHandle> status = trans.Send<LocalChannelHandle>(
@@ -169,7 +169,7 @@
return ReturnStatusOrError(status);
}
- int DataReaderDestroy(DvrPoseRawDataType data_type) {
+ int DataReaderDestroy(uint64_t data_type) {
Transaction trans{*this};
Status<int> status = trans.Send<int>(DVR_POSE_TANGO_READER_DESTROY,
&data_type, sizeof(data_type), nullptr,
@@ -296,8 +296,7 @@
ControllerClientState controllers_[MAX_CONTROLLERS];
};
-int dvrPoseClientGetDataReaderHandle(DvrPoseClient* client,
- DvrPoseRawDataType type,
+int dvrPoseClientGetDataReaderHandle(DvrPoseClient* client, uint64_t type,
ConsumerQueue** queue_out) {
return PoseClient::FromC(client)->GetTangoReaderHandle(type, queue_out);
}
@@ -362,8 +361,7 @@
return PoseClient::FromC(client)->DataCapture(request);
}
-int dvrPoseClientDataReaderDestroy(DvrPoseClient* client,
- DvrPoseRawDataType data_type) {
+int dvrPoseClientDataReaderDestroy(DvrPoseClient* client, uint64_t data_type) {
return PoseClient::FromC(client)->DataReaderDestroy(data_type);
}
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 935d0f6..d4266f6 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -257,7 +257,7 @@
const String8* uniqueDisplayId, DisplayViewport* outViewport) const {
const DisplayViewport* viewport = NULL;
if (viewportType == ViewportType::VIEWPORT_VIRTUAL && uniqueDisplayId != NULL) {
- for (DisplayViewport currentViewport : mVirtualDisplays) {
+ for (const DisplayViewport& currentViewport : mVirtualDisplays) {
if (currentViewport.uniqueId == *uniqueDisplayId) {
viewport = ¤tViewport;
break;
diff --git a/services/inputflinger/InputWindow.cpp b/services/inputflinger/InputWindow.cpp
index b54752b..3ae7972 100644
--- a/services/inputflinger/InputWindow.cpp
+++ b/services/inputflinger/InputWindow.cpp
@@ -49,7 +49,8 @@
|| layoutParamsType == TYPE_NAVIGATION_BAR_PANEL
|| layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY
|| layoutParamsType == TYPE_DOCK_DIVIDER
- || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY;
+ || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY
+ || layoutParamsType == TYPE_INPUT_CONSUMER;
}
bool InputWindowInfo::supportsSplitTouch() const {
diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h
index 610290b..9eb2798 100644
--- a/services/inputflinger/InputWindow.h
+++ b/services/inputflinger/InputWindow.h
@@ -101,6 +101,7 @@
TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19,
TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20,
TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21,
+ TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22,
TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24,
TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27,
TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32,
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index ac739a2..cf01ad0 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -755,7 +755,7 @@
}
Error error = kDefaultError;
- mClient->executeCommands(commandLength, commandHandles,
+ auto ret = mClient->executeCommands(commandLength, commandHandles,
[&](const auto& tmpError, const auto& tmpOutChanged,
const auto& tmpOutLength, const auto& tmpOutHandles)
{
@@ -788,6 +788,11 @@
error = Error::NO_RESOURCES;
}
});
+ // executeCommands can fail because of out-of-fd and we do not want to
+ // abort() in that case
+ if (!ret.isOk()) {
+ ALOGE("executeCommands failed because of %s", ret.description().c_str());
+ }
if (error == Error::NONE) {
std::vector<CommandReader::CommandError> commandErrors =
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 12205af..bb0e33c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -604,11 +604,18 @@
if (useVrFlinger) {
auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) {
- ALOGI("VR request display mode: requestDisplay=%d", requestDisplay);
- mVrFlingerRequestsDisplay = requestDisplay;
- ConditionalLock _l(mStateLock,
- std::this_thread::get_id() != mMainThreadId);
- signalTransaction();
+ // This callback is called from the vr flinger dispatch thread. We
+ // need to call signalTransaction(), which requires holding
+ // mStateLock when we're not on the main thread. Acquiring
+ // mStateLock from the vr flinger dispatch thread might trigger a
+ // deadlock in surface flinger (see b/66916578), so post a message
+ // to be handled on the main thread instead.
+ sp<LambdaMessage> message = new LambdaMessage([=]() {
+ ALOGI("VR request display mode: requestDisplay=%d", requestDisplay);
+ mVrFlingerRequestsDisplay = requestDisplay;
+ signalTransaction();
+ });
+ postMessageAsync(message);
};
mVrFlinger = dvr::VrFlinger::Create(mHwc->getComposer(),
vrFlingerRequestDisplayCallback);
@@ -649,6 +656,12 @@
property_get("persist.sys.sf.color_saturation", value, "1.0");
mSaturation = atof(value);
ALOGV("Saturation is set to %.2f", mSaturation);
+
+ property_get("persist.sys.sf.native_mode", value, "0");
+ mForceNativeColorMode = atoi(value) == 1;
+ if (mForceNativeColorMode) {
+ ALOGV("Forcing native color mode");
+ }
}
void SurfaceFlinger::startBootAnim() {
@@ -1228,12 +1241,13 @@
break;
}
}
+ bool useWideColorMode = hasWideColorModes && hasWideColorDisplay && !mForceNativeColorMode;
sp<DisplayDevice> hw = new DisplayDevice(this, DisplayDevice::DISPLAY_PRIMARY, type, isSecure,
token, fbs, producer, mRenderEngine->getEGLConfig(),
- hasWideColorModes && hasWideColorDisplay);
+ useWideColorMode);
mDisplays.add(token, hw);
android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
- if (hasWideColorModes && hasWideColorDisplay) {
+ if (useWideColorMode) {
defaultColorMode = HAL_COLOR_MODE_SRGB;
}
setActiveColorModeInternal(hw, defaultColorMode);
@@ -1749,6 +1763,10 @@
// pickColorMode translates a given dataspace into the best available color mode.
// Currently only support sRGB and Display-P3.
android_color_mode SurfaceFlinger::pickColorMode(android_dataspace dataSpace) const {
+ if (mForceNativeColorMode) {
+ return HAL_COLOR_MODE_NATIVE;
+ }
+
switch (dataSpace) {
// treat Unknown as regular SRGB buffer, since that's what the rest of the
// system expects.
@@ -2583,8 +2601,10 @@
ALOGV("hasClientComposition");
#ifdef USE_HWC2
- mRenderEngine->setWideColor(displayDevice->getWideColorSupport());
- mRenderEngine->setColorMode(displayDevice->getActiveColorMode());
+ mRenderEngine->setWideColor(
+ displayDevice->getWideColorSupport() && !mForceNativeColorMode);
+ mRenderEngine->setColorMode(mForceNativeColorMode ?
+ HAL_COLOR_MODE_NATIVE : displayDevice->getActiveColorMode());
#endif
if (!displayDevice->makeCurrent(mEGLDisplay, mEGLContext)) {
ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
@@ -3625,6 +3645,7 @@
void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
result.appendFormat("hasWideColorDisplay: %d\n", hasWideColorDisplay);
+ result.appendFormat("forceNativeColorMode: %d\n", mForceNativeColorMode);
// TODO: print out if wide-color mode is active or not
@@ -4078,6 +4099,17 @@
repaintEverything();
return NO_ERROR;
}
+ case 1023: { // Set native mode
+ mForceNativeColorMode = data.readInt32() == 1;
+
+ invalidateHwcGeometry();
+ repaintEverything();
+ return NO_ERROR;
+ }
+ case 1024: { // Is wide color gamut rendering/color management supported?
+ reply->writeBool(hasWideColorDisplay);
+ return NO_ERROR;
+ }
}
}
return err;
@@ -4235,8 +4267,9 @@
WindowDisconnector disconnector(window, NATIVE_WINDOW_API_EGL);
ANativeWindowBuffer* buffer = nullptr;
- result = getWindowBuffer(window, reqWidth, reqHeight, hasWideColorDisplay,
- getRenderEngine().usesWideColor(), &buffer);
+ result = getWindowBuffer(window, reqWidth, reqHeight,
+ hasWideColorDisplay && !mForceNativeColorMode,
+ getRenderEngine().usesWideColor(), &buffer);
if (result != NO_ERROR) {
return result;
}
@@ -4338,8 +4371,8 @@
}
#ifdef USE_HWC2
- engine.setWideColor(hw->getWideColorSupport());
- engine.setColorMode(hw->getActiveColorMode());
+ engine.setWideColor(hw->getWideColorSupport() && !mForceNativeColorMode);
+ engine.setColorMode(mForceNativeColorMode ? HAL_COLOR_MODE_NATIVE : hw->getActiveColorMode());
#endif
// make sure to clear all GL error flags
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 13a057f..7606e10 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -814,6 +814,7 @@
#endif
float mSaturation = 1.0f;
+ bool mForceNativeColorMode = false;
};
}; // namespace android
diff --git a/services/vr/bufferhubd/Android.mk b/services/vr/bufferhubd/Android.mk
index 97f0332..28cf53d 100644
--- a/services/vr/bufferhubd/Android.mk
+++ b/services/vr/bufferhubd/Android.mk
@@ -22,6 +22,9 @@
consumer_queue_channel.cpp \
producer_queue_channel.cpp \
+headerLibraries := \
+ libdvr_headers
+
staticLibraries := \
libperformance \
libpdx_default_transport \
@@ -41,6 +44,7 @@
LOCAL_CFLAGS := -DLOG_TAG=\"bufferhubd\"
LOCAL_CFLAGS += -DTRACE=0
LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_GRAPHICS
+LOCAL_HEADER_LIBRARIES := $(headerLibraries)
LOCAL_STATIC_LIBRARIES := $(staticLibraries)
LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
LOCAL_MODULE := bufferhubd
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index 26843c9..cdb1f91 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -20,8 +20,8 @@
using android::pdx::ErrorStatus;
using android::pdx::Message;
using android::pdx::Status;
-using android::pdx::rpc::DispatchRemoteMethod;
using android::pdx::default_transport::Endpoint;
+using android::pdx::rpc::DispatchRemoteMethod;
namespace android {
namespace dvr {
@@ -53,7 +53,15 @@
stream << " ";
stream << std::setw(6) << "Format";
stream << " ";
- stream << std::setw(11) << "Usage";
+ stream << std::setw(10) << "Usage";
+ stream << " ";
+ stream << std::setw(9) << "Pending";
+ stream << " ";
+ stream << std::setw(18) << "State";
+ stream << " ";
+ stream << std::setw(18) << "Signaled";
+ stream << " ";
+ stream << std::setw(10) << "Index";
stream << " ";
stream << "Name";
stream << std::endl;
@@ -83,46 +91,15 @@
stream << std::setw(8) << info.usage;
stream << std::dec << std::setfill(' ');
stream << " ";
- stream << info.name;
- stream << std::endl;
- }
- }
-
- stream << "Active Consumer Buffers:\n";
- stream << std::right;
- stream << std::setw(6) << "Id";
- stream << " ";
- stream << std::setw(14) << "Geometry";
- stream << " ";
- stream << "Name";
- stream << std::endl;
-
- for (const auto& channel : channels) {
- if (channel->channel_type() == BufferHubChannel::kConsumerType) {
- BufferHubChannel::BufferInfo info = channel->GetBufferInfo();
-
- stream << std::right;
- stream << std::setw(6) << info.id;
+ stream << std::setw(9) << info.pending_count;
stream << " ";
-
- if (info.consumer_count == 0) {
- // consumer_count is tracked by producer. When it's zero, producer must
- // have already hung up and the consumer is orphaned.
- stream << std::setw(14) << "Orphaned.";
- stream << (" channel_id=" + std::to_string(channel->channel_id()));
- stream << std::endl;
- continue;
- }
-
- if (info.format == HAL_PIXEL_FORMAT_BLOB) {
- std::string size = std::to_string(info.width) + " B";
- stream << std::setw(14) << size;
- } else {
- std::string dimensions = std::to_string(info.width) + "x" +
- std::to_string(info.height) + "x" +
- std::to_string(info.layer_count);
- stream << std::setw(14) << dimensions;
- }
+ stream << "0x" << std::hex << std::setfill('0');
+ stream << std::setw(16) << info.state;
+ stream << " ";
+ stream << "0x" << std::setw(16) << info.signaled_mask;
+ stream << std::dec << std::setfill(' ');
+ stream << " ";
+ stream << std::setw(8) << info.index;
stream << " ";
stream << info.name;
stream << std::endl;
@@ -184,6 +161,32 @@
}
}
+ stream << std::endl;
+ stream << "Orphaned Consumer Buffers:\n";
+ stream << std::right;
+ stream << std::setw(6) << "Id";
+ stream << " ";
+ stream << std::setw(14) << "Geometry";
+ stream << " ";
+ stream << "Name";
+ stream << std::endl;
+
+ for (const auto& channel : channels) {
+ BufferHubChannel::BufferInfo info = channel->GetBufferInfo();
+ // consumer_count is tracked by producer. When it's zero, producer must have
+ // already hung up and the consumer is orphaned.
+ if (channel->channel_type() == BufferHubChannel::kConsumerType &&
+ info.consumer_count == 0) {
+ stream << std::right;
+ stream << std::setw(6) << info.id;
+ stream << " ";
+
+ stream << std::setw(14) << "Orphaned.";
+ stream << (" channel_id=" + std::to_string(channel->channel_id()));
+ stream << std::endl;
+ }
+ }
+
return stream.str();
}
@@ -444,6 +447,7 @@
"BufferHubChannel::SignalAvailable: channel_id=%d buffer_id=%d",
channel_id(), buffer_id());
if (!IsDetached()) {
+ signaled_ = true;
const auto status = service_->ModifyChannelEvents(channel_id_, 0, POLLIN);
ALOGE_IF(!status,
"BufferHubChannel::SignalAvailable: failed to signal availability "
@@ -460,6 +464,7 @@
"BufferHubChannel::ClearAvailable: channel_id=%d buffer_id=%d",
channel_id(), buffer_id());
if (!IsDetached()) {
+ signaled_ = false;
const auto status = service_->ModifyChannelEvents(channel_id_, POLLIN, 0);
ALOGE_IF(!status,
"BufferHubChannel::ClearAvailable: failed to clear availability "
diff --git a/services/vr/bufferhubd/buffer_hub.h b/services/vr/bufferhubd/buffer_hub.h
index b0df11f..270ac95 100644
--- a/services/vr/bufferhubd/buffer_hub.h
+++ b/services/vr/bufferhubd/buffer_hub.h
@@ -53,6 +53,10 @@
uint32_t layer_count = 0;
uint32_t format = 0;
uint64_t usage = 0;
+ size_t pending_count = 0;
+ uint64_t state = 0;
+ uint64_t signaled_mask = 0;
+ uint64_t index = 0;
std::string name;
// Data filed for producer queue.
@@ -60,7 +64,9 @@
UsagePolicy usage_policy{0, 0, 0, 0};
BufferInfo(int id, size_t consumer_count, uint32_t width, uint32_t height,
- uint32_t layer_count, uint32_t format, uint64_t usage, const std::string& name)
+ uint32_t layer_count, uint32_t format, uint64_t usage,
+ size_t pending_count, uint64_t state, uint64_t signaled_mask,
+ uint64_t index, const std::string& name)
: id(id),
type(kProducerType),
consumer_count(consumer_count),
@@ -69,6 +75,10 @@
layer_count(layer_count),
format(format),
usage(usage),
+ pending_count(pending_count),
+ state(state),
+ signaled_mask(signaled_mask),
+ index(index),
name(name) {}
BufferInfo(int id, size_t consumer_count, size_t capacity,
@@ -101,6 +111,8 @@
int channel_id() const { return channel_id_; }
bool IsDetached() const { return channel_id_ == kDetachedId; }
+ bool signaled() const { return signaled_; }
+
void Detach() {
if (channel_type_ == kProducerType)
channel_id_ = kDetachedId;
@@ -124,6 +136,8 @@
// buffer if it is detached and re-attached to another channel.
int channel_id_;
+ bool signaled_;
+
ChannelType channel_type_;
BufferHubChannel(const BufferHubChannel&) = delete;
diff --git a/services/vr/bufferhubd/bufferhubd.cpp b/services/vr/bufferhubd/bufferhubd.cpp
index 1613821..b27f218 100644
--- a/services/vr/bufferhubd/bufferhubd.cpp
+++ b/services/vr/bufferhubd/bufferhubd.cpp
@@ -2,6 +2,7 @@
#include <unistd.h>
#include <log/log.h>
+#include <sys/resource.h>
#include <dvr/performance_client_api.h>
#include <pdx/service_dispatcher.h>
@@ -16,6 +17,23 @@
// We need to be able to create endpoints with full perms.
umask(0000);
+ // Bump up the soft limit of open fd to the hard limit.
+ struct rlimit64 rlim;
+ ret = getrlimit64(RLIMIT_NOFILE, &rlim);
+ LOG_ALWAYS_FATAL_IF(ret != 0, "Failed to get nofile limit.");
+
+ ALOGI("Current nofile limit is %llu/%llu.", rlim.rlim_cur, rlim.rlim_max);
+ rlim.rlim_cur = rlim.rlim_max;
+ ret = setrlimit64(RLIMIT_NOFILE, &rlim);
+ ALOGE_IF(ret < 0, "Failed to set nofile limit, error=%s", strerror(errno));
+
+ rlim.rlim_cur = -1;
+ rlim.rlim_max = -1;
+ if (getrlimit64(RLIMIT_NOFILE, &rlim) < 0)
+ ALOGE("Failed to get nofile limit.");
+ else
+ ALOGI("New nofile limit is %llu/%llu.", rlim.rlim_cur, rlim.rlim_max);
+
dispatcher = android::pdx::ServiceDispatcher::Create();
CHECK_ERROR(!dispatcher, error, "Failed to create service dispatcher\n");
diff --git a/services/vr/bufferhubd/consumer_channel.cpp b/services/vr/bufferhubd/consumer_channel.cpp
index ac6896a..a6d2dbb 100644
--- a/services/vr/bufferhubd/consumer_channel.cpp
+++ b/services/vr/bufferhubd/consumer_channel.cpp
@@ -19,9 +19,10 @@
namespace dvr {
ConsumerChannel::ConsumerChannel(BufferHubService* service, int buffer_id,
- int channel_id,
+ int channel_id, uint64_t consumer_state_bit,
const std::shared_ptr<Channel> producer)
: BufferHubChannel(service, buffer_id, channel_id, kConsumerType),
+ consumer_state_bit_(consumer_state_bit),
producer_(producer) {
GetProducer()->AddConsumer(this);
}
@@ -32,8 +33,6 @@
channel_id(), buffer_id());
if (auto producer = GetProducer()) {
- if (!released_) // Producer is waiting for our Release.
- producer->OnConsumerIgnored();
producer->RemoveConsumer(this);
}
}
@@ -43,6 +42,8 @@
if (auto producer = GetProducer()) {
// If producer has not hung up, copy most buffer info from the producer.
info = producer->GetBufferInfo();
+ } else {
+ info.signaled_mask = consumer_state_bit();
}
info.id = buffer_id();
return info;
@@ -55,6 +56,9 @@
void ConsumerChannel::HandleImpulse(Message& message) {
ATRACE_NAME("ConsumerChannel::HandleImpulse");
switch (message.GetOp()) {
+ case BufferHubRPC::ConsumerAcquire::Opcode:
+ OnConsumerAcquire(message);
+ break;
case BufferHubRPC::ConsumerRelease::Opcode:
OnConsumerRelease(message, {});
break;
@@ -70,7 +74,7 @@
switch (message.GetOp()) {
case BufferHubRPC::GetBuffer::Opcode:
DispatchRemoteMethod<BufferHubRPC::GetBuffer>(
- *producer, &ProducerChannel::OnGetBuffer, message);
+ *this, &ConsumerChannel::OnGetBuffer, message);
return true;
case BufferHubRPC::NewConsumer::Opcode:
@@ -98,9 +102,18 @@
}
}
-Status<std::pair<BorrowedFence, ConsumerChannel::MetaData>>
-ConsumerChannel::OnConsumerAcquire(Message& message,
- std::size_t metadata_size) {
+Status<BufferDescription<BorrowedHandle>> ConsumerChannel::OnGetBuffer(
+ Message& /*message*/) {
+ ATRACE_NAME("ConsumerChannel::OnGetBuffer");
+ ALOGD_IF(TRACE, "ConsumerChannel::OnGetBuffer: buffer=%d", buffer_id());
+ if (auto producer = GetProducer()) {
+ return {producer->GetBuffer(consumer_state_bit_)};
+ } else {
+ return ErrorStatus(EPIPE);
+ }
+}
+
+Status<LocalFence> ConsumerChannel::OnConsumerAcquire(Message& message) {
ATRACE_NAME("ConsumerChannel::OnConsumerAcquire");
auto producer = GetProducer();
if (!producer)
@@ -114,7 +127,7 @@
producer->buffer_id());
return ErrorStatus(EBUSY);
} else {
- auto status = producer->OnConsumerAcquire(message, metadata_size);
+ auto status = producer->OnConsumerAcquire(message);
if (status) {
ClearAvailable();
acquired_ = true;
diff --git a/services/vr/bufferhubd/consumer_channel.h b/services/vr/bufferhubd/consumer_channel.h
index 208a002..55cf969 100644
--- a/services/vr/bufferhubd/consumer_channel.h
+++ b/services/vr/bufferhubd/consumer_channel.h
@@ -12,32 +12,35 @@
// Consumer channels are attached to a Producer channel
class ConsumerChannel : public BufferHubChannel {
public:
+ using BorrowedHandle = pdx::BorrowedHandle;
using Channel = pdx::Channel;
using Message = pdx::Message;
ConsumerChannel(BufferHubService* service, int buffer_id, int channel_id,
+ uint64_t consumer_state_bit,
const std::shared_ptr<Channel> producer);
~ConsumerChannel() override;
bool HandleMessage(Message& message) override;
void HandleImpulse(Message& message) override;
+ uint64_t consumer_state_bit() const { return consumer_state_bit_; }
BufferInfo GetBufferInfo() const override;
bool OnProducerPosted();
void OnProducerClosed();
private:
- using MetaData = pdx::rpc::BufferWrapper<std::uint8_t*>;
-
std::shared_ptr<ProducerChannel> GetProducer() const;
- pdx::Status<std::pair<BorrowedFence, MetaData>> OnConsumerAcquire(
- Message& message, std::size_t metadata_size);
+ pdx::Status<BufferDescription<BorrowedHandle>> OnGetBuffer(Message& message);
+
+ pdx::Status<LocalFence> OnConsumerAcquire(Message& message);
pdx::Status<void> OnConsumerRelease(Message& message,
LocalFence release_fence);
pdx::Status<void> OnConsumerSetIgnore(Message& message, bool ignore);
+ uint64_t consumer_state_bit_{0};
bool acquired_{false};
bool released_{true};
bool ignored_{false}; // True if we are ignoring events.
diff --git a/services/vr/bufferhubd/consumer_queue_channel.cpp b/services/vr/bufferhubd/consumer_queue_channel.cpp
index f447e00..4d43001 100644
--- a/services/vr/bufferhubd/consumer_queue_channel.cpp
+++ b/services/vr/bufferhubd/consumer_queue_channel.cpp
@@ -15,10 +15,11 @@
ConsumerQueueChannel::ConsumerQueueChannel(
BufferHubService* service, int buffer_id, int channel_id,
- const std::shared_ptr<Channel>& producer)
+ const std::shared_ptr<Channel>& producer, bool silent)
: BufferHubChannel(service, buffer_id, channel_id, kConsumerQueueType),
producer_(producer),
- capacity_(0) {
+ capacity_(0),
+ silent_(silent) {
GetProducer()->AddConsumer(this);
}
@@ -83,23 +84,30 @@
void ConsumerQueueChannel::RegisterNewBuffer(
const std::shared_ptr<ProducerChannel>& producer_channel, size_t slot) {
ALOGD_IF(TRACE,
- "ConsumerQueueChannel::RegisterNewBuffer: buffer_id=%d slot=%zu",
- producer_channel->buffer_id(), slot);
- pending_buffer_slots_.emplace(producer_channel, slot);
+ "ConsumerQueueChannel::RegisterNewBuffer: queue_id=%d buffer_id=%d "
+ "slot=%zu silent=%d",
+ buffer_id(), producer_channel->buffer_id(), slot, silent_);
+ // Only register buffers if the queue is not silent.
+ if (!silent_) {
+ pending_buffer_slots_.emplace(producer_channel, slot);
- // Signal the client that there is new buffer available throught POLLIN.
- SignalAvailable();
+ // Signal the client that there is new buffer available.
+ SignalAvailable();
+ }
}
Status<std::vector<std::pair<RemoteChannelHandle, size_t>>>
ConsumerQueueChannel::OnConsumerQueueImportBuffers(Message& message) {
std::vector<std::pair<RemoteChannelHandle, size_t>> buffer_handles;
ATRACE_NAME("ConsumerQueueChannel::OnConsumerQueueImportBuffers");
- ALOGD_IF(
- TRACE,
- "ConsumerQueueChannel::OnConsumerQueueImportBuffers number of buffers to "
- "import: %zu",
- pending_buffer_slots_.size());
+ ALOGD_IF(TRACE,
+ "ConsumerQueueChannel::OnConsumerQueueImportBuffers: "
+ "pending_buffer_slots=%zu",
+ pending_buffer_slots_.size());
+
+ // Indicate this is a silent queue that will not import buffers.
+ if (silent_)
+ return ErrorStatus(EBADR);
while (!pending_buffer_slots_.empty()) {
auto producer_channel = pending_buffer_slots_.front().first.lock();
diff --git a/services/vr/bufferhubd/consumer_queue_channel.h b/services/vr/bufferhubd/consumer_queue_channel.h
index aa3f531..8437c4c 100644
--- a/services/vr/bufferhubd/consumer_queue_channel.h
+++ b/services/vr/bufferhubd/consumer_queue_channel.h
@@ -19,7 +19,7 @@
using RemoteChannelHandle = pdx::RemoteChannelHandle;
ConsumerQueueChannel(BufferHubService* service, int buffer_id, int channel_id,
- const std::shared_ptr<Channel>& producer);
+ const std::shared_ptr<Channel>& producer, bool silent);
~ConsumerQueueChannel() override;
bool HandleMessage(Message& message) override;
@@ -54,6 +54,10 @@
// Tracks how many buffers have this queue imported.
size_t capacity_;
+ // A silent queue does not signal or export buffers. It is only used to spawn
+ // another consumer queue.
+ bool silent_;
+
ConsumerQueueChannel(const ConsumerQueueChannel&) = delete;
void operator=(const ConsumerQueueChannel&) = delete;
};
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index b2db795..716db5e 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -2,6 +2,8 @@
#include <log/log.h>
#include <sync/sync.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
#include <sys/poll.h>
#include <utils/Trace.h>
@@ -24,24 +26,88 @@
namespace android {
namespace dvr {
+namespace {
+
+static inline uint64_t FindNextClearedBit(uint64_t bits) {
+ return ~bits - (~bits & (~bits - 1));
+}
+
+} // namespace
+
ProducerChannel::ProducerChannel(BufferHubService* service, int channel_id,
uint32_t width, uint32_t height,
uint32_t layer_count, uint32_t format,
- uint64_t usage, size_t meta_size_bytes,
+ uint64_t usage, size_t user_metadata_size,
int* error)
: BufferHubChannel(service, channel_id, channel_id, kProducerType),
pending_consumers_(0),
producer_owns_(true),
- meta_size_bytes_(meta_size_bytes),
- meta_(meta_size_bytes ? new uint8_t[meta_size_bytes] : nullptr) {
- const int ret = buffer_.Alloc(width, height, layer_count, format, usage);
- if (ret < 0) {
+ user_metadata_size_(user_metadata_size),
+ metadata_buf_size_(BufferHubDefs::kMetadataHeaderSize +
+ user_metadata_size) {
+ if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
ALOGE("ProducerChannel::ProducerChannel: Failed to allocate buffer: %s",
strerror(-ret));
*error = ret;
return;
}
+ if (int ret = metadata_buffer_.Alloc(metadata_buf_size_, /*height=*/1,
+ /*layer_count=*/1,
+ BufferHubDefs::kMetadataFormat,
+ BufferHubDefs::kMetadataUsage)) {
+ ALOGE("ProducerChannel::ProducerChannel: Failed to allocate metadata: %s",
+ strerror(-ret));
+ *error = ret;
+ return;
+ }
+
+ void* metadata_ptr = nullptr;
+ if (int ret = metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
+ /*y=*/0, metadata_buf_size_,
+ /*height=*/1, &metadata_ptr)) {
+ ALOGE("ProducerChannel::ProducerChannel: Failed to lock metadata.");
+ *error = -ret;
+ return;
+ }
+ metadata_header_ =
+ reinterpret_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
+
+ // Using placement new here to reuse shared memory instead of new allocation
+ // and also initialize the value to zero.
+ buffer_state_ =
+ new (&metadata_header_->buffer_state) std::atomic<uint64_t>(0);
+ fence_state_ =
+ new (&metadata_header_->fence_state) std::atomic<uint64_t>(0);
+
+ acquire_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
+ release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
+ if (!acquire_fence_fd_ || !release_fence_fd_) {
+ ALOGE("ProducerChannel::ProducerChannel: Failed to create shared fences.");
+ *error = -EIO;
+ return;
+ }
+
+ dummy_fence_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
+ if (!dummy_fence_fd_) {
+ ALOGE("ProducerChannel::ProducerChannel: Failed to create dummy fences.");
+ *error = -EIO;
+ return;
+ }
+
+ epoll_event event;
+ event.events = 0;
+ event.data.u64 = 0ULL;
+ if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_ADD, dummy_fence_fd_.Get(),
+ &event) < 0) {
+ ALOGE(
+ "ProducerChannel::ProducerChannel: Failed to modify the shared "
+ "release fence to include the dummy fence: %s",
+ strerror(errno));
+ *error = -EIO;
+ return;
+ }
+
// Success.
*error = 0;
}
@@ -49,11 +115,11 @@
Status<std::shared_ptr<ProducerChannel>> ProducerChannel::Create(
BufferHubService* service, int channel_id, uint32_t width, uint32_t height,
uint32_t layer_count, uint32_t format, uint64_t usage,
- size_t meta_size_bytes) {
+ size_t user_metadata_size) {
int error;
std::shared_ptr<ProducerChannel> producer(
new ProducerChannel(service, channel_id, width, height, layer_count,
- format, usage, meta_size_bytes, &error));
+ format, usage, user_metadata_size, &error));
if (error < 0)
return ErrorStatus(-error);
else
@@ -62,16 +128,24 @@
ProducerChannel::~ProducerChannel() {
ALOGD_IF(TRACE,
- "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d",
- channel_id(), buffer_id());
+ "ProducerChannel::~ProducerChannel: channel_id=%d buffer_id=%d "
+ "state=%" PRIx64 ".",
+ channel_id(), buffer_id(), buffer_state_->load());
for (auto consumer : consumer_channels_)
consumer->OnProducerClosed();
}
BufferHubChannel::BufferInfo ProducerChannel::GetBufferInfo() const {
+ // Derive the mask of signaled buffers in this producer / consumer set.
+ uint64_t signaled_mask = signaled() ? BufferHubDefs::kProducerStateBit : 0;
+ for (const ConsumerChannel* consumer : consumer_channels_) {
+ signaled_mask |= consumer->signaled() ? consumer->consumer_state_bit() : 0;
+ }
+
return BufferInfo(buffer_id(), consumer_channels_.size(), buffer_.width(),
buffer_.height(), buffer_.layer_count(), buffer_.format(),
- buffer_.usage(), name_);
+ buffer_.usage(), pending_consumers_, buffer_state_->load(),
+ signaled_mask, metadata_header_->queue_index, name_);
}
void ProducerChannel::HandleImpulse(Message& message) {
@@ -80,6 +154,9 @@
case BufferHubRPC::ProducerGain::Opcode:
OnProducerGain(message);
break;
+ case BufferHubRPC::ProducerPost::Opcode:
+ OnProducerPost(message, {});
+ break;
}
}
@@ -121,16 +198,26 @@
}
}
-Status<NativeBufferHandle<BorrowedHandle>> ProducerChannel::OnGetBuffer(
+BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
+ uint64_t buffer_state_bit) {
+ return {
+ buffer_, metadata_buffer_, buffer_id(),
+ buffer_state_bit, acquire_fence_fd_.Borrow(), release_fence_fd_.Borrow()};
+}
+
+Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer(
Message& /*message*/) {
ATRACE_NAME("ProducerChannel::OnGetBuffer");
- ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d", buffer_id());
- return {NativeBufferHandle<BorrowedHandle>(buffer_, buffer_id())};
+ ALOGD_IF(TRACE, "ProducerChannel::OnGetBuffer: buffer=%d, state=%" PRIx64 ".",
+ buffer_id(), buffer_state_->load());
+ return {GetBuffer(BufferHubDefs::kProducerStateBit)};
}
Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
ATRACE_NAME("ProducerChannel::CreateConsumer");
- ALOGD_IF(TRACE, "ProducerChannel::CreateConsumer: buffer_id=%d", buffer_id());
+ ALOGD_IF(TRACE,
+ "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
+ buffer_id(), producer_owns_);
int channel_id;
auto status = message.PushChannel(0, nullptr, &channel_id);
@@ -141,8 +228,21 @@
return ErrorStatus(ENOMEM);
}
- auto consumer = std::make_shared<ConsumerChannel>(
- service(), buffer_id(), channel_id, shared_from_this());
+ // Try find the next consumer state bit which has not been claimed by any
+ // consumer yet.
+ uint64_t consumer_state_bit = FindNextClearedBit(
+ active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ |
+ BufferHubDefs::kProducerStateBit);
+ if (consumer_state_bit == 0ULL) {
+ ALOGE(
+ "ProducerChannel::CreateConsumer: reached the maximum mumber of "
+ "consumers per producer: 63.");
+ return ErrorStatus(E2BIG);
+ }
+
+ auto consumer =
+ std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
+ consumer_state_bit, shared_from_this());
const auto channel_status = service()->SetChannel(channel_id, consumer);
if (!channel_status) {
ALOGE(
@@ -152,12 +252,14 @@
return ErrorStatus(ENOMEM);
}
- if (!producer_owns_) {
+ if (!producer_owns_ &&
+ !BufferHubDefs::IsBufferReleased(buffer_state_->load())) {
// Signal the new consumer when adding it to a posted producer.
if (consumer->OnProducerPosted())
pending_consumers_++;
}
+ active_consumer_bit_mask_ |= consumer_state_bit;
return {status.take()};
}
@@ -168,8 +270,7 @@
}
Status<void> ProducerChannel::OnProducerPost(
- Message&, LocalFence acquire_fence,
- BufferWrapper<std::vector<std::uint8_t>> metadata) {
+ Message&, LocalFence acquire_fence) {
ATRACE_NAME("ProducerChannel::OnProducerPost");
ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
if (!producer_owns_) {
@@ -177,27 +278,45 @@
return ErrorStatus(EBUSY);
}
- if (meta_size_bytes_ != metadata.size()) {
- ALOGD_IF(TRACE,
- "ProducerChannel::OnProducerPost: Expected meta_size_bytes=%zu "
- "got size=%zu",
- meta_size_bytes_, metadata.size());
- return ErrorStatus(EINVAL);
+ epoll_event event;
+ event.events = 0;
+ event.data.u64 = 0ULL;
+ int ret = epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
+ dummy_fence_fd_.Get(), &event);
+ ALOGE_IF(ret < 0,
+ "ProducerChannel::OnProducerPost: Failed to modify the shared "
+ "release fence to include the dummy fence: %s",
+ strerror(errno));
+
+ eventfd_t dummy_fence_count = 0ULL;
+ if (eventfd_read(dummy_fence_fd_.Get(), &dummy_fence_count) < 0) {
+ const int error = errno;
+ if (error != EAGAIN) {
+ ALOGE(
+ "ProducerChannel::ProducerChannel: Failed to read dummy fence, "
+ "error: %s",
+ strerror(error));
+ return ErrorStatus(error);
+ }
}
- std::copy(metadata.begin(), metadata.end(), meta_.get());
+ ALOGW_IF(dummy_fence_count > 0,
+ "ProducerChannel::ProducerChannel: %" PRIu64
+ " dummy fence(s) was signaled during last release/gain cycle "
+ "buffer_id=%d.",
+ dummy_fence_count, buffer_id());
+
post_fence_ = std::move(acquire_fence);
producer_owns_ = false;
- // Signal any interested consumers. If there are none, automatically release
- // the buffer.
+ // Signal any interested consumers. If there are none, the buffer will stay
+ // in posted state until a consumer comes online. This behavior guarantees
+ // that no frame is silently dropped.
pending_consumers_ = 0;
for (auto consumer : consumer_channels_) {
if (consumer->OnProducerPosted())
pending_consumers_++;
}
- if (pending_consumers_ == 0)
- SignalAvailable();
ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: %d pending consumers",
pending_consumers_);
@@ -214,8 +333,13 @@
}
// There are still pending consumers, return busy.
- if (pending_consumers_ > 0)
+ if (pending_consumers_ > 0) {
+ ALOGE(
+ "ProducerChannel::OnGain: Producer (id=%d) is gaining a buffer that "
+ "still has %d pending consumer(s).",
+ buffer_id(), pending_consumers_);
return ErrorStatus(EBUSY);
+ }
ClearAvailable();
producer_owns_ = true;
@@ -223,9 +347,7 @@
return {std::move(returned_fence_)};
}
-Status<std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>>>
-ProducerChannel::OnConsumerAcquire(Message& /*message*/,
- std::size_t metadata_size) {
+Status<LocalFence> ProducerChannel::OnConsumerAcquire(Message& /*message*/) {
ATRACE_NAME("ProducerChannel::OnConsumerAcquire");
ALOGD_IF(TRACE, "ProducerChannel::OnConsumerAcquire: buffer_id=%d",
buffer_id());
@@ -236,12 +358,7 @@
// Return a borrowed fd to avoid unnecessary duplication of the underlying fd.
// Serialization just needs to read the handle.
- if (metadata_size == 0)
- return {std::make_pair(post_fence_.borrow(),
- WrapBuffer<std::uint8_t>(nullptr, 0))};
- else
- return {std::make_pair(post_fence_.borrow(),
- WrapBuffer(meta_.get(), meta_size_bytes_))};
+ return {std::move(post_fence_)};
}
Status<void> ProducerChannel::OnConsumerRelease(Message&,
@@ -273,17 +390,75 @@
}
OnConsumerIgnored();
+ if (pending_consumers_ == 0) {
+ // Clear the producer bit atomically to transit into released state. This
+ // has to done by BufferHub as it requries synchronization among all
+ // consumers.
+ BufferHubDefs::ModifyBufferState(buffer_state_,
+ BufferHubDefs::kProducerStateBit, 0ULL);
+ ALOGD_IF(TRACE,
+ "ProducerChannel::OnConsumerRelease: releasing last consumer: "
+ "buffer_id=%d state=%" PRIx64 ".",
+ buffer_id(), buffer_state_->load());
+
+ if (orphaned_consumer_bit_mask_) {
+ ALOGW(
+ "ProducerChannel::OnConsumerRelease: orphaned buffer detected "
+ "during the this acquire/release cycle: id=%d orphaned=0x%" PRIx64
+ " queue_index=%" PRIu64 ".",
+ buffer_id(), orphaned_consumer_bit_mask_,
+ metadata_header_->queue_index);
+ orphaned_consumer_bit_mask_ = 0;
+ }
+
+ SignalAvailable();
+ }
+
+ ALOGE_IF(pending_consumers_ &&
+ BufferHubDefs::IsBufferReleased(buffer_state_->load()),
+ "ProducerChannel::OnConsumerRelease: buffer state inconsistent: "
+ "pending_consumers=%d, buffer buffer is in releaed state.",
+ pending_consumers_);
return {};
}
void ProducerChannel::OnConsumerIgnored() {
- if (!--pending_consumers_)
- SignalAvailable();
+ if (pending_consumers_ == 0) {
+ ALOGE("ProducerChannel::OnConsumerIgnored: no pending consumer.");
+ return;
+ }
+
+ --pending_consumers_;
ALOGD_IF(TRACE,
"ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left",
buffer_id(), pending_consumers_);
}
+void ProducerChannel::OnConsumerOrphaned(ConsumerChannel* channel) {
+ // Ignore the orphaned consumer.
+ OnConsumerIgnored();
+
+ const uint64_t consumer_state_bit = channel->consumer_state_bit();
+ ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_bit,
+ "ProducerChannel::OnConsumerOrphaned: Consumer "
+ "(consumer_state_bit=%" PRIx64 ") is already orphaned.",
+ consumer_state_bit);
+ orphaned_consumer_bit_mask_ |= consumer_state_bit;
+
+ // Atomically clear the fence state bit as an orphaned consumer will never
+ // signal a release fence. Also clear the buffer state as it won't be released
+ // as well.
+ fence_state_->fetch_and(~consumer_state_bit);
+ BufferHubDefs::ModifyBufferState(buffer_state_, consumer_state_bit, 0ULL);
+
+ ALOGW(
+ "ProducerChannel::OnConsumerOrphaned: detected new orphaned consumer "
+ "buffer_id=%d consumer_state_bit=%" PRIx64 " queue_index=%" PRIu64
+ " buffer_state=%" PRIx64 " fence_state=%" PRIx64 ".",
+ buffer_id(), consumer_state_bit, metadata_header_->queue_index,
+ buffer_state_->load(), fence_state_->load());
+}
+
Status<void> ProducerChannel::OnProducerMakePersistent(Message& message,
const std::string& name,
int user_id,
@@ -335,6 +510,40 @@
void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
consumer_channels_.erase(
std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
+ active_consumer_bit_mask_ &= ~channel->consumer_state_bit();
+
+ const uint64_t buffer_state = buffer_state_->load();
+ if (BufferHubDefs::IsBufferPosted(buffer_state) ||
+ BufferHubDefs::IsBufferAcquired(buffer_state)) {
+ // The consumer client is being destoryed without releasing. This could
+ // happen in corner cases when the consumer crashes. Here we mark it
+ // orphaned before remove it from producer.
+ OnConsumerOrphaned(channel);
+ }
+
+ if (BufferHubDefs::IsBufferReleased(buffer_state) ||
+ BufferHubDefs::IsBufferGained(buffer_state)) {
+ // The consumer is being close while it is suppose to signal a release
+ // fence. Signal the dummy fence here.
+ if (fence_state_->load() & channel->consumer_state_bit()) {
+ epoll_event event;
+ event.events = EPOLLIN;
+ event.data.u64 = channel->consumer_state_bit();
+ if (epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
+ dummy_fence_fd_.Get(), &event) < 0) {
+ ALOGE(
+ "ProducerChannel::RemoveConsumer: Failed to modify the shared "
+ "release fence to include the dummy fence: %s",
+ strerror(errno));
+ return;
+ }
+ ALOGW(
+ "ProducerChannel::RemoveConsumer: signal dummy release fence "
+ "buffer_id=%d",
+ buffer_id());
+ eventfd_write(dummy_fence_fd_.Get(), 1);
+ }
+ }
}
// Returns true if either the user or group ids match the owning ids or both
@@ -350,10 +559,12 @@
// Returns true if the given parameters match the underlying buffer parameters.
bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
uint32_t layer_count, uint32_t format,
- uint64_t usage, size_t meta_size_bytes) {
- return meta_size_bytes == meta_size_bytes_ && buffer_.width() == width &&
- buffer_.height() == height && buffer_.layer_count() == layer_count &&
- buffer_.format() == format && buffer_.usage() == usage;
+ uint64_t usage,
+ size_t user_metadata_size) {
+ return user_metadata_size == user_metadata_size_ &&
+ buffer_.width() == width && buffer_.height() == height &&
+ buffer_.layer_count() == layer_count && buffer_.format() == format &&
+ buffer_.usage() == usage;
}
} // namespace dvr
diff --git a/services/vr/bufferhubd/producer_channel.h b/services/vr/bufferhubd/producer_channel.h
index 5ada478..e280f4d 100644
--- a/services/vr/bufferhubd/producer_channel.h
+++ b/services/vr/bufferhubd/producer_channel.h
@@ -33,7 +33,7 @@
static pdx::Status<std::shared_ptr<ProducerChannel>> Create(
BufferHubService* service, int channel_id, uint32_t width,
uint32_t height, uint32_t layer_count, uint32_t format, uint64_t usage,
- size_t meta_size_bytes);
+ size_t user_metadata_size);
~ProducerChannel() override;
@@ -42,24 +42,25 @@
BufferInfo GetBufferInfo() const override;
- pdx::Status<NativeBufferHandle<BorrowedHandle>> OnGetBuffer(Message& message);
+ BufferDescription<BorrowedHandle> GetBuffer(uint64_t buffer_state_bit);
pdx::Status<RemoteChannelHandle> CreateConsumer(Message& message);
pdx::Status<RemoteChannelHandle> OnNewConsumer(Message& message);
- pdx::Status<std::pair<BorrowedFence, BufferWrapper<std::uint8_t*>>>
- OnConsumerAcquire(Message& message, std::size_t metadata_size);
+ pdx::Status<LocalFence> OnConsumerAcquire(Message& message);
pdx::Status<void> OnConsumerRelease(Message& message,
LocalFence release_fence);
void OnConsumerIgnored();
+ void OnConsumerOrphaned(ConsumerChannel* channel);
void AddConsumer(ConsumerChannel* channel);
void RemoveConsumer(ConsumerChannel* channel);
bool CheckAccess(int euid, int egid);
bool CheckParameters(uint32_t width, uint32_t height, uint32_t layer_count,
- uint32_t format, uint64_t usage, size_t meta_size_bytes);
+ uint32_t format, uint64_t usage,
+ size_t user_metadata_size);
pdx::Status<void> OnProducerMakePersistent(Message& message,
const std::string& name,
@@ -74,11 +75,28 @@
IonBuffer buffer_;
+ // IonBuffer that is shared between bufferhubd, producer, and consumers.
+ IonBuffer metadata_buffer_;
+ BufferHubDefs::MetadataHeader* metadata_header_ = nullptr;
+ std::atomic<uint64_t>* buffer_state_ = nullptr;
+ std::atomic<uint64_t>* fence_state_ = nullptr;
+
+ // All active consumer bits. Valid bits are the lower 63 bits, while the
+ // highest bit is reserved for the producer and should not be set.
+ uint64_t active_consumer_bit_mask_{0ULL};
+ // All orphaned consumer bits. Valid bits are the lower 63 bits, while the
+ // highest bit is reserved for the producer and should not be set.
+ uint64_t orphaned_consumer_bit_mask_{0ULL};
+
bool producer_owns_;
LocalFence post_fence_;
LocalFence returned_fence_;
- size_t meta_size_bytes_;
- std::unique_ptr<uint8_t[]> meta_;
+ size_t user_metadata_size_; // size of user requested buffer buffer size.
+ size_t metadata_buf_size_; // size of the ion buffer that holds metadata.
+
+ pdx::LocalHandle acquire_fence_fd_;
+ pdx::LocalHandle release_fence_fd_;
+ pdx::LocalHandle dummy_fence_fd_;
static constexpr int kNoCheckId = -1;
static constexpr int kUseCallerId = 0;
@@ -92,11 +110,10 @@
ProducerChannel(BufferHubService* service, int channel, uint32_t width,
uint32_t height, uint32_t layer_count, uint32_t format,
- uint64_t usage, size_t meta_size_bytes, int* error);
+ uint64_t usage, size_t user_metadata_size, int* error);
- pdx::Status<void> OnProducerPost(
- Message& message, LocalFence acquire_fence,
- BufferWrapper<std::vector<std::uint8_t>> metadata);
+ pdx::Status<BufferDescription<BorrowedHandle>> OnGetBuffer(Message& message);
+ pdx::Status<void> OnProducerPost(Message& message, LocalFence acquire_fence);
pdx::Status<LocalFence> OnProducerGain(Message& message);
ProducerChannel(const ProducerChannel&) = delete;
diff --git a/services/vr/bufferhubd/producer_queue_channel.cpp b/services/vr/bufferhubd/producer_queue_channel.cpp
index b8bb728..c0c48c2 100644
--- a/services/vr/bufferhubd/producer_queue_channel.cpp
+++ b/services/vr/bufferhubd/producer_queue_channel.cpp
@@ -7,8 +7,8 @@
using android::pdx::ErrorStatus;
using android::pdx::Message;
-using android::pdx::Status;
using android::pdx::RemoteChannelHandle;
+using android::pdx::Status;
using android::pdx::rpc::DispatchRemoteMethod;
namespace android {
@@ -96,10 +96,12 @@
}
Status<RemoteChannelHandle> ProducerQueueChannel::OnCreateConsumerQueue(
- Message& message) {
+ Message& message, bool silent) {
ATRACE_NAME("ProducerQueueChannel::OnCreateConsumerQueue");
- ALOGD_IF(TRACE, "ProducerQueueChannel::OnCreateConsumerQueue: channel_id=%d",
- channel_id());
+ ALOGD_IF(
+ TRACE,
+ "ProducerQueueChannel::OnCreateConsumerQueue: channel_id=%d slient=%d",
+ channel_id(), silent);
int channel_id;
auto status = message.PushChannel(0, nullptr, &channel_id);
@@ -112,7 +114,7 @@
}
auto consumer_queue_channel = std::make_shared<ConsumerQueueChannel>(
- service(), buffer_id(), channel_id, shared_from_this());
+ service(), buffer_id(), channel_id, shared_from_this(), silent);
// Register the existing buffers with the new consumer queue.
for (size_t slot = 0; slot < BufferHubRPC::kMaxQueueCapacity; slot++) {
@@ -222,7 +224,7 @@
auto producer_channel_status =
ProducerChannel::Create(service(), buffer_id, width, height, layer_count,
- format, usage, config_.meta_size_bytes);
+ format, usage, config_.user_metadata_size);
if (!producer_channel_status) {
ALOGE(
"ProducerQueueChannel::AllocateBuffer: Failed to create producer "
diff --git a/services/vr/bufferhubd/producer_queue_channel.h b/services/vr/bufferhubd/producer_queue_channel.h
index fd519c5..e825f47 100644
--- a/services/vr/bufferhubd/producer_queue_channel.h
+++ b/services/vr/bufferhubd/producer_queue_channel.h
@@ -26,7 +26,7 @@
// Returns a handle for the service channel, as well as the size of the
// metadata associated with the queue.
pdx::Status<pdx::RemoteChannelHandle> OnCreateConsumerQueue(
- pdx::Message& message);
+ pdx::Message& message, bool silent);
pdx::Status<QueueInfo> OnGetQueueInfo(pdx::Message& message);
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index a346c0a..665a32b 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -640,11 +640,9 @@
instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
const VkSurfaceFormatKHR kWideColorFormats[] = {
- {VK_FORMAT_R16G16B16A16_SFLOAT,
- VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT},
- {VK_FORMAT_R16G16B16A16_SFLOAT,
- VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT},
- {VK_FORMAT_A2R10G10B10_UNORM_PACK32,
+ {VK_FORMAT_R8G8B8A8_UNORM,
+ VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
+ {VK_FORMAT_R8G8B8A8_SRGB,
VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
};
const uint32_t kNumWideColorFormats =