Move Vehicle HAL under automotive package

Test: verified unit tests and VTS are passing

Bug: b/33200203
Change-Id: I69cc4bc0d4cbc1a6bf2f77564a8f70412fe06947
diff --git a/automotive/vehicle/2.0/default/Android.mk b/automotive/vehicle/2.0/default/Android.mk
new file mode 100644
index 0000000..a346507
--- /dev/null
+++ b/automotive/vehicle/2.0/default/Android.mk
@@ -0,0 +1,120 @@
+# Copyright (C) 2016 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.
+
+LOCAL_PATH := $(call my-dir)
+
+module_prefix = android.hardware.automotive.vehicle@2.0
+
+###############################################################################
+# Vehicle reference implementation lib
+###############################################################################
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(module_prefix)-manager-lib
+LOCAL_SRC_FILES := \
+    vehicle_hal_manager/AccessControlConfigParser.cpp \
+    vehicle_hal_manager/Obd2SensorStore.cpp \
+    vehicle_hal_manager/SubscriptionManager.cpp \
+    vehicle_hal_manager/VehicleHalManager.cpp \
+    vehicle_hal_manager/VehicleObjectPool.cpp \
+    vehicle_hal_manager/VehicleUtils.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+    libbinder \
+    libhidlbase \
+    libhidltransport \
+    libhwbinder \
+    liblog \
+    libutils \
+    $(module_prefix) \
+
+include $(BUILD_STATIC_LIBRARY)
+
+###############################################################################
+# Vehicle default VehicleHAL implementation
+###############################################################################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= $(module_prefix)-default-impl-lib
+LOCAL_SRC_FILES:= \
+    impl/DefaultVehicleHal.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+    libbinder \
+    libhidlbase \
+    libhidltransport \
+    libhwbinder \
+    liblog \
+    libutils \
+    $(module_prefix) \
+
+include $(BUILD_STATIC_LIBRARY)
+
+
+###############################################################################
+# Vehicle reference implementation unit tests
+###############################################################################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= $(module_prefix)-manager-unit-tests
+
+LOCAL_WHOLE_STATIC_LIBRARIES := $(module_prefix)-manager-lib
+
+LOCAL_SRC_FILES:= \
+    tests/AccessControlConfigParser_test.cpp \
+    tests/Obd2SensorStore_test.cpp \
+    tests/SubscriptionManager_test.cpp \
+    tests/VehicleHalManager_test.cpp \
+    tests/VehicleObjectPool_test.cpp \
+    tests/VehiclePropConfigIndex_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+    libbinder \
+    libhidlbase \
+    libhidltransport \
+    libhwbinder \
+    liblog \
+    libutils \
+    $(module_prefix) \
+
+LOCAL_CFLAGS += -Wall -Wextra
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_NATIVE_TEST)
+
+
+###############################################################################
+# Vehicle HAL service
+###############################################################################
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(module_prefix)-service
+LOCAL_INIT_RC := $(module_prefix)-service.rc
+LOCAL_MODULE_RELATIVE_PATH := hw
+
+LOCAL_SRC_FILES := \
+    VehicleService.cpp
+
+LOCAL_WHOLE_STATIC_LIBRARIES := \
+    $(module_prefix)-manager-lib \
+    $(module_prefix)-default-impl-lib \
+
+LOCAL_SHARED_LIBRARIES := \
+    libbinder \
+    libhidlbase \
+    libhidltransport \
+    libhwbinder \
+    liblog \
+    libutils \
+    $(module_prefix) \
+
+include $(BUILD_EXECUTABLE)
diff --git a/automotive/vehicle/2.0/default/VehicleHal.h b/automotive/vehicle/2.0/default/VehicleHal.h
new file mode 100644
index 0000000..76df5b8
--- /dev/null
+++ b/automotive/vehicle/2.0/default/VehicleHal.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2016 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_VehicleHal_H
+#define android_hardware_automotive_vehicle_V2_0_VehicleHal_H
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include "vehicle_hal_manager/VehicleObjectPool.h"
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+/**
+ * This is a low-level vehicle hal interface that should be implemented by
+ * Vendor.
+ */
+class VehicleHal {
+public:
+    using VehiclePropValuePtr = recyclable_ptr<VehiclePropValue>;
+
+    using HalEventFunction = std::function<void(VehiclePropValuePtr)>;
+    using HalErrorFunction = std::function<void(
+            StatusCode errorCode, int32_t property, int32_t areaId)>;
+
+    virtual ~VehicleHal() {}
+
+    virtual std::vector<VehiclePropConfig> listProperties() = 0;
+    virtual VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue,
+                                    StatusCode* outStatus) = 0;
+
+    virtual StatusCode set(const VehiclePropValue& propValue) = 0;
+
+    /**
+     * Subscribe to HAL property events. This method might be called multiple
+     * times for the same vehicle property to update subscribed areas or sample
+     * rate.
+     *
+     * @param property to subscribe
+     * @param areas a bitwise vehicle areas or 0 for all supported areas
+     * @param sampleRate sample rate in Hz for properties that support sample
+     *                   rate, e.g. for properties with
+     *                   VehiclePropertyChangeMode::CONTINUOUS
+     */
+    virtual StatusCode subscribe(int32_t property,
+                                 int32_t areas,
+                                 float sampleRate) = 0;
+
+    /**
+     * Unsubscribe from HAL events for given property
+     *
+     * @param property vehicle property to unsubscribe
+     */
+    virtual StatusCode unsubscribe(int32_t property) = 0;
+
+    /**
+     * Override this method if you need to do one-time initialization.
+     */
+    virtual void onCreate() {}
+
+    void init(
+        VehiclePropValuePool* valueObjectPool,
+        const HalEventFunction& onHalEvent,
+        const HalErrorFunction& onHalError) {
+        mValuePool = valueObjectPool;
+        mOnHalEvent = onHalEvent;
+        mOnHalPropertySetError = onHalError;
+
+        onCreate();
+    }
+
+    VehiclePropValuePool* getValuePool() {
+        return mValuePool;
+    }
+protected:
+    /* Propagates property change events to vehicle HAL clients. */
+    void doHalEvent(VehiclePropValuePtr v) {
+        mOnHalEvent(std::move(v));
+    }
+
+    /* Propagates error during set operation to the vehicle HAL clients. */
+    void doHalPropertySetError(StatusCode errorCode,
+                               int32_t propId,
+                               int32_t areaId) {
+        mOnHalPropertySetError(errorCode, propId, areaId);
+    }
+
+private:
+    HalEventFunction mOnHalEvent;
+    HalErrorFunction mOnHalPropertySetError;
+    VehiclePropValuePool* mValuePool;
+};
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif //android_hardware_automotive_vehicle_V2_0_VehicleHal_H_
diff --git a/automotive/vehicle/2.0/default/VehicleService.cpp b/automotive/vehicle/2.0/default/VehicleService.cpp
new file mode 100644
index 0000000..345dbcc
--- /dev/null
+++ b/automotive/vehicle/2.0/default/VehicleService.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2016 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 "automotive.vehicle@2.0-service"
+#include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include <iostream>
+
+
+#include <vehicle_hal_manager/VehicleHalManager.h>
+#include <impl/DefaultVehicleHal.h>
+
+using namespace android;
+using namespace android::hardware;
+using namespace android::hardware::automotive::vehicle::V2_0;
+
+int main(int /* argc */, char* /* argv */ []) {
+    auto hal = std::make_unique<impl::DefaultVehicleHal>();
+    auto service = std::make_unique<VehicleHalManager>(hal.get());
+
+    configureRpcThreadpool(1, true /* callerWillJoin */);
+
+    ALOGI("Registering as service...");
+    service->registerAsService("Vehicle");
+
+    ALOGI("Ready");
+    joinRpcThreadpool();
+}
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
new file mode 100644
index 0000000..344a984
--- /dev/null
+++ b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
@@ -0,0 +1,4 @@
+service vehicle-hal-2.0 /system/bin/hw/android.hardware.automotive.vehicle@2.0-service
+    class hal
+    user vehicle_network
+    group system
diff --git a/automotive/vehicle/2.0/default/impl/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/DefaultConfig.h
new file mode 100644
index 0000000..270bf8c
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/DefaultConfig.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2016 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_DefaultConfig_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_DefaultConfig_H_
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <vehicle_hal_manager/VehicleUtils.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+const VehiclePropConfig kVehicleProperties[] = {
+    {
+        .prop = toInt(VehicleProperty::INFO_MAKE),
+        .access = VehiclePropertyAccess::READ,
+        .changeMode = VehiclePropertyChangeMode::STATIC,
+    },
+
+    {
+        .prop = toInt(VehicleProperty::HVAC_POWER_ON),
+        .access = VehiclePropertyAccess::READ_WRITE,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        .supportedAreas = toInt(VehicleAreaZone::ROW_1)
+    },
+
+    {
+        .prop = toInt(VehicleProperty::HVAC_DEFROSTER),
+        .access = VehiclePropertyAccess::READ_WRITE,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        .supportedAreas =
+                VehicleAreaWindow::FRONT_WINDSHIELD
+                | VehicleAreaWindow::REAR_WINDSHIELD
+    },
+
+    {
+        .prop = toInt(VehicleProperty::HVAC_RECIRC_ON),
+        .access = VehiclePropertyAccess::READ_WRITE,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        .supportedAreas = toInt(VehicleAreaZone::ROW_1)
+    },
+
+    {
+        .prop = toInt(VehicleProperty::HVAC_AC_ON),
+        .access = VehiclePropertyAccess::READ_WRITE,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        .supportedAreas = toInt(VehicleAreaZone::ROW_1)
+    },
+
+    {
+        .prop = toInt(VehicleProperty::HVAC_AUTO_ON),
+        .access = VehiclePropertyAccess::READ_WRITE,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        .supportedAreas = toInt(VehicleAreaZone::ROW_1)
+    },
+
+    {
+        .prop = toInt(VehicleProperty::HVAC_FAN_SPEED),
+        .access = VehiclePropertyAccess::READ_WRITE,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        .supportedAreas = toInt(VehicleAreaZone::ROW_1),
+        .areaConfigs = {
+            VehicleAreaConfig {
+                .areaId = toInt(VehicleAreaZone::ROW_1),
+                .minInt32Value = 1,
+                .maxInt32Value = 7
+            }
+        }
+    },
+
+    {
+        .prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION),
+        .access = VehiclePropertyAccess::READ_WRITE,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        .supportedAreas = toInt(VehicleAreaZone::ROW_1),
+    },
+
+    {
+        .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET),
+        .access = VehiclePropertyAccess::READ_WRITE,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        .supportedAreas =
+                VehicleAreaZone::ROW_1_LEFT
+                | VehicleAreaZone::ROW_1_RIGHT,
+        .areaConfigs = {
+            VehicleAreaConfig {
+                .areaId = toInt(VehicleAreaZone::ROW_1_LEFT),
+                .minFloatValue = 16,
+                .maxFloatValue = 32,
+            },
+            VehicleAreaConfig {
+                .areaId = toInt(VehicleAreaZone::ROW_1_RIGHT),
+                .minFloatValue = 16,
+                .maxFloatValue = 32,
+            }
+        }
+    },
+
+    {
+        .prop = toInt(VehicleProperty::NIGHT_MODE),
+        .access = VehiclePropertyAccess::READ,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+    },
+
+    {
+        .prop = toInt(VehicleProperty::DRIVING_STATUS),
+        .access = VehiclePropertyAccess::READ,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+    },
+
+    {
+        .prop = toInt(VehicleProperty::GEAR_SELECTION),
+        .access = VehiclePropertyAccess::READ,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+    },
+
+    {
+        .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+        .access = VehiclePropertyAccess::READ,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        .areaConfigs = {
+            VehicleAreaConfig {
+                .minFloatValue = 0,
+                .maxFloatValue = 1.0
+            }
+        }
+    },
+
+    {
+        .prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS),
+        .access = VehiclePropertyAccess::READ_WRITE,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        .areaConfigs = {
+            VehicleAreaConfig {
+                .minInt32Value = 0,
+                .maxInt32Value = 10
+            }
+        }
+    },
+
+    {
+        .prop = toInt(VehicleProperty::IGNITION_STATE),
+        .access = VehiclePropertyAccess::READ,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+    },
+
+    {
+        .prop = toInt(VehicleProperty::OBD2_LIVE_FRAME),
+        .access = VehiclePropertyAccess::READ,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        .configArray = {0,0}
+    },
+
+    {
+        .prop = toInt(VehicleProperty::OBD2_FREEZE_FRAME),
+        .access = VehiclePropertyAccess::READ,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        .configArray = {0,0}
+    }
+};
+
+}  // impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_DefaultConfig_H_
diff --git a/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.cpp
new file mode 100644
index 0000000..1c26759
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.cpp
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2016 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 "DefaultVehicleHal.h"
+
+#include <algorithm>
+
+#define LOG_TAG "default_vehicle"
+#include <android/log.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+VehicleHal::VehiclePropValuePtr DefaultVehicleHal::get(
+        const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
+    *outStatus = StatusCode::OK;
+
+    VehiclePropValuePtr v;
+    auto property = static_cast<VehicleProperty>(requestedPropValue.prop);
+    int32_t areaId = requestedPropValue.areaId;
+    auto& pool = *getValuePool();
+
+    switch (property) {
+        case VehicleProperty::INFO_MAKE:
+            v = pool.obtainString("Default Car");
+            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;
+
+    StatusCode status = StatusCode::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;
+    }
+
+    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));
+        });
+    mObd2SensorStore.reset(new Obd2SensorStore(
+        obd2LiveFramePropConfig->configArray[0],
+        obd2LiveFramePropConfig->configArray[1]));
+    // precalculate OBD2 sensor values
+    mObd2SensorStore->setIntegerSensor(
+        Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS,
+        toInt(FuelSystemStatus::CLOSED_LOOP));
+    mObd2SensorStore->setIntegerSensor(
+        Obd2IntegerSensorIndex::MALFUNCTION_INDICATOR_LIGHT_ON, 0);
+    mObd2SensorStore->setIntegerSensor(
+        Obd2IntegerSensorIndex::IGNITION_MONITORS_SUPPORTED,
+        toInt(IgnitionMonitorKind::SPARK));
+    mObd2SensorStore->setIntegerSensor(Obd2IntegerSensorIndex::IGNITION_SPECIFIC_MONITORS,
+        CommonIgnitionMonitors::COMPONENTS_AVAILABLE |
+        CommonIgnitionMonitors::MISFIRE_AVAILABLE |
+        SparkIgnitionMonitors::AC_REFRIGERANT_AVAILABLE |
+        SparkIgnitionMonitors::EVAPORATIVE_SYSTEM_AVAILABLE);
+    mObd2SensorStore->setIntegerSensor(
+        Obd2IntegerSensorIndex::INTAKE_AIR_TEMPERATURE, 35);
+    mObd2SensorStore->setIntegerSensor(
+        Obd2IntegerSensorIndex::COMMANDED_SECONDARY_AIR_STATUS,
+        toInt(SecondaryAirStatus::FROM_OUTSIDE_OR_OFF));
+    mObd2SensorStore->setIntegerSensor(
+        Obd2IntegerSensorIndex::NUM_OXYGEN_SENSORS_PRESENT, 1);
+    mObd2SensorStore->setIntegerSensor(
+        Obd2IntegerSensorIndex::RUNTIME_SINCE_ENGINE_START, 500);
+    mObd2SensorStore->setIntegerSensor(
+        Obd2IntegerSensorIndex::DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON, 0);
+    mObd2SensorStore->setIntegerSensor(
+        Obd2IntegerSensorIndex::WARMUPS_SINCE_CODES_CLEARED, 51);
+    mObd2SensorStore->setIntegerSensor(
+        Obd2IntegerSensorIndex::DISTANCE_TRAVELED_SINCE_CODES_CLEARED, 365);
+    mObd2SensorStore->setIntegerSensor(
+        Obd2IntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE, 30);
+    mObd2SensorStore->setIntegerSensor(
+        Obd2IntegerSensorIndex::CONTROL_MODULE_VOLTAGE, 12);
+    mObd2SensorStore->setIntegerSensor(
+        Obd2IntegerSensorIndex::AMBIENT_AIR_TEMPERATURE, 18);
+    mObd2SensorStore->setIntegerSensor(
+        Obd2IntegerSensorIndex::MAX_FUEL_AIR_EQUIVALENCE_RATIO, 1);
+    mObd2SensorStore->setIntegerSensor(
+        Obd2IntegerSensorIndex::FUEL_TYPE, toInt(FuelType::GASOLINE));
+    mObd2SensorStore->setFloatSensor(
+        Obd2FloatSensorIndex::CALCULATED_ENGINE_LOAD, 0.153);
+    mObd2SensorStore->setFloatSensor(
+        Obd2FloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK1, -0.16);
+    mObd2SensorStore->setFloatSensor(
+        Obd2FloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK1, -0.16);
+    mObd2SensorStore->setFloatSensor(
+        Obd2FloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK2, -0.16);
+    mObd2SensorStore->setFloatSensor(
+        Obd2FloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK2, -0.16);
+    mObd2SensorStore->setFloatSensor(
+        Obd2FloatSensorIndex::INTAKE_MANIFOLD_ABSOLUTE_PRESSURE, 7.5);
+    mObd2SensorStore->setFloatSensor(
+        Obd2FloatSensorIndex::ENGINE_RPM, 1250.);
+    mObd2SensorStore->setFloatSensor(
+        Obd2FloatSensorIndex::VEHICLE_SPEED, 40.);
+    mObd2SensorStore->setFloatSensor(
+        Obd2FloatSensorIndex::TIMING_ADVANCE, 2.5);
+    mObd2SensorStore->setFloatSensor(
+        Obd2FloatSensorIndex::THROTTLE_POSITION, 19.75);
+    mObd2SensorStore->setFloatSensor(
+        Obd2FloatSensorIndex::OXYGEN_SENSOR1_VOLTAGE, 0.265);
+    mObd2SensorStore->setFloatSensor(
+        Obd2FloatSensorIndex::FUEL_TANK_LEVEL_INPUT, 0.824);
+    mObd2SensorStore->setFloatSensor(
+        Obd2FloatSensorIndex::EVAPORATION_SYSTEM_VAPOR_PRESSURE, -0.373);
+    mObd2SensorStore->setFloatSensor(
+        Obd2FloatSensorIndex::CATALYST_TEMPERATURE_BANK1_SENSOR1, 190.);
+    mObd2SensorStore->setFloatSensor(
+        Obd2FloatSensorIndex::RELATIVE_THROTTLE_POSITION, 3.);
+    mObd2SensorStore->setFloatSensor(
+        Obd2FloatSensorIndex::ABSOLUTE_THROTTLE_POSITION_B, 0.306);
+    mObd2SensorStore->setFloatSensor(
+        Obd2FloatSensorIndex::ACCELERATOR_PEDAL_POSITION_D, 0.188);
+    mObd2SensorStore->setFloatSensor(
+        Obd2FloatSensorIndex::ACCELERATOR_PEDAL_POSITION_E, 0.094);
+    mObd2SensorStore->setFloatSensor(
+        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;
+    }
+    return StatusCode::OK;
+}
+
+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;
+    }
+    return StatusCode::OK;
+}
+
+StatusCode DefaultVehicleHal::getHvacDefroster(int32_t areaId,
+                                               bool* outValue) {
+    ALOGI("Getting Hvac defroster for area: 0x%x", 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;
+    }
+
+    ALOGI("Getting Hvac defroster for area: 0x%x, OK", areaId);
+    return StatusCode::OK;
+}
+
+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;
+    }
+    return StatusCode::OK;
+}
+
+StatusCode DefaultVehicleHal::fillObd2LiveFrame(VehiclePropValuePtr* v) {
+    (*v)->value.int32Values = mObd2SensorStore->getIntegerSensors();
+    (*v)->value.floatValues = mObd2SensorStore->getFloatSensors();
+    (*v)->value.bytes = mObd2SensorStore->getSensorsBitmask();
+    return StatusCode::OK;
+}
+
+StatusCode DefaultVehicleHal::fillObd2FreezeFrame(VehiclePropValuePtr* v) {
+    (*v)->value.int32Values = mObd2SensorStore->getIntegerSensors();
+    (*v)->value.floatValues = mObd2SensorStore->getFloatSensors();
+    (*v)->value.bytes = mObd2SensorStore->getSensorsBitmask();
+    (*v)->value.stringValue = "P0010";
+    return StatusCode::OK;
+}
+
+
+}  // impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.h b/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.h
new file mode 100644
index 0000000..ccedeeb
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/DefaultVehicleHal.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2016 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_DefaultVehicleHal_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_DefaultVehicleHal_H_
+
+#include <memory>
+
+#include <VehicleHal.h>
+#include <impl/DefaultConfig.h>
+#include <vehicle_hal_manager/Obd2SensorStore.h>
+#include <utils/SystemClock.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+class DefaultVehicleHal : public VehicleHal {
+public:
+    std::vector<VehiclePropConfig> listProperties() override {
+        return std::vector<VehiclePropConfig>(std::begin(kVehicleProperties),
+                                              std::end(kVehicleProperties));
+    }
+
+    VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue,
+                            StatusCode* outStatus) override;
+
+    void onCreate() override;
+
+    StatusCode set(const VehiclePropValue& propValue) override;
+
+    StatusCode subscribe(int32_t /*property*/,
+                         int32_t /*areas*/,
+                         float /*sampleRate*/) override {
+        // TODO(pavelm): implement
+        return StatusCode::OK;
+    }
+
+    StatusCode unsubscribe(int32_t /*property*/) override {
+        // TODO(pavelm): implement
+        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);
+    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;
+    std::unique_ptr<Obd2SensorStore> mObd2SensorStore{nullptr};
+};
+
+}  // impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+
+#endif  // android_hardware_automotive_vehicle_V2_0_impl_DefaultVehicleHal_H_
diff --git a/automotive/vehicle/2.0/default/tests/AccessControlConfigParser_test.cpp b/automotive/vehicle/2.0/default/tests/AccessControlConfigParser_test.cpp
new file mode 100644
index 0000000..7c9a4d9
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/AccessControlConfigParser_test.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2016 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 <gtest/gtest.h>
+#include <memory>
+#include <fstream>
+#include <unordered_set>
+
+#include "vehicle_hal_manager/AccessControlConfigParser.h"
+#include <vehicle_hal_manager/VehicleUtils.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace {
+
+class AccessControlConfigParserTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+        std::vector<int32_t> supportedProperties {
+            toInt(VehicleProperty::HVAC_FAN_SPEED),
+            toInt(VehicleProperty::HVAC_FAN_DIRECTION),
+        };
+        parser.reset(new AccessControlConfigParser(supportedProperties));
+    }
+public:
+    PropertyAclMap aclMap;
+    std::unique_ptr<AccessControlConfigParser> parser;
+};
+
+TEST_F(AccessControlConfigParserTest, basicParsing) {
+    std::stringstream file;
+    file << "S:0x0500 1000 RW" << std::endl;
+
+    ASSERT_TRUE(parser->parseFromStream(&file, &aclMap));
+
+    ASSERT_EQ(1, aclMap.size());
+    auto it = aclMap.find(toInt(VehicleProperty::HVAC_FAN_SPEED));
+    ASSERT_NE(aclMap.end(), it);
+    ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, it->second.access);
+    ASSERT_EQ(toInt(VehicleProperty::HVAC_FAN_SPEED), it->second.propId);
+    ASSERT_EQ(1000u, it->second.uid);
+}
+
+TEST_F(AccessControlConfigParserTest, multipleUids) {
+    std::stringstream file;
+    file << "Set AID_AUDIO 1004" << std::endl
+            << "Set AID_SYSTEM 1000" << std::endl
+            << "S:0x0500 AID_SYSTEM RW" << std::endl
+            << "S:0x0500 AID_AUDIO RW" << std::endl
+            << "S:0x0500 0xbeef R" << std::endl;  // Read-only.
+
+    std::unordered_set<unsigned> expectedUids {1000, 1004, 0xbeef};
+
+    ASSERT_TRUE(parser->parseFromStream(&file, &aclMap));
+
+    auto range = aclMap.equal_range(toInt(VehicleProperty::HVAC_FAN_SPEED));
+    for (auto it = range.first; it != range.second; ++it) {
+        auto& acl = it->second;
+
+        ASSERT_EQ(1, expectedUids.count(acl.uid))
+                << " uid: " << std::hex << acl.uid;
+
+        if (acl.uid == 0xbeef) {
+            ASSERT_EQ(VehiclePropertyAccess::READ, acl.access);
+        } else {
+            ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, acl.access);
+        }
+    }
+}
+
+TEST_F(AccessControlConfigParserTest, fileContainsJunk) {
+    std::stringstream file;
+    file << "This string will be ignored with warning in the log" << std::endl
+         << "# However comments are quit legitimate" << std::endl
+         << "S:0x0500 0xbeef R # YAY" << std::endl;
+
+    ASSERT_FALSE(parser->parseFromStream(&file, &aclMap));
+
+    ASSERT_EQ(1, aclMap.size());
+    auto it = aclMap.find(toInt(VehicleProperty::HVAC_FAN_SPEED));
+    ASSERT_NE(aclMap.end(), it);
+    ASSERT_EQ(VehiclePropertyAccess::READ, it->second.access);
+    ASSERT_EQ(toInt(VehicleProperty::HVAC_FAN_SPEED), it->second.propId);
+    ASSERT_EQ(0xbeef, it->second.uid);
+}
+
+TEST_F(AccessControlConfigParserTest, badIntegerFormat) {
+    std::stringstream file;
+    file << "S:0x0500 A12 RW " << std::endl;
+
+    ASSERT_FALSE(parser->parseFromStream(&file, &aclMap));
+    ASSERT_EQ(0, aclMap.size());
+}
+
+TEST_F(AccessControlConfigParserTest, ignoreNotSupportedProperties) {
+    std::stringstream file;
+    file << "S:0x0666 1000 RW " << std::endl;
+
+    ASSERT_FALSE(parser->parseFromStream(&file, &aclMap));
+    ASSERT_EQ(0, aclMap.size());
+}
+
+TEST_F(AccessControlConfigParserTest, multipleCalls) {
+    std::stringstream configFile;
+    configFile << "S:0x0500 1000 RW" << std::endl;
+
+    ASSERT_TRUE(parser->parseFromStream(&configFile, &aclMap));
+    ASSERT_EQ(1, aclMap.size());
+
+    std::stringstream configFile2;
+    configFile2 << "S:0x0501 1004 RW" << std::endl;
+    ASSERT_TRUE(parser->parseFromStream(&configFile2, &aclMap));
+    ASSERT_EQ(2, aclMap.size());
+
+    auto it = aclMap.find(toInt(VehicleProperty::HVAC_FAN_SPEED));
+    ASSERT_NE(aclMap.end(), it);
+    ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, it->second.access);
+    ASSERT_EQ(toInt(VehicleProperty::HVAC_FAN_SPEED), it->second.propId);
+    ASSERT_EQ(1000u, it->second.uid);
+
+    it = aclMap.find(toInt(VehicleProperty::HVAC_FAN_DIRECTION));
+    ASSERT_NE(aclMap.end(), it);
+    ASSERT_EQ(VehiclePropertyAccess::READ_WRITE, it->second.access);
+    ASSERT_EQ(toInt(VehicleProperty::HVAC_FAN_DIRECTION), it->second.propId);
+    ASSERT_EQ(1004u, it->second.uid);
+}
+
+
+}  // namespace anonymous
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/tests/Obd2SensorStore_test.cpp b/automotive/vehicle/2.0/default/tests/Obd2SensorStore_test.cpp
new file mode 100644
index 0000000..3ebebbd
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/Obd2SensorStore_test.cpp
@@ -0,0 +1,285 @@
+/*
+ * 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.
+ */
+
+ #include <gtest/gtest.h>
+
+#include "vehicle_hal_manager/Obd2SensorStore.h"
+#include "vehicle_hal_manager/VehicleUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace {
+
+static constexpr size_t getNumVendorIntegerSensors() {
+    return 5;
+}
+static constexpr size_t getNumVendorFloatSensors() {
+    return 3;
+}
+
+// this struct holds information necessary for a test to be able to validate
+// that the sensor bitmask contains the right data:
+//   - the index of the byte at which the bit for a given sensor lives
+//   - the expected value of that byte given that a certain sensor is present
+class BitmaskIndexingInfo {
+public:
+    size_t mByteIndex;
+    uint8_t mExpectedByteValue;
+
+    // Returns the information required to validate the bitmask for an
+    // integer-valued sensor.
+    static BitmaskIndexingInfo getForIntegerSensor(size_t index) {
+        const size_t indexInBitstream = index;
+        return getForBitstreamIndex(indexInBitstream);
+    }
+
+    // Returns the information required to validate the bitmask for a
+    // float-valued sensor.
+    static BitmaskIndexingInfo getForFloatSensor(size_t index) {
+        const size_t indexInBitstream = toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX) +
+                                        1 + getNumVendorIntegerSensors() + index;
+        return getForBitstreamIndex(indexInBitstream);
+    }
+
+private:
+    static BitmaskIndexingInfo getForBitstreamIndex(size_t indexInBitstream) {
+        BitmaskIndexingInfo indexingInfo;
+        indexingInfo.mByteIndex = indexInBitstream / 8;
+        indexingInfo.mExpectedByteValue = 1 << (indexInBitstream % 8);
+        return indexingInfo;
+    }
+};
+
+static Obd2SensorStore getSensorStore() {
+    return Obd2SensorStore(getNumVendorIntegerSensors(),
+                           getNumVendorFloatSensors());
+}
+
+// Test that one can set and retrieve a value for the first integer sensor.
+TEST(Obd2SensorStoreTest, setFirstIntegerSensor) {
+    Obd2SensorStore sensorStore(getSensorStore());
+    sensorStore.setIntegerSensor(
+        Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS,
+        toInt(FuelSystemStatus::CLOSED_LOOP));
+    const auto& integerSensors(sensorStore.getIntegerSensors());
+    const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+    ASSERT_EQ(
+        toInt(FuelSystemStatus::CLOSED_LOOP),
+        integerSensors[toInt(Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS)]);
+    const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForIntegerSensor(
+        toInt(Obd2IntegerSensorIndex::FUEL_SYSTEM_STATUS)));
+    ASSERT_EQ(
+        indexingInfo.mExpectedByteValue,
+        sensorBitmask[indexingInfo.mByteIndex]);
+}
+
+// Test that one can set and retrieve a value for the first float sensor.
+TEST(Obd2SensorStoreTest, setFirstFloatSensor) {
+    Obd2SensorStore sensorStore(getSensorStore());
+    sensorStore.setFloatSensor(
+        Obd2FloatSensorIndex::CALCULATED_ENGINE_LOAD,
+        1.25f);
+    const auto& floatSensors(sensorStore.getFloatSensors());
+    const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+    ASSERT_EQ(
+        1.25f,
+        floatSensors[toInt(Obd2FloatSensorIndex::CALCULATED_ENGINE_LOAD)]);
+    const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForFloatSensor(
+        toInt(Obd2FloatSensorIndex::CALCULATED_ENGINE_LOAD)));
+    ASSERT_EQ(
+        indexingInfo.mExpectedByteValue,
+        sensorBitmask[indexingInfo.mByteIndex]);
+}
+
+// Test that one can set and retrieve a value for an integer sensor.
+TEST(Obd2SensorStoreTest, setAnyIntegerSensor) {
+    Obd2SensorStore sensorStore(getSensorStore());
+    sensorStore.setIntegerSensor(
+        Obd2IntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE,
+        4000);
+    const auto& integerSensors(sensorStore.getIntegerSensors());
+    const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+    ASSERT_EQ(4000,
+        integerSensors[toInt(Obd2IntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE)]);
+    const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForIntegerSensor(
+        toInt(Obd2IntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE)));
+    ASSERT_EQ(
+        indexingInfo.mExpectedByteValue,
+        sensorBitmask[indexingInfo.mByteIndex]);
+}
+
+// Test that one can set and retrieve a value for a float sensor.
+TEST(Obd2SensorStoreTest, setAnyFloatSensor) {
+    Obd2SensorStore sensorStore(getSensorStore());
+    sensorStore.setFloatSensor(
+        Obd2FloatSensorIndex::OXYGEN_SENSOR3_VOLTAGE,
+        2.5f);
+    const auto& floatSensors(sensorStore.getFloatSensors());
+    const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+    ASSERT_EQ(2.5f,
+        floatSensors[toInt(Obd2FloatSensorIndex::OXYGEN_SENSOR3_VOLTAGE)]);
+    const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForFloatSensor(
+        toInt(Obd2FloatSensorIndex::OXYGEN_SENSOR3_VOLTAGE)));
+    ASSERT_EQ(
+        indexingInfo.mExpectedByteValue,
+        sensorBitmask[indexingInfo.mByteIndex]);
+}
+
+// Test that one can set and retrieve a value for the last system integer sensor.
+TEST(Obd2SensorStoreTest, setLastSystemIntegerSensor) {
+    Obd2SensorStore sensorStore(getSensorStore());
+    sensorStore.setIntegerSensor(
+        Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX,
+        30);
+    const auto& integerSensors(sensorStore.getIntegerSensors());
+    const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+    ASSERT_EQ(30,
+        integerSensors[toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX)]);
+    const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForIntegerSensor(
+        toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX)));
+    ASSERT_EQ(
+        indexingInfo.mExpectedByteValue,
+        sensorBitmask[indexingInfo.mByteIndex]);
+}
+
+// Test that one can set and retrieve a value for the last system float sensor.
+TEST(Obd2SensorStoreTest, setLastSystemFloatSensor) {
+    Obd2SensorStore sensorStore(getSensorStore());
+    sensorStore.setFloatSensor(
+        Obd2FloatSensorIndex::LAST_SYSTEM_INDEX,
+        2.5f);
+    const auto& floatSensors(sensorStore.getFloatSensors());
+    const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+    ASSERT_EQ(2.5f,
+        floatSensors[toInt(Obd2FloatSensorIndex::LAST_SYSTEM_INDEX)]);
+    const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForFloatSensor(
+        toInt(Obd2FloatSensorIndex::LAST_SYSTEM_INDEX)));
+    ASSERT_EQ(
+        indexingInfo.mExpectedByteValue,
+        sensorBitmask[indexingInfo.mByteIndex]);
+}
+
+// Test that one can set and retrieve a value for two integer sensors at once.
+TEST(Obd2SensorStoreTest, setTwoIntegerSensors) {
+    Obd2SensorStore sensorStore(getSensorStore());
+    sensorStore.setIntegerSensor(
+        Obd2IntegerSensorIndex::CONTROL_MODULE_VOLTAGE,
+        6);
+    sensorStore.setIntegerSensor(
+        Obd2IntegerSensorIndex::TIME_SINCE_TROUBLE_CODES_CLEARED,
+        1245);
+    const auto& integerSensors(sensorStore.getIntegerSensors());
+    const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+    ASSERT_EQ(6,
+        integerSensors[toInt(Obd2IntegerSensorIndex::CONTROL_MODULE_VOLTAGE)]);
+    ASSERT_EQ(1245,
+        integerSensors[toInt(Obd2IntegerSensorIndex::TIME_SINCE_TROUBLE_CODES_CLEARED)]);
+    const BitmaskIndexingInfo voltageIndexingInfo(BitmaskIndexingInfo::getForIntegerSensor(
+        toInt(Obd2IntegerSensorIndex::CONTROL_MODULE_VOLTAGE)));
+    const BitmaskIndexingInfo timeIndexingInfo(BitmaskIndexingInfo::getForIntegerSensor(
+        toInt(Obd2IntegerSensorIndex::TIME_SINCE_TROUBLE_CODES_CLEARED)));
+    if (voltageIndexingInfo.mByteIndex == timeIndexingInfo.mByteIndex) {
+        ASSERT_EQ(
+            voltageIndexingInfo.mExpectedByteValue |
+            timeIndexingInfo.mExpectedByteValue,
+            sensorBitmask[timeIndexingInfo.mByteIndex]);
+    }
+    else {
+        ASSERT_EQ(
+            timeIndexingInfo.mExpectedByteValue,
+            sensorBitmask[timeIndexingInfo.mByteIndex]);
+        ASSERT_EQ(
+            voltageIndexingInfo.mExpectedByteValue,
+            sensorBitmask[voltageIndexingInfo.mByteIndex]);
+    }
+}
+
+// Test that one can set and retrieve a value for two float sensors at once.
+TEST(Obd2SensorStoreTest, setTwoFloatSensors) {
+    Obd2SensorStore sensorStore(getSensorStore());
+    sensorStore.setFloatSensor(
+        Obd2FloatSensorIndex::VEHICLE_SPEED,
+        1.25f);
+    sensorStore.setFloatSensor(
+        Obd2FloatSensorIndex::MAF_AIR_FLOW_RATE,
+        2.5f);
+    const auto& floatSensors(sensorStore.getFloatSensors());
+    const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+    ASSERT_EQ(1.25f,
+        floatSensors[toInt(Obd2FloatSensorIndex::VEHICLE_SPEED)]);
+    ASSERT_EQ(2.5f,
+        floatSensors[toInt(Obd2FloatSensorIndex::MAF_AIR_FLOW_RATE)]);
+    const BitmaskIndexingInfo speedIndexingInfo(BitmaskIndexingInfo::getForFloatSensor(
+        toInt(Obd2FloatSensorIndex::VEHICLE_SPEED)));
+    const BitmaskIndexingInfo airflowIndexingInfo(BitmaskIndexingInfo::getForFloatSensor(
+        toInt(Obd2FloatSensorIndex::MAF_AIR_FLOW_RATE)));
+    if (speedIndexingInfo.mByteIndex == airflowIndexingInfo.mByteIndex) {
+        ASSERT_EQ(
+            speedIndexingInfo.mExpectedByteValue |
+            airflowIndexingInfo.mExpectedByteValue,
+            sensorBitmask[airflowIndexingInfo.mByteIndex]);
+    }
+    else {
+        ASSERT_EQ(
+            speedIndexingInfo.mExpectedByteValue,
+            sensorBitmask[speedIndexingInfo.mByteIndex]);
+        ASSERT_EQ(
+            airflowIndexingInfo.mExpectedByteValue,
+            sensorBitmask[airflowIndexingInfo.mByteIndex]);
+    }
+}
+
+// Test that one can set and retrieve a value for a vendor integer sensor.
+TEST(Obd2SensorStoreTest, setVendorIntegerSensor) {
+    const size_t sensorIndex = toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX) + 2;
+    Obd2SensorStore sensorStore(getSensorStore());
+    sensorStore.setIntegerSensor(sensorIndex, 22);
+    const auto& integerSensors(sensorStore.getIntegerSensors());
+    const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+    ASSERT_EQ(22, integerSensors[sensorIndex]);
+    const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForIntegerSensor(
+        sensorIndex));
+    ASSERT_EQ(
+        indexingInfo.mExpectedByteValue,
+        sensorBitmask[indexingInfo.mByteIndex]);
+}
+
+// Test that one can set and retrieve a value for a vendor float sensor.
+TEST(Obd2SensorStoreTest, setVendorFloatSensor) {
+    const size_t sensorIndex = toInt(Obd2FloatSensorIndex::LAST_SYSTEM_INDEX) + 2;
+    Obd2SensorStore sensorStore(getSensorStore());
+    sensorStore.setFloatSensor(sensorIndex, 1.25f);
+    const auto& floatSensors(sensorStore.getFloatSensors());
+    const auto& sensorBitmask(sensorStore.getSensorsBitmask());
+    ASSERT_EQ(1.25f, floatSensors[sensorIndex]);
+    const BitmaskIndexingInfo indexingInfo(BitmaskIndexingInfo::getForFloatSensor(
+        sensorIndex));
+    ASSERT_EQ(
+        indexingInfo.mExpectedByteValue,
+        sensorBitmask[indexingInfo.mByteIndex]);
+}
+
+}  // namespace anonymous
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp b/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
new file mode 100644
index 0000000..c6c6add
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2016 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 <unordered_map>
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+#include "vehicle_hal_manager/SubscriptionManager.h"
+
+#include "VehicleHalTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace {
+
+using namespace std::placeholders;
+
+class SubscriptionManagerTest : public ::testing::Test {
+public:
+    SubscriptionManager manager;
+
+    static constexpr int32_t PROP1 = toInt(VehicleProperty::HVAC_FAN_SPEED);
+    static constexpr int32_t PROP2 = toInt(VehicleProperty::DISPLAY_BRIGHTNESS);
+
+    sp<IVehicleCallback> cb1 = new MockedVehicleCallback();
+    sp<IVehicleCallback> cb2 = new MockedVehicleCallback();
+    sp<IVehicleCallback> cb3 = new MockedVehicleCallback();
+
+    hidl_vec<SubscribeOptions> subscrToProp1 = {
+        SubscribeOptions {
+            .propId = PROP1,
+            .vehicleAreas = toInt(VehicleAreaZone::ROW_1_LEFT),
+            .flags = SubscribeFlags::HAL_EVENT
+        },
+    };
+
+    hidl_vec<SubscribeOptions> subscrToProp2 = {
+        SubscribeOptions {
+            .propId = PROP2,
+            .flags = SubscribeFlags::HAL_EVENT
+        },
+    };
+
+    hidl_vec<SubscribeOptions> subscrToProp1and2 = {
+        SubscribeOptions {
+            .propId = PROP1,
+            .vehicleAreas = toInt(VehicleAreaZone::ROW_1_LEFT),
+            .flags = SubscribeFlags::HAL_EVENT
+        },
+        SubscribeOptions {
+            .propId = PROP2,
+            .flags = SubscribeFlags::HAL_EVENT
+        },
+    };
+
+    static std::list<sp<IVehicleCallback>> extractCallbacks(
+            const std::list<sp<HalClient>>& clients) {
+        std::list<sp<IVehicleCallback>> callbacks;
+        for (auto c : clients) {
+            callbacks.push_back(c->getCallback());
+        }
+        return callbacks;
+    }
+
+    std::list<sp<HalClient>> clientsToProp1() {
+        return manager.getSubscribedClients(PROP1,
+                                            toInt(VehicleAreaZone::ROW_1_LEFT),
+                                            SubscribeFlags::DEFAULT);
+    }
+
+    std::list<sp<HalClient>> clientsToProp2() {
+        return manager.getSubscribedClients(PROP2, 0,
+                                            SubscribeFlags::DEFAULT);
+    }
+};
+
+
+TEST_F(SubscriptionManagerTest, multipleClients) {
+    manager.addOrUpdateSubscription(cb1, subscrToProp1);
+    manager.addOrUpdateSubscription(cb2, subscrToProp1);
+
+    auto clients = manager.getSubscribedClients(
+            PROP1,
+            toInt(VehicleAreaZone::ROW_1_LEFT),
+            SubscribeFlags::HAL_EVENT);
+
+    ASSERT_ALL_EXISTS({cb1, cb2}, extractCallbacks(clients));
+}
+
+TEST_F(SubscriptionManagerTest, negativeCases) {
+    manager.addOrUpdateSubscription(cb1, subscrToProp1);
+
+    // Wrong zone
+    auto clients = manager.getSubscribedClients(
+            PROP1,
+            toInt(VehicleAreaZone::ROW_2_LEFT),
+            SubscribeFlags::HAL_EVENT);
+    ASSERT_TRUE(clients.empty());
+
+    // Wrong prop
+    clients = manager.getSubscribedClients(
+            toInt(VehicleProperty::AP_POWER_BOOTUP_REASON),
+            toInt(VehicleAreaZone::ROW_1_LEFT),
+            SubscribeFlags::HAL_EVENT);
+    ASSERT_TRUE(clients.empty());
+
+    // Wrong flag
+    clients = manager.getSubscribedClients(
+            PROP1,
+            toInt(VehicleAreaZone::ROW_1_LEFT),
+            SubscribeFlags::SET_CALL);
+    ASSERT_TRUE(clients.empty());
+}
+
+TEST_F(SubscriptionManagerTest, mulipleSubscriptions) {
+    manager.addOrUpdateSubscription(cb1, subscrToProp1);
+
+    auto clients = manager.getSubscribedClients(
+            PROP1,
+            toInt(VehicleAreaZone::ROW_1_LEFT),
+            SubscribeFlags::DEFAULT);
+    ASSERT_EQ((size_t) 1, clients.size());
+    ASSERT_EQ(cb1, clients.front()->getCallback());
+
+    // Same property, but different zone, to make sure we didn't unsubscribe
+    // from previous zone.
+    manager.addOrUpdateSubscription(cb1, {
+        SubscribeOptions {
+                .propId = PROP1,
+                .vehicleAreas = toInt(VehicleAreaZone::ROW_2),
+                .flags = SubscribeFlags::DEFAULT
+            }
+        });
+
+    clients = manager.getSubscribedClients(PROP1,
+                                           toInt(VehicleAreaZone::ROW_1_LEFT),
+                                           SubscribeFlags::DEFAULT);
+    ASSERT_ALL_EXISTS({cb1}, extractCallbacks(clients));
+
+    clients = manager.getSubscribedClients(PROP1,
+                                           toInt(VehicleAreaZone::ROW_2),
+                                           SubscribeFlags::DEFAULT);
+    ASSERT_ALL_EXISTS({cb1}, extractCallbacks(clients));
+}
+
+TEST_F(SubscriptionManagerTest, unsubscribe) {
+    manager.addOrUpdateSubscription(cb1, subscrToProp1);
+    manager.addOrUpdateSubscription(cb2, subscrToProp2);
+    manager.addOrUpdateSubscription(cb3, subscrToProp1and2);
+
+    ASSERT_ALL_EXISTS({cb1, cb3}, extractCallbacks(clientsToProp1()));
+    ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2()));
+
+    ASSERT_FALSE(manager.unsubscribe(cb1, PROP1));
+    ASSERT_ALL_EXISTS({cb3}, extractCallbacks(clientsToProp1()));
+
+    // Make sure nothing changed in PROP2 so far.
+    ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2()));
+
+    // No one subscribed to PROP1, subscription for PROP2 is not affected.
+    ASSERT_TRUE(manager.unsubscribe(cb3, PROP1));
+    ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2()));
+
+    ASSERT_FALSE(manager.unsubscribe(cb3, PROP2));
+    ASSERT_ALL_EXISTS({cb2}, extractCallbacks(clientsToProp2()));
+
+    // The last client unsubscribed from this property.
+    ASSERT_TRUE(manager.unsubscribe(cb2, PROP2));
+
+    // No one was subscribed, return false.
+    ASSERT_FALSE(manager.unsubscribe(cb1, PROP1));
+}
+
+}  // namespace anonymous
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
new file mode 100644
index 0000000..1ca5824
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 2016 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 <unordered_map>
+#include <iostream>
+
+#include <utils/SystemClock.h>
+
+#include <gtest/gtest.h>
+
+#include "vehicle_hal_manager/VehicleHalManager.h"
+
+#include "VehicleHalTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace {
+
+using namespace std::placeholders;
+
+constexpr char kCarMake[] = "Default Car";
+constexpr int kRetriablePropMockedAttempts = 3;
+
+class MockedVehicleHal : public VehicleHal {
+public:
+    MockedVehicleHal() {
+        mConfigs.assign(std::begin(kVehicleProperties),
+                        std::end(kVehicleProperties));
+    }
+
+    std::vector<VehiclePropConfig> listProperties() override {
+        return mConfigs;
+    }
+
+    VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue,
+             StatusCode* outStatus) override {
+        *outStatus = StatusCode::OK;
+        VehiclePropValuePtr pValue;
+        auto property = static_cast<VehicleProperty>(requestedPropValue.prop);
+        int32_t areaId = requestedPropValue.areaId;
+
+        switch (property) {
+            case VehicleProperty::INFO_MAKE:
+                pValue = getValuePool()->obtainString(kCarMake);
+                break;
+            case VehicleProperty::INFO_FUEL_CAPACITY:
+                if (fuelCapacityAttemptsLeft-- > 0) {
+                    // Emulate property not ready yet.
+                    *outStatus = StatusCode::TRY_AGAIN;
+                } else {
+                    pValue = getValuePool()->obtainFloat(42.42);
+                }
+                break;
+            case VehicleProperty::VEHICLE_MAP_SERVICE:
+                pValue = getValuePool()->obtainComplex();
+                pValue->value.int32Values = hidl_vec<int32_t> { 10, 20 };
+                pValue->value.int64Values = hidl_vec<int64_t> { 30, 40 };
+                pValue->value.floatValues = hidl_vec<float_t> { 1.1, 2.2 };
+                pValue->value.bytes = hidl_vec<uint8_t> { 1, 2, 3 };
+                pValue->value.stringValue = kCarMake;
+                break;
+            default:
+                auto key = makeKey(toInt(property), areaId);
+                if (mValues.count(key) == 0) {
+                    ALOGW("");
+                }
+                pValue = getValuePool()->obtain(mValues[key]);
+        }
+
+        if (*outStatus == StatusCode::OK && pValue.get() != nullptr) {
+            pValue->prop = toInt(property);
+            pValue->areaId = areaId;
+            pValue->timestamp = elapsedRealtimeNano();
+        }
+
+        return pValue;
+    }
+
+    StatusCode set(const VehiclePropValue& propValue) override {
+        if (toInt(VehicleProperty::MIRROR_FOLD) == propValue.prop
+                && mirrorFoldAttemptsLeft-- > 0) {
+            return StatusCode::TRY_AGAIN;
+        }
+
+        mValues[makeKey(propValue)] = propValue;
+        return StatusCode::OK;
+    }
+
+    StatusCode subscribe(int32_t property,
+                         int32_t areas,
+                         float sampleRate) override {
+        return StatusCode::OK;
+    }
+
+    StatusCode unsubscribe(int32_t property) override {
+        return StatusCode::OK;
+    }
+
+    void sendPropEvent(recyclable_ptr<VehiclePropValue> value) {
+        doHalEvent(std::move(value));
+    }
+
+    void sendHalError(StatusCode error, int32_t property, int32_t areaId) {
+        doHalPropertySetError(error, property, areaId);
+    }
+
+public:
+    int fuelCapacityAttemptsLeft = kRetriablePropMockedAttempts;
+    int mirrorFoldAttemptsLeft = kRetriablePropMockedAttempts;
+
+private:
+    int64_t makeKey(const VehiclePropValue& v) const {
+        return makeKey(v.prop, v.areaId);
+    }
+
+    int64_t makeKey(int32_t prop, int32_t area) const {
+        return (static_cast<int64_t>(prop) << 32) | area;
+    }
+
+private:
+    std::vector<VehiclePropConfig> mConfigs;
+    std::unordered_map<int64_t, VehiclePropValue> mValues;
+};
+
+class VehicleHalManagerTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+        hal.reset(new MockedVehicleHal);
+        manager.reset(new VehicleHalManager(hal.get()));
+
+        objectPool = hal->getValuePool();
+    }
+
+    void TearDown() override {
+        manager.reset(nullptr);
+        hal.reset(nullptr);
+    }
+public:
+    void invokeGet(int32_t property, int32_t areaId) {
+        VehiclePropValue requestedValue {};
+        requestedValue.prop = property;
+        requestedValue.areaId = areaId;
+
+        invokeGet(requestedValue);
+    }
+
+    void invokeGet(const VehiclePropValue& requestedPropValue) {
+        actualValue = VehiclePropValue {};  // reset previous values
+
+        StatusCode refStatus;
+        VehiclePropValue refValue;
+        bool called = false;
+        manager->get(requestedPropValue, [&refStatus, &refValue, &called]
+            (StatusCode status, const VehiclePropValue& value) {
+            refStatus = status;
+            refValue = value;
+            called = true;
+        });
+        ASSERT_TRUE(called) << "callback wasn't called for prop: "
+                            << hexString(requestedPropValue.prop);
+
+        actualValue = refValue;
+        actualStatusCode = refStatus;
+    }
+
+public:
+    VehiclePropValue actualValue;
+    StatusCode actualStatusCode;
+
+    VehiclePropValuePool* objectPool;
+    std::unique_ptr<MockedVehicleHal> hal;
+    std::unique_ptr<VehicleHalManager> manager;
+};
+
+TEST_F(VehicleHalManagerTest, getPropConfigs) {
+    hidl_vec<int32_t> properties =
+        { toInt(VehicleProperty::HVAC_FAN_SPEED),
+          toInt(VehicleProperty::INFO_MAKE) };
+    bool called = false;
+
+    manager->getPropConfigs(properties,
+            [&called] (StatusCode status,
+                       const hidl_vec<VehiclePropConfig>& c) {
+        ASSERT_EQ(StatusCode::OK, status);
+        ASSERT_EQ(2u, c.size());
+        called = true;
+    });
+
+    ASSERT_TRUE(called);  // Verify callback received.
+
+    called = false;
+    manager->getPropConfigs({ toInt(VehicleProperty::HVAC_FAN_SPEED) },
+            [&called] (StatusCode status,
+                       const hidl_vec<VehiclePropConfig>& c) {
+        ASSERT_EQ(StatusCode::OK, status);
+        ASSERT_EQ(1u, c.size());
+        ASSERT_EQ(toString(kVehicleProperties[1]), toString(c[0]));
+        called = true;
+    });
+    ASSERT_TRUE(called);  // Verify callback received.
+
+    // TODO(pavelm): add case case when property was not declared.
+}
+
+TEST_F(VehicleHalManagerTest, getAllPropConfigs) {
+    bool called = false;
+    manager->getAllPropConfigs(
+            [&called] (const hidl_vec<VehiclePropConfig>& propConfigs) {
+        ASSERT_EQ(arraysize(kVehicleProperties), propConfigs.size());
+
+        for (size_t i = 0; i < propConfigs.size(); i++) {
+            ASSERT_EQ(toString(kVehicleProperties[i]),
+                      toString(propConfigs[i]));
+        }
+        called = true;
+    });
+    ASSERT_TRUE(called);  // Verify callback received.
+}
+
+TEST_F(VehicleHalManagerTest, halErrorEvent) {
+    const auto PROP = toInt(VehicleProperty::DISPLAY_BRIGHTNESS);
+
+    sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
+
+    hidl_vec<SubscribeOptions> options = {
+        SubscribeOptions {
+            .propId = PROP,
+            .flags = SubscribeFlags::DEFAULT
+        },
+    };
+
+    StatusCode res = manager->subscribe(cb, options);
+    ASSERT_EQ(StatusCode::OK, res);
+
+    hal->sendHalError(StatusCode::TRY_AGAIN, PROP, 0 /* area id*/);
+}
+
+TEST_F(VehicleHalManagerTest, subscribe) {
+    const auto PROP = toInt(VehicleProperty::DISPLAY_BRIGHTNESS);
+
+    sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
+
+    hidl_vec<SubscribeOptions> options = {
+        SubscribeOptions {
+            .propId = PROP,
+            .flags = SubscribeFlags::DEFAULT
+        }
+    };
+
+    StatusCode res = manager->subscribe(cb, options);
+    ASSERT_EQ(StatusCode::OK, res);
+
+    auto unsubscribedValue = objectPool->obtain(VehiclePropertyType::INT32);
+    unsubscribedValue->prop = toInt(VehicleProperty::HVAC_FAN_SPEED);
+
+    hal->sendPropEvent(std::move(unsubscribedValue));
+    auto& receivedEnvents = cb->getReceivedEvents();
+
+    ASSERT_TRUE(cb->waitForExpectedEvents(0)) << " Unexpected events received: "
+                                              << receivedEnvents.size()
+                                              << (receivedEnvents.size() > 0
+                                                  ? toString(receivedEnvents.front()[0]) : "");
+
+    auto subscribedValue = objectPool->obtain(VehiclePropertyType::INT32);
+    subscribedValue->prop = PROP;
+    subscribedValue->value.int32Values[0] = 42;
+
+    cb->reset();
+    VehiclePropValue actualValue(*subscribedValue.get());
+    hal->sendPropEvent(std::move(subscribedValue));
+
+    ASSERT_TRUE(cb->waitForExpectedEvents(1)) << "Events received: "
+                                              << receivedEnvents.size();
+
+    ASSERT_EQ(toString(actualValue),
+              toString(cb->getReceivedEvents().front()[0]));
+}
+
+TEST_F(VehicleHalManagerTest, subscribe_WriteOnly) {
+    const auto PROP = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE);
+
+    sp<MockedVehicleCallback> cb = new MockedVehicleCallback();
+
+    hidl_vec<SubscribeOptions> options = {
+        SubscribeOptions {
+            .propId = PROP,
+            .flags = SubscribeFlags::HAL_EVENT
+        },
+    };
+
+    StatusCode res = manager->subscribe(cb, options);
+    // Unable to subscribe on Hal Events for write-only properties.
+    ASSERT_EQ(StatusCode::INVALID_ARG, res);
+
+
+    options[0].flags = SubscribeFlags::SET_CALL;
+
+    res = manager->subscribe(cb, options);
+    // OK to subscribe on SET method call for write-only properties.
+    ASSERT_EQ(StatusCode::OK, res);
+}
+
+TEST_F(VehicleHalManagerTest, get_Complex) {
+    invokeGet(toInt(VehicleProperty::VEHICLE_MAP_SERVICE), 0);
+
+    ASSERT_EQ(StatusCode::OK, actualStatusCode);
+    ASSERT_EQ(toInt(VehicleProperty::VEHICLE_MAP_SERVICE), actualValue.prop);
+
+    ASSERT_EQ(3, actualValue.value.bytes.size());
+    ASSERT_EQ(1, actualValue.value.bytes[0]);
+    ASSERT_EQ(2, actualValue.value.bytes[1]);
+    ASSERT_EQ(3, actualValue.value.bytes[2]);
+
+    ASSERT_EQ(2, actualValue.value.int32Values.size());
+    ASSERT_EQ(10, actualValue.value.int32Values[0]);
+    ASSERT_EQ(20, actualValue.value.int32Values[1]);
+
+    ASSERT_EQ(2, actualValue.value.floatValues.size());
+    ASSERT_FLOAT_EQ(1.1, actualValue.value.floatValues[0]);
+    ASSERT_FLOAT_EQ(2.2, actualValue.value.floatValues[1]);
+
+    ASSERT_EQ(2, actualValue.value.int64Values.size());
+    ASSERT_FLOAT_EQ(30, actualValue.value.int64Values[0]);
+    ASSERT_FLOAT_EQ(40, actualValue.value.int64Values[1]);
+
+    ASSERT_STREQ(kCarMake, actualValue.value.stringValue.c_str());
+}
+
+TEST_F(VehicleHalManagerTest, get_StaticString) {
+    invokeGet(toInt(VehicleProperty::INFO_MAKE), 0);
+
+    ASSERT_EQ(StatusCode::OK, actualStatusCode);
+    ASSERT_EQ(toInt(VehicleProperty::INFO_MAKE), actualValue.prop);
+    ASSERT_STREQ(kCarMake, actualValue.value.stringValue.c_str());
+}
+
+TEST_F(VehicleHalManagerTest, get_NegativeCases) {
+    // Write-only property must fail.
+    invokeGet(toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE), 0);
+    ASSERT_EQ(StatusCode::ACCESS_DENIED, actualStatusCode);
+
+    // Unknown property must fail.
+    invokeGet(toInt(VehicleProperty::MIRROR_Z_MOVE), 0);
+    ASSERT_EQ(StatusCode::INVALID_ARG, actualStatusCode);
+}
+
+TEST_F(VehicleHalManagerTest, get_Retriable) {
+    actualStatusCode = StatusCode::TRY_AGAIN;
+    int attempts = 0;
+    while (StatusCode::TRY_AGAIN == actualStatusCode && ++attempts < 10) {
+        invokeGet(toInt(VehicleProperty::INFO_FUEL_CAPACITY), 0);
+
+    }
+    ASSERT_EQ(StatusCode::OK, actualStatusCode);
+    ASSERT_EQ(kRetriablePropMockedAttempts + 1, attempts);
+    ASSERT_FLOAT_EQ(42.42, actualValue.value.floatValues[0]);
+}
+
+TEST_F(VehicleHalManagerTest, set_Basic) {
+    const auto PROP = toInt(VehicleProperty::DISPLAY_BRIGHTNESS);
+    const auto VAL = 7;
+
+    auto expectedValue = hal->getValuePool()->obtainInt32(VAL);
+    expectedValue->prop = PROP;
+    expectedValue->areaId = 0;
+
+    actualStatusCode = manager->set(*expectedValue.get());
+    ASSERT_EQ(StatusCode::OK, actualStatusCode);
+
+    invokeGet(PROP, 0);
+    ASSERT_EQ(StatusCode::OK, actualStatusCode);
+    ASSERT_EQ(PROP, actualValue.prop);
+    ASSERT_EQ(VAL, actualValue.value.int32Values[0]);
+}
+
+TEST_F(VehicleHalManagerTest, set_DifferentAreas) {
+    const auto PROP = toInt(VehicleProperty::HVAC_FAN_SPEED);
+    const auto VAL1 = 1;
+    const auto VAL2 = 2;
+    const auto AREA1 = toInt(VehicleAreaZone::ROW_1_LEFT);
+    const auto AREA2 = toInt(VehicleAreaZone::ROW_1_RIGHT);
+
+    {
+        auto expectedValue1 = hal->getValuePool()->obtainInt32(VAL1);
+        expectedValue1->prop = PROP;
+        expectedValue1->areaId = AREA1;
+        actualStatusCode = manager->set(*expectedValue1.get());
+        ASSERT_EQ(StatusCode::OK, actualStatusCode);
+
+        auto expectedValue2 = hal->getValuePool()->obtainInt32(VAL2);
+        expectedValue2->prop = PROP;
+        expectedValue2->areaId = AREA2;
+        actualStatusCode = manager->set(*expectedValue2.get());
+        ASSERT_EQ(StatusCode::OK, actualStatusCode);
+    }
+
+    {
+        invokeGet(PROP, AREA1);
+        ASSERT_EQ(StatusCode::OK, actualStatusCode);
+        ASSERT_EQ(PROP, actualValue.prop);
+        ASSERT_EQ(AREA1, actualValue.areaId);
+        ASSERT_EQ(VAL1, actualValue.value.int32Values[0]);
+
+        invokeGet(PROP, AREA2);
+        ASSERT_EQ(StatusCode::OK, actualStatusCode);
+        ASSERT_EQ(PROP, actualValue.prop);
+        ASSERT_EQ(AREA2, actualValue.areaId);
+        ASSERT_EQ(VAL2, actualValue.value.int32Values[0]);
+    }
+}
+
+TEST_F(VehicleHalManagerTest, set_Retriable) {
+    const auto PROP = toInt(VehicleProperty::MIRROR_FOLD);
+
+    auto v = hal->getValuePool()->obtainBoolean(true);
+    v->prop = PROP;
+    v->areaId = 0;
+
+    actualStatusCode = StatusCode::TRY_AGAIN;
+    int attempts = 0;
+    while (StatusCode::TRY_AGAIN == actualStatusCode && ++attempts < 10) {
+        actualStatusCode = manager->set(*v.get());
+    }
+
+    ASSERT_EQ(StatusCode::OK, actualStatusCode);
+    ASSERT_EQ(kRetriablePropMockedAttempts + 1, attempts);
+
+    invokeGet(PROP, 0);
+    ASSERT_EQ(StatusCode::OK, actualStatusCode);
+    ASSERT_TRUE(actualValue.value.int32Values[0]);
+}
+
+TEST(HalClientVectorTest, basic) {
+    HalClientVector clients;
+    sp<IVehicleCallback> callback1 = new MockedVehicleCallback();
+
+    sp<HalClient> c1 = new HalClient(callback1, 10, 20);
+    sp<HalClient> c2 = new HalClient(callback1, 10, 20);
+
+    clients.addOrUpdate(c1);
+    clients.addOrUpdate(c1);
+    clients.addOrUpdate(c2);
+    ASSERT_EQ(2u, clients.size());
+    ASSERT_FALSE(clients.isEmpty());
+    ASSERT_LE(0, clients.indexOf(c1));
+    ASSERT_LE(0, clients.remove(c1));
+    ASSERT_GT(0, clients.indexOf(c1));  // c1 was already removed
+    ASSERT_GT(0, clients.remove(c1));   // attempt to remove c1 again
+    ASSERT_LE(0, clients.remove(c2));
+
+    ASSERT_TRUE(clients.isEmpty());
+}
+
+}  // namespace anonymous
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h b/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h
new file mode 100644
index 0000000..a512fcf
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2016 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_VehicleDebugUtils_H_
+#define android_hardware_automotive_vehicle_V2_0_VehicleDebugUtils_H_
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+#include <vehicle_hal_manager/VehicleUtils.h>
+#include <ios>
+#include <sstream>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+const VehiclePropConfig kVehicleProperties[] = {
+    {
+        .prop = toInt(VehicleProperty::INFO_MAKE),
+        .access = VehiclePropertyAccess::READ,
+        .changeMode = VehiclePropertyChangeMode::STATIC,
+        .configString = "Some=config,options=if,you=have_any",
+    },
+
+    {
+        .prop = toInt(VehicleProperty::HVAC_FAN_SPEED),
+        .access = VehiclePropertyAccess::READ_WRITE,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        .supportedAreas = static_cast<int32_t>(
+            VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT),
+        .areaConfigs = {
+            VehicleAreaConfig {
+                .areaId = toInt(VehicleAreaZone::ROW_1_LEFT),
+                .minInt32Value = 1,
+                .maxInt32Value = 7},
+            VehicleAreaConfig {
+                .areaId = toInt(VehicleAreaZone::ROW_1_RIGHT),
+                .minInt32Value = 1,
+                .maxInt32Value = 5,
+            }
+        }
+    },
+
+    // Write-only property
+    {
+        .prop = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE),
+        .access = VehiclePropertyAccess::WRITE,
+        .changeMode = VehiclePropertyChangeMode::ON_SET,
+        .supportedAreas = static_cast<int32_t>(
+            VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT),
+        .areaConfigs = {
+            VehicleAreaConfig {
+                .areaId = toInt(VehicleAreaZone::ROW_1_LEFT),
+                .minInt32Value = 64,
+                .maxInt32Value = 80},
+            VehicleAreaConfig {
+                .areaId = toInt(VehicleAreaZone::ROW_1_RIGHT),
+                .minInt32Value = 64,
+                .maxInt32Value = 80,
+            }
+        }
+    },
+
+    {
+        .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+        .access = VehiclePropertyAccess::READ,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        .areaConfigs = {
+            VehicleAreaConfig {
+                .minFloatValue = 0,
+                .maxFloatValue = 1.0
+            }
+        }
+    },
+
+    {
+        .prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS),
+        .access = VehiclePropertyAccess::READ_WRITE,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+        .areaConfigs = {
+            VehicleAreaConfig {
+                .minInt32Value = 0,
+                .maxInt32Value = 10
+            }
+        }
+    },
+
+    {
+        .prop = toInt(VehicleProperty::MIRROR_FOLD),
+        .access = VehiclePropertyAccess::READ_WRITE,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+
+    },
+
+    // Complex data type.
+    {
+        .prop = toInt(VehicleProperty::VEHICLE_MAP_SERVICE),
+        .access = VehiclePropertyAccess::READ_WRITE,
+        .changeMode = VehiclePropertyChangeMode::ON_CHANGE
+    }
+};
+
+constexpr auto kTimeout = std::chrono::milliseconds(500);
+
+class MockedVehicleCallback : public IVehicleCallback {
+private:
+    using MuxGuard = std::lock_guard<std::mutex>;
+    using HidlVecOfValues = hidl_vec<VehiclePropValue>;
+public:
+    // Methods from ::android::hardware::automotive::vehicle::V2_0::IVehicleCallback follow.
+    Return<void> onPropertyEvent(
+            const hidl_vec<VehiclePropValue>& values) override {
+        {
+            MuxGuard  g(mLock);
+            mReceivedEvents.push_back(values);
+        }
+        mEventCond.notify_one();
+        return Return<void>();
+    }
+    Return<void> onPropertySet(const VehiclePropValue& value) override {
+        return Return<void>();
+    }
+    Return<void> onPropertySetError(StatusCode errorCode,
+                                    int32_t propId,
+                                    int32_t areaId) override {
+        return Return<void>();
+    }
+
+    bool waitForExpectedEvents(size_t expectedEvents) {
+        std::unique_lock<std::mutex> g(mLock);
+
+        if (expectedEvents == 0 && mReceivedEvents.size() == 0) {
+            // No events expected, let's sleep a little bit to make sure
+            // nothing will show up.
+            return mEventCond.wait_for(g, kTimeout) == std::cv_status::timeout;
+        }
+
+        while (expectedEvents != mReceivedEvents.size()) {
+            if (mEventCond.wait_for(g, kTimeout) == std::cv_status::timeout) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    void reset() {
+        mReceivedEvents.clear();
+    }
+
+    const std::vector<HidlVecOfValues>& getReceivedEvents() {
+        return mReceivedEvents;
+    }
+
+private:
+    std::mutex mLock;
+    std::condition_variable mEventCond;
+    std::vector<HidlVecOfValues> mReceivedEvents;
+};
+
+template<typename T>
+inline std::string hexString(T value) {
+    std::stringstream ss;
+    ss << std::showbase << std::hex << value;
+    return ss.str();
+}
+
+template <typename T, typename Collection>
+inline void assertAllExistsAnyOrder(
+        std::initializer_list<T> expected,
+        const Collection& actual,
+        const char* msg) {
+    std::set<T> expectedSet = expected;
+
+    for (auto a: actual) {
+        ASSERT_EQ(1u, expectedSet.erase(a))
+                << msg << "\nContains not unexpected value.\n";
+    }
+
+    ASSERT_EQ(0u, expectedSet.size())
+            << msg
+            << "\nDoesn't contain expected value.";
+}
+
+#define ASSERT_ALL_EXISTS(...) \
+    assertAllExistsAnyOrder(__VA_ARGS__, (std::string("Called from: ") + \
+            std::string(__FILE__) + std::string(":") + \
+            std::to_string(__LINE__)).c_str()); \
+
+template<typename T>
+inline std::string enumToHexString(T value) {
+    return hexString(toInt(value));
+}
+
+template <typename T>
+inline std::string vecToString(const hidl_vec<T>& vec) {
+    std::stringstream ss("[");
+    for (size_t i = 0; i < vec.size(); i++) {
+        if (i != 0) ss << ",";
+        ss << vec[i];
+    }
+    ss << "]";
+    return ss.str();
+}
+
+inline std::string toString(const VehiclePropValue &v) {
+    std::stringstream ss;
+    ss << "VehiclePropValue {n"
+       << "  prop: " << hexString(v.prop) << ",\n"
+       << "  areaId: " << hexString(v.areaId) << ",\n"
+       << "  timestamp: " << v.timestamp << ",\n"
+       << "  value {\n"
+       << "    int32Values: " << vecToString(v.value.int32Values) << ",\n"
+       << "    floatValues: " << vecToString(v.value.floatValues) << ",\n"
+       << "    int64Values: " << vecToString(v.value.int64Values) << ",\n"
+       << "    bytes: " << vecToString(v.value.bytes) << ",\n"
+       << "    string: " << v.value.stringValue.c_str() << ",\n"
+       << "  }\n"
+       << "}\n";
+
+    return ss.str();
+}
+
+inline std::string toString(const VehiclePropConfig &config) {
+    std::stringstream ss;
+    ss << "VehiclePropConfig {\n"
+       << "  prop: " << hexString(config.prop) << ",\n"
+       << "  supportedAreas: " << hexString(config.supportedAreas) << ",\n"
+       << "  access: " << enumToHexString(config.access) << ",\n"
+       << "  changeMode: " << enumToHexString(config.changeMode) << ",\n"
+       << "  configFlags: " << hexString(config.configFlags) << ",\n"
+       << "  minSampleRate: " << config.minSampleRate << ",\n"
+       << "  maxSampleRate: " << config.maxSampleRate << ",\n"
+       << "  configString: " << config.configString.c_str() << ",\n";
+
+    ss << "  areaConfigs {\n";
+    for (size_t i = 0; i < config.areaConfigs.size(); i++) {
+        const auto &area = config.areaConfigs[i];
+        ss << "    areaId: " << hexString(area.areaId) << ",\n"
+           << "    minFloatValue: " << area.minFloatValue << ",\n"
+           << "    minFloatValue: " << area.maxFloatValue << ",\n"
+           << "    minInt32Value: " << area.minInt32Value << ",\n"
+           << "    minInt32Value: " << area.maxInt32Value << ",\n"
+           << "    minInt64Value: " << area.minInt64Value << ",\n"
+           << "    minInt64Value: " << area.maxInt64Value << ",\n";
+    }
+    ss << "  }\n"
+       << "}\n";
+
+    return ss.str();
+}
+
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+
+#endif //android_hardware_automotive_vehicle_V2_0_VehicleDebugUtils_H_
diff --git a/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp b/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp
new file mode 100644
index 0000000..0d57284
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/VehicleObjectPool_test.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2016 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 <thread>
+
+#include <gtest/gtest.h>
+
+#include <utils/SystemClock.h>
+
+#include "vehicle_hal_manager/VehicleObjectPool.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace {
+
+class VehicleObjectPoolTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+        stats = PoolStats::instance();
+        resetStats();
+        valuePool.reset(new VehiclePropValuePool);
+    }
+
+    void TearDown() override {
+        // At the end, all created objects should be either recycled or deleted.
+        // Some objects could be recycled multiple times, that's why it's <=
+        ASSERT_EQ(stats->Obtained, stats->Recycled);
+        ASSERT_LE(stats->Created, stats->Recycled);
+    }
+private:
+    void resetStats() {
+        stats->Obtained = 0;
+        stats->Created = 0;
+        stats->Recycled = 0;
+    }
+
+public:
+    PoolStats* stats;
+    std::unique_ptr<VehiclePropValuePool> valuePool;
+};
+
+TEST_F(VehicleObjectPoolTest, valuePoolBasicCorrectness) {
+    void* raw = valuePool->obtain(VehiclePropertyType::INT32).get();
+    // At this point, v1 should be recycled and the only object in the pool.
+    ASSERT_EQ(raw, valuePool->obtain(VehiclePropertyType::INT32).get());
+    // Obtaining value of another type - should return a new object
+    ASSERT_NE(raw, valuePool->obtain(VehiclePropertyType::FLOAT).get());
+
+    ASSERT_EQ(3u, stats->Obtained);
+    ASSERT_EQ(2u, stats->Created);
+}
+
+TEST_F(VehicleObjectPoolTest, valuePoolStrings) {
+    valuePool->obtain(VehiclePropertyType::STRING);
+    auto vs = valuePool->obtain(VehiclePropertyType::STRING);
+    vs->value.stringValue = "Hello";
+    void* raw = vs.get();
+    vs.reset();  // delete the pointer
+
+    auto vs2 = valuePool->obtain(VehiclePropertyType::STRING);
+    ASSERT_EQ(0u, vs2->value.stringValue.size());
+    ASSERT_NE(raw, valuePool->obtain(VehiclePropertyType::STRING).get());
+
+    ASSERT_EQ(0u, stats->Obtained);
+}
+
+TEST_F(VehicleObjectPoolTest, valuePoolMultithreadedBenchmark) {
+    // In this test we have T threads that concurrently in C cycles
+    // obtain and release O VehiclePropValue objects of FLOAT / INT32 types.
+
+    const auto T = 2;
+    const auto C  = 500;
+    const auto O = 100;
+
+    auto poolPtr = valuePool.get();
+
+    std::vector<std::thread> threads;
+    auto start = elapsedRealtimeNano();
+    for (int i = 0; i < T; i++) {
+        threads.push_back(std::thread([&poolPtr] () {
+            for (int j = 0; j < C; j++) {
+                std::vector<recyclable_ptr<VehiclePropValue>> vec;
+                for (int k = 0; k < O; k++) {
+                    vec.push_back(
+                        poolPtr->obtain(k % 2 == 0
+                                        ? VehiclePropertyType::FLOAT
+                                        : VehiclePropertyType::INT32));
+                }
+            }
+        }));
+    }
+
+    for (auto& t : threads) {
+        t.join();
+    }
+    auto finish = elapsedRealtimeNano();
+
+    ASSERT_EQ(T * C * O, stats->Obtained);
+    ASSERT_EQ(T * C * O, stats->Recycled);
+    // Created less than obtained.
+    ASSERT_GE(T * O, stats->Created);
+
+    auto elapsedMs = (finish - start) / 1000000;
+    ASSERT_GE(1000, elapsedMs);  // Less a second to access 100K objects.
+                                 // Typically it takes about 0.1s on Nexus6P.
+}
+
+}  // namespace anonymous
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/tests/VehiclePropConfigIndex_test.cpp b/automotive/vehicle/2.0/default/tests/VehiclePropConfigIndex_test.cpp
new file mode 100644
index 0000000..fad4ab3
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/VehiclePropConfigIndex_test.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 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 <gtest/gtest.h>
+
+#include "vehicle_hal_manager/VehiclePropConfigIndex.h"
+
+#include "VehicleHalTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace {
+
+class PropConfigTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+        configs.assign(std::begin(kVehicleProperties),
+                       std::end(kVehicleProperties));
+    }
+
+    void TearDown() override {}
+
+public:
+    std::vector<VehiclePropConfig> configs;
+};
+
+TEST_F(PropConfigTest, hasConfig) {
+    VehiclePropConfigIndex index(configs);
+
+    ASSERT_TRUE(index.hasConfig(toInt(VehicleProperty::HVAC_FAN_SPEED)));
+    ASSERT_TRUE(index.hasConfig(toInt(VehicleProperty::INFO_MAKE)));
+    ASSERT_TRUE(index.hasConfig(toInt(VehicleProperty::INFO_FUEL_CAPACITY)));
+
+    ASSERT_FALSE(index.hasConfig(toInt(VehicleProperty::INVALID)));
+}
+
+TEST_F(PropConfigTest, getAllConfig) {
+    VehiclePropConfigIndex index(configs);
+
+    std::vector<VehiclePropConfig> actualConfigs = index.getAllConfigs();
+    ASSERT_EQ(configs.size(), actualConfigs.size());
+
+    for (size_t i = 0; i < actualConfigs.size(); i++) {
+        ASSERT_EQ(toString(configs[i]), toString(actualConfigs[i]));
+    }
+}
+
+TEST_F(PropConfigTest, getConfigs) {
+    VehiclePropConfigIndex index(configs);
+    auto actualConfig = index.getConfig(toInt(VehicleProperty::HVAC_FAN_SPEED));
+    ASSERT_EQ(toString(configs[1]), toString(actualConfig));
+}
+
+}  // namespace anonymous
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/vehicle_hal_manager/AccessControlConfigParser.cpp b/automotive/vehicle/2.0/default/vehicle_hal_manager/AccessControlConfigParser.cpp
new file mode 100644
index 0000000..6a3f8e5
--- /dev/null
+++ b/automotive/vehicle/2.0/default/vehicle_hal_manager/AccessControlConfigParser.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2016 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 "automotive.vehicle@2.0-impl"
+
+#include "AccessControlConfigParser.h"
+#include "VehicleUtils.h"
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+AccessControlConfigParser::AccessControlConfigParser(
+        const std::vector<int32_t>& properties) {
+    // Property Id in the config file doesn't include information about
+    // type and area. So we want to create a map from these kind of
+    // *stripped* properties to the whole VehicleProperty.
+    // We also want to filter out ACL to the properties that supported
+    // by concrete Vehicle HAL implementation.
+    for (auto prop : properties) {
+        auto strippedProp = prop
+                            & ~toInt(VehiclePropertyType::MASK)
+                            & ~toInt(VehicleArea::MASK);
+        mStrippedToVehiclePropertyMap.emplace(strippedProp, prop);
+    }
+}
+
+bool AccessControlConfigParser::parseFromStream(
+        std::istream* stream, PropertyAclMap* propertyAclMap) {
+    std::list<std::string> tokens;
+    std::string line;
+    int lineNo = 0;
+    bool warnings = false;
+    for (;std::getline(*stream, line); lineNo++) {
+        split(line, &tokens);
+        if (!processTokens(&tokens, propertyAclMap)) {
+            warnings = true;
+            ALOGW("Failed to parse line %d : %s", lineNo, line.c_str());
+        }
+    }
+    return !warnings;
+}
+
+
+bool AccessControlConfigParser::processTokens(std::list<std::string>* tokens,
+                                              PropertyAclMap* propertyAclMap) {
+    std::string token = readNextToken(tokens);
+    if (token.empty() || token[0] == '#') {   // Ignore comment.
+        return true;
+    }
+
+    if (token == "Set") {
+        std::string alias = readNextToken(tokens);
+        std::string strUid = readNextToken(tokens);
+        if (alias.empty() || strUid.empty()) {
+            ALOGW("Expected alias and UID must be specified");
+            return false;
+        }
+        int uid;
+        if (!parseInt(strUid.c_str(), &uid)) {
+            ALOGW("Invalid UID: %d", uid);
+        }
+        mUidMap.emplace(std::move(alias), uid);
+    } else if (token.size() > 2 && token[1] == ':') {
+        VehiclePropertyGroup propGroup;
+        if (!parsePropertyGroup(token[0], &propGroup)) {
+            return false;
+        }
+        std::string strUid = readNextToken(tokens);
+        std::string strAccess = readNextToken(tokens);
+        if (strUid.empty() || strAccess.empty()) {
+            ALOGW("Expected UID and access for property: %s",
+                  token.c_str());
+        }
+
+
+        PropertyAcl acl;
+        if (parsePropertyId(token.substr(2), propGroup, &acl.propId)
+            && parseUid(strUid, &acl.uid)
+            && parseAccess(strAccess, &acl.access)) {
+            propertyAclMap->emplace(acl.propId, std::move(acl));
+        } else {
+            return false;
+        }
+    } else {
+        ALOGW("Unexpected token: %s", token.c_str());
+        return false;
+    }
+
+    return true;
+}
+
+bool AccessControlConfigParser::parsePropertyGroup(
+        char group, VehiclePropertyGroup* outPropertyGroup) const {
+    switch (group) {
+        case 'S':  // Fall through.
+        case 's':
+            *outPropertyGroup = VehiclePropertyGroup::SYSTEM;
+            break;
+        case 'V':  // Fall through.
+        case 'v':
+            *outPropertyGroup = VehiclePropertyGroup::VENDOR;
+            break;
+        default:
+            ALOGW("Unexpected group: %c", group);
+            return false;
+    }
+    return true;
+}
+
+bool AccessControlConfigParser::parsePropertyId(
+        const std::string& strPropId,
+        VehiclePropertyGroup propertyGroup,
+        int32_t* outVehicleProperty) const {
+    int32_t propId;
+    if (!parseInt(strPropId.c_str(), &propId)) {
+        ALOGW("Failed to convert property id to integer: %s",
+              strPropId.c_str());
+        return false;
+    }
+    propId |= static_cast<int>(propertyGroup);
+    auto it = mStrippedToVehiclePropertyMap.find(propId);
+    if (it == mStrippedToVehiclePropertyMap.end()) {
+        ALOGW("Property Id not found or not supported: 0x%x", propId);
+        return false;
+    }
+    *outVehicleProperty = it->second;
+    return true;
+}
+
+bool AccessControlConfigParser::parseInt(const char* strValue,
+                                         int* outIntValue) {
+    char* end;
+    long num = std::strtol(strValue, &end, 0 /* auto detect base */);
+    bool success = *end == 0 && errno != ERANGE;
+    if (success) {
+        *outIntValue = static_cast<int>(num);
+    }
+
+    return success;
+}
+
+bool AccessControlConfigParser::parseUid(const std::string& strUid,
+                                         unsigned* outUid) const {
+    auto element = mUidMap.find(strUid);
+    if (element != mUidMap.end()) {
+        *outUid = element->second;
+    } else {
+        int val;
+        if (!parseInt(strUid.c_str(), &val)) {
+            ALOGW("Failed to convert UID '%s' to integer", strUid.c_str());
+            return false;
+        }
+        *outUid = static_cast<unsigned>(val);
+    }
+    return true;
+}
+
+bool AccessControlConfigParser::parseAccess(
+        const std::string& strAccess, VehiclePropertyAccess* outAccess) const {
+    if (strAccess.size() == 0 || strAccess.size() > 2) {
+        ALOGW("Unknown access mode '%s'", strAccess.c_str());
+        return false;
+    }
+    int32_t access = static_cast<int32_t>(VehiclePropertyAccess::NONE);
+    for (char c : strAccess) {
+        if (c == 'R' || c == 'r') {
+            access |= VehiclePropertyAccess::READ;
+        } else if (c == 'W' || c == 'w') {
+            access |= VehiclePropertyAccess::WRITE;
+        } else {
+            ALOGW("Unknown access mode: %c", c);
+            return false;
+        }
+    }
+    *outAccess = static_cast<VehiclePropertyAccess>(access);
+    return true;
+}
+
+void AccessControlConfigParser::split(const std::string& line,
+                                      std::list<std::string>* outTokens) {
+    outTokens->clear();
+    std::istringstream iss(line);
+
+    while (!iss.eof()) {
+        std::string token;
+        iss >> token;
+        outTokens->push_back(std::move(token));
+    }
+}
+
+std::string AccessControlConfigParser::readNextToken(
+        std::list<std::string>* tokens) const {
+    if (tokens->empty()) {
+        return "";
+    }
+
+    std::string token = tokens->front();
+    tokens->pop_front();
+    return token;
+}
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/vehicle_hal_manager/AccessControlConfigParser.h b/automotive/vehicle/2.0/default/vehicle_hal_manager/AccessControlConfigParser.h
new file mode 100644
index 0000000..8ef6f5a
--- /dev/null
+++ b/automotive/vehicle/2.0/default/vehicle_hal_manager/AccessControlConfigParser.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2016 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_AccessControlConfigParser_H_
+#define android_hardware_automotive_vehicle_V2_0_AccessControlConfigParser_H_
+
+#include <string>
+#include <vector>
+#include <unordered_map>
+#include <list>
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+struct PropertyAcl {
+    int32_t propId;
+    unsigned uid;
+    VehiclePropertyAccess access;
+};
+
+using PropertyAclMap = std::unordered_multimap<int32_t, PropertyAcl>;
+
+/**
+ * Parser for per-property access control in vehicle HAL.
+ *
+ * It supports the following format:
+ *   Set ALIAS_NAME UID
+ *   {S,V}:0x0305   {ALIAS_NAME,UID}   {R,W,RW}
+ *
+ * ALIAS_NAME is just an alias for UID
+ * S - for system properties (VehiclePropertyGroup::SYSTEM)
+ * V - for vendor properties (VehiclePropertyGroup::VENDOR)
+ *
+ * Example:
+ *
+ *   Set AID_AUDIO  1004
+ *   Set AID_MY_APP     10022
+ *
+ *   S:0x0305   AID_AUDIO   RW
+ *   S:0x0305   10021       R
+ *   V:0x0101   AID_MY_APP  R
+ */
+class AccessControlConfigParser {
+public:
+    /**
+     * Creates an instance of AccessControlConfigParser
+     *
+     * @param properties - properties supported by HAL implementation
+     */
+    AccessControlConfigParser(const std::vector<int32_t>& properties);
+
+    /**
+     * Parses config content from given stream and writes results to
+     * propertyAclMap.
+     */
+    bool parseFromStream(std::istream* stream, PropertyAclMap* propertyAclMap);
+
+private:
+    bool processTokens(std::list<std::string>* tokens,
+                       PropertyAclMap* propertyAclMap);
+
+    bool parsePropertyGroup(char group,
+                            VehiclePropertyGroup* outPropertyGroup) const;
+
+    bool parsePropertyId(const std::string& strPropId,
+                                VehiclePropertyGroup propertyGroup,
+                                int32_t* outVehicleProperty) const;
+
+    bool parseUid(const std::string& strUid, unsigned* outUid) const;
+
+    bool parseAccess(const std::string& strAccess,
+                     VehiclePropertyAccess* outAccess) const;
+
+
+    std::string readNextToken(std::list<std::string>* tokens) const;
+
+    static bool parseInt(const char* strValue, int* outIntValue);
+    static void split(const std::string& line,
+                      std::list<std::string>* outTokens);
+
+private:
+    std::unordered_map<std::string, unsigned> mUidMap {};  // Contains UID
+    // aliases.
+
+    // Map property ids w/o TYPE and AREA to VehicleProperty.
+    std::unordered_map<int32_t, int32_t> mStrippedToVehiclePropertyMap;
+};
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_AccessControlConfigParser_H_
diff --git a/automotive/vehicle/2.0/default/vehicle_hal_manager/ConcurrentQueue.h b/automotive/vehicle/2.0/default/vehicle_hal_manager/ConcurrentQueue.h
new file mode 100644
index 0000000..b63429f
--- /dev/null
+++ b/automotive/vehicle/2.0/default/vehicle_hal_manager/ConcurrentQueue.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2016 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_ConcurrentQueue_H_
+#define android_hardware_automotive_vehicle_V2_0_ConcurrentQueue_H_
+
+#include <queue>
+#include <atomic>
+#include <thread>
+#include <condition_variable>
+#include <iostream>
+
+namespace android {
+
+template<typename T>
+class ConcurrentQueue {
+public:
+    void waitForItems() {
+        std::unique_lock<std::mutex> g(mLock);
+        while (mQueue.empty() && mIsActive) {
+            mCond.wait(g);
+        }
+    }
+
+    std::vector<T> flush() {
+        std::vector<T> items;
+
+        MuxGuard g(mLock);
+        if (mQueue.empty() || !mIsActive) {
+            return items;
+        }
+        while (!mQueue.empty()) {
+            items.push_back(std::move(mQueue.front()));
+            mQueue.pop();
+        }
+        return items;
+    }
+
+    void push(T&& item) {
+        {
+            MuxGuard g(mLock);
+            if (!mIsActive) {
+                return;
+            }
+            mQueue.push(std::move(item));
+        }
+        mCond.notify_one();
+    }
+
+    /* Deactivates the queue, thus no one can push items to it, also
+     * notifies all waiting thread.
+     */
+    void deactivate() {
+        {
+            MuxGuard g(mLock);
+            mIsActive = false;
+        }
+        mCond.notify_all();  // To unblock all waiting consumers.
+    }
+
+    ConcurrentQueue() = default;
+
+    ConcurrentQueue(const ConcurrentQueue &) = delete;
+    ConcurrentQueue &operator=(const ConcurrentQueue &) = delete;
+private:
+    using MuxGuard = std::lock_guard<std::mutex>;
+
+    bool mIsActive = true;
+    mutable std::mutex mLock;
+    std::condition_variable mCond;
+    std::queue<T> mQueue;
+};
+
+template<typename T>
+class BatchingConsumer {
+private:
+    enum class State {
+        INIT = 0,
+        RUNNING = 1,
+        STOP_REQUESTED = 2,
+        STOPPED = 3,
+    };
+
+public:
+    BatchingConsumer() : mState(State::INIT) {}
+
+    BatchingConsumer(const BatchingConsumer &) = delete;
+    BatchingConsumer &operator=(const BatchingConsumer &) = delete;
+
+    using OnBatchReceivedFunc = std::function<void(const std::vector<T>& vec)>;
+
+    void run(ConcurrentQueue<T>* queue,
+             std::chrono::nanoseconds batchInterval,
+             const OnBatchReceivedFunc& func) {
+        mQueue = queue;
+        mBatchInterval = batchInterval;
+
+        mWorkerThread = std::thread(
+            &BatchingConsumer<T>::runInternal, this, func);
+    }
+
+    void requestStop() {
+        mState = State::STOP_REQUESTED;
+    }
+
+    void waitStopped() {
+        if (mWorkerThread.joinable()) {
+            mWorkerThread.join();
+        }
+    }
+
+private:
+    void runInternal(const OnBatchReceivedFunc& onBatchReceived) {
+        if (mState.exchange(State::RUNNING) == State::INIT) {
+            while (State::RUNNING == mState) {
+                mQueue->waitForItems();
+                if (State::STOP_REQUESTED == mState) break;
+
+                std::this_thread::sleep_for(mBatchInterval);
+                if (State::STOP_REQUESTED == mState) break;
+
+                std::vector<T> items = mQueue->flush();
+
+                if (items.size() > 0) {
+                    onBatchReceived(items);
+                }
+            }
+        }
+
+        mState = State::STOPPED;
+    }
+
+private:
+    std::thread mWorkerThread;
+
+    std::atomic<State> mState;
+    std::chrono::nanoseconds mBatchInterval;
+    ConcurrentQueue<T>* mQueue;
+};
+
+}  // namespace android
+
+#endif //android_hardware_automotive_vehicle_V2_0_ConcurrentQueue_H_
diff --git a/automotive/vehicle/2.0/default/vehicle_hal_manager/Obd2SensorStore.cpp b/automotive/vehicle/2.0/default/vehicle_hal_manager/Obd2SensorStore.cpp
new file mode 100644
index 0000000..3a252af
--- /dev/null
+++ b/automotive/vehicle/2.0/default/vehicle_hal_manager/Obd2SensorStore.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.
+ */
+
+#include "Obd2SensorStore.h"
+
+#include <vehicle_hal_manager/VehicleUtils.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+Obd2SensorStore::BitmaskInVector::BitmaskInVector(size_t numBits)
+{
+    resize(numBits);
+}
+
+void Obd2SensorStore::BitmaskInVector::resize(size_t numBits) {
+    mStorage = std::vector<uint8_t>((numBits+7)/8, 0);
+}
+
+void Obd2SensorStore::BitmaskInVector::set(size_t index, bool value) {
+    const size_t byteIndex = index / 8;
+    const size_t bitIndex = index % 8;
+    const uint8_t byte = mStorage[byteIndex];
+    uint8_t newValue = value ? (byte | (1 << bitIndex)) :
+                               (byte & ~(1 << bitIndex));
+    mStorage[byteIndex] = newValue;
+}
+
+bool Obd2SensorStore::BitmaskInVector::get(size_t index) const {
+    const size_t byteIndex = index / 8;
+    const size_t bitIndex = index % 8;
+    const uint8_t byte = mStorage[byteIndex];
+    return (byte & (1 << bitIndex)) != 0;
+}
+
+const std::vector<uint8_t>& Obd2SensorStore::BitmaskInVector::getBitmask() const {
+    return mStorage;
+}
+
+Obd2SensorStore::Obd2SensorStore(size_t numVendorIntegerSensors,
+                                 size_t numVendorFloatSensors) {
+        // because the last index is valid *inclusive*
+        const size_t numSystemIntegerSensors = toInt(Obd2IntegerSensorIndex::LAST_SYSTEM_INDEX)+1;
+        const size_t numSystemFloatSensors = toInt(Obd2FloatSensorIndex::LAST_SYSTEM_INDEX)+1;
+        mIntegerSensors = std::vector<int32_t>(
+            numSystemIntegerSensors+numVendorIntegerSensors, 0);
+        mFloatSensors = std::vector<float>(
+            numSystemFloatSensors+numVendorFloatSensors, 0);
+        mSensorsBitmask.resize(mIntegerSensors.size()+mFloatSensors.size());
+}
+
+StatusCode Obd2SensorStore::setIntegerSensor(Obd2IntegerSensorIndex index,
+    int32_t value) {
+    return setIntegerSensor(toInt(index), value);
+}
+StatusCode Obd2SensorStore::setFloatSensor(Obd2FloatSensorIndex index,
+    float value) {
+    return setFloatSensor(toInt(index), value);
+}
+
+StatusCode Obd2SensorStore::setIntegerSensor(size_t index, int32_t value) {
+    mIntegerSensors[index] = value;
+    mSensorsBitmask.set(index, true);
+    return StatusCode::OK;
+}
+
+StatusCode Obd2SensorStore::setFloatSensor(size_t index, float value) {
+    mFloatSensors[index] = value;
+    mSensorsBitmask.set(index + mIntegerSensors.size(), true);
+    return StatusCode::OK;
+}
+
+const std::vector<int32_t>& Obd2SensorStore::getIntegerSensors() const {
+    return mIntegerSensors;
+}
+
+const std::vector<float>& Obd2SensorStore::getFloatSensors() const {
+    return mFloatSensors;
+}
+
+const std::vector<uint8_t>& Obd2SensorStore::getSensorsBitmask() const {
+    return mSensorsBitmask.getBitmask();
+}
+
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/vehicle_hal_manager/Obd2SensorStore.h b/automotive/vehicle/2.0/default/vehicle_hal_manager/Obd2SensorStore.h
new file mode 100644
index 0000000..cbe9893
--- /dev/null
+++ b/automotive/vehicle/2.0/default/vehicle_hal_manager/Obd2SensorStore.h
@@ -0,0 +1,82 @@
+/*
+ * 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_Obd2SensorStore_H_
+#define android_hardware_automotive_vehicle_V2_0_Obd2SensorStore_H_
+
+#include <vector>
+
+#include <VehicleHal.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+// This class wraps all the logic required to create an OBD2 frame.
+// It allows storing sensor values, setting appropriate bitmasks as needed,
+// and returning appropriately laid out storage of sensor values suitable
+// for being returned via a VehicleHal implementation.
+class Obd2SensorStore {
+public:
+    // Creates a sensor storage with a given number of vendor-specific sensors.
+    Obd2SensorStore(size_t numVendorIntegerSensors,
+                    size_t numVendorFloatSensors);
+
+    // Stores an integer-valued sensor.
+    StatusCode setIntegerSensor(Obd2IntegerSensorIndex index, int32_t value);
+    // Stores an integer-valued sensor.
+    StatusCode setIntegerSensor(size_t index, int32_t value);
+
+    // Stores a float-valued sensor.
+    StatusCode setFloatSensor(Obd2FloatSensorIndex index, float value);
+    // Stores a float-valued sensor.
+    StatusCode setFloatSensor(size_t index, float value);
+
+    // Returns a vector that contains all integer sensors stored.
+    const std::vector<int32_t>& getIntegerSensors() const;
+    // Returns a vector that contains all float sensors stored.
+    const std::vector<float>& getFloatSensors() const;
+    // Returns a vector that contains a bitmask for all stored sensors.
+    const std::vector<uint8_t>& getSensorsBitmask() const;
+
+private:
+    class BitmaskInVector {
+    public:
+        BitmaskInVector(size_t numBits = 0);
+        void resize(size_t numBits);
+        bool get(size_t index) const;
+        void set(size_t index, bool value);
+
+        const std::vector<uint8_t>& getBitmask() const;
+
+    private:
+        std::vector<uint8_t> mStorage;
+    };
+
+    std::vector<int32_t> mIntegerSensors;
+    std::vector<float> mFloatSensors;
+    BitmaskInVector mSensorsBitmask;
+};
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_V2_0_Obd2SensorStore_H_
diff --git a/automotive/vehicle/2.0/default/vehicle_hal_manager/SubscriptionManager.cpp b/automotive/vehicle/2.0/default/vehicle_hal_manager/SubscriptionManager.cpp
new file mode 100644
index 0000000..f6f2758
--- /dev/null
+++ b/automotive/vehicle/2.0/default/vehicle_hal_manager/SubscriptionManager.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2016 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 "automotive.vehicle@2.0-impl"
+
+#include "SubscriptionManager.h"
+
+#include <cmath>
+
+#include <android/log.h>
+
+#include "VehicleUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+bool mergeSubscribeOptions(const SubscribeOptions &oldOpts,
+                           const SubscribeOptions &newOpts,
+                           SubscribeOptions *outResult) {
+
+    int32_t updatedAreas = oldOpts.vehicleAreas;
+    if (updatedAreas != kAllSupportedAreas) {
+        updatedAreas = newOpts.vehicleAreas != kAllSupportedAreas
+            ? updatedAreas | newOpts.vehicleAreas
+            : kAllSupportedAreas;
+    }
+
+    float updatedRate = std::max(oldOpts.sampleRate, newOpts.sampleRate);
+    SubscribeFlags updatedFlags = SubscribeFlags(oldOpts.flags | newOpts.flags);
+
+    bool updated = updatedRate > oldOpts.sampleRate
+                   || updatedAreas != oldOpts.vehicleAreas
+                   || updatedFlags != oldOpts.flags;
+    if (updated) {
+        *outResult = oldOpts;
+        outResult->vehicleAreas = updatedAreas;
+        outResult->sampleRate = updatedRate;
+        outResult->flags = updatedFlags;
+    }
+
+    return updated;
+}
+
+void HalClient::addOrUpdateSubscription(const SubscribeOptions &opts)  {
+    auto it = mSubscriptions.find(opts.propId);
+    if (it == mSubscriptions.end()) {
+        mSubscriptions.emplace(opts.propId, opts);
+    } else {
+        const SubscribeOptions& oldOpts = it->second;
+        SubscribeOptions updatedOptions;
+        if (mergeSubscribeOptions(oldOpts, opts, &updatedOptions)) {
+            mSubscriptions.erase(it);
+            mSubscriptions.emplace(opts.propId, updatedOptions);
+        }
+    }
+}
+
+bool HalClient::isSubscribed(int32_t propId,
+                             int32_t areaId,
+                             SubscribeFlags flags) {
+    auto it = mSubscriptions.find(propId);
+    if (it == mSubscriptions.end()) {
+        return false;
+    }
+    const SubscribeOptions& opts = it->second;
+    bool res = (opts.flags & flags)
+           && (opts.vehicleAreas == 0 || areaId == 0 || opts.vehicleAreas & areaId);
+    return res;
+}
+
+std::list<SubscribeOptions> SubscriptionManager::addOrUpdateSubscription(
+        const sp<IVehicleCallback> &callback,
+        const hidl_vec<SubscribeOptions> &optionList) {
+    std::list<SubscribeOptions> updatedSubscriptions;
+
+    MuxGuard g(mLock);
+
+    const sp<HalClient>& client = getOrCreateHalClientLocked(callback);
+
+    for (size_t i = 0; i < optionList.size(); i++) {
+        const SubscribeOptions& opts = optionList[i];
+        client->addOrUpdateSubscription(opts);
+
+        addClientToPropMapLocked(opts.propId, client);
+
+        if (SubscribeFlags::HAL_EVENT & opts.flags) {
+            SubscribeOptions updated;
+            if (updateHalEventSubscriptionLocked(opts, &updated)) {
+                updatedSubscriptions.push_back(updated);
+            }
+        }
+    }
+
+    return updatedSubscriptions;
+}
+
+std::list<HalClientValues> SubscriptionManager::distributeValuesToClients(
+        const std::vector<recyclable_ptr<VehiclePropValue>>& propValues,
+        SubscribeFlags flags) const {
+    std::map<sp<HalClient>, std::list<VehiclePropValue*>> clientValuesMap;
+
+    {
+        MuxGuard g(mLock);
+        for (const auto& propValue: propValues) {
+            VehiclePropValue* v = propValue.get();
+            auto clients = getSubscribedClientsLocked(
+                v->prop, v->areaId, flags);
+            for (const auto& client : clients) {
+                clientValuesMap[client].push_back(v);
+            }
+        }
+    }
+
+    std::list<HalClientValues> clientValues;
+    for (const auto& entry : clientValuesMap) {
+        clientValues.push_back(HalClientValues {
+            .client = entry.first,
+            .values = entry.second
+        });
+    }
+
+    return clientValues;
+}
+
+std::list<sp<HalClient>> SubscriptionManager::getSubscribedClients(
+    int32_t propId, int32_t area, SubscribeFlags flags) const {
+    MuxGuard g(mLock);
+    return getSubscribedClientsLocked(propId, area, flags);
+}
+
+std::list<sp<HalClient>> SubscriptionManager::getSubscribedClientsLocked(
+        int32_t propId, int32_t area, SubscribeFlags flags) const {
+    std::list<sp<HalClient>> subscribedClients;
+
+    sp<HalClientVector> propClients = getClientsForPropertyLocked(propId);
+    if (propClients.get() != nullptr) {
+        for (size_t i = 0; i < propClients->size(); i++) {
+            const auto& client = propClients->itemAt(i);
+            if (client->isSubscribed(propId, area, flags)) {
+                subscribedClients.push_back(client);
+            }
+        }
+    }
+
+    return subscribedClients;
+}
+
+bool SubscriptionManager::updateHalEventSubscriptionLocked(
+        const SubscribeOptions &opts, SubscribeOptions *outUpdated) {
+    bool updated = false;
+    auto it = mHalEventSubscribeOptions.find(opts.propId);
+    if (it == mHalEventSubscribeOptions.end()) {
+        *outUpdated = opts;
+        mHalEventSubscribeOptions.emplace(opts.propId, opts);
+        updated = true;
+    } else {
+        const SubscribeOptions& oldOpts = it->second;
+
+        if (mergeSubscribeOptions(oldOpts, opts, outUpdated)) {
+            mHalEventSubscribeOptions.erase(opts.propId);
+            mHalEventSubscribeOptions.emplace(opts.propId, *outUpdated);
+            updated = true;
+        }
+    }
+
+    return updated;
+}
+
+void SubscriptionManager::addClientToPropMapLocked(
+        int32_t propId, const sp<HalClient> &client) {
+    auto it = mPropToClients.find(propId);
+    sp<HalClientVector> propClients;
+    if (it == mPropToClients.end()) {
+        propClients = new HalClientVector();
+        mPropToClients.insert(std::make_pair(propId, propClients));
+    } else {
+        propClients = it->second;
+    }
+    propClients->addOrUpdate(client);
+}
+
+sp<HalClientVector> SubscriptionManager::getClientsForPropertyLocked(
+        int32_t propId) const {
+    auto it = mPropToClients.find(propId);
+    return it == mPropToClients.end() ? nullptr : it->second;
+}
+
+sp<HalClient> SubscriptionManager::getOrCreateHalClientLocked(
+        const sp<IVehicleCallback>& callback) {
+    auto it = mClients.find(callback);
+    if (it == mClients.end()) {
+        IPCThreadState* self = IPCThreadState::self();
+        pid_t pid = self->getCallingPid();
+        uid_t uid = self->getCallingUid();
+        sp<HalClient> client = new HalClient(callback, pid, uid);
+        mClients.emplace(callback, client);
+        return client;
+    } else {
+        return it->second;
+    }
+}
+
+bool SubscriptionManager::unsubscribe(const sp<IVehicleCallback>& callback,
+                                      int32_t propId) {
+    MuxGuard g(mLock);
+    auto propertyClients = getClientsForPropertyLocked(propId);
+    auto clientIter = mClients.find(callback);
+    if (clientIter == mClients.end()) {
+        ALOGW("Unable to unsubscribe: no callback found, propId: 0x%x", propId);
+    } else {
+        auto client = clientIter->second;
+
+        if (propertyClients != nullptr) {
+            propertyClients->remove(client);
+
+            if (propertyClients->isEmpty()) {
+                mPropToClients.erase(propId);
+            }
+        }
+
+        bool isClientSubscribedToOtherProps = false;
+        for (const auto& propClient : mPropToClients) {
+            if (propClient.second->indexOf(client) >= 0) {
+                isClientSubscribedToOtherProps = true;
+                break;
+            }
+        }
+
+        if (!isClientSubscribedToOtherProps) {
+            mClients.erase(clientIter);
+        }
+    }
+
+    return (propertyClients == nullptr || propertyClients->isEmpty())
+            ? mHalEventSubscribeOptions.erase(propId) == 1
+            : false;
+}
+
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/vehicle_hal_manager/SubscriptionManager.h b/automotive/vehicle/2.0/default/vehicle_hal_manager/SubscriptionManager.h
new file mode 100644
index 0000000..6a12b77
--- /dev/null
+++ b/automotive/vehicle/2.0/default/vehicle_hal_manager/SubscriptionManager.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2016 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_SubscriptionManager_H_
+#define android_hardware_automotive_vehicle_V2_0_SubscriptionManager_H_
+
+#include <memory>
+#include <map>
+#include <set>
+#include <list>
+
+#include <android/log.h>
+#include <hwbinder/IPCThreadState.h>
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+
+#include "ConcurrentQueue.h"
+#include "VehicleObjectPool.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+class HalClient : public android::RefBase {
+public:
+    HalClient(const sp<IVehicleCallback> &callback,
+              int32_t pid,
+              int32_t uid)
+        : mCallback(callback), mPid(pid), mUid(uid) {}
+
+    virtual ~HalClient() {}
+public:
+    sp<IVehicleCallback> getCallback() const {
+        return mCallback;
+    }
+
+    void addOrUpdateSubscription(const SubscribeOptions &opts);
+
+    bool isSubscribed(int32_t propId,
+                      int32_t areaId,
+                      SubscribeFlags flags);
+
+private:
+    const sp<IVehicleCallback> mCallback;
+    const int32_t mPid;
+    const int32_t mUid;
+
+    std::map<int32_t, SubscribeOptions> mSubscriptions;
+};
+
+class HalClientVector : private SortedVector<sp<HalClient>> , public RefBase {
+public:
+    virtual ~HalClientVector() {}
+
+    inline void addOrUpdate(const sp<HalClient> &client) {
+        SortedVector::add(client);
+    }
+
+    using SortedVector::remove;
+    using SortedVector::size;
+    using SortedVector::indexOf;
+    using SortedVector::itemAt;
+    using SortedVector::isEmpty;
+};
+
+struct HalClientValues {
+    sp<HalClient> client;
+    std::list<VehiclePropValue *> values;
+};
+
+class SubscriptionManager {
+public:
+    virtual ~SubscriptionManager() {}
+
+    /**
+     * Updates subscription. Returns the vector of properties subscription that
+     * needs to be updated in VehicleHAL.
+     */
+    std::list<SubscribeOptions> addOrUpdateSubscription(
+            const sp<IVehicleCallback>& callback,
+            const hidl_vec<SubscribeOptions>& optionList);
+
+    /**
+     * Returns a list of IVehicleCallback -> list of VehiclePropValue ready for
+     * dispatching to its clients.
+     */
+    std::list<HalClientValues> distributeValuesToClients(
+            const std::vector<recyclable_ptr<VehiclePropValue>>& propValues,
+            SubscribeFlags flags) const;
+
+    std::list<sp<HalClient>> getSubscribedClients(
+        int32_t propId, int32_t area, SubscribeFlags flags) const;
+
+    /**
+     * Returns true the client was unsubscribed successfully and there are
+     * no more clients subscribed to given propId.
+     */
+    bool unsubscribe(const sp<IVehicleCallback>& callback,
+                     int32_t propId);
+private:
+    std::list<sp< HalClient>> getSubscribedClientsLocked(
+            int32_t propId, int32_t area, SubscribeFlags flags) const;
+
+    bool updateHalEventSubscriptionLocked(const SubscribeOptions &opts,
+                                          SubscribeOptions *out);
+
+    void addClientToPropMapLocked(int32_t propId,
+                                  const sp<HalClient> &client);
+
+    sp<HalClientVector> getClientsForPropertyLocked(
+            int32_t propId) const;
+
+    sp<HalClient> getOrCreateHalClientLocked(
+            const sp<IVehicleCallback> &callback);
+
+private:
+    using MuxGuard = std::lock_guard<std::mutex>;
+
+    mutable std::mutex mLock;
+
+    std::map<sp<IVehicleCallback>, sp<HalClient>> mClients;
+    std::map<int32_t, sp<HalClientVector>> mPropToClients;
+    std::map<int32_t, SubscribeOptions> mHalEventSubscribeOptions;
+};
+
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+
+#endif // android_hardware_automotive_vehicle_V2_0_SubscriptionManager_H_
diff --git a/automotive/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.cpp
new file mode 100644
index 0000000..3a5e504
--- /dev/null
+++ b/automotive/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.cpp
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2016 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 "automotive.vehicle@2.0-impl"
+
+#include "VehicleHalManager.h"
+
+#include <fstream>
+
+#include <android/log.h>
+#include <private/android_filesystem_config.h>
+
+#include "VehicleUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+using namespace std::placeholders;
+
+constexpr std::chrono::milliseconds kHalEventBatchingTimeWindow(10);
+
+const VehiclePropValue kEmptyValue{};
+
+/**
+ * Indicates what's the maximum size of hidl_vec<VehiclePropValue> we want
+ * to store in reusable object pool.
+ */
+constexpr auto kMaxHidlVecOfVehiclPropValuePoolSize = 20;
+
+Return<void> VehicleHalManager::getAllPropConfigs(
+        getAllPropConfigs_cb _hidl_cb) {
+    ALOGI("getAllPropConfigs called");
+    hidl_vec<VehiclePropConfig> hidlConfigs;
+    auto& halConfig = mConfigIndex->getAllConfigs();
+
+    hidlConfigs.setToExternal(
+            const_cast<VehiclePropConfig *>(halConfig.data()),
+            halConfig.size());
+
+    _hidl_cb(hidlConfigs);
+
+    return Void();
+}
+
+Return<void> VehicleHalManager::getPropConfigs(
+        const hidl_vec<int32_t> &properties,
+        getPropConfigs_cb _hidl_cb) {
+    std::vector<VehiclePropConfig> configs;
+    for (size_t i = 0; i < properties.size(); i++) {
+        auto prop = properties[i];
+        if (mConfigIndex->hasConfig(prop)) {
+            configs.push_back(mConfigIndex->getConfig(prop));
+        } else {
+            ALOGW("Requested config for undefined property: 0x%x", prop);
+            _hidl_cb(StatusCode::INVALID_ARG, hidl_vec<VehiclePropConfig>());
+        }
+    }
+
+    _hidl_cb(StatusCode::OK, configs);
+
+    return Void();
+}
+
+Return<void> VehicleHalManager::get(
+        const VehiclePropValue& requestedPropValue, get_cb _hidl_cb) {
+    const auto* config = getPropConfigOrNull(requestedPropValue.prop);
+    if (config == nullptr) {
+        ALOGE("Failed to get value: config not found, property: 0x%x",
+              requestedPropValue.prop);
+        _hidl_cb(StatusCode::INVALID_ARG, kEmptyValue);
+        return Void();
+    }
+
+    if (!checkReadPermission(*config, getCaller())) {
+        _hidl_cb(StatusCode::ACCESS_DENIED, kEmptyValue);
+        return Void();
+    }
+
+    StatusCode status;
+    auto value = mHal->get(requestedPropValue, &status);
+    _hidl_cb(status, value.get() ? *value : kEmptyValue);
+
+
+    return Void();
+}
+
+Return<StatusCode> VehicleHalManager::set(const VehiclePropValue &value) {
+    auto prop = value.prop;
+    const auto* config = getPropConfigOrNull(prop);
+    if (config == nullptr) {
+        ALOGE("Failed to set value: config not found, property: 0x%x", prop);
+        return StatusCode::INVALID_ARG;
+    }
+
+    if (!checkWritePermission(*config, getCaller())) {
+        return StatusCode::ACCESS_DENIED;
+    }
+
+    handlePropertySetEvent(value);
+
+    auto status = mHal->set(value);
+
+    return Return<StatusCode>(status);
+}
+
+Return<StatusCode> VehicleHalManager::subscribe(
+        const sp<IVehicleCallback> &callback,
+        const hidl_vec<SubscribeOptions> &options) {
+    hidl_vec<SubscribeOptions> verifiedOptions(options);
+    auto caller = getCaller();
+    for (size_t i = 0; i < verifiedOptions.size(); i++) {
+        SubscribeOptions& ops = verifiedOptions[i];
+        auto prop = ops.propId;
+
+        const auto* config = getPropConfigOrNull(prop);
+        if (config == nullptr) {
+            ALOGE("Failed to subscribe: config not found, property: 0x%x",
+                  prop);
+            return StatusCode::INVALID_ARG;
+        }
+
+        if (!checkAcl(caller.uid, config->prop, VehiclePropertyAccess::READ)) {
+            return StatusCode::ACCESS_DENIED;
+        }
+
+        if (!isSubscribable(*config, ops.flags)) {
+            ALOGE("Failed to subscribe: property 0x%x is not subscribable",
+                  prop);
+            return StatusCode::INVALID_ARG;
+        }
+
+        int32_t areas = isGlobalProp(prop) ? 0 : ops.vehicleAreas;
+        if (areas != 0 && ((areas & config->supportedAreas) != areas)) {
+            ALOGE("Failed to subscribe property 0x%x. Requested areas 0x%x are "
+                  "out of supported range of 0x%x", prop, ops.vehicleAreas,
+                  config->supportedAreas);
+            return StatusCode::INVALID_ARG;
+        }
+
+        ops.vehicleAreas = areas;
+        ops.sampleRate = checkSampleRate(*config, ops.sampleRate);
+    }
+
+    std::list<SubscribeOptions> updatedOptions =
+        mSubscriptionManager.addOrUpdateSubscription(callback, verifiedOptions);
+
+    for (auto opt : updatedOptions) {
+        mHal->subscribe(opt.propId, opt.vehicleAreas, opt.sampleRate);
+    }
+    // TODO(pavelm): link to death callback (not implemented yet in HIDL)
+
+    return StatusCode::OK;
+}
+
+Return<StatusCode> VehicleHalManager::unsubscribe(
+        const sp<IVehicleCallback>& callback, int32_t propId) {
+    if (mSubscriptionManager.unsubscribe(callback, propId)) {
+        mHal->unsubscribe(propId);
+    }
+    return StatusCode::OK;
+}
+
+Return<void> VehicleHalManager::debugDump(IVehicle::debugDump_cb _hidl_cb) {
+    _hidl_cb("");
+    return Void();
+}
+
+void VehicleHalManager::init() {
+    ALOGI("VehicleHalManager::init");
+
+    mHidlVecOfVehiclePropValuePool.resize(kMaxHidlVecOfVehiclPropValuePoolSize);
+
+
+    mBatchingConsumer.run(&mEventQueue,
+                          kHalEventBatchingTimeWindow,
+                          std::bind(&VehicleHalManager::onBatchHalEvent,
+                                    this, _1));
+
+    mHal->init(&mValueObjectPool,
+               std::bind(&VehicleHalManager::onHalEvent, this, _1),
+               std::bind(&VehicleHalManager::onHalPropertySetError, this,
+                         _1, _2, _3));
+
+    // Initialize index with vehicle configurations received from VehicleHal.
+    auto supportedPropConfigs = mHal->listProperties();
+    mConfigIndex.reset(new VehiclePropConfigIndex(supportedPropConfigs));
+
+    std::vector<int32_t> supportedProperties(
+        supportedPropConfigs.size());
+    for (const auto& config : supportedPropConfigs) {
+        supportedProperties.push_back(config.prop);
+    }
+
+    AccessControlConfigParser aclParser(supportedProperties);
+    const char* configs[] = { "/system/etc/vehicle_access.conf",
+                              "/vendor/etc/vehicle_access.conf" };
+    for (const char* filename : configs) {
+        readAndParseAclConfig(filename, &aclParser, &mPropertyAclMap);
+    }
+}
+
+VehicleHalManager::~VehicleHalManager() {
+    mBatchingConsumer.requestStop();
+    mEventQueue.deactivate();
+    // We have to wait until consumer thread is fully stopped because it may
+    // be in a state of running callback (onBatchHalEvent).
+    mBatchingConsumer.waitStopped();
+    ALOGI("VehicleHalManager::dtor");
+}
+
+void VehicleHalManager::onHalEvent(VehiclePropValuePtr v) {
+    mEventQueue.push(std::move(v));
+}
+
+void VehicleHalManager::onHalPropertySetError(StatusCode errorCode,
+                                              int32_t property,
+                                              int32_t areaId) {
+    const auto& clients = mSubscriptionManager.getSubscribedClients(
+            property, 0, SubscribeFlags::HAL_EVENT);
+
+    for (auto client : clients) {
+        client->getCallback()->onPropertySetError(errorCode, property, areaId);
+    }
+}
+
+void VehicleHalManager::onBatchHalEvent(
+        const std::vector<VehiclePropValuePtr>& values) {
+    const auto& clientValues = mSubscriptionManager.distributeValuesToClients(
+            values, SubscribeFlags::HAL_EVENT);
+
+    for (const HalClientValues& cv : clientValues) {
+        auto vecSize = cv.values.size();
+        hidl_vec<VehiclePropValue> vec;
+        if (vecSize < kMaxHidlVecOfVehiclPropValuePoolSize) {
+            vec.setToExternal(&mHidlVecOfVehiclePropValuePool[0], vecSize);
+        } else {
+            vec.resize(vecSize);
+        }
+
+        int i = 0;
+        for (VehiclePropValue* pValue : cv.values) {
+            shallowCopy(&(vec)[i++], *pValue);
+        }
+        cv.client->getCallback()->onPropertyEvent(vec);
+    }
+}
+
+bool VehicleHalManager::isSampleRateFixed(VehiclePropertyChangeMode mode) {
+    return (mode & VehiclePropertyChangeMode::ON_SET)
+           || (mode & VehiclePropertyChangeMode::ON_CHANGE);
+}
+
+float VehicleHalManager::checkSampleRate(const VehiclePropConfig &config,
+                                         float sampleRate) {
+    if (isSampleRateFixed(config.changeMode)) {
+        if (std::abs(sampleRate) > std::numeric_limits<float>::epsilon()) {
+            ALOGW("Sample rate is greater than zero for on change type. "
+                      "Ignoring it.");
+        }
+        return 0.0;
+    } else {
+        if (sampleRate > config.maxSampleRate) {
+            ALOGW("Sample rate %f is higher than max %f. Setting sampling rate "
+                      "to max.", sampleRate, config.maxSampleRate);
+            return config.maxSampleRate;
+        }
+        if (sampleRate < config.minSampleRate) {
+            ALOGW("Sample rate %f is lower than min %f. Setting sampling rate "
+                      "to min.", sampleRate, config.minSampleRate);
+            return config.minSampleRate;
+        }
+    }
+    return sampleRate;  // Provided sample rate was good, no changes.
+}
+
+bool VehicleHalManager::isSubscribable(const VehiclePropConfig& config,
+                                       SubscribeFlags flags) {
+    bool isReadable = config.access & VehiclePropertyAccess::READ;
+
+    if (!isReadable && (SubscribeFlags::HAL_EVENT & flags)) {
+        ALOGW("Cannot subscribe, property 0x%x is not readable", config.prop);
+        return false;
+    }
+    if (config.changeMode == VehiclePropertyChangeMode::STATIC) {
+        ALOGW("Cannot subscribe, property 0x%x is static", config.prop);
+        return false;
+    }
+
+    //TODO: extend to support event notification for set from android
+    if (config.changeMode == VehiclePropertyChangeMode::POLL) {
+        ALOGW("Cannot subscribe, property 0x%x is poll only", config.prop);
+        return false;
+    }
+    return true;
+}
+
+bool VehicleHalManager::checkAcl(uid_t callerUid, int32_t propertyId,
+                                 VehiclePropertyAccess requiredAccess) const {
+    if (callerUid == AID_SYSTEM && isSystemProperty(propertyId)) {
+        return true;
+    }
+
+    auto range = mPropertyAclMap.equal_range(propertyId);
+    for (auto it = range.first; it != range.second; ++it) {
+        auto& acl = it->second;
+        if (acl.uid == callerUid && (acl.access & requiredAccess)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool VehicleHalManager::checkWritePermission(const VehiclePropConfig &config,
+                                             const Caller& caller) const {
+    if (!(config.access & VehiclePropertyAccess::WRITE)) {
+        ALOGW("Property 0%x has no write access", config.prop);
+        return false;
+    }
+    return checkAcl(caller.uid, config.prop, VehiclePropertyAccess::WRITE);
+}
+
+bool VehicleHalManager::checkReadPermission(const VehiclePropConfig &config,
+                                            const Caller& caller) const {
+    if (!(config.access & VehiclePropertyAccess::READ)) {
+        ALOGW("Property 0%x has no read access", config.prop);
+        return false;
+    }
+
+    return checkAcl(caller.uid, config.prop, VehiclePropertyAccess::READ);
+}
+
+void VehicleHalManager::handlePropertySetEvent(const VehiclePropValue& value) {
+    auto clients = mSubscriptionManager.getSubscribedClients(
+            value.prop, value.areaId, SubscribeFlags::SET_CALL);
+    for (auto client : clients) {
+        client->getCallback()->onPropertySet(value);
+    }
+}
+
+const VehiclePropConfig* VehicleHalManager::getPropConfigOrNull(
+        int32_t prop) const {
+    return mConfigIndex->hasConfig(prop)
+           ? &mConfigIndex->getConfig(prop) : nullptr;
+}
+
+Caller VehicleHalManager::getCaller() {
+    Caller caller;
+    IPCThreadState* self = IPCThreadState::self();
+    caller.pid = self->getCallingPid();
+    caller.uid = self->getCallingUid();
+
+    return caller;
+}
+
+void VehicleHalManager::readAndParseAclConfig(const char* filename,
+                                              AccessControlConfigParser* parser,
+                                              PropertyAclMap* outAclMap) {
+    std::ifstream file(filename);
+    if (file.is_open()) {
+        ALOGI("Parsing file: %s", filename);
+        parser->parseFromStream(&file, outAclMap);
+        file.close();
+    }
+}
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.h b/automotive/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.h
new file mode 100644
index 0000000..4bff4d1
--- /dev/null
+++ b/automotive/vehicle/2.0/default/vehicle_hal_manager/VehicleHalManager.h
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_VehicleHalManager_H_
+#define android_hardware_automotive_vehicle_V2_0_VehicleHalManager_H_
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <list>
+#include <map>
+#include <memory>
+#include <set>
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <hwbinder/IPCThreadState.h>
+
+#include "AccessControlConfigParser.h"
+#include "ConcurrentQueue.h"
+#include "SubscriptionManager.h"
+#include "VehicleHal.h"
+#include "VehicleObjectPool.h"
+#include "VehiclePropConfigIndex.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+struct Caller {
+    pid_t pid;
+    uid_t uid;
+};
+
+/**
+ * This class is a thick proxy between IVehicle HIDL interface and vendor's implementation.
+ *
+ * It has some boilerplate code like batching and caching property values, checking permissions,
+ * etc. Vendors must implement VehicleHal class.
+ */
+class VehicleHalManager : public IVehicle {
+public:
+    VehicleHalManager(VehicleHal* vehicleHal)
+        : mHal(vehicleHal) {
+        init();
+    }
+
+    virtual ~VehicleHalManager();
+
+    void init();
+
+    // ---------------------------------------------------------------------------------------------
+    // Methods derived from IVehicle
+    Return<void> getAllPropConfigs(getAllPropConfigs_cb _hidl_cb)  override;
+    Return<void> getPropConfigs(const hidl_vec<int32_t>& properties,
+                                getPropConfigs_cb _hidl_cb)  override;
+    Return<void> get(const VehiclePropValue& requestedPropValue,
+                     get_cb _hidl_cb)  override;
+    Return<StatusCode> set(const VehiclePropValue& value)  override;
+    Return<StatusCode> subscribe(const sp<IVehicleCallback>& callback,
+                                const hidl_vec<SubscribeOptions>& options)  override;
+    Return<StatusCode> unsubscribe(const sp<IVehicleCallback>& callback,
+                                   int32_t propId)  override;
+    Return<void> debugDump(debugDump_cb _hidl_cb = nullptr) override;
+
+private:
+    using VehiclePropValuePtr = VehicleHal::VehiclePropValuePtr;
+    // Returns true if needs to call again shortly.
+    using RetriableAction = std::function<bool()>;
+
+    // ---------------------------------------------------------------------------------------------
+    // Events received from VehicleHal
+    void onHalEvent(VehiclePropValuePtr  v);
+    void onHalPropertySetError(StatusCode errorCode, int32_t property,
+                               int32_t areaId);
+
+    // ---------------------------------------------------------------------------------------------
+    // This method will be called from BatchingConsumer thread
+    void onBatchHalEvent(const std::vector<VehiclePropValuePtr >& values);
+
+    void handlePropertySetEvent(const VehiclePropValue& value);
+
+    const VehiclePropConfig* getPropConfigOrNull(int32_t prop) const;
+
+    bool checkWritePermission(const VehiclePropConfig &config,
+                              const Caller& callee) const;
+    bool checkReadPermission(const VehiclePropConfig &config,
+                             const Caller& caller) const;
+    bool checkAcl(uid_t callerUid,
+                  int32_t propertyId,
+                  VehiclePropertyAccess requiredAccess) const;
+
+    static bool isSubscribable(const VehiclePropConfig& config,
+                               SubscribeFlags flags);
+    static bool isSampleRateFixed(VehiclePropertyChangeMode mode);
+    static float checkSampleRate(const VehiclePropConfig& config,
+                                 float sampleRate);
+    static void readAndParseAclConfig(const char* filename,
+                                      AccessControlConfigParser* parser,
+                                      PropertyAclMap* outAclMap);
+
+    static Caller getCaller();
+
+private:
+    VehicleHal* mHal;
+    std::unique_ptr<VehiclePropConfigIndex> mConfigIndex;
+    SubscriptionManager mSubscriptionManager;
+
+    hidl_vec<VehiclePropValue> mHidlVecOfVehiclePropValuePool;
+
+    ConcurrentQueue<VehiclePropValuePtr> mEventQueue;
+    BatchingConsumer<VehiclePropValuePtr> mBatchingConsumer;
+    VehiclePropValuePool mValueObjectPool;
+    PropertyAclMap mPropertyAclMap;
+};
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+
+#endif // android_hardware_automotive_vehicle_V2_0_VehicleHalManager_H_
diff --git a/automotive/vehicle/2.0/default/vehicle_hal_manager/VehicleObjectPool.cpp b/automotive/vehicle/2.0/default/vehicle_hal_manager/VehicleObjectPool.cpp
new file mode 100644
index 0000000..a79c55c
--- /dev/null
+++ b/automotive/vehicle/2.0/default/vehicle_hal_manager/VehicleObjectPool.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2016 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 "automotive.vehicle@2.0-impl"
+
+#include "VehicleObjectPool.h"
+
+#include <log/log.h>
+
+#include "VehicleUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtain(
+        VehiclePropertyType type, size_t vecSize) {
+    return isDisposable(type, vecSize)
+           ? obtainDisposable(type, vecSize)
+           : obtainRecylable(type, vecSize);
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtain(
+        const VehiclePropValue& src) {
+    if (src.prop == toInt(VehicleProperty::INVALID)) {
+        ALOGE("Unable to obtain an object from pool for unknown property");
+        return RecyclableType();
+    }
+    VehiclePropertyType type = getPropType(src.prop);
+    size_t vecSize = getVehicleRawValueVectorSize(src.value, type);;
+    auto dest = obtain(type, vecSize);
+
+    dest->prop = src.prop;
+    dest->areaId = src.areaId;
+    dest->timestamp = src.timestamp;
+    copyVehicleRawValue(&dest->value, src.value);
+
+    return dest;
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainInt32(
+        int32_t value) {
+    auto val = obtain(VehiclePropertyType::INT32);
+    val->value.int32Values[0] = value;
+    return val;
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainInt64(
+        int64_t value) {
+    auto val = obtain(VehiclePropertyType::INT64);
+    val->value.int64Values[0] = value;
+    return val;
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainFloat(
+        float value)  {
+    auto val = obtain(VehiclePropertyType::FLOAT);
+    val->value.floatValues[0] = value;
+    return val;
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainString(
+        const char* cstr) {
+    auto val = obtain(VehiclePropertyType::STRING);
+    val->value.stringValue = cstr;
+    return val;
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainComplex() {
+    return obtain(VehiclePropertyType::COMPLEX);
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainRecylable(
+        VehiclePropertyType type, size_t vecSize) {
+    // VehiclePropertyType is not overlapping with vectorSize.
+    int32_t key = static_cast<int32_t>(type)
+                  | static_cast<int32_t>(vecSize);
+
+    std::lock_guard<std::mutex> g(mLock);
+    auto it = mValueTypePools.find(key);
+
+    if (it == mValueTypePools.end()) {
+        auto newPool(std::make_unique<InternalPool>(type, vecSize));
+        it = mValueTypePools.emplace(key, std::move(newPool)).first;
+    }
+    return it->second->obtain();
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainBoolean(
+        bool value)  {
+    return obtainInt32(value);
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainDisposable(
+        VehiclePropertyType valueType, size_t vectorSize) const {
+    return RecyclableType {
+        createVehiclePropValue(valueType, vectorSize).release(),
+        mDisposableDeleter
+    };
+}
+
+VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtain(
+        VehiclePropertyType type) {
+    return obtain(type, 1);
+}
+
+
+void VehiclePropValuePool::InternalPool::recycle(VehiclePropValue* o) {
+    if (o == nullptr) {
+        ALOGE("Attempt to recycle nullptr");
+        return;
+    }
+
+    if (!check(&o->value)) {
+        ALOGE("Discarding value for prop 0x%x because it contains "
+                  "data that is not consistent with this pool. "
+                  "Expected type: %d, vector size: %d",
+              o->prop, mPropType, mVectorSize);
+        delete o;
+    } else {
+        ObjectPool<VehiclePropValue>::recycle(o);
+    }
+}
+
+bool VehiclePropValuePool::InternalPool::check(VehiclePropValue::RawValue* v) {
+    return check(&v->int32Values,
+                 (VehiclePropertyType::INT32 == mPropType
+                  || VehiclePropertyType::INT32_VEC == mPropType
+                  || VehiclePropertyType::BOOLEAN == mPropType))
+           && check(&v->floatValues,
+                    (VehiclePropertyType::FLOAT == mPropType
+                     || VehiclePropertyType::FLOAT_VEC == mPropType))
+           && check(&v->int64Values,
+                    VehiclePropertyType::INT64 == mPropType)
+           && check(&v->bytes,
+                    VehiclePropertyType::BYTES == mPropType)
+           && v->stringValue.size() == 0;
+}
+
+VehiclePropValue* VehiclePropValuePool::InternalPool::createObject() {
+    return createVehiclePropValue(mPropType, mVectorSize).release();
+}
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/vehicle_hal_manager/VehicleObjectPool.h b/automotive/vehicle/2.0/default/vehicle_hal_manager/VehicleObjectPool.h
new file mode 100644
index 0000000..05c649b
--- /dev/null
+++ b/automotive/vehicle/2.0/default/vehicle_hal_manager/VehicleObjectPool.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2016 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_VehicleObjectPool_H_
+#define android_hardware_automotive_vehicle_V2_0_VehicleObjectPool_H_
+
+#include <deque>
+#include <map>
+#include <mutex>
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+// Handy metric mostly for unit tests and debug.
+#define INC_METRIC_IF_DEBUG(val) PoolStats::instance()->val++;
+struct PoolStats {
+    std::atomic<uint32_t> Obtained {0};
+    std::atomic<uint32_t> Created {0};
+    std::atomic<uint32_t> Recycled {0};
+
+    static PoolStats* instance() {
+        static PoolStats inst;
+        return &inst;
+    }
+};
+
+template<typename T>
+struct Deleter  {
+    using OnDeleteFunc = std::function<void(T*)>;
+
+    Deleter(const OnDeleteFunc& f) : mOnDelete(f) {};
+
+    Deleter() = default;
+    Deleter(const Deleter&) = default;
+
+    void operator()(T* o) {
+        mOnDelete(o);
+    }
+private:
+    OnDeleteFunc mOnDelete;
+};
+
+/**
+ * This is std::unique_ptr<> with custom delete operation that typically moves
+ * the pointer it holds back to ObjectPool.
+ */
+template <typename T>
+using recyclable_ptr = typename std::unique_ptr<T, Deleter<T>>;
+
+/**
+ * Generic abstract object pool class. Users of this class must implement
+ * #createObject method.
+ *
+ * This class is thread-safe. Concurrent calls to #obtain(...) method from
+ * multiple threads is OK, also client can obtain an object in one thread and
+ * then move ownership to another thread.
+ *
+ */
+template<typename T>
+class ObjectPool {
+public:
+    ObjectPool() = default;
+    virtual ~ObjectPool() = default;
+
+    virtual recyclable_ptr<T> obtain() {
+        std::lock_guard<std::mutex> g(mLock);
+        INC_METRIC_IF_DEBUG(Obtained)
+        if (mObjects.empty()) {
+            INC_METRIC_IF_DEBUG(Created)
+            return wrap(createObject());
+        }
+
+        auto o = wrap(mObjects.front().release());
+        mObjects.pop_front();
+
+        return o;
+    }
+
+    ObjectPool& operator =(const ObjectPool &) = delete;
+    ObjectPool(const ObjectPool &) = delete;
+
+protected:
+    virtual T* createObject() = 0;
+
+    virtual void recycle(T* o) {
+        INC_METRIC_IF_DEBUG(Recycled)
+        std::lock_guard<std::mutex> g(mLock);
+        mObjects.push_back(std::unique_ptr<T> { o } );
+    }
+
+private:
+    const Deleter<T>& getDeleter() {
+        if (!mDeleter.get()) {
+            Deleter<T> *d = new Deleter<T>(std::bind(
+                &ObjectPool::recycle, this, std::placeholders::_1));
+            mDeleter.reset(d);
+        }
+        return *mDeleter.get();
+    }
+
+    recyclable_ptr<T> wrap(T* raw) {
+        return recyclable_ptr<T> { raw, getDeleter() };
+    }
+
+private:
+    mutable std::mutex mLock;
+    std::deque<std::unique_ptr<T>> mObjects;
+    std::unique_ptr<Deleter<T>> mDeleter;
+};
+
+/**
+ * This class provides a pool of recycable VehiclePropertyValue objects.
+ *
+ * It has only one overloaded public method - obtain(...), users must call this
+ * method when new object is needed with given VehiclePropertyType and vector
+ * size (for vector properties). This method returns a recycable smart pointer
+ * to VehiclePropertyValue, essentially this is a std::unique_ptr with custom
+ * delete function, so recycable object has only one owner and developers can
+ * safely pass it around. Once this object goes out of scope, it will be
+ * returned the the object pool.
+ *
+ * Some objects are not recycable: strings and vector data types with
+ * vector length > maxRecyclableVectorSize (provided in the constructor). These
+ * objects will be deleted immediately once the go out of scope. There's no
+ * synchornization penalty for these objects since we do not store them in the
+ * pool.
+ *
+ * This class is thread-safe. Users can obtain an object in one thread and pass
+ * it to another.
+ *
+ * Sample usage:
+ *
+ *   VehiclePropValuePool pool;
+ *   auto v = pool.obtain(VehiclePropertyType::INT32);
+ *   v->propId = VehicleProperty::HVAC_FAN_SPEED;
+ *   v->areaId = VehicleAreaZone::ROW_1_LEFT;
+ *   v->timestamp = elapsedRealtimeNano();
+ *   v->value->int32Values[0] = 42;
+ *
+ *
+ */
+class VehiclePropValuePool {
+public:
+    using RecyclableType = recyclable_ptr<VehiclePropValue>;
+
+    /**
+     * Creates VehiclePropValuePool
+     *
+     * @param maxRecyclableVectorSize - vector value types (e.g.
+     * VehiclePropertyType::INT32_VEC) with size equal or less to this value
+     * will be stored in the pool. If users tries to obtain value with vector
+     * size greater than maxRecyclableVectorSize user will receive appropriate
+     * object, but once it goes out of scope it will be deleted immediately, not
+     * returning back to the object pool.
+     *
+     */
+    VehiclePropValuePool(size_t maxRecyclableVectorSize = 4) :
+        mMaxRecyclableVectorSize(maxRecyclableVectorSize) {};
+
+    RecyclableType obtain(VehiclePropertyType type);
+
+    RecyclableType obtain(VehiclePropertyType type, size_t vecSize);
+    RecyclableType obtain(const VehiclePropValue& src);
+    RecyclableType obtainBoolean(bool value);
+    RecyclableType obtainInt32(int32_t value);
+    RecyclableType obtainInt64(int64_t value);
+    RecyclableType obtainFloat(float value);
+    RecyclableType obtainString(const char* cstr);
+    RecyclableType obtainComplex();
+
+    VehiclePropValuePool(VehiclePropValuePool& ) = delete;
+    VehiclePropValuePool& operator=(VehiclePropValuePool&) = delete;
+private:
+    bool isDisposable(VehiclePropertyType type, size_t vecSize) const {
+        return vecSize > mMaxRecyclableVectorSize ||
+               VehiclePropertyType::STRING == type ||
+               VehiclePropertyType::COMPLEX == type;
+    }
+
+    RecyclableType obtainDisposable(VehiclePropertyType valueType,
+                                    size_t vectorSize) const;
+    RecyclableType obtainRecylable(VehiclePropertyType type,
+                                   size_t vecSize);
+
+    class InternalPool: public ObjectPool<VehiclePropValue> {
+    public:
+        InternalPool(VehiclePropertyType type, size_t vectorSize)
+            : mPropType(type), mVectorSize(vectorSize) {}
+
+        RecyclableType obtain() {
+            return ObjectPool<VehiclePropValue>::obtain();
+        }
+    protected:
+        VehiclePropValue* createObject() override;
+        void recycle(VehiclePropValue* o) override;
+    private:
+        bool check(VehiclePropValue::RawValue* v);
+
+        template <typename VecType>
+        bool check(hidl_vec<VecType>* vec, bool expected) {
+            return vec->size() == (expected ? mVectorSize : 0);
+        }
+    private:
+        VehiclePropertyType mPropType;
+        size_t mVectorSize;
+    };
+
+private:
+    const Deleter<VehiclePropValue> mDisposableDeleter {
+        [] (VehiclePropValue* v) {
+            delete v;
+        }
+    };
+
+private:
+    mutable std::mutex mLock;
+    const size_t mMaxRecyclableVectorSize;
+    std::map<int32_t, std::unique_ptr<InternalPool>> mValueTypePools;
+};
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_VehicleObjectPool_H_
diff --git a/automotive/vehicle/2.0/default/vehicle_hal_manager/VehiclePropConfigIndex.h b/automotive/vehicle/2.0/default/vehicle_hal_manager/VehiclePropConfigIndex.h
new file mode 100644
index 0000000..0528f68
--- /dev/null
+++ b/automotive/vehicle/2.0/default/vehicle_hal_manager/VehiclePropConfigIndex.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 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_VehiclePropConfigIndex_H_
+#define android_hardware_automotive_vehicle_V2_0_VehiclePropConfigIndex_H_
+
+#include <utils/KeyedVector.h>
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+/*
+ * This is thread-safe immutable class to hold vehicle property configuration
+ * data.
+ */
+class VehiclePropConfigIndex {
+public:
+    VehiclePropConfigIndex(
+        const std::vector<VehiclePropConfig>& properties)
+        : mConfigs(properties), mPropToConfig(mConfigs)
+    {}
+
+    bool hasConfig(int32_t property) const {
+        return mPropToConfig.indexOfKey(property) >= 0;
+    }
+
+    const VehiclePropConfig& getConfig(int32_t property) const {
+        return *mPropToConfig.valueFor(property);
+    }
+
+    const std::vector<VehiclePropConfig>& getAllConfigs() const {
+        return mConfigs;
+    }
+
+private:
+    typedef KeyedVector<int32_t, const VehiclePropConfig*> PropConfigMap;
+    class ImmutablePropConfigMap : private PropConfigMap {
+    public:
+        ImmutablePropConfigMap(const std::vector<VehiclePropConfig>& configs) {
+            setCapacity(configs.size());
+            for (auto& config : configs) {
+                add(config.prop, &config);
+            }
+        }
+    public:
+        using PropConfigMap::valueFor;
+        using PropConfigMap::indexOfKey;
+    };
+
+private:
+    const std::vector<VehiclePropConfig> mConfigs;
+    const ImmutablePropConfigMap mPropToConfig;  // mConfigs must be declared
+                                                 // first.
+};
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_VehiclePropConfigIndex_H_
diff --git a/automotive/vehicle/2.0/default/vehicle_hal_manager/VehicleUtils.cpp b/automotive/vehicle/2.0/default/vehicle_hal_manager/VehicleUtils.cpp
new file mode 100644
index 0000000..311cdef
--- /dev/null
+++ b/automotive/vehicle/2.0/default/vehicle_hal_manager/VehicleUtils.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2016 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 "automotive.vehicle@2.0-impl"
+
+#include "VehicleUtils.h"
+
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+//namespace utils {
+
+std::unique_ptr<VehiclePropValue> createVehiclePropValue(
+    VehiclePropertyType type, size_t vecSize) {
+    auto val = std::unique_ptr<VehiclePropValue>(new VehiclePropValue);
+    switch (type) {
+        case VehiclePropertyType::INT32:      // fall through
+        case VehiclePropertyType::INT32_VEC:  // fall through
+        case VehiclePropertyType::BOOLEAN:
+            val->value.int32Values.resize(vecSize);
+            break;
+        case VehiclePropertyType::FLOAT:      // fall through
+        case VehiclePropertyType::FLOAT_VEC:
+            val->value.floatValues.resize(vecSize);
+            break;
+        case VehiclePropertyType::INT64:
+            val->value.int64Values.resize(vecSize);
+            break;
+        case VehiclePropertyType::BYTES:
+            val->value.bytes.resize(vecSize);
+            break;
+        case VehiclePropertyType::STRING:
+        case VehiclePropertyType::COMPLEX:
+            break; // Valid, but nothing to do.
+        default:
+            ALOGE("createVehiclePropValue: unknown type: %d", type);
+            val.reset(nullptr);
+    }
+    return val;
+}
+
+size_t getVehicleRawValueVectorSize(
+    const VehiclePropValue::RawValue& value, VehiclePropertyType type) {
+    switch (type) {
+        case VehiclePropertyType::INT32:      // fall through
+        case VehiclePropertyType::INT32_VEC:  // fall through
+        case VehiclePropertyType::BOOLEAN:
+            return value.int32Values.size();
+        case VehiclePropertyType::FLOAT:      // fall through
+        case VehiclePropertyType::FLOAT_VEC:
+            return value.floatValues.size();
+        case VehiclePropertyType::INT64:
+            return value.int64Values.size();
+        case VehiclePropertyType::BYTES:
+            return value.bytes.size();
+        default:
+            return 0;
+    }
+}
+
+template<typename T>
+inline void copyHidlVec(hidl_vec <T>* dest, const hidl_vec <T>& src) {
+    for (size_t i = 0; i < std::min(dest->size(), src.size()); i++) {
+        (*dest)[i] = src[i];
+    }
+}
+
+void copyVehicleRawValue(VehiclePropValue::RawValue* dest,
+                         const VehiclePropValue::RawValue& src) {
+    dest->int32Values = src.int32Values;
+    dest->floatValues = src.floatValues;
+    dest->int64Values = src.int64Values;
+    dest->bytes = src.bytes;
+    dest->stringValue = src.stringValue;
+}
+
+template<typename T>
+void shallowCopyHidlVec(hidl_vec <T>* dest, const hidl_vec <T>& src) {
+    if (src.size() > 0) {
+        dest->setToExternal(const_cast<T*>(&src[0]), src.size());
+    } else if (dest->size() > 0) {
+        dest->resize(0);
+    }
+}
+
+void shallowCopyHidlStr(hidl_string* dest, const hidl_string& src) {
+    if (!src.empty()) {
+        dest->setToExternal(src.c_str(), src.size());
+    } else if (dest->size() > 0) {
+        dest->setToExternal(0, 0);
+    }
+}
+
+void shallowCopy(VehiclePropValue* dest, const VehiclePropValue& src) {
+    dest->prop = src.prop;
+    dest->areaId = src.areaId;
+    dest->timestamp = src.timestamp;
+    shallowCopyHidlVec(&dest->value.int32Values, src.value.int32Values);
+    shallowCopyHidlVec(&dest->value.int64Values, src.value.int64Values);
+    shallowCopyHidlVec(&dest->value.floatValues, src.value.floatValues);
+    shallowCopyHidlVec(&dest->value.bytes, src.value.bytes);
+    shallowCopyHidlStr(&dest->value.stringValue, src.value.stringValue);
+}
+
+
+//}  // namespace utils
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/vehicle_hal_manager/VehicleUtils.h b/automotive/vehicle/2.0/default/vehicle_hal_manager/VehicleUtils.h
new file mode 100644
index 0000000..ce0b163
--- /dev/null
+++ b/automotive/vehicle/2.0/default/vehicle_hal_manager/VehicleUtils.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 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_VehicleUtils_H_
+#define android_hardware_automotive_vehicle_V2_0_VehicleUtils_H_
+
+#include <memory>
+
+#include <hidl/HidlSupport.h>
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+/** Represents all supported areas for a property. Can be used is  */
+constexpr int32_t kAllSupportedAreas = 0;
+
+/** Returns underlying (integer) value for given enum. */
+template<typename ENUM>
+inline constexpr typename std::underlying_type<ENUM>::type toInt(
+        ENUM const value) {
+    return static_cast<typename std::underlying_type<ENUM>::type>(value);
+}
+
+inline constexpr VehiclePropertyType getPropType(int32_t prop) {
+    return static_cast<VehiclePropertyType>(
+            prop & toInt(VehiclePropertyType::MASK));
+}
+
+inline constexpr VehiclePropertyGroup getPropGroup(int32_t prop) {
+    return static_cast<VehiclePropertyGroup>(
+            prop & toInt(VehiclePropertyGroup::MASK));
+}
+
+inline constexpr VehicleArea getPropArea(int32_t prop) {
+    return static_cast<VehicleArea>(prop & toInt(VehicleArea::MASK));
+}
+
+inline constexpr bool isGlobalProp(int32_t prop) {
+    return getPropArea(prop) == VehicleArea::GLOBAL;
+}
+
+inline constexpr bool isSystemProperty(int32_t prop) {
+    return VehiclePropertyGroup::SYSTEM == getPropGroup(prop);
+}
+
+std::unique_ptr<VehiclePropValue> createVehiclePropValue(
+    VehiclePropertyType type, size_t vecSize);
+
+size_t getVehicleRawValueVectorSize(
+    const VehiclePropValue::RawValue& value, VehiclePropertyType type);
+
+void copyVehicleRawValue(VehiclePropValue::RawValue* dest,
+                                const VehiclePropValue::RawValue& src);
+
+template<typename T>
+void shallowCopyHidlVec(hidl_vec<T>* dest, const hidl_vec<T>& src);
+
+void shallowCopyHidlStr(hidl_string* dest, const hidl_string& src);
+
+void shallowCopy(VehiclePropValue* dest, const VehiclePropValue& src);
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_VehicleUtils_H_