Revert^4 "Surround View Service implementation"

3c278b4e0a7a58f6f14026243909110259330bae

Bug: 150412314
Test: m -j

Change-Id: Ie05aaa4b7b4fe17709720422e258ce5f2ce7840b
diff --git a/surround_view/service-impl/Android.bp b/surround_view/service-impl/Android.bp
new file mode 100644
index 0000000..b4dac9f
--- /dev/null
+++ b/surround_view/service-impl/Android.bp
@@ -0,0 +1,114 @@
+//
+// Copyright 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.automotive.sv.service@1.0-impl",
+    vendor: true,
+    srcs: [
+        "CoreLibSetupHelper.cpp",
+        "SurroundViewService.cpp",
+        "SurroundView2dSession.cpp",
+        "SurroundView3dSession.cpp",
+        "service.cpp",
+    ],
+    init_rc: ["android.automotive.sv.service@1.0-impl.rc"],
+    shared_libs: [
+        "android.hardware.automotive.sv@1.0",
+        "android.hidl.memory@1.0",
+        "libbase",
+        "libbinder",
+        "libcore_lib_shared",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "libhidlmemory",
+        "libui",
+        "libutils",
+    ],
+    required: [
+        "cam0.png",
+        "cam1.png",
+        "cam2.png",
+        "cam3.png",
+    ],
+    // Disable builds except for arm64 and emulator devices
+    enabled: false,
+    arch: {
+        arm64: {
+            enabled: true,
+        },
+        x86: {
+            enabled: true,
+        },
+        x86_64: {
+            enabled: true,
+        },
+    },
+    vintf_fragments: [
+        "manifest_android.hardware.automotive.sv@1.0.xml",
+    ],
+}
+
+cc_prebuilt_library_shared {
+    name: "libcore_lib_shared",
+    proprietary: true,
+    arch: {
+        arm64: {
+            srcs: ["lib/arm64/libcore_lib_shared.so"]
+        },
+        x86: {
+            srcs: ["lib/x86/libcore_lib.so"]
+        },
+        x86_64: {
+            srcs: ["lib/x86-64/libcore_lib.so"]
+        },
+    },
+    shared_libs: [
+        "libEGL",
+        "libGLESv2",
+        "libGLESv3",
+        "libc",
+        "libm",
+        "libdl",
+        "libz",
+        "liblog",
+    ],
+}
+
+prebuilt_etc {
+    name: "cam0.png",
+    src: "test_data/0.png",
+    sub_dir: "automotive/sv",
+}
+
+prebuilt_etc {
+    name: "cam1.png",
+    src: "test_data/1.png",
+    sub_dir: "automotive/sv",
+}
+
+prebuilt_etc {
+    name: "cam2.png",
+    src: "test_data/2.png",
+    sub_dir: "automotive/sv",
+}
+
+prebuilt_etc {
+    name: "cam3.png",
+    src: "test_data/3.png",
+    sub_dir: "automotive/sv",
+}
+
diff --git a/surround_view/service-impl/CoreLibSetupHelper.cpp b/surround_view/service-impl/CoreLibSetupHelper.cpp
new file mode 100644
index 0000000..4812efe
--- /dev/null
+++ b/surround_view/service-impl/CoreLibSetupHelper.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright 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 "CoreLibSetupHelper.h"
+
+using namespace android_auto::surround_view;
+
+namespace android_auto {
+namespace surround_view {
+
+vector<SurroundViewCameraParams> GetCameras() {
+  std::vector<android_auto::surround_view::SurroundViewCameraParams> cameras;
+
+  // Camera 1.
+  {
+    android_auto::surround_view::SurroundViewCameraParams camera_params;
+
+    camera_params.intrinsics[0] = 608.0026093794693;
+    camera_params.intrinsics[1] = 0.0;
+    camera_params.intrinsics[2] = 968.699544102168;
+    camera_params.intrinsics[3] = 0.0;
+    camera_params.intrinsics[4] = 608.205469489769;
+    camera_params.intrinsics[5] = 476.38843298898996;
+    camera_params.intrinsics[6] = 0.0;
+    camera_params.intrinsics[7] = 0.0;
+    camera_params.intrinsics[8] = 1.0;
+
+    camera_params.distorion[0] = -0.03711481733589263;
+    camera_params.distorion[1] = -0.0014805627895442888;
+    camera_params.distorion[2] = -0.00030212056866592464;
+    camera_params.distorion[3] = -0.00020149538570397933;
+
+    camera_params.rvec[0] = 2.26308;
+    camera_params.rvec[1] = 0.0382788;
+    camera_params.rvec[2] = -0.0220549;
+
+    camera_params.tvec[0] = -7.8028875403817685e-02;
+    camera_params.tvec[1] = 1.4537396465103221e+00;
+    camera_params.tvec[2] = -8.4197165554645001e-02;
+
+    camera_params.size.width = 1920;
+    camera_params.size.height = 1024;
+
+    camera_params.circular_fov = 179;
+
+    cameras.push_back(camera_params);
+  }
+
+  // Camera 2.
+  {
+    android_auto::surround_view::SurroundViewCameraParams camera_params;
+
+    camera_params.intrinsics[0] = 607.8691721095306;
+    camera_params.intrinsics[1] = 0.0;
+    camera_params.intrinsics[2] = 975.5686146375716;
+    camera_params.intrinsics[3] = 0.0;
+    camera_params.intrinsics[4] = 608.0112887189435;
+    camera_params.intrinsics[5] = 481.1938786570715;
+    camera_params.intrinsics[6] = 0.0;
+    camera_params.intrinsics[7] = 0.0;
+    camera_params.intrinsics[8] = 1.0;
+
+    camera_params.distorion[0] = -0.040116809827977926;
+    camera_params.distorion[1] = 0.0028769489398543014;
+    camera_params.distorion[2] = -0.002651039958977229;
+    camera_params.distorion[3] = 0.00024260630476736675;
+
+    camera_params.rvec[0] = 1.67415;
+    camera_params.rvec[1] = -1.74075;
+    camera_params.rvec[2] = 0.789399;
+
+    camera_params.tvec[0] = 2.9715052384687407e-01;
+    camera_params.tvec[1] = 1.1407102692699396e+00;
+    camera_params.tvec[2] = 3.0074545273489206e-01;
+
+    camera_params.size.width = 1920;
+    camera_params.size.height = 1024;
+
+    camera_params.circular_fov = 179;
+
+    cameras.push_back(camera_params);
+  }
+
+  // Camera 3.
+  {
+    android_auto::surround_view::SurroundViewCameraParams camera_params;
+
+    camera_params.intrinsics[0] = 608.557299289448;
+    camera_params.intrinsics[1] = 0.0;
+    camera_params.intrinsics[2] = 960.1949354417656;
+    camera_params.intrinsics[3] = 0.0;
+    camera_params.intrinsics[4] = 608.8093878512448;
+    camera_params.intrinsics[5] = 474.74744054048256;
+    camera_params.intrinsics[6] = 0.0;
+    camera_params.intrinsics[7] = 0.0;
+    camera_params.intrinsics[8] = 1.0;
+
+    camera_params.distorion[0] = -0.03998488563470043;
+    camera_params.distorion[1] = 0.0024786686909103388;
+    camera_params.distorion[2] = -0.002354736769480817;
+    camera_params.distorion[3] = 0.00018369619088506146;
+
+    camera_params.rvec[0] = -0.106409;
+    camera_params.rvec[1] = -2.83697;
+    camera_params.rvec[2] = 1.28629;
+
+    camera_params.tvec[0] = 1.7115269161259747e-01;
+    camera_params.tvec[1] = 1.4376160762596599e+00;
+    camera_params.tvec[2] = -1.9028844233159006e-02;
+
+    camera_params.size.width = 1920;
+    camera_params.size.height = 1024;
+
+    camera_params.circular_fov = 179;
+
+    cameras.push_back(camera_params);
+  }
+
+  // Camera 4.
+  {
+    android_auto::surround_view::SurroundViewCameraParams camera_params;
+
+    camera_params.intrinsics[0] = 608.1221963545495;
+    camera_params.intrinsics[1] = 0.0;
+    camera_params.intrinsics[2] = 943.6280444638576;
+    camera_params.intrinsics[3] = 0.0;
+    camera_params.intrinsics[4] = 608.0523818661524;
+    camera_params.intrinsics[5] = 474.8564698210861;
+    camera_params.intrinsics[6] = 0.0;
+    camera_params.intrinsics[7] = 0.0;
+    camera_params.intrinsics[8] = 1.0;
+
+    camera_params.distorion[0] = -0.038096507459563965;
+    camera_params.distorion[1] = 0.0004008114278766646;
+    camera_params.distorion[2] = -0.0013549275607082035;
+    camera_params.distorion[3] = -5.9961182248325556e-06;
+
+    camera_params.rvec[0] = 1.63019;
+    camera_params.rvec[1] = 1.76475;
+    camera_params.rvec[2] = -0.827941;
+
+    camera_params.tvec[0] = -3.0842691427126512e-01;
+    camera_params.tvec[1] = 1.0884122033556984e+00;
+    camera_params.tvec[2] = 3.4419058255954926e-01;
+
+    camera_params.size.width = 1920;
+    camera_params.size.height = 1024;
+
+    camera_params.circular_fov = 179;
+
+    cameras.push_back(camera_params);
+  }
+  return cameras;
+
+}
+
+SurroundView2dParams Get2dParams() {
+  android_auto::surround_view::Size2dInteger
+      resolution{ /*width=*/ 1024, /*height*/ 768};
+  // make sure resolution has the same ratio with physical_size.
+  // {480 *360 }
+  android_auto::surround_view::Size2dFloat physical_size{8.0, 6.0};
+  android_auto::surround_view::Coordinate2dFloat physical_center{0, 0};
+
+  return android_auto::surround_view::SurroundView2dParams(
+      resolution, physical_size, physical_center);
+}
+
+SurroundView3dParams Get3dParams() {
+  return android_auto::surround_view::SurroundView3dParams(
+      /*plane_radius=*/ 8.0f,
+      /*plane_divisions=*/ 50,
+      /*curve_height=*/ 6.0f,
+      /*curve_divisions=*/ 50,
+      /*angular_divisions=*/ 90,
+      /*curve_coefficient=*/ 3.0f,
+      /*resolution=*/ Size2dInteger(1024, 768));
+}
+
+BoundingBox GetBoundingBox() {
+  return android_auto::surround_view::BoundingBox(
+      /*x=*/ -0.01f,
+      /*y=*/ 0.01f,
+      /*width=*/ 0.01f,
+      /*height=*/ 0.01f);
+}
+
+vector<float> GetUndistortionScales() {
+  return vector<float>{1.0f, 1.0f, 1.0f, 1.0f};
+}
+
+
+} // namespace surround_view
+} // namespace audroid_auto
+
diff --git a/surround_view/service-impl/CoreLibSetupHelper.h b/surround_view/service-impl/CoreLibSetupHelper.h
new file mode 100644
index 0000000..889ebf2
--- /dev/null
+++ b/surround_view/service-impl/CoreLibSetupHelper.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 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 <string>
+#include <vector>
+#include "core_lib.h"
+
+using namespace std;
+
+// TODO(b/150412555): The helper method should only be used for testing
+// purposes once EVS camera is used.
+namespace android_auto {
+namespace surround_view {
+
+vector<SurroundViewCameraParams> GetCameras();
+
+SurroundView2dParams Get2dParams();
+
+SurroundView3dParams Get3dParams();
+
+BoundingBox GetBoundingBox();
+
+vector<float> GetUndistortionScales();
+
+}  // namespace surround_view
+}  // namespace android_auto
+
diff --git a/surround_view/service-impl/README b/surround_view/service-impl/README
new file mode 100644
index 0000000..d7b5e7c
--- /dev/null
+++ b/surround_view/service-impl/README
@@ -0,0 +1 @@
+The core_lib.h and the .so files are copied from google3 at Mar 19, 2020.
diff --git a/surround_view/service-impl/SurroundView2dSession.cpp b/surround_view/service-impl/SurroundView2dSession.cpp
new file mode 100644
index 0000000..a2d1fb5
--- /dev/null
+++ b/surround_view/service-impl/SurroundView2dSession.cpp
@@ -0,0 +1,421 @@
+/*
+ * Copyright 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 "SurroundViewService"
+
+#include <android-base/logging.h>
+#include <android/hardware_buffer.h>
+#include <utils/SystemClock.h>
+
+#include "SurroundView2dSession.h"
+#include "CoreLibSetupHelper.h"
+
+using namespace android_auto::surround_view;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+static const char kGrayColor = 128;
+static const int kNumChannels = 3;
+static const int kFrameDelayInMilliseconds = 30;
+
+SurroundView2dSession::SurroundView2dSession() :
+    mStreamState(STOPPED) {
+    mEvsCameraIds = {"0", "1", "2", "3"};
+}
+
+// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession
+Return<SvResult> SurroundView2dSession::startStream(
+    const sp<ISurroundViewStream>& stream) {
+    LOG(DEBUG) << __FUNCTION__;
+    scoped_lock<mutex> lock(mAccessLock);
+
+    if (!mIsInitialized && !initialize()) {
+        LOG(ERROR) << "There is an error while initializing the use case. "
+                   << "Exiting";
+        return SvResult::INTERNAL_ERROR;
+    }
+
+    if (mStreamState != STOPPED) {
+        LOG(ERROR) << "Ignoring startVideoStream call"
+                   << "when a stream is already running.";
+        return SvResult::INTERNAL_ERROR;
+    }
+
+    if (stream == nullptr) {
+        LOG(ERROR) << "The input stream is invalid";
+        return SvResult::INTERNAL_ERROR;
+    }
+    mStream = stream;
+
+    LOG(DEBUG) << "Notify SvEvent::STREAM_STARTED";
+    mStream->notify(SvEvent::STREAM_STARTED);
+
+    // Start the frame generation thread
+    mStreamState = RUNNING;
+    mCaptureThread = thread([this](){
+        generateFrames();
+    });
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView2dSession::stopStream() {
+    LOG(DEBUG) << __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 {};
+}
+
+Return<void> SurroundView2dSession::doneWithFrames(
+    const SvFramesDesc& svFramesDesc){
+    LOG(DEBUG) << __FUNCTION__;
+    scoped_lock <mutex> lock(mAccessLock);
+
+    framesRecord.inUse = false;
+
+    (void)svFramesDesc;
+    return {};
+}
+
+// Methods from ISurroundView2dSession follow.
+Return<void> SurroundView2dSession::get2dMappingInfo(
+    get2dMappingInfo_cb _hidl_cb) {
+    LOG(DEBUG) << __FUNCTION__;
+
+    _hidl_cb(mInfo);
+    return {};
+}
+
+Return<SvResult> SurroundView2dSession::set2dConfig(
+    const Sv2dConfig& sv2dConfig) {
+    LOG(DEBUG) << __FUNCTION__;
+    scoped_lock <mutex> lock(mAccessLock);
+
+    if (sv2dConfig.width <=0 || sv2dConfig.width > 4096) {
+        LOG(WARNING) << "The width of 2d config is out of the range (0, 4096]"
+                     << "Ignored!";
+        return SvResult::INVALID_ARG;
+    }
+
+    mConfig.width = sv2dConfig.width;
+    mConfig.blending = sv2dConfig.blending;
+    mHeight = mConfig.width * mInfo.height / mInfo.width;
+
+    if (mStream != nullptr) {
+        LOG(DEBUG) << "Notify SvEvent::CONFIG_UPDATED";
+        mStream->notify(SvEvent::CONFIG_UPDATED);
+    }
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView2dSession::get2dConfig(get2dConfig_cb _hidl_cb) {
+    LOG(DEBUG) << __FUNCTION__;
+
+    _hidl_cb(mConfig);
+    return {};
+}
+
+Return<void> SurroundView2dSession::projectCameraPoints(
+        const hidl_vec<Point2dInt>& points2dCamera,
+        const hidl_string& cameraId,
+        projectCameraPoints_cb _hidl_cb) {
+    LOG(DEBUG) << __FUNCTION__;
+    scoped_lock <mutex> lock(mAccessLock);
+
+    bool cameraIdFound = false;
+    for (auto& evsCameraId : mEvsCameraIds) {
+      if (cameraId == evsCameraId) {
+          cameraIdFound = true;
+          LOG(INFO) << "Camera id found.";
+          break;
+      }
+    }
+
+    if (!cameraIdFound) {
+        LOG(ERROR) << "Camera id not found.";
+        _hidl_cb({});
+        return {};
+    }
+
+    hidl_vec<Point2dFloat> outPoints;
+    outPoints.resize(points2dCamera.size());
+
+    int width = mConfig.width;
+    int height = mHeight;
+    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].x > width-1 ||
+            points2dCamera[i].y < 0 || points2dCamera[i].y > height-1) {
+            LOG(WARNING) << __FUNCTION__
+                         << ": 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 {};
+}
+
+void SurroundView2dSession::generateFrames() {
+    int sequenceId = 0;
+
+    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;
+            }
+
+            if (mOutputWidth != mConfig.width || mOutputHeight != mHeight) {
+                LOG(DEBUG) << "Config changed. Re-allocate memory."
+                           << " Old width: "
+                           << mOutputWidth
+                           << " Old height: "
+                           << mOutputHeight
+                           << " New width: "
+                           << mConfig.width
+                           << " New height: "
+                           << mHeight;
+                delete[] static_cast<char*>(mOutputPointer.data_pointer);
+                mOutputWidth = mConfig.width;
+                mOutputHeight = mHeight;
+                mOutputPointer.height = mOutputHeight;
+                mOutputPointer.width = mOutputWidth;
+                mOutputPointer.format = Format::RGB;
+                mOutputPointer.data_pointer =
+                    new char[mOutputHeight * mOutputWidth * kNumChannels];
+
+                if (!mOutputPointer.data_pointer) {
+                    LOG(ERROR) << "Memory allocation failed. Exiting.";
+                    break;
+                }
+
+                Size2dInteger size = Size2dInteger(mOutputWidth, mOutputHeight);
+                mSurroundView->Update2dOutputResolution(size);
+
+                mSvTexture = new GraphicBuffer(mOutputWidth,
+                                               mOutputHeight,
+                                               HAL_PIXEL_FORMAT_RGB_888,
+                                               1,
+                                               GRALLOC_USAGE_HW_TEXTURE,
+                                               "SvTexture");
+                if (mSvTexture->initCheck() == OK) {
+                    LOG(INFO) << "Successfully allocated Graphic Buffer";
+                } else {
+                    LOG(ERROR) << "Failed to allocate Graphic Buffer";
+                    break;
+                }
+            }
+        }
+
+        if (mSurroundView->Get2dSurroundView(mInputPointers, &mOutputPointer)) {
+            LOG(INFO) << "Get2dSurroundView succeeded";
+        } else {
+            LOG(ERROR) << "Get2dSurroundView failed. "
+                       << "Using memset to initialize to gray";
+            memset(mOutputPointer.data_pointer, kGrayColor,
+                   mOutputHeight * mOutputWidth * kNumChannels);
+        }
+
+        void* textureDataPtr = nullptr;
+        mSvTexture->lock(GRALLOC_USAGE_SW_WRITE_OFTEN
+                         | GRALLOC_USAGE_SW_READ_NEVER,
+                         &textureDataPtr);
+        if (!textureDataPtr) {
+            LOG(ERROR) << "Failed to gain write access to GraphicBuffer!";
+            break;
+        }
+
+        // Note: there is a chance that the stride of the texture is not the same
+        // as the width. For example, when the input frame is 1920 * 1080, the
+        // width is 1080, but the stride is 2048. So we'd better copy the data line
+        // by line, instead of single memcpy.
+        uint8_t* writePtr = static_cast<uint8_t*>(textureDataPtr);
+        uint8_t* readPtr = static_cast<uint8_t*>(mOutputPointer.data_pointer);
+        const int readStride = mOutputWidth * kNumChannels;
+        const int writeStride = mSvTexture->getStride() * kNumChannels;
+        if (readStride == writeStride) {
+            memcpy(writePtr, readPtr, readStride * mSvTexture->getHeight());
+        } else {
+            for (int i=0; i<mSvTexture->getHeight(); i++) {
+                memcpy(writePtr, readPtr, readStride);
+                writePtr = writePtr + writeStride;
+                readPtr = readPtr + readStride;
+            }
+        }
+        LOG(INFO) << "memcpy finished";
+        mSvTexture->unlock();
+
+        ANativeWindowBuffer* buffer = mSvTexture->getNativeBuffer();
+        LOG(DEBUG) << "ANativeWindowBuffer->handle: "
+                   << buffer->handle;
+
+        framesRecord.frames.svBuffers.resize(1);
+        SvBuffer& svBuffer = framesRecord.frames.svBuffers[0];
+        svBuffer.viewId = 0;
+        svBuffer.hardwareBuffer.nativeHandle = buffer->handle;
+        AHardwareBuffer_Desc* pDesc =
+            reinterpret_cast<AHardwareBuffer_Desc *>(
+                &svBuffer.hardwareBuffer.description);
+        pDesc->width = mOutputWidth;
+        pDesc->height = mOutputHeight;
+        pDesc->layers = 1;
+        pDesc->usage = GRALLOC_USAGE_HW_TEXTURE;
+        pDesc->stride = mSvTexture->getStride();
+        pDesc->format = HAL_PIXEL_FORMAT_RGB_888;
+        framesRecord.frames.timestampNs = elapsedRealtimeNano();
+        framesRecord.frames.sequenceId = sequenceId++;
+
+        {
+            scoped_lock<mutex> lock(mAccessLock);
+
+            if (framesRecord.inUse) {
+                LOG(DEBUG) << "Notify SvEvent::FRAME_DROPPED";
+                mStream->notify(SvEvent::FRAME_DROPPED);
+            } else {
+                framesRecord.inUse = true;
+                mStream->receiveFrames(framesRecord.frames);
+            }
+        }
+
+        // TODO(b/150412555): adding delays explicitly. This delay should be
+        // removed when EVS camera is used.
+        this_thread::sleep_for(chrono::milliseconds(
+            kFrameDelayInMilliseconds));
+    }
+
+    // If we've been asked to stop, send an event to signal the actual
+    // end of stream
+    LOG(DEBUG) << "Notify SvEvent::STREAM_STOPPED";
+    mStream->notify(SvEvent::STREAM_STOPPED);
+}
+
+bool SurroundView2dSession::initialize() {
+    lock_guard<mutex> lock(mAccessLock, adopt_lock);
+
+    // TODO(b/150412555): ask core-lib team to add API description for "create"
+    // method in the .h file.
+    // The create method will never return a null pointer based the API
+    // description.
+    mSurroundView = unique_ptr<SurroundView>(Create());
+
+    mSurroundView->SetStaticData(GetCameras(), Get2dParams(), Get3dParams(),
+                                 GetUndistortionScales(), GetBoundingBox());
+
+    // TODO(b/150412555): remove after EVS camera is used
+    mInputPointers = mSurroundView->ReadImages(
+        "/etc/automotive/sv/cam0.png",
+        "/etc/automotive/sv/cam1.png",
+        "/etc/automotive/sv/cam2.png",
+        "/etc/automotive/sv/cam3.png");
+    if (mInputPointers.size() == 4
+        && mInputPointers[0].cpu_data_pointer != nullptr) {
+        LOG(INFO) << "ReadImages succeeded";
+    } else {
+        LOG(ERROR) << "Failed to read images";
+        return false;
+    }
+
+    mOutputWidth = Get2dParams().resolution.width;
+    mOutputHeight = Get2dParams().resolution.height;
+
+    mConfig.width = mOutputWidth;
+    mConfig.blending = SvQuality::HIGH;
+    mHeight = mOutputHeight;
+
+    mOutputPointer.height = mOutputHeight;
+    mOutputPointer.width = mOutputWidth;
+    mOutputPointer.format = mInputPointers[0].format;
+    mOutputPointer.data_pointer = new char[
+        mOutputHeight * mOutputWidth * kNumChannels];
+
+    if (!mOutputPointer.data_pointer) {
+        LOG(ERROR) << "Memory allocation failed. Exiting.";
+        return false;
+    }
+
+    mSvTexture = new GraphicBuffer(mOutputWidth,
+                                   mOutputHeight,
+                                   HAL_PIXEL_FORMAT_RGB_888,
+                                   1,
+                                   GRALLOC_USAGE_HW_TEXTURE,
+                                   "SvTexture");
+
+    //TODO(b/150412555): the 2d mapping info should be read from config file.
+    mInfo.width = 8;
+    mInfo.height = 6;
+    mInfo.center.isValid = true;
+    mInfo.center.x = 0;
+    mInfo.center.y = 0;
+
+    if (mSvTexture->initCheck() == OK) {
+        LOG(INFO) << "Successfully allocated Graphic Buffer";
+    } else {
+        LOG(ERROR) << "Failed to allocate Graphic Buffer";
+        return false;
+    }
+
+    if (mSurroundView->Start2dPipeline()) {
+        LOG(INFO) << "Start2dPipeline succeeded";
+    } else {
+        LOG(ERROR) << "Start2dPipeline failed";
+        return false;
+    }
+
+    mIsInitialized = true;
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/surround_view/service-impl/SurroundView2dSession.h b/surround_view/service-impl/SurroundView2dSession.h
new file mode 100644
index 0000000..c9591f1
--- /dev/null
+++ b/surround_view/service-impl/SurroundView2dSession.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 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 "CoreLibSetupHelper.h"
+#include <thread>
+
+#include <ui/GraphicBuffer.h>
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+
+using namespace android_auto::surround_view;
+
+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;
+
+private:
+    void generateFrames();
+    bool initialize();
+
+    enum StreamStateValues {
+        STOPPED,
+        RUNNING,
+        STOPPING,
+        DEAD,
+    };
+    StreamStateValues mStreamState GUARDED_BY(mAccessLock);
+
+    // Stream subscribed for the session.
+    sp<ISurroundViewStream> mStream GUARDED_BY(mAccessLock);
+
+    Sv2dConfig mConfig GUARDED_BY(mAccessLock);
+    int mHeight GUARDED_BY(mAccessLock);
+    Sv2dMappingInfo mInfo GUARDED_BY(mAccessLock);
+
+    thread mCaptureThread GUARDED_BY(mAccessLock);
+
+    struct FramesRecord {
+        SvFramesDesc frames;
+        bool inUse = false;
+    };
+
+    FramesRecord framesRecord GUARDED_BY(mAccessLock);
+
+    // Synchronization necessary to deconflict mCaptureThread from the main
+    // service thread
+    mutex mAccessLock;
+
+    vector<string> mEvsCameraIds GUARDED_BY(mAccessLock);
+
+    unique_ptr<SurroundView> mSurroundView GUARDED_BY(mAccessLock);
+
+    vector<SurroundViewInputBufferPointers>
+        mInputPointers GUARDED_BY(mAccessLock);
+    SurroundViewResultPointer mOutputPointer GUARDED_BY(mAccessLock);
+    int mOutputWidth, mOutputHeight GUARDED_BY(mAccessLock);
+
+    sp<GraphicBuffer> mSvTexture GUARDED_BY(mAccessLock);
+
+    bool mIsInitialized GUARDED_BY(mAccessLock) = false;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/surround_view/service-impl/SurroundView3dSession.cpp b/surround_view/service-impl/SurroundView3dSession.cpp
new file mode 100644
index 0000000..9eed0cd
--- /dev/null
+++ b/surround_view/service-impl/SurroundView3dSession.cpp
@@ -0,0 +1,511 @@
+/*
+ * Copyright 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 "SurroundViewService"
+
+#include <android-base/logging.h>
+#include <android/hardware_buffer.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
+#include <set>
+#include <utils/SystemClock.h>
+
+#include "SurroundView3dSession.h"
+#include "sv_3d_params.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 {
+
+static const char kGrayColor = 128;
+static const int kNumChannels = 4;
+
+SurroundView3dSession::SurroundView3dSession() :
+    mStreamState(STOPPED){
+    mEvsCameraIds = {"0" , "1", "2", "3"};
+}
+
+// Methods from ::android::hardware::automotive::sv::V1_0::ISurroundViewSession.
+Return<SvResult> SurroundView3dSession::startStream(
+    const sp<ISurroundViewStream>& stream) {
+    LOG(DEBUG) << __FUNCTION__;
+    scoped_lock<mutex> lock(mAccessLock);
+
+    if (!mIsInitialized && !initialize()) {
+        LOG(ERROR) << "There is an error while initializing the use case. "
+                   << "Exiting";
+        return SvResult::INTERNAL_ERROR;
+    }
+
+    if (mStreamState != STOPPED) {
+        LOG(ERROR) << "Ignoring startVideoStream call when a stream is "
+                   << "already running.";
+        return SvResult::INTERNAL_ERROR;
+    }
+
+    if (mViews.empty()) {
+        LOG(ERROR) << "No views have been set for current Surround View"
+                   << "3d Session. Please call setViews before starting"
+                   << "the stream.";
+        return SvResult::VIEW_NOT_SET;
+    }
+
+    if (stream == nullptr) {
+        LOG(ERROR) << "The input stream is invalid";
+        return SvResult::INTERNAL_ERROR;
+    }
+    mStream = stream;
+
+    LOG(DEBUG) << "Notify SvEvent::STREAM_STARTED";
+    mStream->notify(SvEvent::STREAM_STARTED);
+
+    // Start the frame generation thread
+    mStreamState = RUNNING;
+    mCaptureThread = thread([this](){
+        generateFrames();
+    });
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::stopStream() {
+    LOG(DEBUG) << __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 {};
+}
+
+Return<void> SurroundView3dSession::doneWithFrames(
+    const SvFramesDesc& svFramesDesc){
+    LOG(DEBUG) << __FUNCTION__;
+    scoped_lock <mutex> lock(mAccessLock);
+
+    framesRecord.inUse = false;
+
+    (void)svFramesDesc;
+    return {};
+}
+
+// Methods from ISurroundView3dSession follow.
+Return<SvResult> SurroundView3dSession::setViews(
+    const hidl_vec<View3d>& views) {
+    LOG(DEBUG) << __FUNCTION__;
+    scoped_lock <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) {
+    LOG(DEBUG) << __FUNCTION__;
+    scoped_lock <mutex> lock(mAccessLock);
+
+    if (sv3dConfig.width <=0 || sv3dConfig.width > 4096) {
+        LOG(WARNING) << "The width of 3d config is out of the range (0, 4096]"
+                     << "Ignored!";
+        return SvResult::INVALID_ARG;
+    }
+
+    if (sv3dConfig.height <=0 || sv3dConfig.height > 4096) {
+        LOG(WARNING) << "The height of 3d config is out of the range (0, 4096]"
+                     << "Ignored!";
+        return SvResult::INVALID_ARG;
+    }
+
+    mConfig.width = sv3dConfig.width;
+    mConfig.height = sv3dConfig.height;
+    mConfig.carDetails = sv3dConfig.carDetails;
+
+    if (mStream != nullptr) {
+        LOG(DEBUG) << "Notify SvEvent::CONFIG_UPDATED";
+        mStream->notify(SvEvent::CONFIG_UPDATED);
+    }
+
+    return SvResult::OK;
+}
+
+Return<void> SurroundView3dSession::get3dConfig(get3dConfig_cb _hidl_cb) {
+    LOG(DEBUG) << __FUNCTION__;
+
+    _hidl_cb(mConfig);
+    return {};
+}
+
+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()) {
+        LOG(ERROR) << "shared memory and overlaysMemoryDesc size mismatch.";
+        return false;
+    }
+
+    // Map memory.
+    sp<IMemory> pSharedMemory = mapMemory(overlaysData.overlaysMemory);
+    if(pSharedMemory == nullptr) {
+        LOG(ERROR) << "mapMemory failed.";
+        return false;
+    }
+
+    // Get Data pointer.
+    uint8_t* pData = static_cast<uint8_t*>(
+        static_cast<void*>(pSharedMemory->getPointer()));
+    if (pData == nullptr) {
+        LOG(ERROR) << "Shared memory getPointer() failed.";
+        return false;
+    }
+
+    int idOffset = 0;
+    set<uint16_t> overlayIdSet;
+    for (auto& overlayMemDesc : overlaysData.overlaysMemoryDesc) {
+
+        if (overlayIdSet.find(overlayMemDesc.id) != overlayIdSet.end()) {
+            LOG(ERROR) << "Duplicate id within memory descriptor.";
+            return false;
+        }
+        overlayIdSet.insert(overlayMemDesc.id);
+
+        if(overlayMemDesc.verticesCount < 3) {
+            LOG(ERROR) << "Less than 3 vertices.";
+            return false;
+        }
+
+        if (overlayMemDesc.overlayPrimitive == OverlayPrimitive::TRIANGLES &&
+                overlayMemDesc.verticesCount % 3 != 0) {
+            LOG(ERROR) << "Triangles primitive does not have vertices "
+                       << "multiple of 3.";
+            return false;
+        }
+
+        const uint16_t overlayId = *((uint16_t*)(pData + idOffset));
+
+        if (overlayId != overlayMemDesc.id) {
+            LOG(ERROR) << "Overlay id mismatch "
+                       << overlayId
+                       << ", "
+                       << overlayMemDesc.id;
+            return false;
+        }
+
+        idOffset += kIdSize + (kVertexSize * overlayMemDesc.verticesCount);
+    }
+
+    return true;
+}
+
+// TODO(b/150412555): the overlay related methods are incomplete.
+Return<SvResult>  SurroundView3dSession::updateOverlays(
+        const OverlaysData& overlaysData) {
+
+    if(!VerifyOverlayData(overlaysData)) {
+        LOG(ERROR) << "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) {
+
+    vector<Point3dFloat> points3d;
+    bool cameraIdFound = false;
+    for (auto& evsCameraId : mEvsCameraIds) {
+      if (cameraId == evsCameraId) {
+          cameraIdFound = true;
+          LOG(INFO) << "Camera id found.";
+          break;
+      }
+    }
+
+    if (!cameraIdFound) {
+        LOG(ERROR) << "Camera id not found.";
+        _hidl_cb(points3d);
+        return {};
+    }
+
+    for (const auto& cameraPoint : cameraPoints) {
+        Point3dFloat point3d;
+        point3d.isValid = (cameraPoint.x >= 0
+                           && cameraPoint.x < mConfig.width
+                           && cameraPoint.y >= 0
+                           && cameraPoint.y < mConfig.height);
+        if (!point3d.isValid) {
+            LOG(WARNING) << "Camera point out of bounds.";
+        }
+        points3d.push_back(point3d);
+    }
+    _hidl_cb(points3d);
+    return {};
+}
+
+void SurroundView3dSession::generateFrames() {
+    int sequenceId = 0;
+
+    // TODO(b/150412555): do not use the setViews for frames generation
+    // since there is a discrepancy between the HIDL APIs and core lib APIs.
+    vector<vector<float>> matrix;
+    matrix.resize(4);
+    for (int i=0; i<4; i++) {
+        matrix[i].resize(4);
+    }
+
+    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;
+            }
+
+            if (mOutputWidth != mConfig.width
+                || mOutputHeight != mConfig.height) {
+                LOG(DEBUG) << "Config changed. Re-allocate memory. "
+                           << "Old width: "
+                           << mOutputWidth
+                           << ", old height: "
+                           << mOutputHeight
+                           << "; New width: "
+                           << mConfig.width
+                           << ", new height: "
+                           << mConfig.height;
+                delete[] static_cast<char*>(mOutputPointer.data_pointer);
+                mOutputWidth = mConfig.width;
+                mOutputHeight = mConfig.height;
+                mOutputPointer.height = mOutputHeight;
+                mOutputPointer.width = mOutputWidth;
+                mOutputPointer.format = Format::RGBA;
+                mOutputPointer.data_pointer =
+                    new char[mOutputHeight * mOutputWidth * kNumChannels];
+
+                if (!mOutputPointer.data_pointer) {
+                    LOG(ERROR) << "Memory allocation failed. Exiting.";
+                    break;
+                }
+
+                Size2dInteger size = Size2dInteger(mOutputWidth, mOutputHeight);
+                mSurroundView->Update3dOutputResolution(size);
+
+                mSvTexture = new GraphicBuffer(mOutputWidth,
+                                               mOutputHeight,
+                                               HAL_PIXEL_FORMAT_RGBA_8888,
+                                               1,
+                                               GRALLOC_USAGE_HW_TEXTURE,
+                                               "SvTexture");
+                if (mSvTexture->initCheck() == OK) {
+                    LOG(INFO) << "Successfully allocated Graphic Buffer";
+                } else {
+                    LOG(ERROR) << "Failed to allocate Graphic Buffer";
+                    break;
+                }
+            }
+        }
+
+        // TODO(b/150412555): use hard-coded views for now. Change view every 10
+        // frames.
+        int recViewId = sequenceId / 10 % 16;
+        for (int i=0; i<4; i++)
+            for (int j=0; j<4; j++) {
+                matrix[i][j] = kRecViews[recViewId][i*4+j];
+        }
+
+        if (mSurroundView->Get3dSurroundView(
+            mInputPointers, matrix, &mOutputPointer)) {
+            LOG(INFO) << "Get3dSurroundView succeeded";
+        } else {
+            LOG(ERROR) << "Get3dSurroundView failed. "
+                       << "Using memset to initialize to gray.";
+            memset(mOutputPointer.data_pointer, kGrayColor,
+                   mOutputHeight * mOutputWidth * kNumChannels);
+        }
+
+        void* textureDataPtr = nullptr;
+        mSvTexture->lock(GRALLOC_USAGE_SW_WRITE_OFTEN
+                        | GRALLOC_USAGE_SW_READ_NEVER,
+                        &textureDataPtr);
+        if (!textureDataPtr) {
+            LOG(ERROR) << "Failed to gain write access to GraphicBuffer!";
+            break;
+        }
+
+        // Note: there is a chance that the stride of the texture is not the
+        // same as the width. For example, when the input frame is 1920 * 1080,
+        // the width is 1080, but the stride is 2048. So we'd better copy the
+        // data line by line, instead of single memcpy.
+        uint8_t* writePtr = static_cast<uint8_t*>(textureDataPtr);
+        uint8_t* readPtr = static_cast<uint8_t*>(mOutputPointer.data_pointer);
+        const int readStride = mOutputWidth * kNumChannels;
+        const int writeStride = mSvTexture->getStride() * kNumChannels;
+        if (readStride == writeStride) {
+            memcpy(writePtr, readPtr, readStride * mSvTexture->getHeight());
+        } else {
+            for (int i=0; i<mSvTexture->getHeight(); i++) {
+                memcpy(writePtr, readPtr, readStride);
+                writePtr = writePtr + writeStride;
+                readPtr = readPtr + readStride;
+            }
+        }
+        LOG(INFO) << "memcpy finished!";
+        mSvTexture->unlock();
+
+        ANativeWindowBuffer* buffer = mSvTexture->getNativeBuffer();
+        LOG(DEBUG) << "ANativeWindowBuffer->handle: " << buffer->handle;
+
+        framesRecord.frames.svBuffers.resize(1);
+        SvBuffer& svBuffer = framesRecord.frames.svBuffers[0];
+        svBuffer.viewId = 0;
+        svBuffer.hardwareBuffer.nativeHandle = buffer->handle;
+        AHardwareBuffer_Desc* pDesc =
+            reinterpret_cast<AHardwareBuffer_Desc *>(
+                &svBuffer.hardwareBuffer.description);
+        pDesc->width = mOutputWidth;
+        pDesc->height = mOutputHeight;
+        pDesc->layers = 1;
+        pDesc->usage = GRALLOC_USAGE_HW_TEXTURE;
+        pDesc->stride = mSvTexture->getStride();
+        pDesc->format = HAL_PIXEL_FORMAT_RGBA_8888;
+        framesRecord.frames.timestampNs = elapsedRealtimeNano();
+        framesRecord.frames.sequenceId = sequenceId++;
+
+        {
+            scoped_lock<mutex> lock(mAccessLock);
+
+            if (framesRecord.inUse) {
+                LOG(DEBUG) << "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
+    LOG(DEBUG) << "Notify SvEvent::STREAM_STOPPED";
+    mStream->notify(SvEvent::STREAM_STOPPED);
+}
+
+bool SurroundView3dSession::initialize() {
+    lock_guard<mutex> lock(mAccessLock, adopt_lock);
+
+    // TODO(b/150412555): ask core-lib team to add API description for "create"
+    // method in the .h file.
+    // The create method will never return a null pointer based the API
+    // description.
+    mSurroundView = unique_ptr<SurroundView>(Create());
+
+    mSurroundView->SetStaticData(GetCameras(), Get2dParams(), Get3dParams(),
+                                 GetUndistortionScales(), GetBoundingBox());
+
+    // TODO(b/150412555): remove after EVS camera is used
+    mInputPointers = mSurroundView->ReadImages(
+        "/etc/automotive/sv/cam0.png",
+        "/etc/automotive/sv/cam1.png",
+        "/etc/automotive/sv/cam2.png",
+        "/etc/automotive/sv/cam3.png");
+    if (mInputPointers.size() == 4
+        && mInputPointers[0].cpu_data_pointer != nullptr) {
+        LOG(INFO) << "ReadImages succeeded";
+    } else {
+        LOG(ERROR) << "Failed to read images";
+        return false;
+    }
+
+    mOutputWidth = Get3dParams().resolution.width;
+    mOutputHeight = Get3dParams().resolution.height;
+
+    mConfig.width = mOutputWidth;
+    mConfig.height = mOutputHeight;
+    mConfig.carDetails = SvQuality::HIGH;
+
+    mOutputPointer.height = mOutputHeight;
+    mOutputPointer.width = mOutputWidth;
+    mOutputPointer.format = Format::RGBA;
+    mOutputPointer.data_pointer = new char[
+        mOutputHeight * mOutputWidth * kNumChannels];
+
+    if (!mOutputPointer.data_pointer) {
+        LOG(ERROR) << "Memory allocation failed. Exiting.";
+        return false;
+    }
+
+    mSvTexture = new GraphicBuffer(mOutputWidth,
+                                   mOutputHeight,
+                                   HAL_PIXEL_FORMAT_RGBA_8888,
+                                   1,
+                                   GRALLOC_USAGE_HW_TEXTURE,
+                                   "SvTexture");
+
+    if (mSvTexture->initCheck() == OK) {
+        LOG(INFO) << "Successfully allocated Graphic Buffer";
+    } else {
+        LOG(ERROR) << "Failed to allocate Graphic Buffer";
+        return false;
+    }
+
+    if (mSurroundView->Start3dPipeline()) {
+        LOG(INFO) << "Start3dPipeline succeeded";
+    } else {
+        LOG(ERROR) << "Start3dPipeline failed";
+        return false;
+    }
+
+    mIsInitialized = true;
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/surround_view/service-impl/SurroundView3dSession.h b/surround_view/service-impl/SurroundView3dSession.h
new file mode 100644
index 0000000..12337b6
--- /dev/null
+++ b/surround_view/service-impl/SurroundView3dSession.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright 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 "CoreLibSetupHelper.h"
+#include <thread>
+
+#include <ui/GraphicBuffer.h>
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+
+using namespace android_auto::surround_view;
+
+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);
+
+private:
+    void generateFrames();
+    bool initialize();
+
+    enum StreamStateValues {
+        STOPPED,
+        RUNNING,
+        STOPPING,
+        DEAD,
+    };
+
+    // Stream subscribed for the session.
+    sp<ISurroundViewStream> mStream GUARDED_BY(mAccessLock);
+    StreamStateValues mStreamState GUARDED_BY(mAccessLock);
+
+    thread mCaptureThread; // The thread we'll use to synthesize frames
+
+    struct FramesRecord {
+        SvFramesDesc frames;
+        bool inUse = false;
+    };
+
+    FramesRecord framesRecord GUARDED_BY(mAccessLock);
+
+    // Synchronization necessary to deconflict mCaptureThread from the main service thread
+    mutex mAccessLock;
+
+    vector<View3d> mViews GUARDED_BY(mAccessLock);
+
+    Sv3dConfig mConfig GUARDED_BY(mAccessLock);
+
+    vector<string> mEvsCameraIds GUARDED_BY(mAccessLock);
+
+    unique_ptr<SurroundView> mSurroundView GUARDED_BY(mAccessLock);
+
+    vector<SurroundViewInputBufferPointers>
+        mInputPointers GUARDED_BY(mAccessLock);
+    SurroundViewResultPointer mOutputPointer GUARDED_BY(mAccessLock);
+    int mOutputWidth, mOutputHeight GUARDED_BY(mAccessLock);
+
+    sp<GraphicBuffer> mSvTexture GUARDED_BY(mAccessLock);
+
+    bool mIsInitialized GUARDED_BY(mAccessLock) = false;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/SurroundViewService.cpp b/surround_view/service-impl/SurroundViewService.cpp
new file mode 100644
index 0000000..8e6a683
--- /dev/null
+++ b/surround_view/service-impl/SurroundViewService.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright 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 "SurroundViewService"
+
+#include <android-base/logging.h>
+
+#include "CoreLibSetupHelper.h"
+#include "SurroundViewService.h"
+
+using namespace android_auto::surround_view;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace sv {
+namespace V1_0 {
+namespace implementation {
+
+std::mutex SurroundViewService::sLock;
+sp<SurroundViewService> SurroundViewService::sService;
+sp<SurroundView2dSession> SurroundViewService::sSurroundView2dSession;
+sp<SurroundView3dSession> SurroundViewService::sSurroundView3dSession;
+
+const std::string kCameraIds[] = {"0", "1", "2", "3"};
+
+sp<SurroundViewService> SurroundViewService::getInstance() {
+    std::scoped_lock<std::mutex> lock(sLock);
+    if (sService == nullptr) {
+        sService = new SurroundViewService();
+    }
+    return sService;
+}
+
+Return<void> SurroundViewService::getCameraIds(getCameraIds_cb _hidl_cb) {
+    hidl_vec<hidl_string> cameraIds = {kCameraIds[0], kCameraIds[1],
+        kCameraIds[2], kCameraIds[3]};
+    _hidl_cb(cameraIds);
+    return {};
+}
+
+Return<void> SurroundViewService::start2dSession(start2dSession_cb _hidl_cb) {
+    LOG(DEBUG) << __FUNCTION__;
+    std::scoped_lock<std::mutex> lock(sLock);
+
+    if (sSurroundView2dSession != nullptr) {
+        LOG(WARNING) << "Only one 2d session is supported at the same time";
+        _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
+    } else {
+        sSurroundView2dSession = new SurroundView2dSession();
+        _hidl_cb(sSurroundView2dSession, SvResult::OK);
+    }
+    return {};
+}
+
+Return<SvResult> SurroundViewService::stop2dSession(
+    const sp<ISurroundView2dSession>& sv2dSession) {
+    LOG(DEBUG) << __FUNCTION__;
+    std::scoped_lock<std::mutex> lock(sLock);
+
+    if (sv2dSession != nullptr && sv2dSession == sSurroundView2dSession) {
+        sSurroundView2dSession = nullptr;
+        return SvResult::OK;
+    } else {
+        LOG(ERROR) << __FUNCTION__ << ": Invalid argument";
+        return SvResult::INVALID_ARG;
+    }
+}
+
+Return<void> SurroundViewService::start3dSession(start3dSession_cb _hidl_cb) {
+    LOG(DEBUG) << __FUNCTION__;
+    std::scoped_lock<std::mutex> lock(sLock);
+
+    if (sSurroundView3dSession != nullptr) {
+        LOG(WARNING) << "Only one 3d session is supported at the same time";
+        _hidl_cb(nullptr, SvResult::INTERNAL_ERROR);
+    } else {
+        sSurroundView3dSession = new SurroundView3dSession();
+        _hidl_cb(sSurroundView3dSession, SvResult::OK);
+    }
+    return {};
+}
+
+Return<SvResult> SurroundViewService::stop3dSession(
+    const sp<ISurroundView3dSession>& sv3dSession) {
+    LOG(DEBUG) << __FUNCTION__;
+    std::scoped_lock<std::mutex> lock(sLock);
+
+    if (sv3dSession != nullptr && sv3dSession == sSurroundView3dSession) {
+        sSurroundView3dSession = nullptr;
+        return SvResult::OK;
+    } else {
+        LOG(ERROR) << __FUNCTION__ << ": Invalid argument";
+        return SvResult::INVALID_ARG;
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/surround_view/service-impl/SurroundViewService.h b/surround_view/service-impl/SurroundViewService.h
new file mode 100644
index 0000000..7518463
--- /dev/null
+++ b/surround_view/service-impl/SurroundViewService.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 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>
+
+#include <thread>
+
+using namespace ::android::hardware::automotive::sv::V1_0;
+using ::android::hardware::Return;
+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;
+
+    static sp<SurroundViewService> getInstance();
+private:
+    SurroundViewService() {};
+
+    static std::mutex sLock;
+    static sp<SurroundViewService> sService GUARDED_BY(sLock);
+
+    static sp<SurroundView2dSession> sSurroundView2dSession GUARDED_BY(sLock);
+    static sp<SurroundView3dSession> sSurroundView3dSession GUARDED_BY(sLock);
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace sv
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/surround_view/service-impl/android.automotive.sv.service@1.0-impl.rc b/surround_view/service-impl/android.automotive.sv.service@1.0-impl.rc
new file mode 100644
index 0000000..4207e8f
--- /dev/null
+++ b/surround_view/service-impl/android.automotive.sv.service@1.0-impl.rc
@@ -0,0 +1,5 @@
+service sv_service_impl /vendor/bin/android.automotive.sv.service@1.0-impl
+    class hal
+    user automotive_evs
+    group automotive_evs
+    disabled
diff --git a/surround_view/service-impl/core_lib.h b/surround_view/service-impl/core_lib.h
new file mode 100644
index 0000000..04ff43a
--- /dev/null
+++ b/surround_view/service-impl/core_lib.h
@@ -0,0 +1,528 @@
+#ifndef WIRELESS_ANDROID_AUTOMOTIVE_CAML_SURROUND_VIEW_CORE_LIB_H_
+#define WIRELESS_ANDROID_AUTOMOTIVE_CAML_SURROUND_VIEW_CORE_LIB_H_
+
+#include <cstdint>
+#include <vector>
+
+namespace android_auto {
+namespace surround_view {
+
+// bounding box (bb)
+// It is used to describe the car model bounding box in 3D.
+// It assumes z = 0 and only x, y are used in the struct.
+// Of course, it is compatible to the 2d version bounding box and may be used
+// for other bounding box purpose (e.g., 2d bounding box in image).
+struct BoundingBox {
+  // (x,y) is bounding box's top left corner coordinate.
+  float x;
+  float y;
+
+  // (width, height) is the size of the bounding box.
+  float width;
+  float height;
+
+  BoundingBox() : x(0.0f), y(0.0f), width(0.0f), height(0.0f) {}
+
+  BoundingBox(float x_, float y_, float width_, float height_)
+      : x(x_), y(y_), width(width_), height(height_) {}
+
+  BoundingBox(const BoundingBox& bb_)
+      : x(bb_.x), y(bb_.y), width(bb_.width), height(bb_.height) {}
+
+  // Checks if data is valid.
+  bool IsValid() const { return width >= 0 && height >= 0; }
+
+  bool operator==(const BoundingBox& rhs) const {
+    return x == rhs.x && y == rhs.y && width == rhs.width &&
+           height == rhs.height;
+  }
+
+  BoundingBox& operator=(const BoundingBox& rhs) {
+    x = rhs.x;
+    y = rhs.y;
+    width = rhs.width;
+    height = rhs.height;
+    return *this;
+  }
+};
+
+template <typename T>
+struct Coordinate2dBase {
+  // x coordinate.
+  T x;
+
+  // y coordinate.
+  T y;
+
+  Coordinate2dBase() : x(0), y(0) {}
+
+  Coordinate2dBase(T x_, T y_) : x(x_), y(y_) {}
+
+  bool operator==(const Coordinate2dBase& rhs) const {
+    return x == rhs.x && y == rhs.y;
+  }
+
+  Coordinate2dBase& operator=(const Coordinate2dBase& rhs) {
+    x = rhs.x;
+    y = rhs.y;
+    return *this;
+  }
+};
+
+// integer type size.
+typedef Coordinate2dBase<int> Coordinate2dInteger;
+
+// float type size.
+typedef Coordinate2dBase<float> Coordinate2dFloat;
+
+struct Coordinate3dFloat {
+  // x coordinate.
+  float x;
+
+  // y coordinate.
+  float y;
+
+  // z coordinate.
+  float z;
+
+  Coordinate3dFloat() : x(0), y(0), z(0) {}
+
+  Coordinate3dFloat(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {}
+
+  bool operator==(const Coordinate3dFloat& rhs) const {
+    return x == rhs.x && y == rhs.y;
+  }
+
+  Coordinate3dFloat& operator=(const Coordinate3dFloat& rhs) {
+    x = rhs.x;
+    y = rhs.y;
+    return *this;
+  }
+};
+
+//  pixel weight used for illumination assessment
+struct PixelWeight {
+  // x and y are the coordinates (absolute value) in image space.
+  // pixel coordinate x in horizontal direction.
+  float x;
+
+  // pixel coordinate y in vertical direction.
+  float y;
+
+  // pixel weight, range in [0, 1].
+  float weight;
+
+  PixelWeight() : x(-1), y(-1), weight(0) {}
+
+  PixelWeight(int x_, int y_, int weight_) : x(x_), y(y_), weight(weight_) {}
+
+  bool operator==(const PixelWeight& rhs) const {
+    return x == rhs.x && y == rhs.y && weight == rhs.weight;
+  }
+
+  PixelWeight& operator=(const PixelWeight& rhs) {
+    x = rhs.x;
+    y = rhs.y;
+    weight = rhs.weight;
+    return *this;
+  }
+};
+
+// base size 2d type template.
+template <typename T>
+struct Size2dBase {
+  // width of size.
+  T width;
+
+  // height of size.
+  T height;
+
+  Size2dBase() : width(0), height(0) {}
+
+  Size2dBase(T width_, T height_) : width(width_), height(height_) {}
+
+  bool IsValid() const { return width > 0 && height > 0; }
+
+  bool operator==(const Size2dBase& rhs) const {
+    return width == rhs.width && height == rhs.height;
+  }
+
+  Size2dBase& operator=(const Size2dBase& rhs) {
+    width = rhs.width;
+    height = rhs.height;
+    return *this;
+  }
+};
+
+// integer type size.
+typedef Size2dBase<int> Size2dInteger;
+
+// float type size.
+typedef Size2dBase<float> Size2dFloat;
+
+//  surround view 2d parameters
+struct SurroundView2dParams {
+  // surround view 2d image resolution (width, height).
+  Size2dInteger resolution;
+
+  // the physical size of surround view 2d area in surround view coordinate.
+  // (surround view coordinate is defined as X rightward, Y forward and
+  // the origin lies on the center of the (symmetric) bowl (ground).
+  // When bowl is not used, surround view coordinate origin lies on the
+  // center of car model bounding box.)
+  // The unit should be consistent with camera extrinsics (translation).
+  Size2dFloat physical_size;
+
+  // the center of surround view 2d area in surround view coordinate
+  // (consistent with extrinsics coordinate).
+  Coordinate2dFloat physical_center;
+
+  SurroundView2dParams()
+      : resolution{0, 0},
+        physical_size{0.0f, 0.0f},
+        physical_center{0.0f, 0.0f} {}
+
+  SurroundView2dParams(Size2dInteger resolution_, Size2dFloat physical_size_,
+                       Coordinate2dFloat physical_center_)
+      : resolution(resolution_),
+        physical_size(physical_size_),
+        physical_center(physical_center_) {}
+
+  // Checks if data is valid.
+  bool IsValid() const {
+    return resolution.IsValid() && physical_size.IsValid();
+  }
+
+  bool operator==(const SurroundView2dParams& rhs) const {
+    return resolution == rhs.resolution && physical_size == rhs.physical_size &&
+           physical_center == rhs.physical_center;
+  }
+
+  SurroundView2dParams& operator=(const SurroundView2dParams& rhs) {
+    resolution = rhs.resolution;
+    physical_size = rhs.physical_size;
+    physical_center = rhs.physical_center;
+    return *this;
+  }
+};
+
+//  surround view 3d parameters
+struct SurroundView3dParams {
+  // Bowl center is the origin of the surround view coordinate. If surround view
+  // coordinate is different from the global one, a coordinate system
+  // transformation function is required.
+
+  // planar area radius.
+  // Range in (0, +Inf).
+  float plane_radius;
+
+  // the number of divisions on the plane area of bowl, in the direction
+  // of the radius.
+  // Range in [1, +Inf).
+  int plane_divisions;
+
+  // bowl curve curve height.
+  // Range in (0, +Inf).
+  float curve_height;
+
+  // the number of points on bowl curve curve along radius direction.
+  // Range in [1, +Inf).
+  int curve_divisions;
+
+  // the number of points along circle (360 degrees)
+  // Range in [1, +Inf).
+  int angular_divisions;
+
+  // the parabola coefficient of bowl curve curve.
+  // The curve formula is z = a * (x^2 + y^2) for sqrt(x^2 + y^2) >
+  // plane_radius; a is curve_coefficient.
+  // Range in (0, +Inf).
+  float curve_coefficient;
+
+  // render output image size.
+  Size2dInteger resolution;
+
+  SurroundView3dParams()
+      : plane_radius(0.0f),
+        plane_divisions(0),
+        curve_height(0.0f),
+        curve_divisions(0),
+        angular_divisions(0),
+        curve_coefficient(0.0f),
+        resolution(0, 0) {}
+
+  SurroundView3dParams(float plane_radius_, int plane_divisions_,
+                       float curve_height_, int curve_divisions_,
+                       int angular_divisions_, float curve_coefficient_,
+                       Size2dInteger resolution_)
+      : plane_radius(plane_radius_),
+        plane_divisions(plane_divisions_),
+        curve_height(curve_height_),
+        curve_divisions(curve_divisions_),
+        angular_divisions(angular_divisions_),
+        curve_coefficient(curve_coefficient_),
+        resolution(resolution_) {}
+
+  // Checks if data is valid.
+  bool IsValid() const {
+    return plane_radius > 0 && plane_divisions > 0 && curve_height > 0 &&
+           angular_divisions > 0 && curve_coefficient > 0 &&
+           curve_divisions > 0 && resolution.IsValid();
+  }
+
+  bool operator==(const SurroundView3dParams& rhs) const {
+    return plane_radius == rhs.plane_radius &&
+           plane_divisions == rhs.plane_divisions &&
+           curve_height == rhs.curve_height &&
+           curve_divisions == rhs.curve_divisions &&
+           angular_divisions == rhs.angular_divisions &&
+           curve_coefficient == rhs.curve_coefficient &&
+           resolution == rhs.resolution;
+  }
+
+  SurroundView3dParams& operator=(const SurroundView3dParams& rhs) {
+    plane_radius = rhs.plane_radius;
+    plane_divisions = rhs.plane_divisions;
+    curve_height = rhs.curve_height;
+    curve_divisions = rhs.curve_divisions;
+    angular_divisions = rhs.angular_divisions;
+    curve_coefficient = rhs.curve_coefficient;
+    resolution = rhs.resolution;
+    return *this;
+  }
+};
+
+// surround view camera parameters with native types only.
+struct SurroundViewCameraParams {
+  // All calibration data |intrinsics|, |rvec| and |tvec|
+  // follow OpenCV format excepting using native arrays, refer:
+  // https://docs.opencv.org/3.4.0/db/d58/group__calib3d__fisheye.html
+  // camera intrinsics. It is the 1d array of camera matrix(3X3) with row first.
+  float intrinsics[9];
+
+  // lens distortion parameters.
+  float distorion[4];
+
+  // rotation vector.
+  float rvec[3];
+
+  // translation vector.
+  float tvec[3];
+
+  // camera image size (width, height).
+  Size2dInteger size;
+
+  // fisheye circular fov.
+  float circular_fov;
+
+  bool operator==(const SurroundViewCameraParams& rhs) const {
+    return (0 == std::memcmp(intrinsics, rhs.intrinsics, 9 * sizeof(float))) &&
+           (0 == std::memcmp(distorion, rhs.distorion, 4 * sizeof(float))) &&
+           (0 == std::memcmp(rvec, rhs.rvec, 3 * sizeof(float))) &&
+           (0 == std::memcmp(tvec, rhs.tvec, 3 * sizeof(float))) &&
+           size == rhs.size && circular_fov == rhs.circular_fov;
+  }
+
+  SurroundViewCameraParams& operator=(const SurroundViewCameraParams& rhs) {
+    std::memcpy(intrinsics, rhs.intrinsics, 9 * sizeof(float));
+    std::memcpy(distorion, rhs.distorion, 4 * sizeof(float));
+    std::memcpy(rvec, rhs.rvec, 3 * sizeof(float));
+    std::memcpy(tvec, rhs.tvec, 3 * sizeof(float));
+    size = rhs.size;
+    circular_fov = rhs.circular_fov;
+    return *this;
+  }
+};
+
+// 3D vertex of an overlay object.
+struct OverlayVertex {
+  // Position in 3d coordinates in world space in order X,Y,Z.
+  float pos[3];
+  // RGBA values, A is used for transparency.
+  uint8_t rgba[4];
+
+  // normalized texture coordinates, in width and height direction. Range [0,
+  // 1].
+  float tex[2];
+
+  // normalized vertex normal.
+  float nor[3];
+
+  bool operator==(const OverlayVertex& rhs) const {
+    return (0 == std::memcmp(pos, rhs.pos, 3 * sizeof(float))) &&
+           (0 == std::memcmp(rgba, rhs.rgba, 4 * sizeof(uint8_t))) &&
+           (0 == std::memcmp(tex, rhs.tex, 2 * sizeof(float))) &&
+           (0 == std::memcmp(nor, rhs.nor, 3 * sizeof(float)));
+  }
+
+  OverlayVertex& operator=(const OverlayVertex& rhs) {
+    std::memcpy(pos, rhs.pos, 3 * sizeof(float));
+    std::memcpy(rgba, rhs.rgba, 4 * sizeof(uint8_t));
+    std::memcpy(tex, rhs.tex, 2 * sizeof(float));
+    std::memcpy(nor, rhs.nor, 3 * sizeof(float));
+    return *this;
+  }
+};
+
+// Overlay is a list of vertices (may be a single or multiple objects in scene)
+// coming from a single source or type of sensor.
+struct Overlay {
+  // Uniqiue Id identifying each overlay.
+  uint16_t id;
+
+  // List of overlay vertices. 3 consecutive vertices form a triangle.
+  std::vector<OverlayVertex> vertices;
+
+  // Constructor initializing all member.
+  Overlay(uint16_t id_, const std::vector<OverlayVertex>& vertices_) {
+    id = id_;
+    vertices = vertices_;
+  }
+
+  // Default constructor.
+  Overlay() {
+    id = 0;
+    vertices = std::vector<OverlayVertex>();
+  }
+};
+
+enum Format {
+  GRAY = 0,
+  RGB = 1,
+  RGBA = 2,
+};
+
+struct SurroundViewInputBufferPointers {
+  void* gpu_data_pointer;
+  void* cpu_data_pointer;
+  Format format;
+  int width;
+  int height;
+  SurroundViewInputBufferPointers()
+      : gpu_data_pointer(nullptr),
+        cpu_data_pointer(nullptr),
+        width(0),
+        height(0) {}
+  SurroundViewInputBufferPointers(void* gpu_data_pointer_,
+                                  void* cpu_data_pointer_, Format format_,
+                                  int width_, int height_)
+      : gpu_data_pointer(gpu_data_pointer_),
+        cpu_data_pointer(cpu_data_pointer_),
+        format(format_),
+        width(width_),
+        height(height_) {}
+};
+
+struct SurroundViewResultPointer {
+  void* data_pointer;
+  Format format;
+  int width;
+  int height;
+  SurroundViewResultPointer() : data_pointer(nullptr), width(0), height(0) {}
+  SurroundViewResultPointer(Format format_, int width_, int height_)
+      : format(format_), width(width_), height(height_) {
+    // default formate is gray.
+    const int byte_per_pixel = format_ == RGB ? 3 : format_ == RGBA ? 4 : 1;
+    data_pointer =
+        static_cast<void*>(new char[width * height * byte_per_pixel]);
+  }
+  ~SurroundViewResultPointer() {
+    if (data_pointer) {
+      // delete[] static_cast<char*>(data_pointer);
+      data_pointer = nullptr;
+    }
+  }
+};
+
+class SurroundView {
+ public:
+  virtual ~SurroundView() = default;
+
+  // Sets SurroundView static data.
+  // For each input, please refer to the definition.
+  virtual bool SetStaticData(
+      const std::vector<SurroundViewCameraParams>& cameras_params,
+      const SurroundView2dParams& surround_view_2d_params,
+      const SurroundView3dParams& surround_view_3d_params,
+      const std::vector<float>& undistortion_focal_length_scales,
+      const BoundingBox& car_model_bb) = 0;
+
+  // Starts 2d pipeline. Returns false if error occurs.
+  virtual bool Start2dPipeline() = 0;
+
+  // Starts 3d pipeline. Returns false if error occurs.
+  virtual bool Start3dPipeline() = 0;
+
+  // Stops 2d pipleline. It releases resource owned by the pipeline.
+  // Returns false if error occurs.
+  virtual void Stop2dPipeline() = 0;
+
+  // Stops 3d pipeline. It releases resource owned by the pipeline.
+  virtual void Stop3dPipeline() = 0;
+
+  // Updates 2d output resolution on-the-fly. Starts2dPipeline() must be called
+  // before this can be called. For quality assurance, the resolution should not
+  // be larger than the original one. This call is not thread safe and there is
+  // no sync between Get2dSurroundView() and this call.
+  virtual bool Update2dOutputResolution(const Size2dInteger& resolution) = 0;
+
+  // Updates 3d output resolution on-the-fly. Starts3dPipeline() must be called
+  // before this can be called. For quality assurance, the resolution should not
+  // be larger than the original one. This call is not thread safe and there is
+  // no sync between Get3dSurroundView() and this call.
+  virtual bool Update3dOutputResolution(const Size2dInteger& resolution) = 0;
+
+  // Projects camera's pixel location to surround view 2d image location.
+  // camera_point is the pixel location in raw camera's space.
+  // camera_index is the camera's index.
+  // surround_view_2d_point is the surround view 2d image pixel location.
+  virtual bool GetProjectionPointFromRawCameraToSurroundView2d(
+      const Coordinate2dInteger& camera_point, int camera_index,
+      Coordinate2dFloat* surround_view_2d_point) = 0;
+
+  // Projects camera's pixel location to surround view 3d bowl coordinate.
+  // camera_point is the pixel location in raw camera's space.
+  // camera_index is the camera's index.
+  // surround_view_3d_point is the surround view 3d vertex.
+  virtual bool GetProjectionPointFromRawCameraToSurroundView3d(
+      const Coordinate2dInteger& camera_point, int camera_index,
+      Coordinate3dFloat* surround_view_3d_point) = 0;
+
+  // Gets 2d surround view image.
+  // It takes input_pointers as input, and output is result_pointer.
+  // Please refer to the definition of SurroundViewInputBufferPointers and
+  // SurroundViewResultPointer.
+  virtual bool Get2dSurroundView(
+      const std::vector<SurroundViewInputBufferPointers>& input_pointers,
+      SurroundViewResultPointer* result_pointer) = 0;
+
+  // Gets 3d surround view image.
+  // It takes input_pointers and view_matrix as input, and output is
+  // result_pointer. view_matrix is 4 x 4 matrix.
+  // Please refer to the definition of
+  // SurroundViewInputBufferPointers and
+  // SurroundViewResultPointer.
+  virtual bool Get3dSurroundView(
+      const std::vector<SurroundViewInputBufferPointers>& input_pointers,
+      const std::vector<std::vector<float>> view_matrix,
+      SurroundViewResultPointer* result_pointer) = 0;
+
+  // Sets 3d overlays.
+  virtual bool Set3dOverlay(const std::vector<Overlay>& overlays) = 0;
+
+  // for test only.
+  // TODO(xxqian): remove thest two fns.
+  virtual std::vector<SurroundViewInputBufferPointers> ReadImages(
+      const char* filename0, const char* filename1, const char* filename2,
+      const char* filename3) = 0;
+
+  virtual void WriteImage(const SurroundViewResultPointer result_pointerer,
+                          const char* filename) = 0;
+};
+
+SurroundView* Create();
+
+}  // namespace surround_view
+}  // namespace android_auto
+
+#endif  // WIRELESS_ANDROID_AUTOMOTIVE_CAML_SURROUND_VIEW_CORE_LIB_H_
diff --git a/surround_view/service-impl/lib/arm64/libcore_lib_shared.so b/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
new file mode 100644
index 0000000..0175c16
--- /dev/null
+++ b/surround_view/service-impl/lib/arm64/libcore_lib_shared.so
Binary files differ
diff --git a/surround_view/service-impl/lib/x86-64/libcore_lib.so b/surround_view/service-impl/lib/x86-64/libcore_lib.so
new file mode 100755
index 0000000..96479c6
--- /dev/null
+++ b/surround_view/service-impl/lib/x86-64/libcore_lib.so
Binary files differ
diff --git a/surround_view/service-impl/lib/x86/libcore_lib.so b/surround_view/service-impl/lib/x86/libcore_lib.so
new file mode 100755
index 0000000..96479c6
--- /dev/null
+++ b/surround_view/service-impl/lib/x86/libcore_lib.so
Binary files differ
diff --git a/surround_view/service-impl/manifest_android.hardware.automotive.sv@1.0.xml b/surround_view/service-impl/manifest_android.hardware.automotive.sv@1.0.xml
new file mode 100644
index 0000000..f9e4548
--- /dev/null
+++ b/surround_view/service-impl/manifest_android.hardware.automotive.sv@1.0.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright 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.
+-->
+<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/surround_view/service-impl/service.cpp b/surround_view/service-impl/service.cpp
new file mode 100644
index 0000000..a7ce6f3
--- /dev/null
+++ b/surround_view/service-impl/service.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 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 "SurroundViewService"
+
+#include <android-base/logging.h>
+#include <android/hardware/automotive/sv/1.0/ISurroundViewStream.h>
+#include <android/hardware_buffer.h>
+#include <hidl/HidlTransportSupport.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() {
+    LOG(INFO) << "ISurroundViewService default implementation is starting";
+    android::sp<ISurroundViewService> service = SurroundViewService::getInstance();
+
+    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();
+
+    if (status != android::OK) {
+        LOG(ERROR) << "Could not register default Surround View Service. Status: "
+                   << status;
+    }
+
+    joinRpcThreadpool();
+
+    // In normal operation, we don't expect the thread pool to exit
+    LOG(ERROR) << "Surround View Service is shutting down";
+    return 1;
+}
diff --git a/surround_view/service-impl/sv_3d_params.h b/surround_view/service-impl/sv_3d_params.h
new file mode 100644
index 0000000..b0df5fa
--- /dev/null
+++ b/surround_view/service-impl/sv_3d_params.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef SV_3D_PARAMS_H
+#define SV_3D_PARAMS_H
+
+#include <vector>
+#include <hidl/HidlSupport.h>
+
+using ::android::hardware::hidl_vec;
+
+static std::vector<android::hardware::hidl_vec<float>> kRecViews = {
+    {0, -0.747409, 0.664364, 0, 1, 0, -0, 0, -0, 0.664364, 0.747409, 0, -0, 1.32873, -4.52598, 1},
+    {-0.382683, -0.690516, 0.613792, 0, 0.92388, -0.286021, 0.254241, 0, 0, 0.664364, 0.747409, 0, -0, 1.32873, -4.52598, 1},
+    {-0.707107, -0.528498, 0.469776, 0, 0.707107, -0.528498, 0.469776, 0, 0, 0.664364, 0.747409, 0, -0, 1.32873, -4.52598, 1},
+    {-0.92388, -0.286021, 0.254241, 0, 0.382683, -0.690516, 0.613792, 0, 0, 0.664364, 0.747409, 0, -1.19209e-07, 1.32873, -4.52598, 1},
+    {-1, 3.26703e-08, -2.90403e-08, 0, -4.37114e-08, -0.747409, 0.664364, 0, 0, 0.664364, 0.747409, 0, -0, 1.32873, -4.52598, 1},
+    {-0.92388, 0.286021, -0.254241, 0, -0.382683, -0.690516, 0.613792, 0, 0, 0.664364, 0.747409, 0, -0, 1.32873, -4.52598, 1},
+    {-0.707107, 0.528498, -0.469776, 0, -0.707107, -0.528498, 0.469776, 0, 0, 0.664364, 0.747409, 0, -0, 1.32873, -4.52598, 1},
+    {-0.382683, 0.690516, -0.613792, 0, -0.92388, -0.286021, 0.254241, 0, 0, 0.664364, 0.747409, 0, 1.19209e-07, 1.32873, -4.52598, 1},
+    {8.74228e-08, 0.747409, -0.664364, 0, -1, 6.53406e-08, -5.80805e-08, 0, 0, 0.664364, 0.747409, 0, -0, 1.32873, -4.52598, 1},
+    {0.382683, 0.690516, -0.613792, 0, -0.92388, 0.286021, -0.254241, 0, 0, 0.664364, 0.747409, 0, 1.19209e-07, 1.32873, -4.52598, 1},
+    {0.707107, 0.528498, -0.469776, 0, -0.707107, 0.528498, -0.469776, 0, 0, 0.664364, 0.747409, 0, 1.19209e-07, 1.32873, -4.52598, 1},
+    {0.92388, 0.286021, -0.254241, 0, -0.382684, 0.690516, -0.613792, 0, 0, 0.664364, 0.747409, 0, 1.19209e-07, 1.32873, -4.52598, 1},
+    {1, -8.91277e-09, 7.92246e-09, 0, 1.19249e-08, 0.747409, -0.664364, 0, -0, 0.664364, 0.747409, 0, 3.55271e-15, 1.32873, -4.52598, 1},
+    {0.92388, -0.286021, 0.254241, 0, 0.382684, 0.690516, -0.613792, 0, -0, 0.664364, 0.747409, 0, -0, 1.32873, -4.52598, 1},
+    {0.707107, -0.528498, 0.469776, 0, 0.707107, 0.528498, -0.469776, 0, -0, 0.664364, 0.747409, 0, -1.19209e-07, 1.32873, -4.52598, 1},
+    {0.382683, -0.690516, 0.613792, 0, 0.92388, 0.286021, -0.254241, 0, -0, 0.664364, 0.747409, 0, -1.19209e-07, 1.32873, -4.52598, 1},
+};
+
+#endif // SV_3D_PARAMS_H
+
diff --git a/surround_view/service-impl/test_data/0.png b/surround_view/service-impl/test_data/0.png
new file mode 100644
index 0000000..283751b
--- /dev/null
+++ b/surround_view/service-impl/test_data/0.png
Binary files differ
diff --git a/surround_view/service-impl/test_data/1.png b/surround_view/service-impl/test_data/1.png
new file mode 100644
index 0000000..55abd66
--- /dev/null
+++ b/surround_view/service-impl/test_data/1.png
Binary files differ
diff --git a/surround_view/service-impl/test_data/2.png b/surround_view/service-impl/test_data/2.png
new file mode 100644
index 0000000..c66dd61
--- /dev/null
+++ b/surround_view/service-impl/test_data/2.png
Binary files differ
diff --git a/surround_view/service-impl/test_data/3.png b/surround_view/service-impl/test_data/3.png
new file mode 100644
index 0000000..f9d2c60
--- /dev/null
+++ b/surround_view/service-impl/test_data/3.png
Binary files differ