Merge "[vts-core] add VtsHalBootV1_0TargetTest to vts-core"
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..98e125b
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+  "presubmit": [
+    {
+      "name": "hidl_implementation_test"
+    }
+  ]
+}
+
diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
index 2703b2b..15be3bf 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
@@ -24,7 +24,7 @@
     //        flushCommand makes sure all local command are sent, thus should reduce
     //        the latency between local and remote destruction.
     IPCThreadState::self()->flushCommands();
-    usleep(100);
+    usleep(100 * 1000);
 }
 
 TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index fb96323..0778720 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -699,13 +699,27 @@
 
     Return<Result> closeStream() {
         open = false;
-        return stream->close();
+        auto res = stream->close();
+        stream.clear();
+        waitForStreamDestruction();
+        return res;
+    }
+
+    void waitForStreamDestruction() {
+        // FIXME: there is no way to know when the remote IStream is being destroyed
+        //        Binder does not support testing if an object is alive, thus
+        //        wait for 100ms to let the binder destruction propagates and
+        //        the remote device has the time to be destroyed.
+        //        flushCommand makes sure all local command are sent, thus should reduce
+        //        the latency between local and remote destruction.
+        IPCThreadState::self()->flushCommands();
+        usleep(100 * 1000);
     }
 
    private:
     void TearDown() override {
         if (open) {
-            ASSERT_OK(stream->close());
+            ASSERT_OK(closeStream());
         }
         AudioConfigPrimaryTest::TearDown();
     }
@@ -1003,8 +1017,14 @@
                ASSERT_RESULT(invalidStateOrNotSupported, stream->stop()))
 
 TEST_IO_STREAM(close, "Make sure a stream can be closed", ASSERT_OK(closeStream()))
-TEST_IO_STREAM(closeTwice, "Make sure a stream can not be closed twice", ASSERT_OK(closeStream());
-               ASSERT_RESULT(Result::INVALID_STATE, closeStream()))
+// clang-format off
+TEST_IO_STREAM(closeTwice, "Make sure a stream can not be closed twice",
+        auto streamCopy = stream;
+        ASSERT_OK(closeStream());
+        ASSERT_RESULT(Result::INVALID_STATE, streamCopy->close());
+        streamCopy.clear();
+        waitForStreamDestruction())
+// clang-format on
 
 static void testCreateTooBigMmapBuffer(IStream* stream) {
     MmapBufferInfo info;
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index fc441ed..2c5e5cc 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -162,672 +162,708 @@
 };
 
 const ConfigDeclaration kVehicleProperties[]{
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::STATIC,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.floatValues = {15000.0f}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::STATIC,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.floatValues = {15000.0f}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::INFO_FUEL_TYPE),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::STATIC,
-         },
-     .initialValue = {.int32Values = {1}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::INFO_FUEL_TYPE),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::STATIC,
+                 },
+         .initialValue = {.int32Values = {1}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::INFO_EV_BATTERY_CAPACITY),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::STATIC,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.floatValues = {150000.0f}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::INFO_EV_BATTERY_CAPACITY),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::STATIC,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.floatValues = {150000.0f}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::INFO_EV_CONNECTOR_TYPE),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::STATIC,
-         },
-     .initialValue = {.int32Values = {1}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::INFO_EV_CONNECTOR_TYPE),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::STATIC,
+                 },
+         .initialValue = {.int32Values = {1}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::STATIC,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.int32Values = {SEAT_1_LEFT}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::STATIC,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.int32Values = {SEAT_1_LEFT}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::INFO_FUEL_DOOR_LOCATION),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::STATIC,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.int32Values = {FUEL_DOOR_REAR_LEFT}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::INFO_FUEL_DOOR_LOCATION),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::STATIC,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.int32Values = {FUEL_DOOR_REAR_LEFT}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::INFO_EV_PORT_LOCATION),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::STATIC,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::INFO_EV_PORT_LOCATION),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::STATIC,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::INFO_MAKE),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::STATIC,
-         },
-     .initialValue = {.stringValue = "Toy Vehicle"}},
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .minSampleRate = 1.0f,
-             .maxSampleRate = 10.0f,
-         },
-     .initialValue = {.floatValues = {0.0f}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::INFO_MAKE),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::STATIC,
+                 },
+         .initialValue = {.stringValue = "Toy Vehicle"}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .minSampleRate = 1.0f,
+                         .maxSampleRate = 10.0f,
+                 },
+         .initialValue = {.floatValues = {0.0f}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::VEHICLE_SPEED_DISPLAY_UNITS),
-             .access = VehiclePropertyAccess::READ_WRITE,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .configArray = {(int)VehicleUnit::METER_PER_SEC,
-                             (int)VehicleUnit::MILES_PER_HOUR,
-                             (int)VehicleUnit::KILOMETERS_PER_HOUR},
-         },
-     .initialValue = {.int32Values = {(int)VehicleUnit::KILOMETERS_PER_HOUR}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::VEHICLE_SPEED_DISPLAY_UNITS),
+                         .access = VehiclePropertyAccess::READ_WRITE,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .configArray = {(int)VehicleUnit::METER_PER_SEC,
+                                         (int)VehicleUnit::MILES_PER_HOUR,
+                                         (int)VehicleUnit::KILOMETERS_PER_HOUR},
+                 },
+         .initialValue = {.int32Values = {(int)VehicleUnit::KILOMETERS_PER_HOUR}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::STATIC,
-             // this was a zoned property on an old vhal, but it is meant to be global
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.int32Values = {SEAT_1_LEFT}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::STATIC,
+                         // this was a zoned property on an old vhal, but it is meant to be global
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.int32Values = {SEAT_1_LEFT}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::PERF_ODOMETER),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-         },
-     .initialValue = {.floatValues = {0.0f}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::PERF_ODOMETER),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                 },
+         .initialValue = {.floatValues = {0.0f}}},
 
-    {
-        .config =
-            {
-                .prop = toInt(VehicleProperty::ENGINE_RPM),
-                .access = VehiclePropertyAccess::READ,
-                .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
-                .minSampleRate = 1.0f,
-                .maxSampleRate = 10.0f,
-            },
-        .initialValue = {.floatValues = {0.0f}},
-    },
+        {
+                .config =
+                        {
+                                .prop = toInt(VehicleProperty::ENGINE_RPM),
+                                .access = VehiclePropertyAccess::READ,
+                                .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                                .minSampleRate = 1.0f,
+                                .maxSampleRate = 10.0f,
+                        },
+                .initialValue = {.floatValues = {0.0f}},
+        },
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::FUEL_LEVEL),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.floatValues = {15000.0f}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::FUEL_LEVEL),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.floatValues = {15000.0f}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::FUEL_DOOR_OPEN),
-             .access = VehiclePropertyAccess::READ_WRITE,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.int32Values = {0}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::FUEL_DOOR_OPEN),
+                         .access = VehiclePropertyAccess::READ_WRITE,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.int32Values = {0}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::EV_BATTERY_LEVEL),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.floatValues = {150000.0f}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::EV_BATTERY_LEVEL),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.floatValues = {150000.0f}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::EV_CHARGE_PORT_OPEN),
-             .access = VehiclePropertyAccess::READ_WRITE,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.int32Values = {0}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::EV_CHARGE_PORT_OPEN),
+                         .access = VehiclePropertyAccess::READ_WRITE,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.int32Values = {0}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::EV_CHARGE_PORT_CONNECTED),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.int32Values = {0}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::EV_CHARGE_PORT_CONNECTED),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.int32Values = {0}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.floatValues = {0.0f}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.floatValues = {0.0f}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::RANGE_REMAINING),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-             .minSampleRate = 1.0f,
-             .maxSampleRate = 2.0f,
-         },
-     .initialValue = {.floatValues = {100.0f}}},  // units in meters
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::RANGE_REMAINING),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                         .minSampleRate = 1.0f,
+                         .maxSampleRate = 2.0f,
+                 },
+         .initialValue = {.floatValues = {100.0f}}},  // units in meters
 
-    {.config =
-         {.prop = toInt(VehicleProperty::TIRE_PRESSURE),
-          .access = VehiclePropertyAccess::READ,
-          .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
-          .minSampleRate = 1.0f,
-          .maxSampleRate = 2.0f,
-          .areaConfigs =
-              {VehicleAreaConfig{
-                   .areaId = WHEEL_FRONT_LEFT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f,
-               },
-               VehicleAreaConfig{
-                   .areaId = WHEEL_FRONT_RIGHT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f,
-               },
-               VehicleAreaConfig{
-                   .areaId = WHEEL_REAR_LEFT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f,
-               },
-               VehicleAreaConfig{
-                   .areaId = WHEEL_REAR_RIGHT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f,
-               }}},
-     .initialValue = {.floatValues = {200}}},  // units in kPa
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::TIRE_PRESSURE),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                         .areaConfigs = {VehicleAreaConfig{
+                                                 .areaId = WHEEL_FRONT_LEFT,
+                                                 .minFloatValue = 100.0f,
+                                                 .maxFloatValue = 300.0f,
+                                         },
+                                         VehicleAreaConfig{
+                                                 .areaId = WHEEL_FRONT_RIGHT,
+                                                 .minFloatValue = 100.0f,
+                                                 .maxFloatValue = 300.0f,
+                                         },
+                                         VehicleAreaConfig{
+                                                 .areaId = WHEEL_REAR_LEFT,
+                                                 .minFloatValue = 100.0f,
+                                                 .maxFloatValue = 300.0f,
+                                         },
+                                         VehicleAreaConfig{
+                                                 .areaId = WHEEL_REAR_RIGHT,
+                                                 .minFloatValue = 100.0f,
+                                                 .maxFloatValue = 300.0f,
+                                         }},
+                         .minSampleRate = 1.0f,
+                         .maxSampleRate = 2.0f,
+                 },
+         .initialValue = {.floatValues = {200}}},  // units in kPa
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::CURRENT_GEAR),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-         },
-     .initialValue = {.int32Values = {toInt(VehicleGear::GEAR_PARK)}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::CURRENT_GEAR),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                 },
+         .initialValue = {.int32Values = {toInt(VehicleGear::GEAR_PARK)}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::PARKING_BRAKE_ON),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-         },
-     .initialValue = {.int32Values = {1}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::PARKING_BRAKE_ON),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                 },
+         .initialValue = {.int32Values = {1}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::FUEL_LEVEL_LOW),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.int32Values = {0}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::FUEL_LEVEL_LOW),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.int32Values = {0}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::HW_KEY_INPUT),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-         },
-     .initialValue = {.int32Values = {0, 0, 0}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::HW_KEY_INPUT),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                 },
+         .initialValue = {.int32Values = {0, 0, 0}}},
 
-    {.config = {.prop = toInt(VehicleProperty::HVAC_POWER_ON),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}},
-                // TODO(bryaneyler): Ideally, this is generated dynamically from
-                // kHvacPowerProperties.
-                .configArray = {toInt(VehicleProperty::HVAC_FAN_SPEED),
-                                toInt(VehicleProperty::HVAC_FAN_DIRECTION)}},
-     .initialValue = {.int32Values = {1}}},
+        {.config = {.prop = toInt(VehicleProperty::HVAC_POWER_ON),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}},
+                    // TODO(bryaneyler): Ideally, this is generated dynamically from
+                    // kHvacPowerProperties.
+                    .configArray = {toInt(VehicleProperty::HVAC_FAN_SPEED),
+                                    toInt(VehicleProperty::HVAC_FAN_DIRECTION)}},
+         .initialValue = {.int32Values = {1}}},
 
-    {
-        .config = {.prop = toInt(VehicleProperty::HVAC_DEFROSTER),
-                   .access = VehiclePropertyAccess::READ_WRITE,
-                   .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                   .areaConfigs =
-                       {VehicleAreaConfig{.areaId = toInt(VehicleAreaWindow::FRONT_WINDSHIELD)},
-                        VehicleAreaConfig{.areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}},
-        .initialValue = {.int32Values = {0}}  // Will be used for all areas.
-    },
+        {
+                .config = {.prop = toInt(VehicleProperty::HVAC_DEFROSTER),
+                           .access = VehiclePropertyAccess::READ_WRITE,
+                           .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                           .areaConfigs =
+                                   {VehicleAreaConfig{
+                                            .areaId = toInt(VehicleAreaWindow::FRONT_WINDSHIELD)},
+                                    VehicleAreaConfig{
+                                            .areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}},
+                .initialValue = {.int32Values = {0}}  // Will be used for all areas.
+        },
 
-    {.config = {.prop = toInt(VehicleProperty::HVAC_MAX_DEFROST_ON),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
-     .initialValue = {.int32Values = {0}}},
+        {.config = {.prop = toInt(VehicleProperty::HVAC_MAX_DEFROST_ON),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+         .initialValue = {.int32Values = {0}}},
 
-    {.config = {.prop = toInt(VehicleProperty::HVAC_RECIRC_ON),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
-     .initialValue = {.int32Values = {1}}},
+        {.config = {.prop = toInt(VehicleProperty::HVAC_RECIRC_ON),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+         .initialValue = {.int32Values = {1}}},
 
-    {.config = {.prop = toInt(VehicleProperty::HVAC_AUTO_RECIRC_ON),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
-     .initialValue = {.int32Values = {0}}},
+        {.config = {.prop = toInt(VehicleProperty::HVAC_AUTO_RECIRC_ON),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+         .initialValue = {.int32Values = {0}}},
 
-    {.config = {.prop = toInt(VehicleProperty::HVAC_AC_ON),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
-     .initialValue = {.int32Values = {1}}},
+        {.config = {.prop = toInt(VehicleProperty::HVAC_AC_ON),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+         .initialValue = {.int32Values = {1}}},
 
-    {.config = {.prop = toInt(VehicleProperty::HVAC_MAX_AC_ON),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
-     .initialValue = {.int32Values = {0}}},
+        {.config = {.prop = toInt(VehicleProperty::HVAC_MAX_AC_ON),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+         .initialValue = {.int32Values = {0}}},
 
-    {.config = {.prop = toInt(VehicleProperty::HVAC_AUTO_ON),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
-     .initialValue = {.int32Values = {1}}},
+        {.config = {.prop = toInt(VehicleProperty::HVAC_AUTO_ON),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+         .initialValue = {.int32Values = {1}}},
 
-    {.config = {.prop = toInt(VehicleProperty::HVAC_DUAL_ON),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
-     .initialValue = {.int32Values = {0}}},
+        {.config = {.prop = toInt(VehicleProperty::HVAC_DUAL_ON),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+         .initialValue = {.int32Values = {0}}},
 
-    {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_SPEED),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{
-                    .areaId = HVAC_ALL, .minInt32Value = 1, .maxInt32Value = 7}}},
-     .initialValue = {.int32Values = {3}}},
+        {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_SPEED),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{
+                            .areaId = HVAC_ALL, .minInt32Value = 1, .maxInt32Value = 7}}},
+         .initialValue = {.int32Values = {3}}},
 
-    {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
-     .initialValue = {.int32Values = {toInt(VehicleHvacFanDirection::FACE)}}},
+        {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+         .initialValue = {.int32Values = {toInt(VehicleHvacFanDirection::FACE)}}},
 
-    {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION_AVAILABLE),
-                .access = VehiclePropertyAccess::READ,
-                .changeMode = VehiclePropertyChangeMode::STATIC,
-                .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
-     .initialValue = {.int32Values = {FAN_DIRECTION_FACE, FAN_DIRECTION_FLOOR,
-                                      FAN_DIRECTION_FACE | FAN_DIRECTION_FLOOR}}},
+        {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION_AVAILABLE),
+                    .access = VehiclePropertyAccess::READ,
+                    .changeMode = VehiclePropertyChangeMode::STATIC,
+                    .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+         .initialValue = {.int32Values = {FAN_DIRECTION_FACE, FAN_DIRECTION_FLOOR,
+                                          FAN_DIRECTION_FACE | FAN_DIRECTION_FLOOR}}},
 
-    {.config = {.prop = toInt(VehicleProperty::HVAC_SEAT_VENTILATION),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{
-                                    .areaId = SEAT_1_LEFT, .minInt32Value = 0, .maxInt32Value = 3,
-                                },
-                                VehicleAreaConfig{
-                                    .areaId = SEAT_1_RIGHT, .minInt32Value = 0, .maxInt32Value = 3,
-                                }}},
-     .initialValue = {.int32Values = {0}}},  // 0 is off and +ve values indicate ventilation level.
+        {.config = {.prop = toInt(VehicleProperty::HVAC_SEAT_VENTILATION),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{
+                                            .areaId = SEAT_1_LEFT,
+                                            .minInt32Value = 0,
+                                            .maxInt32Value = 3,
+                                    },
+                                    VehicleAreaConfig{
+                                            .areaId = SEAT_1_RIGHT,
+                                            .minInt32Value = 0,
+                                            .maxInt32Value = 3,
+                                    }}},
+         .initialValue =
+                 {.int32Values = {0}}},  // 0 is off and +ve values indicate ventilation level.
 
-    {.config = {.prop = toInt(VehicleProperty::HVAC_STEERING_WHEEL_HEAT),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{
-                    .areaId = (0), .minInt32Value = -2, .maxInt32Value = 2}}},
-     .initialValue = {.int32Values = {0}}},  // +ve values for heating and -ve for cooling
+        {.config = {.prop = toInt(VehicleProperty::HVAC_STEERING_WHEEL_HEAT),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{
+                            .areaId = (0), .minInt32Value = -2, .maxInt32Value = 2}}},
+         .initialValue = {.int32Values = {0}}},  // +ve values for heating and -ve for cooling
 
-    {.config = {.prop = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{
-                                    .areaId = SEAT_1_LEFT, .minInt32Value = -2, .maxInt32Value = 2,
-                                },
-                                VehicleAreaConfig{
-                                    .areaId = SEAT_1_RIGHT, .minInt32Value = -2, .maxInt32Value = 2,
-                                }}},
-     .initialValue = {.int32Values = {0}}},  // +ve values for heating and -ve for cooling
+        {.config = {.prop = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{
+                                            .areaId = SEAT_1_LEFT,
+                                            .minInt32Value = -2,
+                                            .maxInt32Value = 2,
+                                    },
+                                    VehicleAreaConfig{
+                                            .areaId = SEAT_1_RIGHT,
+                                            .minInt32Value = -2,
+                                            .maxInt32Value = 2,
+                                    }}},
+         .initialValue = {.int32Values = {0}}},  // +ve values for heating and -ve for cooling
 
-    {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{
-                                    .areaId = HVAC_LEFT,
-                                    .minFloatValue = 16,
-                                    .maxFloatValue = 32,
-                                },
-                                VehicleAreaConfig{
-                                    .areaId = HVAC_RIGHT,
-                                    .minFloatValue = 16,
-                                    .maxFloatValue = 32,
-                                }}},
-     .initialAreaValues = {{HVAC_LEFT, {.floatValues = {16}}},
-                           {HVAC_RIGHT, {.floatValues = {20}}}}},
+        {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{
+                                            .areaId = HVAC_LEFT,
+                                            .minFloatValue = 16,
+                                            .maxFloatValue = 32,
+                                    },
+                                    VehicleAreaConfig{
+                                            .areaId = HVAC_RIGHT,
+                                            .minFloatValue = 16,
+                                            .maxFloatValue = 32,
+                                    }}},
+         .initialAreaValues = {{HVAC_LEFT, {.floatValues = {16}}},
+                               {HVAC_RIGHT, {.floatValues = {20}}}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE),
-             .access = VehiclePropertyAccess::READ,
-             // TODO(bryaneyler): Support ON_CHANGE as well.
-             .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
-             .minSampleRate = 1.0f,
-             .maxSampleRate = 2.0f,
-         },
-     .initialValue = {.floatValues = {25.0f}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE),
+                         .access = VehiclePropertyAccess::READ,
+                         // TODO(bryaneyler): Support ON_CHANGE as well.
+                         .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                         .minSampleRate = 1.0f,
+                         .maxSampleRate = 2.0f,
+                 },
+         .initialValue = {.floatValues = {25.0f}}},
 
