Add pipe interface to DefaultVehicleHal

- Create base communications interface
- Refactor socket calls to use SocketComm class

Test: Use python scripts and custom emulator to test communications

Change-Id: Ia401587223035e748991516a2285cc31cb71a9c9
diff --git a/automotive/vehicle/2.0/default/Android.mk b/automotive/vehicle/2.0/default/Android.mk
index 324be51..c592165 100644
--- a/automotive/vehicle/2.0/default/Android.mk
+++ b/automotive/vehicle/2.0/default/Android.mk
@@ -76,6 +76,8 @@
 LOCAL_MODULE:= $(vhal_v2_0)-default-impl-lib
 LOCAL_SRC_FILES:= \
     impl/vhal_v2_0/DefaultVehicleHal.cpp \
+    impl/vhal_v2_0/PipeComm.cpp \
+    impl/vhal_v2_0/SocketComm.cpp
 
 LOCAL_C_INCLUDES := \
     $(LOCAL_PATH)/impl/vhal_v2_0
@@ -87,6 +89,7 @@
     $(vhal_v2_0)-manager-lib \
 
 LOCAL_SHARED_LIBRARIES := \
+    libbase \
     libbinder \
     libhidlbase \
     libhidltransport \
@@ -99,6 +102,8 @@
 LOCAL_STATIC_LIBRARIES := \
     $(vhal_v2_0)-libproto-native \
 
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+
 include $(BUILD_STATIC_LIBRARY)
 
 
@@ -148,6 +153,7 @@
     VehicleService.cpp
 
 LOCAL_SHARED_LIBRARIES := \
+    libbase \
     libbinder \
     libhidlbase \
     libhidltransport \
@@ -162,4 +168,6 @@
     $(vhal_v2_0)-default-impl-lib \
     $(vhal_v2_0)-libproto-native \
 
+LOCAL_CFLAGS += -Wall -Wextra -Werror
+
 include $(BUILD_EXECUTABLE)
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommBase.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommBase.h
new file mode 100644
index 0000000..6832ad3
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommBase.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 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 android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_
+
+#include <string>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+/**
+ * This is the communications base class.  It defines the interface used in DefaultVehicleHal to
+ * send and receive data to and from the emulator.
+ */
+class CommBase {
+public:
+    virtual ~CommBase() = default;
+
+    /**
+     * Closes a connection if it is open.
+     */
+    virtual void stop() {}
+
+    /**
+     * Creates a connection to the other side.
+     *
+     * @return int Returns fd or socket number if connection is successful.
+     *              Otherwise, returns -1 if no connection is availble.
+     */
+    virtual int connect() { return 0; }
+
+    /**
+     * Opens the communications channel.
+     *
+     * @return int Returns 0 if channel is opened, else -errno if failed.
+     */
+    virtual int open() = 0;
+
+    /**
+     * Blocking call to read data from the connection.
+     *
+     * @return std::vector<uint8_t> Serialized protobuf data received from emulator.  This will be
+     *              an empty vector if the connection was closed or some other error occurred.
+     */
+    virtual std::vector<uint8_t> read() = 0;
+
+    /**
+     * Transmits a string of data to the emulator.
+     *
+     * @param data Serialized protobuf data to transmit.
+     *
+     * @return int Number of bytes transmitted, or -1 if failed.
+     */
+    virtual int write(const std::vector<uint8_t>& data) = 0;
+};
+
+}  // impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+
+#endif  // android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
index d3d77b6..fca56c7 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
@@ -18,14 +18,14 @@
 #include <android/log.h>
 
 #include <algorithm>
-#include <netinet/in.h>
-#include <sys/socket.h>
+#include <android-base/properties.h>
+#include <cstdio>
 
 #include "DefaultVehicleHal.h"
+#include "PipeComm.h"
+#include "SocketComm.h"
 #include "VehicleHalProto.pb.h"
 
