diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2017-09-21 21:52:54 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2017-09-21 21:52:54 +0000 |
commit | 9c01bca1e81a75a6738e7917974cdafe1862cb5e (patch) | |
tree | d6fd810e0c564efccb114f1d574f792524bb2d15 | |
parent | 237fc04e3221b9e5f479406c48041f6e2d02cfa2 (diff) | |
parent | 5d0c9188a7cc5b49df32e025ab9a4455f3bc0324 (diff) | |
download | native-9c01bca1e81a75a6738e7917974cdafe1862cb5e.tar.gz |
release-request-a84b3435-75fa-41e8-bd3c-ca0f4cbd5cc5-for-git_oc-m2-release-4352002 snap-temp-L88700000105039240
Change-Id: I7b9499f10f42b6f860c54192535f3619a4618d1d
26 files changed, 785 insertions, 403 deletions
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp index 3c4a933ad6..f29da17457 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -1796,8 +1796,14 @@ bool reconcile_secondary_dex_file(const std::string& dex_path, } 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 d277bd3ad8..dd32ac6425 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -801,7 +801,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) { CHECK(storage_flag == FLAG_STORAGE_CE || storage_flag == FLAG_STORAGE_DE); // Empty paths are not allowed. @@ -815,15 +815,18 @@ bool validate_secondary_dex_path(const std::string& pkgname, const std::string& // 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 (strncmp(dex_path.c_str(), app_private_dir.c_str(), app_private_dir.size()) != 0) { - return false; + 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 we got here we have a valid path. diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h index da3a2933ec..e938042a3b 100644 --- a/cmds/installd/utils.h +++ b/cmds/installd/utils.h @@ -125,7 +125,7 @@ std::string read_path_inode(const std::string& parent, const char* name, const c 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/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl index 6b7254cbb3..3264666a21 100644 --- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl +++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl @@ -38,4 +38,20 @@ interface IPackageManagerNative { * 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 8c6ef691a2..e1b9a8a6f1 100644 --- a/libs/hwc2on1adapter/HWC2On1Adapter.cpp +++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp @@ -2005,10 +2005,21 @@ Error HWC2On1Adapter::Layer::setTransform(Transform transform) { 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/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h index 3e93788521..0699fefd38 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 @@ -66,6 +66,11 @@ class BufferHubQueue : public pdx::Client { 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]; } @@ -218,7 +223,7 @@ class BufferHubQueue : public pdx::Client { // 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}; diff --git a/libs/vr/libdvr/dvr_buffer.cpp b/libs/vr/libdvr/dvr_buffer.cpp index 4d9b215361..1a9923444e 100644 --- a/libs/vr/libdvr/dvr_buffer.cpp +++ b/libs/vr/libdvr/dvr_buffer.cpp @@ -44,7 +44,13 @@ void dvrWriteBufferCreateEmpty(DvrWriteBuffer** write_buffer) { } 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 @@ void dvrReadBufferCreateEmpty(DvrReadBuffer** read_buffer) { *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 4adb5d2da1..035252d0b9 100644 --- a/libs/vr/libdvr/dvr_buffer_queue.cpp +++ b/libs/vr/libdvr/dvr_buffer_queue.cpp @@ -63,7 +63,7 @@ int DvrWriteBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) { } int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer, - int* out_fence_fd) { + int* out_fence_fd, size_t* out_slot) { size_t slot; pdx::LocalHandle fence; std::shared_ptr<BufferProducer> buffer_producer; @@ -141,6 +141,86 @@ int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer, write_buffer->write_buffer = std::move(buffer_producer); *out_fence_fd = fence.Release(); + if (out_slot) { + // TODO(b/65469368): Remove this null check once dvrWriteBufferQueueDequeue + // is deprecated. + *out_slot = slot; + } + return 0; +} + +int DvrWriteBufferQueue::GainBuffer(int timeout, + DvrWriteBuffer** out_write_buffer, + DvrNativeBufferMetadata* out_meta, + int* out_fence_fd) { + DvrWriteBuffer write_buffer; + int fence_fd; + size_t slot; + const int ret = Dequeue(timeout, &write_buffer, &fence_fd, &slot); + if (ret < 0) { + ALOGE_IF( + ret != -ETIMEDOUT, + "DvrWriteBufferQueue::GainBuffer: Failed to dequeue buffer, ret=%d", + ret); + return ret; + } + + 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(write_buffer.write_buffer); + + *out_write_buffer = write_buffers_[slot].release(); + *out_fence_fd = fence_fd; + + 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 released does not " + "belong to this buffer queue."); + return -EINVAL; + } + + pdx::LocalHandle fence(ready_fence_fd); + // TODO(b/65455724): All BufferHub operations should be async. + const int ret = write_buffer->write_buffer->Post(fence, meta, sizeof(*meta)); + 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; } @@ -236,7 +316,29 @@ int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout, if (!write_queue || !write_buffer || !out_fence_fd) return -EINVAL; - return write_queue->Dequeue(timeout, write_buffer, out_fence_fd); + // TODO(b/65469368): Deprecate this API once new GainBuffer API is in use. + return write_queue->Dequeue(timeout, write_buffer, out_fence_fd, nullptr); +} + +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, @@ -268,8 +370,8 @@ int DvrReadBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) { } int DvrReadBufferQueue::Dequeue(int timeout, DvrReadBuffer* read_buffer, - int* out_fence_fd, void* out_meta, - size_t meta_size_bytes) { + int* out_fence_fd, size_t* out_slot, + void* out_meta, size_t meta_size_bytes) { if (meta_size_bytes != consumer_queue_->metadata_size()) { ALOGE( "DvrReadBufferQueue::Dequeue: Invalid metadata size, expected (%zu), " @@ -291,6 +393,95 @@ int DvrReadBufferQueue::Dequeue(int timeout, DvrReadBuffer* read_buffer, read_buffer->read_buffer = buffer_status.take(); *out_fence_fd = acquire_fence.Release(); + + if (out_slot) { + // TODO(b/65469368): Remove this null check once dvrReadBufferQueueDequeue + // is deprecated. + *out_slot = slot; + } + return 0; +} + +int DvrReadBufferQueue::AcquireBuffer(int timeout, + DvrReadBuffer** out_read_buffer, + DvrNativeBufferMetadata* out_meta, + int* out_fence_fd) { + DvrReadBuffer read_buffer; + int fence_fd; + size_t slot; + const int ret = Dequeue(timeout, &read_buffer, &fence_fd, &slot, out_meta, + sizeof(*out_meta)); + if (ret < 0) { + ALOGE_IF( + ret != -ETIMEDOUT, + "DvrReadBufferQueue::AcquireBuffer: Failed to dequeue buffer, error=%d", + ret); + return ret; + } + + 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(read_buffer.read_buffer); + + *out_read_buffer = read_buffers_[slot].release(); + *out_fence_fd = fence_fd; + + 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."); + return -EINVAL; + } + + pdx::LocalHandle fence(release_fence_fd); + int ret = 0; + if (fence) { + ret = read_buffer->read_buffer->Release(fence); + } else { + // TODO(b/65458354): Send metadata back to producer once shared memory based + // metadata is implemented. + // TODO(b/65455724): All BufferHub operations should be async. + ret = read_buffer->read_buffer->ReleaseAsync(); + } + 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 +502,11 @@ void DvrReadBufferQueue::SetBufferRemovedCallback( } 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); }); } } @@ -366,8 +559,30 @@ int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout, if (meta_size_bytes != 0 && !out_meta) return -EINVAL; - return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta, - meta_size_bytes); + // TODO(b/65469368): Deprecate this API once new AcquireBuffer API is in use. + return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, nullptr, + out_meta, 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( diff --git a/libs/vr/libdvr/dvr_buffer_queue_internal.h b/libs/vr/libdvr/dvr_buffer_queue_internal.h index 795d6cdc25..f9c0bfd7c7 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 @@ typedef void (*DvrReadBufferQueueBufferRemovedCallback)(DvrReadBuffer* buffer, void* context); struct DvrWriteBufferQueue { + using BufferHubQueue = android::dvr::BufferHubQueue; using ProducerQueue = android::dvr::ProducerQueue; // Create a concrete object for DvrWriteBufferQueue. @@ -37,19 +42,28 @@ struct DvrWriteBufferQueue { int GetNativeWindow(ANativeWindow** out_window); int CreateReadQueue(DvrReadBufferQueue** out_read_queue); - int Dequeue(int timeout, DvrWriteBuffer* write_buffer, int* out_fence_fd); + int Dequeue(int timeout, DvrWriteBuffer* write_buffer, int* out_fence_fd, + size_t* out_slot); + 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_; 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 @@ struct DvrReadBufferQueue { 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); + size_t* out_slot, void* out_meta, size_t meta_size_bytes); + 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 @@ struct DvrReadBufferQueue { 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 28b6c28e9f..de8bb96aec 100644 --- a/libs/vr/libdvr/dvr_internal.h +++ b/libs/vr/libdvr/dvr_internal.h @@ -34,10 +34,20 @@ DvrWriteBuffer* CreateDvrWriteBufferFromBufferProducer( 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/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h index 6daf157f36..8f45ce7e40 100644 --- a/libs/vr/libdvr/include/dvr/dvr_api.h +++ b/libs/vr/libdvr/include/dvr/dvr_api.h @@ -34,6 +34,7 @@ typedef struct AHardwareBuffer AHardwareBuffer; typedef struct DvrReadBufferQueue DvrReadBufferQueue; typedef struct DvrWriteBufferQueue DvrWriteBufferQueue; +typedef struct DvrNativeBufferMetadata DvrNativeBufferMetadata; typedef struct DvrSurface DvrSurface; typedef uint64_t DvrSurfaceAttributeType; @@ -180,6 +181,13 @@ typedef int (*DvrWriteBufferQueueDequeuePtr)(DvrWriteBufferQueue* write_queue, 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 +202,13 @@ typedef int (*DvrReadBufferQueueDequeuePtr)(DvrReadBufferQueue* read_queue, 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, diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h index 9036773464..cce8c7ee40 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 @@ DVR_V1_API_ENTRY(WriteBufferQueueCreate); // 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 8b9e0482d9..bf695c7dbc 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 dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue, 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 dvrReadBufferQueueGetEventFd(DvrReadBufferQueue* read_queue); 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/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp index ab2ee75a3e..a9302a7561 100644 --- a/libs/vr/libdvr/tests/Android.bp +++ b/libs/vr/libdvr/tests/Android.bp @@ -47,6 +47,7 @@ cc_test { 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 0b30c3869a..f1c5e48916 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 uint32_t kBufferFormat = AHARDWAREBUFFER_FORMAT_BLOB; 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 @@ class DvrBufferQueueTest : public ::testing::Test { 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 @@ TEST_F(DvrBufferQueueTest, TestWrite_QueueGetCapacity) { 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 @@ TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromWriteQueue) { 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 @@ TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromReadQueue) { 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); - - DvrReadBuffer* read_buffer = nullptr; - DvrWriteBuffer* write_buffer = nullptr; - - 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)); + kQueueCapacity, sizeof(DvrNativeBufferMetadata), &write_queue_); + ASSERT_EQ(ret, 0); - DvrReadBufferQueue* read_queue = nullptr; - - ASSERT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue)); + DvrWriteBuffer* wb = nullptr; + EXPECT_FALSE(dvrWriteBufferIsValid(wb)); - const int kTimeoutMs = 0; + DvrNativeBufferMetadata meta = {0}; 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 = {0}; + DvrNativeBufferMetadata meta2 = {0}; 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=*/0, &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 @@ TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) { 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 @@ TEST_F(DvrBufferQueueTest, TestGetANativeWindow) { // 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 = {0}; DvrReadBufferQueue* read_queue = nullptr; DvrWriteBuffer* wb1 = nullptr; DvrWriteBuffer* wb2 = nullptr; @@ -300,13 +263,6 @@ TEST_F(DvrBufferQueueTest, TestResizeBuffer) { 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 @@ TEST_F(DvrBufferQueueTest, TestResizeBuffer) { 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 @@ TEST_F(DvrBufferQueueTest, TestResizeBuffer) { 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 @@ TEST_F(DvrBufferQueueTest, TestResizeBuffer) { 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 @@ TEST_F(DvrBufferQueueTest, TestResizeBuffer) { 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 @@ TEST_F(DvrBufferQueueTest, TestReadQueueEventFd) { // 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 @@ TEST_F(DvrBufferQueueTest, TestStableBufferIdAndHardwareBuffer) { 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=*/0, + &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 @@ TEST_F(DvrBufferQueueTest, TestStableBufferIdAndHardwareBuffer) { 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=*/0, + &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 @@ TEST_F(DvrBufferQueueTest, TestStableBufferIdAndHardwareBuffer) { 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 @@ TEST_F(DvrBufferQueueTest, TestStableBufferIdAndHardwareBuffer) { 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_uds/client_channel.cpp b/libs/vr/libpdx_uds/client_channel.cpp index 9d9161784a..3f785fa62e 100644 --- a/libs/vr/libpdx_uds/client_channel.cpp +++ b/libs/vr/libpdx_uds/client_channel.cpp @@ -90,10 +90,12 @@ Status<void> SendRequest(const BorrowedHandle& socket_fd, 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/ipc_helper.cpp b/libs/vr/libpdx_uds/ipc_helper.cpp index d75ce86e4b..f85b3bb666 100644 --- a/libs/vr/libpdx_uds/ipc_helper.cpp +++ b/libs/vr/libpdx_uds/ipc_helper.cpp @@ -20,6 +20,9 @@ namespace uds { 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) { } 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 @@ Status<void> ReceivePayload::Receive(const BorrowedHandle& socket_fd, 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 @@ Status<void> ReceivePayload::Receive(const BorrowedHandle& socket_fd, 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 @@ Status<void> ReceivePayload::Receive(const BorrowedHandle& socket_fd, 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/ipc_helper.h b/libs/vr/libpdx_uds/private/uds/ipc_helper.h index bde16d3d31..664a0d1a1b 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 @@ class SendPayload : public MessageWriter, public OutputResourceMapper { 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; @@ -156,18 +157,22 @@ class ResponseHeader { }; 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/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp index 40396b90c5..ef8cca38dd 100644 --- a/libs/vr/libvrflinger/display_manager_service.cpp +++ b/libs/vr/libvrflinger/display_manager_service.cpp @@ -65,6 +65,7 @@ void DisplayManagerService::OnChannelClose( } 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 10abc5efa3..ac68a5e3a4 100644 --- a/libs/vr/libvrflinger/display_service.cpp +++ b/libs/vr/libvrflinger/display_service.cpp @@ -124,6 +124,8 @@ void DisplayService::OnChannelClose(pdx::Message& message, // 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>( diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp index c19fb249dd..de6477b1ef 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 @@ namespace { 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,6 +86,29 @@ bool SetThreadPolicy(const std::string& scheduler_class, return true; } +// 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()); + } + + ~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() @@ -101,6 +127,8 @@ bool HardwareComposer::Initialize( return false; } + is_standalone_device_ = property_get_bool(kDvrStandaloneProperty, false); + request_display_callback_ = request_display_callback; HWC::Error error = HWC::Error::None; @@ -198,10 +226,17 @@ void HardwareComposer::UpdatePostThreadState(PostThreadStateType state, } void HardwareComposer::OnPostThreadResumed() { - composer_.reset(new Hwc2::Composer(false)); - composer_callback_ = new ComposerCallback; - composer_->registerCallback(composer_callback_); - Layer::SetComposer(composer_.get()); + // 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); @@ -224,9 +259,13 @@ void HardwareComposer::OnPostThreadPaused() { EnableVsync(false); } - composer_callback_ = nullptr; - composer_.reset(nullptr); - Layer::SetComposer(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"); @@ -256,6 +295,12 @@ HWC::Error HardwareComposer::EnableVsync(bool enabled) { : 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 = composer_->presentDisplay(display, &present_fence); @@ -393,14 +438,12 @@ void HardwareComposer::PostLayers() { 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()); @@ -459,7 +502,7 @@ void HardwareComposer::SetDisplaySurfaces( 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. @@ -569,60 +612,28 @@ int HardwareComposer::PostThreadPollInterruptible( } } -// 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(composer_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 = composer_callback_->GetVsyncTime(); - return 0; } + return {predicted_vsync_time}; } int HardwareComposer::SleepUntil(int64_t wakeup_timestamp) { @@ -640,8 +651,8 @@ int HardwareComposer::SleepUntil(int64_t wakeup_timestamp) { 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() { @@ -664,15 +675,6 @@ void HardwareComposer::PostThread() { 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( @@ -737,26 +739,41 @@ void HardwareComposer::PostThread() { 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(); @@ -806,6 +823,38 @@ void HardwareComposer::PostThread() { } } + { + 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(); } } @@ -893,17 +942,28 @@ void HardwareComposer::SetBacklightBrightness(int brightness) { } } -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(); } @@ -912,31 +972,83 @@ Return<void> HardwareComposer::ComposerCallback::onRefresh( 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); + } -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; + return {timestamp}; } Hwc2::Composer* Layer::composer_{nullptr}; diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h index 550e6877f5..8131e50989 100644 --- a/libs/vr/libvrflinger/hardware_composer.h +++ b/libs/vr/libvrflinger/hardware_composer.h @@ -142,9 +142,7 @@ class Layer { bool operator<(const Layer& other) const { return GetSurfaceId() < other.GetSurfaceId(); } - bool operator<(int surface_id) const { - return GetSurfaceId() < surface_id; - } + bool operator<(int surface_id) const { return GetSurfaceId() < surface_id; } // Sets the composer instance used by all Layer instances. static void SetComposer(Hwc2::Composer* composer) { composer_ = composer; } @@ -336,22 +334,27 @@ class HardwareComposer { 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); @@ -391,11 +394,10 @@ class HardwareComposer { // 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(); @@ -413,6 +415,7 @@ class HardwareComposer { void UpdateConfigBuffer(); bool initialized_; + bool is_standalone_device_; std::unique_ptr<Hwc2::Composer> composer_; sp<ComposerCallback> composer_callback_; @@ -455,15 +458,15 @@ class HardwareComposer { // 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 fcf94f0865..85dc586eae 100644 --- a/libs/vr/libvrflinger/vr_flinger.cpp +++ b/libs/vr/libvrflinger/vr_flinger.cpp @@ -64,9 +64,6 @@ bool VrFlinger::Init(Hwc2::Composer* hidl, 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 @@ bool VrFlinger::Init(Hwc2::Composer* hidl, 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 3098b43318..fdeb899f66 100644 --- a/libs/vr/libvrflinger/vsync_service.cpp +++ b/libs/vr/libvrflinger/vsync_service.cpp @@ -110,6 +110,7 @@ void VSyncService::UpdateClients() { } pdx::Status<void> VSyncService::HandleMessage(pdx::Message& message) { + ATRACE_NAME("VSyncService::HandleMessage"); switch (message.GetOp()) { case VSyncProtocol::Wait::Opcode: AddWaiter(message); diff --git a/services/inputflinger/InputWindow.cpp b/services/inputflinger/InputWindow.cpp index b54752b08b..3ae7972779 100644 --- a/services/inputflinger/InputWindow.cpp +++ b/services/inputflinger/InputWindow.cpp @@ -49,7 +49,8 @@ bool InputWindowInfo::isTrustedOverlay() const { || 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 610290b2e2..9eb27983cd 100644 --- a/services/inputflinger/InputWindow.h +++ b/services/inputflinger/InputWindow.h @@ -101,6 +101,7 @@ struct InputWindowInfo { 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, |