Fix EVS VTS test cases

- Correctly handle a payload of EvsEventDesc type variables.
- Explicitly duplicate buffers to hold.
- Proeprly handle ultrasonic APIs that are not implemented yet.

Bug: 226628778
Test: atest VtsHalEvsTargetTest on Seahawk
Change-Id: I4c202b171d6cc905732e0687743cb481893a6dd2
diff --git a/automotive/evs/aidl/vts/FrameHandler.cpp b/automotive/evs/aidl/vts/FrameHandler.cpp
index bab832b..e51be67 100644
--- a/automotive/evs/aidl/vts/FrameHandler.cpp
+++ b/automotive/evs/aidl/vts/FrameHandler.cpp
@@ -19,22 +19,73 @@
 #include "FrameHandler.h"
 #include "FormatConvert.h"
 
+#include <aidl/android/hardware/graphics/common/HardwareBuffer.h>
 #include <aidl/android/hardware/graphics/common/HardwareBufferDescription.h>
 #include <aidlcommonsupport/NativeHandle.h>
 #include <android-base/logging.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/GraphicBufferAllocator.h>
 
+namespace {
+
 using ::aidl::android::hardware::automotive::evs::BufferDesc;
 using ::aidl::android::hardware::automotive::evs::CameraDesc;
 using ::aidl::android::hardware::automotive::evs::EvsEventDesc;
 using ::aidl::android::hardware::automotive::evs::EvsEventType;
 using ::aidl::android::hardware::automotive::evs::IEvsCamera;
 using ::aidl::android::hardware::automotive::evs::IEvsDisplay;
+using ::aidl::android::hardware::common::NativeHandle;
+using ::aidl::android::hardware::graphics::common::HardwareBuffer;
 using ::aidl::android::hardware::graphics::common::HardwareBufferDescription;
 using ::ndk::ScopedAStatus;
 using std::chrono_literals::operator""s;
 
+NativeHandle dupNativeHandle(const NativeHandle& handle, bool doDup) {
+    NativeHandle dup;
+
+    dup.fds = std::vector<::ndk::ScopedFileDescriptor>(handle.fds.size());
+    if (!doDup) {
+        for (auto i = 0; i < handle.fds.size(); ++i) {
+            dup.fds.at(i).set(handle.fds[i].get());
+        }
+    } else {
+        for (auto i = 0; i < handle.fds.size(); ++i) {
+            dup.fds[i] = std::move(handle.fds[i].dup());
+        }
+    }
+    dup.ints = handle.ints;
+
+    return std::move(dup);
+}
+
+HardwareBuffer dupHardwareBuffer(const HardwareBuffer& buffer, bool doDup) {
+    HardwareBuffer dup = {
+            .description = buffer.description,
+            .handle = dupNativeHandle(buffer.handle, doDup),
+    };
+
+    return std::move(dup);
+}
+
+BufferDesc dupBufferDesc(const BufferDesc& src, bool doDup) {
+    BufferDesc dup = {
+            .buffer = dupHardwareBuffer(src.buffer, doDup),
+            .pixelSizeBytes = src.pixelSizeBytes,
+            .bufferId = src.bufferId,
+            .deviceId = src.deviceId,
+            .timestamp = src.timestamp,
+            .metadata = src.metadata,
+    };
+
+    return std::move(dup);
+}
+
+bool comparePayload(const EvsEventDesc& l, const EvsEventDesc& r) {
+    return std::equal(l.payload.begin(), l.payload.end(), r.payload.begin());
+}
+
+} // namespace
+
 FrameHandler::FrameHandler(const std::shared_ptr<IEvsCamera>& pCamera, const CameraDesc& cameraInfo,
                            const std::shared_ptr<IEvsDisplay>& pDisplay, BufferControlFlag mode)
     : mCamera(pCamera), mCameraInfo(cameraInfo), mDisplay(pDisplay), mReturnMode(mode) {
@@ -169,15 +220,24 @@
     mFrameSignal.notify_all();
 
     switch (mReturnMode) {
-        case eAutoReturn:
+        case eAutoReturn: {
             // Send the camera buffer back now that the client has seen it
             LOG(DEBUG) << "Calling doneWithFrame";
-            mCamera->doneWithFrame(buffers);
+            if (!mCamera->doneWithFrame(buffers).isOk()) {
+                LOG(WARNING) << "Failed to return buffers";
+            }
             break;
-        case eNoAutoReturn:
+        }
+
+        case eNoAutoReturn: {
             // Hang onto the buffer handles for now -- the client will return it explicitly later
-            // mHeldBuffers.push(buffers);
+            std::vector<BufferDesc> buffersToHold;
+            for (const auto& buffer : buffers) {
+                buffersToHold.push_back(dupBufferDesc(buffer, /* doDup = */ true));
+            }
+            mHeldBuffers.push(std::move(buffersToHold));
             break;
+        }
     }
 
     LOG(DEBUG) << "Frame handling complete";
@@ -188,8 +248,7 @@
     // Local flag we use to keep track of when the stream is stopping
     std::unique_lock<std::mutex> lock(mEventLock);
     mLatestEventDesc.aType = event.aType;
-    mLatestEventDesc.payload[0] = event.payload[0];
-    mLatestEventDesc.payload[1] = event.payload[1];
+    mLatestEventDesc.payload = event.payload;
     if (mLatestEventDesc.aType == EvsEventType::STREAM_STOPPED) {
         // Signal that the last frame has been received and the stream is stopped
         mRunning = false;
@@ -319,13 +378,9 @@
         bool result = mEventSignal.wait_until(
                 lock, now + 5s, [this, aTargetEvent, ignorePayload, &aReceivedEvent, &found]() {
                     found = (mLatestEventDesc.aType == aTargetEvent.aType) &&
-                            (ignorePayload ||
-                             (mLatestEventDesc.payload[0] == aTargetEvent.payload[0] &&
-                              mLatestEventDesc.payload[1] == aTargetEvent.payload[1]));
-
+                            (ignorePayload || comparePayload(mLatestEventDesc, aTargetEvent));
                     aReceivedEvent.aType = mLatestEventDesc.aType;
-                    aReceivedEvent.payload[0] = mLatestEventDesc.payload[0];
-                    aReceivedEvent.payload[1] = mLatestEventDesc.payload[1];
+                    aReceivedEvent.payload = mLatestEventDesc.payload;
                     return found;
                 });
 
diff --git a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
index 7fcac38..a442368 100644
--- a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
+++ b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
@@ -139,7 +139,12 @@
         ASSERT_NE(mEnumerator, nullptr);
 
         // Get the ultrasonics array list
-        ASSERT_TRUE(mEnumerator->getUltrasonicsArrayList(&mUltrasonicsArraysInfo).isOk())
+        auto result = mEnumerator->getUltrasonicsArrayList(&mUltrasonicsArraysInfo);
+        ASSERT_TRUE(result.isOk() ||
+                // TODO(b/149874793): Remove below conditions when
+                // getUltrasonicsArrayList() is implemented.
+                (!result.isOk() && result.getServiceSpecificError() ==
+                        static_cast<int32_t>(EvsResult::NOT_IMPLEMENTED)))
                 << "Failed to get a list of available ultrasonics arrays";
         LOG(INFO) << "We have " << mCameraInfo.size() << " ultrasonics arrays.";
     }
@@ -523,7 +528,7 @@
         // Ask for a very large number of buffers in flight to ensure it errors correctly
         auto badResult = pCam->setMaxFramesInFlight(0xFFFFFFFF);
         EXPECT_TRUE(!badResult.isOk() && badResult.getServiceSpecificError() ==
-                                                 static_cast<int>(EvsResult::BUFFER_NOT_AVAILABLE));
+                                                 static_cast<int>(EvsResult::INVALID_ARG));
 
         // Now ask for exactly two buffers in flight as we'll test behavior in that case
         ASSERT_TRUE(pCam->setMaxFramesInFlight(kBuffersToHold).isOk());