-    {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_DISPLAY_UNITS),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS},
-                .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}},
-     .initialValue = {.int32Values = {(int)VehicleUnit::FAHRENHEIT}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_DISPLAY_UNITS),
+                         .access = VehiclePropertyAccess::READ_WRITE,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                         .configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS},
+                 },
+         .initialValue = {.int32Values = {(int)VehicleUnit::FAHRENHEIT}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::NIGHT_MODE),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-         },
-     .initialValue = {.int32Values = {0}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::NIGHT_MODE),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                 },
+         .initialValue = {.int32Values = {0}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::GEAR_SELECTION),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-         },
-     .initialValue = {.int32Values = {toInt(VehicleGear::GEAR_PARK)}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::GEAR_SELECTION),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                 },
+         .initialValue = {.int32Values = {toInt(VehicleGear::GEAR_PARK)}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::IGNITION_STATE),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-         },
-     .initialValue = {.int32Values = {toInt(VehicleIgnitionState::ON)}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::IGNITION_STATE),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                 },
+         .initialValue = {.int32Values = {toInt(VehicleIgnitionState::ON)}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::ENGINE_OIL_LEVEL),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-         },
-     .initialValue = {.int32Values = {toInt(VehicleOilLevel::NORMAL)}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::ENGINE_OIL_LEVEL),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                 },
+         .initialValue = {.int32Values = {toInt(VehicleOilLevel::NORMAL)}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::ENGINE_OIL_TEMP),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
-             .minSampleRate = 0.1,  // 0.1 Hz, every 10 seconds
-             .maxSampleRate = 10,   // 10 Hz, every 100 ms
-         },
-     .initialValue = {.floatValues = {101.0f}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::ENGINE_OIL_TEMP),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                         .minSampleRate = 0.1,  // 0.1 Hz, every 10 seconds
+                         .maxSampleRate = 10,   // 10 Hz, every 100 ms
+                 },
+         .initialValue = {.floatValues = {101.0f}}},
 
-    {
-        .config =
-            {
-                .prop = kGenerateFakeDataControllingProperty,
-                .access = VehiclePropertyAccess::WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-            },
-    },
+        {
+                .config =
+                        {
+                                .prop = kGenerateFakeDataControllingProperty,
+                                .access = VehiclePropertyAccess::WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                        },
+        },
 
-    {.config = {.prop = toInt(VehicleProperty::DOOR_LOCK),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT},
-                                VehicleAreaConfig{.areaId = DOOR_1_RIGHT},
-                                VehicleAreaConfig{.areaId = DOOR_2_LEFT},
-                                VehicleAreaConfig{.areaId = DOOR_2_RIGHT}}},
-     .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}},
-                           {DOOR_1_RIGHT, {.int32Values = {1}}},
-                           {DOOR_2_LEFT, {.int32Values = {1}}},
-                           {DOOR_2_RIGHT, {.int32Values = {1}}}}},
+        {.config = {.prop = toInt(VehicleProperty::DOOR_LOCK),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT},
+                                    VehicleAreaConfig{.areaId = DOOR_1_RIGHT},
+                                    VehicleAreaConfig{.areaId = DOOR_2_LEFT},
+                                    VehicleAreaConfig{.areaId = DOOR_2_RIGHT}}},
+         .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}},
+                               {DOOR_1_RIGHT, {.int32Values = {1}}},
+                               {DOOR_2_LEFT, {.int32Values = {1}}},
+                               {DOOR_2_RIGHT, {.int32Values = {1}}}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::DOOR_POS),
-             .access = VehiclePropertyAccess::READ_WRITE,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .areaConfigs =
-                 {VehicleAreaConfig{.areaId = DOOR_1_LEFT, .minInt32Value = 0, .maxInt32Value = 1},
-                  VehicleAreaConfig{.areaId = DOOR_1_RIGHT, .minInt32Value = 0, .maxInt32Value = 1},
-                  VehicleAreaConfig{.areaId = DOOR_2_LEFT, .minInt32Value = 0, .maxInt32Value = 1},
-                  VehicleAreaConfig{.areaId = DOOR_2_RIGHT, .minInt32Value = 0, .maxInt32Value = 1},
-                  VehicleAreaConfig{.areaId = DOOR_REAR, .minInt32Value = 0, .maxInt32Value = 1}}},
-     .initialValue = {.int32Values = {0}}},
+        {.config = {.prop = toInt(VehicleProperty::DOOR_POS),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs =
+                            {VehicleAreaConfig{
+                                     .areaId = DOOR_1_LEFT, .minInt32Value = 0, .maxInt32Value = 1},
+                             VehicleAreaConfig{.areaId = DOOR_1_RIGHT,
+                                               .minInt32Value = 0,
+                                               .maxInt32Value = 1},
+                             VehicleAreaConfig{
+                                     .areaId = DOOR_2_LEFT, .minInt32Value = 0, .maxInt32Value = 1},
+                             VehicleAreaConfig{.areaId = DOOR_2_RIGHT,
+                                               .minInt32Value = 0,
+                                               .maxInt32Value = 1},
+                             VehicleAreaConfig{
+                                     .areaId = DOOR_REAR, .minInt32Value = 0, .maxInt32Value = 1}}},
+         .initialValue = {.int32Values = {0}}},
 
-    {.config = {.prop = toInt(VehicleProperty::WINDOW_LOCK),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{.areaId = WINDOW_1_RIGHT | WINDOW_2_LEFT |
-                                                            WINDOW_2_RIGHT}}},
-     .initialAreaValues = {{WINDOW_1_RIGHT | WINDOW_2_LEFT | WINDOW_2_RIGHT,
-                            {.int32Values = {0}}}}},
+        {.config = {.prop = toInt(VehicleProperty::WINDOW_LOCK),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{.areaId = WINDOW_1_RIGHT | WINDOW_2_LEFT |
+                                                                WINDOW_2_RIGHT}}},
+         .initialAreaValues = {{WINDOW_1_RIGHT | WINDOW_2_LEFT | WINDOW_2_RIGHT,
+                                {.int32Values = {0}}}}},
 
-    {.config =
-         {.prop = toInt(VehicleProperty::WINDOW_POS),
-          .access =
-              VehiclePropertyAccess::READ_WRITE,
-          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-          .areaConfigs =
-              {VehicleAreaConfig{.areaId = WINDOW_1_LEFT, .minInt32Value = 0, .maxInt32Value = 10},
-               VehicleAreaConfig{.areaId = WINDOW_1_RIGHT, .minInt32Value = 0, .maxInt32Value = 10},
-               VehicleAreaConfig{.areaId = WINDOW_2_LEFT, .minInt32Value = 0, .maxInt32Value = 10},
-               VehicleAreaConfig{.areaId = WINDOW_2_RIGHT, .minInt32Value = 0, .maxInt32Value = 10},
-               VehicleAreaConfig{
-                   .areaId = WINDOW_ROOF_TOP_1, .minInt32Value = -10, .maxInt32Value = 10}}},
-     .initialValue = {.int32Values = {0}}},
+        {.config = {.prop = toInt(VehicleProperty::WINDOW_POS),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{.areaId = WINDOW_1_LEFT,
+                                                      .minInt32Value = 0,
+                                                      .maxInt32Value = 10},
+                                    VehicleAreaConfig{.areaId = WINDOW_1_RIGHT,
+                                                      .minInt32Value = 0,
+                                                      .maxInt32Value = 10},
+                                    VehicleAreaConfig{.areaId = WINDOW_2_LEFT,
+                                                      .minInt32Value = 0,
+                                                      .maxInt32Value = 10},
+                                    VehicleAreaConfig{.areaId = WINDOW_2_RIGHT,
+                                                      .minInt32Value = 0,
+                                                      .maxInt32Value = 10},
+                                    VehicleAreaConfig{.areaId = WINDOW_ROOF_TOP_1,
+                                                      .minInt32Value = -10,
+                                                      .maxInt32Value = 10}}},
+         .initialValue = {.int32Values = {0}}},
 
-    {.config =
-         {
-             .prop = WHEEL_TICK,
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
-             .configArray = {ALL_WHEELS, 50000, 50000, 50000, 50000},
-             .minSampleRate = 1.0f,
-             .maxSampleRate = 10.0f,
-         },
-     .initialValue = {.int64Values = {0, 100000, 200000, 300000, 400000}}},
+        {.config =
+                 {
+                         .prop = WHEEL_TICK,
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                         .configArray = {ALL_WHEELS, 50000, 50000, 50000, 50000},
+                         .minSampleRate = 1.0f,
+                         .maxSampleRate = 10.0f,
+                 },
+         .initialValue = {.int64Values = {0, 100000, 200000, 300000, 400000}}},
 
-    {.config = {.prop = ABS_ACTIVE,
-                .access = VehiclePropertyAccess::READ,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
-     .initialValue = {.int32Values = {0}}},
+        {.config = {.prop = ABS_ACTIVE,
+                    .access = VehiclePropertyAccess::READ,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
+         .initialValue = {.int32Values = {0}}},
 
-    {.config = {.prop = TRACTION_CONTROL_ACTIVE,
-                .access = VehiclePropertyAccess::READ,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
-     .initialValue = {.int32Values = {0}}},
+        {.config = {.prop = TRACTION_CONTROL_ACTIVE,
+                    .access = VehiclePropertyAccess::READ,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
+         .initialValue = {.int32Values = {0}}},
 
-    {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
-                .access = VehiclePropertyAccess::READ,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .configArray = {3}},
-     .initialValue = {.int32Values = {toInt(VehicleApPowerStateReq::ON), 0}}},
+        {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
+                    .access = VehiclePropertyAccess::READ,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .configArray = {3}},
+         .initialValue = {.int32Values = {toInt(VehicleApPowerStateReq::ON), 0}}},
 
-    {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
-     .initialValue = {.int32Values = {toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL), 0}}},
+        {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
+         .initialValue = {.int32Values = {toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL), 0}}},
 
-    {.config = {.prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS),
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{.minInt32Value = 0, .maxInt32Value = 100}}},
-     .initialValue = {.int32Values = {100}}},
+        {.config = {.prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS),
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{.minInt32Value = 0, .maxInt32Value = 100}}},
+         .initialValue = {.int32Values = {100}}},
 
-    {
-        .config = {.prop = OBD2_LIVE_FRAME,
-                   .access = VehiclePropertyAccess::READ,
-                   .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                   .configArray = {0, 0}},
-    },
+        {
+                .config = {.prop = OBD2_LIVE_FRAME,
+                           .access = VehiclePropertyAccess::READ,
+                           .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                           .configArray = {0, 0}},
+        },
 
-    {
-        .config = {.prop = OBD2_FREEZE_FRAME,
-                   .access = VehiclePropertyAccess::READ,
-                   .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                   .configArray = {0, 0}},
-    },
+        {
+                .config = {.prop = OBD2_FREEZE_FRAME,
+                           .access = VehiclePropertyAccess::READ,
+                           .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                           .configArray = {0, 0}},
+        },
 
-    {
-        .config = {.prop = OBD2_FREEZE_FRAME_INFO,
-                   .access = VehiclePropertyAccess::READ,
-                   .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
-    },
+        {
+                .config = {.prop = OBD2_FREEZE_FRAME_INFO,
+                           .access = VehiclePropertyAccess::READ,
+                           .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
+        },
 
-    {
-        .config = {.prop = OBD2_FREEZE_FRAME_CLEAR,
-                   .access = VehiclePropertyAccess::WRITE,
-                   .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                   .configArray = {1}},
-    },
+        {
+                .config = {.prop = OBD2_FREEZE_FRAME_CLEAR,
+                           .access = VehiclePropertyAccess::WRITE,
+                           .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                           .configArray = {1}},
+        },
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::HEADLIGHTS_STATE),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::HEADLIGHTS_STATE),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_STATE),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_STATE),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::FOG_LIGHTS_STATE),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::FOG_LIGHTS_STATE),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::HAZARD_LIGHTS_STATE),
-             .access = VehiclePropertyAccess::READ,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::HAZARD_LIGHTS_STATE),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::HEADLIGHTS_SWITCH),
-             .access = VehiclePropertyAccess::READ_WRITE,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::HEADLIGHTS_SWITCH),
+                         .access = VehiclePropertyAccess::READ_WRITE,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_SWITCH),
-             .access = VehiclePropertyAccess::READ_WRITE,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_SWITCH),
+                         .access = VehiclePropertyAccess::READ_WRITE,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::FOG_LIGHTS_SWITCH),
-             .access = VehiclePropertyAccess::READ_WRITE,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::FOG_LIGHTS_SWITCH),
+                         .access = VehiclePropertyAccess::READ_WRITE,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::HAZARD_LIGHTS_SWITCH),
-             .access = VehiclePropertyAccess::READ_WRITE,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
-         },
-     .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
+        {.config =
+                 {
+                         .prop = toInt(VehicleProperty::HAZARD_LIGHTS_SWITCH),
+                         .access = VehiclePropertyAccess::READ_WRITE,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+                 },
+         .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
 
-    {.config = {.prop = VEHICLE_MAP_SERVICE,
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE}},
+        {.config = {.prop = VEHICLE_MAP_SERVICE,
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE}},
 
-    // Example Vendor Extension properties for testing
-    {.config = {.prop = VENDOR_EXTENSION_BOOLEAN_PROPERTY,
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT},
-                                VehicleAreaConfig{.areaId = DOOR_1_RIGHT},
-                                VehicleAreaConfig{.areaId = DOOR_2_LEFT},
-                                VehicleAreaConfig{.areaId = DOOR_2_RIGHT}}},
-     .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}},
-                           {DOOR_1_RIGHT, {.int32Values = {1}}},
-                           {DOOR_2_LEFT, {.int32Values = {0}}},
-                           {DOOR_2_RIGHT, {.int32Values = {0}}}}},
+        // Example Vendor Extension properties for testing
+        {.config = {.prop = VENDOR_EXTENSION_BOOLEAN_PROPERTY,
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT},
+                                    VehicleAreaConfig{.areaId = DOOR_1_RIGHT},
+                                    VehicleAreaConfig{.areaId = DOOR_2_LEFT},
+                                    VehicleAreaConfig{.areaId = DOOR_2_RIGHT}}},
+         .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}},
+                               {DOOR_1_RIGHT, {.int32Values = {1}}},
+                               {DOOR_2_LEFT, {.int32Values = {0}}},
+                               {DOOR_2_RIGHT, {.int32Values = {0}}}}},
 
-    {.config = {.prop = VENDOR_EXTENSION_FLOAT_PROPERTY,
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{
-                                    .areaId = HVAC_LEFT, .minFloatValue = -10, .maxFloatValue = 10},
-                                VehicleAreaConfig{.areaId = HVAC_RIGHT,
-                                                  .minFloatValue = -10,
-                                                  .maxFloatValue = 10}}},
-     .initialAreaValues = {{HVAC_LEFT, {.floatValues = {1}}}, {HVAC_RIGHT, {.floatValues = {2}}}}},
+        {.config = {.prop = VENDOR_EXTENSION_FLOAT_PROPERTY,
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_LEFT,
+                                                      .minFloatValue = -10,
+                                                      .maxFloatValue = 10},
+                                    VehicleAreaConfig{.areaId = HVAC_RIGHT,
+                                                      .minFloatValue = -10,
+                                                      .maxFloatValue = 10}}},
+         .initialAreaValues = {{HVAC_LEFT, {.floatValues = {1}}},
+                               {HVAC_RIGHT, {.floatValues = {2}}}}},
 
-    {.config = {.prop = VENDOR_EXTENSION_INT_PROPERTY,
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .areaConfigs = {VehicleAreaConfig{
-                                    .areaId = (int)VehicleAreaWindow::FRONT_WINDSHIELD,
-                                    .minInt32Value = -100,
-                                    .maxInt32Value = 100},
-                                VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::REAR_WINDSHIELD,
-                                                  .minInt32Value = -100,
-                                                  .maxInt32Value = 100},
-                                VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::ROOF_TOP_1,
-                                                  .minInt32Value = -100,
-                                                  .maxInt32Value = 100}}},
-     .initialAreaValues = {{(int)VehicleAreaWindow::FRONT_WINDSHIELD, {.int32Values = {1}}},
-                           {(int)VehicleAreaWindow::REAR_WINDSHIELD, {.int32Values = {0}}},
-                           {(int)VehicleAreaWindow::ROOF_TOP_1, {.int32Values = {-1}}}}},
+        {.config = {.prop = VENDOR_EXTENSION_INT_PROPERTY,
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .areaConfigs =
+                            {VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::FRONT_WINDSHIELD,
+                                               .minInt32Value = -100,
+                                               .maxInt32Value = 100},
+                             VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::REAR_WINDSHIELD,
+                                               .minInt32Value = -100,
+                                               .maxInt32Value = 100},
+                             VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::ROOF_TOP_1,
+                                               .minInt32Value = -100,
+                                               .maxInt32Value = 100}}},
+         .initialAreaValues = {{(int)VehicleAreaWindow::FRONT_WINDSHIELD, {.int32Values = {1}}},
+                               {(int)VehicleAreaWindow::REAR_WINDSHIELD, {.int32Values = {0}}},
+                               {(int)VehicleAreaWindow::ROOF_TOP_1, {.int32Values = {-1}}}}},
 
-    {.config = {.prop = VENDOR_EXTENSION_STRING_PROPERTY,
-                .access = VehiclePropertyAccess::READ_WRITE,
-                .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
-     .initialValue = {.stringValue = "Vendor String Property"}},
+        {.config = {.prop = VENDOR_EXTENSION_STRING_PROPERTY,
+                    .access = VehiclePropertyAccess::READ_WRITE,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
+         .initialValue = {.stringValue = "Vendor String Property"}},
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index ba81a52..e1da030 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -249,8 +249,8 @@
 
             // Create a separate instance for each individual zone
             VehiclePropValue prop = {
-                .prop = cfg.prop,
-                .areaId = curArea,
+                    .areaId = curArea,
+                    .prop = cfg.prop,
             };
 
             if (it.initialAreaValues.size() > 0) {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
index b8fd2ba..8677f83 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
@@ -101,9 +101,11 @@
                   rawEvent.toStyledString().c_str());
             continue;
         }
-        VehiclePropValue event = {.prop = rawEvent["prop"].asInt(),
-                                  .areaId = rawEvent["areaId"].asInt(),
-                                  .timestamp = rawEvent["timestamp"].asInt64()};
+        VehiclePropValue event = {
+                .timestamp = rawEvent["timestamp"].asInt64(),
+                .areaId = rawEvent["areaId"].asInt(),
+                .prop = rawEvent["prop"].asInt(),
+        };
 
         Json::Value rawEventValue = rawEvent["value"];
         auto& value = event.value;
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
index 356a6b9..9dc7085 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
@@ -120,7 +120,10 @@
     }
 
     {
-        VehiclePropValue request = { .prop = propId, .areaId = areaId };
+        VehiclePropValue request = {
+                .areaId = areaId,
+                .prop = propId,
+        };
         StatusCode halStatus;
         auto val = mHal->get(request, &halStatus);
         if (val != nullptr) {
@@ -150,10 +153,10 @@
                                     VehicleEmulator::EmulatorMessage& respMsg) {
     emulator::VehiclePropValue protoVal = rxMsg.value(0);
     VehiclePropValue val = {
-        .prop = protoVal.prop(),
-        .areaId = protoVal.area_id(),
-        .status = (VehiclePropertyStatus)protoVal.status(),
-        .timestamp = elapsedRealtimeNano(),
+            .timestamp = elapsedRealtimeNano(),
+            .areaId = protoVal.area_id(),
+            .prop = protoVal.prop(),
+            .status = (VehiclePropertyStatus)protoVal.status(),
     };
 
     respMsg.set_msg_type(emulator::SET_PROPERTY_RESP);
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 8332df2..e6b70d8 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -221,7 +221,7 @@
     </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.health</name>
-        <version>2.0</version>
+        <version>2.1</version>
         <interface>
             <name>IHealth</name>
             <instance>default</instance>
diff --git a/dumpstate/1.0/vts/functional/Android.bp b/dumpstate/1.0/vts/functional/Android.bp
index fc64d05..3bac281 100644
--- a/dumpstate/1.0/vts/functional/Android.bp
+++ b/dumpstate/1.0/vts/functional/Android.bp
@@ -18,5 +18,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalDumpstateV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.dumpstate@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp b/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp
index 57ebf2a..96b13c5 100644
--- a/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp
+++ b/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp
@@ -21,32 +21,19 @@
 
 #include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
 #include <cutils/native_handle.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
 using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
 using ::android::hardware::Return;
 using ::android::sp;
 
-// Test environment for Dumpstate HIDL HAL.
-class DumpstateHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static DumpstateHidlEnvironment* Instance() {
-        static DumpstateHidlEnvironment* instance = new DumpstateHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IDumpstateDevice>(); }
-};
-
-class DumpstateHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   public:
+class DumpstateHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
     virtual void SetUp() override {
-        dumpstate = ::testing::VtsHalHidlTargetTestBase::getService<IDumpstateDevice>(
-            DumpstateHidlEnvironment::Instance()->getServiceName<IDumpstateDevice>());
+        dumpstate = IDumpstateDevice::getService(GetParam());
         ASSERT_NE(dumpstate, nullptr) << "Could not get HIDL instance";
     }
 
@@ -54,14 +41,14 @@
 };
 
 // Negative test: make sure dumpstateBoard() doesn't crash when passed a null pointer.
