[SV HIDL] Default implementation for Surround View

Bug: 148618804

Test: atest -c VtsHalSurroundViewV1_0TargetTest (tested together with Change-id I1c6bfa77adb699ab80337497aac4582861315bcd)

Change-Id: Ibc9e32d9cc6c93ca71f34bc54e3bdecdf2c4dba2
diff --git a/automotive/sv/1.0/default/Android.bp b/automotive/sv/1.0/default/Android.bp
new file mode 100644
index 0000000..8417949
--- /dev/null
+++ b/automotive/sv/1.0/default/Android.bp
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2020 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.
+//
+
+cc_binary {
+    name: "android.hardware.automotive.sv@1.0-service",
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "service.cpp",
+        "SurroundViewService.cpp",
+        "SurroundView2dSession.cpp",
+        "SurroundView3dSession.cpp",
+    ],
+    init_rc: ["android.hardware.automotive.sv@1.0-service.rc"],
+    vintf_fragments: ["android.hardware.automotive.sv@1.0-service.xml"],
+    shared_libs: [
+        "android.hardware.automotive.sv@1.0",
+        "android.hidl.memory@1.0",
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libui",
+        "libutils",
+        "libhidlmemory",
+    ],
+
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
diff --git a/automotive/sv/1.0/default/SurroundView2dSession.cpp b/automotive/sv/1.0/default/SurroundView2dSession.cpp
new file mode 100644
index 0000000..4f97598
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView2dSession.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2020 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 "SurroundView2dSession.h"
+
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+SurroundView2dSession::SurroundView2dSession() :
+    mStreamState(STOPPED) {
+    mEvsCameraIds = {"0" , "1", "2", "3"};
+
+    mConfig.width = 640;
+    mConfig.blending = SvQuality::HIGH;
+
+    framesRecord.frames.svBuffers.resize(1);
+    framesRecord.frames.svBuffers[0].viewId = 0;
+    framesRecord.frames.svBuffers[0].hardwareBuffer.nativeHandle =
+        new native_handle_t();
+    framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] =
+        mConfig.width;
+    framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] =
+        mConfig.width * 3 / 4;
+}
+
+// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession
+Return<SvResult> SurroundView2dSession::startStream(
+    const sp<ISurroundViewStream>& stream) {
+    ALOGD("SurroundView2dSession::startStream");
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    if (mStreamState != STOPPED) {
+        ALOGE("ignoring startVideoStream call"
+              "when a stream is already running.");
+        return SvResult::INTERNAL_ERROR;
+    }
+
+    mStream = stream;
+
+    ALOGD("Notify SvEvent::STREAM_STARTED");
+    mStream->notify(SvEvent::STREAM_STARTED);
+
+    // Start the frame generation thread
+    mStreamState = RUNNING;
+    mCaptureThread = std::thread([this](){ generateFrames(); });
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView2dSession::stopStream() {
+    ALOGD("SurroundView2dSession::stopStream");
+    std::unique_lock <std::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
+        ALOGD("Waiting for stream thread to end...");
+        lock.unlock();
+        mCaptureThread.join();
+        lock.lock();
+
+        mStreamState = STOPPED;
+        mStream = nullptr;
+        ALOGD("Stream marked STOPPED.");
+    }
+
+    return android::hardware::Void();
+}
+
+Return<void> SurroundView2dSession::doneWithFrames(
+    const SvFramesDesc& svFramesDesc){
+    ALOGD("SurroundView2dSession::doneWithFrames");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    framesRecord.inUse = false;
+
+    (void)svFramesDesc;
+    return android::hardware::Void();
+}
+
+// Methods from ISurroundView2dSession follow.
+Return<void> SurroundView2dSession::get2dMappingInfo(
+    get2dMappingInfo_cb _hidl_cb) {
+    ALOGD("SurroundView2dSession::get2dMappingInfo");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    Sv2dMappingInfo info;
+    info.width = 8; // keeps ratio to 4:3
+    info.height = 6;
+    info.center.isValid = true;
+    info.center.x = 0;
+    info.center.y = 0;
+    _hidl_cb(info);
+    return android::hardware::Void();
+}
+
+Return<SvResult> SurroundView2dSession::set2dConfig(
+    const Sv2dConfig& sv2dConfig) {
+    ALOGD("SurroundView2dSession::setConfig");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    mConfig.width = sv2dConfig.width;
+    mConfig.blending = sv2dConfig.blending;
+    ALOGD("Notify SvEvent::CONFIG_UPDATED");
+    mStream->notify(SvEvent::CONFIG_UPDATED);
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView2dSession::get2dConfig(get2dConfig_cb _hidl_cb) {
+    ALOGD("SurroundView2dSession::getConfig");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    _hidl_cb(mConfig);
+    return android::hardware::Void();
+}
+
+Return<void> SurroundView2dSession::projectCameraPoints(
+        const hidl_vec<Point2dInt>& points2dCamera,
+        const hidl_string& cameraId,
+        projectCameraPoints_cb _hidl_cb) {
+    ALOGD("SurroundView2dSession::projectCameraPoints");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    bool cameraIdFound = false;
+    for (auto evsCameraId : mEvsCameraIds) {
+      if (cameraId == evsCameraId) {
+          cameraIdFound = true;
+          ALOGI("Camera id found.");
+          break;
+      }
+    }
+
+    if (!cameraIdFound) {
+        ALOGE("Camera id not found.");
+        _hidl_cb(hidl_vec<Point2dFloat>());
+        return android::hardware::Void();
+    }
+
+    hidl_vec<Point2dFloat> outPoints;
+    outPoints.resize(points2dCamera.size());
+
+    int width = mConfig.width;
+    int height = mConfig.width * 3 / 4;
+    for (int i=0; i<points2dCamera.size(); i++) {
+        // Assuming all the points in the image frame can be projected into 2d
+        // Surround View space. Otherwise cannot.
+        if (points2dCamera[i].x < 0 || points2dCamera[i].y > width-1 ||
+            points2dCamera[i].x < 0 || points2dCamera[i].y > height-1) {
+            ALOGW("SurroundView2dSession::projectCameraPoints "
+                  "gets invalid 2d camera points. Ignored");
+            outPoints[i].isValid = false;
+            outPoints[i].x = 10000;
+            outPoints[i].y = 10000;
+        } else {
+            outPoints[i].isValid = true;
+            outPoints[i].x = 0;
+            outPoints[i].y = 0;
+        }
+    }
+
+    _hidl_cb(outPoints);
+    return android::hardware::Void();
+}
+
+void SurroundView2dSession::generateFrames() {
+    ALOGD("SurroundView2dSession::generateFrames");
+
+    int sequenceId = 0;
+
+    while(true) {
+        {
+            std::lock_guard<std::mutex> lock(mAccessLock);
+
+            if (mStreamState != RUNNING) {
+                // Break out of our main thread loop
+                break;
+            }
+
+            framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] =
+                mConfig.width;
+            framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] =
+                mConfig.width * 3 / 4;
+        }
+
+        usleep(100 * 1000);
+
+        framesRecord.frames.timestampNs = elapsedRealtimeNano();
+        framesRecord.frames.sequenceId = sequenceId++;
+
+        {
+            std::lock_guard<std::mutex> lock(mAccessLock);
+
+            if (framesRecord.inUse) {
+                ALOGD("Notify SvEvent::FRAME_DROPPED");
+                mStream->notify(SvEvent::FRAME_DROPPED);
+            } else {
+                framesRecord.inUse = true;
+                mStream->receiveFrames(framesRecord.frames);
+            }
+        }
+    }
+
+    // If we've been asked to stop, send an event to signal the actual
+    // end of stream
+    ALOGD("Notify SvEvent::STREAM_STOPPED");
+    mStream->notify(SvEvent::STREAM_STOPPED);
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundView2dSession.h b/automotive/sv/1.0/default/SurroundView2dSession.h
new file mode 100644
index 0000000..ee751e7
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView2dSession.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2020 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 <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <thread>
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+using ::std::mutex;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class SurroundView2dSession : public ISurroundView2dSession {
+public:
+    SurroundView2dSession();
+
+    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+    Return<SvResult> startStream(
+        const sp<ISurroundViewStream>& stream) override;
+    Return<void> stopStream() override;
+    Return<void> doneWithFrames(const SvFramesDesc& svFramesDesc) override;
+
+    // Methods from ISurroundView2dSession follow.
+    Return<void> get2dMappingInfo(get2dMappingInfo_cb _hidl_cb) override;
+    Return<SvResult> set2dConfig(const Sv2dConfig& sv2dConfig) override;
+    Return<void> get2dConfig(get2dConfig_cb _hidl_cb) override;
+    Return<void> projectCameraPoints(
+        const hidl_vec<Point2dInt>& points2dCamera,
+        const hidl_string& cameraId,
+        projectCameraPoints_cb _hidl_cb) override;
+
+    // TODO(tanmayp): Make private and add set/get method.
+    // Stream subscribed for the session.
+    sp<ISurroundViewStream> mStream;
+
+private:
+    void generateFrames();
+
+    enum StreamStateValues {
+        STOPPED,
+        RUNNING,
+        STOPPING,
+        DEAD,
+    };
+    StreamStateValues mStreamState;
+
+    Sv2dConfig mConfig;
+
+    std::thread mCaptureThread; // The thread we'll use to synthesize frames
+
+    struct FramesRecord {
+        SvFramesDesc frames;
+        bool inUse = false;
+    };
+
+    FramesRecord framesRecord;
+
+    // Synchronization necessary to deconflict mCaptureThread from the main service thread
+    std::mutex mAccessLock;
+
+    std::vector<std::string> mEvsCameraIds;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundView3dSession.cpp b/automotive/sv/1.0/default/SurroundView3dSession.cpp
new file mode 100644
index 0000000..da36f32
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView3dSession.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2020 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 "SurroundView3dSession.h"
+
+#include <set>
+
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::hardware::hidl_memory;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+SurroundView3dSession::SurroundView3dSession() :
+    mStreamState(STOPPED){
+
+    mEvsCameraIds = {"0" , "1", "2", "3"};
+
+    mConfig.width = 640;
+    mConfig.height = 480;
+    mConfig.carDetails = SvQuality::HIGH;
+
+    framesRecord.frames.svBuffers.resize(1);
+    framesRecord.frames.svBuffers[0].viewId = 0;
+    framesRecord.frames.svBuffers[0].hardwareBuffer.nativeHandle = new native_handle_t();
+    framesRecord.frames.svBuffers[0].hardwareBuffer.description[0] = mConfig.width;
+    framesRecord.frames.svBuffers[0].hardwareBuffer.description[1] = mConfig.height;
+}
+
+// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+Return<SvResult> SurroundView3dSession::startStream(
+    const sp<ISurroundViewStream>& stream) {
+    ALOGD("SurroundView3dSession::startStream");
+    std::lock_guard<std::mutex> lock(mAccessLock);
+
+    if (mStreamState != STOPPED) {
+        ALOGE("ignoring startVideoStream call when a stream is already running.");
+        return SvResult::INTERNAL_ERROR;
+    }
+
+    if (mViews.empty()) {
+        ALOGE("No views have been set for current Surround View 3d Session. "
+              "Please call setViews before starting the stream.");
+        return SvResult::VIEW_NOT_SET;
+    }
+
+    mStream = stream;
+
+    ALOGD("Notify SvEvent::STREAM_STARTED");
+    mStream->notify(SvEvent::STREAM_STARTED);
+
+    // Start the frame generation thread
+    mStreamState = RUNNING;
+    mCaptureThread = std::thread([this](){ generateFrames(); });
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::stopStream() {
+    ALOGD("SurroundView3dSession::stopStream");
+    std::unique_lock <std::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
+        ALOGD("Waiting for stream thread to end...");
+        lock.unlock();
+        mCaptureThread.join();
+        lock.lock();
+
+        mStreamState = STOPPED;
+        mStream = nullptr;
+        ALOGD("Stream marked STOPPED.");
+    }
+
+    return android::hardware::Void();
+}
+
+Return<void> SurroundView3dSession::doneWithFrames(
+    const SvFramesDesc& svFramesDesc){
+    ALOGD("SurroundView3dSession::doneWithFrames");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    framesRecord.inUse = false;
+
+    (void)svFramesDesc;
+    return android::hardware::Void();
+}
+
+// Methods from ISurroundView3dSession follow.
+Return<SvResult> SurroundView3dSession::setViews(const hidl_vec<View3d>& views) {
+    ALOGD("SurroundView3dSession::stopStream");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    mViews.resize(views.size());
+    for (int i=0; i<views.size(); i++) {
+        mViews[i] = views[i];
+    }
+
+    return SvResult::OK;
+}
+
+Return<SvResult> SurroundView3dSession::set3dConfig(const Sv3dConfig& sv3dConfig) {
+    ALOGD("SurroundView3dSession::set3dConfig");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    mConfig.width = sv3dConfig.width;
+    mConfig.height = sv3dConfig.height;
+    mConfig.carDetails = sv3dConfig.carDetails;
+    ALOGD("Notify SvEvent::CONFIG_UPDATED");
+    mStream->notify(SvEvent::CONFIG_UPDATED);
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::get3dConfig(get3dConfig_cb _hidl_cb) {
+    ALOGD("SurroundView3dSession::get3dConfig");
+    std::unique_lock <std::mutex> lock(mAccessLock);
+
+    _hidl_cb(mConfig);
+    return android::hardware::Void();
+}
+
+bool VerifyOverlayData(const OverlaysData& overlaysData) {
+    // Check size of shared memory matches overlaysMemoryDesc.
+    const int kVertexSize = 16;
+    const int kIdSize = 2;
+    int memDescSize = 0;
+    for (auto overlayMemDesc : overlaysData.overlaysMemoryDesc) {
+        memDescSize += kIdSize + kVertexSize * overlayMemDesc.verticesCount;
+    }
+    if (memDescSize != overlaysData.overlaysMemory.size()) {
+        ALOGE("shared memory and overlaysMemoryDesc size mismatch.");
+        return false;
+    }
+
+    // Map memory.
+    sp<IMemory> pSharedMemory = mapMemory(overlaysData.overlaysMemory);
+    if(pSharedMemory.get() == nullptr) {
+        ALOGE("mapMemory failed.");
+        return false;
+    }
+
+    // Get Data pointer.
+    uint8_t* pData = (uint8_t*)((void*)pSharedMemory->getPointer());
+    if (pData == nullptr) {
+        ALOGE("Shared memory getPointer() failed.");
+        return false;
+    }
+
+    int idOffset = 0;
+    std::set<uint16_t> overlayIdSet;
+    for (auto overlayMemDesc : overlaysData.overlaysMemoryDesc) {
+
+        if (overlayIdSet.find(overlayMemDesc.id) != overlayIdSet.end()) {
+            ALOGE("Duplicate id within memory descriptor.");
+            return false;
+        }
+        overlayIdSet.insert(overlayMemDesc.id);
+
+        if(overlayMemDesc.verticesCount < 3) {
+            ALOGE("Less than 3 vertices.");
+            return false;
+        }
+
+        if (overlayMemDesc.overlayPrimitive == OverlayPrimitive::TRIANGLES &&
+                overlayMemDesc.verticesCount % 3 != 0) {
+            ALOGE("Triangles primitive does not have vertices multiple of 3.");
+            return false;
+        }
+
+        uint16_t overlayId = *((uint16_t*)(pData + idOffset));
+
+        if (overlayId != overlayMemDesc.id) {
+            ALOGE("Overlay id mismatch %d , %d", overlayId, overlayMemDesc.id);
+            return false;
+        }
+
+        idOffset += kIdSize + (kVertexSize * overlayMemDesc.verticesCount);
+    }
+
+    return true;
+}
+
+Return<SvResult>  SurroundView3dSession::updateOverlays(
+        const OverlaysData& overlaysData) {
+
+    if(!VerifyOverlayData(overlaysData)) {
+        ALOGE("VerifyOverlayData failed.");
+        return SvResult::INVALID_ARG;
+    }
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::projectCameraPointsTo3dSurface(
+    const hidl_vec<Point2dInt>& cameraPoints,
+    const hidl_string& cameraId,
+    projectCameraPointsTo3dSurface_cb _hidl_cb) {
+
+    std::vector<Point3dFloat> points3d;
+    bool cameraIdFound = false;
+    for (auto evsCameraId : mEvsCameraIds) {
+      if (cameraId == evsCameraId) {
+          cameraIdFound = true;
+          ALOGI("Camera id found.");
+          break;
+      }
+    }
+
+    if (!cameraIdFound) {
+        ALOGE("Camera id not found.");
+        _hidl_cb(points3d);
+        return android::hardware::Void();
+    }
+
+    for (const auto cameraPoint : cameraPoints) {
+        Point3dFloat point3d;
+        point3d.isValid = true;
+
+        if (cameraPoint.x < 0 || cameraPoint.x >= mConfig.width-1 ||
+                cameraPoint.y < 0 || cameraPoint.y >= mConfig.height-1) {
+            ALOGE("Camera point out of bounds.");
+            point3d.isValid = false;
+        }
+        points3d.push_back(point3d);
+    }
+    _hidl_cb(points3d);
+    return android::hardware::Void();
+}
+
+void SurroundView3dSession::generateFrames() {
+    ALOGD("SurroundView3dSession::generateFrames");
+
+    int sequenceId = 0;
+
+    while(true) {
+        {
+            std::lock_guard<std::mutex> lock(mAccessLock);
+
+            if (mStreamState != RUNNING) {
+                // Break out of our main thread loop
+                break;
+            }
+        }
+
+        usleep(100 * 1000);
+
+        framesRecord.frames.timestampNs = elapsedRealtimeNano();
+        framesRecord.frames.sequenceId = sequenceId++;
+
+        framesRecord.frames.svBuffers.resize(mViews.size());
+        for (int i=0; i<mViews.size(); i++) {
+            framesRecord.frames.svBuffers[i].viewId = mViews[i].viewId;
+            framesRecord.frames.svBuffers[i].hardwareBuffer.nativeHandle = new native_handle_t();
+            framesRecord.frames.svBuffers[i].hardwareBuffer.description[0] = mConfig.width; // width
+            framesRecord.frames.svBuffers[i].hardwareBuffer.description[1] = mConfig.height; // height
+        }
+
+        {
+            std::lock_guard<std::mutex> lock(mAccessLock);
+
+            if (framesRecord.inUse) {
+                ALOGD("Notify SvEvent::FRAME_DROPPED");
+                mStream->notify(SvEvent::FRAME_DROPPED);
+            } else {
+                framesRecord.inUse = true;
+                mStream->receiveFrames(framesRecord.frames);
+            }
+        }
+    }
+
+    // If we've been asked to stop, send an event to signal the actual end of stream
+    ALOGD("Notify SvEvent::STREAM_STOPPED");
+    mStream->notify(SvEvent::STREAM_STOPPED);
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundView3dSession.h b/automotive/sv/1.0/default/SurroundView3dSession.h
new file mode 100644
index 0000000..5c638db
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundView3dSession.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2020 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 <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <thread>
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+using ::std::mutex;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class SurroundView3dSession : public ISurroundView3dSession {
+public:
+    SurroundView3dSession();
+
+    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+    Return<SvResult> startStream(
+        const sp<ISurroundViewStream>& stream) override;
+    Return<void> stopStream() override;
+    Return<void> doneWithFrames(const SvFramesDesc& svFramesDesc) override;
+
+    // Methods from ISurroundView3dSession follow.
+    Return<SvResult> setViews(const hidl_vec<View3d>& views) override;
+    Return<SvResult> set3dConfig(const Sv3dConfig& sv3dConfig) override;
+    Return<void> get3dConfig(get3dConfig_cb _hidl_cb) override;
+    Return<SvResult>  updateOverlays(const OverlaysData& overlaysData);
+    Return<void> projectCameraPointsTo3dSurface(
+        const hidl_vec<Point2dInt>& cameraPoints,
+        const hidl_string& cameraId,
+        projectCameraPointsTo3dSurface_cb _hidl_cb);
+
+    // Stream subscribed for the session.
+    // TODO(tanmayp): Make private and add set/get method.
+    sp<ISurroundViewStream> mStream;
+
+private:
+    void generateFrames();
+
+    enum StreamStateValues {
+        STOPPED,
+        RUNNING,
+        STOPPING,
+        DEAD,
+    };
+    StreamStateValues mStreamState;
+
+    std::thread mCaptureThread; // The thread we'll use to synthesize frames
+
+    struct FramesRecord {
+        SvFramesDesc frames;
+        bool inUse = false;
+    };
+
+    FramesRecord framesRecord;
+
+    // Synchronization necessary to deconflict mCaptureThread from the main service thread
+    std::mutex mAccessLock;
+
+    std::vector<View3d> mViews;
+
+    Sv3dConfig mConfig;
+
+    std::vector<std::string> mEvsCameraIds;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/sv/1.0/default/SurroundViewService.cpp b/automotive/sv/1.0/default/SurroundViewService.cpp
new file mode 100644
index 0000000..fe89dd5
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundViewService.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 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 "SurroundViewService.h"
+
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+const std::string kCameraIds[] = {"0", "1", "2", "3"};
+
+Return<void> SurroundViewService::getCameraIds(getCameraIds_cb _hidl_cb) {
+  std::vector<hidl_string> cameraIds = {kCameraIds[0], kCameraIds[1],
+          kCameraIds[2], kCameraIds[3]};
+  _hidl_cb(cameraIds);
+  return android::hardware::Void();
+}
+
+Return<void> SurroundViewService::start2dSession(start2dSession_cb _hidl_cb) {
+    ALOGD("SurroundViewService::start2dSession");
+    if (mSurroundView2dSession != nullptr) {
+        ALOGW("Only one 2d session is supported at the same time");
+        _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
+    } else {
+        mSurroundView2dSession = new SurroundView2dSession();
+        _hidl_cb(mSurroundView2dSession, SvResult::OK);
+    }
+    return android::hardware::Void();
+}
+
+Return<SvResult> SurroundViewService::stop2dSession(
+    const sp<ISurroundView2dSession>& sv2dSession) {
+    ALOGD("SurroundViewService::stop2dSession");
+    if (sv2dSession != nullptr && sv2dSession == mSurroundView2dSession) {
+        mSurroundView2dSession = nullptr;
+        return SvResult::OK;
+    } else {
+        ALOGE("Invalid arg for stop2dSession");
+        return SvResult::INVALID_ARG;
+    }
+}
+
+Return<void> SurroundViewService::start3dSession(start3dSession_cb _hidl_cb) {
+    ALOGD("SurroundViewService::start3dSession");
+    if (mSurroundView3dSession != nullptr) {
+        ALOGW("Only one 3d session is supported at the same time");
+        _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
+    } else {
+        mSurroundView3dSession = new SurroundView3dSession();
+        _hidl_cb(mSurroundView3dSession, SvResult::OK);
+    }
+    return android::hardware::Void();
+}
+
+Return<SvResult> SurroundViewService::stop3dSession(
+    const sp<ISurroundView3dSession>& sv3dSession) {
+    ALOGD("SurroundViewService::stop3dSession");
+    if (sv3dSession != nullptr && sv3dSession == mSurroundView3dSession) {
+        mSurroundView3dSession = nullptr;
+        return SvResult::OK;
+    } else {
+        ALOGE("Invalid arg for stop3dSession");
+        return SvResult::INVALID_ARG;
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/automotive/sv/1.0/default/SurroundViewService.h b/automotive/sv/1.0/default/SurroundViewService.h
new file mode 100644
index 0000000..9e0e151
--- /dev/null
+++ b/automotive/sv/1.0/default/SurroundViewService.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 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 "SurroundView2dSession.h"
+#include "SurroundView3dSession.h"
+
+#include <android/hardware/automotive/sv/1.0/types.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewService.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView2dSession.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundView3dSession.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+class SurroundViewService : public ISurroundViewService {
+public:
+    // Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewService follow.
+    Return<void> getCameraIds(getCameraIds_cb _hidl_cb) override;
+    Return<void> start2dSession(start2dSession_cb _hidl_cb) override;
+    Return<SvResult> stop2dSession(
+        const sp<ISurroundView2dSession>& sv2dSession) override;
+
+    Return<void> start3dSession(start3dSession_cb _hidl_cb) override;
+    Return<SvResult> stop3dSession(
+        const sp<ISurroundView3dSession>& sv3dSession) override;
+
+private:
+    sp<SurroundView2dSession> mSurroundView2dSession;
+    sp<SurroundView3dSession> mSurroundView3dSession;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc
new file mode 100644
index 0000000..e822017
--- /dev/null
+++ b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.rc
@@ -0,0 +1,5 @@
+service sv_service /vendor/bin/hw/android.hardware.automotive.sv@1.0-service
+    class hal
+    user automotive_evs
+    group automotive_evs
+    disabled
diff --git a/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml
new file mode 100644
index 0000000..ba8e5ac
--- /dev/null
+++ b/automotive/sv/1.0/default/android.hardware.automotive.sv@1.0-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.automotive.sv</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>ISurroundViewService</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/automotive/sv/1.0/default/service.cpp b/automotive/sv/1.0/default/service.cpp
new file mode 100644
index 0000000..fae7425
--- /dev/null
+++ b/automotive/sv/1.0/default/service.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "android.hardware.automotive.sv@1.0-service"
+
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware_buffer.h>
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <thread>
+#include <ui/GraphicBuffer.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/SystemClock.h>
+
+#include "SurroundViewService.h"
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// implementation:
+using android::hardware::automotive::sv::V1_0::implementation::SurroundViewService;
+
+int main() {
+    ALOGI("ISurroundViewService default implementation is starting");
+    android::sp<ISurroundViewService> service = new SurroundViewService();
+
+    configureRpcThreadpool(1, true /* callerWillJoin */);
+
+    // Register our service -- if somebody is already registered by our name,
+    // they will be killed (their thread pool will throw an exception).
+    android::status_t status = service->registerAsService();
+
+    LOG_ALWAYS_FATAL_IF(status != android::OK,
+                        "Could not register default Surround View Service (%d)",
+                        status);
+
+    joinRpcThreadpool();
+
+    // In normal operation, we don't expect the thread pool to exit
+    ALOGE("Surround View Service is shutting down");
+    return 1;
+}