Merge "Enable vehicle HAL to be controlled via ADB"
diff --git a/automotive/vehicle/2.0/default/Android.mk b/automotive/vehicle/2.0/default/Android.mk
index a346507..e822044 100644
--- a/automotive/vehicle/2.0/default/Android.mk
+++ b/automotive/vehicle/2.0/default/Android.mk
@@ -41,6 +41,28 @@
 include $(BUILD_STATIC_LIBRARY)
 
 ###############################################################################
+# Vehicle HAL Protobuf library
+###############################################################################
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-proto-files-under, impl/proto)
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+
+LOCAL_MODULE := $(module_prefix)-libproto-native
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STRIP_MODULE := keep_symbols
+
+generated_sources_dir := $(call local-generated-sources-dir)
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+    $(generated_sources_dir)/proto/$(LOCAL_PATH)/impl/proto
+
+include $(BUILD_STATIC_LIBRARY)
+
+
+###############################################################################
 # Vehicle default VehicleHAL implementation
 ###############################################################################
 include $(CLEAR_VARS)
@@ -55,9 +77,13 @@
     libhidltransport \
     libhwbinder \
     liblog \
+    libprotobuf-cpp-lite \
     libutils \
     $(module_prefix) \
 
+LOCAL_STATIC_LIBRARIES := \
+    $(module_prefix)-libproto-native
+
 include $(BUILD_STATIC_LIBRARY)
 
 
@@ -114,7 +140,11 @@
     libhidltransport \
     libhwbinder \
     liblog \
+    libprotobuf-cpp-lite \
     libutils \
     $(module_prefix) \
 
+LOCAL_STATIC_LIBRARIES := \
+    $(module_prefix)-libproto-native
+
 include $(BUILD_EXECUTABLE)
diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
index 344a984..1ee4d47 100644
--- a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
+++ b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
@@ -1,4 +1,4 @@
 service vehicle-hal-2.0 /system/bin/hw/android.hardware.automotive.vehicle@2.0-service
     class hal
     user vehicle_network
-    group system
+    group system inet
diff --git a/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.cpp
index 1c26759..88717a9 100644
--- a/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.cpp
@@ -14,12 +14,17 @@
  * limitations under the License.
  */
 
-#include "DefaultVehicleHal.h"
+#define LOG_TAG "DefaultVehicleHal"
 
 #include <algorithm>
-
-#define LOG_TAG "default_vehicle"
 #include <android/log.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include "DefaultVehicleHal.h"