-#define DEBUG_SOCKET    (33452)
-
 namespace android {
 namespace hardware {
 namespace automotive {
@@ -293,34 +293,35 @@
 void DefaultVehicleHal::parseRxProtoBuf(std::vector<uint8_t>& msg) {
     emulator::EmulatorMessage rxMsg;
     emulator::EmulatorMessage respMsg;
-    std::string str(reinterpret_cast<const char*>(msg.data()), msg.size());
 
-    rxMsg.ParseFromString(str);
+    if (rxMsg.ParseFromArray(msg.data(), msg.size())) {
+        switch (rxMsg.msg_type()) {
+        case emulator::GET_CONFIG_CMD:
+            doGetConfig(rxMsg, respMsg);
+            break;
+        case emulator::GET_CONFIG_ALL_CMD:
+            doGetConfigAll(rxMsg, respMsg);
+            break;
+        case emulator::GET_PROPERTY_CMD:
+            doGetProperty(rxMsg, respMsg);
+            break;
+        case emulator::GET_PROPERTY_ALL_CMD:
+            doGetPropertyAll(rxMsg, respMsg);
+            break;
+        case emulator::SET_PROPERTY_CMD:
+            doSetProperty(rxMsg, respMsg);
+            break;
+        default:
+            ALOGW("%s: Unknown message received, type = %d", __FUNCTION__, rxMsg.msg_type());
+            respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD);
+            break;
+        }
 
-    switch (rxMsg.msg_type()) {
-    case emulator::GET_CONFIG_CMD:
-        doGetConfig(rxMsg, respMsg);
-        break;
-    case emulator::GET_CONFIG_ALL_CMD:
-        doGetConfigAll(rxMsg, respMsg);
-        break;
-    case emulator::GET_PROPERTY_CMD:
-        doGetProperty(rxMsg, respMsg);
-        break;
-    case emulator::GET_PROPERTY_ALL_CMD:
-        doGetPropertyAll(rxMsg, respMsg);
-        break;
-    case emulator::SET_PROPERTY_CMD:
-        doSetProperty(rxMsg, respMsg);
-        break;
-    default:
-        ALOGW("%s: Unknown message received, type = %d", __FUNCTION__, rxMsg.msg_type());
-        respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD);
-        break;
+        // Send the reply
+        txMsg(respMsg);
+    } else {
+        ALOGE("%s: ParseFromString() failed. msgSize=%d", __FUNCTION__, static_cast<int>(msg.size()));
     }
-
-    // Send the reply
-    txMsg(respMsg);
 }
 
 // Copies internal VehiclePropConfig data structure to protobuf VehiclePropConfig
@@ -415,94 +416,50 @@
     }
 }
 