-TEST_F(DumpstateHidlTest, TestNullHandle) {
+TEST_P(DumpstateHidlTest, TestNullHandle) {
     Return<void> status = dumpstate->dumpstateBoard(nullptr);
 
     ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
 }
 
 // Negative test: make sure dumpstateBoard() ignores a handle with no FD.
-TEST_F(DumpstateHidlTest, TestHandleWithNoFd) {
+TEST_P(DumpstateHidlTest, TestHandleWithNoFd) {
     native_handle_t* handle = native_handle_create(0, 0);
     ASSERT_NE(handle, nullptr) << "Could not create native_handle";
 
@@ -74,7 +61,7 @@
 }
 
 // Positive test: make sure dumpstateBoard() writes something to the FD.
-TEST_F(DumpstateHidlTest, TestOk) {
+TEST_P(DumpstateHidlTest, TestOk) {
     // Index 0 corresponds to the read end of the pipe; 1 to the write end.
     int fds[2];
     ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
@@ -94,7 +81,7 @@
 }
 
 // Positive test: make sure dumpstateBoard() doesn't crash with two FDs.
-TEST_F(DumpstateHidlTest, TestHandleWithTwoFds) {
+TEST_P(DumpstateHidlTest, TestHandleWithTwoFds) {
     int fds1[2];
     int fds2[2];
     ASSERT_EQ(0, pipe2(fds1, O_NONBLOCK)) << errno;
@@ -111,11 +98,7 @@
     native_handle_close(handle);
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(DumpstateHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    DumpstateHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, DumpstateHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IDumpstateDevice::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/health/2.0/default/Android.bp b/health/2.0/default/Android.bp
index 1c455d3..3c5877e 100644
--- a/health/2.0/default/Android.bp
+++ b/health/2.0/default/Android.bp
@@ -31,7 +31,11 @@
     vendor_available: true,
     srcs: [
         "Health.cpp",
-        "healthd_common.cpp",
+        "healthd_common_adapter.cpp",
+    ],
+
+    whole_static_libs: [
+        "libhealthloop",
     ],
 
     export_include_dirs: ["include"],
diff --git a/health/2.0/default/Health.cpp b/health/2.0/default/Health.cpp
index a2b81d1..c0c5a40 100644
--- a/health/2.0/default/Health.cpp
+++ b/health/2.0/default/Health.cpp
@@ -148,7 +148,14 @@
 
     // Retrieve all information and call healthd_mode_ops->battery_update, which calls
     // notifyListeners.
-    bool chargerOnline = battery_monitor_->update();
+    battery_monitor_->updateValues();
+    struct BatteryProperties props = getBatteryProperties(battery_monitor_.get());
+    bool log = healthd_board_battery_update(&props);
+    if (log) {
+        battery_monitor_->logValues();
+    }
+    healthd_mode_ops->battery_update(&props);
+    bool chargerOnline = battery_monitor_->isChargerOnline();
 
     // adjust uevent / wakealarm periods
     healthd_battery_update_internal(chargerOnline);
diff --git a/health/2.0/default/healthd_common.cpp b/health/2.0/default/healthd_common.cpp
deleted file mode 100644
index b5fdc8e..0000000
--- a/health/2.0/default/healthd_common.cpp
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "android.hardware.health@2.0-impl"
-#define KLOG_LEVEL 6
-
-#include <healthd/BatteryMonitor.h>
-#include <healthd/healthd.h>
-
-#include <batteryservice/BatteryService.h>
-#include <cutils/klog.h>
-#include <cutils/uevent.h>
-#include <errno.h>
-#include <libgen.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/timerfd.h>
-#include <unistd.h>
-#include <utils/Errors.h>
-
-#include <health2/Health.h>
-
-using namespace android;
-
-// Periodic chores fast interval in seconds
-#define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
-// Periodic chores fast interval in seconds
-#define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
-
-static struct healthd_config healthd_config = {
-    .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
-    .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW,
-    .batteryStatusPath = String8(String8::kEmptyString),
-    .batteryHealthPath = String8(String8::kEmptyString),
-    .batteryPresentPath = String8(String8::kEmptyString),
-    .batteryCapacityPath = String8(String8::kEmptyString),
-    .batteryVoltagePath = String8(String8::kEmptyString),
-    .batteryTemperaturePath = String8(String8::kEmptyString),
-    .batteryTechnologyPath = String8(String8::kEmptyString),
-    .batteryCurrentNowPath = String8(String8::kEmptyString),
-    .batteryCurrentAvgPath = String8(String8::kEmptyString),
-    .batteryChargeCounterPath = String8(String8::kEmptyString),
-    .batteryFullChargePath = String8(String8::kEmptyString),
-    .batteryCycleCountPath = String8(String8::kEmptyString),
-    .energyCounter = NULL,
-    .boot_min_cap = 0,
-    .screen_on = NULL,
-};
-
-static int eventct;
-static int epollfd;
-
-#define POWER_SUPPLY_SUBSYSTEM "power_supply"
-
-static int uevent_fd;
-static int wakealarm_fd;
-
-// -1 for no epoll timeout
-static int awake_poll_interval = -1;
-
-static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST;
-
-using ::android::hardware::health::V2_0::implementation::Health;
-
-struct healthd_mode_ops* healthd_mode_ops = nullptr;
-
-int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
-    struct epoll_event ev;
-
-    ev.events = EPOLLIN;
-
-    if (wakeup == EVENT_WAKEUP_FD) ev.events |= EPOLLWAKEUP;
-
-    ev.data.ptr = (void*)handler;
-    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
-        KLOG_ERROR(LOG_TAG, "epoll_ctl failed; errno=%d\n", errno);
-        return -1;
-    }
-
-    eventct++;
-    return 0;
-}
-
-static void wakealarm_set_interval(int interval) {
-    struct itimerspec itval;
-
-    if (wakealarm_fd == -1) return;
-
-    wakealarm_wake_interval = interval;
-
-    if (interval == -1) interval = 0;
-
-    itval.it_interval.tv_sec = interval;
-    itval.it_interval.tv_nsec = 0;
-    itval.it_value.tv_sec = interval;
-    itval.it_value.tv_nsec = 0;
-
-    if (timerfd_settime(wakealarm_fd, 0, &itval, NULL) == -1)
-        KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
-}
-
-void healthd_battery_update_internal(bool charger_online) {
-    // Fast wake interval when on charger (watch for overheat);
-    // slow wake interval when on battery (watch for drained battery).
-
-    int new_wake_interval = charger_online ? healthd_config.periodic_chores_interval_fast
-                                           : healthd_config.periodic_chores_interval_slow;
-
-    if (new_wake_interval != wakealarm_wake_interval) wakealarm_set_interval(new_wake_interval);
-
-    // During awake periods poll at fast rate.  If wake alarm is set at fast
-    // rate then just use the alarm; if wake alarm is set at slow rate then
-    // poll at fast rate while awake and let alarm wake up at slow rate when
-    // asleep.
-
-    if (healthd_config.periodic_chores_interval_fast == -1)
-        awake_poll_interval = -1;
-    else
-        awake_poll_interval = new_wake_interval == healthd_config.periodic_chores_interval_fast
-                                  ? -1
-                                  : healthd_config.periodic_chores_interval_fast * 1000;
-}
-
-static void healthd_battery_update(void) {
-    Health::getImplementation()->update();
-}
-
-static void periodic_chores() {
-    healthd_battery_update();
-}
-
-#define UEVENT_MSG_LEN 2048
-static void uevent_event(uint32_t /*epevents*/) {
-    char msg[UEVENT_MSG_LEN + 2];
-    char* cp;
-    int n;
-
-    n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
-    if (n <= 0) return;
-    if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
-        return;
-
-    msg[n] = '\0';
-    msg[n + 1] = '\0';
-    cp = msg;
-
-    while (*cp) {
-        if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
-            healthd_battery_update();
-            break;
-        }
-
-        /* advance to after the next \0 */
-        while (*cp++)
-            ;
-    }
-}
-
-static void uevent_init(void) {
-    uevent_fd = uevent_open_socket(64 * 1024, true);
-
-    if (uevent_fd < 0) {
-        KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
-        return;
-    }
-
-    fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
-    if (healthd_register_event(uevent_fd, uevent_event, EVENT_WAKEUP_FD))
-        KLOG_ERROR(LOG_TAG, "register for uevent events failed\n");
-}
-
-static void wakealarm_event(uint32_t /*epevents*/) {
-    unsigned long long wakeups;
-
-    if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
-        KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
-        return;
-    }
-
-    periodic_chores();
-}
-
-static void wakealarm_init(void) {
-    wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
-    if (wakealarm_fd == -1) {
-        KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
-        return;
-    }
-
-    if (healthd_register_event(wakealarm_fd, wakealarm_event, EVENT_WAKEUP_FD))
-        KLOG_ERROR(LOG_TAG, "Registration of wakealarm event failed\n");
-
-    wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
-}
-
-static void healthd_mainloop(void) {
-    int nevents = 0;
-    while (1) {
-        struct epoll_event events[eventct];
-        int timeout = awake_poll_interval;
-        int mode_timeout;
-
-        /* Don't wait for first timer timeout to run periodic chores */
-        if (!nevents) periodic_chores();
-
-        healthd_mode_ops->heartbeat();
-
-        mode_timeout = healthd_mode_ops->preparetowait();
-        if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout)) timeout = mode_timeout;
-        nevents = epoll_wait(epollfd, events, eventct, timeout);
-        if (nevents == -1) {
-            if (errno == EINTR) continue;
-            KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
-            break;
-        }
-
-        for (int n = 0; n < nevents; ++n) {
-            if (events[n].data.ptr) (*(void (*)(int))events[n].data.ptr)(events[n].events);
-        }
-    }
-
-    return;
-}
-
-static int healthd_init() {
-    epollfd = epoll_create1(EPOLL_CLOEXEC);
-    if (epollfd == -1) {
-        KLOG_ERROR(LOG_TAG, "epoll_create1 failed; errno=%d\n", errno);
-        return -1;
-    }
-
-    healthd_mode_ops->init(&healthd_config);
-    wakealarm_init();
-    uevent_init();
-
-    return 0;
-}
-
-int healthd_main() {
-    int ret;
-
-    klog_set_level(KLOG_LEVEL);
-
-    if (!healthd_mode_ops) {
-        KLOG_ERROR("healthd ops not set, exiting\n");
-        exit(1);
-    }
-
-    ret = healthd_init();
-    if (ret) {
-        KLOG_ERROR("Initialization failed, exiting\n");
-        exit(2);
-    }
-
-    healthd_mainloop();
-    KLOG_ERROR("Main loop terminated, exiting\n");
-    return 3;
-}
diff --git a/health/2.0/default/healthd_common_adapter.cpp b/health/2.0/default/healthd_common_adapter.cpp
new file mode 100644
index 0000000..8fc689d
--- /dev/null
+++ b/health/2.0/default/healthd_common_adapter.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// Support legacy functions in healthd/healthd.h using healthd_mode_ops.
+// New code should use HealthLoop directly instead.
+
+#include <memory>
+
+#include <cutils/klog.h>
+#include <health/HealthLoop.h>
+#include <health2/Health.h>
+#include <healthd/healthd.h>
+
+using android::hardware::health::HealthLoop;
+using android::hardware::health::V2_0::implementation::Health;
+
+struct healthd_mode_ops* healthd_mode_ops = nullptr;
+
+// Adapter of HealthLoop to use legacy healthd_mode_ops.
+class HealthLoopAdapter : public HealthLoop {
+   public:
+    // Expose internal functions, assuming clients calls them in the same thread
+    // where StartLoop is called.
+    int RegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) {
+        return HealthLoop::RegisterEvent(fd, func, wakeup);
+    }
+    void AdjustWakealarmPeriods(bool charger_online) {
+        return HealthLoop::AdjustWakealarmPeriods(charger_online);
+    }
+   protected:
+    void Init(healthd_config* config) override { healthd_mode_ops->init(config); }
+    void Heartbeat() override { healthd_mode_ops->heartbeat(); }
+    int PrepareToWait() override { return healthd_mode_ops->preparetowait(); }
+    void ScheduleBatteryUpdate() override { Health::getImplementation()->update(); }
+};
+static std::unique_ptr<HealthLoopAdapter> health_loop;
+
+int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
+    auto wrapped_handler = [handler](auto*, uint32_t epevents) { handler(epevents); };
+    return health_loop->RegisterEvent(fd, wrapped_handler, wakeup);
+}
+
+void healthd_battery_update_internal(bool charger_online) {
+    health_loop->AdjustWakealarmPeriods(charger_online);
+}
+
+int healthd_main() {
+    if (!healthd_mode_ops) {
+        KLOG_ERROR("healthd ops not set, exiting\n");
+        exit(1);
+    }
+
+    health_loop = std::make_unique<HealthLoopAdapter>();
+
+    int ret = health_loop->StartLoop();
+
+    // Should not reach here. The following will exit().
+    health_loop.reset();
+
+    return ret;
+}
diff --git a/health/2.1/Android.bp b/health/2.1/Android.bp
new file mode 100644
index 0000000..254bfc0
--- /dev/null
+++ b/health/2.1/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.health@2.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IHealth.hal",
+        "IHealthInfoCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.health@1.0",
+        "android.hardware.health@2.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/health/2.1/IHealth.hal b/health/2.1/IHealth.hal
new file mode 100644
index 0000000..8a5152a
--- /dev/null
+++ b/health/2.1/IHealth.hal
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.hardware.health@2.1;
+
+import @2.0::IHealth;
+import @2.0::Result;
+import HealthConfig;
+import HealthInfo;
+import IHealthInfoCallback;
+
+/**
+ * IHealth manages health info and posts events on registered callbacks.
+ *
+ * An implementation of @2.1::IHealth must be able to handle both
+ * @2.0::IHealthInfoCallback and @2.1::IHealthInfoCallback.
+ * - When registerCallback() is called, an implementation must cast the callback
+ * to @2.1::IHealthInfoCallback.
+ *   - If the cast is successful, when a health info broadcast is sent, the
+ *     implementation must call
+ *     @2.1::IHealthInfoCallback.healthInfoChanged_2_1(). All fields introduced
+ *     in 2.1 must be set appropriately. The implementation must not call
+ *     @2.0::IHealthInfoCallback.healthInfoChanged().
+ *   - If the cast is unsuccessful, the implementation must call
+ *     @2.0::IHealthInfoCallback.healthInfoChanged().
+ * - When unregisterCallback() is called, from then on, updates must not be sent
+ *   through either healthInfoChanged_2_1() or healthInfoChanged().
+ *
+ * Passthrough implementations are not required to send health info to all
+ * callbacks periodically, but they must do so when update() is called.
+ * Binderized implementations must send health info to all callbacks
+ * periodically. The intervals between two notifications must be retrieved from
+ * the passthrough implementation through the getHealthConfig() function.
+ */
+interface IHealth extends @2.0::IHealth {
+    /**
+     * Get configuration of this HAL.
+     *
+     * @return result SUCCESS if successful,
+     *                NOT_SUPPORTED if this API is not supported,
+     *                UNKNOWN for other errors.
+     * @return config HAL configuration, to be ignored if result is not
+     *                SUCCESS.
+     */
+    getHealthConfig() generates (Result result, HealthConfig config);
+
+    /**
+     * Get Health Information.
+     *
+     * @return result SUCCESS if successful,
+     *                NOT_SUPPORTED if this API is not supported,
+     *                UNKNOWN for other errors.
+     * @return value  Health information, to be ignored if result is not
+     *                SUCCESS.
+     */
+    getHealthInfo_2_1() generates (Result result, @2.1::HealthInfo value);
+
+    /**
+     * Return whether the screen should be kept on in charger mode.
+     *
+     * @return result SUCCESS if successful,
+     *                NOT_SUPPORTED if this API is not supported,
+     *                UNKNOWN for other errors.
+     * @return value whether screen should be kept on.
+     */
+    shouldKeepScreenOn() generates (Result result, bool value);
+};
diff --git a/health/2.1/IHealthInfoCallback.hal b/health/2.1/IHealthInfoCallback.hal
new file mode 100644
index 0000000..275f018
--- /dev/null
+++ b/health/2.1/IHealthInfoCallback.hal
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.hardware.health@2.1;
+
+import @2.0::IHealthInfoCallback;
+
+/**
+ * IHealthInfoCallback is the updated callback interface to
+ * {@link IHealth.registerCallback}.
+ *
+ * A @2.1::IHealthInfoCallback must implement healthInfoChanged_2_1(). The
+ * inherited healthInfoChanged() function is never called when the HAL
+ * implementation post events. See documentation on @2.1::IHealth for details.
+ */
+interface IHealthInfoCallback extends @2.0::IHealthInfoCallback {
+    /**
+     * An implementation of IHealth must call healthInfoChanged on all
+     * registered callbacks after health info changes.
+     * @param info the updated HealthInfo
+     */
+    oneway healthInfoChanged_2_1(HealthInfo info);
+};
diff --git a/health/2.1/types.hal b/health/2.1/types.hal
new file mode 100644
index 0000000..efd8d6f
--- /dev/null
+++ b/health/2.1/types.hal
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+package android.hardware.health@2.1;
+
+import @1.0::HealthConfig;
+import @2.0::HealthInfo;
+
+/**
+ * Battery capacity level. This enum provides additional information along side
+ * with the battery capacity.
+ * Clients of this HAL must use this value before inferring it from the
+ * battery capacity.
+ */
+enum BatteryCapacityLevel : int32_t {
+    /**
+     * Battery capacity level is unknown.
+     * Battery capacity level must be set to this value if and only if battery
+     * is not present.
+     */
+    UNKNOWN = 0,
+    /**
+     * Battery is at critical level. The Android framework must schedule a
+     * shutdown when it sees this value from the HAL.
+     */
+    CRITICAL,
+    /**
+     * Battery is low. The Android framework may limit the performance of
+     * the device when it sees this value from the HAL.
+     */
+    LOW,
+    /**
+     * Battery level is normal.
+     */
+    NORMAL,
+    /**
+     * Battery level is high.
+     */
+    HIGH,
+    /**
+     * Battery is full. It must be set to FULL if and only if battery level is
+     * 100.
+     */
+    FULL,
+};
+
+/**
+ * Combined Health Information.
+ */
+struct HealthInfo {
+    /**
+     * V2.0 HealthInfo.
+     * If a member is unsupported, it is filled with:
+     * - 0 (for integers);
+     * - false (for booleans);
+     * - empty string (for strings);
+     * - UNKNOWN (for BatteryStatus and BatteryHealth).
+     */
+    @2.0::HealthInfo legacy;
+
+    /**
+     * Battery capacity level. See BatteryCapacityLevel for more details.
+     */
+    BatteryCapacityLevel batteryCapacityLevel;
+
+    /**
+     * Estimated time to fully charge the device (in seconds).
+     * Value must be 0 if and only if batteryCapacityLevel is FULL or UNKNOWN.
+     * Otherwise, value must be positive.
+     */
+    int64_t batteryChargeTimeToFullNowSeconds;
+
+    /**
+     * Estimated battery full capacity (in microamp hours, uAh).
+     * Value must be 0 if unknown.
+     * Value must be positive if known, and must be between [50%, 120%] of
+     * batteryFullCharge (the designed capacity).
+     */
+    int32_t batteryFullCapacityUah;
+};
+
+/**
+ * Combined configuration of a health HAL implementation.
+ */
+struct HealthConfig {
+    /**
+     * 1.0 version of health config.
+     */
+    @1.0::HealthConfig battery;
+
+    /**
+     * Minimum battery level for charger to reboot into Android (in percent).
+     * Value should be in range [0, 100].
+     */
+    int32_t bootMinCap;
+};
diff --git a/health/2.1/vts/OWNERS b/health/2.1/vts/OWNERS
new file mode 100644
index 0000000..20450ba
--- /dev/null
+++ b/health/2.1/vts/OWNERS
@@ -0,0 +1,3 @@
+elsk@google.com
+hridya@google.com
+sspatil@google.com
diff --git a/health/2.1/vts/functional/Android.bp b/health/2.1/vts/functional/Android.bp
new file mode 100644
index 0000000..5aa873a
--- /dev/null
+++ b/health/2.1/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalHealthV2_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalHealthV2_1TargetTest.cpp"],
+    static_libs: [
+        "libgflags",
+        "libgmock",
+        "android.hardware.health@1.0",
+        "android.hardware.health@2.0",
+        "android.hardware.health@2.1",
+    ],
+    test_suites: ["general-tests"],
+}
diff --git a/health/2.1/vts/functional/VtsHalHealthV2_1TargetTest.cpp b/health/2.1/vts/functional/VtsHalHealthV2_1TargetTest.cpp
new file mode 100644
index 0000000..7df4926
--- /dev/null
+++ b/health/2.1/vts/functional/VtsHalHealthV2_1TargetTest.cpp
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2019 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 "health_hidl_hal_test"
+
+#include <mutex>
+#include <set>
+#include <string>
+
+#include <android-base/logging.h>
+#include <android/hardware/health/1.0/types.h>
+#include <android/hardware/health/2.0/types.h>
+#include <android/hardware/health/2.1/IHealth.h>
+#include <android/hardware/health/2.1/IHealthInfoCallback.h>
+#include <android/hardware/health/2.1/types.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+using ::android::hardware::health::V1_0::BatteryStatus;
+using ::android::hardware::health::V2_0::Result;
+using ::testing::AnyOf;
+using ::testing::AssertionFailure;
+using ::testing::AssertionResult;
+using ::testing::AssertionSuccess;
+using namespace std::chrono_literals;
+
+using ::android::hardware::health::V1_0::toString;
+using ::android::hardware::health::V2_0::toString;
+using ::android::hardware::health::V2_1::toString;
+
+// Return expr if it is evaluated to false.
+#define TEST_AND_RETURN(expr) \
+    do {                      \
+        auto res = (expr);    \
+        if (!res) return res; \
+    } while (0)
+
+// Return a descriptive AssertionFailure() if expr is evaluated to false.
+#define TEST_AND_RETURN_FAILURE(expr)                       \
+    do {                                                    \
+        auto res = (expr);                                  \
+        if (!res) {                                         \
+            return AssertionFailure() << #expr " is false"; \
+        }                                                   \
+    } while (0)
+
+namespace android {
+namespace hardware {
+namespace health {
+
+namespace V2_0 {
+std::ostream& operator<<(std::ostream& os, const Result& res) {
+    return os << toString(res);
+}
+}  // namespace V2_0
+
+namespace V2_1 {
+
+class HealthHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        service_ = IHealth::getService(GetParam());
+        ASSERT_NE(nullptr, service_.get()) << "Instance '" << GetParam() << "'' is not available.";
+    }
+
+    sp<IHealth> service_;
+};
+
+class CallbackBase {
+  public:
+    Return<void> healthInfoChangedInternal() {
+        std::lock_guard<std::mutex> lock(mutex_);
+        invoked_ = true;
+        invoked_notify_.notify_all();
+        return Void();
+    }
+    template <typename R, typename P>
+    bool waitInvoke(std::chrono::duration<R, P> duration) {
+        std::unique_lock<std::mutex> lock(mutex_);
+        bool r = invoked_notify_.wait_for(lock, duration, [this] { return this->invoked_; });
+        invoked_ = false;
+        return r;
+    }
+
+  private:
+    std::mutex mutex_;
+    std::condition_variable invoked_notify_;
+    bool invoked_ = false;
+};
+
+class Callback_2_0 : public android::hardware::health::V2_0::IHealthInfoCallback,
+                     public CallbackBase {
+    Return<void> healthInfoChanged(const android::hardware::health::V2_0::HealthInfo&) override {
+        return healthInfoChangedInternal();
+    }
+};
+
+class Callback_2_1 : public android::hardware::health::V2_1::IHealthInfoCallback,
+                     public CallbackBase {
+    Return<void> healthInfoChanged(const android::hardware::health::V2_0::HealthInfo&) override {
+        ADD_FAILURE() << "android::hardware::health::V2_1::IHealthInfoCallback::healthInfoChanged "
+                      << "is called, but it shouldn't be";
+        return Void();
+    }
+    Return<void> healthInfoChanged_2_1(const HealthInfo&) override {
+        return healthInfoChangedInternal();
+    }
+};
+
+template <typename T>
+AssertionResult IsOk(const Return<T>& r) {
+    return r.isOk() ? AssertionSuccess() : (AssertionFailure() << r.description());
+}
+
+// Both IsOk() and Result::SUCCESS
+AssertionResult ResultIsSuccess(const Return<Result>& r) {
+    if (!r.isOk()) {
+        return AssertionFailure() << r.description();
+    }
+    if (static_cast<Result>(r) != Result::SUCCESS) {
+        return AssertionFailure() << toString(static_cast<Result>(r));
+    }
+    return AssertionSuccess();
+}
+
+/**
+ * Test whether callbacks work. Tested functions are IHealth::registerCallback,
+ * unregisterCallback, and update.
+ */
+template <typename Callback>
+AssertionResult TestCallbacks(sp<IHealth> service) {
+    sp<Callback> first = new Callback();
+    sp<Callback> second = new Callback();
+
+    TEST_AND_RETURN(ResultIsSuccess(service->registerCallback(first)));
+    TEST_AND_RETURN(ResultIsSuccess(service->registerCallback(second)));
+
+    // registerCallback may or may not invoke the callback immediately, so the test needs
+    // to wait for the invocation. If the implementation chooses not to invoke the callback
+    // immediately, just wait for some time.
+    first->waitInvoke(200ms);
+    second->waitInvoke(200ms);
+
+    // assert that the first callback is invoked when update is called.
+    TEST_AND_RETURN(ResultIsSuccess(service->update()));
+
+    TEST_AND_RETURN_FAILURE(first->waitInvoke(1s));
+    TEST_AND_RETURN_FAILURE(second->waitInvoke(1s));
+
+    TEST_AND_RETURN(ResultIsSuccess(service->unregisterCallback(first)));
+
+    // clear any potentially pending callbacks result from wakealarm / kernel events
+    // If there is none, just wait for some time.
+    first->waitInvoke(200ms);
+    second->waitInvoke(200ms);
+
+    // assert that the second callback is still invoked even though the first is unregistered.
+    TEST_AND_RETURN(ResultIsSuccess(service->update()));
+
+    TEST_AND_RETURN_FAILURE(!first->waitInvoke(200ms));
+    TEST_AND_RETURN_FAILURE(second->waitInvoke(1s));
+
+    TEST_AND_RETURN(ResultIsSuccess(service->unregisterCallback(second)));
+    return AssertionSuccess();
+}
+
+TEST_P(HealthHidlTest, Callbacks_2_0) {
+    EXPECT_TRUE(TestCallbacks<Callback_2_0>(service_));
+}
+
+TEST_P(HealthHidlTest, Callbacks_2_1) {
+    EXPECT_TRUE(TestCallbacks<Callback_2_1>(service_));
+}
+
+template <typename Callback>
+AssertionResult TestUnregisterNonExistentCallback(sp<IHealth> service) {
+    sp<Callback> callback = new Callback();
+    auto ret = service->unregisterCallback(callback);
+    TEST_AND_RETURN(IsOk(ret));
+    if (static_cast<Result>(ret) != Result::NOT_FOUND) {
+        return AssertionFailure()
+               << "Unregistering non-existent callback should return NOT_FOUND, but returned "
+               << static_cast<Result>(ret);
+    }
+    return AssertionSuccess();
+}
+
+TEST_P(HealthHidlTest, UnregisterNonExistentCallback_2_0) {
+    EXPECT_TRUE(TestUnregisterNonExistentCallback<Callback_2_0>(service_));
+}
+
+TEST_P(HealthHidlTest, UnregisterNonExistentCallback_2_1) {
+    EXPECT_TRUE(TestUnregisterNonExistentCallback<Callback_2_1>(service_));
+}
+
+template <typename T>
+AssertionResult IsEnum(T value) {
+    for (auto it : hidl_enum_range<T>()) {
+        if (it == value) {
+            return AssertionSuccess();
+        }
+    }
+
+    return AssertionFailure() << static_cast<std::underlying_type_t<T>>(value) << " is not valid";
+}
+
+/*
+ * Tests the values returned by getHealthInfo() from interface IHealth.
+ */
+TEST_P(HealthHidlTest, getHealthInfo_2_1) {
+    EXPECT_TRUE(IsOk(service_->getHealthInfo_2_1([](auto result, const auto& value) {
+        if (result == Result::NOT_SUPPORTED) {
+            return;
+        }
+        ASSERT_EQ(Result::SUCCESS, result);
+        const auto& legacy = value.legacy.legacy;
+
+        EXPECT_TRUE(IsEnum(value.batteryCapacityLevel)) << " BatteryCapacityLevel";
+        EXPECT_GE(value.batteryChargeTimeToFullNowSeconds, 0);
+
+        EXPECT_GE(value.batteryFullCapacityUah, 0) << "batteryFullCapacityUah is unknown";
+        EXPECT_GE(value.batteryFullCapacityUah, legacy.batteryFullCharge * 0.50);
+        EXPECT_LE(value.batteryFullCapacityUah, legacy.batteryFullCharge * 1.20);
+    })));
+}
+
+TEST_P(HealthHidlTest, getHealthConfig) {
+    EXPECT_TRUE(IsOk(service_->getHealthConfig([](auto result, const auto&) {
+        EXPECT_THAT(result, AnyOf(Result::SUCCESS, Result::NOT_SUPPORTED));
+    })));
+}
+
+TEST_P(HealthHidlTest, shouldKeepScreenOn) {
+    EXPECT_TRUE(IsOk(service_->shouldKeepScreenOn([](auto result, const auto&) {
+        EXPECT_THAT(result, AnyOf(Result::SUCCESS, Result::NOT_SUPPORTED));
+    })));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        , HealthHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IHealth::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+}  // namespace V2_1
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/health/utils/libhealthloop/Android.bp b/health/utils/libhealthloop/Android.bp
new file mode 100644
index 0000000..de0f24f
--- /dev/null
+++ b/health/utils/libhealthloop/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_static {
+    name: "libhealthloop",
+    vendor_available: true,
+    recovery_available: true,
+    srcs: [
+        "HealthLoop.cpp",
+        "utils.cpp",
+    ],
+    shared_libs: [
+        "libcutils",
+        "libbase",
+    ],
+    header_libs: [
+        "libbatteryservice_headers",
+        "libhealthd_headers",
+        "libutils_headers",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+}
diff --git a/health/utils/libhealthloop/HealthLoop.cpp b/health/utils/libhealthloop/HealthLoop.cpp
new file mode 100644
index 0000000..3f4b5bc
--- /dev/null
+++ b/health/utils/libhealthloop/HealthLoop.cpp
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2013 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 "HealthLoop"
+#define KLOG_LEVEL 6
+
+#include <health/HealthLoop.h>
+
+#include <errno.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <batteryservice/BatteryService.h>
+#include <cutils/klog.h>
+#include <cutils/uevent.h>
+#include <healthd/healthd.h>
+#include <utils/Errors.h>
+
+#include <health/utils.h>
+
+using namespace android;
+using namespace std::chrono_literals;
+
+#define POWER_SUPPLY_SUBSYSTEM "power_supply"
+
+namespace android {
+namespace hardware {
+namespace health {
+
+HealthLoop::HealthLoop() {
+    InitHealthdConfig(&healthd_config_);
+    awake_poll_interval_ = -1;
+    wakealarm_wake_interval_ = healthd_config_.periodic_chores_interval_fast;
+}
+
+HealthLoop::~HealthLoop() {
+    LOG(FATAL) << "HealthLoop cannot be destroyed";
+}
+
+int HealthLoop::RegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) {
+    CHECK(!reject_event_register_);
+
+    auto* event_handler =
+            event_handlers_
+                    .emplace_back(std::make_unique<EventHandler>(EventHandler{this, fd, func}))
+                    .get();
+
+    struct epoll_event ev;
+
+    ev.events = EPOLLIN;
+
+    if (wakeup == EVENT_WAKEUP_FD) ev.events |= EPOLLWAKEUP;
+
+    ev.data.ptr = reinterpret_cast<void*>(event_handler);
+
+    if (epoll_ctl(epollfd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
+        KLOG_ERROR(LOG_TAG, "epoll_ctl failed; errno=%d\n", errno);
+        return -1;
+    }
+
+    return 0;
+}
+
+void HealthLoop::WakeAlarmSetInterval(int interval) {
+    struct itimerspec itval;
+
+    if (wakealarm_fd_ == -1) return;
+
+    wakealarm_wake_interval_ = interval;
+
+    if (interval == -1) interval = 0;
+
+    itval.it_interval.tv_sec = interval;
+    itval.it_interval.tv_nsec = 0;
+    itval.it_value.tv_sec = interval;
+    itval.it_value.tv_nsec = 0;
+
+    if (timerfd_settime(wakealarm_fd_, 0, &itval, NULL) == -1)
+        KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
+}
+
+void HealthLoop::AdjustWakealarmPeriods(bool charger_online) {
+    // Fast wake interval when on charger (watch for overheat);
+    // slow wake interval when on battery (watch for drained battery).
+
+    int new_wake_interval = charger_online ? healthd_config_.periodic_chores_interval_fast
+                                           : healthd_config_.periodic_chores_interval_slow;
+
+    if (new_wake_interval != wakealarm_wake_interval_) WakeAlarmSetInterval(new_wake_interval);
+
+    // During awake periods poll at fast rate.  If wake alarm is set at fast
+    // rate then just use the alarm; if wake alarm is set at slow rate then
+    // poll at fast rate while awake and let alarm wake up at slow rate when
+    // asleep.
+
+    if (healthd_config_.periodic_chores_interval_fast == -1)
+        awake_poll_interval_ = -1;
+    else
+        awake_poll_interval_ = new_wake_interval == healthd_config_.periodic_chores_interval_fast
+                                       ? -1
+                                       : healthd_config_.periodic_chores_interval_fast * 1000;
+}
+
+void HealthLoop::PeriodicChores() {
+    ScheduleBatteryUpdate();
+}
+
+// TODO(b/140330870): Use BPF instead.
+#define UEVENT_MSG_LEN 2048
+void HealthLoop::UeventEvent(uint32_t /*epevents*/) {
+    // No need to lock because uevent_fd_ is guaranteed to be initialized.
+
+    char msg[UEVENT_MSG_LEN + 2];
+    char* cp;
+    int n;
+
+    n = uevent_kernel_multicast_recv(uevent_fd_, msg, UEVENT_MSG_LEN);
+    if (n <= 0) return;
+    if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
+        return;
+
+    msg[n] = '\0';
+    msg[n + 1] = '\0';
+    cp = msg;
+
+    while (*cp) {
+        if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
+            ScheduleBatteryUpdate();
+            break;
+        }
+
+        /* advance to after the next \0 */
+        while (*cp++)
+            ;
+    }
+}
+
+void HealthLoop::UeventInit(void) {
+    uevent_fd_.reset(uevent_open_socket(64 * 1024, true));
+
+    if (uevent_fd_ < 0) {
+        KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
+        return;
+    }
+
+    fcntl(uevent_fd_, F_SETFL, O_NONBLOCK);
+    if (RegisterEvent(uevent_fd_, &HealthLoop::UeventEvent, EVENT_WAKEUP_FD))
+        KLOG_ERROR(LOG_TAG, "register for uevent events failed\n");
+}
+
+void HealthLoop::WakeAlarmEvent(uint32_t /*epevents*/) {
+    // No need to lock because wakealarm_fd_ is guaranteed to be initialized.
+
+    unsigned long long wakeups;
+
+    if (read(wakealarm_fd_, &wakeups, sizeof(wakeups)) == -1) {
+        KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
+        return;
+    }
+
+    PeriodicChores();
+}
+
+void HealthLoop::WakeAlarmInit(void) {
+    wakealarm_fd_.reset(timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK));
+    if (wakealarm_fd_ == -1) {
+        KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
+        return;
+    }
+
+    if (RegisterEvent(wakealarm_fd_, &HealthLoop::WakeAlarmEvent, EVENT_WAKEUP_FD))
+        KLOG_ERROR(LOG_TAG, "Registration of wakealarm event failed\n");
+
+    WakeAlarmSetInterval(healthd_config_.periodic_chores_interval_fast);
+}
+
+void HealthLoop::MainLoop(void) {
+    int nevents = 0;
+    while (1) {
+        reject_event_register_ = true;
+        size_t eventct = event_handlers_.size();
+        struct epoll_event events[eventct];
+        int timeout = awake_poll_interval_;
+
+        int mode_timeout;
+
+        /* Don't wait for first timer timeout to run periodic chores */
+        if (!nevents) PeriodicChores();
+
+        Heartbeat();
+
+        mode_timeout = PrepareToWait();
+        if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout)) timeout = mode_timeout;
+        nevents = epoll_wait(epollfd_, events, eventct, timeout);
+        if (nevents == -1) {
+            if (errno == EINTR) continue;
+            KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
+            break;
+        }
+
+        for (int n = 0; n < nevents; ++n) {
+            if (events[n].data.ptr) {
+                auto* event_handler = reinterpret_cast<EventHandler*>(events[n].data.ptr);
+                event_handler->func(event_handler->object, events[n].events);
+            }
+        }
+    }
+
+    return;
+}
+
+int HealthLoop::InitInternal() {
+    epollfd_.reset(epoll_create1(EPOLL_CLOEXEC));
+    if (epollfd_ == -1) {
+        KLOG_ERROR(LOG_TAG, "epoll_create1 failed; errno=%d\n", errno);
+        return -1;
+    }
+
+    // Call subclass's init for any additional init steps.
+    // Note that healthd_config_ is initialized before wakealarm_fd_; see
+    // AdjustUeventWakealarmPeriods().
+    Init(&healthd_config_);
+
+    WakeAlarmInit();
+    UeventInit();
+
+    return 0;
+}
+
+int HealthLoop::StartLoop() {
+    int ret;
+
+    klog_set_level(KLOG_LEVEL);
+
+    ret = InitInternal();
+    if (ret) {
+        KLOG_ERROR(LOG_TAG, "Initialization failed, exiting\n");
+        return 2;
+    }
+
+    MainLoop();
+    KLOG_ERROR(LOG_TAG, "Main loop terminated, exiting\n");
+    return 3;
+}
+
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/health/utils/libhealthloop/include/health/HealthLoop.h b/health/utils/libhealthloop/include/health/HealthLoop.h
new file mode 100644
index 0000000..693e6cb
--- /dev/null
+++ b/health/utils/libhealthloop/include/health/HealthLoop.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#include <android-base/unique_fd.h>
+#include <healthd/healthd.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+
+class HealthLoop {
+  public:
+    HealthLoop();
+
+    // Client is responsible for holding this forever. Process will exit
+    // when this is destroyed.
+    virtual ~HealthLoop();
+
+    // Initialize and start the main loop. This function does not exit unless
+    // the process is interrupted.
+    // Once the loop is started, event handlers are no longer allowed to be
+    // registered.
+    int StartLoop();
+
+  protected:
+    // healthd_mode_ops overrides. Note that healthd_mode_ops->battery_update
+    // is missing because it is only used by BatteryMonitor.
+    // Init is called right after epollfd_ is initialized (so RegisterEvent
+    // is allowed) but before other things are initialized (so SetChargerOnline
+    // is not allowed.)
+    virtual void Init(healthd_config* config) = 0;
+    virtual void Heartbeat() = 0;
+    virtual int PrepareToWait() = 0;
+
+    // Note that this is NOT healthd_mode_ops->battery_update(BatteryProperties*),
+    // which is called by BatteryMonitor after values are fetched. This is the
+    // implementation of healthd_battery_update(), which calls
+    // the correct IHealth::update(),
+    // which calls BatteryMonitor::update(), which calls
+    // healthd_mode_ops->battery_update(BatteryProperties*).
+    virtual void ScheduleBatteryUpdate() = 0;
+
+    // Register an epoll event. When there is an event, |func| will be
+    // called with |this| as the first argument and |epevents| as the second.
+    // This may be called in a different thread from where StartLoop is called
+    // (for obvious reasons; StartLoop never ends).
+    // Once the loop is started, event handlers are no longer allowed to be
+    // registered.
+    using BoundFunction = std::function<void(HealthLoop*, uint32_t /* epevents */)>;
+    int RegisterEvent(int fd, BoundFunction func, EventWakeup wakeup);
+
+    // Helper for implementing ScheduleBatteryUpdate(). An implementation of
+    // ScheduleBatteryUpdate should get charger_online from BatteryMonitor::update(),
+    // then reset wake alarm interval by calling AdjustWakealarmPeriods.
+    void AdjustWakealarmPeriods(bool charger_online);
+
+  private:
+    struct EventHandler {
+        HealthLoop* object = nullptr;
+        int fd;
+        BoundFunction func;
+    };
+
+    int InitInternal();
+    void MainLoop();
+    void WakeAlarmInit();
+    void WakeAlarmEvent(uint32_t);
+    void UeventInit();
+    void UeventEvent(uint32_t);
+    void WakeAlarmSetInterval(int interval);
+    void PeriodicChores();
+
+    // These are fixed after InitInternal() is called.
+    struct healthd_config healthd_config_;
+    android::base::unique_fd wakealarm_fd_;
+    android::base::unique_fd uevent_fd_;
+
+    android::base::unique_fd epollfd_;
+    std::vector<std::unique_ptr<EventHandler>> event_handlers_;
+    int awake_poll_interval_;  // -1 for no epoll timeout
+    int wakealarm_wake_interval_;
+
+    // If set to true, future RegisterEvent() will be rejected. This is to ensure all
+    // events are registered before StartLoop().
+    bool reject_event_register_ = false;
+};
+
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/health/utils/libhealthloop/include/health/utils.h b/health/utils/libhealthloop/include/health/utils.h
new file mode 100644
index 0000000..e46771c
--- /dev/null
+++ b/health/utils/libhealthloop/include/health/utils.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <healthd/healthd.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+
+void InitHealthdConfig(struct healthd_config* healthd_config);
+
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/health/utils/libhealthloop/utils.cpp b/health/utils/libhealthloop/utils.cpp
new file mode 100644
index 0000000..b0d153f
--- /dev/null
+++ b/health/utils/libhealthloop/utils.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 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 <health/utils.h>
+namespace android {
+namespace hardware {
+namespace health {
+
+// Periodic chores fast interval in seconds
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
+// Periodic chores fast interval in seconds
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
+
+void InitHealthdConfig(struct healthd_config* healthd_config) {
+    *healthd_config = {
+            .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
+            .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW,
+            .batteryStatusPath = String8(String8::kEmptyString),
+            .batteryHealthPath = String8(String8::kEmptyString),
+            .batteryPresentPath = String8(String8::kEmptyString),
+            .batteryCapacityPath = String8(String8::kEmptyString),
+            .batteryVoltagePath = String8(String8::kEmptyString),
+            .batteryTemperaturePath = String8(String8::kEmptyString),
+            .batteryTechnologyPath = String8(String8::kEmptyString),
+            .batteryCurrentNowPath = String8(String8::kEmptyString),
+            .batteryCurrentAvgPath = String8(String8::kEmptyString),
+            .batteryChargeCounterPath = String8(String8::kEmptyString),
+            .batteryFullChargePath = String8(String8::kEmptyString),
+            .batteryCycleCountPath = String8(String8::kEmptyString),
+            .energyCounter = NULL,
+            .boot_min_cap = 0,
+            .screen_on = NULL,
+    };
+}
+
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/nfc/1.0/vts/functional/Android.bp b/nfc/1.0/vts/functional/Android.bp
index c2e365e..40b82bb 100644
--- a/nfc/1.0/vts/functional/Android.bp
+++ b/nfc/1.0/vts/functional/Android.bp
@@ -21,5 +21,5 @@
     static_libs: [
         "android.hardware.nfc@1.0",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/nfc/1.0/vts/functional/AndroidTest.xml b/nfc/1.0/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..364672b
--- /dev/null
+++ b/nfc/1.0/vts/functional/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<configuration description="Runs VtsHalNfcV1_0TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalNfcV1_0TargetTest->/data/local/tmp/VtsHalNfcV1_0TargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalNfcV1_0TargetTest" />
+        <option name="native-test-timeout" value="180000"/>
+    </test>
+</configuration>
diff --git a/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp b/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp
index e17c961..1feae9d 100644
--- a/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp
+++ b/nfc/1.0/vts/functional/VtsHalNfcV1_0TargetTest.cpp
@@ -20,11 +20,12 @@
 #include <android/hardware/nfc/1.0/INfc.h>
 #include <android/hardware/nfc/1.0/INfcClientCallback.h>
 #include <android/hardware/nfc/1.0/types.h>
+#include <gtest/gtest.h>
 #include <hardware/nfc.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 
 using ::android::hardware::nfc::V1_0::INfc;
 using ::android::hardware::nfc::V1_0::INfcClientCallback;
@@ -94,26 +95,11 @@
     };
 };
 
-// Test environment for Nfc HIDL HAL.
-class NfcHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static NfcHidlEnvironment* Instance() {
-    static NfcHidlEnvironment* instance = new NfcHidlEnvironment;
-    return instance;
-  }
-
-  virtual void registerTestServices() override { registerTestService<INfc>(); }
- private:
-  NfcHidlEnvironment() {}
-};
-
 // The main test class for NFC HIDL HAL.
-class NfcHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class NfcHidlTest : public ::testing::TestWithParam<std::string> {
  public:
   virtual void SetUp() override {
-    nfc_ = ::testing::VtsHalHidlTargetTestBase::getService<INfc>(
-        NfcHidlEnvironment::Instance()->getServiceName<INfc>());
+    nfc_ = INfc::getService(GetParam());
     ASSERT_NE(nfc_, nullptr);
 
     nfc_cb_ = new NfcClientCallback();
@@ -186,7 +172,7 @@
  * Since open and close calls are a part of SetUp() and TearDown(),
  * the function definition is intentionally kept empty
  */
-TEST_F(NfcHidlTest, OpenAndClose) {}
+TEST_P(NfcHidlTest, OpenAndClose) {}
 
 /*
  * WriteCoreReset:
@@ -194,7 +180,7 @@
  * Waits for CORE_RESET_RSP
  * Checks the status, version number and configuration status
  */
-TEST_F(NfcHidlTest, WriteCoreReset) {
+TEST_P(NfcHidlTest, WriteCoreReset) {
   std::vector<uint8_t> cmd = CORE_RESET_CMD;
   NfcData data = cmd;
   EXPECT_EQ(data.size(), nfc_->write(data));
@@ -229,7 +215,7 @@
  * Waits for CORE_RESET_RSP
  * Checks the status, version number and configuration status
  */
-TEST_F(NfcHidlTest, WriteCoreResetConfigReset) {
+TEST_P(NfcHidlTest, WriteCoreResetConfigReset) {
   std::vector<uint8_t> cmd = CORE_RESET_CMD_CONFIG_RESET;
   NfcData data = cmd;
   EXPECT_EQ(data.size(), nfc_->write(data));
@@ -264,7 +250,7 @@
  * Waits for response
  * Checks SYNTAX_ERROR status
  */
-TEST_F(NfcHidlTest, WriteInvalidCommand) {
+TEST_P(NfcHidlTest, WriteInvalidCommand) {
   // Send an Error Command
   std::vector<uint8_t> cmd = INVALID_COMMAND;
   NfcData data = cmd;
@@ -285,7 +271,7 @@
  * Send CORE_CONN_CREATE_CMD for loop-back mode
  * Check the response
  */
-TEST_F(NfcHidlTest, WriteInvalidAndThenValidCommand) {
+TEST_P(NfcHidlTest, WriteInvalidAndThenValidCommand) {
     std::vector<uint8_t> cmd = CORE_RESET_CMD;
     NfcData data = cmd;
     EXPECT_EQ(data.size(), nfc_->write(data));
@@ -349,7 +335,7 @@
  * Checks the data received
  * Repeat to send total of 1Mb data
  */
-TEST_F(NfcHidlTest, Bandwidth) {
+TEST_P(NfcHidlTest, Bandwidth) {
     std::vector<uint8_t> cmd = CORE_RESET_CMD;
     NfcData data = cmd;
     EXPECT_EQ(data.size(), nfc_->write(data));
@@ -437,7 +423,7 @@
  * Waits for NfcEvent.OPEN_CPLT
  * Checks status
  */
-TEST_F(NfcHidlTest, PowerCycle) {
+TEST_P(NfcHidlTest, PowerCycle) {
   EXPECT_EQ(NfcStatus::OK, nfc_->powerCycle());
   // Wait for NfcEvent.OPEN_CPLT
   auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
@@ -451,7 +437,7 @@
  * Calls powerCycle() after close()
  * Checks status
  */
-TEST_F(NfcHidlTest, PowerCycleAfterClose) {
+TEST_P(NfcHidlTest, PowerCycleAfterClose) {
   EXPECT_EQ(NfcStatus::OK, nfc_->close());
   // Wait for CLOSE_CPLT event
   auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
@@ -474,7 +460,7 @@
  * Calls coreInitialized() with different data
  * Waits for NfcEvent.POST_INIT_CPLT
  */
-TEST_F(NfcHidlTest, CoreInitialized) {
+TEST_P(NfcHidlTest, CoreInitialized) {
   NfcData data;
   data.resize(1);
   // These parameters might lead to device specific proprietary behavior
@@ -501,7 +487,7 @@
  * Calls controlGranted()
  * Checks the return value
  */
-TEST_F(NfcHidlTest, ControlGranted) {
+TEST_P(NfcHidlTest, ControlGranted) {
   EXPECT_EQ(NfcStatus::OK, nfc_->controlGranted());
 }
 
@@ -510,7 +496,7 @@
  * Call controlGranted() after close
  * Checks the return value
  */
-TEST_F(NfcHidlTest, ControlGrantedAfterClose) {
+TEST_P(NfcHidlTest, ControlGrantedAfterClose) {
   EXPECT_EQ(NfcStatus::OK, nfc_->close());
   // Wait for CLOSE_CPLT event
   auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
@@ -532,7 +518,7 @@
  * Calls prediscover()
  * Checks the return value
  */
-TEST_F(NfcHidlTest, PreDiscover) {
+TEST_P(NfcHidlTest, PreDiscover) {
   EXPECT_EQ(NfcStatus::OK, nfc_->prediscover());
 }
 
@@ -541,7 +527,7 @@
  * Call prediscover() after close
  * Checks the return value
  */
-TEST_F(NfcHidlTest, PreDiscoverAfterClose) {
+TEST_P(NfcHidlTest, PreDiscoverAfterClose) {
   EXPECT_EQ(NfcStatus::OK, nfc_->close());
   // Wait for CLOSE_CPLT event
   auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
@@ -564,7 +550,7 @@
  * Calls close() multiple times
  * Checks status
  */
-TEST_F(NfcHidlTest, CloseAfterClose) {
+TEST_P(NfcHidlTest, CloseAfterClose) {
   EXPECT_EQ(NfcStatus::OK, nfc_->close());
   // Wait for CLOSE_CPLT event
   auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
@@ -587,15 +573,18 @@
  * Calls open() multiple times
  * Checks status
  */
-TEST_F(NfcHidlTest, OpenAfterOpen) {
+TEST_P(NfcHidlTest, OpenAfterOpen) {
   EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
   EXPECT_EQ(NfcStatus::OK, nfc_->open(nfc_cb_));
 }
 
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, NfcHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(INfc::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
 int main(int argc, char** argv) {
-  ::testing::AddGlobalTestEnvironment(NfcHidlEnvironment::Instance());
   ::testing::InitGoogleTest(&argc, argv);
-  NfcHidlEnvironment::Instance()->init(&argc, argv);
 
   std::system("svc nfc disable"); /* Turn off NFC */
   sleep(5);
diff --git a/nfc/1.1/vts/functional/Android.bp b/nfc/1.1/vts/functional/Android.bp
index 6698c5a..8da0ce3 100644
--- a/nfc/1.1/vts/functional/Android.bp
+++ b/nfc/1.1/vts/functional/Android.bp
@@ -22,5 +22,5 @@
         "android.hardware.nfc@1.0",
         "android.hardware.nfc@1.1",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/nfc/1.1/vts/functional/VtsHalNfcV1_1TargetTest.cpp b/nfc/1.1/vts/functional/VtsHalNfcV1_1TargetTest.cpp
index 0b7c88b..13537e4 100644
--- a/nfc/1.1/vts/functional/VtsHalNfcV1_1TargetTest.cpp
+++ b/nfc/1.1/vts/functional/VtsHalNfcV1_1TargetTest.cpp
@@ -21,11 +21,12 @@
 #include <android/hardware/nfc/1.1/INfc.h>
 #include <android/hardware/nfc/1.1/INfcClientCallback.h>
 #include <android/hardware/nfc/1.1/types.h>
+#include <gtest/gtest.h>
 #include <hardware/nfc.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 
 using ::android::hardware::nfc::V1_1::INfc;
 using ::android::hardware::nfc::V1_1::INfcClientCallback;
@@ -83,25 +84,11 @@
     };
 };
 
-// Test environment for Nfc HIDL HAL.
-class NfcHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static NfcHidlEnvironment* Instance() {
-        static NfcHidlEnvironment* instance = new NfcHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<INfc>(); }
-   private:
-    NfcHidlEnvironment() {}
-};
-
 // The main test class for NFC HIDL HAL.
-class NfcHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class NfcHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        nfc_ = ::testing::VtsHalHidlTargetTestBase::getService<INfc>();
+        nfc_ = INfc::getService(GetParam());
         ASSERT_NE(nfc_, nullptr);
 
         nfc_cb_ = new NfcClientCallback();
@@ -151,7 +138,7 @@
  * calls factoryReset()
  * checks status
  */
-TEST_F(NfcHidlTest, FactoryReset) {
+TEST_P(NfcHidlTest, FactoryReset) {
     nfc_->factoryReset();
 
     EXPECT_EQ(NfcStatus::OK, nfc_->close());
@@ -174,7 +161,7 @@
  * Makes an open call, waits for NfcEvent.OPEN_CPLT
  * Immediately calls closeforPowerOffCase() and waits for NfcEvent.CLOSE_CPLT
  */
-TEST_F(NfcHidlTest, OpenAndCloseForPowerOff) {
+TEST_P(NfcHidlTest, OpenAndCloseForPowerOff) {
     EXPECT_EQ(NfcStatus::OK, nfc_->closeForPowerOffCase());
     // Wait for CLOSE_CPLT event
     auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
@@ -195,7 +182,7 @@
  * Calls closeForPowerOffCase()
  * Calls close() - checks failed status
  */
-TEST_F(NfcHidlTest, CloseForPowerCaseOffAfterClose) {
+TEST_P(NfcHidlTest, CloseForPowerCaseOffAfterClose) {
     EXPECT_EQ(NfcStatus::OK, nfc_->closeForPowerOffCase());
     // Wait for CLOSE_CPLT event
     auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
@@ -218,16 +205,19 @@
  * Calls getConfig()
  * checks if fields in NfcConfig are populated correctly
  */
-TEST_F(NfcHidlTest, GetConfig) {
+TEST_P(NfcHidlTest, GetConfig) {
     nfc_->getConfig([](NfcConfig config) {
         EXPECT_GE(config.maxIsoDepTransceiveLength, MIN_ISO_DEP_TRANSCEIVE_LENGTH);
     });
 }
 
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, NfcHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(INfc::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
 int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(NfcHidlEnvironment::Instance());
     ::testing::InitGoogleTest(&argc, argv);
-    NfcHidlEnvironment::Instance()->init(&argc, argv);
 
     std::system("svc nfc disable"); /* Turn off NFC */
     sleep(5);
diff --git a/nfc/1.2/vts/functional/Android.bp b/nfc/1.2/vts/functional/Android.bp
index 13b254c..7b50a36 100644
--- a/nfc/1.2/vts/functional/Android.bp
+++ b/nfc/1.2/vts/functional/Android.bp
@@ -23,4 +23,5 @@
         "android.hardware.nfc@1.1",
         "android.hardware.nfc@1.2",
     ],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/nfc/1.2/vts/functional/VtsHalNfcV1_2TargetTest.cpp b/nfc/1.2/vts/functional/VtsHalNfcV1_2TargetTest.cpp
index 54d3127..3ec088d 100644
--- a/nfc/1.2/vts/functional/VtsHalNfcV1_2TargetTest.cpp
+++ b/nfc/1.2/vts/functional/VtsHalNfcV1_2TargetTest.cpp
@@ -20,11 +20,12 @@
 #include <android/hardware/nfc/1.1/INfcClientCallback.h>
 #include <android/hardware/nfc/1.2/INfc.h>
 #include <android/hardware/nfc/1.2/types.h>
+#include <gtest/gtest.h>
 #include <hardware/nfc.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 
 using ::android::sp;
 using ::android::hardware::hidl_vec;
@@ -83,26 +84,11 @@
     };
 };
 
-// Test environment for Nfc HIDL HAL.
-class NfcHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static NfcHidlEnvironment* Instance() {
-        static NfcHidlEnvironment* instance = new NfcHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<INfc>(); }
-
-   private:
-    NfcHidlEnvironment() {}
-};
-
 // The main test class for NFC HIDL HAL.
-class NfcHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class NfcHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        nfc_ = ::testing::VtsHalHidlTargetTestBase::getService<INfc>();
+        nfc_ = INfc::getService(GetParam());
         ASSERT_NE(nfc_, nullptr);
 
         nfc_cb_ = new NfcClientCallback();
@@ -152,7 +138,7 @@
  * Calls getConfig()
  * checks if fields in NfcConfig are populated correctly
  */
-TEST_F(NfcHidlTest, GetExtendedConfig) {
+TEST_P(NfcHidlTest, GetExtendedConfig) {
     nfc_->getConfig_1_2([](NfcConfig config) {
         for (uint8_t uicc : config.offHostRouteUicc) {
             EXPECT_GE(uicc, MIN_OFFHOST_ROUTE_ID);
@@ -169,10 +155,13 @@
     });
 }
 
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, NfcHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(INfc::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
 int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(NfcHidlEnvironment::Instance());
     ::testing::InitGoogleTest(&argc, argv);
-    NfcHidlEnvironment::Instance()->init(&argc, argv);
 
     std::system("svc nfc disable"); /* Turn off NFC */
     sleep(5);
diff --git a/power/1.0/vts/functional/Android.bp b/power/1.0/vts/functional/Android.bp
index a716f02..5d5676d 100644
--- a/power/1.0/vts/functional/Android.bp
+++ b/power/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalPowerV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.power@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp b/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp
index 999b2b4..ba08ee7 100644
--- a/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp
+++ b/power/1.0/vts/functional/VtsHalPowerV1_0TargetTest.cpp
@@ -21,9 +21,9 @@
 
 #include <android-base/unique_fd.h>
 #include <android/hardware/power/1.0/IPower.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include <fcntl.h>
 #include <algorithm>
@@ -45,23 +45,10 @@
 #define AVAILABLE_GOVERNORS_PATH \
   "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors"
 
-// Test environment for Power HIDL HAL.
-class PowerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static PowerHidlEnvironment* Instance() {
-        static PowerHidlEnvironment* instance = new PowerHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IPower>(); }
-};
-
-class PowerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class PowerHidlTest : public testing::TestWithParam<std::string> {
  public:
   virtual void SetUp() override {
-      power = ::testing::VtsHalHidlTargetTestBase::getService<IPower>(
-          PowerHidlEnvironment::Instance()->getServiceName<IPower>());
+      power = IPower::getService(GetParam());
       ASSERT_NE(power, nullptr);
   }
 
@@ -71,7 +58,7 @@
 };
 
 // Sanity check Power::setInteractive.
-TEST_F(PowerHidlTest, SetInteractive) {
+TEST_P(PowerHidlTest, SetInteractive) {
   Return<void> ret;
 
   ret = power->setInteractive(true);
@@ -83,7 +70,7 @@
 
 // Test Power::setInteractive and Power::powerHint(Launch)
 // with each available CPU governor, if available
-TEST_F(PowerHidlTest, TryDifferentGovernors) {
+TEST_P(PowerHidlTest, TryDifferentGovernors) {
   Return<void> ret;
 
   unique_fd fd1(open(CPU_GOVERNOR_PATH, O_RDWR));
@@ -125,7 +112,7 @@
 }
 
 // Sanity check Power::powerHint on good and bad inputs.
-TEST_F(PowerHidlTest, PowerHint) {
+TEST_P(PowerHidlTest, PowerHint) {
   PowerHint badHint = static_cast<PowerHint>(0xA);
   auto hints = {PowerHint::VSYNC,         PowerHint::INTERACTION,
                 PowerHint::VIDEO_ENCODE,  PowerHint::VIDEO_DECODE,
@@ -163,7 +150,7 @@
 }
 
 // Sanity check Power::setFeature() on good and bad inputs.
-TEST_F(PowerHidlTest, SetFeature) {
+TEST_P(PowerHidlTest, SetFeature) {
   Return<void> ret;
   ret = power->setFeature(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, true);
   ASSERT_TRUE(ret.isOk());
@@ -178,7 +165,7 @@
 }
 
 // Sanity check Power::getPlatformLowPowerStats().
-TEST_F(PowerHidlTest, GetPlatformLowPowerStats) {
+TEST_P(PowerHidlTest, GetPlatformLowPowerStats) {
   hidl_vec<PowerStatePlatformSleepState> vec;
   Status s;
   auto cb = [&vec, &s](hidl_vec<PowerStatePlatformSleepState> states,
@@ -191,11 +178,7 @@
   ASSERT_TRUE(s == Status::SUCCESS || s == Status::FILESYSTEM_ERROR);
 }
 
-int main(int argc, char **argv) {
-    ::testing::AddGlobalTestEnvironment(PowerHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    PowerHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, PowerHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IPower::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/power/1.1/vts/functional/Android.bp b/power/1.1/vts/functional/Android.bp
index de75984..d9a32df 100644
--- a/power/1.1/vts/functional/Android.bp
+++ b/power/1.1/vts/functional/Android.bp
@@ -22,5 +22,5 @@
         "android.hardware.power@1.0",
         "android.hardware.power@1.1",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/power/1.1/vts/functional/VtsHalPowerV1_1TargetTest.cpp b/power/1.1/vts/functional/VtsHalPowerV1_1TargetTest.cpp
index 4427b15..e9a722c 100644
--- a/power/1.1/vts/functional/VtsHalPowerV1_1TargetTest.cpp
+++ b/power/1.1/vts/functional/VtsHalPowerV1_1TargetTest.cpp
@@ -17,9 +17,9 @@
 #define LOG_TAG "power_hidl_hal_test"
 #include <android-base/logging.h>
 #include <android/hardware/power/1.1/IPower.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 using ::android::hardware::power::V1_1::IPower;
 using ::android::hardware::power::V1_1::PowerStateSubsystem;
@@ -29,23 +29,10 @@
 using ::android::hardware::Return;
 using ::android::sp;
 
-// Test environment for Power HIDL HAL.
-class PowerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static PowerHidlEnvironment* Instance() {
-        static PowerHidlEnvironment* instance = new PowerHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IPower>(); }
-};
-
-class PowerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class PowerHidlTest : public testing::TestWithParam<std::string> {
  public:
   virtual void SetUp() override {
-      power = ::testing::VtsHalHidlTargetTestBase::getService<IPower>(
-          PowerHidlEnvironment::Instance()->getServiceName<IPower>());
+      power = IPower::getService(GetParam());
       ASSERT_NE(power, nullptr);
   }
 
@@ -55,7 +42,7 @@
 };
 
 // Sanity check Power::getSubsystemLowPowerStats().
-TEST_F(PowerHidlTest, GetSubsystemLowPowerStats) {
+TEST_P(PowerHidlTest, GetSubsystemLowPowerStats) {
   hidl_vec<PowerStateSubsystem> vec;
   Status s;
   auto cb = [&vec, &s](hidl_vec<PowerStateSubsystem> subsystems,
@@ -70,7 +57,7 @@
 }
 
 // Sanity check Power::powerHintAsync on good and bad inputs.
-TEST_F(PowerHidlTest, PowerHintAsync) {
+TEST_P(PowerHidlTest, PowerHintAsync) {
     PowerHint badHint = static_cast<PowerHint>(0xA);
     auto hints = {PowerHint::VSYNC,        PowerHint::INTERACTION, PowerHint::VIDEO_ENCODE,
                   PowerHint::VIDEO_DECODE, PowerHint::LOW_POWER,   PowerHint::SUSTAINED_PERFORMANCE,
@@ -104,11 +91,7 @@
     } while (std::next_permutation(hints2.begin(), hints2.end(), compareHints));
 }
 
-int main(int argc, char **argv) {
-    ::testing::AddGlobalTestEnvironment(PowerHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    PowerHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, PowerHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IPower::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/power/1.2/vts/functional/Android.bp b/power/1.2/vts/functional/Android.bp
index f424bfa..5385faa 100644
--- a/power/1.2/vts/functional/Android.bp
+++ b/power/1.2/vts/functional/Android.bp
@@ -23,5 +23,5 @@
         "android.hardware.power@1.1",
         "android.hardware.power@1.2",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/power/1.2/vts/functional/VtsHalPowerV1_2TargetTest.cpp b/power/1.2/vts/functional/VtsHalPowerV1_2TargetTest.cpp
index 5e92997..a5ecf5d 100644
--- a/power/1.2/vts/functional/VtsHalPowerV1_2TargetTest.cpp
+++ b/power/1.2/vts/functional/VtsHalPowerV1_2TargetTest.cpp
@@ -17,9 +17,9 @@
 #define LOG_TAG "power_hidl_hal_test"
 #include <android-base/logging.h>
 #include <android/hardware/power/1.2/IPower.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 using ::android::sp;
 using ::android::hardware::hidl_vec;
@@ -27,23 +27,10 @@
 using ::android::hardware::power::V1_2::IPower;
 using ::android::hardware::power::V1_2::PowerHint;
 
-// Test environment for Power HIDL HAL.
-class PowerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static PowerHidlEnvironment* Instance() {
-        static PowerHidlEnvironment* instance = new PowerHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IPower>(); }
-};
-
-class PowerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class PowerHidlTest : public testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        power = ::testing::VtsHalHidlTargetTestBase::getService<IPower>(
-            PowerHidlEnvironment::Instance()->getServiceName<IPower>());
+        power = IPower::getService(GetParam());
         ASSERT_NE(power, nullptr);
     }
 
@@ -51,7 +38,7 @@
 };
 
 // Sanity check Power::PowerHintAsync_1_2 on good and bad inputs.
-TEST_F(PowerHidlTest, PowerHintAsync_1_2) {
+TEST_P(PowerHidlTest, PowerHintAsync_1_2) {
     std::vector<PowerHint> hints;
     for (uint32_t i = static_cast<uint32_t>(PowerHint::VSYNC);
          i <= static_cast<uint32_t>(PowerHint::CAMERA_SHOT); ++i) {
@@ -89,11 +76,8 @@
     } while (std::next_permutation(hints2.begin(), hints2.end(), compareHints));
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(PowerHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    PowerHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, PowerHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IPower::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
diff --git a/power/1.3/vts/functional/Android.bp b/power/1.3/vts/functional/Android.bp
index 06f6e7a..77e8619 100644
--- a/power/1.3/vts/functional/Android.bp
+++ b/power/1.3/vts/functional/Android.bp
@@ -24,5 +24,5 @@
         "android.hardware.power@1.2",
         "android.hardware.power@1.3",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/power/1.3/vts/functional/VtsHalPowerV1_3TargetTest.cpp b/power/1.3/vts/functional/VtsHalPowerV1_3TargetTest.cpp
index af1a1d8..3cf2adc 100644
--- a/power/1.3/vts/functional/VtsHalPowerV1_3TargetTest.cpp
+++ b/power/1.3/vts/functional/VtsHalPowerV1_3TargetTest.cpp
@@ -17,9 +17,9 @@
 #define LOG_TAG "power_hidl_hal_test"
 #include <android-base/logging.h>
 #include <android/hardware/power/1.3/IPower.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 using ::android::sp;
 using ::android::hardware::hidl_vec;
@@ -27,38 +27,21 @@
 using ::android::hardware::power::V1_3::IPower;
 using ::android::hardware::power::V1_3::PowerHint;
 
-// Test environment for Power HIDL HAL.
-class PowerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static PowerHidlEnvironment* Instance() {
-        static PowerHidlEnvironment* instance = new PowerHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IPower>(); }
-};
-
-class PowerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class PowerHidlTest : public testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        power = ::testing::VtsHalHidlTargetTestBase::getService<IPower>(
-            PowerHidlEnvironment::Instance()->getServiceName<IPower>());
+        power = IPower::getService(GetParam());
         ASSERT_NE(power, nullptr);
     }
 
     sp<IPower> power;
 };
 
-TEST_F(PowerHidlTest, PowerHintAsync_1_3) {
+TEST_P(PowerHidlTest, PowerHintAsync_1_3) {
     ASSERT_TRUE(power->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING, 0).isOk());
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(PowerHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    PowerHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, PowerHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IPower::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/power/stats/1.0/vts/functional/Android.bp b/power/stats/1.0/vts/functional/Android.bp
index f564cbe..ab47061 100644
--- a/power/stats/1.0/vts/functional/Android.bp
+++ b/power/stats/1.0/vts/functional/Android.bp
@@ -33,4 +33,5 @@
         "libfmq",
         "libutils",
     ],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/power/stats/1.0/vts/functional/VtsHalPowerStatsV1_0TargetTest.cpp b/power/stats/1.0/vts/functional/VtsHalPowerStatsV1_0TargetTest.cpp
index 835a47b..3359669 100644
--- a/power/stats/1.0/vts/functional/VtsHalPowerStatsV1_0TargetTest.cpp
+++ b/power/stats/1.0/vts/functional/VtsHalPowerStatsV1_0TargetTest.cpp
@@ -16,13 +16,15 @@
 
 #define LOG_TAG "android.power.stats.vts"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/power/stats/1.0/IPowerStats.h>
 #include <fmq/MessageQueue.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
 #include <hidl/MQDescriptor.h>
+#include <hidl/ServiceManagement.h>
 #include <inttypes.h>
+
 #include <algorithm>
 #include <random>
 #include <thread>
@@ -49,23 +51,11 @@
 }  // namespace
 
 typedef hardware::MessageQueue<EnergyData, kSynchronizedReadWrite> MessageQueueSync;
-// Test environment for Power HIDL HAL.
-class PowerStatsHidlEnv : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static PowerStatsHidlEnv* Instance() {
-        static PowerStatsHidlEnv* instance = new PowerStatsHidlEnv;
-        return instance;
-    }
 
-    virtual void registerTestServices() override { registerTestService<IPowerStats>(); }
-};
-
-class PowerStatsHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class PowerStatsHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        service_ = ::testing::VtsHalHidlTargetTestBase::getService<IPowerStats>(
-            PowerStatsHidlEnv::Instance()->getServiceName<IPowerStats>());
+        service_ = IPowerStats::getService(GetParam());
         ASSERT_NE(service_, nullptr);
     }
 
@@ -157,7 +147,7 @@
 }
 
 // Each PowerEntity must have a valid name
-TEST_F(PowerStatsHidlTest, ValidatePowerEntityNames) {
+TEST_P(PowerStatsHidlTest, ValidatePowerEntityNames) {
     hidl_vec<PowerEntityInfo> infos;
     getInfos(infos);
     for (auto info : infos) {
@@ -166,18 +156,18 @@
 }
 
 // Each PowerEntity must have a unique ID
-TEST_F(PowerStatsHidlTest, ValidatePowerEntityIds) {
+TEST_P(PowerStatsHidlTest, ValidatePowerEntityIds) {
     hidl_vec<PowerEntityInfo> infos;
     getInfos(infos);
 
-    set<uint32_t> ids;
+    std::set<uint32_t> ids;
     for (auto info : infos) {
         ASSERT_TRUE(ids.insert(info.powerEntityId).second);
     }
 }
 
 // Each PowerEntityStateSpace must have an associated PowerEntityInfo
-TEST_F(PowerStatsHidlTest, ValidateStateInfoAssociation) {
+TEST_P(PowerStatsHidlTest, ValidateStateInfoAssociation) {
     hidl_vec<PowerEntityInfo> infos;
     getInfos(infos);
 
@@ -195,7 +185,7 @@
 }
 
 // Each state must have a valid name
-TEST_F(PowerStatsHidlTest, ValidateStateNames) {
+TEST_P(PowerStatsHidlTest, ValidateStateNames) {
     hidl_vec<PowerEntityStateSpace> stateSpaces;
     getStateSpaces(stateSpaces);
 
@@ -207,12 +197,12 @@
 }
 
 // Each state must have an ID that is unique to the PowerEntityStateSpace
-TEST_F(PowerStatsHidlTest, ValidateStateUniqueIds) {
+TEST_P(PowerStatsHidlTest, ValidateStateUniqueIds) {
     hidl_vec<PowerEntityStateSpace> stateSpaces;
     getStateSpaces(stateSpaces);
 
     for (auto stateSpace : stateSpaces) {
-        set<uint32_t> stateIds;
+        std::set<uint32_t> stateIds;
         for (auto state : stateSpace.states) {
             ASSERT_TRUE(stateIds.insert(state.powerEntityStateId).second);
         }
@@ -221,7 +211,7 @@
 
 // getPowerEntityStateInfo must support passing in requested IDs
 // Results must contain state space information for all requested IDs
-TEST_F(PowerStatsHidlTest, ValidateStateInfoAssociationSelect) {
+TEST_P(PowerStatsHidlTest, ValidateStateInfoAssociationSelect) {
     std::vector<uint32_t> randomIds;
     getRandomIds(randomIds);
 
@@ -244,7 +234,7 @@
 }
 
 // Requested state space info must match initially obtained stateinfos
-TEST_F(PowerStatsHidlTest, ValidateStateInfoSelect) {
+TEST_P(PowerStatsHidlTest, ValidateStateInfoSelect) {
     hidl_vec<PowerEntityStateSpace> stateSpaces;
     getStateSpaces(stateSpaces);
     if (stateSpaces.size() == 0) {
@@ -279,7 +269,7 @@
 
 // stateResidencyResults must contain results for every PowerEntityStateSpace
 // returned by getPowerEntityStateInfo
-TEST_F(PowerStatsHidlTest, ValidateResidencyResultsAssociation) {
+TEST_P(PowerStatsHidlTest, ValidateResidencyResultsAssociation) {
     hidl_vec<PowerEntityStateSpace> stateSpaces;
     getStateSpaces(stateSpaces);
 
@@ -311,7 +301,7 @@
 // getPowerEntityStateResidencyData must support passing in requested IDs
 // stateResidencyResults must contain results for each PowerEntityStateSpace
 // returned by getPowerEntityStateInfo
-TEST_F(PowerStatsHidlTest, ValidateResidencyResultsAssociationSelect) {
+TEST_P(PowerStatsHidlTest, ValidateResidencyResultsAssociationSelect) {
     std::vector<uint32_t> randomIds;
     getRandomIds(randomIds);
     if (randomIds.empty()) {
@@ -346,7 +336,7 @@
     }
 }
 
-TEST_F(PowerStatsHidlTest, ValidateRailInfo) {
+TEST_P(PowerStatsHidlTest, ValidateRailInfo) {
     hidl_vec<RailInfo> rails[2];
     Status s;
     auto cb = [&rails, &s](hidl_vec<RailInfo> rail_subsys, Status status) {
@@ -359,7 +349,7 @@
         /* Rails size should be non-zero on SUCCESS*/
         ASSERT_NE(rails[0].size(), 0);
         /* check if indices returned are unique*/
-        set<uint32_t> ids;
+        std::set<uint32_t> ids;
         for (auto rail : rails[0]) {
             ASSERT_TRUE(ids.insert(rail.index).second);
         }
@@ -402,7 +392,7 @@
     }
 }
 
-TEST_F(PowerStatsHidlTest, ValidateAllPowerData) {
+TEST_P(PowerStatsHidlTest, ValidateAllPowerData) {
     hidl_vec<EnergyData> measurements[2];
     Status s;
     auto cb = [&measurements, &s](hidl_vec<EnergyData> measure, Status status) {
@@ -451,7 +441,7 @@
     }
 }
 
-TEST_F(PowerStatsHidlTest, ValidateFilteredPowerData) {
+TEST_P(PowerStatsHidlTest, ValidateFilteredPowerData) {
     hidl_vec<RailInfo> rails;
     hidl_vec<EnergyData> measurements;
     hidl_vec<uint32_t> indices;
@@ -559,23 +549,19 @@
     }
 }
 
-TEST_F(PowerStatsHidlTest, StreamEnergyData) {
+TEST_P(PowerStatsHidlTest, StreamEnergyData) {
     std::time_t seed = std::time(nullptr);
     std::srand(seed);
     std::thread thread1 = std::thread(readEnergy, service_, std::rand() % 5000);
     thread1.join();
 }
 
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, PowerStatsHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IPowerStats::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
 }  // namespace vts
 }  // namespace stats
 }  // namespace power
 }  // namespace android
-
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(android::power::stats::vts::PowerStatsHidlEnv::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    android::power::stats::vts::PowerStatsHidlEnv::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
diff --git a/vibrator/1.0/vts/functional/Android.bp b/vibrator/1.0/vts/functional/Android.bp
index 391d3d4..10ec2cb 100644
--- a/vibrator/1.0/vts/functional/Android.bp
+++ b/vibrator/1.0/vts/functional/Android.bp
@@ -19,6 +19,6 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalVibratorV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.vibrator@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
diff --git a/vibrator/1.0/vts/functional/VtsHalVibratorV1_0TargetTest.cpp b/vibrator/1.0/vts/functional/VtsHalVibratorV1_0TargetTest.cpp
index 6f8aa02..2aee338 100644
--- a/vibrator/1.0/vts/functional/VtsHalVibratorV1_0TargetTest.cpp
+++ b/vibrator/1.0/vts/functional/VtsHalVibratorV1_0TargetTest.cpp
@@ -21,8 +21,9 @@
 #include <android/hardware/vibrator/1.0/types.h>
 #include <unistd.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 using ::android::sp;
 using ::android::hardware::hidl_enum_range;
@@ -35,27 +36,11 @@
 
 #define EXPECT_OK(ret) EXPECT_TRUE((ret).isOk())
 
-// Test environment for Vibrator HIDL HAL.
-class VibratorHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static VibratorHidlEnvironment* Instance() {
-      static VibratorHidlEnvironment* instance = new VibratorHidlEnvironment;
-      return instance;
-  }
-
-  virtual void registerTestServices() override { registerTestService<IVibrator>(); }
-
- private:
-  VibratorHidlEnvironment() {}
-};
-
 // The main test class for VIBRATOR HIDL HAL.
-class VibratorHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class VibratorHidlTest : public ::testing::TestWithParam<std::string> {
  public:
   virtual void SetUp() override {
-    vibrator = ::testing::VtsHalHidlTargetTestBase::getService<IVibrator>(
-        VibratorHidlEnvironment::Instance()->getServiceName<IVibrator>());
+    vibrator = IVibrator::getService(GetParam());
     ASSERT_NE(vibrator, nullptr);
   }
 
@@ -79,13 +64,13 @@
             << "Effects that return UNSUPPORTED_OPERATION must have a duration of zero";
 }
 
-TEST_F(VibratorHidlTest, OnThenOffBeforeTimeout) {
+TEST_P(VibratorHidlTest, OnThenOffBeforeTimeout) {
   EXPECT_EQ(Status::OK, vibrator->on(2000));
   sleep(1);
   EXPECT_EQ(Status::OK, vibrator->off());
 }
 
-TEST_F(VibratorHidlTest, PerformEffect) {
+TEST_P(VibratorHidlTest, PerformEffect) {
   vibrator->perform(Effect::CLICK, EffectStrength::MEDIUM, validatePerformEffect);
   vibrator->perform(Effect::DOUBLE_CLICK, EffectStrength::LIGHT, validatePerformEffect);
 }
@@ -93,7 +78,7 @@
 /*
  * Test to make sure effect values above the valid range are rejected.
  */
-TEST_F(VibratorHidlTest, PerformEffect_BadEffects_AboveValidRange) {
+TEST_P(VibratorHidlTest, PerformEffect_BadEffects_AboveValidRange) {
     Effect effect = *std::prev(hidl_enum_range<Effect>().end());
     Effect badEffect = static_cast<Effect>(static_cast<int32_t>(effect) + 1);
     EXPECT_OK(vibrator->perform(badEffect, EffectStrength::LIGHT, validatePerformEffectBadInput));
@@ -102,7 +87,7 @@
 /*
  * Test to make sure effect values below the valid range are rejected.
  */
-TEST_F(VibratorHidlTest, PerformEffect_BadEffects_BelowValidRange) {
+TEST_P(VibratorHidlTest, PerformEffect_BadEffects_BelowValidRange) {
     Effect effect = *hidl_enum_range<Effect>().begin();
     Effect badEffect = static_cast<Effect>(static_cast<int32_t>(effect) - 1);
     EXPECT_OK(vibrator->perform(badEffect, EffectStrength::LIGHT, validatePerformEffectBadInput));
@@ -111,7 +96,7 @@
 /*
  * Test to make sure strength values above the valid range are rejected.
  */
-TEST_F(VibratorHidlTest, PerformEffect_BadStrength_AboveValidRange) {
+TEST_P(VibratorHidlTest, PerformEffect_BadStrength_AboveValidRange) {
     EffectStrength strength = *std::prev(hidl_enum_range<EffectStrength>().end());
     EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) + 1);
     EXPECT_OK(vibrator->perform(Effect::CLICK, badStrength, validatePerformEffectBadInput));
@@ -120,13 +105,13 @@
 /*
  * Test to make sure strength values below the valid range are rejected.
  */
-TEST_F(VibratorHidlTest, PerformEffect_BadStrength_BelowValidRange) {
+TEST_P(VibratorHidlTest, PerformEffect_BadStrength_BelowValidRange) {
     EffectStrength strength = *hidl_enum_range<EffectStrength>().begin();
     EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) - 1);
     EXPECT_OK(vibrator->perform(Effect::CLICK, badStrength, validatePerformEffectBadInput));
 }
 
-TEST_F(VibratorHidlTest, ChangeVibrationalAmplitude) {
+TEST_P(VibratorHidlTest, ChangeVibrationalAmplitude) {
   if (vibrator->supportsAmplitudeControl()) {
     EXPECT_EQ(Status::OK, vibrator->setAmplitude(1));
     EXPECT_EQ(Status::OK, vibrator->on(2000));
@@ -137,23 +122,19 @@
   }
 }
 
-TEST_F(VibratorHidlTest, AmplitudeOutsideRangeFails) {
+TEST_P(VibratorHidlTest, AmplitudeOutsideRangeFails) {
   if (vibrator->supportsAmplitudeControl()) {
     EXPECT_EQ(Status::BAD_VALUE, vibrator->setAmplitude(0));
   }
 }
 
-TEST_F(VibratorHidlTest, SetAmplitudeReturnUnsupportedOperationIfNotSupported) {
+TEST_P(VibratorHidlTest, SetAmplitudeReturnUnsupportedOperationIfNotSupported) {
   if (!vibrator->supportsAmplitudeControl()) {
     EXPECT_EQ(Status::UNSUPPORTED_OPERATION, vibrator->setAmplitude(1));
   }
 }
 
-int main(int argc, char **argv) {
-  ::testing::AddGlobalTestEnvironment(VibratorHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  VibratorHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  LOG(INFO) << "Test result = " << status;
-  return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, VibratorHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVibrator::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/vibrator/1.1/vts/functional/Android.bp b/vibrator/1.1/vts/functional/Android.bp
index c65ff41..4cde350 100644
--- a/vibrator/1.1/vts/functional/Android.bp
+++ b/vibrator/1.1/vts/functional/Android.bp
@@ -22,6 +22,6 @@
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
diff --git a/vibrator/1.1/vts/functional/VtsHalVibratorV1_1TargetTest.cpp b/vibrator/1.1/vts/functional/VtsHalVibratorV1_1TargetTest.cpp
index 3c3ebf2..da94308 100644
--- a/vibrator/1.1/vts/functional/VtsHalVibratorV1_1TargetTest.cpp
+++ b/vibrator/1.1/vts/functional/VtsHalVibratorV1_1TargetTest.cpp
@@ -16,11 +16,12 @@
 
 #define LOG_TAG "vibrator_hidl_hal_test"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/vibrator/1.1/IVibrator.h>
 #include <android/hardware/vibrator/1.1/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <unistd.h>
 
 using ::android::sp;
@@ -34,27 +35,11 @@
 
 #define EXPECT_OK(ret) EXPECT_TRUE((ret).isOk())
 
-// Test environment for Vibrator HIDL HAL.
-class VibratorHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static VibratorHidlEnvironment* Instance() {
-        static VibratorHidlEnvironment* instance = new VibratorHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IVibrator>(); }
-
-   private:
-    VibratorHidlEnvironment() {}
-};
-
 // The main test class for VIBRATOR HIDL HAL 1.1.
-class VibratorHidlTest_1_1 : public ::testing::VtsHalHidlTargetTestBase {
+class VibratorHidlTest_1_1 : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        vibrator = ::testing::VtsHalHidlTargetTestBase::getService<IVibrator>(
-            VibratorHidlEnvironment::Instance()->getServiceName<IVibrator>());
+        vibrator = IVibrator::getService(GetParam());
         ASSERT_NE(vibrator, nullptr);
     }
 
@@ -80,7 +65,7 @@
             << "Effects that return UNSUPPORTED_OPERATION must have a duration of zero";
 }
 
-TEST_F(VibratorHidlTest_1_1, PerformEffect_1_1) {
+TEST_P(VibratorHidlTest_1_1, PerformEffect_1_1) {
     vibrator->perform_1_1(Effect_1_1::CLICK, EffectStrength::MEDIUM, validatePerformEffect);
     vibrator->perform_1_1(Effect_1_1::TICK, EffectStrength::STRONG, validatePerformEffect);
 }
@@ -88,7 +73,7 @@
 /*
  * Test to make sure effect values above the valid range are rejected.
  */
-TEST_F(VibratorHidlTest_1_1, PerformEffect_1_1_BadEffects_AboveValidRange) {
+TEST_P(VibratorHidlTest_1_1, PerformEffect_1_1_BadEffects_AboveValidRange) {
     Effect_1_1 effect = *std::prev(hidl_enum_range<Effect_1_1>().end());
     Effect_1_1 badEffect = static_cast<Effect_1_1>(static_cast<int32_t>(effect) + 1);
     EXPECT_OK(
@@ -98,7 +83,7 @@
 /*
  * Test to make sure effect values below the valid range are rejected.
  */
-TEST_F(VibratorHidlTest_1_1, PerformEffect_1_1_BadEffects_BelowValidRange) {
+TEST_P(VibratorHidlTest_1_1, PerformEffect_1_1_BadEffects_BelowValidRange) {
     Effect_1_1 effect = *hidl_enum_range<Effect_1_1>().begin();
     Effect_1_1 badEffect = static_cast<Effect_1_1>(static_cast<int32_t>(effect) - 1);
     EXPECT_OK(
@@ -108,7 +93,7 @@
 /*
  * Test to make sure strength values above the valid range are rejected.
  */
-TEST_F(VibratorHidlTest_1_1, PerformEffect_1_1_BadStrength_AboveValidRange) {
+TEST_P(VibratorHidlTest_1_1, PerformEffect_1_1_BadStrength_AboveValidRange) {
     EffectStrength strength = *std::prev(hidl_enum_range<EffectStrength>().end());
     EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) + 1);
     EXPECT_OK(vibrator->perform_1_1(Effect_1_1::CLICK, badStrength, validatePerformEffectBadInput));
@@ -117,17 +102,13 @@
 /*
  * Test to make sure strength values below the valid range are rejected.
  */
-TEST_F(VibratorHidlTest_1_1, PerformEffect_1_1_BadStrength_BelowValidRange) {
+TEST_P(VibratorHidlTest_1_1, PerformEffect_1_1_BadStrength_BelowValidRange) {
     EffectStrength strength = *hidl_enum_range<EffectStrength>().begin();
     EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) - 1);
     EXPECT_OK(vibrator->perform_1_1(Effect_1_1::CLICK, badStrength, validatePerformEffectBadInput));
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(VibratorHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    VibratorHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, VibratorHidlTest_1_1,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVibrator::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/vibrator/1.2/vts/functional/Android.bp b/vibrator/1.2/vts/functional/Android.bp
index 1e3ec97..e7052f2 100644
--- a/vibrator/1.2/vts/functional/Android.bp
+++ b/vibrator/1.2/vts/functional/Android.bp
@@ -23,6 +23,6 @@
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
diff --git a/vibrator/1.2/vts/functional/VtsHalVibratorV1_2TargetTest.cpp b/vibrator/1.2/vts/functional/VtsHalVibratorV1_2TargetTest.cpp
index d69695a..2058e85 100644
--- a/vibrator/1.2/vts/functional/VtsHalVibratorV1_2TargetTest.cpp
+++ b/vibrator/1.2/vts/functional/VtsHalVibratorV1_2TargetTest.cpp
@@ -16,12 +16,13 @@
 
 #define LOG_TAG "vibrator_hidl_hal_test"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/vibrator/1.0/types.h>
 #include <android/hardware/vibrator/1.2/IVibrator.h>
 #include <android/hardware/vibrator/1.2/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <unistd.h>
 
 using ::android::hardware::vibrator::V1_0::Status;
@@ -35,27 +36,11 @@
 
 #define EXPECT_OK(ret) ASSERT_TRUE((ret).isOk())
 
-// Test environment for Vibrator HIDL HAL.
-class VibratorHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static VibratorHidlEnvironment* Instance() {
-        static VibratorHidlEnvironment* instance = new VibratorHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IVibrator>(); }
-
-   private:
-    VibratorHidlEnvironment() {}
-};
-
 // The main test class for VIBRATOR HIDL HAL 1.2.
-class VibratorHidlTest_1_2 : public ::testing::VtsHalHidlTargetTestBase {
+class VibratorHidlTest_1_2 : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        vibrator = ::testing::VtsHalHidlTargetTestBase::getService<IVibrator>(
-            VibratorHidlEnvironment::Instance()->getServiceName<IVibrator>());
+        vibrator = IVibrator::getService(GetParam());
         ASSERT_NE(vibrator, nullptr);
     }
 
@@ -85,7 +70,7 @@
  * Test to make sure effects within the valid range return are either supported and return OK with
  * a valid duration, or are unsupported and return UNSUPPORTED_OPERATION with a duration of 0.
  */
-TEST_F(VibratorHidlTest_1_2, PerformEffect_1_2) {
+TEST_P(VibratorHidlTest_1_2, PerformEffect_1_2) {
     for (const auto& effect : hidl_enum_range<Effect>()) {
         for (const auto& strength : hidl_enum_range<EffectStrength>()) {
             EXPECT_OK(vibrator->perform_1_2(effect, strength, validatePerformEffect));
@@ -96,7 +81,7 @@
 /*
  * Test to make sure effect values above the valid range are rejected.
  */
-TEST_F(VibratorHidlTest_1_2, PerformEffect_1_2_BadEffects_AboveValidRange) {
+TEST_P(VibratorHidlTest_1_2, PerformEffect_1_2_BadEffects_AboveValidRange) {
     Effect effect = *std::prev(hidl_enum_range<Effect>().end());
     Effect badEffect = static_cast<Effect>(static_cast<int32_t>(effect) + 1);
     EXPECT_OK(
@@ -106,7 +91,7 @@
 /*
  * Test to make sure effect values below the valid range are rejected.
  */
-TEST_F(VibratorHidlTest_1_2, PerformEffect_1_2_BadEffects_BelowValidRange) {
+TEST_P(VibratorHidlTest_1_2, PerformEffect_1_2_BadEffects_BelowValidRange) {
     Effect effect = *hidl_enum_range<Effect>().begin();
     Effect badEffect = static_cast<Effect>(static_cast<int32_t>(effect) - 1);
     EXPECT_OK(
@@ -116,7 +101,7 @@
 /*
  * Test to make sure strength values above the valid range are rejected.
  */
-TEST_F(VibratorHidlTest_1_2, PerformEffect_1_2_BadStrength_AboveValidRange) {
+TEST_P(VibratorHidlTest_1_2, PerformEffect_1_2_BadStrength_AboveValidRange) {
     EffectStrength strength = *std::prev(hidl_enum_range<EffectStrength>().end());
     EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) + 1);
     EXPECT_OK(vibrator->perform_1_2(Effect::THUD, badStrength, validatePerformEffectBadInput));
@@ -125,17 +110,13 @@
 /*
  * Test to make sure strength values below the valid range are rejected.
  */
-TEST_F(VibratorHidlTest_1_2, PerformEffect_1_2_BadStrength_BelowValidRange) {
+TEST_P(VibratorHidlTest_1_2, PerformEffect_1_2_BadStrength_BelowValidRange) {
     EffectStrength strength = *hidl_enum_range<EffectStrength>().begin();
     EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) - 1);
     EXPECT_OK(vibrator->perform_1_2(Effect::THUD, badStrength, validatePerformEffectBadInput));
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(VibratorHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    VibratorHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, VibratorHidlTest_1_2,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVibrator::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.rc b/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.rc
deleted file mode 100644
index ed7a562..0000000
--- a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service vendor.vibrator-1-3 /vendor/bin/hw/android.hardware.vibrator@1.3-service.example
-    class hal
-    user system
-    group system
diff --git a/vibrator/1.3/vts/functional/Android.bp b/vibrator/1.3/vts/functional/Android.bp
index 5b4c893..038dc5c 100644
--- a/vibrator/1.3/vts/functional/Android.bp
+++ b/vibrator/1.3/vts/functional/Android.bp
@@ -24,6 +24,6 @@
         "android.hardware.vibrator@1.2",
         "android.hardware.vibrator@1.3",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
 
diff --git a/vibrator/1.3/vts/functional/VtsHalVibratorV1_3TargetTest.cpp b/vibrator/1.3/vts/functional/VtsHalVibratorV1_3TargetTest.cpp
index 818f9c7..3cd3430 100644
--- a/vibrator/1.3/vts/functional/VtsHalVibratorV1_3TargetTest.cpp
+++ b/vibrator/1.3/vts/functional/VtsHalVibratorV1_3TargetTest.cpp
@@ -16,11 +16,12 @@
 
 #define LOG_TAG "vibrator_hidl_hal_test"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/vibrator/1.0/types.h>
 #include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <unistd.h>
 
 using ::android::sp;
@@ -34,27 +35,11 @@
 
 #define EXPECT_OK(ret) ASSERT_TRUE((ret).isOk())
 
-// Test environment for Vibrator HIDL HAL.
-class VibratorHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static VibratorHidlEnvironment* Instance() {
-        static VibratorHidlEnvironment* instance = new VibratorHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IVibrator>(); }
-
-   private:
-    VibratorHidlEnvironment() {}
-};
-
 // The main test class for VIBRATOR HIDL HAL 1.3.
-class VibratorHidlTest_1_3 : public ::testing::VtsHalHidlTargetTestBase {
+class VibratorHidlTest_1_3 : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        vibrator = ::testing::VtsHalHidlTargetTestBase::getService<IVibrator>(
-            VibratorHidlEnvironment::Instance()->getServiceName<IVibrator>());
+        vibrator = IVibrator::getService(GetParam());
         ASSERT_NE(vibrator, nullptr);
     }
 
@@ -63,7 +48,7 @@
     sp<IVibrator> vibrator;
 };
 
-TEST_F(VibratorHidlTest_1_3, ChangeVibrationalExternalControl) {
+TEST_P(VibratorHidlTest_1_3, ChangeVibrationalExternalControl) {
     if (vibrator->supportsExternalControl()) {
         EXPECT_EQ(Status::OK, vibrator->setExternalControl(true));
         sleep(1);
@@ -72,7 +57,7 @@
     }
 }
 
-TEST_F(VibratorHidlTest_1_3, SetExternalControlReturnUnsupportedOperationIfNotSupported) {
+TEST_P(VibratorHidlTest_1_3, SetExternalControlReturnUnsupportedOperationIfNotSupported) {
     if (!vibrator->supportsExternalControl()) {
         EXPECT_EQ(Status::UNSUPPORTED_OPERATION, vibrator->setExternalControl(true));
     }
@@ -98,7 +83,7 @@
  * Test to make sure effects within the valid range return are either supported and return OK with
  * a valid duration, or are unsupported and return UNSUPPORTED_OPERATION with a duration of 0.
  */
-TEST_F(VibratorHidlTest_1_3, PerformEffect_1_3) {
+TEST_P(VibratorHidlTest_1_3, PerformEffect_1_3) {
     for (const auto& effect : hidl_enum_range<Effect>()) {
         for (const auto& strength : hidl_enum_range<EffectStrength>()) {
             EXPECT_OK(vibrator->perform_1_3(effect, strength, validatePerformEffect));
@@ -109,7 +94,7 @@
 /*
  * Test to make sure effect values above the valid range are rejected.
  */
-TEST_F(VibratorHidlTest_1_3, PerformEffect_1_3_BadEffects_AboveValidRange) {
+TEST_P(VibratorHidlTest_1_3, PerformEffect_1_3_BadEffects_AboveValidRange) {
     Effect effect = *std::prev(hidl_enum_range<Effect>().end());
     Effect badEffect = static_cast<Effect>(static_cast<int32_t>(effect) + 1);
     EXPECT_OK(vibrator->perform_1_3(badEffect, EffectStrength::LIGHT,
@@ -119,7 +104,7 @@
 /*
  * Test to make sure effect values below the valid range are rejected.
  */
-TEST_F(VibratorHidlTest_1_3, PerformEffect_1_3_BadEffects_BelowValidRange) {
+TEST_P(VibratorHidlTest_1_3, PerformEffect_1_3_BadEffects_BelowValidRange) {
     Effect effect = *hidl_enum_range<Effect>().begin();
     Effect badEffect = static_cast<Effect>(static_cast<int32_t>(effect) - 1);
     EXPECT_OK(vibrator->perform_1_3(badEffect, EffectStrength::LIGHT,
@@ -129,7 +114,7 @@
 /*
  * Test to make sure strength values above the valid range are rejected.
  */
-TEST_F(VibratorHidlTest_1_3, PerformEffect_1_3_BadStrength_AboveValidRange) {
+TEST_P(VibratorHidlTest_1_3, PerformEffect_1_3_BadStrength_AboveValidRange) {
     EffectStrength strength = *std::prev(hidl_enum_range<EffectStrength>().end());
     EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) + 1);
     EXPECT_OK(vibrator->perform_1_3(Effect::THUD, badStrength,
@@ -139,18 +124,14 @@
 /*
  * Test to make sure strength values below the valid range are rejected.
  */
-TEST_F(VibratorHidlTest_1_3, PerformEffect_1_3_BadStrength_BelowValidRange) {
+TEST_P(VibratorHidlTest_1_3, PerformEffect_1_3_BadStrength_BelowValidRange) {
     EffectStrength strength = *hidl_enum_range<EffectStrength>().begin();
     EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) - 1);
     EXPECT_OK(vibrator->perform_1_3(Effect::THUD, badStrength,
                                     validatePerformEffectUnsupportedOperation));
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(VibratorHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    VibratorHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, VibratorHidlTest_1_3,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVibrator::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/vibrator/1.3/example/Android.bp b/vibrator/1.4/vts/functional/Android.bp
similarity index 65%
copy from vibrator/1.3/example/Android.bp
copy to vibrator/1.4/vts/functional/Android.bp
index 07f1c26..202a824 100644
--- a/vibrator/1.3/example/Android.bp
+++ b/vibrator/1.4/vts/functional/Android.bp
@@ -12,22 +12,22 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
+//
 
-cc_binary {
-    name: "android.hardware.vibrator@1.3-service.example",
-    vendor: true,
-    relative_install_path: "hw",
-    init_rc: ["android.hardware.vibrator@1.3-service.example.rc"],
-    vintf_fragments: ["android.hardware.vibrator@1.3-service.example.xml"],
-    srcs: ["service.cpp", "Vibrator.cpp"],
-    cflags: ["-Wall", "-Werror"],
-    shared_libs: [
-        "libhidlbase",
-        "liblog",
-        "libutils",
+cc_test {
+    name: "VtsHalVibratorV1_4TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalVibratorV1_4TargetTest.cpp"],
+    static_libs: [
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
         "android.hardware.vibrator@1.3",
+        "android.hardware.vibrator@1.4",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts-core",
     ],
 }
+
diff --git a/vibrator/1.4/vts/functional/VtsHalVibratorV1_4TargetTest.cpp b/vibrator/1.4/vts/functional/VtsHalVibratorV1_4TargetTest.cpp
new file mode 100644
index 0000000..1b6abe9
--- /dev/null
+++ b/vibrator/1.4/vts/functional/VtsHalVibratorV1_4TargetTest.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2019 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 "vibrator_hidl_hal_test"
+
+#include <android-base/logging.h>
+#include <android/hardware/vibrator/1.0/types.h>
+#include <android/hardware/vibrator/1.4/IVibrator.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <getopt.h>
+#include <unistd.h>
+
+#include <future>
+
+using ::android::sp;
+using ::android::hardware::hidl_bitfield;
+using ::android::hardware::hidl_enum_range;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::vibrator::V1_0::EffectStrength;
+using ::android::hardware::vibrator::V1_0::Status;
+using ::android::hardware::vibrator::V1_3::Effect;
+using ::android::hardware::vibrator::V1_4::Capabilities;
+using ::android::hardware::vibrator::V1_4::IVibrator;
+using ::android::hardware::vibrator::V1_4::IVibratorCallback;
+
+static uint32_t sCompletionLimitMs = UINT32_MAX;
+
+#define EXPECT_OK(ret) ASSERT_TRUE((ret).isOk())
+
+class CompletionCallback : public IVibratorCallback {
+  public:
+    CompletionCallback(std::function<void()> callback) : mCallback(callback) {}
+    Return<void> onComplete() override {
+        mCallback();
+        return Void();
+    }
+
+  private:
+    std::function<void()> mCallback;
+};
+
+class VibratorHidlTest_1_4 : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        vibrator = IVibrator::getService(GetParam());
+        ASSERT_NE(vibrator, nullptr);
+        capabilities = vibrator->getCapabilities();
+    }
+
+    virtual void TearDown() override {}
+
+    sp<IVibrator> vibrator;
+    hidl_bitfield<Capabilities> capabilities;
+};
+
+TEST_P(VibratorHidlTest_1_4, OnWithCallback) {
+    if (capabilities & Capabilities::ON_COMPLETION_CALLBACK) {
+        std::promise<void> completionPromise;
+        std::future<void> completionFuture{completionPromise.get_future()};
+        sp<CompletionCallback> callback =
+                new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+        uint32_t duration = 250;
+        std::chrono::milliseconds timeout{duration * 2};
+        EXPECT_EQ(Status::OK, vibrator->on_1_4(duration, callback));
+        EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
+        vibrator->off();
+    }
+}
+
+static void validatePerformEffectUnsupportedOperation(Status status, uint32_t lengthMs) {
+    ASSERT_EQ(Status::UNSUPPORTED_OPERATION, status);
+    ASSERT_EQ(static_cast<uint32_t>(0), lengthMs)
+            << "Effects that return UNSUPPORTED_OPERATION must have a duration of zero";
+}
+
+static void validatePerformEffect(Status status, uint32_t lengthMs) {
+    ASSERT_TRUE(status == Status::OK || status == Status::UNSUPPORTED_OPERATION);
+    if (status == Status::OK) {
+        ASSERT_LT(static_cast<uint32_t>(0), lengthMs)
+                << "Effects that return OK must return a positive duration";
+    } else {
+        validatePerformEffectUnsupportedOperation(status, lengthMs);
+    }
+}
+
+/*
+ * Test to make sure effects within the valid range return are either supported and return OK with
+ * a valid duration, or are unsupported and return UNSUPPORTED_OPERATION with a duration of 0.
+ */
+TEST_P(VibratorHidlTest_1_4, PerformEffect_1_4) {
+    Status performStatus;
+    uint32_t performLength;
+    auto validateWrapper = [&](Status status, uint32_t lengthMs) {
+        performStatus = status;
+        performLength = lengthMs;
+        validatePerformEffect(status, lengthMs);
+    };
+    for (const auto& effect : hidl_enum_range<Effect>()) {
+        for (const auto& strength : hidl_enum_range<EffectStrength>()) {
+            std::promise<void> completionPromise;
+            std::future<void> completionFuture{completionPromise.get_future()};
+            sp<CompletionCallback> callback =
+                    new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+            EXPECT_OK(vibrator->perform_1_4(effect, strength, callback, validateWrapper));
+            if (performStatus == Status::OK && performLength < sCompletionLimitMs &&
+                (capabilities & Capabilities::PERFORM_COMPLETION_CALLBACK)) {
+                std::chrono::milliseconds timeout{performLength * 2};
+                EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
+            }
+        }
+    }
+}
+
+/*
+ * Test to make sure effect values above the valid range are rejected.
+ */
+TEST_P(VibratorHidlTest_1_4, PerformEffect_1_4_BadEffects_AboveValidRange) {
+    Effect effect = *std::prev(hidl_enum_range<Effect>().end());
+    Effect badEffect = static_cast<Effect>(static_cast<int32_t>(effect) + 1);
+    EXPECT_OK(vibrator->perform_1_4(badEffect, EffectStrength::LIGHT, nullptr,
+                                    validatePerformEffectUnsupportedOperation));
+}
+
+/*
+ * Test to make sure effect values below the valid range are rejected.
+ */
+TEST_P(VibratorHidlTest_1_4, PerformEffect_1_4_BadEffects_BelowValidRange) {
+    Effect effect = *hidl_enum_range<Effect>().begin();
+    Effect badEffect = static_cast<Effect>(static_cast<int32_t>(effect) - 1);
+    EXPECT_OK(vibrator->perform_1_4(badEffect, EffectStrength::LIGHT, nullptr,
+                                    validatePerformEffectUnsupportedOperation));
+}
+
+/*
+ * Test to make sure strength values above the valid range are rejected.
+ */
+TEST_P(VibratorHidlTest_1_4, PerformEffect_1_4_BadStrength_AboveValidRange) {
+    EffectStrength strength = *std::prev(hidl_enum_range<EffectStrength>().end());
+    EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) + 1);
+    EXPECT_OK(vibrator->perform_1_4(Effect::THUD, badStrength, nullptr,
+                                    validatePerformEffectUnsupportedOperation));
+}
+
+/*
+ * Test to make sure strength values below the valid range are rejected.
+ */
+TEST_P(VibratorHidlTest_1_4, PerformEffect_1_4_BadStrength_BelowValidRange) {
+    EffectStrength strength = *hidl_enum_range<EffectStrength>().begin();
+    EffectStrength badStrength = static_cast<EffectStrength>(static_cast<int32_t>(strength) - 1);
+    EXPECT_OK(vibrator->perform_1_4(Effect::THUD, badStrength, nullptr,
+                                    validatePerformEffectUnsupportedOperation));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, VibratorHidlTest_1_4,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVibrator::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+enum {
+    OPTION_COMPLETION_LIMIT_MS,
+};
+
+int main(int argc, char** argv) {
+    struct option options[] = {
+            {"completion-limit-ms", required_argument, 0, OPTION_COMPLETION_LIMIT_MS}, {}};
+
+    printf("Running main() from %s\n", __FILE__);
+    testing::InitGoogleTest(&argc, argv);
+
+    while (true) {
+        int opt = getopt_long(argc, argv, "", options, nullptr);
+        if (opt == -1) {
+            break;
+        }
+        switch (opt) {
+            case OPTION_COMPLETION_LIMIT_MS:
+                std::istringstream(optarg) >> sCompletionLimitMs;
+                break;
+            default:
+                printf("Unrecognized option\n");
+                return -EINVAL;
+        }
+    }
+
+    return RUN_ALL_TESTS();
+}
diff --git a/vibrator/1.3/example/Android.bp b/vibrator/1.x/example/Android.bp
similarity index 81%
rename from vibrator/1.3/example/Android.bp
rename to vibrator/1.x/example/Android.bp
index 07f1c26..afbbb75 100644
--- a/vibrator/1.3/example/Android.bp
+++ b/vibrator/1.x/example/Android.bp
@@ -14,11 +14,11 @@
 // limitations under the License.
 
 cc_binary {
-    name: "android.hardware.vibrator@1.3-service.example",
+    name: "android.hardware.vibrator@1.x-service.example",
     vendor: true,
     relative_install_path: "hw",
-    init_rc: ["android.hardware.vibrator@1.3-service.example.rc"],
-    vintf_fragments: ["android.hardware.vibrator@1.3-service.example.xml"],
+    init_rc: ["android.hardware.vibrator@1.x-service.example.rc"],
+    vintf_fragments: ["android.hardware.vibrator@1.x-service.example.xml"],
     srcs: ["service.cpp", "Vibrator.cpp"],
     cflags: ["-Wall", "-Werror"],
     shared_libs: [
@@ -29,5 +29,6 @@
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
         "android.hardware.vibrator@1.3",
+        "android.hardware.vibrator@1.4",
     ],
 }
diff --git a/vibrator/1.3/example/OWNERS b/vibrator/1.x/example/OWNERS
similarity index 100%
rename from vibrator/1.3/example/OWNERS
rename to vibrator/1.x/example/OWNERS
diff --git a/vibrator/1.3/example/Vibrator.cpp b/vibrator/1.x/example/Vibrator.cpp
similarity index 86%
rename from vibrator/1.3/example/Vibrator.cpp
rename to vibrator/1.x/example/Vibrator.cpp
index b529437..4dd1cb9 100644
--- a/vibrator/1.3/example/Vibrator.cpp
+++ b/vibrator/1.x/example/Vibrator.cpp
@@ -23,7 +23,7 @@
 namespace android {
 namespace hardware {
 namespace vibrator {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 
 static constexpr uint32_t MS_PER_S = 1000;
@@ -100,7 +100,25 @@
     }
 }
 
-Return<void> Vibrator::perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {
+Return<void> Vibrator::perform_1_3(V1_3::Effect effect, EffectStrength strength,
+                                   perform_cb _hidl_cb) {
+    return perform<decltype(effect)>(effect, strength, _hidl_cb);
+}
+
+// Methods from ::android::hardware::vibrator::V1_4::IVibrator follow.
+
+Return<hidl_bitfield<Capabilities>> Vibrator::getCapabilities() {
+    return Capabilities::ON_COMPLETION_CALLBACK | Capabilities::PERFORM_COMPLETION_CALLBACK;
+}
+
+Return<Status> Vibrator::on_1_4(uint32_t timeoutMs, const sp<IVibratorCallback>& callback) {
+    mCallback = callback;
+    return on(timeoutMs);
+}
+
+Return<void> Vibrator::perform_1_4(V1_3::Effect effect, EffectStrength strength,
+                                   const sp<IVibratorCallback>& callback, perform_cb _hidl_cb) {
+    mCallback = callback;
     return perform<decltype(effect)>(effect, strength, _hidl_cb);
 }
 
@@ -148,6 +166,14 @@
         return Status::UNSUPPORTED_OPERATION;
     } else {
         ALOGI("Enabled: %s -> %s\n", mEnabled ? "true" : "false", enabled ? "true" : "false");
+        if (mEnabled && !enabled) {
+            if (auto callback = mCallback) {
+                mCallback = nullptr;
+                if (auto ret = callback->onComplete(); !ret.isOk()) {
+                    ALOGE("Failed completion callback: %s", ret.description().c_str());
+                }
+            }
+        }
         mEnabled = enabled;
         return Status::OK;
     }
@@ -271,7 +297,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace vibrator
 }  // namespace hardware
 }  // namespace android
diff --git a/vibrator/1.3/example/Vibrator.h b/vibrator/1.x/example/Vibrator.h
similarity index 75%
rename from vibrator/1.3/example/Vibrator.h
rename to vibrator/1.x/example/Vibrator.h
index 5180774..ff63431 100644
--- a/vibrator/1.3/example/Vibrator.h
+++ b/vibrator/1.x/example/Vibrator.h
@@ -13,20 +13,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#ifndef ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
-#define ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
+#ifndef ANDROID_HARDWARE_VIBRATOR_V1_x_VIBRATOR_H
+#define ANDROID_HARDWARE_VIBRATOR_V1_x_VIBRATOR_H
 
-#include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <android/hardware/vibrator/1.4/IVibrator.h>
 #include <hidl/Status.h>
 
 namespace android {
 namespace hardware {
 namespace vibrator {
-namespace V1_3 {
+namespace V1_4 {
 namespace implementation {
 
 using android::hardware::vibrator::V1_0::EffectStrength;
 using android::hardware::vibrator::V1_0::Status;
+using android::hardware::vibrator::V1_3::Effect;
 
 class Vibrator : public IVibrator {
   public:
@@ -51,7 +52,14 @@
     // Methods from ::android::hardware::vibrator::V1_3::IVibrator follow.
     Return<bool> supportsExternalControl() override;
     Return<Status> setExternalControl(bool enabled) override;
-    Return<void> perform_1_3(Effect effect, EffectStrength strength, perform_cb _hidl_cb) override;
+    Return<void> perform_1_3(V1_3::Effect effect, EffectStrength strength,
+                             perform_cb _hidl_cb) override;
+
+    // Methods from ::android::hardware::vibrator::V1_4::IVibrator follow.
+    Return<hidl_bitfield<Capabilities>> getCapabilities() override;
+    Return<Status> on_1_4(uint32_t timeoutMs, const sp<IVibratorCallback>& callback) override;
+    Return<void> perform_1_4(V1_3::Effect effect, EffectStrength strength,
+                             const sp<IVibratorCallback>& callback, perform_cb _hidl_cb) override;
 
   private:
     Return<void> perform(Effect effect, EffectStrength strength, perform_cb _hidl_cb);
@@ -72,11 +80,12 @@
     bool mExternalControl{false};
     std::mutex mMutex;
     timer_t mTimer{nullptr};
+    sp<IVibratorCallback> mCallback{nullptr};
 };
 }  // namespace implementation
-}  // namespace V1_3
+}  // namespace V1_4
 }  // namespace vibrator
 }  // namespace hardware
 }  // namespace android
 
-#endif  // ANDROID_HARDWARE_VIBRATOR_V1_3_VIBRATOR_H
+#endif  // ANDROID_HARDWARE_VIBRATOR_V1_x_VIBRATOR_H
diff --git a/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.rc b/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.rc
new file mode 100644
index 0000000..4893db6
--- /dev/null
+++ b/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.rc
@@ -0,0 +1,4 @@
+service vendor.vibrator-1-x /vendor/bin/hw/android.hardware.vibrator@1.x-service.example
+    class hal
+    user system
+    group system
diff --git a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml b/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.xml
similarity index 89%
rename from vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml
rename to vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.xml
index 172aa21..ebc8c4b 100644
--- a/vibrator/1.3/example/android.hardware.vibrator@1.3-service.example.xml
+++ b/vibrator/1.x/example/android.hardware.vibrator@1.x-service.example.xml
@@ -2,7 +2,7 @@
     <hal format="hidl">
         <name>android.hardware.vibrator</name>
         <transport>hwbinder</transport>
-        <version>1.3</version>
+        <version>1.4</version>
         <interface>
             <name>IVibrator</name>
             <instance>default</instance>
diff --git a/vibrator/1.3/example/service.cpp b/vibrator/1.x/example/service.cpp
similarity index 82%
rename from vibrator/1.3/example/service.cpp
rename to vibrator/1.x/example/service.cpp
index 449996e..13c6691 100644
--- a/vibrator/1.3/example/service.cpp
+++ b/vibrator/1.x/example/service.cpp
@@ -13,17 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "android.hardware.vibrator@1.3-service.example"
+#define LOG_TAG "android.hardware.vibrator@1.x-service.example"
 
-#include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <android/hardware/vibrator/1.4/IVibrator.h>
 #include <hidl/HidlTransportSupport.h>
 
 #include "Vibrator.h"
 
 using android::hardware::configureRpcThreadpool;
 using android::hardware::joinRpcThreadpool;
-using android::hardware::vibrator::V1_3::IVibrator;
-using android::hardware::vibrator::V1_3::implementation::Vibrator;
+using android::hardware::vibrator::V1_4::IVibrator;
+using android::hardware::vibrator::V1_4::implementation::Vibrator;
 using namespace android;
 
 status_t registerVibratorService() {