Improve test coverage for SurroundViewSession

Bug: 159733690
Bug: 162599435
Test: Run "atest -v -w -c sv_session_tests"; and check the logs for
"sv_session_test"

Change-Id: Ic5c4e7268470c2c769a62d600081a0f19c76e667
Merged-In: Ic5c4e7268470c2c769a62d600081a0f19c76e667
(cherry picked from commit d43fd9b527772edba2627c98e6ec064553bc5189)
diff --git a/surround_view/service-impl/SurroundViewSessionTests.cpp b/surround_view/service-impl/SurroundViewSessionTests.cpp
index b694aaf..2ad6d49 100644
--- a/surround_view/service-impl/SurroundViewSessionTests.cpp
+++ b/surround_view/service-impl/SurroundViewSessionTests.cpp
@@ -28,6 +28,7 @@
 #include <android-base/logging.h>
 
 #include <gtest/gtest.h>
+#include <time.h>
 
 namespace android {
 namespace hardware {
@@ -39,6 +40,7 @@
 
 const char* kSvConfigFilename = "vendor/etc/automotive/sv/sv_sample_config.xml";
 
+// TODO(b/159733690): Verify the callbacks using help/mock methods
 TEST(SurroundViewSessionTests, startAndStopSurroundView2dSession) {
     sp<IEvsEnumerator> fakeEvs = new MockEvsEnumerator();
     IOModule* ioModule = new IOModule(kSvConfigFilename);
@@ -57,6 +59,8 @@
 
     EXPECT_EQ(sv2dSession->startStream(sv2dCallback), SvResult::OK);
 
+    sleep(5);
+
     sv2dSession->stopStream();
 }
 
@@ -86,6 +90,8 @@
 
     EXPECT_EQ(sv3dSession->startStream(sv3dCallback), SvResult::OK);
 
+    sleep(5);
+
     sv3dSession->stopStream();
 }
 
diff --git a/surround_view/service-impl/mock-evs/MockEvsCamera.cpp b/surround_view/service-impl/mock-evs/MockEvsCamera.cpp
index f268e5b..dcd7405 100644
--- a/surround_view/service-impl/mock-evs/MockEvsCamera.cpp
+++ b/surround_view/service-impl/mock-evs/MockEvsCamera.cpp
@@ -16,6 +16,8 @@
 
 #include "MockEvsCamera.h"
 
+#include <stdlib.h>
+
 namespace android {
 namespace hardware {
 namespace automotive {
@@ -23,10 +25,26 @@
 namespace V1_0 {
 namespace implementation {
 
-MockEvsCamera::MockEvsCamera() {
-    mConfigManager =
-            ConfigManager::Create(
-                    "/vendor/etc/automotive/evs/evs_sample_configuration.xml");
+// TODO(b/159733690): the number should come from xml
+const int kFramesCount = 4;
+const int kFrameGenerationDelayMillis = 30;
+const char kConfigFilePath[] =
+        "/vendor/etc/automotive/evs/evs_sample_configuration.xml";
+
+MockEvsCamera::MockEvsCamera(const string& cameraId, const Stream& streamCfg) {
+    mConfigManager = ConfigManager::Create(kConfigFilePath);
+
+    mStreamCfg.height = streamCfg.height;
+    mStreamCfg.width = streamCfg.width;
+
+    mCameraDesc.v1.cameraId = cameraId;
+    unique_ptr<ConfigManager::CameraGroupInfo>& cameraGroupInfo =
+            mConfigManager->getCameraGroupInfo(mCameraDesc.v1.cameraId);
+    if (cameraGroupInfo != nullptr) {
+        mCameraDesc.metadata.setToExternal(
+                (uint8_t*)cameraGroupInfo->characteristics,
+                get_camera_metadata_size(cameraGroupInfo->characteristics));
+    }
 }
 
 Return<void> MockEvsCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) {
@@ -46,8 +64,20 @@
 Return<EvsResult> MockEvsCamera::startVideoStream(
         const ::android::sp<IEvsCameraStream_1_0>& stream) {
     LOG(INFO) << __FUNCTION__;
+    scoped_lock<mutex> lock(mAccessLock);
 
-    (void)stream;
+    mStream = IEvsCameraStream_1_1::castFrom(stream).withDefault(nullptr);
+
+    if (mStreamState != STOPPED) {
+        LOG(ERROR) << "Ignoring startVideoStream call when a stream is "
+                   << "already running.";
+        return EvsResult::STREAM_ALREADY_RUNNING;
+    }
+
+    // Start the frame generation thread
+    mStreamState = RUNNING;
+    mCaptureThread = thread([this]() { generateFrames(); });
+
     return EvsResult::OK;
 }
 
@@ -60,6 +90,22 @@
 
 Return<void> MockEvsCamera::stopVideoStream() {
     LOG(INFO) << __FUNCTION__;
+
+    unique_lock<mutex> lock(mAccessLock);
+    if (mStreamState == RUNNING) {
+        // Tell the GenerateFrames loop we want it to stop
+        mStreamState = STOPPING;
+        // Block outside the mutex until the "stop" flag has been acknowledged
+        // We won't send any more frames, but the client might still get some
+        // already in flight
+        LOG(DEBUG) << __FUNCTION__ << ": Waiting for stream thread to end...";
+        lock.unlock();
+        mCaptureThread.join();
+        lock.lock();
+        mStreamState = STOPPED;
+        mStream = nullptr;
+        LOG(DEBUG) << "Stream marked STOPPED.";
+    }
     return {};
 }
 
@@ -80,9 +126,7 @@
 }
 
 Return<void> MockEvsCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) {
-    // Not implemented.
-
-    (void)_hidl_cb;
+    _hidl_cb(mCameraDesc);
     return {};
 }
 
@@ -195,6 +239,69 @@
     return {};
 }
 
+void MockEvsCamera::initializeFrames(int framesCount) {
+    LOG(INFO) << "StreamCfg width: " << mStreamCfg.width
+              << " height: " << mStreamCfg.height;
+
+    string label = "EmptyBuffer_";
+    mGraphicBuffers.resize(framesCount);
+    mBufferDescs.resize(framesCount);
+    for (int i = 0; i < framesCount; i++) {
+        mGraphicBuffers[i] = new GraphicBuffer(mStreamCfg.width,
+                                               mStreamCfg.height,
+                                               HAL_PIXEL_FORMAT_RGBA_8888,
+                                               1,
+                                               GRALLOC_USAGE_HW_TEXTURE,
+                                               label + (char)(i + 48));
+        mBufferDescs[i].buffer.nativeHandle =
+                mGraphicBuffers[i]->getNativeBuffer()->handle;
+        AHardwareBuffer_Desc* pDesc =
+                reinterpret_cast<AHardwareBuffer_Desc*>(
+                        &mBufferDescs[i].buffer.description);
+        pDesc->width = mStreamCfg.width;
+        pDesc->height = mStreamCfg.height;
+        pDesc->layers = 1;
+        pDesc->usage = GRALLOC_USAGE_HW_TEXTURE;
+        pDesc->stride = mGraphicBuffers[i]->getStride();
+        pDesc->format = HAL_PIXEL_FORMAT_RGBA_8888;
+    }
+}
+
+void MockEvsCamera::generateFrames() {
+    initializeFrames(kFramesCount);
+
+    while (true) {
+        {
+            scoped_lock<mutex> lock(mAccessLock);
+            if (mStreamState != RUNNING) {
+                // Break out of our main thread loop
+                LOG(INFO) << "StreamState does not equal to RUNNING. "
+                          << "Exiting the loop";
+                break;
+            }
+        }
+
+        mStream->deliverFrame_1_1(mBufferDescs);
+        std::this_thread::sleep_for(
+                std::chrono::milliseconds(kFrameGenerationDelayMillis));
+    }
+
+    {
+        scoped_lock<mutex> lock(mAccessLock);
+
+        if (mStream != nullptr) {
+            LOG(DEBUG) << "Notify EvsEventType::STREAM_STOPPED";
+
+            EvsEventDesc evsEventDesc;
+            evsEventDesc.aType = EvsEventType::STREAM_STOPPED;
+            mStream->notify(evsEventDesc);
+        } else {
+            LOG(WARNING) << "EVS stream is not valid any more. "
+                         << "The notify call is ignored.";
+        }
+    }
+}
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace sv
diff --git a/surround_view/service-impl/mock-evs/MockEvsCamera.h b/surround_view/service-impl/mock-evs/MockEvsCamera.h
index d393702..e06a474 100644
--- a/surround_view/service-impl/mock-evs/MockEvsCamera.h
+++ b/surround_view/service-impl/mock-evs/MockEvsCamera.h
@@ -17,13 +17,21 @@
 #pragma once
 
 #include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
 #include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
 #include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
 
 #include <ConfigManager.h>
 
+#include <ui/GraphicBuffer.h>
+
+#include <mutex>
+#include <thread>
+
 using ::android::hardware::automotive::evs::V1_0::EvsResult;
 using ::android::hardware::automotive::evs::V1_1::CameraParam;
+using ::android::hardware::automotive::evs::V1_1::EvsEventDesc;
+using ::android::hardware::automotive::evs::V1_1::EvsEventType;
 
 namespace android {
 namespace hardware {
@@ -38,6 +46,7 @@
 using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
 using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
 using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
+using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream;
 using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
 using IEvsEnumerator_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsEnumerator;
 
@@ -45,7 +54,7 @@
 // implemented.
 class MockEvsCamera : public IEvsCamera_1_1 {
 public:
-    MockEvsCamera();
+    MockEvsCamera(const std::string& cameraId, const Stream& streamCfg);
 
     // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
     Return<void> getCameraInfo(getCameraInfo_cb _hidl_cb) override;
@@ -79,7 +88,30 @@
                                        importExternalBuffers_cb _hidl_cb) override;
 
 private:
+    void initializeFrames(int framesCount);
+    void generateFrames();
+
     std::unique_ptr<ConfigManager> mConfigManager;
+
+    std::mutex mAccessLock;
+
+    enum StreamStateValues {
+        STOPPED,
+        RUNNING,
+        STOPPING,
+        DEAD,
+    };
+    StreamStateValues mStreamState GUARDED_BY(mAccessLock);
+    Stream mStreamCfg;
+
+    std::vector<android::sp<GraphicBuffer>> mGraphicBuffers;
+    std::vector<BufferDesc_1_1> mBufferDescs;
+    CameraDesc_1_1 mCameraDesc;
+
+    std::string mCameraId;
+    std::thread mCaptureThread;  // The thread we'll use to synthesize frames
+
+    android::sp<IEvsCameraStream_1_1> mStream;
 };
 
 }  // namespace implementation
diff --git a/surround_view/service-impl/mock-evs/MockEvsEnumerator.cpp b/surround_view/service-impl/mock-evs/MockEvsEnumerator.cpp
index 946083c..9e3e5e4 100644
--- a/surround_view/service-impl/mock-evs/MockEvsEnumerator.cpp
+++ b/surround_view/service-impl/mock-evs/MockEvsEnumerator.cpp
@@ -109,11 +109,8 @@
 
 Return<sp<IEvsCamera_1_1>> MockEvsEnumerator::openCamera_1_1(
         const hidl_string& cameraId, const Stream& streamCfg) {
-    // Not implemented.
-
-    (void)cameraId;
-    (void)streamCfg;
-    return new MockEvsCamera();
+    LOG(INFO) << __FUNCTION__ << ": " << streamCfg.width << ", " << streamCfg.height;
+    return new MockEvsCamera(cameraId, streamCfg);
 }
 
 Return<void> MockEvsEnumerator::getDisplayIdList(getDisplayIdList_cb _list_cb) {
diff --git a/surround_view/service-impl/mock-evs/MockSurroundViewCallback.cpp b/surround_view/service-impl/mock-evs/MockSurroundViewCallback.cpp
index d059f72..03f9594 100644
--- a/surround_view/service-impl/mock-evs/MockSurroundViewCallback.cpp
+++ b/surround_view/service-impl/mock-evs/MockSurroundViewCallback.cpp
@@ -18,9 +18,13 @@
 
 #include <android-base/logging.h>
 
+#include <thread>
+
 using ::android::sp;
 using ::android::hardware::Return;
 
+using ::std::thread;
+
 namespace android {
 namespace hardware {
 namespace automotive {
@@ -29,9 +33,8 @@
 namespace implementation {
 
 MockSurroundViewCallback::MockSurroundViewCallback(
-        sp<ISurroundViewSession> pSession) {
-    (void)pSession;
-}
+        sp<ISurroundViewSession> pSession) :
+        mSession(pSession) {}
 
 Return<void> MockSurroundViewCallback::notify(SvEvent svEvent) {
     LOG(INFO) << __FUNCTION__ << "SvEvent received: " << (int)svEvent;
@@ -42,6 +45,13 @@
         const SvFramesDesc& svFramesDesc) {
     LOG(INFO) << __FUNCTION__ << svFramesDesc.svBuffers.size()
               << " frames are received";
+
+    // Create a separate thread to return the frames to the session. This
+    // simulates the behavior of oneway HIDL method call.
+    thread mockHidlThread([this, &svFramesDesc]() {
+        mSession->doneWithFrames(svFramesDesc);
+    });
+    mockHidlThread.detach();
     return {};
 }
 
diff --git a/surround_view/service-impl/mock-evs/MockSurroundViewCallback.h b/surround_view/service-impl/mock-evs/MockSurroundViewCallback.h
index 7239bf6..eeabc98 100644
--- a/surround_view/service-impl/mock-evs/MockSurroundViewCallback.h
+++ b/surround_view/service-impl/mock-evs/MockSurroundViewCallback.h
@@ -35,6 +35,9 @@
     // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewStream.
     android::hardware::Return<void> notify(SvEvent svEvent) override;
     android::hardware::Return<void> receiveFrames(const SvFramesDesc& svFramesDesc) override;
+
+private:
+    android::sp<ISurroundViewSession> mSession;
 };
 
 }  // namespace implementation