+#include "VehicleHalProto.pb.h"
+
+#define DEBUG_SOCKET    (33452)
 
 namespace android {
 namespace hardware {
@@ -29,144 +34,157 @@
 
 namespace impl {
 
-VehicleHal::VehiclePropValuePtr DefaultVehicleHal::get(
-        const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
-    *outStatus = StatusCode::OK;
+void DefaultVehicleHal::doGetConfig(emulator::EmulatorMessage& rxMsg,
+                                    emulator::EmulatorMessage& respMsg) {
+    std::vector<VehiclePropConfig> configs = listProperties();
+    emulator::VehiclePropGet getProp = rxMsg.prop(0);
 
-    VehiclePropValuePtr v;
-    auto property = static_cast<VehicleProperty>(requestedPropValue.prop);
-    int32_t areaId = requestedPropValue.areaId;
-    auto& pool = *getValuePool();
+    respMsg.set_msg_type(emulator::GET_CONFIG_RESP);
+    respMsg.set_status(emulator::ERROR_INVALID_PROPERTY);
 
-    switch (property) {
-        case VehicleProperty::INFO_MAKE:
-            v = pool.obtainString("Default Car");
+    for (auto& config : configs) {
+        // Find the config we are looking for
+        if (config.prop == getProp.prop()) {
+            emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
+            populateProtoVehicleConfig(protoCfg, config);
+            respMsg.set_status(emulator::RESULT_OK);
             break;
-        case VehicleProperty::HVAC_FAN_SPEED:
-            v = pool.obtainInt32(mFanSpeed);
-            break;
-        case VehicleProperty::HVAC_POWER_ON:
-            v = pool.obtainBoolean(mHvacPowerOn);
-            break;
-        case VehicleProperty::HVAC_RECIRC_ON:
-            v = pool.obtainBoolean(mHvacRecircOn);
-            break;
-        case VehicleProperty::HVAC_AC_ON:
-            v = pool.obtainBoolean(mHvacAcOn);
-            break;
-        case VehicleProperty::HVAC_AUTO_ON:
-            v = pool.obtainBoolean(mHvacAutoOn);
-            break;
-        case VehicleProperty::HVAC_FAN_DIRECTION:
-            v = pool.obtainInt32(toInt(mFanDirection));
-            break;
-        case VehicleProperty::HVAC_DEFROSTER:
-            bool defroster;
-            *outStatus = getHvacDefroster(areaId, &defroster);
-            if (StatusCode::OK == *outStatus) {
-                v = pool.obtainBoolean(defroster);
-            }
-            break;
-        case VehicleProperty::HVAC_TEMPERATURE_SET:
-            float value;
-            *outStatus = getHvacTemperature(requestedPropValue.areaId,
-                                            &value);
-            if (StatusCode::OK == *outStatus) {
-                v = pool.obtainFloat(value);
-            }
-            break;
-        case VehicleProperty::INFO_FUEL_CAPACITY:
-            v = pool.obtainFloat(0.75f);
-            break;
-        case VehicleProperty::DISPLAY_BRIGHTNESS:
-            v = pool.obtainInt32(mBrightness);
-            break;
-        case VehicleProperty::NIGHT_MODE:
-            v = pool.obtainBoolean(false);
-            break;
-        case VehicleProperty::GEAR_SELECTION:
-            v = pool.obtainInt32(toInt(VehicleGear::GEAR_PARK));
-            break;
-        case VehicleProperty::DRIVING_STATUS:
-            v = pool.obtainInt32(toInt(VehicleDrivingStatus::UNRESTRICTED));
-            break;
-        case VehicleProperty::IGNITION_STATE:
-            v = pool.obtainInt32(toInt(VehicleIgnitionState::ACC));
-            break;
-        case VehicleProperty::OBD2_LIVE_FRAME:
-            v = pool.obtainComplex();
-            *outStatus = fillObd2LiveFrame(&v);
-            break;
-        case VehicleProperty::OBD2_FREEZE_FRAME:
-            v = pool.obtainComplex();
-            *outStatus = fillObd2FreezeFrame(&v);
-            break;
-        default:
-            *outStatus = StatusCode::INVALID_ARG;
+        }
     }
-
-    if (StatusCode::OK == *outStatus && v.get() != nullptr) {
-        v->prop = toInt(property);
-        v->areaId = areaId;
-        v->timestamp = elapsedRealtimeNano();
-    }
-
-    return v;
 }
 
-StatusCode DefaultVehicleHal::set(const VehiclePropValue& propValue) {
-    auto property = static_cast<VehicleProperty>(propValue.prop);
-    const auto& v = propValue.value;
+void DefaultVehicleHal::doGetConfigAll(emulator::EmulatorMessage& /* rxMsg */,
+                                       emulator::EmulatorMessage& respMsg) {
+    std::vector<VehiclePropConfig> configs = listProperties();
 
-    StatusCode status = StatusCode::OK;
+    respMsg.set_msg_type(emulator::GET_CONFIG_ALL_RESP);
+    respMsg.set_status(emulator::RESULT_OK);
 
-    switch (property) {
-        case VehicleProperty::HVAC_POWER_ON:
-            mHvacPowerOn = v.int32Values[0] == 1;
-            break;
-        case VehicleProperty::HVAC_RECIRC_ON:
-            mHvacRecircOn = v.int32Values[0] == 1;
-            break;
-        case VehicleProperty::HVAC_AC_ON:
-            mHvacAcOn = v.int32Values[0] == 1;
-            break;
-        case VehicleProperty::HVAC_AUTO_ON:
-            mHvacAutoOn = v.int32Values[0] == 1;
-            break;
-        case VehicleProperty::HVAC_DEFROSTER:
-            status = setHvacDefroster(propValue.areaId, v.int32Values[0] == 1);
-            break;
-        case VehicleProperty::HVAC_FAN_DIRECTION:
-            mFanDirection =
-                    static_cast<VehicleHvacFanDirection>(v.int32Values[0]);
-            break;
-        case VehicleProperty::HVAC_FAN_SPEED:
-            mFanSpeed = v.int32Values[0];
-            break;
-        case VehicleProperty::HVAC_TEMPERATURE_SET:
-            status = setHvacTemperature(propValue.areaId, v.floatValues[0]);
-            break;
-        case VehicleProperty::DISPLAY_BRIGHTNESS:
-            mBrightness = v.int32Values[0];
-            break;
-        default:
-            status = StatusCode::INVALID_ARG;
+    for (auto& config : configs) {
+        emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
+        populateProtoVehicleConfig(protoCfg, config);
     }
-
-    return status;
 }
 
-void DefaultVehicleHal::onCreate() {
-    const auto& propConfigs(listProperties());
-    auto obd2LiveFramePropConfig = std::find_if(
-        propConfigs.begin(),
-        propConfigs.end(),
-        [] (VehiclePropConfig config) -> bool {
-            return (config.prop == toInt(VehicleProperty::OBD2_LIVE_FRAME));
-        });
+void DefaultVehicleHal::doGetProperty(emulator::EmulatorMessage& rxMsg,
+                                      emulator::EmulatorMessage& respMsg) {
+    int32_t areaId = 0;
+    emulator::VehiclePropGet getProp = rxMsg.prop(0);
+    int32_t propId = getProp.prop();
+    emulator::Status status = emulator::ERROR_INVALID_PROPERTY;
+    VehiclePropValue* val;
+
+    respMsg.set_msg_type(emulator::GET_PROPERTY_RESP);
+
+    if (getProp.has_area_id()) {
+        areaId = getProp.area_id();
+    }
+
+    {
+        std::lock_guard<std::mutex> lock(mPropsMutex);
+
+        val = getVehiclePropValueLocked(propId, areaId);
+        if (val != nullptr) {
+            emulator::VehiclePropValue* protoVal = respMsg.add_value();
+            populateProtoVehiclePropValue(protoVal, val);
+            status = emulator::RESULT_OK;
+        }
+    }
+
+    respMsg.set_status(status);
+}
+
+void DefaultVehicleHal::doGetPropertyAll(emulator::EmulatorMessage& /* rxMsg */,
+                                         emulator::EmulatorMessage& respMsg) {
+    respMsg.set_msg_type(emulator::GET_PROPERTY_ALL_RESP);
+    respMsg.set_status(emulator::RESULT_OK);
+
+    {
+        std::lock_guard<std::mutex> lock(mPropsMutex);
+
+        for (auto& propVal : mProps) {
+            emulator::VehiclePropValue* protoVal = respMsg.add_value();
+            populateProtoVehiclePropValue(protoVal, propVal.get());
+        }
+    }
+}
+
+void DefaultVehicleHal::doSetProperty(emulator::EmulatorMessage& rxMsg,
+                                      emulator::EmulatorMessage& respMsg) {
+    emulator::VehiclePropValue protoVal = rxMsg.value(0);
+    VehiclePropValue val;
+
+    respMsg.set_msg_type(emulator::SET_PROPERTY_RESP);
+
+    val.prop = protoVal.prop();
+    val.areaId = protoVal.area_id();
+
+    // Copy value data if it is set.  This automatically handles complex data types if needed.
+    if (protoVal.has_string_value()) {
+        val.value.stringValue = protoVal.string_value().c_str();
+    }
+
+    if (protoVal.has_bytes_value()) {
+        std::vector<uint8_t> tmp(protoVal.bytes_value().begin(), protoVal.bytes_value().end());
+        val.value.bytes = tmp;
+    }
+
+    if (protoVal.int32_values_size() > 0) {
+        std::vector<int32_t> int32Values = std::vector<int32_t>(protoVal.int32_values_size());
+        for (int i=0; i<protoVal.int32_values_size(); i++) {
+            int32Values[i] = protoVal.int32_values(i);
+        }
+        val.value.int32Values = int32Values;
+    }
+
+    if (protoVal.int64_values_size() > 0) {
+        std::vector<int64_t> int64Values = std::vector<int64_t>(protoVal.int64_values_size());
+        for (int i=0; i<protoVal.int64_values_size(); i++) {
+            int64Values[i] = protoVal.int64_values(i);
+        }
+        val.value.int64Values = int64Values;
+    }
+
+    if (protoVal.float_values_size() > 0) {
+        std::vector<float> floatValues = std::vector<float>(protoVal.float_values_size());
+        for (int i=0; i<protoVal.float_values_size(); i++) {
+            floatValues[i] = protoVal.float_values(i);
+        }
+        val.value.floatValues = floatValues;
+    }
+
+    if (updateProperty(val) == StatusCode::OK) {
+        // Send property up to VehicleHalManager via callback
+        auto& pool = *getValuePool();
+        VehiclePropValuePtr v = pool.obtain(val);
+
+        doHalEvent(std::move(v));
+        respMsg.set_status(emulator::RESULT_OK);
+    } else {
+        respMsg.set_status(emulator::ERROR_INVALID_PROPERTY);
+    }
+}
+
+// This function should only be called while mPropsMutex is locked.
+VehiclePropValue* DefaultVehicleHal::getVehiclePropValueLocked(int32_t propId, int32_t areaId) {
+    if (getPropArea(propId) == VehicleArea::GLOBAL) {
+        // In VehicleHal, global properties have areaId = -1.  We use 0.
+        areaId = 0;
+    }
+
+    for (auto& prop : mProps) {
+        if ((prop->prop == propId) && (prop->areaId == areaId)) {
+            return prop.get();
+        }
+    }
+    ALOGW("%s: Property not found:  propId = 0x%x, areaId = 0x%x", __FUNCTION__, propId, areaId);
+    return nullptr;
+}
+
+void DefaultVehicleHal::initObd2LiveFrame(VehiclePropConfig& obd2LiveFramePropConfig) {
     mObd2SensorStore.reset(new Obd2SensorStore(
-        obd2LiveFramePropConfig->configArray[0],
-        obd2LiveFramePropConfig->configArray[1]));
+        obd2LiveFramePropConfig.configArray[0],
+        obd2LiveFramePropConfig.configArray[1]));
     // precalculate OBD2 sensor values
     mObd2SensorStore->setIntegerSensor(
         Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS,
@@ -246,56 +264,461 @@
         Obd2FloatSensorIndex::COMMANDED_THROTTLE_ACTUATOR, 0.024);
 }
 
-StatusCode DefaultVehicleHal::getHvacTemperature(int32_t areaId,
-                                                 float* outValue)  {
-    if (areaId == toInt(VehicleAreaZone::ROW_1_LEFT)) {
-        *outValue = mRow1LeftHvacTemperatureSet;
-    } else if (areaId == toInt(VehicleAreaZone::ROW_1_RIGHT)) {
-        *outValue = mRow1RightHvacTemperatureSet;
-    } else {
-        return StatusCode::INVALID_ARG;
+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);
+
+    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;
     }
-    return StatusCode::OK;
+
+    // Send the reply
+    txMsg(respMsg);
 }
 
-StatusCode DefaultVehicleHal::setHvacTemperature(
-    int32_t areaId, float value) {
-    if (areaId == toInt(VehicleAreaZone::ROW_1_LEFT)) {
-        mRow1LeftHvacTemperatureSet = value;
-    } else if (areaId == toInt(VehicleAreaZone::ROW_1_RIGHT)) {
-        mRow1RightHvacTemperatureSet = value;
-    } else {
-        return StatusCode::INVALID_ARG;
+// Copies internal VehiclePropConfig data structure to protobuf VehiclePropConfig
+void DefaultVehicleHal::populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
+                                                   const VehiclePropConfig& cfg) {
+    protoCfg->set_prop(cfg.prop);
+    protoCfg->set_access(toInt(cfg.access));
+    protoCfg->set_change_mode(toInt(cfg.changeMode));
+    protoCfg->set_value_type(toInt(getPropType(cfg.prop)));
+
+    if (!isGlobalProp(cfg.prop)) {
+        protoCfg->set_supported_areas(cfg.supportedAreas);
     }
-    return StatusCode::OK;
+
+    for (auto& configElement : cfg.configArray) {
+        protoCfg->add_config_array(configElement);
+    }
+
+    if (cfg.configString.size() > 0) {
+        protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size());
+    }
+
+    // Populate the min/max values based on property type
+    switch (getPropType(cfg.prop)) {
+    case VehiclePropertyType::STRING:
+    case VehiclePropertyType::BOOLEAN:
+    case VehiclePropertyType::INT32_VEC:
+    case VehiclePropertyType::FLOAT_VEC:
+    case VehiclePropertyType::BYTES:
+    case VehiclePropertyType::COMPLEX:
+        // Do nothing.  These types don't have min/max values
+        break;
+    case VehiclePropertyType::INT64:
+        if (cfg.areaConfigs.size() > 0) {
+            emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
+            aCfg->set_min_int64_value(cfg.areaConfigs[0].minInt64Value);
+            aCfg->set_max_int64_value(cfg.areaConfigs[0].maxInt64Value);
+        }
+        break;
+    case VehiclePropertyType::FLOAT:
+        if (cfg.areaConfigs.size() > 0) {
+            emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
+            aCfg->set_min_float_value(cfg.areaConfigs[0].minFloatValue);
+            aCfg->set_max_float_value(cfg.areaConfigs[0].maxFloatValue);
+        }
+        break;
+    case VehiclePropertyType::INT32:
+        if (cfg.areaConfigs.size() > 0) {
+            emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
+            aCfg->set_min_int32_value(cfg.areaConfigs[0].minInt32Value);
+            aCfg->set_max_int32_value(cfg.areaConfigs[0].maxInt32Value);
+        }
+        break;
+    default:
+        ALOGW("%s: Unknown property type:  0x%x", __FUNCTION__, toInt(getPropType(cfg.prop)));
+        break;
+    }
+
+    protoCfg->set_min_sample_rate(cfg.minSampleRate);
+    protoCfg->set_max_sample_rate(cfg.maxSampleRate);
 }
 
-StatusCode DefaultVehicleHal::getHvacDefroster(int32_t areaId,
-                                               bool* outValue) {
-    ALOGI("Getting Hvac defroster for area: 0x%x", areaId);
+// Copies internal VehiclePropValue data structure to protobuf VehiclePropValue
+void DefaultVehicleHal::populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
+                                                      const VehiclePropValue* val) {
+    protoVal->set_prop(val->prop);
+    protoVal->set_value_type(toInt(getPropType(val->prop)));
+    protoVal->set_timestamp(val->timestamp);
+    protoVal->set_area_id(val->areaId);
 
-    if (areaId == toInt(VehicleAreaWindow::FRONT_WINDSHIELD)) {
-        *outValue = mFrontDefroster;
-    } else if (areaId == toInt(VehicleAreaWindow::REAR_WINDSHIELD)) {
-        *outValue = mRearDefroster;
-    } else {
-        ALOGE("Unable to get hvac defroster for area: 0x%x", areaId);
-        return StatusCode::INVALID_ARG;
+    // Copy value data if it is set.
+    //  - for bytes and strings, this is indicated by size > 0
+    //  - for int32, int64, and float, copy the values if vectors have data
+    if (val->value.stringValue.size() > 0) {
+        protoVal->set_string_value(val->value.stringValue.c_str(), val->value.stringValue.size());
     }
 
-    ALOGI("Getting Hvac defroster for area: 0x%x, OK", areaId);
-    return StatusCode::OK;
+    if (val->value.bytes.size() > 0) {
+        protoVal->set_bytes_value(val->value.bytes.data(), val->value.bytes.size());
+    }
+
+    for (auto& int32Value : val->value.int32Values) {
+        protoVal->add_int32_values(int32Value);
+    }
+
+    for (auto& int64Value : val->value.int64Values) {
+        protoVal->add_int64_values(int64Value);
+    }
+
+    for (auto& floatValue : val->value.floatValues) {
+        protoVal->add_float_values(floatValue);
+    }
 }
 
-StatusCode DefaultVehicleHal::setHvacDefroster(int32_t areaId, bool value) {
-    if (areaId == toInt(VehicleAreaWindow::FRONT_WINDSHIELD)) {
-        mFrontDefroster = value;
-    } else if (areaId == toInt(VehicleAreaWindow::REAR_WINDSHIELD)) {
-        mRearDefroster = value;
-    } else {
-        return StatusCode::INVALID_ARG;
+void DefaultVehicleHal::rxMsg(void) {
+    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;
+        }
+
+        std::vector<uint8_t> msg = std::vector<uint8_t>(msgSize);
+
+        numBytes = read(mCurSocket, msg.data(), msgSize);
+
+        if ((numBytes == msgSize) && (msgSize > 0)) {
+            // Received a message.
+            parseRxProtoBuf(msg);
+        } else {
+            // This happens when connection is closed
+            ALOGD("%s: numBytes=%d, msgSize=%d", __FUNCTION__, numBytes, msgSize);
+            break;
+        }
+    } while (mExit == 0);
+}
+
+void DefaultVehicleHal::rxThread(void) {
+    // Initialize the socket
+    {
+        int retVal;
+        struct sockaddr_in servAddr;
+
+        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);
     }
-    return StatusCode::OK;
+
+    while (mExit == 0) {
+        struct sockaddr_in cliAddr;
+        socklen_t cliLen = sizeof(cliAddr);
+        int cSocket = accept(mSocket, reinterpret_cast<struct sockaddr*>(&cliAddr), &cliLen);
+
+        if (cSocket >= 0) {
+            {
+                std::lock_guard<std::mutex> lock(mTxMutex);
+                mCurSocket = cSocket;
+            }
+            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;
+            }
+        }
+
+        // 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.
+// TODO:  Co-locate the default values with the configuration structure, to make it easier to
+//          add new properties and their defaults.
+void DefaultVehicleHal::setDefaultValue(VehiclePropValue* prop) {
+    switch (prop->prop) {
+    case toInt(VehicleProperty::INFO_MAKE):
+        prop->value.stringValue = "Default Car";
+        break;
+    case toInt(VehicleProperty::HVAC_POWER_ON):
+        prop->value.int32Values[0] = 1;
+        break;
+    case toInt(VehicleProperty::HVAC_DEFROSTER):
+        prop->value.int32Values[0] = 0;
+        break;
+    case toInt(VehicleProperty::HVAC_RECIRC_ON):
+        prop->value.int32Values[0] = 1;
+        break;
+    case toInt(VehicleProperty::HVAC_AC_ON):
+        prop->value.int32Values[0] = 1;
+        break;
+    case toInt(VehicleProperty::HVAC_AUTO_ON):
+        prop->value.int32Values[0] = 1;
+        break;
+    case toInt(VehicleProperty::HVAC_FAN_SPEED):
+        prop->value.int32Values[0] = 3;
+        break;
+    case toInt(VehicleProperty::HVAC_FAN_DIRECTION):
+        prop->value.int32Values[0] = toInt(VehicleHvacFanDirection::FACE);
+        break;
+    case toInt(VehicleProperty::HVAC_TEMPERATURE_SET):
+        prop->value.floatValues[0] = 16;
+        break;
+    case toInt(VehicleProperty::NIGHT_MODE):
+        prop->value.int32Values[0] = 0;
+        break;
+    case toInt(VehicleProperty::DRIVING_STATUS):
+        prop->value.int32Values[0] = toInt(VehicleDrivingStatus::UNRESTRICTED);
+        break;
+    case toInt(VehicleProperty::GEAR_SELECTION):
+        prop->value.int32Values[0] = toInt(VehicleGear::GEAR_PARK);
+        break;
+    case toInt(VehicleProperty::INFO_FUEL_CAPACITY):
+        prop->value.floatValues[0] = 0.75f;
+        break;
+    case toInt(VehicleProperty::DISPLAY_BRIGHTNESS):
+        prop->value.int32Values[0] = 7;
+        break;
+    case toInt(VehicleProperty::IGNITION_STATE):
+        prop->value.int32Values[0] = toInt(VehicleIgnitionState::ON);
+        break;
+    case toInt(VehicleProperty::OBD2_LIVE_FRAME):
+        // OBD2 is handled separately
+        break;
+    case toInt(VehicleProperty::OBD2_FREEZE_FRAME):
+        // OBD2 is handled separately
+        break;
+    default:
+        ALOGW("%s: propId=0x%x not found", __FUNCTION__, prop->prop);
+        break;
+    }
+}
+
+// Transmit a reply back to the emulator
+void DefaultVehicleHal::txMsg(emulator::EmulatorMessage& txMsg) {
+    std::string msgString;
+
+    if (txMsg.SerializeToString(&msgString)) {
+        int32_t msgLen = msgString.length();
+        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 (retVal < 0) {
+            ALOGE("%s: Failed to tx message: retval=%d, errno=%d", __FUNCTION__, retVal, errno);
+        }
+    } else {
+        ALOGE("%s: SerializeToString failed!", __FUNCTION__);
+    }
+}
+
+// Updates the property value held in the HAL
+StatusCode DefaultVehicleHal::updateProperty(const VehiclePropValue& propValue) {
+    auto propId = propValue.prop;
+    auto areaId = propValue.areaId;
+    StatusCode status = StatusCode::INVALID_ARG;
+
+    {
+        std::lock_guard<std::mutex> lock(mPropsMutex);
+
+        VehiclePropValue* internalPropValue = getVehiclePropValueLocked(propId, areaId);
+        if (internalPropValue != nullptr) {
+            internalPropValue->value = propValue.value;
+            internalPropValue->timestamp = elapsedRealtimeNano();
+            status = StatusCode::OK;
+        }
+    }
+    return status;
+}
+
+VehicleHal::VehiclePropValuePtr DefaultVehicleHal::get(
+        const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
+    auto areaId = requestedPropValue.areaId;
+    auto& pool = *getValuePool();
+    auto propId = requestedPropValue.prop;
+    StatusCode status;
+    VehiclePropValuePtr v = nullptr;
+
+    switch (propId) {
+    case toInt(VehicleProperty::OBD2_LIVE_FRAME):
+        v = pool.obtainComplex();
+        status = fillObd2LiveFrame(&v);
+        break;
+    case toInt(VehicleProperty::OBD2_FREEZE_FRAME):
+        v = pool.obtainComplex();
+        status = fillObd2FreezeFrame(&v);
+        break;
+    default:
+        {
+            std::lock_guard<std::mutex> lock(mPropsMutex);
+
+            VehiclePropValue *internalPropValue = getVehiclePropValueLocked(propId, areaId);
+            if (internalPropValue != nullptr) {
+                v = pool.obtain(*internalPropValue);
+            }
+        }
+
+        if (v != nullptr) {
+            status = StatusCode::OK;
+        } else {
+            status = StatusCode::INVALID_ARG;
+        }
+        break;
+    }
+
+    *outStatus = status;
+    return v;
+}
+
+StatusCode DefaultVehicleHal::set(const VehiclePropValue& propValue) {
+    StatusCode status = updateProperty(propValue);
+
+    if (status == StatusCode::OK) {
+        // Send property update to emulator
+        emulator::EmulatorMessage msg;
+        emulator::VehiclePropValue *val = msg.add_value();
+        populateProtoVehiclePropValue(val, &propValue);
+        msg.set_status(emulator::RESULT_OK);
+        msg.set_msg_type(emulator::SET_PROPERTY_ASYNC);
+        txMsg(msg);
+    }
+
+    return status;
+}
+
+// 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();
+
+    for (auto& cfg : configs) {
+        VehiclePropertyType propType = getPropType(cfg.prop);
+        int32_t supportedAreas = cfg.supportedAreas;
+        int32_t vecSize;
+
+        // Set the vector size based on property type
+        switch (propType) {
+        case VehiclePropertyType::BOOLEAN:
+        case VehiclePropertyType::INT32:
+        case VehiclePropertyType::INT64:
+        case VehiclePropertyType::FLOAT:
+            vecSize = 1;
+            break;
+        case VehiclePropertyType::INT32_VEC:
+        case VehiclePropertyType::FLOAT_VEC:
+        case VehiclePropertyType::BYTES:
+            // TODO:  Add proper support for these types
+            vecSize = 1;
+            break;
+        case VehiclePropertyType::STRING:
+            // Require individual handling
+            vecSize = 0;
+            break;
+        case VehiclePropertyType::COMPLEX:
+            switch (cfg.prop) {
+            case toInt(VehicleProperty::OBD2_LIVE_FRAME):
+                initObd2LiveFrame(cfg);
+                break;
+            default:
+                // Need to handle each complex property separately
+                break;
+            }
+            continue;
+            break;
+        case VehiclePropertyType::MASK:
+        default:
+            ALOGW("%s: propType=0x%x not found", __FUNCTION__, propType);
+            vecSize = 0;
+            break;
+        }
+
+        //  A global property will have supportedAreas = 0
+        if (getPropArea(cfg.prop) == VehicleArea::GLOBAL) {
+            supportedAreas = 0;
+        }
+
+        // This loop is a do-while so it executes at least once to handle global properties
+        do {
+            int32_t curArea = supportedAreas;
+
+            // Clear the right-most bit of supportedAreas
+            supportedAreas &= supportedAreas - 1;
+
+            // Set curArea to the previously cleared bit
+            curArea ^= supportedAreas;
+
+            // Create a separate instance for each individual zone
+            std::unique_ptr<VehiclePropValue> prop = createVehiclePropValue(propType, vecSize);
+            prop->areaId = curArea;
+            prop->prop = cfg.prop;
+            setDefaultValue(prop.get());
+            mProps.push_back(std::move(prop));
+        } while (supportedAreas != 0);
+    }
+
+    // Start rx thread
+    mThread = std::thread(&DefaultVehicleHal::rxThread, this);
 }
 
 StatusCode DefaultVehicleHal::fillObd2LiveFrame(VehiclePropValuePtr* v) {
diff --git a/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.h b/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.h
index ccedeeb..edfc224 100644
--- a/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.h
@@ -21,8 +21,12 @@
 
 #include <VehicleHal.h>
 #include <impl/DefaultConfig.h>
-#include <vehicle_hal_manager/Obd2SensorStore.h>
+#include <sys/socket.h>
+#include <thread>
 #include <utils/SystemClock.h>
+#include <vehicle_hal_manager/Obd2SensorStore.h>
+#include "VehicleHalProto.pb.h"
+
 
 namespace android {
 namespace hardware {
@@ -34,6 +38,23 @@
 
 class DefaultVehicleHal : public VehicleHal {
 public:
+    DefaultVehicleHal() : mThread() {}
+    ~DefaultVehicleHal() override {
+        // Notify thread to finish and wait for it to terminate
+        mExit = 1;
+
+        // Close emulator socket if it is open
+        {
+            std::lock_guard<std::mutex> lock(mTxMutex);
+            if (mCurSocket != -1) {
+                close(mCurSocket);
+                mCurSocket = -1;
+            }
+        }
+
+        mThread.join();
+    }
+
     std::vector<VehiclePropConfig> listProperties() override {
         return std::vector<VehiclePropConfig>(std::begin(kVehicleProperties),
                                               std::end(kVehicleProperties));
@@ -46,38 +67,47 @@
 
     StatusCode set(const VehiclePropValue& propValue) override;
 
-    StatusCode subscribe(int32_t /*property*/,
-                         int32_t /*areas*/,
-                         float /*sampleRate*/) override {
-        // TODO(pavelm): implement
+    StatusCode subscribe(int32_t property, int32_t areas, float sampleRate) {
+        ALOGD("%s: not implemented: prop=0x%x, areas=0x%x, rate=%f", __FUNCTION__, property,
+              areas, sampleRate);
         return StatusCode::OK;
     }
 
-    StatusCode unsubscribe(int32_t /*property*/) override {
-        // TODO(pavelm): implement
+    StatusCode unsubscribe(int32_t property) {
+        ALOGD("%s: not implemented: prop=0x%x", __FUNCTION__, property);
         return StatusCode::OK;
     }
 
 private:
-    StatusCode getHvacTemperature(int32_t areaId, float* outValue);
-    StatusCode setHvacTemperature(int32_t areaId, float value);
-    StatusCode getHvacDefroster(int32_t areaId, bool* outValue);
-    StatusCode setHvacDefroster(int32_t areaId, bool value);
+    void doGetConfig(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
+    void doGetConfigAll(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
+    void doGetProperty(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
+    void doGetPropertyAll(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
+    void doSetProperty(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
+    VehiclePropValue* getVehiclePropValueLocked(int32_t propId, int32_t areaId);
+    void initObd2LiveFrame(VehiclePropConfig& obd2LiveFramePropConfig);
+    void parseRxProtoBuf(std::vector<uint8_t>& msg);
+    void populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
+                                    const VehiclePropConfig& cfg);
+    void populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
+                                       const VehiclePropValue* val);
+    void setDefaultValue(VehiclePropValue* prop);
+    void rxMsg(void);
+    void rxThread(void);
+    void txMsg(emulator::EmulatorMessage& txMsg);
+    StatusCode updateProperty(const VehiclePropValue& propValue);
     StatusCode fillObd2LiveFrame(VehiclePropValuePtr* v);
     StatusCode fillObd2FreezeFrame(VehiclePropValuePtr* v);
 private:
-    int32_t mFanSpeed = 3;
-    int32_t mBrightness = 7;
-    float mRow1LeftHvacTemperatureSet = 16;
-    float mRow1RightHvacTemperatureSet = 22;
-    bool mFrontDefroster = false;
-    bool mRearDefroster = false;
-    bool mHvacPowerOn = true;
-    bool mHvacRecircOn = true;
-    bool mHvacAcOn = true;
-    bool mHvacAutoOn = true;
-    VehicleHvacFanDirection mFanDirection = VehicleHvacFanDirection::FACE;
+    // 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<Obd2SensorStore> mObd2SensorStore{nullptr};
+    std::mutex mPropsMutex;
+    int mSocket;
+    std::mutex mTxMutex;
+    std::thread mThread;
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/impl/proto/VehicleHalProto.proto b/automotive/vehicle/2.0/default/impl/proto/VehicleHalProto.proto
new file mode 100644
index 0000000..86433f5
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/proto/VehicleHalProto.proto
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+package emulator;
+
+// CMD messages are from workstation --> VHAL
+// RESP messages are from VHAL --> workstation
+enum MsgType {
+    GET_CONFIG_CMD                      = 0;
+    GET_CONFIG_RESP                     = 1;
+    GET_CONFIG_ALL_CMD                  = 2;
+    GET_CONFIG_ALL_RESP                 = 3;
+    GET_PROPERTY_CMD                    = 4;
+    GET_PROPERTY_RESP                   = 5;
+    GET_PROPERTY_ALL_CMD                = 6;
+    GET_PROPERTY_ALL_RESP               = 7;
+    SET_PROPERTY_CMD                    = 8;
+    SET_PROPERTY_RESP                   = 9;
+    SET_PROPERTY_ASYNC                  = 10;
+}
+enum Status {
+    RESULT_OK                           = 0;
+    ERROR_UNKNOWN                       = 1;
+    ERROR_UNIMPLEMENTED_CMD             = 2;
+    ERROR_INVALID_PROPERTY              = 3;
+    ERROR_INVALID_AREA_ID               = 4;
+    ERROR_PROPERTY_UNINITIALIZED        = 5;
+    ERROR_WRITE_ONLY_PROPERTY           = 6;
+    ERROR_MEMORY_ALLOC_FAILED           = 7;
+    ERROR_INVALID_OPERATION             = 8;
+}
+
+message VehicleAreaConfig {
+    required int32  area_id             = 1;
+    optional sint32 min_int32_value     = 2;
+    optional sint32 max_int32_value     = 3;
+    optional sint64 min_int64_value     = 4;
+    optional sint64 max_int64_value     = 5;
+    optional float  min_float_value     = 6;
+    optional float  max_float_value     = 7;
+}
+
+message VehiclePropConfig {
+    required int32             prop                = 1;
+    optional int32             access              = 2;
+    optional int32             change_mode         = 3;
+    optional int32             value_type          = 4;
+    optional int32             supported_areas     = 5;
+    repeated VehicleAreaConfig area_configs        = 6;
+    optional int32             config_flags        = 7;
+    repeated int32             config_array        = 8;
+    optional string            config_string       = 9;
+    optional float             min_sample_rate     = 10;
+    optional float             max_sample_rate     = 11;
+};
+
+message VehiclePropValue {
+    // common data
+    required int32  prop                = 1;
+    optional int32  value_type          = 2;
+    optional int64  timestamp           = 3;    // required for valid data from HAL, skipped for set
+
+    // values
+    optional int32  area_id             = 4;
+    repeated sint32 int32_values        = 5;    // this also covers boolean value.
+    repeated sint64 int64_values        = 6;
+    repeated float  float_values        = 7;
+    optional string string_value        = 8;
+    optional bytes  bytes_value         = 9;
+};
+
+// This structure is used to notify what values to get from the Vehicle HAL
+message VehiclePropGet {
+    required int32 prop                 = 1;
+    optional int32 area_id              = 2;
+};
+
+message EmulatorMessage {
+    required MsgType           msg_type = 1;
+    optional Status            status   = 2;    // Only for RESP messages
+    repeated VehiclePropGet    prop     = 3;    // Provided for getConfig, getProperty commands
+    repeated VehiclePropConfig config   = 4;
+    repeated VehiclePropValue  value    = 5;
+};