@@ -587,7 +592,7 @@
     std::shared_ptr<IEvsDisplay> pDisplay;
     ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
     EXPECT_NE(pDisplay, nullptr);
-    LOG(INFO) << "Display " << targetDisplayId << " is in use.";
+    LOG(INFO) << "Display " << static_cast<int>(targetDisplayId) << " is in use.";
 
     // Get the display descriptor
     DisplayDesc displayDesc;
@@ -1137,8 +1142,8 @@
 
                 EvsEventDesc aTargetEvent;
                 aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
-                aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
-                aTargetEvent.payload[1] = val0;
+                aTargetEvent.payload.push_back(static_cast<int32_t>(cmd));
+                aTargetEvent.payload.push_back(val0);
                 if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification0)) {
                     LOG(WARNING) << "A timer is expired before a target event is fired.";
                 }
@@ -1152,8 +1157,8 @@
 
                 EvsEventDesc aTargetEvent;
                 aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
-                aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
-                aTargetEvent.payload[1] = val0;
+                aTargetEvent.payload.push_back(static_cast<int32_t>(cmd));
+                aTargetEvent.payload.push_back(val0);
                 if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification1)) {
                     LOG(WARNING) << "A timer is expired before a target event is fired.";
                 }
@@ -1188,11 +1193,13 @@
                       static_cast<EvsEventType>(aNotification0.aType));
             ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
                       static_cast<EvsEventType>(aNotification1.aType));
+            ASSERT_GE(aNotification0.payload.size(), 2);
+            ASSERT_GE(aNotification1.payload.size(), 2);
             ASSERT_EQ(cmd, static_cast<CameraParam>(aNotification0.payload[0]));
             ASSERT_EQ(cmd, static_cast<CameraParam>(aNotification1.payload[0]));
             for (auto&& v : values) {
-                ASSERT_EQ(v, static_cast<int32_t>(aNotification0.payload[1]));
-                ASSERT_EQ(v, static_cast<int32_t>(aNotification1.payload[1]));
+                ASSERT_EQ(v, aNotification0.payload[1]);
+                ASSERT_EQ(v, aNotification1.payload[1]);
             }
 
             // Clients expects to receive a parameter change notification
