diff options
| author | Changyeon Jo <changyeon@google.com> | 2019-11-21 10:16:33 -0800 |
|---|---|---|
| committer | Changyeon Jo <changyeon@google.com> | 2020-01-04 09:12:37 -0800 |
| commit | b927b889e9523495c6532168a4850a8a1ef9d58f (patch) | |
| tree | c8d51872e9fb5d420a3c3d5ca0b67c048778a334 /evs | |
| parent | 4ede4d6dfd45b72b7baef2f411d0be4660fbed1c (diff) | |
| download | platform_packages_services_Car-b927b889e9523495c6532168a4850a8a1ef9d58f.tar.gz platform_packages_services_Car-b927b889e9523495c6532168a4850a8a1ef9d58f.tar.bz2 platform_packages_services_Car-b927b889e9523495c6532168a4850a8a1ef9d58f.zip | |
Implement a fence-based frame delivery mechanism
For the clients that implement IEvsCameraStream v1.1 interface, this
change introduces new logic to deliver the imagery data.
While a previous logic keeps forwarding frames until the buffer pool is
running out, VirtualCamera instance requests a new frame and waits on a
fence that HalCamera instance returns. HalCamera signals a fence when
new frame is delivered by EVS HW module and pending VirtualCamera
instances will forward a frame to the clients.
Bug: 142275664
Test: VtsHalEvsV1_1TargetTest
Change-Id: I181c31a56800fcf4de0cf74e530deb7ef8e227d4
Signed-off-by: Changyeon Jo <changyeon@google.com>
Diffstat (limited to 'evs')
| -rw-r--r-- | evs/manager/1.1/Android.bp | 10 | ||||
| -rw-r--r-- | evs/manager/1.1/HalCamera.cpp | 49 | ||||
| -rw-r--r-- | evs/manager/1.1/HalCamera.h | 14 | ||||
| -rw-r--r-- | evs/manager/1.1/VirtualCamera.cpp | 83 | ||||
| -rw-r--r-- | evs/manager/1.1/VirtualCamera.h | 7 | ||||
| -rw-r--r-- | evs/manager/1.1/sync/unique_fd.cpp | 96 | ||||
| -rw-r--r-- | evs/manager/1.1/sync/unique_fd.h | 72 | ||||
| -rw-r--r-- | evs/manager/1.1/sync/unique_fence.cpp | 140 | ||||
| -rw-r--r-- | evs/manager/1.1/sync/unique_fence.h | 76 | ||||
| -rw-r--r-- | evs/manager/1.1/sync/unique_timeline.cpp | 72 | ||||
| -rw-r--r-- | evs/manager/1.1/sync/unique_timeline.h | 94 | ||||
| -rw-r--r-- | evs/sampleDriver/ConfigManager.cpp | 8 |
12 files changed, 680 insertions, 41 deletions
diff --git a/evs/manager/1.1/Android.bp b/evs/manager/1.1/Android.bp index 5bea4bb9f..18b9463f4 100644 --- a/evs/manager/1.1/Android.bp +++ b/evs/manager/1.1/Android.bp @@ -25,6 +25,9 @@ cc_binary { "HalCamera.cpp", "VirtualCamera.cpp", "HalDisplay.cpp", + "sync/unique_fd.cpp", + "sync/unique_fence.cpp", + "sync/unique_timeline.cpp", ], shared_libs: [ @@ -32,6 +35,7 @@ cc_binary { "liblog", "libutils", "libui", + "libsync", "libhidlbase", "libhardware", "android.hardware.automotive.evs@1.0", @@ -47,11 +51,15 @@ cc_binary { cflags: ["-DLOG_TAG=\"EvsManagerV1_1\""] + [ "-DGL_GLEXT_PROTOTYPES", "-DEGL_EGLEXT_PROTOTYPES", - ] + [ + "-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS", "-Wall", "-Werror", "-Wunused", "-Wunreachable-code", + "-Wthread-safety", ], + include_dirs: [ + "system/core/libsync", + ], } diff --git a/evs/manager/1.1/HalCamera.cpp b/evs/manager/1.1/HalCamera.cpp index 25712ba05..5a35edfbc 100644 --- a/evs/manager/1.1/HalCamera.cpp +++ b/evs/manager/1.1/HalCamera.cpp @@ -127,6 +127,23 @@ bool HalCamera::changeFramesInFlight(int delta) { } +UniqueFence HalCamera::requestNewFrame(sp<VirtualCamera> client) { + std::lock_guard<std::mutex> lock(mSessionMutex); + + // If no client has requested new frame, this method marks that there is new + // request and returns new fence. If there is any pending request, then + // this method duplicates exising fence and return simply. + if (mClientsWaitFrame.size() < 1) { + mSessionFence.Reset(); + mTimeline->BumpFenceEventCounter(); + mSessionFence = mTimeline->CreateFence("SessionFence"); + } + + mClientsWaitFrame.emplace_back(client); + return mSessionFence.Dup(); +} + + Return<EvsResult> HalCamera::clientStreamStarting() { Return<EvsResult> result = EvsResult::OK; @@ -151,7 +168,7 @@ void HalCamera::clientStreamEnding() { // If not, then stop the hardware stream if (!stillRunning) { - mStreamState = STOPPED; + mStreamState = STOPPING; mHwCamera->stopVideoStream(); } } @@ -223,15 +240,39 @@ Return<void> HalCamera::deliverFrame(const BufferDesc_1_0& buffer) { Return<void> HalCamera::deliverFrame_1_1(const hardware::hidl_vec<BufferDesc_1_1>& buffer) { ALOGV("Received a frame"); unsigned frameDeliveries = 0; + // Frames are being forwarded to v1.0 clients always but, for v1.1 + // clients, only to them who requested new frame. for (auto&& client : mClients) { sp<VirtualCamera> vCam = client.promote(); - if (vCam != nullptr) { - if (vCam->deliverFrame(buffer[0])) { - ++frameDeliveries; + if (vCam == nullptr || vCam->getVersion() > 0) { + continue; + } + + if (vCam->deliverFrame(buffer[0])) { + ++frameDeliveries; + } + } + + unsigned frameDeliveriesV1 = 0; + { + std::lock_guard<std::mutex> lock(mSessionMutex); + for (auto&& client : mClientsWaitFrame) { + sp<VirtualCamera> vCam = client.promote(); + if (vCam != nullptr) { + if (vCam->deliverFrame(buffer[0])) { + ++frameDeliveriesV1; + } } } + + // Increase a timeline + if (frameDeliveriesV1 > 0) { + mTimeline->BumpTimelineEventCounter(); + mClientsWaitFrame.clear(); + } } + frameDeliveries += frameDeliveriesV1; if (frameDeliveries < 1) { // If none of our clients could accept the frame, then return it // right away. diff --git a/evs/manager/1.1/HalCamera.h b/evs/manager/1.1/HalCamera.h index ab35a1fd2..b34dfc75a 100644 --- a/evs/manager/1.1/HalCamera.h +++ b/evs/manager/1.1/HalCamera.h @@ -25,6 +25,9 @@ #include <thread> #include <list> +#include "sync/unique_fd.h" +#include "sync/unique_fence.h" +#include "sync/unique_timeline.h" using namespace ::android::hardware::automotive::evs::V1_1; using ::android::hardware::Return; @@ -53,7 +56,9 @@ class VirtualCamera; // From VirtualCamera.h // stream from the hardware camera and distribute it to the associated VirtualCamera objects. class HalCamera : public IEvsCameraStream_1_1 { public: - HalCamera(sp<IEvsCamera_1_1> hwCamera) : mHwCamera(hwCamera) {}; + HalCamera(sp<IEvsCamera_1_1> hwCamera) + : mHwCamera(hwCamera), + mTimeline(new UniqueTimeline(0)) {} // Factory methods for client VirtualCameras sp<VirtualCamera> makeVirtualCamera(); @@ -63,6 +68,7 @@ public: sp<IEvsCamera_1_0> getHwCamera() { return mHwCamera; }; unsigned getClientCount() { return mClients.size(); }; bool changeFramesInFlight(int delta); + UniqueFence requestNewFrame(sp<VirtualCamera> virtualCamera); Return<EvsResult> clientStreamStarting(); void clientStreamEnding(); @@ -100,6 +106,12 @@ private: std::vector<FrameRecord> mFrames; wp<VirtualCamera> mMaster = nullptr; std::mutex mMasterLock; + + // synchronization + std::mutex mSessionMutex; + std::list<wp<VirtualCamera>> mClientsWaitFrame GUARDED_BY(mSessionMutex); + std::unique_ptr<UniqueTimeline> mTimeline GUARDED_BY(mSessionMutex); + UniqueFence mSessionFence GUARDED_BY(mSessionMutex); }; } // namespace implementation diff --git a/evs/manager/1.1/VirtualCamera.cpp b/evs/manager/1.1/VirtualCamera.cpp index b6c451392..093ec6e3c 100644 --- a/evs/manager/1.1/VirtualCamera.cpp +++ b/evs/manager/1.1/VirtualCamera.cpp @@ -33,7 +33,8 @@ namespace implementation { VirtualCamera::VirtualCamera(sp<HalCamera> halCamera) : - mHalCamera(halCamera) { + mHalCamera(halCamera), + mStreamState(STOPPED){ } @@ -44,7 +45,7 @@ VirtualCamera::~VirtualCamera() { void VirtualCamera::shutdown() { // In normal operation, the stream should already be stopped by the time we get here - if (mStreamState != STOPPED) { + if (mHalCamera != nullptr && mStreamState != STOPPED) { // Note that if we hit this case, no terminating frame will be sent to the client, // but they're probably already dead anyway. ALOGW("Virtual camera being shutdown while stream is running"); @@ -52,6 +53,11 @@ void VirtualCamera::shutdown() { // Tell the frame delivery pipeline we don't want any more frames mStreamState = STOPPING; + // Join a capture thread + if (mCaptureThread.joinable()) { + mCaptureThread.join(); + } + if (mFramesHeld.size() > 0) { ALOGW("VirtualCamera destructing with frames in flight."); @@ -101,31 +107,22 @@ bool VirtualCamera::deliverFrame(const BufferDesc_1_1& bufDesc) { // Keep a record of this frame so we can clean up if we have to in case of client death mFramesHeld.emplace_back(bufDesc); - // Forward frames if new frames from all physical devices have arrived. - { - // TODO: this is only for a test - for now, forwarding only a single frame. - if (mStream_1_1 != nullptr) { - // Pass this buffer through to our client - hardware::hidl_vec<BufferDesc_1_1> frames; - frames.resize(1); - frames[0] = bufDesc; - mStream_1_1->deliverFrame_1_1(frames); - } else { - // Forward a frame to v1.0 client - BufferDesc_1_0 frame_1_0 = {}; - const AHardwareBuffer_Desc* pDesc = - reinterpret_cast<const AHardwareBuffer_Desc *>(&bufDesc.buffer.description); - frame_1_0.width = pDesc->width; - frame_1_0.height = pDesc->height; - frame_1_0.format = pDesc->format; - frame_1_0.usage = pDesc->usage; - frame_1_0.stride = pDesc->stride; - frame_1_0.memHandle = bufDesc.buffer.nativeHandle; - frame_1_0.pixelSize = bufDesc.pixelSize; - frame_1_0.bufferId = bufDesc.bufferId; - - mStream->deliverFrame(frame_1_0); - } + // v1.0 client uses an old frame-delivery mechanism. + if (mStream_1_1 == nullptr) { + // Forward a frame to v1.0 client + BufferDesc_1_0 frame_1_0 = {}; + const AHardwareBuffer_Desc* pDesc = + reinterpret_cast<const AHardwareBuffer_Desc *>(&bufDesc.buffer.description); + frame_1_0.width = pDesc->width; + frame_1_0.height = pDesc->height; + frame_1_0.format = pDesc->format; + frame_1_0.usage = pDesc->usage; + frame_1_0.stride = pDesc->stride; + frame_1_0.memHandle = bufDesc.buffer.nativeHandle; + frame_1_0.pixelSize = bufDesc.pixelSize; + frame_1_0.bufferId = bufDesc.bufferId; + + mStream->deliverFrame(frame_1_0); } return true; @@ -136,9 +133,9 @@ bool VirtualCamera::deliverFrame(const BufferDesc_1_1& bufDesc) { bool VirtualCamera::notify(const EvsEventDesc& event) { switch(event.aType) { case EvsEventType::STREAM_STOPPED: - // Warn if we got an unexpected stream termination if (mStreamState != STOPPING) { - ALOGW("Stream unexpectedly stopped"); + // Warn if we got an unexpected stream termination + ALOGW("Stream unexpectedly stopped, current status 0x%X", mStreamState); } // Mark the stream as stopped. @@ -235,6 +232,29 @@ Return<EvsResult> VirtualCamera::startVideoStream(const ::android::sp<IEvsCamera return EvsResult::UNDERLYING_SERVICE_ERROR; } + // Start a thread that waits on the fence and forwards collected frames + // to the v1.1 client. + if (mStream_1_1 != nullptr) { + mCaptureThread = std::thread([this]() { + constexpr int kFrameTimeoutMs = 500; + while (mStreamState == RUNNING) { + UniqueFence fence = mHalCamera->requestNewFrame(this); + if (fence.Wait(kFrameTimeoutMs) < 0) { + ALOGE("%p: Camera hangs? %s", this, strerror(errno)); + } else { + // Fetch frames and forward to the client + if (mFramesHeld.size() > 0 && mStream_1_1 != nullptr) { + // Pass this buffer through to our client + hardware::hidl_vec<BufferDesc_1_1> frames; + frames.resize(1); + frames[0] = mFramesHeld.back(); + mStream_1_1->deliverFrame_1_1(frames); + } + } + } + }); + } + // TODO(changyeon): // Detect and exit if we encounter a stalled stream or unresponsive driver? // Consider using a timer and watching for frame arrival? @@ -277,6 +297,11 @@ Return<void> VirtualCamera::stopVideoStream() { // Tell the frame delivery pipeline we don't want any more frames mStreamState = STOPPING; + // Join a thread + if (mCaptureThread.joinable()) { + mCaptureThread.join(); + } + // Deliver an empty frame to close out the frame stream if (mStream_1_1 != nullptr) { // v1.1 client waits for a stream stopped event diff --git a/evs/manager/1.1/VirtualCamera.h b/evs/manager/1.1/VirtualCamera.h index 42cadcb7c..08303c6c0 100644 --- a/evs/manager/1.1/VirtualCamera.h +++ b/evs/manager/1.1/VirtualCamera.h @@ -62,6 +62,7 @@ public: sp<HalCamera> getHalCamera() { return mHalCamera; }; unsigned getAllowedBuffers() { return mFramesAllowed; }; bool isStreaming() { return mStreamState == RUNNING; } + bool getVersion() const { return (int)(mStream_1_1 != nullptr); } // Proxy to receive frames and forward them to the client's stream bool notify(const EvsEventDesc& event); @@ -99,13 +100,15 @@ private: sp<IEvsCameraStream_1_0> mStream; sp<IEvsCameraStream_1_1> mStream_1_1; - std::deque<BufferDesc_1_1> mFramesHeld; unsigned mFramesAllowed = 1; enum { STOPPED, RUNNING, STOPPING, - } mStreamState = STOPPED; + } mStreamState; + + std::deque<BufferDesc_1_1> mFramesHeld; + std::thread mCaptureThread; }; } // namespace implementation diff --git a/evs/manager/1.1/sync/unique_fd.cpp b/evs/manager/1.1/sync/unique_fd.cpp new file mode 100644 index 000000000..49aa87653 --- /dev/null +++ b/evs/manager/1.1/sync/unique_fd.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unique_fd.h" + +#include <errno.h> +#include <string.h> + +#include <cutils/log.h> + +namespace android { +namespace automotive { +namespace evs { +namespace V1_1 { +namespace implementation { + +UniqueFd::UniqueFd() : fd_(-1) {} + +UniqueFd::UniqueFd(int fd) : fd_(fd) { +} + +UniqueFd::~UniqueFd() { + InternalClose(); +} + +UniqueFd::UniqueFd(UniqueFd&& other) : fd_(other.fd_) { + other.fd_ = -1; +} + +UniqueFd& UniqueFd::operator=(UniqueFd&& other) { + InternalClose(); + fd_ = other.fd_; + other.fd_ = -1; + return *this; +} + +void UniqueFd::Reset(int new_fd) { + InternalClose(); + fd_ = new_fd; +} + +UniqueFd UniqueFd::Dup() const { + return (fd_ >= 0) ? UniqueFd(InternalDup()) : UniqueFd(fd_); +} + +UniqueFd::operator bool() const { + return fd_ >= 0; +} + +int UniqueFd::Get() const { + return fd_; +} + +int UniqueFd::GetUnowned() const { + return InternalDup(); +} + +int UniqueFd::Release() { + int ret = fd_; + fd_ = -1; + return ret; +} + +void UniqueFd::InternalClose() { + if (fd_ >= 0) { + int err = close(fd_); + LOG_ALWAYS_FATAL_IF(err < 0, "Error closing UniqueFd -- %s", strerror(errno)); + } + fd_ = -1; +} + +int UniqueFd::InternalDup() const { + int new_fd = fd_ >= 0 ? dup(fd_) : fd_; + LOG_ALWAYS_FATAL_IF(new_fd < 0 && fd_ >= 0, "Error duplicating UniqueFd -- %s", + strerror(errno)); + return new_fd; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace evs +} // namespace automotive +} // namespace android diff --git a/evs/manager/1.1/sync/unique_fd.h b/evs/manager/1.1/sync/unique_fd.h new file mode 100644 index 000000000..204a5fc3c --- /dev/null +++ b/evs/manager/1.1/sync/unique_fd.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace android { +namespace automotive { +namespace evs { +namespace V1_1 { +namespace implementation { + +// This is a simple C++ wrapper around a POSIX file descriptor. It is meant to +// enforce ownership just like unique_ptr<T> +// +// Instances of this type cannot be copied, but they can be moved. +class UniqueFd { +public: + UniqueFd(); + explicit UniqueFd(int fd); + ~UniqueFd(); + UniqueFd(UniqueFd&&); + UniqueFd& operator=(UniqueFd&&); + + // Destroy the current descriptor, and take ownership of a new one. + void Reset(int new_fd = -1); + + // Duplicate the current descriptor. + UniqueFd Dup() const; + + // Returns true if the descriptor is valid. False otherwise. + explicit operator bool() const; + + // Gets the descriptor + int Get() const; + + // Gets a unowned duplicate of the descriptor. The caller is responsible for + // closing it. + int GetUnowned() const; + + // Gets the descriptor and releases ownership. The caller is responsible for + // closing it. + int Release(); + +private: + UniqueFd(const UniqueFd&) = delete; + UniqueFd& operator=(const UniqueFd&) = delete; + + void InternalClose(); + int InternalDup() const; + + int fd_; +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace evs +} // namespace automotive +} // namespace android + diff --git a/evs/manager/1.1/sync/unique_fence.cpp b/evs/manager/1.1/sync/unique_fence.cpp new file mode 100644 index 000000000..467b36817 --- /dev/null +++ b/evs/manager/1.1/sync/unique_fence.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unique_fence.h" + +#include <errno.h> +#include <cinttypes> +#include <cstring> +#include <memory> +#include <string> + +#include <cutils/log.h> +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wzero-length-array" +#endif // __clang__ +#include <sync/sync.h> +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__ +#include <utils/String8.h> + +constexpr int kWarningTimeout = 2000; + +namespace android { +namespace automotive { +namespace evs { +namespace V1_1 { +namespace implementation { + +namespace { + +const char* GetStatusString(int status) { + if (status == 0) { + return "active"; + } else if (status == 1) { + return "signaled"; + } else { + return "error"; + } +} + +} // namespace + +UniqueFence::UniqueFence() {} + +UniqueFence::UniqueFence(int fd) : fd_(fd) {} + +UniqueFence::UniqueFence(UniqueFence&& other) = default; +UniqueFence& UniqueFence::operator=(UniqueFence&& other) = default; + +void UniqueFence::Reset() { + fd_.Reset(); +} + +UniqueFence UniqueFence::Dup() const { + return UniqueFence(fd_.GetUnowned()); +} + +int UniqueFence::Get() const { + return fd_.Get(); +} + +int UniqueFence::GetUnowned() const { + return fd_.GetUnowned(); +} + +UniqueFence::operator bool() const { + return static_cast<bool>(fd_); +} + +void UniqueFence::GetDebugStateDump(String8& result) const { + constexpr int INDENT = 8; + struct sync_file_info* finfo = sync_file_info(fd_.Get()); + if (finfo == nullptr) { + result.append("no debug info available"); + return; + } + result.appendFormat("name: %s status: %d (%s)", finfo->name, finfo->status, + GetStatusString(finfo->status)); + + struct sync_fence_info* pinfo = sync_get_fence_info(finfo); + for (uint32_t i = 0; i < finfo->num_fences; i++) { + result.appendFormat("\n%*spt %u driver: %s obj: %s: status: %d(%s) timestamp: %llu", INDENT, + "", i, pinfo[i].driver_name, pinfo[i].obj_name, pinfo[i].status, + GetStatusString(pinfo[i].status), pinfo[i].timestamp_ns); + } + sync_file_info_free(finfo); +} + +int UniqueFence::Wait(int wait_time_ms) { + if (wait_time_ms == -1) { + int err = sync_wait(fd_.Get(), kWarningTimeout); + if (err >= 0 || errno != ETIME) return err; + + String8 dump; + GetDebugStateDump(dump); + ALOGW("Waited on fence %d for %d ms. [%s]", fd_.Get(), kWarningTimeout, dump.string()); + } + return sync_wait(fd_.Get(), wait_time_ms); +} + +UniqueFence UniqueFence::Merge(const char* name, const UniqueFence& fence1, + const UniqueFence& fence2) { + UniqueFence merged_fence; + if (fence1.fd_ || fence2.fd_) { + if (fence1.fd_ && fence2.fd_) { + merged_fence.fd_.Reset(sync_merge(name, fence1.fd_.Get(), fence2.fd_.Get())); + } else if (fence1.fd_) { + // We merge the fence with itself so that we always generate a fence with + // a new name. + merged_fence.fd_.Reset(sync_merge(name, fence1.fd_.Get(), fence1.fd_.Get())); + } else if (fence2.fd_) { + // We merge the fence with itself so that we always generate a fence with + // a new name. + merged_fence.fd_.Reset(sync_merge(name, fence2.fd_.Get(), fence2.fd_.Get())); + } + ALOGE_IF(!merged_fence.fd_, "merging fences: %s", strerror(errno)); + } + return merged_fence; +} + +} // namespace implementation +} // namespace V1_1 +} // namespace evs +} // namespace automotive +} // namespace android diff --git a/evs/manager/1.1/sync/unique_fence.h b/evs/manager/1.1/sync/unique_fence.h new file mode 100644 index 000000000..7dd9f91b3 --- /dev/null +++ b/evs/manager/1.1/sync/unique_fence.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <utils/String8.h> + +#include "unique_fd.h" + +namespace android { +namespace automotive { +namespace evs { +namespace V1_1 { +namespace implementation { + +// This is a simple C++ wrapper around the sw_sync interface. It is used to +// create and maintain sync fences created from a timeline. +class UniqueFence { +public: + UniqueFence(); + explicit UniqueFence(int fd); + + UniqueFence(UniqueFence&&); + UniqueFence& operator=(UniqueFence&&); + + // Destroy the current fence. + void Reset(); + + // Duplicate the fence. + UniqueFence Dup() const; + + // Gets the descriptor + int Get() const; + + // Gets an unowned duplicate of the fence descriptor. + int GetUnowned() const; + + // Returns true if the fence is set to a valid descriptor. False otherwise. + explicit operator bool() const; + + // Waits on the fence for the indicated amount of time in milliseconds. The + // default value of -1 means to wait forever. + int Wait(int wait_time_ms = -1); + + // Gets a string containing debug information for the fence. + void GetDebugStateDump(String8& result) const; + + // Creates a new fence that signals when both input fences are signaled. Note + // that it is possible to merge multiple fences this way. + static UniqueFence Merge(const char* name, const UniqueFence& fence1, + const UniqueFence& fence2); + +private: + // The fence file descriptor + UniqueFd fd_; +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace evs +} // namespace automotive +} // namespace android + diff --git a/evs/manager/1.1/sync/unique_timeline.cpp b/evs/manager/1.1/sync/unique_timeline.cpp new file mode 100644 index 000000000..c44ca602d --- /dev/null +++ b/evs/manager/1.1/sync/unique_timeline.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "unique_timeline.h" + +#include <errno.h> +#include <string.h> +#include <limits> + +#include <cutils/log.h> +#include <sw_sync.h> + +namespace android { +namespace automotive { +namespace evs { +namespace V1_1 { +namespace implementation { + +UniqueTimeline::UniqueTimeline(unsigned offset) + : fd_(sw_sync_timeline_create()), fence_counter_(offset) { + LOG_ALWAYS_FATAL_IF(!fd_, "Failed to create a timeline."); +} + +UniqueTimeline::~UniqueTimeline() { + // Force any fences waiting on the timeline to be released by incrementing + // by the difference between the two counters. The sw_sync driver has + // changed behavior several times, and no longer releases fences when the + // timeline fd is closed. While at one point adding MAX_UINT worked (by + // adding MAX_INT with two separate calls), even that stopped working. + // (See b/35115489 for background) + BumpTimelineEventCounter(fence_counter_ - timeline_counter_); +} + +bool UniqueTimeline::Supported() { + UniqueFd fd{sw_sync_timeline_create()}; + return !!fd; +} + +UniqueFence UniqueTimeline::CreateFence(const char* name) { + UniqueFence fence(sw_sync_fence_create(fd_.Get(), name, fence_counter_)); + LOG_ALWAYS_FATAL_IF(!fence, "Cannot create fence -- %s", strerror(errno)); + return fence; +} + +void UniqueTimeline::BumpTimelineEventCounter() { + BumpTimelineEventCounter(1); +} + +void UniqueTimeline::BumpTimelineEventCounter(unsigned count) { + timeline_counter_ += count; + int err = sw_sync_timeline_inc(fd_.Get(), count); + LOG_ALWAYS_FATAL_IF(err < 0, "Cannot bump timeline counter -- %s", strerror(errno)); +} + +} // namespace implementation +} // namespace V1_1 +} // namespace evs +} // namespace automotive +} // namespace android diff --git a/evs/manager/1.1/sync/unique_timeline.h b/evs/manager/1.1/sync/unique_timeline.h new file mode 100644 index 000000000..17c27034f --- /dev/null +++ b/evs/manager/1.1/sync/unique_timeline.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "unique_fd.h" +#include "unique_fence.h" + +namespace android { +namespace automotive { +namespace evs { +namespace V1_1 { +namespace implementation { + +// This is a simple C++ wrapper around the sw_sync interface. It is used to +// create sync fences using timeline semantics. +// +// The timeline has two counters, a fence event counter maintained here in this +// class, and the timeline counter hidden in the driver. The one in the driver +// is initialized to zero when creating the timeline, and the one here is +// initialized to one. The counters are meant to be independently incremented. +// +// When the driver counter is incremented, all fences that were created with +// counts after the previous value of the timeline counter, and before (and +// including) the new value are signaled by the driver. +// +// All fences are signaled if the timeline is also destroyed. +// +// The typical uses of these fences is to acquire a fence for some future point +// on the timeline, and incrementing the local fence event counter to +// distinguish between separate events. Then later when the event actually +// occurs you increment the drivers count. +// +// Since the fences are file descriptors, they can be easily sent to another +// process, which can wait for them to signal without needing to define some +// other IPC mechanism to communicate the event. If the fence is sent well in +// advance, there should be minimal latency too. +// +// Instances of this class cannot be copied, but can be moved. +class UniqueTimeline { +public: + // Initializes the timeline, using the given initial_fence_couter value. + explicit UniqueTimeline(unsigned initial_fence_counter); + + ~UniqueTimeline(); + + // Returns true if it is possible to create timelines. + static bool Supported(); + + // Creates a fence fd using the current value of the fence counter. + // A negative value is returned on error. + UniqueFence CreateFence(const char* name); + + // Increments the counter used when creating fences + void BumpFenceEventCounter() { fence_counter_ += 1; } + + // Increments the drivers version of the counter, signaling any fences in the + // range. + void BumpTimelineEventCounter(); + +private: + void BumpTimelineEventCounter(unsigned); + + // The timeline file descriptor. + UniqueFd fd_{-1}; + + // The counter used when creating fences on the timeline. + unsigned fence_counter_{0}; + + // The effective count for the timeline. The kernel driver has the actual + // value, we just track what it should be. If it ever becomes out of sync, + // it could be a problem for releasing fences on destruction. + unsigned timeline_counter_{0}; +}; + +} // namespace implementation +} // namespace V1_1 +} // namespace evs +} // namespace automotive +} // namespace android + diff --git a/evs/sampleDriver/ConfigManager.cpp b/evs/sampleDriver/ConfigManager.cpp index d93c93e60..d419cd9ee 100644 --- a/evs/sampleDriver/ConfigManager.cpp +++ b/evs/sampleDriver/ConfigManager.cpp @@ -267,7 +267,7 @@ ConfigManager::readCameraMetadata(const XMLElement * const aParamElem, ); aCamera->cameraMetadata.insert_or_assign( - tag, make_pair(make_unique<void *>(data), count) + tag, make_pair(data, count) ); ++numEntries; @@ -286,7 +286,7 @@ ConfigManager::readCameraMetadata(const XMLElement * const aParamElem, *data) ) { aCamera->cameraMetadata.insert_or_assign( - tag, make_pair(make_unique<void *>(data), 1) + tag, make_pair((void *)data, 1) ); ++numEntries; @@ -315,7 +315,7 @@ ConfigManager::readCameraMetadata(const XMLElement * const aParamElem, } aCamera->cameraMetadata.insert_or_assign( - tag, make_pair(make_unique<void *>(data), len) + tag, make_pair((void *)data, len) ); ++numEntries; @@ -374,7 +374,7 @@ ConfigManager::constructCameraMetadata(CameraInfo *aCamera, /* try to add new camera metadata entry */ int32_t err = add_camera_metadata_entry(aCamera->characteristics, tag, - entry.first.get(), + entry.first, entry.second); if (err) { ALOGE("Failed to add an entry with a tag 0x%X", tag); |
