aboutsummaryrefslogtreecommitdiffstats
path: root/evs
diff options
context:
space:
mode:
authorChangyeon Jo <changyeon@google.com>2019-11-21 10:16:33 -0800
committerChangyeon Jo <changyeon@google.com>2020-01-04 09:12:37 -0800
commitb927b889e9523495c6532168a4850a8a1ef9d58f (patch)
treec8d51872e9fb5d420a3c3d5ca0b67c048778a334 /evs
parent4ede4d6dfd45b72b7baef2f411d0be4660fbed1c (diff)
downloadplatform_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.bp10
-rw-r--r--evs/manager/1.1/HalCamera.cpp49
-rw-r--r--evs/manager/1.1/HalCamera.h14
-rw-r--r--evs/manager/1.1/VirtualCamera.cpp83
-rw-r--r--evs/manager/1.1/VirtualCamera.h7
-rw-r--r--evs/manager/1.1/sync/unique_fd.cpp96
-rw-r--r--evs/manager/1.1/sync/unique_fd.h72
-rw-r--r--evs/manager/1.1/sync/unique_fence.cpp140
-rw-r--r--evs/manager/1.1/sync/unique_fence.h76
-rw-r--r--evs/manager/1.1/sync/unique_timeline.cpp72
-rw-r--r--evs/manager/1.1/sync/unique_timeline.h94
-rw-r--r--evs/sampleDriver/ConfigManager.cpp8
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);