-void DefaultVehicleHal::rxMsg(void) {
+void DefaultVehicleHal::rxMsg() {
     int  numBytes = 0;
-    int32_t msgSize;
-    do {
-        // This is a variable length message.
-        // Read the number of bytes to rx over the socket
-        numBytes = read(mCurSocket, &msgSize, sizeof(msgSize));
 
-        if (numBytes != sizeof(msgSize)) {
-            // This happens when connection is closed
-            ALOGD("%s: numBytes=%d, expected=4", __FUNCTION__, numBytes);
-            break;
-        }
+    while (mExit == 0) {
+        std::vector<uint8_t> msg = mComm->read();
 
-        std::vector<uint8_t> msg = std::vector<uint8_t>(msgSize);
-
-        numBytes = read(mCurSocket, msg.data(), msgSize);
-
-        if ((numBytes == msgSize) && (msgSize > 0)) {
+        if (msg.size() > 0) {
             // Received a message.
             parseRxProtoBuf(msg);
         } else {
             // This happens when connection is closed
-            ALOGD("%s: numBytes=%d, msgSize=%d", __FUNCTION__, numBytes, msgSize);
+            ALOGD("%s: numBytes=%d, msgSize=%d", __FUNCTION__, numBytes,
+                  static_cast<int32_t>(msg.size()));
             break;
         }
-    } while (mExit == 0);
+    }
 }
 
-void DefaultVehicleHal::rxThread(void) {
-    // Initialize the socket
-    {
-        int retVal;
-        struct sockaddr_in servAddr;
+void DefaultVehicleHal::rxThread() {
+    bool isEmulator = android::base::GetBoolProperty("ro.kernel.qemu", false);
 
-        mSocket = socket(AF_INET, SOCK_STREAM, 0);
-        if (mSocket < 0) {
-            ALOGE("%s: socket() failed, mSocket=%d, errno=%d", __FUNCTION__, mSocket, errno);
-            mSocket = -1;
-            return;
-        }
-
-        bzero(&servAddr, sizeof(servAddr));
-        servAddr.sin_family = AF_INET;
-        servAddr.sin_addr.s_addr = INADDR_ANY;
-        servAddr.sin_port = htons(DEBUG_SOCKET);
-
-        retVal = bind(mSocket, reinterpret_cast<struct sockaddr*>(&servAddr), sizeof(servAddr));
-        if(retVal < 0) {
-            ALOGE("%s: Error on binding: retVal=%d, errno=%d", __FUNCTION__, retVal, errno);
-            close(mSocket);
-            mSocket = -1;
-            return;
-        }
-
-        listen(mSocket, 1);
-
-        // Set the socket to be non-blocking so we can poll it continouously
-        fcntl(mSocket, F_SETFL, O_NONBLOCK);
+    if (isEmulator) {
+        // Initialize pipe to Emulator
+        mComm.reset(new PipeComm);
+    } else {
+        // Initialize socket over ADB
+        mComm.reset(new SocketComm);
     }
 
-    while (mExit == 0) {
-        struct sockaddr_in cliAddr;
-        socklen_t cliLen = sizeof(cliAddr);
-        int cSocket = accept(mSocket, reinterpret_cast<struct sockaddr*>(&cliAddr), &cliLen);
+    int retVal = mComm->open();
 
-        if (cSocket >= 0) {
-            {
-                std::lock_guard<std::mutex> lock(mTxMutex);
-                mCurSocket = cSocket;
+    if (retVal == 0) {
+        // Comms are properly opened
+        while (mExit == 0) {
+            retVal = mComm->connect();
+
+            if (retVal >= 0) {
+                rxMsg();
             }
-            ALOGD("%s: Incoming connection received on socket %d", __FUNCTION__, cSocket);
-            rxMsg();
-            ALOGD("%s: Connection terminated on socket %d", __FUNCTION__, cSocket);
-            {
-                std::lock_guard<std::mutex> lock(mTxMutex);
-                mCurSocket = -1;
-            }
+
+            // Check every 100ms for a new connection
+            std::this_thread::sleep_for(std::chrono::milliseconds(100));
         }
-
-        // TODO:  Use a blocking socket?
-        // Check every 100ms for a new socket connection
-        std::this_thread::sleep_for(std::chrono::milliseconds(100));
     }
-
-    // Shutdown the socket
-    close(mSocket);
-    mSocket = -1;
 }
 
 // This function sets the default value of a property if we are interested in setting it.
@@ -569,21 +526,15 @@
 
 // Transmit a reply back to the emulator
 void DefaultVehicleHal::txMsg(emulator::EmulatorMessage& txMsg) {
-    std::string msgString;
+    int numBytes = txMsg.ByteSize();
+    std::vector<uint8_t> msg(numBytes);
 
-    if (txMsg.SerializeToString(&msgString)) {
-        int32_t msgLen = msgString.length();
+    if (txMsg.SerializeToArray(msg.data(), msg.size())) {
         int retVal = 0;
 
-        // TODO:  Prepend the message length to the string without a copy
-        msgString.insert(0, reinterpret_cast<char*>(&msgLen), 4);
-
         // Send the message
-        {
-            std::lock_guard<std::mutex> lock(mTxMutex);
-            if (mCurSocket != -1) {
-                retVal = write(mCurSocket, msgString.data(), msgString.size());
-            }
+        if (mExit == 0) {
+            mComm->write(msg);
         }
 
         if (retVal < 0) {
@@ -683,9 +634,7 @@
 // Parse supported properties list and generate vector of property values to hold current values.
 void DefaultVehicleHal::onCreate() {
     // Initialize member variables
-    mCurSocket = -1;
     mExit = 0;
-    mSocket = -1;
 
     // Get the list of configurations supported by this HAL
     std::vector<VehiclePropConfig> configs = listProperties();
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
index 51f7ba3..2df9514 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
@@ -23,6 +23,9 @@
 
 #include <utils/SystemClock.h>
 
+#include "CommBase.h"
+#include "VehicleHalProto.pb.h"
+
 #include <vhal_v2_0/VehicleHal.h>
 #include <vhal_v2_0/Obd2SensorStore.h>
 
@@ -45,13 +48,7 @@
         mExit = 1;
 
         // Close emulator socket if it is open
-        {
-            std::lock_guard<std::mutex> lock(mTxMutex);
-            if (mCurSocket != -1) {
-                close(mCurSocket);
-                mCurSocket = -1;
-            }
-        }
+        mComm->stop();
 
         mThread.join();
     }
@@ -94,8 +91,8 @@
     void populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
                                        const VehiclePropValue* val);
     void setDefaultValue(VehiclePropValue* prop);
-    void rxMsg(void);
-    void rxThread(void);
+    void rxMsg();
+    void rxThread();
     void txMsg(emulator::EmulatorMessage& txMsg);
     StatusCode updateProperty(const VehiclePropValue& propValue);
     StatusCode fillObd2LiveFrame(VehiclePropValue* v);
@@ -106,14 +103,12 @@
 private:
     // TODO:  Use a hashtable to support indexing props
     std::vector<std::unique_ptr<VehiclePropValue>> mProps;
-    std::atomic<int> mCurSocket;
     std::atomic<int> mExit;
     std::unique_ptr<VehiclePropValue> mLiveObd2Frame {nullptr};
     std::vector<std::unique_ptr<VehiclePropValue>> mFreezeObd2Frames;
     std::mutex mPropsMutex;
-    int mSocket;
-    std::mutex mTxMutex;
     std::thread mThread;
+    std::unique_ptr<CommBase> mComm{nullptr};
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp
new file mode 100644
index 0000000..6f219fa
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 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 "PipeComm"
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <android/log.h>
+#include <system/qemu_pipe.h>
+
+#include "PipeComm.h"
+
+#define CAR_SERVICE_NAME "pipe:qemud:car"
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+PipeComm::PipeComm() {
+    // Initialize member vars
+    mPipeFd = -1;
+}
+
+
+int PipeComm::open() {
+    int fd = qemu_pipe_open(CAR_SERVICE_NAME);
+
+    if (fd < 0) {
+        ALOGE("%s: Could not open connection to service: %s %d", __FUNCTION__, strerror(errno), fd);
+        return -errno;
+    }
+
+    ALOGI("%s: OPENED PIPE, fd=%d", __FUNCTION__, fd);
+    mPipeFd = fd;
+    return 0;
+}
+
+std::vector<uint8_t> PipeComm::read() {
+    static constexpr int MAX_RX_MSG_SZ = 2048;
+    std::vector<uint8_t> msg = std::vector<uint8_t>(MAX_RX_MSG_SZ);
+    int numBytes;
+
+    numBytes = qemu_pipe_frame_recv(mPipeFd, msg.data(), msg.size());
+
+    if (numBytes == MAX_RX_MSG_SZ) {
+        ALOGE("%s:  Received max size = %d", __FUNCTION__, MAX_RX_MSG_SZ);
+    } else if (numBytes > 0) {
+        msg.resize(numBytes);
+        return msg;
+    } else {
+        ALOGD("%s: Connection terminated on pipe %d, numBytes=%d", __FUNCTION__, mPipeFd, numBytes);
+        {
+            std::lock_guard<std::mutex> lock(mMutex);
+            mPipeFd = -1;
+        }
+    }
+
+    return std::vector<uint8_t>();
+}
+
+int PipeComm::write(const std::vector<uint8_t>& data) {
+    int retVal = 0;
+
+    {
+        std::lock_guard<std::mutex> lock(mMutex);
+        if (mPipeFd != -1) {
+            retVal = qemu_pipe_frame_send(mPipeFd, data.data(), data.size());
+        }
+    }
+
+    if (retVal < 0) {
+        retVal = -errno;
+        ALOGE("%s:  send_cmd: (fd=%d): ERROR: %s", __FUNCTION__, mPipeFd, strerror(errno));
+    }
+
+    return retVal;
+}
+
+
+}  // impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+
+
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.h
new file mode 100644
index 0000000..bcd32d0
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 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 android_hardware_automotive_vehicle_V2_0_impl_PipeComm_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_PipeComm_H_
+
+#include <mutex>
+#include <vector>
+#include "CommBase.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+/**
+ * PipeComm uses a qemu pipe interface to connect to the Goldfish Emulator.
+ */
+class PipeComm : public CommBase {
+public:
+    PipeComm();
+
+    /**
+     * Opens a pipe and begins listening.
+     *
+     * @return int Returns 0 on success.
+     */
+    int open() override;
+
+    /**
+     * Blocking call to read data from the connection.
+     *
+     * @return std::vector<uint8_t> Serialized protobuf data received from emulator.  This will be
+     *              an empty vector if the connection was closed or some other error occurred.
+     */
+    std::vector<uint8_t> read() override;
+
+    /**
+     * Transmits a string of data to the emulator.
+     *
+     * @param data Serialized protobuf data to transmit.
+     *
+     * @return int Number of bytes transmitted, or -1 if failed.
+     */
+    int write(const std::vector<uint8_t>& data) override;
+
+private:
+    std::mutex mMutex;
+    int mPipeFd;
+};
+
+}  // impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+
+#endif  // android_hardware_automotive_vehicle_V2_0_impl_PipeComm_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
new file mode 100644
index 0000000..a3ef4b1
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2017 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 "SocketComm"
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <android/log.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include "SocketComm.h"
+
+// Socket to use when communicating with Host PC
+static constexpr int DEBUG_SOCKET = 33452;
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+SocketComm::SocketComm() {
+    // Initialize member vars
+    mCurSockFd = -1;
+    mExit      =  0;
+    mSockFd    = -1;
+}
+
+
+SocketComm::~SocketComm() {
+    stop();
+}
+
+int SocketComm::connect() {
+    sockaddr_in cliAddr;
+    socklen_t cliLen = sizeof(cliAddr);
+    int cSockFd = accept(mSockFd, reinterpret_cast<struct sockaddr*>(&cliAddr), &cliLen);
+
+    if (cSockFd >= 0) {
+        {
+            std::lock_guard<std::mutex> lock(mMutex);
+            mCurSockFd = cSockFd;
+        }
+        ALOGD("%s: Incoming connection received on socket %d", __FUNCTION__, cSockFd);
+    } else {
+        cSockFd = -1;
+    }
+
+    return cSockFd;
+}
+
+int SocketComm::open() {
+    int retVal;
+    struct sockaddr_in servAddr;
+
+    mSockFd = socket(AF_INET, SOCK_STREAM, 0);
+    if (mSockFd < 0) {
+        ALOGE("%s: socket() failed, mSockFd=%d, errno=%d", __FUNCTION__, mSockFd, errno);
+        mSockFd = -1;
+        return -errno;
+    }
+
+    memset(&servAddr, 0, sizeof(servAddr));
+    servAddr.sin_family = AF_INET;
+    servAddr.sin_addr.s_addr = INADDR_ANY;
+    servAddr.sin_port = htons(DEBUG_SOCKET);
+
+    retVal = bind(mSockFd, reinterpret_cast<struct sockaddr*>(&servAddr), sizeof(servAddr));
+    if(retVal < 0) {
+        ALOGE("%s: Error on binding: retVal=%d, errno=%d", __FUNCTION__, retVal, errno);
+        close(mSockFd);
+        mSockFd = -1;
+        return -errno;
+    }
+
+    listen(mSockFd, 1);
+
+    // Set the socket to be non-blocking so we can poll it continouously
+    fcntl(mSockFd, F_SETFL, O_NONBLOCK);
+
+    return 0;
+}
+
+std::vector<uint8_t> SocketComm::read() {
+    int32_t msgSize;
+    int numBytes = 0;
+
+    // This is a variable length message.
+    // Read the number of bytes to rx over the socket
+    numBytes = ::read(mCurSockFd, &msgSize, sizeof(msgSize));
+    msgSize = ntohl(msgSize);
+
+    if (numBytes != sizeof(msgSize)) {
+        // This happens when connection is closed
+        ALOGD("%s: numBytes=%d, expected=4", __FUNCTION__, numBytes);
+        ALOGD("%s: Connection terminated on socket %d", __FUNCTION__, mCurSockFd);
+        {
+            std::lock_guard<std::mutex> lock(mMutex);
+            mCurSockFd = -1;
+        }
+
+        return std::vector<uint8_t>();
+    }
+
+    std::vector<uint8_t> msg = std::vector<uint8_t>(msgSize);
+
+    numBytes = ::read(mCurSockFd, msg.data(), msgSize);
+
+    if ((numBytes == msgSize) && (msgSize > 0)) {
+        // Received a message.
+        return msg;
+    } else {
+        // This happens when connection is closed
+        ALOGD("%s: numBytes=%d, msgSize=%d", __FUNCTION__, numBytes, msgSize);
+        ALOGD("%s: Connection terminated on socket %d", __FUNCTION__, mCurSockFd);
+        {
+            std::lock_guard<std::mutex> lock(mMutex);
+            mCurSockFd = -1;
+        }
+
+        return std::vector<uint8_t>();
+    }
+}
+
+void SocketComm::stop() {
+    if (mExit == 0) {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mExit = 1;
+
+        // Close emulator socket if it is open
+        if (mCurSockFd != -1) {
+            close(mCurSockFd);
+            mCurSockFd = -1;
+        }
+
+        if (mSockFd != -1) {
+            close(mSockFd);
+            mSockFd = -1;
+        }
+    }
+}
+
+int SocketComm::write(const std::vector<uint8_t>& data) {
+    static constexpr int MSG_HEADER_LEN = 4;
+    int retVal = 0;
+    union {
+        uint32_t msgLen;
+        uint8_t msgLenBytes[MSG_HEADER_LEN];
+    };
+
+    // Prepare header for the message
+    msgLen = static_cast<uint32_t>(data.size());
+    msgLen = htonl(msgLen);
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (mCurSockFd != -1) {
+        retVal = ::write(mCurSockFd, msgLenBytes, MSG_HEADER_LEN);
+
+        if (retVal == MSG_HEADER_LEN) {
+            retVal = ::write(mCurSockFd, data.data(), data.size());
+        }
+    }
+
+    return retVal;
+}
+
+
+}  // impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h
new file mode 100644
index 0000000..12cfb29
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 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 android_hardware_automotive_vehicle_V2_0_impl_SocketComm_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_SocketComm_H_
+
+#include <mutex>
+#include <vector>
+#include "CommBase.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+/**
+ * SocketComm opens a socket via adb's TCP port forwarding to enable a Host PC to connect to
+ * the VehicleHAL.
+ */
+class SocketComm : public CommBase {
+public:
+    SocketComm();
+    virtual ~SocketComm();
+
+    /**
+     * Creates a connection to the other side.
+     *
+     * @return int Returns fd or socket number if connection is successful.
+     *              Otherwise, returns -1 if no connection is availble.
+     */
+    int connect() override;
+
+    /**
+     * Opens a socket and begins listening.
+     *
+     * @return int Returns 0 on success.
+     */
+    int open() override;
+
+    /**
+     * Blocking call to read data from the connection.
+     *
+     * @return std::vector<uint8_t> Serialized protobuf data received from emulator.  This will be
+     *              an empty vector if the connection was closed or some other error occurred.
+     */
+    std::vector<uint8_t> read() override;
+
+    /**
+     * Closes a connection if it is open.
+     */
+    void stop() override;
+
+    /**
+     * Transmits a string of data to the emulator.
+     *
+     * @param data Serialized protobuf data to transmit.
+     *
+     * @return int Number of bytes transmitted, or -1 if failed.
+     */
+    int write(const std::vector<uint8_t>& data) override;
+
+private:
+    int mCurSockFd;
+    std::atomic<int> mExit;
+    std::mutex mMutex;
+    int mSockFd;
+};
+
+}  // impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+
+#endif  // android_hardware_automotive_vehicle_V2_0_impl_SocketComm_H_