@@ -1281,8 +1288,8 @@
 
                 EvsEventDesc aTargetEvent;
                 aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
-                aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
-                aTargetEvent.payload[1] = val0;
+                aTargetEvent.payload.push_back(static_cast<int32_t>(cmd));
+                aTargetEvent.payload.push_back(val0);
                 if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification0)) {
                     LOG(WARNING) << "A timer is expired before a target event is fired.";
                 }
@@ -1295,8 +1302,8 @@
 
                 EvsEventDesc aTargetEvent;
                 aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
-                aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
-                aTargetEvent.payload[1] = val0;
+                aTargetEvent.payload.push_back(static_cast<int32_t>(cmd));
+                aTargetEvent.payload.push_back(val0);
                 if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification1)) {
                     LOG(WARNING) << "A timer is expired before a target event is fired.";
                 }
@@ -1336,11 +1343,13 @@
                       static_cast<EvsEventType>(aNotification0.aType));
             ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
                       static_cast<EvsEventType>(aNotification1.aType));
+            ASSERT_GE(aNotification0.payload.size(), 2);
+            ASSERT_GE(aNotification1.payload.size(), 2);
             ASSERT_EQ(cmd, static_cast<CameraParam>(aNotification0.payload[0]));
             ASSERT_EQ(cmd, static_cast<CameraParam>(aNotification1.payload[0]));
             for (auto&& v : values) {
-                ASSERT_EQ(v, static_cast<int32_t>(aNotification0.payload[1]));
-                ASSERT_EQ(v, static_cast<int32_t>(aNotification1.payload[1]));
+                ASSERT_EQ(v, aNotification0.payload[1]);
+                ASSERT_EQ(v, aNotification1.payload[1]);
             }
         }
 
@@ -1461,8 +1470,9 @@
 
                         EvsEventDesc aTargetEvent;
                         aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
-                        aTargetEvent.payload[0] = static_cast<uint32_t>(CameraParam::AUTO_FOCUS);
-                        aTargetEvent.payload[1] = 0;
+                        aTargetEvent.payload.push_back(
+                                static_cast<int32_t>(CameraParam::AUTO_FOCUS));
+                        aTargetEvent.payload.push_back(0);
                         if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) {
                             LOG(WARNING) << "A timer is expired before a target event is fired.";
                         }
@@ -1504,8 +1514,8 @@
 
                     EvsEventDesc aTargetEvent;
                     aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
-                    aTargetEvent.payload[0] = static_cast<uint32_t>(cam1Cmds[0]);
-                    aTargetEvent.payload[1] = val0;
+                    aTargetEvent.payload.push_back(static_cast<int32_t>(cam1Cmds[0]));
+                    aTargetEvent.payload.push_back(val0);
                     if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) {
                         LOG(WARNING) << "A timer is expired before a target event is fired.";
                     }
@@ -1533,9 +1543,10 @@
 
         // Verify a change notification
         ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType), EvsEventType::PARAMETER_CHANGED);
+        ASSERT_GE(aNotification.payload.size(), 2);
         ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]), cam1Cmds[0]);
         for (auto&& v : values) {
-            ASSERT_EQ(v, static_cast<int32_t>(aNotification.payload[1]));
+            ASSERT_EQ(v, aNotification.payload[1]);
         }
 
         listener = std::thread([&frameHandler1, &aNotification, &listening, &eventCond] {
@@ -1582,8 +1593,9 @@
 
                         EvsEventDesc aTargetEvent;
                         aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
-                        aTargetEvent.payload[0] = static_cast<uint32_t>(CameraParam::AUTO_FOCUS);
-                        aTargetEvent.payload[1] = 0;
+                        aTargetEvent.payload.push_back(
+                                static_cast<int32_t>(CameraParam::AUTO_FOCUS));
+                        aTargetEvent.payload.push_back(0);
                         if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) {
                             LOG(WARNING) << "A timer is expired before a target event is fired.";
                         }
@@ -1621,8 +1633,8 @@
 
                     EvsEventDesc aTargetEvent;
                     aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
-                    aTargetEvent.payload[0] = static_cast<uint32_t>(cam0Cmds[0]);
-                    aTargetEvent.payload[1] = val0;
+                    aTargetEvent.payload.push_back(static_cast<int32_t>(cam0Cmds[0]));
+                    aTargetEvent.payload.push_back(val0);
                     if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) {
                         LOG(WARNING) << "A timer is expired before a target event is fired.";
                     }
@@ -1646,9 +1658,10 @@
         }
         // Verify a change notification
         ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType), EvsEventType::PARAMETER_CHANGED);
+        ASSERT_GE(aNotification.payload.size(), 2);
         ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]), cam0Cmds[0]);
         for (auto&& v : values) {
-            ASSERT_EQ(v, static_cast<int32_t>(aNotification.payload[1]));
+            ASSERT_EQ(v, aNotification.payload[1]);
         }
 
         // Turn off the display (yes, before the stream stops -- it should be handled)